MATSIM
PopulationReaderMatsimV6.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * *
4  * *********************************************************************** *
5  * *
6  * copyright : (C) 2011 by the members listed in the COPYING, *
7  * LICENSE and WARRANTY file. *
8  * email : info at matsim dot org *
9  * *
10  * *********************************************************************** *
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * See also COPYING, LICENSE and WARRANTY file *
17  * *
18  * *********************************************************************** */
19 
20 package org.matsim.core.population.io;
21 
22 import java.util.ArrayList;
23 import java.util.Map;
24 import java.util.Objects;
25 import java.util.Stack;
26 
27 import org.apache.logging.log4j.LogManager;
28 import org.apache.logging.log4j.Logger;
29 import org.matsim.api.core.v01.Coord;
30 import org.matsim.api.core.v01.Id;
31 import org.matsim.api.core.v01.Scenario;
54 import org.matsim.core.utils.misc.Time;
60 import org.matsim.vehicles.Vehicle;
61 import org.xml.sax.Attributes;
62 
63 import com.google.inject.Inject;
64 
72 /* deliberately package */ class PopulationReaderMatsimV6 extends MatsimXmlParser implements MatsimReader {
73  private static final Logger log = LogManager.getLogger(PopulationReaderMatsimV6.class);
74 
75  /* package */ final static String POPULATION = "population";
76  /* package */ final static String PERSON = "person";
77  /* package */ 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";
83 
84  private final static String ATTR_POPULATION_DESC = "desc";
85  /* package */ 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";
101 // private final static String ATTR_LEG_ARRTIME = "arr_time";
102  private static final String ATTR_ROUTE_STARTLINK = "start_link";
103  private static final String ATTR_ROUTE_ENDLINK = "end_link";
104 
105  private final static String VALUE_YES = "yes";
106  private final static String VALUE_NO = "no";
107  private final static String VALUE_UNDEF = "undef";
108 
109  // TODO: infrastructure to configure converters
110  private final AttributesXmlReaderDelegate attributesReader = new AttributesXmlReaderDelegate();
111 
112  final Scenario scenario;
113  final Population plans;
114  private final String externalInputCRS;
115 
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;
122  private org.matsim.utils.objectattributes.attributable.Attributes currAttributes = null;
123 
124  private final String targetCRS;
125  private CoordinateTransformation coordinateTransformation = new IdentityTransformation();
126 
127  private Activity prevAct = null;
128 
129 
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);
142  }
143  }
144 
145  public ObjectAttributesConverter getObjectAttributesConverter()
146  {
147  return attributesReader.getObjectAttributesConverter();
148  }
149 
150  public void putAttributeConverter( final Class<?> clazz , AttributeConverter<?> converter ) {
151  attributesReader.putAttributeConverter( clazz , converter );
152  }
153 
154  @Inject
155  public void putAttributeConverters( final Map<Class<?>, AttributeConverter<?>> converters ) {
156  attributesReader.putAttributeConverters( converters );
157  }
158 
159  @Override
160  public void startTag(final String name, final Attributes atts, final Stack<String> context) {
161  switch( name ) {
162  case POPULATION:
163  startPopulation(atts);
164  break;
165  case PERSON:
166  startPerson(atts);
167  break;
168  case ATTRIBUTES:
169  switch( context.peek() ) {
170  case POPULATION:
171  currAttributes = scenario.getPopulation().getAttributes();
172  break;
173  case PERSON:
174  currAttributes = currperson.getAttributes();
175  break;
176  case PLAN:
177  currAttributes = currplan.getAttributes();
178  break;
179  case ACT:
180  currAttributes = curract.getAttributes();
181  break;
182  case LEG:
184  break;
185  default:
186  throw new RuntimeException( context.peek() );
187  }
188  // deliberate fall-through
189  case ATTRIBUTE:
190  attributesReader.startTag( name , atts ,context , currAttributes );
191  break;
192  case PLAN:
193  startPlan(atts);
194  break;
195  case ACT:
196  startAct(atts);
197  break;
198  case LEG:
199  startLeg(atts);
200  break;
201  case ROUTE:
202  startRoute(atts);
203  break;
204  default:
205  throw new RuntimeException(this + "[tag=" + name + " not known or not supported]");
206  }
207  }
208 
209  @Override
210  public void endTag(final String name, final String content, final Stack<String> context) {
211  switch ( name ) {
212  case PERSON:
213  this.plans.addPerson(this.currperson);
214  this.currperson = null;
215  break;
216  case ATTRIBUTE:
217  this.attributesReader.endTag( name , content , context );
218  break;
219  case ATTRIBUTES:
220  switch( context.peek() ) {
221  case POPULATION:
222  String inputCRS = ProjectionUtils.getCRS(scenario.getPopulation());
223 
224  if (inputCRS != null && targetCRS != null) {
225  if (externalInputCRS != null) {
226  // warn or crash?
227  log.warn("coordinate transformation defined both in config and in input file: setting from input file will be used");
228  }
229  coordinateTransformation = TransformationFactory.getCoordinateTransformation(inputCRS, targetCRS);
230  ProjectionUtils.putCRS(scenario.getPopulation(), targetCRS);
231  }
232  break;
233  case LEG:
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);
238  }
239  AttributesUtils.copyTo(currAttributes, currleg.getAttributes());
240  break;
241  }
242  break;
243  case PLAN:
244  if (this.currplan.getPlanElements() instanceof ArrayList<?>) {
245  ((ArrayList<?>) this.currplan.getPlanElements()).trimToSize();
246  }
247  this.currplan = null;
248  break;
249  case ACT:
250  this.prevAct = this.curract;
251  this.curract = null;
252  break;
253  case ROUTE:
254  endRoute(content);
255  break;
256  }
257  }
258 
259  private void startPopulation(final Attributes atts) {
260  this.plans.setName(atts.getValue(ATTR_POPULATION_DESC));
261  }
262 
263  private void startPerson(final Attributes atts) {
264  this.currperson = PopulationUtils.getFactory().createPerson(Id.create(atts.getValue(ATTR_PERSON_ID), Person.class));
265  }
266 
267  private void startPlan(final Attributes atts) {
268  String sel = atts.getValue(ATTR_PLAN_SELECTED);
269  boolean selected;
270  if (VALUE_YES.equals(sel)) {
271  selected = true;
272  }
273  else if (VALUE_NO.equals(sel)) {
274  selected = false;
275  }
276  else {
277  throw new IllegalArgumentException(
278  "Attribute 'selected' of Element 'Plan' is neither 'yes' nor 'no', is " + sel);
279  }
280  this.routeDescription = null;
281  this.currplan = PersonUtils.createAndAddPlan(this.currperson, selected);
282 
283  String scoreString = atts.getValue(ATTR_PLAN_SCORE);
284  if (scoreString != null) {
285  double score = Double.parseDouble(scoreString);
286  this.currplan.setScore(score);
287  }
288 
289  String type = atts.getValue(ATTR_PLAN_TYPE);
290  if (type != null) {
291  this.currplan.setType(type);
292  }
293  }
294 
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);
302  } else {
303  this.curract = PopulationUtils.createActivityFromFacilityId(actType, facilityId);
304  }
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);
308  }
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);
312  }
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);
317  } else {
318  this.curract = PopulationUtils.createActivityFromLinkId(actType, linkId);
319  }
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);
323  }
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);
328  } else {
329  this.curract = PopulationUtils.createActivityFromCoord(actType, coord);
330  }
331  } else {
332  throw new IllegalArgumentException("In this version of MATSim either the facility, the link or the coords must be specified for an Act.");
333  }
334 
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));
338 
339  // Check whether the given times match the assumptions made in InteractionActivity. Otherwise, convert it to a regular Activity.
340  if (isStageActivity && (startTime.isDefined() || endTime.isDefined() || duration.isUndefined() || duration.seconds() > 0.0)) {
341  this.curract = PopulationUtils.createActivity(this.curract);
342  } else {
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);
346  }
347  this.currplan.addActivity(this.curract);
348 
349  if (this.routeDescription != null) {
350  finishLastRoute();
351  }
352  }
353 
354  private Coord parseCoord(Attributes atts) {
355  if ( atts.getValue( ATTR_ACT_Z ) != null ) {
356  return coordinateTransformation.transform(
357  new Coord(
358  Double.parseDouble(atts.getValue(ATTR_ACT_X)),
359  Double.parseDouble(atts.getValue(ATTR_ACT_Y)),
360  Double.parseDouble(atts.getValue(ATTR_ACT_Z)) ) );
361  }
362  else {
363  return coordinateTransformation.transform(
364  new Coord(
365  Double.parseDouble(atts.getValue(ATTR_ACT_X)),
366  Double.parseDouble(atts.getValue(ATTR_ACT_Y))));
367  }
368  }
369 
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();
376  }
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();
382  }
383 
384  this.currRoute.setStartLinkId(startLinkId);
385  this.currRoute.setEndLinkId(endLinkId);
386  this.currRoute.setRouteDescription(this.routeDescription.trim());
387 
388  // yy I think that my intuition would be to put the following into prepareForSim. kai, dec'16
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()));
393  }
394  } else {
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);
404  }
405  }
406  }
407  }
408  if (this.currRoute.getTravelTime().isUndefined()) {
409  this.currleg.getTravelTime().ifDefined(this.currRoute::setTravelTime);
410  }
411 
412  this.routeDescription = null;
413  this.currRoute = null;
414 
415  }
416 
417  private Coord getCoord(Activity activity) {
418  // yy I think that my intuition would be to put the following into prepareForSim. kai, dec'16
419  if (activity == null) {
420  return null;
421  }
422  Coord fromCoord;
423  if (activity.getCoord() != null) {
424  fromCoord = activity.getCoord();
425  } else {
426  if (!this.scenario.getNetwork().getLinks().isEmpty()) {
427  fromCoord = this.scenario.getNetwork().getLinks().get(activity.getLinkId()).getCoord();
428  } else {
429  fromCoord = null;
430  }
431  }
432  return fromCoord;
433  }
434 
435  private void startLeg(final Attributes atts) {
436  if (this.routeDescription != null) {
437  finishLastRoute();
438  }
439 
440  String mode = atts.getValue(ATTR_LEG_MODE);
441  if (VALUE_UNDEF.equals(mode)) {
442  mode = "undefined";
443  }
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);
449 // LegImpl r = this.currleg;
450 // r.setTravelTime( Time.parseTime(atts.getValue(ATTR_LEG_ARRTIME)) - r.getDepartureTime() );
451  // arrival time is in dtd, but no longer evaluated in code (according to not being in API). kai, jun'16
452  }
453 
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");
458 
459  if (routeType == null) {
460  String legMode = this.currleg.getMode();
461  if ("pt".equals(legMode)) {
462  routeType = "experimentalPt1";
463  } else if ("car".equals(legMode)) {
464  //yyyy couldn't we check against all network modes of config here? paul, jul '24
465  routeType = "links";
466  } else {
467  routeType = "generic";
468  }
469  }
470 
471  RouteFactories factory = this.scenario.getPopulation().getFactory().getRouteFactories();
472  Class<? extends Route> routeClass = factory.getRouteClassForType(routeType);
473 
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);
476 
477  if (atts.getValue("trav_time") != null) {
478  Time.parseOptionalTime(atts.getValue("trav_time"))
479  .ifDefinedOrElse(currRoute::setTravelTime, currRoute::setTravelTimeUndefined);
480  }
481 
482  if (atts.getValue("distance") != null) {
483  this.currRoute.setDistance(Double.parseDouble(atts.getValue("distance")));
484  }
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));
488  }
489  }
490 
491  private void endRoute(final String content) {
492  this.routeDescription = content;
493 
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());
499 
500  // yy I think that my intuition would be to put the following into prepareForSim. kai, dec'16
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()));
505  }
506  } else {
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);
516  }
517  }
518  }
519  }
520  if (this.currRoute.getTravelTime().isUndefined()) {
521  this.currleg.getTravelTime().ifDefined(this.currRoute::setTravelTime);
522  }
523 
524  if (this.currRoute.getEndLinkId() != null) {
525  // this route is complete
526  this.currRoute = null;
527  this.routeDescription = null;
528  }
529  }
530 
531 }
abstract void startTag(String name, Attributes atts, Stack< String > context)