diff --git a/core/src/main/java/org/eqasim/core/components/config/ConfigAdapter.java b/core/src/main/java/org/eqasim/core/components/config/ConfigAdapter.java index 46e5261bc..386d26517 100644 --- a/core/src/main/java/org/eqasim/core/components/config/ConfigAdapter.java +++ b/core/src/main/java/org/eqasim/core/components/config/ConfigAdapter.java @@ -1,7 +1,5 @@ package org.eqasim.core.components.config; -import java.util.function.Consumer; - import org.matsim.core.config.CommandLine; import org.matsim.core.config.CommandLine.ConfigurationException; import org.matsim.core.config.Config; @@ -10,16 +8,19 @@ import org.matsim.core.config.ConfigWriter; public class ConfigAdapter { - static public void run(String[] args, ConfigGroup[] modules, Consumer adapter) + static public void run(String[] args, ConfigGroup[] modules, ConfigAdapterConsumer adapter) throws ConfigurationException { CommandLine cmd = new CommandLine.Builder(args) // - .requireOptions("input-path", "output-path") // + .requireOptions("input-path", "output-path", "prefix") // .build(); Config config = ConfigUtils.loadConfig(cmd.getOptionStrict("input-path"), modules); - adapter.accept(config); + adapter.accept(config, cmd.getOptionStrict("prefix")); new ConfigWriter(config).write(cmd.getOptionStrict("output-path")); } - + + public interface ConfigAdapterConsumer { + void accept(Config config, String prefix); + } } diff --git a/core/src/main/java/org/eqasim/core/scenario/RunInsertVehicles.java b/core/src/main/java/org/eqasim/core/scenario/RunInsertVehicles.java new file mode 100644 index 000000000..e94d4b0ce --- /dev/null +++ b/core/src/main/java/org/eqasim/core/scenario/RunInsertVehicles.java @@ -0,0 +1,60 @@ +package org.eqasim.core.scenario; + +import java.io.UncheckedIOException; +import java.util.HashMap; +import java.util.Map; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.population.Person; +import org.matsim.core.config.CommandLine; +import org.matsim.core.config.CommandLine.ConfigurationException; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.population.io.PopulationReader; +import org.matsim.core.population.io.PopulationWriter; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.vehicles.MatsimVehicleWriter; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleUtils; +import org.matsim.vehicles.Vehicles; +import org.matsim.vehicles.VehiclesFactory; + +public class RunInsertVehicles { + + static public void insertVehicles(Config config, Scenario scenario) { + Vehicles vehicles = scenario.getVehicles(); + VehiclesFactory factory = vehicles.getFactory(); + + vehicles.addVehicleType(VehicleUtils.getDefaultVehicleType()); + for (Person person : scenario.getPopulation().getPersons().values()) { + Map> personVehicles = new HashMap<>(); + + for (String mode : config.routing().getNetworkModes()) { + Vehicle vehicle = factory.createVehicle(Id.createVehicleId(person.getId().toString() + ":" + mode), + VehicleUtils.getDefaultVehicleType()); + vehicles.addVehicle(vehicle); + + personVehicles.put(mode, vehicle.getId()); + } + + VehicleUtils.insertVehicleIdsIntoPersonAttributes(person, personVehicles); + } + } + + static public void main(String[] args) throws UncheckedIOException, ConfigurationException { + CommandLine cmd = new CommandLine.Builder(args) // + .requireOptions("config-path", "input-population-path", "output-vehicles-path", + "output-population-path") // + .build(); + + Config config = ConfigUtils.loadConfig(cmd.getOptionStrict("config-path")); + Scenario scenario = ScenarioUtils.createScenario(ConfigUtils.createConfig()); + new PopulationReader(scenario).readFile(cmd.getOptionStrict("input-population-path")); + + insertVehicles(config, scenario); + + new MatsimVehicleWriter(scenario.getVehicles()).writeFile(cmd.getOptionStrict("output-vehicles-path")); + new PopulationWriter(scenario.getPopulation()).write(cmd.getOptionStrict("output-population-path")); + } +} diff --git a/core/src/main/java/org/eqasim/core/scenario/cutter/ConfigCutter.java b/core/src/main/java/org/eqasim/core/scenario/cutter/ConfigCutter.java index 3514f3da4..e2f95441d 100644 --- a/core/src/main/java/org/eqasim/core/scenario/cutter/ConfigCutter.java +++ b/core/src/main/java/org/eqasim/core/scenario/cutter/ConfigCutter.java @@ -16,5 +16,6 @@ public void run(Config config) { config.households().setInputFile(prefix + "households.xml.gz"); config.transit().setTransitScheduleFile(prefix + "transit_schedule.xml.gz"); config.transit().setVehiclesFile(prefix + "transit_vehicles.xml.gz"); + config.vehicles().setVehiclesFile(prefix + "vehicles.xml.gz"); } } diff --git a/core/src/main/java/org/eqasim/core/scenario/cutter/RunScenarioCutter.java b/core/src/main/java/org/eqasim/core/scenario/cutter/RunScenarioCutter.java index 9c422814a..8595f2a86 100644 --- a/core/src/main/java/org/eqasim/core/scenario/cutter/RunScenarioCutter.java +++ b/core/src/main/java/org/eqasim/core/scenario/cutter/RunScenarioCutter.java @@ -17,6 +17,7 @@ import org.eqasim.core.scenario.cutter.network.RoadNetwork; import org.eqasim.core.scenario.cutter.outside.OutsideActivityAdapter; import org.eqasim.core.scenario.cutter.population.CleanHouseholds; +import org.eqasim.core.scenario.cutter.population.CleanVehicles; import org.eqasim.core.scenario.cutter.population.PopulationCutter; import org.eqasim.core.scenario.cutter.population.PopulationCutterModule; import org.eqasim.core.scenario.cutter.population.RemoveEmptyPlans; @@ -27,6 +28,7 @@ import org.eqasim.core.scenario.routing.PopulationRouter; import org.eqasim.core.scenario.routing.PopulationRouterModule; import org.eqasim.core.scenario.validation.ScenarioValidator; +import org.eqasim.core.scenario.validation.VehiclesValidator; import org.eqasim.core.simulation.EqasimConfigurator; import org.eqasim.core.simulation.mode_choice.AbstractEqasimExtension; import org.eqasim.core.simulation.termination.EqasimTerminationModule; @@ -43,10 +45,10 @@ public class RunScenarioCutter { public static final Collection REQUIRED_ARGS = Set.of("config-path", "output-path", "extent-path"); - public static final Collection OPTIONAL_ARGS = Set.of("threads", "prefix", "extent-attribute", "extent-value", "plans-path", "events-path", "skip-routing"); + public static final Collection OPTIONAL_ARGS = Set.of("threads", "prefix", "extent-attribute", + "extent-value", "plans-path", "events-path", "skip-routing"); - static public void main(String[] args) - throws ConfigurationException, IOException, InterruptedException { + static public void main(String[] args) throws ConfigurationException, IOException, InterruptedException { CommandLine cmd = new CommandLine.Builder(args) // .requireOptions(REQUIRED_ARGS) // .allowOptions(OPTIONAL_ARGS) // @@ -69,10 +71,12 @@ static public void main(String[] args) // Load scenario EqasimConfigurator configurator = new EqasimConfigurator(); configurator.getModules().removeIf(m -> m instanceof EqasimTerminationModule); - + Config config = ConfigUtils.loadConfig(cmd.getOptionStrict("config-path"), configurator.getConfigGroups()); cmd.applyConfiguration(config); + VehiclesValidator.validate(config); + Optional plansPath = cmd.getOption("plans-path"); if (plansPath.isPresent()) { @@ -106,7 +110,8 @@ static public void main(String[] args) // Cut population Injector populationCutterInjector = new InjectorBuilder(scenario) // - .addOverridingModules(configurator.getModules().stream().filter(module -> !(module instanceof AbstractEqasimExtension)).toList()) // + .addOverridingModules(configurator.getModules().stream() + .filter(module -> !(module instanceof AbstractEqasimExtension)).toList()) // .addOverridingModule( new PopulationCutterModule(extent, numberOfThreads, 40, cmd.getOption("events-path"))) // .addOverridingModule(new CutterTravelTimeModule(travelTime)) // @@ -128,6 +133,10 @@ static public void main(String[] args) CleanHouseholds cleanHouseholds = new CleanHouseholds(scenario.getPopulation()); cleanHouseholds.run(scenario.getHouseholds()); + // .. and make vehicles consistent + CleanVehicles cleanVehicles = new CleanVehicles(scenario.getPopulation()); + cleanVehicles.run(scenario.getVehicles()); + // Cut transit StopSequenceCrossingPointFinder stopSequenceCrossingPointFinder = new DefaultStopSequenceCrossingPointFinder( extent); @@ -159,7 +168,8 @@ static public void main(String[] args) // Final routing Injector routingInjector = new InjectorBuilder(scenario) // - .addOverridingModules(configurator.getModules().stream().filter(module -> !(module instanceof AbstractEqasimExtension)).toList()) // + .addOverridingModules(configurator.getModules().stream() + .filter(module -> !(module instanceof AbstractEqasimExtension)).toList()) // .addOverridingModule(new PopulationRouterModule(numberOfThreads, 100, false)) // .addOverridingModule(new CutterTravelTimeModule(travelTime)) // .addOverridingModule(new TimeInterpretationModule()) // @@ -167,7 +177,7 @@ static public void main(String[] args) boolean skipRouting = Boolean.parseBoolean(cmd.getOption("skip-routing").orElse("false")); - if(!skipRouting) { + if (!skipRouting) { PopulationRouter router = routingInjector.getInstance(PopulationRouter.class); router.run(scenario.getPopulation()); // Check validity after cutting diff --git a/core/src/main/java/org/eqasim/core/scenario/cutter/RunScenarioCutterV2.java b/core/src/main/java/org/eqasim/core/scenario/cutter/RunScenarioCutterV2.java index 91840a932..f5d5cadb8 100644 --- a/core/src/main/java/org/eqasim/core/scenario/cutter/RunScenarioCutterV2.java +++ b/core/src/main/java/org/eqasim/core/scenario/cutter/RunScenarioCutterV2.java @@ -1,5 +1,14 @@ package org.eqasim.core.scenario.cutter; +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + import org.apache.commons.io.FileUtils; import org.eqasim.core.scenario.cutter.extent.ScenarioExtent; import org.eqasim.core.scenario.cutter.extent.ShapeScenarioExtent; @@ -20,11 +29,6 @@ import org.matsim.core.population.io.PopulationReader; import org.matsim.core.scenario.ScenarioUtils; -import java.io.File; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.*; - public class RunScenarioCutterV2 { public static final String[] SHAPEFILE_EXTENSIONS = new String[]{".shp", ".cpg", ".dbf", ".qmd", ".shx", ".prj"}; diff --git a/core/src/main/java/org/eqasim/core/scenario/cutter/ScenarioWriter.java b/core/src/main/java/org/eqasim/core/scenario/cutter/ScenarioWriter.java index 0ff309db1..9f6ac113b 100644 --- a/core/src/main/java/org/eqasim/core/scenario/cutter/ScenarioWriter.java +++ b/core/src/main/java/org/eqasim/core/scenario/cutter/ScenarioWriter.java @@ -42,12 +42,8 @@ public void run(File outputDirectory) { .writeFile(new File(outputDirectory, prefix + "transit_schedule.xml.gz").toString()); new MatsimVehicleWriter(scenario.getTransitVehicles()) .writeFile(new File(outputDirectory, prefix + "transit_vehicles.xml.gz").toString()); - - if (config.vehicles().getVehiclesFile() != null) { - new MatsimVehicleWriter(scenario.getVehicles()) - .writeFile(new File(outputDirectory, prefix + "vehicles.xml.gz").toString()); - } - + new MatsimVehicleWriter(scenario.getVehicles()) + .writeFile(new File(outputDirectory, prefix + "vehicles.xml.gz").toString()); } static void checkOutputDirectory(File outputDirectory) { diff --git a/core/src/main/java/org/eqasim/core/scenario/cutter/population/CleanVehicles.java b/core/src/main/java/org/eqasim/core/scenario/cutter/population/CleanVehicles.java new file mode 100644 index 000000000..6983ab271 --- /dev/null +++ b/core/src/main/java/org/eqasim/core/scenario/cutter/population/CleanVehicles.java @@ -0,0 +1,26 @@ +package org.eqasim.core.scenario.cutter.population; + +import org.matsim.api.core.v01.IdSet; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.Population; +import org.matsim.vehicles.Vehicle; +import org.matsim.vehicles.VehicleUtils; +import org.matsim.vehicles.Vehicles; + +public class CleanVehicles { + private final IdSet retainedIds = new IdSet<>(Vehicle.class); + + public CleanVehicles(Population population) { + for (Person person : population.getPersons().values()) { + retainedIds.addAll(VehicleUtils.getVehicleIds(person).values()); + } + } + + public void run(Vehicles vehicles) { + IdSet removeIds = new IdSet<>(Vehicle.class); + removeIds.addAll(vehicles.getVehicles().keySet()); + removeIds.removeAll(retainedIds); + + removeIds.forEach(vehicles::removeVehicle); + } +} diff --git a/core/src/main/java/org/eqasim/core/scenario/routing/RunPopulationRouting.java b/core/src/main/java/org/eqasim/core/scenario/routing/RunPopulationRouting.java index eb9755a4b..f0c7b7f2e 100644 --- a/core/src/main/java/org/eqasim/core/scenario/routing/RunPopulationRouting.java +++ b/core/src/main/java/org/eqasim/core/scenario/routing/RunPopulationRouting.java @@ -1,34 +1,22 @@ package org.eqasim.core.scenario.routing; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; import java.util.Set; import org.eqasim.core.misc.InjectorBuilder; +import org.eqasim.core.scenario.validation.VehiclesValidator; import org.eqasim.core.simulation.EqasimConfigurator; import org.eqasim.core.simulation.mode_choice.AbstractEqasimExtension; import org.eqasim.core.simulation.termination.EqasimTerminationConfigGroup; -import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; -import org.matsim.api.core.v01.population.Leg; -import org.matsim.api.core.v01.population.Person; -import org.matsim.api.core.v01.population.Plan; import org.matsim.core.config.CommandLine; import org.matsim.core.config.CommandLine.ConfigurationException; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; -import org.matsim.core.config.groups.QSimConfigGroup.VehiclesSource; import org.matsim.core.population.io.PopulationWriter; -import org.matsim.core.population.routes.NetworkRoute; -import org.matsim.core.router.TripStructureUtils; import org.matsim.core.scenario.ScenarioUtils; import org.matsim.core.utils.timing.TimeInterpretationModule; import org.matsim.facilities.ActivityFacility; -import org.matsim.vehicles.Vehicle; -import org.matsim.vehicles.VehicleUtils; -import org.matsim.vehicles.Vehicles; -import org.matsim.vehicles.VehiclesFactory; import com.google.inject.Injector; @@ -41,17 +29,17 @@ static public void main(String[] args) throws ConfigurationException, Interrupte EqasimConfigurator configurator = new EqasimConfigurator(); Config config = ConfigUtils.loadConfig(cmd.getOptionStrict("config-path"), configurator.getConfigGroups()); - config.getModules().remove(EqasimTerminationConfigGroup.GROUP_NAME); + config.getModules().remove(EqasimTerminationConfigGroup.GROUP_NAME); configurator.addOptionalConfigGroups(config); cmd.applyConfiguration(config); config.replanning().clearStrategySettings(); + VehiclesValidator.validate(config); int batchSize = cmd.getOption("batch-size").map(Integer::parseInt).orElse(100); int numberOfThreads = cmd.getOption("threads").map(Integer::parseInt) .orElse(Runtime.getRuntime().availableProcessors()); Scenario scenario = ScenarioUtils.loadScenario(config); - insertVehicles(config, scenario); if (scenario.getActivityFacilities() != null) { for (ActivityFacility facility : scenario.getActivityFacilities().getFacilities().values()) { @@ -70,54 +58,14 @@ static public void main(String[] args) throws ConfigurationException, Interrupte } Injector injector = new InjectorBuilder(scenario) // - .addOverridingModules(configurator.getModules().stream().filter(module -> !(module instanceof AbstractEqasimExtension)).toList()) // + .addOverridingModules(configurator.getModules().stream() + .filter(module -> !(module instanceof AbstractEqasimExtension)).toList()) // .addOverridingModule(new PopulationRouterModule(numberOfThreads, batchSize, true, modes)) // .addOverridingModule(new TimeInterpretationModule()).build(); PopulationRouter populationRouter = injector.getInstance(PopulationRouter.class); populationRouter.run(scenario.getPopulation()); - clearVehicles(config, scenario); new PopulationWriter(scenario.getPopulation()).write(cmd.getOptionStrict("output-path")); } - - static public void insertVehicles(Config config, Scenario scenario) { - if (config.qsim().getVehiclesSource().equals(VehiclesSource.defaultVehicle)) { - Vehicles vehicles = scenario.getVehicles(); - VehiclesFactory factory = vehicles.getFactory(); - - vehicles.addVehicleType(VehicleUtils.getDefaultVehicleType()); - - for (Person person : scenario.getPopulation().getPersons().values()) { - Map> personVehicles = new HashMap<>(); - - for (String mode : config.routing().getNetworkModes()) { - Vehicle vehicle = factory.createVehicle(Id.createVehicleId(person.getId().toString() + ":" + mode), - VehicleUtils.getDefaultVehicleType()); - vehicles.addVehicle(vehicle); - - personVehicles.put(mode, vehicle.getId()); - } - - VehicleUtils.insertVehicleIdsIntoAttributes(person, personVehicles); - } - } - } - - static public void clearVehicles(Config config, Scenario scenario) { - if (config.qsim().getVehiclesSource().equals(VehiclesSource.defaultVehicle)) { - for (Person person : scenario.getPopulation().getPersons().values()) { - person.getAttributes().removeAttribute("vehicles"); - - for (Plan plan : person.getPlans()) { - for (Leg leg : TripStructureUtils.getLegs(plan)) { - if (leg.getRoute() instanceof NetworkRoute) { - NetworkRoute route = (NetworkRoute) leg.getRoute(); - route.setVehicleId(null); - } - } - } - } - } - } } diff --git a/core/src/main/java/org/eqasim/core/scenario/validation/VehiclesValidator.java b/core/src/main/java/org/eqasim/core/scenario/validation/VehiclesValidator.java new file mode 100644 index 000000000..12d62361b --- /dev/null +++ b/core/src/main/java/org/eqasim/core/scenario/validation/VehiclesValidator.java @@ -0,0 +1,16 @@ +package org.eqasim.core.scenario.validation; + +import org.matsim.core.config.Config; +import org.matsim.core.config.groups.QSimConfigGroup.VehiclesSource; + +public class VehiclesValidator { + static public void validate(Config config) { + boolean missingVehicles = config.vehicles().getVehiclesFile() == null; + boolean wrongVehicleSource = !config.qsim().getVehiclesSource().equals(VehiclesSource.fromVehiclesData); + + if (missingVehicles || wrongVehicleSource) { + throw new IllegalStateException( + "Eqasim now requires every scenario to provide a vehicles file and to use fromVehiclesData in qsim.vehiclesSource. See RunInsertVehicles to retrofit existing scenarios."); + } + } +} diff --git a/core/src/main/java/org/eqasim/core/standalone_mode_choice/RunStandaloneModeChoice.java b/core/src/main/java/org/eqasim/core/standalone_mode_choice/RunStandaloneModeChoice.java index 6ae13803c..1732b73ec 100644 --- a/core/src/main/java/org/eqasim/core/standalone_mode_choice/RunStandaloneModeChoice.java +++ b/core/src/main/java/org/eqasim/core/standalone_mode_choice/RunStandaloneModeChoice.java @@ -28,6 +28,7 @@ import org.eqasim.core.misc.InjectorBuilder; import org.eqasim.core.scenario.routing.RunPopulationRouting; import org.eqasim.core.scenario.validation.ScenarioValidator; +import org.eqasim.core.scenario.validation.VehiclesValidator; import org.eqasim.core.simulation.EqasimConfigurator; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.network.Link; @@ -164,6 +165,7 @@ public static void main(String[] args) throws CommandLine.ConfigurationException Config config = ConfigUtils.loadConfig(cmd.getOptionStrict(CMD_CONFIG_PATH), configGroups); configurator.addOptionalConfigGroups(config); cmd.applyConfiguration(config); + VehiclesValidator.validate(config); Optional travelTimesFactorsPath = cmd.getOption(CMD_TRAVEL_TIMES_FACTORS_PATH); Optional recordedTravelTimesPath = cmd.getOption(CMD_RECORDED_TRAVEL_TIMES_PATH); @@ -187,8 +189,6 @@ public static void main(String[] args) throws CommandLine.ConfigurationException scenarioValidator.checkScenario(scenario); } configurator.adjustScenario(scenario); - //The line below has to be done here right after scenario loading and not in the StandaloneModeChoicePerformer - RunPopulationRouting.insertVehicles(config, scenario); StandaloneModeChoiceConfigurator standaloneModeChoiceConfigurator = cmd.hasOption(MODE_CHOICE_CONFIGURATOR_CLASS) ? StandaloneModeChoiceConfigurator.getSubclassInstance(cmd.getOptionStrict(MODE_CHOICE_CONFIGURATOR_CLASS), config, cmd) : new StandaloneModeChoiceConfigurator(config, cmd); diff --git a/core/src/main/java/org/eqasim/core/standalone_mode_choice/StandaloneModeChoicePerformer.java b/core/src/main/java/org/eqasim/core/standalone_mode_choice/StandaloneModeChoicePerformer.java index 4b94fb144..1060633b7 100644 --- a/core/src/main/java/org/eqasim/core/standalone_mode_choice/StandaloneModeChoicePerformer.java +++ b/core/src/main/java/org/eqasim/core/standalone_mode_choice/StandaloneModeChoicePerformer.java @@ -131,8 +131,6 @@ public void run() throws InterruptedException { } String outputPlansName = outputDirectoryHierarchy.getOutputFilename("output_plans.xml.gz"); - // We do this right here before writing the population file so that following simulations using it work well - RunPopulationRouting.clearVehicles(this.scenario.getConfig(), this.scenario); new PopulationWriter(population).write(outputPlansName); ConfigUtils.writeConfig(scenario.getConfig(), this.outputDirectoryHierarchy.getOutputFilename("output_config.xml")); } diff --git a/core/src/main/resources/melun/config.xml b/core/src/main/resources/melun/config.xml index 3e1ac5464..c2668c938 100644 --- a/core/src/main/resources/melun/config.xml +++ b/core/src/main/resources/melun/config.xml @@ -705,7 +705,7 @@ - + @@ -818,7 +818,7 @@ - + diff --git a/core/src/main/resources/melun/population.xml.gz b/core/src/main/resources/melun/population.xml.gz index 9e84aaf64..7942eeb9c 100644 Binary files a/core/src/main/resources/melun/population.xml.gz and b/core/src/main/resources/melun/population.xml.gz differ diff --git a/core/src/main/resources/melun/vehicles.xml.gz b/core/src/main/resources/melun/vehicles.xml.gz new file mode 100644 index 000000000..6f779f7ea Binary files /dev/null and b/core/src/main/resources/melun/vehicles.xml.gz differ diff --git a/core/src/test/java/org/eqasim/TestEmissions.java b/core/src/test/java/org/eqasim/TestEmissions.java index 5d4a8e73c..21dddcb9d 100644 --- a/core/src/test/java/org/eqasim/TestEmissions.java +++ b/core/src/test/java/org/eqasim/TestEmissions.java @@ -63,6 +63,7 @@ import org.matsim.core.utils.gis.ShapeFileReader; import org.matsim.examples.ExamplesUtils; import org.matsim.utils.objectattributes.attributable.Attributes; +import org.matsim.vehicles.MatsimVehicleReader; import org.matsim.vehicles.MatsimVehicleWriter; import org.matsim.vehicles.Vehicle; import org.matsim.vehicles.VehicleType; @@ -93,7 +94,7 @@ public void tearDown() throws IOException { private void runMelunSimulation() { EqasimConfigurator eqasimConfigurator = new EqasimConfigurator(); - Config config = ConfigUtils.loadConfig("melun_test/input/config_emissions.xml", + Config config = ConfigUtils.loadConfig("melun_test/input/config.xml", eqasimConfigurator.getConfigGroups()); ((ControllerConfigGroup) config.getModules().get(ControllerConfigGroup.GROUP_NAME)) .setOutputDirectory("melun_test/output"); @@ -129,38 +130,27 @@ protected void installEqasimExtension() { controller.run(); } - private void runCreateVehicles() { - VehicleType testCarType = VehicleUtils.createVehicleType(Id.create("test_car", VehicleType.class)); - testCarType.setLength(7.5); - testCarType.setWidth(1.); - testCarType.setNetworkMode("car"); - Attributes hbefa_attributes = testCarType.getEngineInformation().getAttributes(); - hbefa_attributes.putAttribute("HbefaVehicleCategory", "PASSENGER_CAR"); - hbefa_attributes.putAttribute("HbefaTechnology", "diesel"); - hbefa_attributes.putAttribute("HbefaSizeClass", "<1,4L"); - hbefa_attributes.putAttribute("HbefaEmissionsConcept", "PC diesel Euro-3 (DPF)"); - + private void runAddHbefa() { Vehicles vehicles = VehicleUtils.createVehiclesContainer(); - vehicles.addVehicleType(testCarType); - - EqasimConfigurator eqasimConfigurator = new EqasimConfigurator(); - Config config = ConfigUtils.loadConfig("melun_test/input/config.xml", eqasimConfigurator.getConfigGroups()); - Scenario scenario = ScenarioUtils.loadScenario(config); - for (Person person : scenario.getPopulation().getPersons().values()) { - Vehicle vehicle = VehicleUtils.createVehicle(Id.createVehicleId(person.getId().toString()), testCarType); - vehicles.addVehicle(vehicle); + new MatsimVehicleReader(vehicles).readFile("melun_test/input/vehicles.xml.gz"); + + for (VehicleType vehicleType : vehicles.getVehicleTypes().values()) { + Attributes hbefa_attributes = vehicleType.getEngineInformation().getAttributes(); + hbefa_attributes.putAttribute("HbefaVehicleCategory", "PASSENGER_CAR"); + hbefa_attributes.putAttribute("HbefaTechnology", "diesel"); + hbefa_attributes.putAttribute("HbefaSizeClass", "<1,4L"); + hbefa_attributes.putAttribute("HbefaEmissionsConcept", "PC diesel Euro-3 (DPF)"); } MatsimVehicleWriter writer = new MatsimVehicleWriter(vehicles); - writer.writeFile("melun_test/input/vehicles.xml"); + writer.writeFile("melun_test/input/vehicles.xml.gz"); + } - + private void runModifyConfig() { Config config = ConfigUtils.loadConfig("melun_test/input/config.xml"); config.controller().setOutputDirectory("melun_test/output"); - config.qsim().setVehiclesSource(QSimConfigGroup.VehiclesSource.fromVehiclesData); - config.vehicles().setVehiclesFile("vehicles.xml"); - ConfigUtils.writeConfig(config, "melun_test/input/config_emissions.xml"); + ConfigUtils.writeConfig(config, "melun_test/input/config.xml"); } private void runModifyNetwork() { @@ -184,7 +174,7 @@ private void runMelunEmissions() throws CommandLine.ConfigurationException, IOEx Assert.assertEquals(3412, (long) counts.getOrDefault("bike", 0L)); Assert.assertEquals(2108, (long) counts.get("pt")); - RunComputeEmissionsEvents.main(new String[] { "--config-path", "melun_test/input/config_emissions.xml", + RunComputeEmissionsEvents.main(new String[] { "--config-path", "melun_test/input/config.xml", "--hbefa-cold-avg", "sample_41_EFA_ColdStart_vehcat_2020average.csv", "--hbefa-hot-avg", "sample_41_EFA_HOT_vehcat_2020average.csv", "--hbefa-cold-detailed", "sample_41_EFA_ColdStart_SubSegm_2020detailed.csv", "--hbefa-hot-detailed", @@ -192,7 +182,7 @@ private void runMelunEmissions() throws CommandLine.ConfigurationException, IOEx assertEquals(355977, countLines(new File("melun_test/output/output_emissions_events.xml.gz"))); - RunExportEmissionsNetwork.main(new String[] { "--config-path", "melun_test/input/config_emissions.xml", + RunExportEmissionsNetwork.main(new String[] { "--config-path", "melun_test/input/config.xml", "--pollutants", "PM,CO,NOx,Unknown", "--time-bin-size", "3600" }); Collection features = ShapeFileReader.getAllFeatures("melun_test/output/emissions_network.shp"); @@ -222,7 +212,7 @@ private void runMelunEmissions() throws CommandLine.ConfigurationException, IOEx @Test public void runTestEmissions() throws CommandLine.ConfigurationException, IOException { - runCreateVehicles(); + runAddHbefa(); runModifyConfig(); runModifyNetwork(); runMelunSimulation(); diff --git a/core/src/test/java/org/eqasim/TestSimulationPipeline.java b/core/src/test/java/org/eqasim/TestSimulationPipeline.java index 9e0b0373b..b09c89273 100644 --- a/core/src/test/java/org/eqasim/TestSimulationPipeline.java +++ b/core/src/test/java/org/eqasim/TestSimulationPipeline.java @@ -212,6 +212,8 @@ private void runCutter() throws Exception { "--prefix", "center_", "--extent-path", "melun_test/input/center.shp" }); + + runMelunSimulation("melun_test/cutter/center_config.xml", "melun_test/output_cutter"); } public void runCutterV2() throws CommandLine.ConfigurationException, IOException, InterruptedException { diff --git a/ile_de_france/src/main/java/org/eqasim/ile_de_france/IDFConfigurator.java b/ile_de_france/src/main/java/org/eqasim/ile_de_france/IDFConfigurator.java index 044312764..788f9b82d 100644 --- a/ile_de_france/src/main/java/org/eqasim/ile_de_france/IDFConfigurator.java +++ b/ile_de_france/src/main/java/org/eqasim/ile_de_france/IDFConfigurator.java @@ -1,28 +1,7 @@ package org.eqasim.ile_de_france; import org.eqasim.core.simulation.EqasimConfigurator; -import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.Scenario; -import org.matsim.api.core.v01.population.Person; -import org.matsim.core.config.Config; -import org.matsim.core.config.groups.QSimConfigGroup; -import org.matsim.vehicles.Vehicle; -import org.matsim.vehicles.VehicleUtils; - -import java.util.HashMap; -import java.util.Map; public class IDFConfigurator extends EqasimConfigurator { - public void adjustScenario(Scenario scenario) { - // if there is a vehicles file defined in config, manually assign them to their agents - Config config = scenario.getConfig(); - if (config.qsim().getVehiclesSource() == QSimConfigGroup.VehiclesSource.fromVehiclesData) { - for (Person person : scenario.getPopulation().getPersons().values()) { - Id vehicleId = Id.createVehicleId(person.getId()); - Map> modeVehicle = new HashMap<>(); - modeVehicle.put("car", vehicleId); - VehicleUtils.insertVehicleIdsIntoAttributes(person, modeVehicle); - } - } - } + } diff --git a/ile_de_france/src/main/java/org/eqasim/ile_de_france/RunSimulation.java b/ile_de_france/src/main/java/org/eqasim/ile_de_france/RunSimulation.java index 4ca601e7d..4a5ce91bd 100644 --- a/ile_de_france/src/main/java/org/eqasim/ile_de_france/RunSimulation.java +++ b/ile_de_france/src/main/java/org/eqasim/ile_de_france/RunSimulation.java @@ -1,5 +1,6 @@ package org.eqasim.ile_de_france; +import org.eqasim.core.scenario.validation.VehiclesValidator; import org.eqasim.core.simulation.analysis.EqasimAnalysisModule; import org.eqasim.core.simulation.mode_choice.EqasimModeChoiceModule; import org.eqasim.ile_de_france.mode_choice.IDFModeChoiceModule; @@ -22,6 +23,7 @@ static public void main(String[] args) throws ConfigurationException { Config config = ConfigUtils.loadConfig(cmd.getOptionStrict("config-path"), configurator.getConfigGroups()); configurator.addOptionalConfigGroups(config); cmd.applyConfiguration(config); + VehiclesValidator.validate(config); Scenario scenario = ScenarioUtils.createScenario(config); configurator.configureScenario(scenario); diff --git a/ile_de_france/src/main/java/org/eqasim/ile_de_france/scenario/RunAdaptConfig.java b/ile_de_france/src/main/java/org/eqasim/ile_de_france/scenario/RunAdaptConfig.java index 625fcebb4..a171cbef6 100644 --- a/ile_de_france/src/main/java/org/eqasim/ile_de_france/scenario/RunAdaptConfig.java +++ b/ile_de_france/src/main/java/org/eqasim/ile_de_france/scenario/RunAdaptConfig.java @@ -8,6 +8,9 @@ import org.matsim.contribs.discrete_mode_choice.modules.config.DiscreteModeChoiceConfigGroup; import org.matsim.core.config.CommandLine.ConfigurationException; import org.matsim.core.config.Config; +import org.matsim.core.config.groups.QSimConfigGroup; +import org.matsim.core.config.groups.QSimConfigGroup.VehiclesSource; +import org.matsim.core.config.groups.VehiclesConfigGroup; public class RunAdaptConfig { static public void main(String[] args) throws ConfigurationException { @@ -15,7 +18,7 @@ static public void main(String[] args) throws ConfigurationException { ConfigAdapter.run(args, configurator.getConfigGroups(), RunAdaptConfig::adaptConfiguration); } - static public void adaptConfiguration(Config config) { + static public void adaptConfiguration(Config config, String prefix) { // Adjust eqasim config EqasimConfigGroup eqasimConfig = EqasimConfigGroup.get(config); @@ -37,5 +40,12 @@ static public void adaptConfiguration(Config config) { config.qsim().setFlowCapFactor(0.045); config.qsim().setStorageCapFactor(0.045); } + + // Vehicles + QSimConfigGroup qsimConfig = config.qsim(); + qsimConfig.setVehiclesSource(VehiclesSource.fromVehiclesData); + + VehiclesConfigGroup vehiclesConfig = config.vehicles(); + vehiclesConfig.setVehiclesFile(prefix + "vehicles.xml.gz"); } } diff --git a/ile_de_france/src/test/java/org/eqasim/ile_de_france/TestCorisica.java b/ile_de_france/src/test/java/org/eqasim/ile_de_france/TestCorisica.java index c21ab644a..3423fa884 100644 --- a/ile_de_france/src/test/java/org/eqasim/ile_de_france/TestCorisica.java +++ b/ile_de_france/src/test/java/org/eqasim/ile_de_france/TestCorisica.java @@ -8,6 +8,7 @@ import java.util.Map; import org.apache.commons.io.FileUtils; +import org.eqasim.core.scenario.RunInsertVehicles; import org.eqasim.core.scenario.cutter.RunScenarioCutter; import org.eqasim.core.standalone_mode_choice.RunStandaloneModeChoice; import org.junit.After; @@ -18,7 +19,10 @@ import org.matsim.api.core.v01.events.handler.PersonDepartureEventHandler; import org.matsim.core.api.experimental.events.EventsManager; import org.matsim.core.config.CommandLine.ConfigurationException; +import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.ConfigWriter; +import org.matsim.core.config.groups.QSimConfigGroup.VehiclesSource; import org.matsim.core.events.EventsUtils; import org.matsim.core.events.MatsimEventsReader; import org.matsim.core.population.io.PopulationReader; @@ -36,6 +40,14 @@ public void tearDown() throws IOException { FileUtils.deleteDirectory(new File("corsica_test")); } + private void adjustConfig() { + IDFConfigurator configurator = new IDFConfigurator(); + Config config = ConfigUtils.loadConfig("corsica_test/corsica_config.xml", configurator.getConfigGroups()); + config.vehicles().setVehiclesFile("corsica_vehicles.xml.gz"); + config.qsim().setVehiclesSource(VehiclesSource.fromVehiclesData); + new ConfigWriter(config).write("corsica_test/corsica_config.xml"); + } + @Test public void testCorsicaPipeline() throws ConfigurationException, InterruptedException, MalformedURLException, IOException { @@ -44,6 +56,15 @@ public void testCorsicaPipeline() // Run the simulation { + adjustConfig(); + + RunInsertVehicles.main(new String[] { // + "--config-path", "corsica_test/corsica_config.xml", // + "--input-population-path", "corsica_test/corsica_population.xml.gz", // + "--output-population-path", "corsica_test/corsica_population.xml.gz", // + "--output-vehicles-path", "corsica_test/corsica_vehicles.xml.gz", // + }); + RunSimulation.main(new String[] { // "--config-path", "corsica_test/corsica_config.xml", // "--config:controler.lastIteration", "2", // , @@ -75,10 +96,9 @@ public void testCorsicaPipeline() } // Cut the scenario based on output plans - { + { RunScenarioCutter.main(new String[] { // "--config-path", "corsica_test/corsica_config.xml", // - "--config:plans.inputPlansFile", "simulation_output/output_plans.xml.gz", // "--extent-path", "corsica_test/extent.shp", // "--threads", "4", // "--prefix", "cut_", // @@ -89,7 +109,7 @@ public void testCorsicaPipeline() } // Run the cut simulation - { + { RunSimulation.main(new String[] { // "--config-path", "corsica_test/cut_config.xml", // "--config:controler.lastIteration", "2", // , @@ -97,9 +117,9 @@ public void testCorsicaPipeline() }); Map counts = countLegs("corsica_test/cut_output/output_events.xml.gz"); - Assert.assertEquals(420, (long) counts.get("car")); + Assert.assertEquals(422, (long) counts.get("car")); Assert.assertEquals(53, (long) counts.get("car_passenger")); - Assert.assertEquals(103, (long) counts.get("walk")); + Assert.assertEquals(101, (long) counts.get("walk")); Assert.assertEquals(0, (long) counts.getOrDefault("bike", 0L)); Assert.assertEquals(0, (long) counts.getOrDefault("pt", 0L)); Assert.assertEquals(6, (long) counts.get("outside")); diff --git a/los_angeles/src/main/java/org/eqasim/los_angeles/scenario/RunAdaptConfig.java b/los_angeles/src/main/java/org/eqasim/los_angeles/scenario/RunAdaptConfig.java index aee94feef..96e03a1da 100644 --- a/los_angeles/src/main/java/org/eqasim/los_angeles/scenario/RunAdaptConfig.java +++ b/los_angeles/src/main/java/org/eqasim/los_angeles/scenario/RunAdaptConfig.java @@ -24,7 +24,7 @@ static public void main(String[] args) throws ConfigurationException { ConfigAdapter.run(args, configurator.getConfigGroups(), RunAdaptConfig::adaptConfiguration); } - static public void adaptConfiguration(Config config) { + static public void adaptConfiguration(Config config, String prefix) { // Ignore some input files config.transit().setVehiclesFile(null); config.households().setInputFile(null); diff --git a/san_francisco/src/main/java/org/eqasim/san_francisco/scenario/RunAdaptConfig.java b/san_francisco/src/main/java/org/eqasim/san_francisco/scenario/RunAdaptConfig.java index 416d2af9e..e1d87b39f 100644 --- a/san_francisco/src/main/java/org/eqasim/san_francisco/scenario/RunAdaptConfig.java +++ b/san_francisco/src/main/java/org/eqasim/san_francisco/scenario/RunAdaptConfig.java @@ -25,7 +25,7 @@ static public void main(String[] args) throws ConfigurationException { ConfigAdapter.run(args, configurator.getConfigGroups(), RunAdaptConfig::adaptConfiguration); } - static public void adaptConfiguration(Config config) { + static public void adaptConfiguration(Config config, String prefix) { // Set up mode choice EqasimConfigGroup eqasimConfig = EqasimConfigGroup.get(config); diff --git a/sao_paulo/src/main/java/org/eqasim/sao_paulo/scenario/RunAdaptConfig.java b/sao_paulo/src/main/java/org/eqasim/sao_paulo/scenario/RunAdaptConfig.java index 5d8e4ebe0..d4f3867ee 100644 --- a/sao_paulo/src/main/java/org/eqasim/sao_paulo/scenario/RunAdaptConfig.java +++ b/sao_paulo/src/main/java/org/eqasim/sao_paulo/scenario/RunAdaptConfig.java @@ -21,7 +21,7 @@ static public void main(String[] args) throws ConfigurationException { ConfigAdapter.run(args, configurator.getConfigGroups(), RunAdaptConfig::adaptConfiguration); } - static public void adaptConfiguration(Config config) { + static public void adaptConfiguration(Config config, String prefix) { // Ignore some input files // config.transit().setVehiclesFile(null); // config.households().setInputFile(null);