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

Revision 927, 18.2 kB (checked in by smidl, 14 years ago)

traffic agents -- pro BDM > r904

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