root/applications/doprava/aimsun_bdm/aimsun_ds.cpp @ 1089

Revision 1089, 23.3 kB (checked in by ondrak, 14 years ago)

Added option to set simulation length in number of cycles

Line 
1/*
2 */
3
4/* Class definition */
5#include "aimsun_ds.h"
6#include "tools.h"
7
8// TODO: reference additional headers your program requires here
9#include <process.h>
10#include <strsafe.h>
11#include <shlwapi.h>
12#include <io.h>
13
14//#include <atlbase.h>
15
16#define MAX_PATH_BYTES  (MAX_PATH*sizeof(TCHAR))
17#define MAX_EXE_BYTES   (MAX_EXE_PATH*sizeof(TCHAR))
18
19/* Contoller list is hardwired for Aimsun scenario `zlicin_495_601.sce` */
20#define NUM_CONTROLLERS 2
21const TCHAR * ControllerList[NUM_CONTROLLERS] = { TEXT("K_5_495"), TEXT("K_5_601") };
22const TCHAR * WindowStr[NUM_CONTROLLERS]      = { TEXT("els3@5.495"), TEXT("els3@5.601") };
23const int IntersectionIDs[] = { 495, 601 };
24const int NumLanes[] = { 6, 6 };
25const int NumIntersections = sizeof ( IntersectionIDs )/sizeof(int);
26
27/* Entrance sections are hardwired for Aimsun scenario `zlicin_495_601.sce` */
28const int EntranceSections[] = { 1, 42, 45, 287, 26 };
29const int NumEntranceSections = sizeof(EntranceSections)/sizeof(int);
30
31/* Identifiers of sections that Aimsun shall collect statistics for are also
32   hardwired for the scenario `zlicin_495_601.sce`. */
33const int StatIds[] = {
34        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
35        26, 27, 35, 28, 29, 30, 31, 32, 33, 34, 39, 36, 37, 38, 21, 22, 23, 24, 25, 40,
36        42, 43, 44, 45, 49, 46, 47, 50, 51, 287, 288, 54, 55, 56, 57, 58, 59, 60, 61,
37        62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77 };
38const int NumStatIds = sizeof(StatIds)/sizeof(int);
39
40const int LaneQueuesSectIds[] = {
41        1,      2,      3,      6,      7,                              // 495_QA
42        3,      4,      5,                                              // 495_QB
43        35,     28,     32,     33,     34,                             // 495_QC
44        26,     27,     35,     28,     29,     30,     31,             // 495_QD
45        16,     17,     18,     19,     20,     14,     15,             // 495_QE
46        16,     17,     18,     19,     20,     12,     13,             // 495_QF
47        21,     22,     23,     24,     25,     40,     21,     22,     23,     24,     25,     40,                     // 601_QA
48        43,     44, 43, 44,     42,                             // 601_QB (bus terminal)
49        45,     49,     50,                                             // 601_QC
50        45,     49,     51,                                             // 601_QD
51        61,     62,     63,     64,     65,                             // 601_QE
52        287,288,54,     55,     56,     57,     58,     59,     60,     61,     62,     63,     64,     65      // 601_QSE
53 };
54const int NumLaneQueuesSectIds = sizeof(LaneQueuesSectIds)/sizeof(int);
55const int LaneQueuesLaneIds[] = {
56        1,      1,      2,      1,      1,                              // 495_QA
57        1,      1,      1,                                              // 495_QB
58        2,      2,      1,      1,      1,                              // 495_QC
59        1,      1,      1,      1,      1,      1,      1,              // 495_QD
60        2,      2,      2,      2,      2,      1,      1,              // 495_QE
61        1,      1,      1,      1,      1,      1,      1,              // 495_QF
62        2,      2,      2,      2,      2,      2,      1,      1,      1,      1,      1,      1,                      // 601_QA
63        2,      2,      1,      1,      1,                              // 601_QB (bus terminal)
64        1,      1,      1,                                              // 601_QC
65        2,      2,      1,                                              // 601_QD
66        2,      2,      2,      2,      2,                              // 601_QE
67        1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1       // 601_QSE
68};
69
70/* This array contains offsets of particular lanes stored in LaneQueuesSectIds,
71   plus the would-be offset of the next non-existent lane (this is used to
72   set the limits of the index when extracting statistical data from the
73   section_stats structure). */
74int LaneQueueOffsets[] = {
75        0, 5, 8, 13, 20, 27,
76        34, 46, 51, 54, 57, 62, NumLaneQueuesSectIds };
77
78/* The position of the statistics is given by the indices in the StatIds
79   array. In order to parse the statistics correctly we have to create
80   a copy of LaneQueuesSectIds holding indices to the StatIds array instead
81   of the original section ids. */
82int * LaneQueuesStatPos;
83
84const TCHAR * PatternsELS3[] = { TEXT("GetramELS3.dll"), TEXT("GetramELS3d.dll") };
85const TCHAR * PatternsVGS[] = { TEXT("GetramVGS.dll"), TEXT("GetramVGSd.dll") };
86
87/* Offsets of `dt` components (dt is the vector returned by AimsunDS, it contains composite
88   values of all measurements for all intersections in the system). */
89const int SignalPlanOffsets[]  = {  0, 42 };
90const int QueueLengthOffsets[] = {  6, 48 };
91const int MeasurementOffsets[] = { 12, 54 };
92
93AimsunDS::AimsunDS () : DS()
94{
95  /* Description of the channels of the data vector. */
96  Drv = RV ( "{"
97    "495_VA  495_VB   495_VC   495_VD   495_VE   495_VF "
98    "495_QA  495_QB   495_QC   495_QD   495_QE   495_QF "
99    "495_DVA 495_DVB  495_DVA1 495_DVB1 495_DVC  495_DVD  495_DVE  495_DVF  495_DVF1 "
100    "495_S1  495_S2   495_S3   495_S4   495_S5   495_S5a "
101    "601_VA  601_VB   601_VC   601_VD   601_VE   601_SE "
102    "601_QA  601_QB   601_QC   601_QD   601_QE   601_QSE "
103        "601_DVA 601_DVAa 601_DVB  601_DVBa 601_DVB1 601_DVC  601_DVD  601_DVD1 601_DSE 601_DVE 601_DSE1 601_DVE1 "
104    "601_S6  601_S6a  601_S7   601_S8   601_S9   601_S9a "
105    "}",
106        "    1,      1,      1,      1,      1,       1,      "
107        "    1,      1,      1,      1,      1,       1,      "
108        "    2,      2,      2,      2,      2,       2,      2,      2,      2,"
109        "    2,      2,      2,      2,      2,       2,"
110        "    1,      1,      1,      1,      1,       1,      "
111        "    1,      1,      1,      1,      1,       1,      "
112        "    2,      2,      2,      2,      2,       2,       2,       2,       2,       2,       2,       2,"
113        "    2,      2,      2,      2,      2,       2"
114        );
115  /* Remember the size of the data vector. */
116  dtsize = Drv._dsize();
117
118  /* Description of the channels of the input vector. */
119  Urv = RV ( "{"
120          "Tc "
121          "495_offset "
122          "495_VA  495_VB   495_VC   495_VD   495_VE   495_VF "
123          "601_offset "
124          "601_VA  601_VB   601_VC   601_VD   601_VE   601_SE "
125          "}" );
126  /* Remember the size of the input vector. */
127  utsize = Urv._dsize();
128
129  /* Initialise the pointer to received data. */
130  p_rsp = NULL;
131}
132
133void AimsunDS::from_setting ( const Setting &cfg )
134{
135        /* Check the `stop time` field in configuration. */
136        UI::get ( stopTime, cfg, "stop_time" );
137
138        /* Try to load number of stop cycle from configuration,
139           if the value is present, stopTime is overwritten */
140        if (UI::get ( stopCycle, cfg, "stop_cycle" )) {
141                //TODO I don't know if I can read length of step somewhere, so hardwired now
142                int totalTime=stopCycle*90;
143               
144                int hours = totalTime / 3600;
145                int minutes = ( totalTime % 3600 )/ 60;
146                int seconds = totalTime % 60; 
147               
148                stopTime=int_to_string(hours)+":"+int_to_string(minutes)+":"+int_to_string(seconds);
149        }
150        else {
151                stopCycle=960;
152        }
153
154        /* Query the configuration file for the name of the file containsing
155           vehicle entrances. */
156        UI::get ( entranceFileName, cfg, "entrances" );
157}
158
159void AimsunDS::validate ()
160{
161        HKEY  hKey;
162        TCHAR szBasePath[MAX_PATH];             /**< Base path of the whole application, root of the tree. */
163        TCHAR szDllPath[MAX_PATH];              /**< Directory where all DLLs reside. Will be added to PATH. */
164        TCHAR szSceDllPath[MAX_PATH];   /**< Temporary storage for DLL path rewritten in the scenario file. */
165        TCHAR szSceDir[MAX_PATH];               /**< Directory of the simulated scenario. */
166        TCHAR szScePath[MAX_PATH];              /**< Full path to the Aimsun scenario file. The file resides in `szSceDir`. */
167        TCHAR szScePathA[MAX_PATH];
168        TCHAR szScePathB[MAX_PATH];
169        TCHAR szScePathC[MAX_PATH];
170        TCHAR szNetPath[MAX_PATH];
171        TCHAR szHomeDir[MAX_PATH];              /**< Installation directory of Aimsun 4.2.x */
172        TCHAR szELS3Path[MAX_PATH];             /**< Full path of the simulator of ELS3 controller. */
173        TCHAR szExePath[MAX_EXE_PATH];  /**< Command line when staring ELS3 controllers. */
174        TCHAR szEntrancePath[MAX_PATH]; /**< Points to the CSV file with vehicle entrances for the simulation. */
175        DWORD dwBufLen = MAX_PATH_BYTES;
176        LONG  res;
177
178        intptr_t hPid;
179
180        int verIndex = 1; //@TODO@: 0 is for release, 1 for debug build of the DLL libraries.
181
182        /* The root directory of the simulator tree is defined externally
183           in "CMakeLists.txt". */
184        StringCbCopy ( szBasePath, MAX_PATH_BYTES, BASE_PATH );
185
186        /* Create the path to DLL directory. The path is defined externally
187           in  "CMakeLists.txt".
188           The path will be used to inject the appropriate location of
189           Getram extensions into the selected Aimsun scenario and also
190           to modify PATH variable of executed processes in order to
191           provide access to API DLLs. */
192        StringCbCopy ( szDllPath, MAX_PATH_BYTES, DLL_PATH );
193
194        /* Add the DLL directory to the PATH used by this process.
195           The PATH will be passed to all other processes started
196           by this one and hence they will be able to find API
197           DLLs. */
198        _addpath ( szDllPath );
199
200#ifdef LATER_OR_NEVER
201        GetPrivateProfileString (
202                TEXT("paths"),
203                TEXT("base"),
204                NULL,
205                szBasePath,
206                MAX_PATH,
207                TEXT(".\\simulate.ini")
208                );
209#endif
210
211        /* Find the location of Aimsun executable. It is stored in registry tree as
212           \\HKEY_LOCAL_MACHINE\SOFTWARE\TSS-Transport Simulation Systems\GETRAM\4.2.0 */
213        res = RegOpenKeyEx (
214                HKEY_LOCAL_MACHINE,
215                TEXT("SOFTWARE\\TSS-Transport Simulation Systems\\GETRAM\\4.2.0"),
216                0,
217                KEY_QUERY_VALUE,
218                &hKey
219                );
220        if ( res != ERROR_SUCCESS )
221        {
222                perror ( "Cannot get handle to Aimsun registry entry" );
223                return;
224        }
225
226        /* The executable location is `HomeDir` key. */
227        res = RegQueryValueEx (
228                hKey,
229                TEXT("HomeDir"),
230        NULL, NULL,
231                (LPBYTE) szHomeDir,
232                &dwBufLen
233                );
234        RegCloseKey( hKey );
235    if (( res != ERROR_SUCCESS ) || ( dwBufLen > MAX_PATH_BYTES ))
236        {
237                perror ( "Cannot read the Aimsun home directory from registry" );
238        return;
239        }
240
241        /* Concatenate the home path with the executable name. */
242        StringCbCat ( szHomeDir, MAX_PATH_BYTES, TEXT("\\aimsun42.exe") );
243
244        /* Create the version of home path including the quotation marks. */
245        StringCbCopy ( szExePath, MAX_EXE_PATH, TEXT("\"") );
246        StringCbCat ( szExePath, MAX_EXE_PATH, szHomeDir );
247        StringCbCat ( szExePath, MAX_EXE_PATH, TEXT("\"") );
248
249        /* Create the path to ELS3 executable. */
250        StringCbCopy ( szELS3Path, MAX_PATH_BYTES, TEXT("\"") );
251        StringCbCat ( szELS3Path, MAX_PATH_BYTES, szBasePath );
252        StringCbCat ( szELS3Path, MAX_PATH_BYTES, TEXT("\\els3\\els3sample.exe\"") );
253
254        /* Aimsun scenario modification.
255           We have to take care of items that are specified by absolute
256           paths in the scenario file. These items include:
257           - network path (section #NETWORK),
258           - ELS3 Getram extension DLL (section #EXTENSIONS),
259           - VGS Getram extension DLL (section #EXTENSIONS).
260
261           We will start with constructing the new network path.*/
262        StringCbCopy ( szSceDir, MAX_EXE_PATH, szBasePath );
263        StringCbCat ( szSceDir, MAX_EXE_PATH, TEXT("\\scenarios\\zlicin_495_601") );
264        StringCbCopy ( szNetPath, MAX_EXE_PATH, szSceDir );
265        StringCbCat ( szNetPath, MAX_EXE_PATH, TEXT("\\zlicin_495_601") );
266
267        /* Our convention is that the scenario file name corresponds
268           to the network path name. */
269        StringCbCopy ( szScePath, MAX_EXE_PATH, szNetPath );
270        StringCbCat ( szScePath, MAX_EXE_PATH, TEXT(".sce") );
271
272        /* First modification step: Replace the location of ELS3 Getram
273           extension.
274           Start with constructing full path to the extension DLL.*/
275        StringCbCopy ( szSceDllPath, MAX_EXE_PATH, szDllPath );
276        StringCbCat ( szSceDllPath, MAX_EXE_PATH, TEXT("\\") );
277        StringCbCat ( szSceDllPath, MAX_EXE_PATH, PatternsELS3[verIndex] );
278        /* We are not allowed to modify scenario in place (it is part
279           of SVN snapshot and we do not want our local changes to
280           propagate to the trunk with every commit). Therefore we
281           need an alternative scenario name that will be constructed
282           now. */
283        StringCbCopy ( szScePathA, MAX_EXE_PATH, szScePath );
284        StringCbCat ( szScePathA, MAX_EXE_PATH, TEXT(".a") );
285        /* And do the replacements. */
286        replace_in_scenario (
287                szScePath, szScePathA,
288                TEXT("#EXTENSIONS"),
289                PatternsELS3,
290                2,
291                szSceDllPath
292                );
293
294        /* Second modification step.
295           Replace the location of VGS Getram extension. */
296        StringCbCopy ( szSceDllPath, MAX_EXE_PATH, szDllPath );
297        StringCbCat ( szSceDllPath, MAX_EXE_PATH, TEXT("\\") );
298        StringCbCat ( szSceDllPath, MAX_EXE_PATH, PatternsVGS[verIndex] );
299        StringCbCopy ( szScePathB, MAX_EXE_PATH, szScePath );
300        StringCbCat ( szScePathB, MAX_EXE_PATH, TEXT(".b") );
301        replace_in_scenario (
302                szScePathA, szScePathB,
303                TEXT("#EXTENSIONS"),
304                PatternsVGS,
305                2,
306                szSceDllPath
307                );
308
309        const TCHAR * pattern_net[] = { TEXT("zlicin_495_601") };
310
311        /* Third modification step.
312           Replace the network path. */
313        StringCbCopy ( szScePathC, MAX_EXE_PATH, szScePath );
314        StringCbCat ( szScePathC, MAX_EXE_PATH, TEXT(".c") );
315        replace_in_scenario (
316                szScePathB, szScePathC,
317                TEXT("#NETWORK"),
318                pattern_net,
319                1,
320                szNetPath
321                );
322
323        /* Fourth modification step.
324           Replace the `stop time` field of RunTime information. */
325        replace_stoptime (
326                szNetPath,
327                stopTime.c_str()
328                );
329
330        //???
331        //StringCbCat ( szScePath, MAX_EXE_PATH, TEXT("\"") );
332        //StringCbCat ( szScePath, MAX_EXE_PATH, TEXT("\"") );
333
334        /* Spawn the process. */
335        hPid = _tspawnl (
336                _P_NOWAIT,
337                szHomeDir,
338                szExePath,
339                TEXT("-run"),
340                szScePathC,
341                NULL
342                );
343
344        if ( hPid < 0 )
345        {
346                perror ( "Cannot start Aimsun by _spawnl()" );
347                return;
348        }
349
350        /* Now that Aimsun is running, we need to start also the controllers. */
351        for ( int c = 0 ; c < NUM_CONTROLLERS ; c++ )
352        {
353                TCHAR szELS3Config[MAX_PATH];
354                szELS3Config[0] = 0;
355                StringCbCat ( szELS3Config, MAX_PATH_BYTES, TEXT("\"") );
356                StringCbCat ( szELS3Config, MAX_PATH_BYTES, szBasePath );
357                StringCbCat ( szELS3Config, MAX_PATH_BYTES, TEXT("\\els3\\configs\\") );
358                StringCbCat ( szELS3Config, MAX_PATH_BYTES, ControllerList[c] );
359                StringCbCat ( szELS3Config, MAX_PATH_BYTES, TEXT(".ini\"") );
360
361                /* Create the command line for the controller. */
362                szExePath[0] = 0;
363                StringCbCat ( szExePath, MAX_EXE_PATH, TEXT("start \"") );
364                StringCbCat ( szExePath, MAX_EXE_PATH, WindowStr[c] );
365                StringCbCat ( szExePath, MAX_EXE_PATH, TEXT("\" ") );
366                StringCbCat ( szExePath, MAX_EXE_PATH, szELS3Path );
367                StringCbCat ( szExePath, MAX_EXE_PATH, TEXT(" -a") );
368                StringCbCat ( szExePath, MAX_EXE_PATH, TEXT(" -l frm,det,spl") );
369                StringCbCat ( szExePath, MAX_EXE_PATH, TEXT(" -c 12.12.2007 00:00:00") );
370                StringCbCat ( szExePath, MAX_EXE_PATH, TEXT(" -f ") );
371                StringCbCat ( szExePath, MAX_EXE_PATH, szELS3Config );
372
373                /* Spawn the process. */
374                _tsystem ( szExePath );
375        }
376
377        /* Aaaaggggrrrrrhhhh!
378           C++ is much much faster than Matlab and we have a synchronisation
379           issue with els3 controllers starting too late. */
380        Sleep ( 5000 );
381
382
383        /* Prepare full path for vehicle input data. */
384        StringCbCopy ( szEntrancePath, MAX_EXE_PATH, szSceDir );
385        StringCbCat  ( szEntrancePath, MAX_EXE_PATH, TEXT("\\") );
386        StringCbCat  ( szEntrancePath, MAX_EXE_PATH, entranceFileName.c_str() );
387
388        /* Initialise and start the vehicle input.
389           The function call refers to delay-loaded DLL, so expect possible
390           complainst in case that the DLL canot be found in PATH. */
391        initVGS (
392                HEADWAY_UNIFORM,
393                szEntrancePath,
394                TEXT("sect_stats.csv"),
395                TEXT("glob_stats.csv")
396                );
397
398        /* Create LaneQueuesStatPos holding indices to the statistical data for the
399           sections listed in LaneQueuesSectIds in the same order. */
400        LaneQueuesStatPos = (int *) calloc ( NumLaneQueuesSectIds, sizeof(int));
401        for ( int i=0 ; i < NumLaneQueuesSectIds ; i++ )
402        {
403                int p = _search_index ( StatIds, NumStatIds, LaneQueuesSectIds[i] );
404                if ( p >= 0 )
405                {
406                        LaneQueuesStatPos[i] = p;
407                }
408                else
409                {
410                        fprintf ( stderr, "Cannot find index  LaneQueuesStatIds[%d]=%d in StatIds!\n",
411                                i, LaneQueuesSectIds[i] );
412                    exit(1);
413                }
414        }
415
416}
417
418void AimsunDS::initVGS (
419        const vgs_headway_mode headway,
420        const string &entrancePath,
421        const string &sectionStatsPath,
422        const string &globalStatsPath
423        )
424{
425    int res;
426       
427        /* Allocate space for the section statistics.
428           TODO: This is ugly. This should be part of VGS API. */
429        sections_stats.queues = (int*) calloc ( MAX_SECTS*MAX_LANES, sizeof(int) );
430        sections_stats.stats  = (vgs_se_stat_entry*) calloc ( MAX_SECTS, sizeof(vgs_se_stat_entry) );
431
432        /* Pass information about entrance sections to VGS API (and so to the
433       GetramVGS extension that will be generating vehicles for these
434           entrances). */
435    vgs_set_entrance_sections ( EntranceSections, NumEntranceSections );
436   
437    /* Check the validity of the headway mode. */
438    res = vgs_is_valid_headway_mode ( headway );
439    if ( !res )
440        {
441        fprintf ( stderr, "Invalid headway mode '%d'\n", headway );
442                exit ( -1 );
443        }
444   
445    /* Specify where to find the CSV with vehicle entrances and which
446           headway mode to use for generating vehicle flows. */
447        vgs_generate_vehicles ( entrancePath.c_str(), headway );
448   
449    /* Pass to VGS API information about section identifiers we want to
450       collect statistics for (and VGS will pass it to the GetramVGS
451       extension). */ 
452        vgs_set_stats_sections ( StatIds, NumStatIds );
453   
454    /* Specify where to store CSV files with statistical data. */
455        vgs_set_stats_file_names ( sectionStatsPath.c_str(), globalStatsPath.c_str() );
456   
457    /* Specify the maximum queuing speed in kmph. */
458    vgs_set_max_qspeed ( 3.6f );
459   
460    /* Unlock the semaphore blocking Aimsun from execution. */
461    vgs_unlock_aimsun();
462}
463
464void AimsunDS::getdata ( vec &dt ) const
465{
466        /* Return the last data. */
467        printf ( "\n\tAimsunDS::getdata() starting\n" );
468
469        if ( p_rsp == NULL )
470        {
471                fprintf ( stderr, "ERROR: AimsunDS::getdata() - no data available yet!\n" );
472                return;
473        }
474
475        /* Loop over all controllers in the measurement set. */
476        for ( int i = 0; i < p_rsp->count; i++)
477        {
478                det_stats * ds_ptr  = p_rsp->dets + i;
479                sp_stats *  sp_ptr  = p_rsp->sps  + i;
480
481                printf ( "\tRealised signal plans:\n" );
482
483                /* Loop over all measurement sets. We will deliver just
484                   the last one. */
485                for ( int j = 0; j < sp_ptr->count ; j++ )
486                {
487                        sp_stattab * dat_ptr = sp_ptr->splans + j;
488                        int          pos     = _search_index ( IntersectionIDs, NumIntersections, dat_ptr->its_id );
489                        int          offset  = SignalPlanOffsets[pos];
490
491                        printf ( "\t[%3d] t=%6ds ", j, dat_ptr->global_time );
492
493                        /* Copy particular signals. */
494                        for ( int k = 0 ; k < dat_ptr->num_siggroups ; k++ )
495                        {
496                                dt[k+offset] = dat_ptr->green_time[k];
497                                printf ( "%3d ", dat_ptr->green_time[k] );
498                        }
499                        printf ( "\n" );
500                }
501
502                printf ( "\tDetector data:\n" );
503
504                /* Loop over all mesurement records with intensities and
505                   occupancies. */
506                for ( int j = 0 ; j < ds_ptr->count ; j++ )
507                {
508                        det_aggreg_table * dat_ptr = ds_ptr->stats + j;
509                        int  pos     = _search_index ( IntersectionIDs, NumIntersections, dat_ptr->its_id );
510                        int  moffset = MeasurementOffsets[pos];
511
512                        printf ( "\t[%3d] t=%6ds ", j, dat_ptr->global_time );
513
514                        for ( int k = 0 ; k < dat_ptr->num_det ; k++ )
515                        {
516                                dt[2*k+moffset]   = dat_ptr->dt_intensity[k];
517                                dt[2*k+moffset+1] = dat_ptr->dt_occupancy[k];
518                                printf ( "{%2d/%2d} ",
519                                        dat_ptr->dt_intensity[k], dat_ptr->dt_occupancy[k] );
520                        }
521                        printf ( "\n\n" );
522                }
523        }
524
525        /* Loop over the statistical data. We will extract the queue length for
526           every intersection and store it into the data vector. */
527        int oLanes = 0; // lane offset for the actual intersection
528        int oLpos  = 0;
529        for ( int i = 0 ; i < NumIntersections ; i++ )
530        {
531                /* Every intersection has a certain number of lanes that (roughly)
532                   correspond to the number of signal groups. */
533                int nLanes  = NumLanes[i];
534                int qoffset = QueueLengthOffsets[i];
535                for ( int j = 0 ; j < nLanes ; j++ )
536                {
537                        /* Initial queue length for this lane is zero. */
538                        int qLen = 0;
539                        /* Every lane has one or more section identifiers at certain
540                           positions in LaneQueuesStatIds. The sequence of lanes
541                           is given by offsets in LaneQueueOffsets, the position of
542                           the statistical information is stored in LaneQueuesStatPos. */
543                        for ( int k = oLpos ; k < LaneQueueOffsets[oLanes+j+1] ; k++ )
544                        {
545                                /* Get the index into statistical information records. */
546                                int pi = LaneQueuesStatPos[k];
547                                int pl = LaneQueuesLaneIds[k]-1; // indices are not zero-based
548                                /* Now query the last queue length (section with more than
549                                   one lane holds several queue lengths) and add it to the
550                                   acumulated queue length value. */
551                                qLen += sections_stats.queues[pi*sections_stats.max_lanes+pl];
552                        }
553                        /* Move the lane position offset. */
554                        oLpos = LaneQueueOffsets[oLanes+j+1];
555                        /* Update the data vector. */
556                        dt[qoffset+j] = qLen;
557                }
558                oLanes = oLanes + nLanes;
559        }
560
561        printf ( "\tAimsunDS::getdata() finished\n" );
562        cout << dt ;
563}
564
565
566void AimsunDS::write ( vec &ut )
567{
568    eh_res     sp_res;   /* Result code from write operation. */
569        eh_hrdels3 hrdsp[2]; /* Signal plan for two intersections. */
570   
571    /* Check that the length of the vector is correct. */
572    if ( ut.size() != utsize )
573    {
574      fprintf ( stderr, "Incorrect length of data vector (should be %d)", utsize );
575      exit(-1);
576    }
577    /* Check that the phase lengths sum to correct cycle time. */
578    /*
579        if ( ut[0]+ut[1]+ut[2] != 80 )
580    {
581      fprintf ( stderr, "Intersection 495: F1+F2+F3 != Tc (should be 80)" );
582      exit(-1);
583    }
584    if ( ut[3]+ut[4]+ut[5] != 80 )
585    {
586      fprintf ( stderr, "Intersection 601: F1+F2+F3 != Tc (should be 80)" );
587      exit(-1);
588    }*/
589
590    hrdsp[0].id = 495;
591    hrdsp[0].sp.cycle_time   = int ( ut[0] );
592        hrdsp[0].sp.offset       = int ( ut[1] );
593        hrdsp[0].sp.phase_len[0] = int ( ut[2] );
594    hrdsp[0].sp.phase_len[1] = int ( ut[3] );
595    hrdsp[0].sp.phase_len[2] = int ( ut[4] );
596    hrdsp[0].sp.phase_len[3] = -1;
597
598    hrdsp[1].id = 601;
599    hrdsp[1].sp.cycle_time   = int ( ut[ 0] );
600    hrdsp[1].sp.offset       = int ( ut[ 8] );
601    hrdsp[1].sp.phase_len[0] = int ( ut[ 9] );
602    hrdsp[1].sp.phase_len[1] = int ( ut[10] );
603    hrdsp[1].sp.phase_len[2] = int ( ut[11] );
604    hrdsp[1].sp.phase_len[3] = -1;
605
606        /* Write new signal plan to the shared memory of active controllers. */
607    sp_res = eh_write_hrd_data( hrdsp, 2 );
608
609        if ( sp_res != EH_RES_OK )
610        {
611                printf ( "eh_write_hrd_data(): " );
612                if ( sp_res == EH_RES_WCNT )
613                {
614                        printf ( "Wrong count of ELS3...\n" );
615                }
616                else if ( sp_res == EH_RES_WRID )
617                {
618                        printf ( "Wrong intersection ID...\n" );
619                }
620                else
621                {
622                        printf ( "Unknown error [%d] ...\n", sp_res );
623                }
624        }
625}
626
627
628void AimsunDS::step()
629{
630        eh_wres      wsp_res;   /* Result code of the wait operation. */
631    int          count;         /* Count of measurement sets. */
632   
633    /* Wait for 100 seconds until data from all ELS3 controllers arrive. */
634        wsp_res = eh_wait_on_rsp_complete( 100000 );
635
636        if ( wsp_res != EH_WRES_OK )
637        {
638                printf ( "eh_wait_on_rsp_complete(): " );
639
640                if ( wsp_res == EH_WRES_TIMEOUT )
641                {
642                        printf ( "Timeout elapsed ...\n" );
643                }
644                else if ( wsp_res == EH_WRES_EXIT )
645                {
646                        printf ( "Some ELS3 has exited ...\n" );
647                }
648                else
649                {
650                        printf ( "Unknown error [%d] ...\n", wsp_res );
651                }
652                exit(-1);
653        }
654
655        /* This will copy the detector data out. It is needed by the
656           Matlab HRDS version due to its internal structure - realised
657           signal plans are read asynchronously and later. The value
658       of `count` reports the number of data sets that will be
659       returned by the call to `eh_read_realised_sp()`. This coount
660       will be at least 1 but it may be higher in cases where the
661       controller reports measurements in short intervals but we are
662       reading them less frequently. */
663        count = eh_copy_out_measurements ();
664
665        printf ( "got %d measurements from controllers ...", count );
666
667        /* Read realised signal plan from shared memory. */
668        if ( eh_read_realised_sp( &p_rsp ) == EH_RES_OK )
669        {
670                printf("\nsuccesfully read data from controllers\n" );
671        }
672        else
673        {
674                printf(" but got no data ???\n");
675        }
676
677        /* Finally we will also read the last statistical information
678           from the VGS interface. */
679        vgs_get_last_stats ( &sections_stats );
680}
681
682string AimsunDS::int_to_string(int const i)
683{
684        std::stringstream ss;
685        ss << i;
686        if (i<10)
687                return "0" + ss.str();
688        else
689                return ss.str();
690}
Note: See TracBrowser for help on using the browser.