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

Revision 855, 17.4 kB (checked in by smidl, 14 years ago)

log_level

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  /* Initialise the pointer to received data. */
307  p_rsp = NULL;
308}
309
310void AimsunDS::initVGS (
311        const vgs_headway_mode headway,
312        const string &entrancePath,
313        const string &sectionStatsPath,
314        const string &globalStatsPath
315        )
316{
317    int res;
318       
319        /* Pass information about entrance sections to VGS API (and so to the
320       GetramVGS extension that will be generating vehicles for these
321           entrances). */
322    vgs_set_entrance_sections ( EntranceSections, NumEntranceSections );
323   
324    /* Check the validity of the headway mode. */
325    res = vgs_is_valid_headway_mode ( headway );
326    if ( !res )
327        {
328        fprintf ( stderr, "Invalid headway mode '%d'\n", headway );
329                exit ( -1 );
330        }
331   
332    /* Specify where to find the CSV with vehicle entrances and which
333           headway mode to use for generating vehicle flows. */
334        vgs_generate_vehicles ( entrancePath.c_str(), headway );
335   
336    /* Pass to VGS API information about section identifiers we want to
337       collect statistics for (and VGS will pass it to the GetramVGS
338       extension). */ 
339        vgs_set_stats_sections ( StatIds, NumStatIds );
340   
341    /* Specify where to store CSV files with statistical data. */
342        vgs_set_stats_file_names ( sectionStatsPath.c_str(), globalStatsPath.c_str() );
343   
344    /* Specify the maximum queuing speed in kmph. */
345    vgs_set_max_qspeed ( 3.6f );
346   
347    /* Unlock the semaphore blocking Aimsun from execution. */
348    vgs_unlock_aimsun();
349}
350
351void AimsunDS::getdata ( vec &dt ) const
352{
353        /* Return the last data. */
354        printf ( "\n\tAimsunDS::getdata() starting\n" );
355
356        if ( p_rsp == NULL )
357        {
358                fprintf ( stderr, "ERROR: AimsunDS::getdata() - no data available yet!\n" );
359                return;
360        }
361
362        /* Loop over all measurement sets (currently we will deliver
363        just the last one, but this will surely change. */
364        for ( int i = 0; i < p_rsp->count; i++)
365        {
366                det_stats * ds_ptr = p_rsp->dets + i;
367                sp_stats *  sp_ptr = p_rsp->sps  + i;
368
369                printf ( "\tRealised signal plans:\n" );
370
371                /* Loop over all intersections and fill in signal plan
372                data. */
373                for ( int j = 0; j < sp_ptr->count ; j++ )
374                {
375                        sp_stattab * dat_ptr = sp_ptr->splans + j;
376                        int          offset  = SignalPlanOffsets[j];
377
378                        printf ( "\t[%3d] t=%6ds ", j, dat_ptr->global_time );
379
380                        for ( int k = 0 ; k < dat_ptr->num_siggroups ; k++ )
381                        {
382                                dt[k+offset] = dat_ptr->green_time[k];
383                                printf ( "%3d ", dat_ptr->green_time[k] );
384                        }
385                        printf ( "\n" );
386                }
387
388                printf ( "\n\tDetector data:\n" );
389
390                /* Loop over all intersections and fill in the
391                detector measurements. */
392                for ( int j = 0 ; j < ds_ptr->count ; j++ )
393                {
394                        det_aggreg_table * dat_ptr = ds_ptr->stats + j;
395                        int                ioffset  = IntensityOffsets[j];
396                        int                ooffset  = OccupancyOffsets[j];
397
398                        printf ( "\t[%3d] t=%6ds ", j, dat_ptr->global_time );
399
400                        for ( int k = 0 ; k < dat_ptr->num_det ; k++ )
401                        {
402                                dt[k+ioffset] = dat_ptr->dt_intensity[k];
403                                dt[k+ooffset] = dat_ptr->dt_occupancy[k];
404                                printf ( "{%2d/%2d} ",
405                                        dat_ptr->dt_intensity[k], dat_ptr->dt_occupancy[k] );
406                        }
407                        printf ( "\n" );
408                }
409        }
410        printf ( "\tAimsunDS::getdata() finished\n" );
411}
412
413
414void AimsunDS::write ( vec &ut )
415{
416    eh_res     sp_res;   /* Result code from write operation. */
417        eh_hrdels3 hrdsp[2]; /* Signal plan for two intersections. */
418   
419    /* Check that the length of the vector is correct. */
420    if ( ut.size() != utsize )
421    {
422      fprintf ( stderr, "Incorrect length of data vector (should be %d)", utsize );
423      exit(-1);
424    }
425    /* Check that the phase lengths sum to correct cycle time. */
426    /*
427        if ( ut[0]+ut[1]+ut[2] != 80 )
428    {
429      fprintf ( stderr, "Intersection 495: F1+F2+F3 != Tc (should be 80)" );
430      exit(-1);
431    }
432    if ( ut[3]+ut[4]+ut[5] != 80 )
433    {
434      fprintf ( stderr, "Intersection 601: F1+F2+F3 != Tc (should be 80)" );
435      exit(-1);
436    }*/
437
438    hrdsp[0].id = 495;
439    hrdsp[0].sp.cycle_time   = int ( ut[0] );
440        hrdsp[0].sp.offset       = int ( ut[1] );
441        hrdsp[0].sp.phase_len[0] = int ( ut[2] );
442    hrdsp[0].sp.phase_len[1] = int ( ut[3] );
443    hrdsp[0].sp.phase_len[2] = int ( ut[4] );
444    hrdsp[0].sp.phase_len[3] = -1;
445
446    hrdsp[1].id = 601;
447    hrdsp[1].sp.cycle_time   = int ( ut[ 0] );
448    hrdsp[1].sp.offset       = int ( ut[ 8] );
449    hrdsp[1].sp.phase_len[0] = int ( ut[ 9] );
450    hrdsp[1].sp.phase_len[1] = int ( ut[10] );
451    hrdsp[1].sp.phase_len[2] = int ( ut[11] );
452    hrdsp[1].sp.phase_len[3] = -1;
453
454        /* Write new signal plan to the shared memory of active controllers. */
455    sp_res = eh_write_hrd_data( hrdsp, 2 );
456
457        if ( sp_res != EH_RES_OK )
458        {
459                printf ( "eh_write_hrd_data(): " );
460                if ( sp_res == EH_RES_WCNT )
461                {
462                        printf ( "Wrong count of ELS3...\n" );
463                }
464                else if ( sp_res == EH_RES_WRID )
465                {
466                        printf ( "Wrong intersection ID...\n" );
467                }
468                else
469                {
470                        printf ( "Unknown error [%d] ...\n", sp_res );
471                }
472        }
473}
474
475
476void AimsunDS::step()
477{
478        eh_wres      wsp_res;   /* Result code of the wait operation. */
479    int          count;         /* Count of measurement sets. */
480   
481    /* Wait for 100 seconds until data from all ELS3 controllers arrive. */
482        wsp_res = eh_wait_on_rsp_complete( 100000 );
483
484        if ( wsp_res != EH_WRES_OK )
485        {
486                printf ( "eh_wait_on_rsp_complete(): " );
487
488                if ( wsp_res == EH_WRES_TIMEOUT )
489                {
490                        printf ( "Timeout elapsed ...\n" );
491                }
492                else if ( wsp_res == EH_WRES_EXIT )
493                {
494                        printf ( "Some ELS3 has exited ...\n" );
495                }
496                else
497                {
498                        printf ( "Unknown error [%d] ...\n", wsp_res );
499                }
500                exit(-1);
501        }
502
503        /* This will copy the detector data out. It is needed by the
504           Matlab HRDS version due to its internal structure - realised
505           signal plans are read asynchronously and later. The value
506       of `count` reports the number of data sets that will be
507       returned by the call to `eh_read_realised_sp()`. This coount
508       will be at least 1 but it may be higher in cases where the
509       controller reports measurements in short intervals but we are
510       reading them less frequently. */
511        count = eh_copy_out_measurements ();
512
513        printf ( "got %d measurements from controllers ...", count );
514
515        /* Read realised signal plan from shared memory. */
516        if ( eh_read_realised_sp( &p_rsp ) == EH_RES_OK )
517        {
518                printf("\nsuccesfully read data from controllers\n" );
519        }
520        else
521        {
522                printf(" but got no data ???\n");
523        }
524}
Note: See TracBrowser for help on using the browser.