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

Revision 1123, 23.6 kB (checked in by prikryl, 14 years ago)

Provide queues by lanes rather than by signal groups.

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