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

Revision 841, 17.5 kB (checked in by smidl, 14 years ago)

Specify sizes in AimsunDS

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