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

Revision 844, 17.5 kB (checked in by prikryl, 14 years ago)

Do not use ATL macros (ATL is not shipped with Visual Studio Express).

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