Skip to content

Commit 65b50a7

Browse files
author
Lara CODECA
committed
PyPML now uses numpy.random.RandomState and the time has been removed from the init.
- Readme updated, - all examples updated with seed and time removed, - random grid example fixed (buses now last 1h and not 24h) - example for the use of uncertainty added.
1 parent cf2f20a commit 65b50a7

7 files changed

Lines changed: 179 additions & 27 deletions

File tree

README.rst

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,13 @@ December 5-7, 2018, Taipei, Taiwan.
1111

1212
--------
1313
Reqirements:
14-
* It requires at least [SUMO 1.0.0](https://github.com/eclipse/sumo/tree/v1_0_0).
15-
* It requires at least [SUMO 1.0.1](https://github.com/eclipse/sumo/tree/v1_0_1)
16-
if multi-threading is needed.
14+
* It requires at least [SUMO 1.0.1](https://github.com/eclipse/sumo/tree/v1_0_1).
1715

1816
Tested with:
1917
* Eclipse SUMO Version 1.1.0
2018
Build features: Linux-4.18.0-3-amd64 x86_64 GNU 8.2.0 Release Proj GUI GDAL FFmpeg OSG GL2PS SWIG
2119
* Eclipse SUMO Version 1.0.1
2220
Build features: Linux-4.18.0-1-amd64 Proj GUI GDAL FFmpeg OSG GL2PS SWIG
23-
* Eclipse SUMO Version 1.0.0
24-
Build features: Linux-4.18.0-1-amd64 Proj GUI GDAL FFmpeg OSG GL2PS SWIG
25-
2621

2722
Installation:
2823
* Install: `pip3 install .` from the root directory, or `python3 setup.py install`
@@ -31,11 +26,13 @@ Installation:
3126
Examples:
3227
* Given the ~under development~ status of the project, examples are provided.
3328
* examples/simple.example.py
34-
* examples/subscriptions.example.py
35-
* examples/random_grid is a more complex scenario than test_grid.
29+
* examples/subscriptions.example.py (Subscription usage)
30+
* examples/uncert.example.py (Uncertainty usage)
31+
* examples/random.grid.example.py applies the simple.example.py to random_grid,
32+
a more complex scenario than test_grid.
3633

3734
Important:
38-
* PyPML behavior in case of multiple TraCI servers is umpredictable due to how the subscription are
35+
* PyPML behavior in case of multiple TraCI servers is unpredictable due to how the subscriptions are
3936
implemented, to work around this issue we provide functions to retrieve vehicle and simulation
4037
subscriptions from the library: `get_traci_vehicle_subscriptions` and
4138
`get_traci_simulation_subscriptions`

examples/random.grid.example.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,10 @@ def _main():
3737
""" Example of parking management in SUMO. """
3838

3939
## TESTED WITH: SUMO 1.1.0
40-
traci.start(['/home/drone/Applications/SUMO/sumo-1.1.0/bin/sumo',
41-
'-c', 'random_grid/random.sumocfg'], port=42041)
42-
## Running with the last-monday development version
43-
# traci.start(['sumo-gui', '-c', 'test_scenario/sumo.simple.cfg'], port=42041)
40+
traci.start(['sumo', '-c', 'random_grid/random.sumocfg'], port=42043)
4441

4542
parking_monitor_options = {
43+
'seed': 42,
4644
'addStepListener': True,
4745
'logging': {
4846
'stdout': False,
@@ -59,7 +57,7 @@ def _main():
5957
},
6058
}
6159

62-
monitor = ParkingMonitor(traci, parking_monitor_options, 383.0)
60+
monitor = ParkingMonitor(traci, parking_monitor_options)
6361
# parking travel time structure initialized
6462
monitor.compute_parking_travel_time()
6563

examples/random_grid/rou/buses.flows.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<stop busStop="busStop_3083_1_22" duration="30.00" until="233.25"/>
99
<stop busStop="busStop_-4682_1_24" duration="30.00" until="294.75"/>
1010
</route>
11-
<flow id="bus:1_eastbound" type="bus" route="bus:1_eastbound" begin="0.0" end="86400" period="300" line="Bus1-EastBound" >
11+
<flow id="bus:1_eastbound" type="bus" route="bus:1_eastbound" begin="0.0" end="3600" period="300" line="Bus1-EastBound" >
1212
<param key="name" value="Bus1-EastBound"/>
1313
</flow>
1414

@@ -19,7 +19,7 @@
1919
<stop busStop="busStop_-1016_1_10" duration="30.00" until="216.75"/>
2020
<stop busStop="busStop_402_1_8" duration="30.00" until="283.50"/>
2121
</route>
22-
<flow id="bus:1_westbound" type="bus" route="bus:1_westbound" begin="0.0" end="86400" period="300" line="Bus1-WestBound" >
22+
<flow id="bus:1_westbound" type="bus" route="bus:1_westbound" begin="0.0" end="3600" period="300" line="Bus1-WestBound" >
2323
<param key="name" value="Bus1-WestBound"/>
2424
</flow>
2525

@@ -32,7 +32,7 @@
3232
<stop busStop="busStop_4675_1_16" duration="30.00" until="356.50"/>
3333
<stop busStop="busStop_7051_1_18" duration="30.00" until="409.50"/>
3434
</route>
35-
<flow id="bus:2_northbound" type="bus" route="bus:2_northbound" begin="0.0" end="86400" period="300" line="Bus2-NorthBound" >
35+
<flow id="bus:2_northbound" type="bus" route="bus:2_northbound" begin="0.0" end="3600" period="300" line="Bus2-NorthBound" >
3636
<param key="name" value="Bus2-NorthBound"/>
3737
</flow>
3838

@@ -45,7 +45,7 @@
4545
<stop busStop="busStop_400_1_3" duration="30.00" until="356.50"/>
4646
<stop busStop="busStop_5517_1_1" duration="30.00" until="435.75"/>
4747
</route>
48-
<flow id="bus:2_southbound" type="bus" route="bus:2_southbound" begin="0.0" end="86400" period="300" line="Bus2-SouthBound" >
48+
<flow id="bus:2_southbound" type="bus" route="bus:2_southbound" begin="0.0" end="3600" period="300" line="Bus2-SouthBound" >
4949
<param key="name" value="Bus2-SouthBound"/>
5050
</flow>
5151
</routes>

examples/simple.example.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def _main():
5656
},
5757
}
5858

59-
monitor = ParkingMonitor(traci, parking_monitor_options, 0.0)
59+
monitor = ParkingMonitor(traci, parking_monitor_options)
6060
# parking travel time structure initialized
6161
monitor.compute_parking_travel_time()
6262

@@ -69,7 +69,7 @@ def _main():
6969
## the vehicle is not in the simulation anymore
7070
continue
7171
if vehicle['stopped']:
72-
## the vehicle is stopped and it does not require additional
72+
## the vehicle is stopped and it does not require additional
7373
## parking changes at least for the moment
7474
continue
7575
if not vehicle['edge'] or ':' in vehicle['edge']:

examples/subscriptions.example.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def _main():
4141
traci.start(['sumo', '-c', 'test_scenario/sumo.subscriptions.cfg'], port=42042)
4242

4343
parking_monitor_options = {
44+
'seed': 42,
4445
'addStepListener': True,
4546
'logging': {
4647
'stdout': False,
@@ -69,7 +70,7 @@ def _main():
6970
},
7071
}
7172

72-
monitor = ParkingMonitor(traci, parking_monitor_options, 0.0)
73+
monitor = ParkingMonitor(traci, parking_monitor_options)
7374
# parking travel time structure initialized
7475
monitor.compute_parking_travel_time()
7576

@@ -84,7 +85,7 @@ def _main():
8485
## the vehicle is not in the simulation anymore
8586
continue
8687
if vehicle['stopped']:
87-
## the vehicle is stopped and it does not require additional
88+
## the vehicle is stopped and it does not require additional
8889
## parking changes at least for the moment
8990
continue
9091
if vehicle['id'] in vehicles_with_subscriptions:

examples/uncert.example.py

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#!/usr/bin/env python3
2+
3+
""" Example of usage of PyPML.
4+
5+
Python Parking Monitor Library (PyPML)
6+
Copyright (C) 2018
7+
Lara CODECA
8+
9+
This program is free software: you can redistribute it and/or modify
10+
it under the terms of the GNU General Public License as published by
11+
the Free Software Foundation, either version 3 of the License, or
12+
(at your option) any later version.
13+
14+
This program is distributed in the hope that it will be useful,
15+
but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
GNU General Public License for more details.
18+
19+
You should have received a copy of the GNU General Public License
20+
along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
"""
22+
23+
import logging
24+
import os
25+
import sys
26+
import traceback
27+
from pypml import ParkingMonitor
28+
29+
# """ Import SUMO library """
30+
if 'SUMO_TOOLS' in os.environ:
31+
sys.path.append(os.environ['SUMO_TOOLS'])
32+
import traci
33+
else:
34+
sys.exit("Please declare environment variable 'SUMO_TOOLS'")
35+
36+
def _main():
37+
""" Example of parking management in SUMO. """
38+
39+
## TESTED WITH: SUMO 1.1.0
40+
traci.start(['sumo', '-c', 'test_scenario/sumo.simple.cfg'], port=42044)
41+
42+
parking_monitor_options = {
43+
'seed': 42,
44+
'addStepListener': True,
45+
'logging': {
46+
'stdout': False,
47+
'filename': 'uncert.example.log',
48+
'level': logging.DEBUG,
49+
},
50+
'sumo_parking_file': 'test_scenario/parkings.small.add.xml',
51+
'blacklist': [],
52+
'vclasses': {'truck', 'passenger', 'motorcycle'},
53+
'generic_conf': [
54+
{
55+
'cond': ['<', 'total_capacity', 25],
56+
'set_to': [
57+
['uncertainty', {
58+
'mu': 0.0,
59+
'sigma': ['*', 'total_capacity', 0.10]
60+
}
61+
],
62+
],
63+
},
64+
],
65+
'specific_conf': {},
66+
'subscriptions': {
67+
'only_parkings': True,
68+
},
69+
}
70+
71+
monitor = ParkingMonitor(traci, parking_monitor_options)
72+
# parking travel time structure initialized
73+
monitor.compute_parking_travel_time()
74+
75+
while traci.simulation.getMinExpectedNumber() > 0:
76+
traci.simulationStep()
77+
78+
## PARKING OPTIMIZATION
79+
for vehicle in monitor.get_vehicle_iterator():
80+
if vehicle['arrived']:
81+
## the vehicle is not in the simulation anymore
82+
continue
83+
if vehicle['stopped']:
84+
## the vehicle is stopped and it does not require additional
85+
## parking changes at least for the moment
86+
continue
87+
if not vehicle['edge'] or ':' in vehicle['edge']:
88+
## the vehicle is on an intersection and the change would not be safe.
89+
continue
90+
if vehicle['stops']:
91+
_, _, stopping_place, stop_flags, _, _ = vehicle['stops'][0]
92+
if monitor.is_parking_area(stop_flags):
93+
### OPTIMIZE VEHICLE
94+
availability = monitor.get_free_places(stopping_place,
95+
vclass=vehicle['vClass'],
96+
with_projections=False,
97+
with_uncertainty=True)
98+
if availability < 1:
99+
alternatives = monitor.get_closest_parkings(stopping_place, num=25)
100+
for trtime, alt in alternatives:
101+
alt_availability = monitor.get_free_places(
102+
alt, vclass=vehicle['vClass'],
103+
with_projections=False, with_uncertainty=True)
104+
print(trtime, alt, alt_availability)
105+
if alt_availability > 1:
106+
## reroute vehicle
107+
route = None
108+
try:
109+
edge = monitor.get_parking_access(alt).split('_')[0]
110+
route = traci.simulation.findRoute(
111+
vehicle['edge'], edge, vType=vehicle['vClass'])
112+
except traci.exceptions.TraCIException:
113+
route = None
114+
115+
if route and len(route.edges) >= 2:
116+
try:
117+
traci.vehicle.rerouteParkingArea(vehicle['id'], alt)
118+
print("""Vehicle {} is going to be rerouted from {} """
119+
"""[{}] to {} [{}].""".format(vehicle['id'],
120+
stopping_place,
121+
availability, alt,
122+
alt_availability))
123+
except traci.exceptions.TraCIException:
124+
print([monitor.get_parking_access(alt), route])
125+
raise
126+
break
127+
128+
if __name__ == '__main__':
129+
## ======================== PROFILER ======================== ##
130+
import cProfile, pstats, io
131+
profiler = cProfile.Profile()
132+
profiler.enable()
133+
## ======================== PROFILER ======================== ##
134+
135+
try:
136+
_main()
137+
except traci.exceptions.TraCIException:
138+
exc_type, exc_value, exc_traceback = sys.exc_info()
139+
traceback.print_exception(exc_type, exc_value, exc_traceback, limit=10, file=sys.stdout)
140+
finally:
141+
traci.close()
142+
## ======================== PROFILER ======================== ##
143+
profiler.disable()
144+
results = io.StringIO()
145+
pstats.Stats(profiler, stream=results).sort_stats('cumulative').print_stats(25)
146+
print(results.getvalue())
147+
## ======================== PROFILER ======================== ##

pypml/pypml.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121
import logging
2222
import operator
2323
import os
24-
import random
2524
import sys
2625
import xml.etree.ElementTree
2726

27+
from numpy.random import RandomState
28+
2829
# """ Import TraCI library """
2930
if 'SUMO_TOOLS' in os.environ:
3031
sys.path.append(os.environ['SUMO_TOOLS'])
@@ -39,6 +40,7 @@ class ParkingMonitor(traci.StepListener):
3940

4041
_logger = None
4142
_options = None
43+
_random = None
4244

4345
_parking_db = dict()
4446
_routers_db = dict()
@@ -89,16 +91,16 @@ def _logs(self):
8991
else:
9092
self._logger = None
9193

92-
def __init__(self, traci_handler, options, time=0.0):
94+
def __init__(self, traci_handler, options):
9395
""" Initialize the knowlegde base for the parking monitor.
9496
9597
traci_handler: already initialized TraCI socket that is going to be used by PyPML
9698
options: in order to reduce the number of parameters and increase the flexibility,
9799
the complete initialization is done using a dict()
98-
time: beginning of the simulation in seconds (for statistical and logging purposes)
99100
100101
Options format:
101102
{
103+
'seed': Integer. Initialization seed for numpy.random.RandomState.
102104
'addStepListener': Boolean. Ff True, pypml is added as step listener in SUMO.
103105
In case it's False the function step() must be called by hand every
104106
simulation step.
@@ -163,11 +165,18 @@ def __init__(self, traci_handler, options, time=0.0):
163165

164166
self._options = options
165167

168+
## Random generator initialization
169+
if 'seed' in options:
170+
self._random = RandomState(seed=options['seed'])
171+
else:
172+
self._random = RandomState()
173+
166174
## Logs initialization
167175
self._logs()
168176

169177
## TraCI initialization
170178
self._traci_handler = traci_handler
179+
time = self._traci_handler.simulation.getTime()
171180

172181
## Read parkings and routers from SUMO add.xml
173182
self._load_parkings_and_routers()
@@ -835,8 +844,8 @@ def get_free_places(self, parking, with_uncertainty=False,
835844

836845
error = 0
837846
if with_uncertainty:
838-
error = round(random.normalvariate(self._parking_db[parking]['uncertainty']['mu'],
839-
self._parking_db[parking]['uncertainty']['sigma']))
847+
error = round(self._random.normal(self._parking_db[parking]['uncertainty']['mu'],
848+
self._parking_db[parking]['uncertainty']['sigma']))
840849

841850
current_capacity = dict()
842851
for key, capacity in self._parking_db[parking]['capacity_by_class'].items():

0 commit comments

Comments
 (0)