MATSIM
ScenarioLoaderImpl.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * ScenarioLoader
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2009 by the members listed in the COPYING, *
8  * LICENSE and WARRANTY file. *
9  * email : info at matsim dot org *
10  * *
11  * *********************************************************************** *
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * See also COPYING, LICENSE and WARRANTY file *
18  * *
19  * *********************************************************************** */
20 package org.matsim.core.scenario;
21 
22 import com.google.inject.Inject;
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
26 import org.matsim.api.core.v01.Scenario;
28 import org.matsim.core.config.Config;
38 import org.matsim.core.utils.io.IOUtils;
50 
51 
52 import java.io.UncheckedIOException;
53 import java.net.URL;
54 import java.util.*;
55 
57 
75 // deliberately non-public. Use method in ScenarioUtils.
76 class ScenarioLoaderImpl {
77 
78  private static final Logger log = LogManager.getLogger(ScenarioLoaderImpl.class);
79 
80  private final Config config;
81 
82  private final MutableScenario scenario;
83 
84  private Map<Class<?>, AttributeConverter<?>> attributeConverters = Collections.emptyMap();
85 
86  @Inject
87  public void setAttributeConverters(Map<Class<?>, AttributeConverter<?>> attributeConverters) {
88  log.debug( "setting "+attributeConverters );
89  this.attributeConverters = attributeConverters;
90  }
91 
92  ScenarioLoaderImpl(Config config) {
93  this.config = config;
94  this.scenario = (MutableScenario) ScenarioUtils.createScenario(this.config);
95  }
96 
97  ScenarioLoaderImpl(Scenario scenario) {
98  this.scenario = (MutableScenario) scenario;
99  this.config = this.scenario.getConfig();
100  }
101 
108  Scenario loadScenario() {
109 // String currentDir = new File("tmp").getAbsolutePath();
110 // currentDir = currentDir.substring(0, currentDir.length() - 3);
111 // log.info("loading scenario from base directory: " + currentDir);
112  // the above is not used and thus only causing confusion in the log output. kai, sep'18
113 
114  this.loadNetwork();
115  this.loadActivityFacilities();
116  this.loadPopulation();
117  this.loadHouseholds(); // tests internally if the file is there
118  this.loadTransit(); // tests internally if the file is there
119  this.loadTransitVehicles(); // tests internally if the file is there
120  if (this.config.vehicles().getVehiclesFile()!=null ) {
121  this.loadVehicles() ;
122  }
123  if (this.config.network().getLaneDefinitionsFile()!=null ) {
124  this.loadLanes();
125  }
126  return this.scenario;
127  }
128 
132  private void loadNetwork() {
133  if ((this.config.network() != null) && (this.config.network().getInputFile() != null)) {
134  URL networkUrl = this.config.network().getInputFileURL(this.config.getContext());
135  log.info("loading network from " + networkUrl);
136  String inputCRS = config.network().getInputCRS();
137 
138  MatsimNetworkReader reader =
139  new MatsimNetworkReader(
140  inputCRS,
141  config.global().getCoordinateSystem(),
142  this.scenario.getNetwork());
143  reader.putAttributeConverters( attributeConverters );
144  reader.parse(networkUrl);
145 
146  if ((this.config.network().getChangeEventsInputFile()!= null) && this.config.network().isTimeVariantNetwork()) {
147  log.info("loading network change events from " + this.config.network().getChangeEventsInputFileUrl(this.config.getContext()).getFile());
148  Network network = this.scenario.getNetwork();
149  List<NetworkChangeEvent> changeEvents = new ArrayList<>() ;
150  NetworkChangeEventsParser parser = new NetworkChangeEventsParser(network,changeEvents);
151  parser.parse(this.config.network().getChangeEventsInputFileUrl(config.getContext()));
152  NetworkUtils.setNetworkChangeEvents(network,changeEvents);
153  }
154  }
155  }
156 
157  private void loadActivityFacilities() {
158  if ((this.config.facilities() != null) && (this.config.facilities().getInputFile() != null)) {
159  URL facilitiesFileName = this.config.facilities().getInputFileURL(config.getContext());
160  log.info("loading facilities from " + facilitiesFileName);
161 
162  final String inputCRS = config.facilities().getInputCRS();
163  final String internalCRS = config.global().getCoordinateSystem();
164 
165  MatsimFacilitiesReader reader = new MatsimFacilitiesReader(inputCRS, internalCRS, this.scenario.getActivityFacilities());
166  reader.putAttributeConverters(attributeConverters);
167  reader.parse(facilitiesFileName);
168 
169  log.info("loaded " + this.scenario.getActivityFacilities().getFacilities().size() + " facilities from " + facilitiesFileName);
170  }
171  else {
172  log.info("no facilities file set in config, therefore not loading any facilities. This is not a problem except if you are using facilities");
173  }
174  if ((this.config.facilities() != null) && (this.config.facilities().getInputFacilitiesAttributesFile() != null)) {
175  if ( !this.config.facilities().isInsistingOnUsingDeprecatedFacilitiesAttributeFile() ) {
176  throw new RuntimeException(FacilitiesConfigGroup.FACILITIES_ATTRIBUTES_DEPRECATION_MESSAGE) ;
177  }
178  URL facilitiesAttributesURL = ConfigGroup.getInputFileURL(this.config.getContext(), this.config.facilities().getInputFacilitiesAttributesFile());
179  log.info("loading facility attributes from " + facilitiesAttributesURL);
180  parseObjectAttributesToAttributable(
181  facilitiesAttributesURL,
182  scenario.getActivityFacilities().getFacilities().values(),
183  "facilityAttributes not empty after going through all facilities, meaning that it contains material for facilityIDs that " +
184  "are not in the container. This is not necessarily a bug so we will continue, but note that such material " +
185  "will no longer be contained in the output_* files.");
186  }
187  else {
188  log.info("no facility-attributes file set in config, not loading any facility attributes");
189  }
190  }
191 
192 
193  private void loadPopulation() {
194  if ((this.config.plans() != null) && (this.config.plans().getInputFile() != null)) {
195  URL populationFileName = this.config.plans().getInputFileURL(this.config.getContext());
196  log.info("loading population from " + populationFileName);
197 
198  final String targetCRS = config.global().getCoordinateSystem();
199  final String internalCRS = config.global().getCoordinateSystem();
200 
201  final PopulationReader reader = new PopulationReader(targetCRS, internalCRS, this.scenario);
202  reader.putAttributeConverters( attributeConverters );
203  reader.parse( populationFileName );
204 
205  PopulationUtils.printPlansCount(this.scenario.getPopulation()) ;
206  }
207  else {
208  log.info("no population file set in config, not able to load population");
209  }
210 
211  if ((this.config.plans() != null) && (this.config.plans().getInputPersonAttributeFile() != null)) {
212  URL personAttributesURL = this.config.plans().getInputPersonAttributeFileURL(this.config.getContext());
213  log.info("loading person attributes from " + personAttributesURL);
214  parseObjectAttributesToAttributable(
215  personAttributesURL,
216  scenario.getPopulation().getPersons().values(),
217  "personAttributes not empty after going through all persons, meaning that it contains material for personIDs that " +
218  "are not in the population. This is not necessarily a bug so we will continue, but note that such material " +
219  "will no longer be contained in the output_* files. (We have this happening in particular when the same personAttributes " +
220  "file is used for the 10pct and the 1pct scenario. The material that is still there will follow. kai, jun'19"
221  );
222 
223  final String outputDirectory = this.config.controller().getOutputDirectory();
224 // final File outDir = new File( outputDirectory );
225 // if ( outDir.exists() && outDir.canWrite() ){
226 // // since ScenarioLoader is supposed to only read material, there are cases where the output directory does not exist at
227 // // this stage. One could maybe write to the "config.getContext()" directory. However, sometimes this is a URL, and thus also
228 // // non-writeable, and it is even less systematic than writing into the output directory. kai, jun'19
229 //
230 // String outFilename = outputDirectory + "/input_plans_with_person_attributes.xml.gz";
231 // PopulationUtils.writePopulation( scenario.getPopulation(), outFilename );
232 //
233 // log.warn(
234 // "a file with path=" + outFilename + " was just written in order to facilitate the transition to having person attributes inside " +
235 // "the persons. " );
236 // }
237  // TD says to rather not have this kind of side effect. kai, jul'19
238 
239  if ( !this.config.plans().isInsistingOnUsingDeprecatedPersonAttributeFile() ) {
240  throw new RuntimeException(PERSON_ATTRIBUTES_DEPRECATION_MESSAGE) ;
241  }
242  }
243  else {
244  log.info("no person-attributes file set in config, not loading any person attributes");
245  }
246  }
247 
248  private void loadHouseholds() {
249  if ( (this.config.households() != null) && (this.config.households().getInputFile() != null) ) {
250  URL householdsFile = this.config.households().getInputFileURL(this.config.getContext());
251  log.info("loading households from " + householdsFile);
252  HouseholdsReaderV10 reader = new HouseholdsReaderV10(this.scenario.getHouseholds());
253  reader.putAttributeConverters(this.attributeConverters);
254  reader.parse(householdsFile);
255  log.info("households loaded.");
256  }
257  else {
258  log.info("no households file set in config, not loading households");
259  }
260  if ((this.config.households() != null)) {
261  final String fn = this.config.households().getInputHouseholdAttributesFile();
262  if(( fn != null)) {
263  if (!this.config.households().isInsistingOnUsingDeprecatedHouseholdsAttributeFile()) {
264  throw new RuntimeException(HouseholdsConfigGroup.HOUSEHOLD_ATTRIBUTES_DEPRECATION_MESSAGE);
265  }
266 
267  URL householdAttributesFileName = ConfigGroup.getInputFileURL(this.config.getContext(), fn ) ;
268  log.info("loading household attributes from " + householdAttributesFileName);
269  parseObjectAttributesToAttributable(
270  householdAttributesFileName,
271  this.scenario.getHouseholds().getHouseholds().values(),
272  "householdAttributes not empty after going through all households, meaning that it contains material for householdIDs that " +
273  "are not in the container. This is not necessarily a bug so we will continue, but note that such material " +
274  "will no longer be contained in the output_* files.");
275  }
276  }
277  else {
278  log.info("no household-attributes file set in config, not loading any household attributes");
279  }
280  }
281 
282  private void loadTransit() throws UncheckedIOException {
283 
284  if ( this.config.transit().getTransitScheduleFile() != null ) {
285  URL transitScheduleFile = this.config.transit().getTransitScheduleFileURL(this.config.getContext());
286  final String inputCRS = config.transit().getInputScheduleCRS();
287  final String internalCRS = config.global().getCoordinateSystem();
288 
289  new TransitScheduleReader( inputCRS, internalCRS, this.scenario).readURL(transitScheduleFile );
290  }
291  else {
292  log.info("no transit schedule file set in config, not loading any transit schedule");
293  }
294 
295  if ( this.config.transit().getTransitLinesAttributesFile() != null ) {
296  if (!this.config.transit().isInsistingOnUsingDeprecatedAttributeFiles()) {
297  throw new RuntimeException(TransitConfigGroup.TRANSIT_ATTRIBUTES_DEPRECATION_MESSAGE);
298  }
299 
300  URL transitLinesAttributesFileName = IOUtils.extendUrl(this.config.getContext(), this.config.transit().getTransitLinesAttributesFile());
301  log.info("loading transit lines attributes from " + transitLinesAttributesFileName);
302  parseObjectAttributesToAttributable(
303  transitLinesAttributesFileName,
304  this.scenario.getTransitSchedule().getTransitLines().values(),
305  "transit lines attributes not empty after going through all lines, meaning that it contains material for line IDs that " +
306  "are not in the container. This is not necessarily a bug so we will continue, but note that such material " +
307  "will no longer be contained in the output_* files.");
308  }
309 
310  if ( this.config.transit().getTransitStopsAttributesFile() != null ) {
311  if (!this.config.transit().isInsistingOnUsingDeprecatedAttributeFiles()) {
312  throw new RuntimeException(TransitConfigGroup.TRANSIT_ATTRIBUTES_DEPRECATION_MESSAGE);
313  }
314 
315  URL transitStopsAttributesURL = IOUtils.extendUrl(this.config.getContext(), this.config.transit().getTransitStopsAttributesFile());
316  log.info("loading transit stop facilities attributes from " + transitStopsAttributesURL);
317  parseObjectAttributesToAttributable(
318  transitStopsAttributesURL,
319  this.scenario.getTransitSchedule().getFacilities().values(),
320  "transit stops attributes not empty after going through all stops, meaning that it contains material for stop IDs that " +
321  "are not in the container. This is not necessarily a bug so we will continue, but note that such material " +
322  "will no longer be contained in the output_* files.");
323  }
324  }
325 
326  private void loadTransitVehicles() throws UncheckedIOException {
327  final String vehiclesFile = this.config.transit().getVehiclesFile();
328  if ( vehiclesFile != null ) {
329  log.info("loading transit vehicles from " + vehiclesFile);
330  new MatsimVehicleReader(this.scenario.getTransitVehicles()).readURL(this.config.transit().getVehiclesFileURL(this.config.getContext() ) );
331  }
332  else {
333  log.info("no transit vehicles file set in config, not loading any transit vehicles");
334  }
335  }
336  private void loadVehicles() throws UncheckedIOException {
337  final String vehiclesFile = this.config.vehicles().getVehiclesFile();
338  if ( vehiclesFile != null ) {
339  log.info("loading vehicles from " + vehiclesFile );
340  new MatsimVehicleReader(this.scenario.getVehicles()).readURL(IOUtils.extendUrl(this.config.getContext(), vehiclesFile ) );
341  }
342  else {
343  log.info("no vehicles file set in config, not loading any vehicles");
344  }
345  }
346 
347  private void loadLanes() {
348  String filename = this.config.network().getLaneDefinitionsFile();
349  if (filename != null){
350  LanesReader reader = new LanesReader(this.scenario);
351  reader.readURL( ConfigGroup.getInputFileURL(this.config.getContext(), filename ) );
352  }
353  else {
354  log.info("no lanes file set in config, not loading any lanes");
355  }
356  }
357 
358  private <T extends Identifiable<?> & Attributable> void parseObjectAttributesToAttributable(
359  URL url,
360  Iterable<T> attributables,
361  String message) {
362  final ObjectAttributes attributes = new ObjectAttributes();
363  ObjectAttributesXmlReader reader = new ObjectAttributesXmlReader(attributes);
364  reader.putAttributeConverters( attributeConverters );
365  reader.parse(url);
366 
367  for( T facility : attributables ) {
368  Collection<String> keys = ObjectAttributesUtils.getAllAttributeNames( attributes, facility.getId().toString() );
369  for( String key : keys ){
370  Object value = attributes.getAttribute( facility.getId().toString(), key );
371  facility.getAttributes().putAttribute( key, value ) ;
372  }
373  attributes.removeAllAttributes( facility.getId().toString() );
374  }
375  // (some of the above could also become a static helper method in ObjectAttributesUtils, but this here seems the only
376  // place within matsim core where the personAttributes are automatically read so maybe there is no need for this. kai, jun'19)
377 
378  if ( !attributes.toString().equals( "" ) ) {
379  log.warn( message ) ;
380  log.warn( "showing the first 1000 characters from the remaining personAttributes ...") ;
381  log.warn( attributes.toString().substring( 0, Math.min(attributes.toString().length(), 1000 ) ) );
382  log.warn("");
383  }
384  }
385 
386 }