Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/import/matsim/matsim_importPlans.py
169679 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2010-2025 German Aerospace Center (DLR) and others.
4
# This program and the accompanying materials are made available under the
5
# terms of the Eclipse Public License 2.0 which is available at
6
# https://www.eclipse.org/legal/epl-2.0/
7
# This Source Code may also be made available under the following Secondary
8
# Licenses when the conditions for such availability set forth in the Eclipse
9
# Public License 2.0 are satisfied: GNU General Public License, version 2
10
# or later which is available at
11
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
14
# @file matsim_importPlans.py
15
# @author Jakob Erdmann
16
# @author Camillo Fillinger
17
# @date 2019-09-27
18
19
"""
20
Import person plans from MATSim
21
"""
22
from __future__ import absolute_import
23
from __future__ import print_function
24
25
import os
26
import sys
27
import subprocess
28
from xml.sax import saxutils
29
30
try:
31
from StringIO import StringIO
32
except ImportError:
33
from io import StringIO
34
35
if 'SUMO_HOME' in os.environ:
36
sys.path.append(os.path.join(os.environ['SUMO_HOME'], 'tools'))
37
sys.path.append(os.path.join(os.environ['SUMO_HOME'], 'tools', 'route'))
38
import sumolib # noqa
39
import sort_routes
40
41
42
def get_options(args=None):
43
op = sumolib.options.ArgumentParser()
44
op.add_argument("-p", "--plan-file", category="input", required=True,
45
type=op.data_file, help="MATSim plan file (mandatory)")
46
op.add_argument("-o", "--output-file", category="input", required=True,
47
type=op.route_file, help="SUMO output route file (mandatory)")
48
op.add_argument("-n", "--net-file", category="input", type=op.net_file,
49
help="SUMO net file (mandatory for --repair or --remove-loops)")
50
op.add_argument("--vehicles-only", action="store_true", category="processing",
51
default=False, help="Import only vehicles instead of persons")
52
op.add_argument("--no-bikes", action="store_true", category="processing",
53
default=False, help="do not import bike trips")
54
op.add_argument("--no-rides", action="store_true", category="processing",
55
default=False, help="do not import ride trips")
56
op.add_argument("--repair", action="store_true", category="processing",
57
default=False, help="Repair routes after import (needs a SUMO net)")
58
op.add_argument("--remove-loops", action="store_true", category="processing",
59
default=False, help="Remove loops in routes after import (needs a SUMO net)")
60
op.add_argument("--prefer-coordinate", action="store_true", category="processing",
61
default=False, help="Use coordinates instead of link ids if both are given")
62
op.add_argument("--default-start", metavar="TIME", default="0:0:0", category="time",
63
help="default start time for the first activity")
64
op.add_argument("--default-end", metavar="TIME", default="24:0:0", category="time",
65
help="default end time for the last activity")
66
op.add_argument("--default-dur", metavar="TIME", default="1:0:0", category="time",
67
help="default duration for activities")
68
op.add_argument("-v", "--verbose", action="store_true", category="processing",
69
default=False, help="tell me what you are doing")
70
options = op.parse_args(args)
71
72
if not options.net_file and (options.repair or options.remove_loops):
73
op.print_help()
74
sys.exit()
75
76
return options
77
78
79
def getLocation(options, activity, attr, prj=None):
80
if activity.link and (not options.prefer_coordinate or not activity.x):
81
return '%s="%s"' % (attr, activity.link)
82
elif activity.x and activity.y:
83
if prj:
84
lon, lat = prj(activity.x, activity.y, inverse=True)
85
if attr == "edge":
86
return 'lon="%s" lat="%s"' % (lon, lat)
87
else:
88
return '%sLonLat="%s,%s"' % (attr, lon, lat)
89
else:
90
if attr == "edge":
91
return 'x="%s" y="%s"' % (activity.x, activity.y)
92
else:
93
return '%sXY="%s,%s"' % (attr, activity.x, activity.y)
94
else:
95
return None
96
97
98
def skipLeg(options, leg):
99
# walk and public transport are not relevant
100
if leg.mode.endswith("walk") or leg.mode == "pt":
101
return True
102
if options.no_rides and leg.mode == "ride":
103
return True
104
if options.no_bikes and leg.mode in ("bike", "bicycle"):
105
return True
106
return False
107
108
109
def writeLeg(outf, options, idveh, leg, start, end, types):
110
""" Write the vehicles and trips. """
111
if skipLeg(options, leg):
112
return
113
depart = leg.dep_time if options.vehicles_only else "triggered"
114
mode = ' type="%s"' % leg.mode if leg.mode else ""
115
if leg.mode:
116
types.add(leg.mode)
117
if leg.route is None or leg.route[0].distance == "NaN" or leg.mode in ("bike", "bicycle"):
118
outf.write(' <trip id="%s" depart="%s" %s %s%s/>\n'
119
% (idveh, depart, start, end, mode))
120
else:
121
outf.write(' <vehicle id="%s" depart="%s"%s>\n' % (idveh, depart, mode))
122
outf.write(' <route edges="%s"/>\n' % (leg.route[0].getText()))
123
outf.write(' </vehicle>\n')
124
125
126
def main(options):
127
128
prj = None
129
for attributes in sumolib.xml.parse(options.plan_file, 'attributes'):
130
for attribute in attributes.attribute:
131
if attribute.attr_name == "coordinateReferenceSystem":
132
projName = attribute.getText().strip()
133
try:
134
import pyproj
135
try:
136
prj = pyproj.Proj("EPSG:31468" if projName == "GK4" else projName)
137
except pyproj.exceptions.CRSError as e:
138
print("Warning: Could not interpret coordinate system '%s' (%s)" % (
139
projName, e), file=sys.stderr)
140
except ImportError:
141
print("Warning: install pyproj to support input with coordinates", file=sys.stderr)
142
143
persons = [] # (depart, xmlsnippet)
144
types = set()
145
for index, person in enumerate(sumolib.xml.parse(options.plan_file, 'person')):
146
outf = StringIO()
147
vehIndex = 0
148
plan = person.plan[0]
149
if len(plan.getChildList()) == 0:
150
continue
151
firstAct = plan.getChildList()[0]
152
depart = firstAct.start_time
153
if depart is None:
154
depart = options.default_start
155
attributes = person.attributes[0] if person.attributes else None
156
157
# write vehicles
158
vehicleslist = []
159
untillist = []
160
durations = []
161
lastAct = None
162
lastLeg = None
163
for item in plan.getChildList():
164
leg = None
165
idveh = "%s_%s" % (person.id, vehIndex)
166
if "act" in item.name: # act or activity
167
if lastLeg is not None:
168
leg = lastLeg
169
leg.dep_time = lastAct.end_time
170
writeLeg(outf, options, idveh, leg,
171
getLocation(options, lastAct, "from", prj),
172
getLocation(options, item, "to", prj), types)
173
lastLeg = None
174
# set missing end_time:
175
if not item.end_time:
176
if item.start_time and item.max_dur:
177
item.end_time = sumolib.miscutils.humanReadableTime(
178
sumolib.miscutils.parseTime(item.start_time) +
179
sumolib.miscutils.parseTime(item.max_dur)
180
)
181
elif item.start_time:
182
item.end_time = sumolib.miscutils.humanReadableTime(
183
sumolib.miscutils.parseTime(item.start_time) +
184
sumolib.miscutils.parseTime(options.default_dur)
185
)
186
elif item.max_dur and leg:
187
item.end_time = sumolib.miscutils.humanReadableTime(
188
sumolib.miscutils.parseTime(leg.dep_time) +
189
sumolib.miscutils.parseTime(options.default_dur) +
190
sumolib.miscutils.parseTime(item.max_dur)
191
)
192
lastAct = item
193
durations.append(item.max_dur if item.max_dur else options.default_dur)
194
if item.name == "leg":
195
if item.route is None:
196
lastLeg = item
197
else:
198
leg = item
199
start = 'from="%s"' % leg.route[0].start_link
200
end = 'to="%s"' % leg.route[0].end_link
201
writeLeg(outf, options, idveh, leg, start, end, types)
202
if leg:
203
untillist.append(leg.dep_time)
204
vehicleslist.append(idveh if leg.mode != "pt" else "pt")
205
vehIndex += 1
206
untillist.append(lastAct.end_time if lastAct.end_time else options.default_end)
207
208
# write person
209
if not options.vehicles_only:
210
vehIndex = 0
211
actIndex = 0
212
outf.write(' <person id="%s" depart="%s">\n' % (person.id, depart))
213
if attributes is not None:
214
for attr in attributes.attribute:
215
outf.write(' <param key="%s" value=%s/>\n' % (
216
attr.attr_name, saxutils.quoteattr(attr.getText())))
217
218
lastLeg = None
219
for item in plan.getChildList():
220
if "act" in item.name: # act or activity
221
end = getLocation(options, item, "to", prj)
222
if lastLeg is not None:
223
if lastLeg.mode == "non_network_walk":
224
pass
225
# outf.write(' <transship to="%s"/>\n' % item.link)
226
elif lastLeg.mode in ("walk", "transit_walk"):
227
outf.write(' <walk %s/>\n' % end)
228
elif lastLeg.mode == "pt":
229
outf.write(' <personTrip modes="public" %s/>\n' % end)
230
elif skipLeg(options, lastLeg):
231
outf.write(' <!-- ride lines="%s" %s mode="%s"/-->\n' % (
232
vehicleslist[vehIndex], end, lastLeg.mode))
233
else:
234
outf.write(' <ride lines="%s" %s/>\n' % (vehicleslist[vehIndex], end))
235
vehIndex += 1
236
until = untillist[vehIndex]
237
if until:
238
timing = 'until="%s"' % until
239
else:
240
timing = 'duration="%s"' % durations[actIndex]
241
outf.write(' <stop %s %s actType="%s"/>\n' %
242
(getLocation(options, item, "edge", prj), timing, item.type))
243
actIndex += 1
244
if item.name == "leg":
245
lastLeg = item
246
outf.write(' </person>\n')
247
persons.append((sumolib.miscutils.parseTime(depart), index, outf.getvalue()))
248
249
persons.sort()
250
tmpout = options.output_file + ".tmp"
251
with open(tmpout, 'w') as outf:
252
sumolib.writeXMLHeader(outf, root="routes")
253
for t in sorted(types):
254
vClass = ""
255
if t in ("bike", "bicycle"):
256
vClass = ' vClass="bicycle"'
257
outf.write(' <vType id="%s"%s/>\n' % (t, vClass))
258
for depart, index, xml in persons:
259
outf.write(xml)
260
outf.write('</routes>\n')
261
outf.close()
262
# use duarouter for sorting when --vehicles-only is set
263
if options.repair or options.remove_loops:
264
args = ["-n", options.net_file, "-a", tmpout, "-o", options.output_file]
265
args += ["--repair"] if options.repair else []
266
args += ["--remove-loops"] if options.remove_loops else []
267
args += ["--write-trips", "--write-trips.geo"] if options.prefer_coordinate else []
268
subprocess.call([sumolib.checkBinary("duarouter")] + args)
269
elif options.vehicles_only:
270
sort_routes.main([tmpout, '-o', options.output_file])
271
else:
272
os.rename(tmpout, options.output_file)
273
274
275
if __name__ == "__main__":
276
main(get_options())
277
278