20 package org.matsim.core.population.io;
22 import java.util.ArrayList;
24 import java.util.Objects;
25 import java.util.Stack;
27 import org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
61 import org.xml.sax.Attributes;
63 import com.google.inject.Inject;
72 class PopulationReaderMatsimV6
extends MatsimXmlParser implements MatsimReader {
73 private static final Logger log = LogManager.getLogger(PopulationReaderMatsimV6.class);
75 final static String POPULATION =
"population";
76 final static String PERSON =
"person";
77 final static String ATTRIBUTES =
"attributes";
78 private final static String ATTRIBUTE =
"attribute";
79 private final static String PLAN =
"plan";
80 private final static String ACT =
"activity";
81 private final static String LEG =
"leg";
82 private final static String ROUTE =
"route";
84 private final static String ATTR_POPULATION_DESC =
"desc";
85 final static String ATTR_PERSON_ID =
"id";
86 private final static String ATTR_PLAN_SCORE =
"score";
87 private final static String ATTR_PLAN_TYPE =
"type";
88 private final static String ATTR_PLAN_SELECTED =
"selected";
89 private final static String ATTR_ACT_TYPE =
"type";
90 private final static String ATTR_ACT_X =
"x";
91 private final static String ATTR_ACT_Y =
"y";
92 private static final String ATTR_ACT_Z =
"z";
93 private final static String ATTR_ACT_LINK =
"link";
94 private final static String ATTR_ACT_FACILITY =
"facility";
95 private final static String ATTR_ACT_STARTTIME =
"start_time";
96 private final static String ATTR_ACT_ENDTIME =
"end_time";
97 private final static String ATTR_ACT_MAXDUR =
"max_dur";
98 private final static String ATTR_LEG_MODE =
"mode";
99 private final static String ATTR_LEG_DEPTIME =
"dep_time";
100 private final static String ATTR_LEG_TRAVTIME =
"trav_time";
102 private static final String ATTR_ROUTE_STARTLINK =
"start_link";
103 private static final String ATTR_ROUTE_ENDLINK =
"end_link";
105 private final static String VALUE_YES =
"yes";
106 private final static String VALUE_NO =
"no";
107 private final static String VALUE_UNDEF =
"undef";
110 private final AttributesXmlReaderDelegate attributesReader =
new AttributesXmlReaderDelegate();
112 final Scenario scenario;
113 final Population plans;
114 private final String externalInputCRS;
116 Person currperson = null;
117 private Plan currplan = null;
118 private Activity curract = null;
119 private Leg currleg = null;
120 private Route currRoute = null;
121 private String routeDescription = null;
124 private final String targetCRS;
125 private CoordinateTransformation coordinateTransformation =
new IdentityTransformation();
127 private Activity prevAct = null;
130 PopulationReaderMatsimV6(
131 final String inputCRS,
132 final String targetCRS,
133 final Scenario scenario) {
134 super(ValidationType.DTD_ONLY);
135 this.externalInputCRS = inputCRS;
136 this.targetCRS = targetCRS;
137 this.scenario = scenario;
138 this.plans = scenario.getPopulation();
139 if (targetCRS != null && externalInputCRS !=null) {
140 this.coordinateTransformation = TransformationFactory.getCoordinateTransformation(externalInputCRS, targetCRS);
141 ProjectionUtils.putCRS(this.plans, targetCRS);
145 public ObjectAttributesConverter getObjectAttributesConverter()
147 return attributesReader.getObjectAttributesConverter();
150 public void putAttributeConverter(
final Class<?> clazz , AttributeConverter<?> converter ) {
151 attributesReader.putAttributeConverter( clazz , converter );
155 public void putAttributeConverters(
final Map<Class<?>, AttributeConverter<?>> converters ) {
156 attributesReader.putAttributeConverters( converters );
160 public void startTag(
final String name,
final Attributes atts,
final Stack<String> context) {
163 startPopulation(atts);
169 switch( context.peek() ) {
171 currAttributes = scenario.getPopulation().getAttributes();
174 currAttributes = currperson.getAttributes();
177 currAttributes = currplan.getAttributes();
180 currAttributes = curract.getAttributes();
190 attributesReader.startTag( name , atts ,context , currAttributes );
205 throw new RuntimeException(
this +
"[tag=" + name +
" not known or not supported]");
210 public void endTag(
final String name,
final String content,
final Stack<String> context) {
213 this.plans.addPerson(this.currperson);
214 this.currperson = null;
217 this.attributesReader.endTag( name , content , context );
220 switch( context.peek() ) {
222 String inputCRS = ProjectionUtils.getCRS(scenario.getPopulation());
224 if (inputCRS != null && targetCRS != null) {
225 if (externalInputCRS != null) {
227 log.warn(
"coordinate transformation defined both in config and in input file: setting from input file will be used");
229 coordinateTransformation = TransformationFactory.getCoordinateTransformation(inputCRS, targetCRS);
230 ProjectionUtils.putCRS(scenario.getPopulation(), targetCRS);
234 Object routingMode = currAttributes.getAttribute(TripStructureUtils.routingMode);
235 if (Objects.nonNull(routingMode) && routingMode instanceof String) {
236 currAttributes.removeAttribute(TripStructureUtils.routingMode);
237 currleg.setRoutingMode((String) routingMode);
239 AttributesUtils.copyTo(currAttributes, currleg.getAttributes());
244 if (this.currplan.getPlanElements() instanceof ArrayList<?>) {
245 ((ArrayList<?>) this.currplan.getPlanElements()).trimToSize();
247 this.currplan = null;
250 this.prevAct = this.curract;
259 private void startPopulation(
final Attributes atts) {
260 this.plans.setName(atts.getValue(ATTR_POPULATION_DESC));
263 private void startPerson(
final Attributes atts) {
264 this.currperson = PopulationUtils.getFactory().createPerson(Id.create(atts.getValue(ATTR_PERSON_ID), Person.class));
267 private void startPlan(
final Attributes atts) {
268 String sel = atts.getValue(ATTR_PLAN_SELECTED);
270 if (VALUE_YES.equals(sel)) {
273 else if (VALUE_NO.equals(sel)) {
277 throw new IllegalArgumentException(
278 "Attribute 'selected' of Element 'Plan' is neither 'yes' nor 'no', is " + sel);
280 this.routeDescription = null;
281 this.currplan = PersonUtils.createAndAddPlan(this.currperson, selected);
283 String scoreString = atts.getValue(ATTR_PLAN_SCORE);
284 if (scoreString != null) {
285 double score = Double.parseDouble(scoreString);
286 this.currplan.setScore(score);
289 String type = atts.getValue(ATTR_PLAN_TYPE);
291 this.currplan.setType(type);
295 private void startAct(
final Attributes atts) {
296 final String actType = atts.getValue(ATTR_ACT_TYPE);
297 final boolean isStageActivity = StageActivityTypeIdentifier.isStageActivity(actType);
298 if (atts.getValue(ATTR_ACT_FACILITY) != null) {
299 final Id<ActivityFacility> facilityId = Id.create(atts.getValue(ATTR_ACT_FACILITY), ActivityFacility.class);
300 if (isStageActivity) {
301 this.curract = PopulationUtils.createInteractionActivityFromFacilityId(actType, facilityId);
303 this.curract = PopulationUtils.createActivityFromFacilityId(actType, facilityId);
305 if (atts.getValue(ATTR_ACT_LINK) != null) {
306 final Id<Link> linkId = Id.create(atts.getValue(ATTR_ACT_LINK), Link.class);
307 this.curract.setLinkId(linkId);
309 if ((atts.getValue(ATTR_ACT_X) != null) && (atts.getValue(ATTR_ACT_Y) != null)) {
310 final Coord coord = parseCoord(atts);
311 this.curract.setCoord(coord);
313 }
else if (atts.getValue(ATTR_ACT_LINK) != null) {
314 Id<Link> linkId = Id.create(atts.getValue(ATTR_ACT_LINK), Link.class);
315 if (isStageActivity) {
316 this.curract = PopulationUtils.createInteractionActivityFromLinkId(actType, linkId);
318 this.curract = PopulationUtils.createActivityFromLinkId(actType, linkId);
320 if ((atts.getValue(ATTR_ACT_X) != null) && (atts.getValue(ATTR_ACT_Y) != null)) {
321 final Coord coord = parseCoord(atts);
322 this.curract.setCoord(coord);
324 }
else if ((atts.getValue(ATTR_ACT_X) != null) && (atts.getValue(ATTR_ACT_Y) != null)) {
325 final Coord coord = parseCoord(atts);
326 if (isStageActivity) {
327 this.curract = PopulationUtils.createInteractionActivityFromCoord(actType, coord);
329 this.curract = PopulationUtils.createActivityFromCoord(actType, coord);
332 throw new IllegalArgumentException(
"In this version of MATSim either the facility, the link or the coords must be specified for an Act.");
335 final OptionalTime startTime = Time.parseOptionalTime(atts.getValue(ATTR_ACT_STARTTIME));
336 final OptionalTime duration = Time.parseOptionalTime(atts.getValue(ATTR_ACT_MAXDUR));
337 final OptionalTime endTime = Time.parseOptionalTime(atts.getValue(ATTR_ACT_ENDTIME));
340 if (isStageActivity && (startTime.isDefined() || endTime.isDefined() || duration.isUndefined() || duration.seconds() > 0.0)) {
341 this.curract = PopulationUtils.createActivity(this.curract);
343 startTime.ifDefinedOrElse(this.curract::setStartTime, this.curract::setStartTimeUndefined);
344 duration.ifDefinedOrElse(this.curract::setMaximumDuration, this.curract::setMaximumDurationUndefined);
345 endTime.ifDefinedOrElse(this.curract::setEndTime, this.curract::setEndTimeUndefined);
347 this.currplan.addActivity(this.curract);
349 if (this.routeDescription != null) {
354 private Coord parseCoord(Attributes atts) {
355 if ( atts.getValue( ATTR_ACT_Z ) != null ) {
356 return coordinateTransformation.transform(
358 Double.parseDouble(atts.getValue(ATTR_ACT_X)),
359 Double.parseDouble(atts.getValue(ATTR_ACT_Y)),
360 Double.parseDouble(atts.getValue(ATTR_ACT_Z)) ) );
363 return coordinateTransformation.transform(
365 Double.parseDouble(atts.getValue(ATTR_ACT_X)),
366 Double.parseDouble(atts.getValue(ATTR_ACT_Y))));
370 private void finishLastRoute() {
371 Id<Link> startLinkId = null;
372 if (this.currRoute.getStartLinkId() != null) {
373 startLinkId = this.currRoute.getStartLinkId();
374 }
else if (this.prevAct.getLinkId() != null) {
375 startLinkId = this.prevAct.getLinkId();
377 Id<Link> endLinkId = null;
378 if (this.currRoute.getEndLinkId() != null) {
379 endLinkId = this.currRoute.getEndLinkId();
380 }
else if (this.curract != null && this.curract.getLinkId() != null) {
381 endLinkId = this.curract.getLinkId();
384 this.currRoute.setStartLinkId(startLinkId);
385 this.currRoute.setEndLinkId(endLinkId);
386 this.currRoute.setRouteDescription(this.routeDescription.trim());
389 if (Double.isNaN(
this.currRoute.getDistance())) {
390 if (this.currRoute instanceof NetworkRoute) {
391 if (!this.scenario.getNetwork().getLinks().isEmpty()) {
392 this.currRoute.setDistance(RouteUtils.calcDistanceExcludingStartEndLink((NetworkRoute)
this.currRoute,
this.scenario.getNetwork()));
395 Coord fromCoord = getCoord(this.prevAct);
396 Coord toCoord = getCoord(this.curract);
397 if (fromCoord != null && toCoord != null) {
398 double dist = CoordUtils.calcEuclideanDistance(fromCoord, toCoord);
399 if ( this.scenario.getConfig().routing().
400 getModeRoutingParams().containsKey( this.currleg.getMode() ) ) {
401 double estimatedNetworkDistance = dist * this.scenario.getConfig().routing().
402 getModeRoutingParams().get( this.currleg.getMode() ).getBeelineDistanceFactor() ;
403 this.currRoute.setDistance(estimatedNetworkDistance);
408 if (this.currRoute.getTravelTime().isUndefined()) {
409 this.currleg.getTravelTime().ifDefined(this.currRoute::setTravelTime);
412 this.routeDescription = null;
413 this.currRoute = null;
417 private Coord getCoord(Activity activity) {
419 if (activity == null) {
423 if (activity.getCoord() != null) {
424 fromCoord = activity.getCoord();
426 if (!this.scenario.getNetwork().getLinks().isEmpty()) {
427 fromCoord = this.scenario.getNetwork().getLinks().get(activity.getLinkId()).getCoord();
435 private void startLeg(
final Attributes atts) {
436 if (this.routeDescription != null) {
440 String mode = atts.getValue(ATTR_LEG_MODE);
441 if (VALUE_UNDEF.equals(mode)) {
444 this.currleg = PopulationUtils.createAndAddLeg( this.currplan, mode.intern() );
445 Time.parseOptionalTime(atts.getValue(ATTR_LEG_DEPTIME))
446 .ifDefinedOrElse(currleg::setDepartureTime, currleg::setDepartureTimeUndefined);
447 Time.parseOptionalTime(atts.getValue(ATTR_LEG_TRAVTIME))
448 .ifDefinedOrElse(currleg::setTravelTime, currleg::setTravelTimeUndefined);
454 private void startRoute(
final Attributes atts) {
455 String startLinkId = atts.getValue(ATTR_ROUTE_STARTLINK);
456 String endLinkId = atts.getValue(ATTR_ROUTE_ENDLINK);
457 String routeType = atts.getValue(
"type");
459 if (routeType == null) {
460 String legMode = this.currleg.getMode();
461 if (
"pt".equals(legMode)) {
462 routeType =
"experimentalPt1";
463 }
else if (
"car".equals(legMode)) {
467 routeType =
"generic";
471 RouteFactories factory = this.scenario.getPopulation().getFactory().getRouteFactories();
472 Class<? extends Route> routeClass = factory.getRouteClassForType(routeType);
474 this.currRoute = this.scenario.getPopulation().getFactory().getRouteFactories().createRoute(routeClass, startLinkId == null ? null : Id.create(startLinkId, Link.class), endLinkId == null ? null : Id.create(endLinkId, Link.class));
475 this.currleg.setRoute(this.currRoute);
477 if (atts.getValue(
"trav_time") != null) {
478 Time.parseOptionalTime(atts.getValue(
"trav_time"))
479 .ifDefinedOrElse(currRoute::setTravelTime, currRoute::setTravelTimeUndefined);
482 if (atts.getValue(
"distance") != null) {
483 this.currRoute.setDistance(Double.parseDouble(atts.getValue(
"distance")));
485 final String vehicleRefId = atts.getValue(
"vehicleRefId");
486 if (vehicleRefId != null && !vehicleRefId.equals(
"null") && this.currRoute instanceof NetworkRoute ) {
487 ((NetworkRoute)this.currRoute).setVehicleId(Id.create(vehicleRefId, Vehicle.class));
491 private void endRoute(
final String content) {
492 this.routeDescription = content;
494 Id<Link> startLinkId = this.currRoute.getStartLinkId();
495 Id<Link> endLinkId = this.currRoute.getEndLinkId();
496 this.currRoute.setStartLinkId(startLinkId);
497 this.currRoute.setEndLinkId(endLinkId);
498 this.currRoute.setRouteDescription(this.routeDescription.trim());
501 if (Double.isNaN(
this.currRoute.getDistance())) {
502 if (this.currRoute instanceof NetworkRoute) {
503 if (!this.scenario.getNetwork().getLinks().isEmpty()) {
504 this.currRoute.setDistance(RouteUtils.calcDistanceExcludingStartEndLink((NetworkRoute)
this.currRoute,
this.scenario.getNetwork()));
507 Coord fromCoord = getCoord(this.prevAct);
508 Coord toCoord = getCoord(this.curract);
509 if (fromCoord != null && toCoord != null) {
510 double dist = CoordUtils.calcEuclideanDistance(fromCoord, toCoord);
511 if ( this.scenario.getConfig().routing().
512 getModeRoutingParams().containsKey( this.currleg.getMode() ) ) {
513 double estimatedNetworkDistance = dist * this.scenario.getConfig().routing().
514 getModeRoutingParams().get( this.currleg.getMode() ).getBeelineDistanceFactor() ;
515 this.currRoute.setDistance(estimatedNetworkDistance);
520 if (this.currRoute.getTravelTime().isUndefined()) {
521 this.currleg.getTravelTime().ifDefined(this.currRoute::setTravelTime);
524 if (this.currRoute.getEndLinkId() != null) {
526 this.currRoute = null;
527 this.routeDescription = null;
abstract void startTag(String name, Attributes atts, Stack< String > context)