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

Revision 986, 18.2 kB (checked in by ondrak, 14 years ago)

added queues 601_Q1 and 601_Q2 to aimsun_ds.cpp
added function to count expected_density to LaneHandler?
added compulsory input_distances and output_distances to cfg
action_rv renamed to rv_action (to match convention)
some work on GreenWaveTrafficAgent?

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