Skip to content

Commit ece4932

Browse files
sebhoerlTarek Chouaki
and
Tarek Chouaki
authored
feat: require vehicles for IDF by default (#227)
* feat: require vehiclces for IDF by default BREAKING CHANGE: scenarios without vehicles will not work anymore * add script for retrofitting * fix retrofit script * change vehicles path in cutter * fixed for cutting with vehicles * chore: moving RunInsertVehicles to core * fix: adding vehicles if necessary * chore: running a scenario resulting from the RunScenarioCutter in the tests * revert auto-generation of vehicles and bugfix in cleaning vehicles * avoid deprecated call * update vehicles in test scenario * fix emission tests * make cutting vehicles optional * revert optional vehicles and add verification * add validator to SMC * fix corsica tests --------- Co-authored-by: Tarek Chouaki <[email protected]>
1 parent ad293ff commit ece4932

File tree

23 files changed

+209
-146
lines changed

23 files changed

+209
-146
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package org.eqasim.core.components.config;
22

3-
import java.util.function.Consumer;
4-
53
import org.matsim.core.config.CommandLine;
64
import org.matsim.core.config.CommandLine.ConfigurationException;
75
import org.matsim.core.config.Config;
@@ -10,16 +8,19 @@
108
import org.matsim.core.config.ConfigWriter;
119

1210
public class ConfigAdapter {
13-
static public void run(String[] args, ConfigGroup[] modules, Consumer<Config> adapter)
11+
static public void run(String[] args, ConfigGroup[] modules, ConfigAdapterConsumer adapter)
1412
throws ConfigurationException {
1513
CommandLine cmd = new CommandLine.Builder(args) //
16-
.requireOptions("input-path", "output-path") //
14+
.requireOptions("input-path", "output-path", "prefix") //
1715
.build();
1816

1917
Config config = ConfigUtils.loadConfig(cmd.getOptionStrict("input-path"), modules);
20-
adapter.accept(config);
18+
adapter.accept(config, cmd.getOptionStrict("prefix"));
2119

2220
new ConfigWriter(config).write(cmd.getOptionStrict("output-path"));
2321
}
24-
22+
23+
public interface ConfigAdapterConsumer {
24+
void accept(Config config, String prefix);
25+
}
2526
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.eqasim.core.scenario;
2+
3+
import java.io.UncheckedIOException;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
7+
import org.matsim.api.core.v01.Id;
8+
import org.matsim.api.core.v01.Scenario;
9+
import org.matsim.api.core.v01.population.Person;
10+
import org.matsim.core.config.CommandLine;
11+
import org.matsim.core.config.CommandLine.ConfigurationException;
12+
import org.matsim.core.config.Config;
13+
import org.matsim.core.config.ConfigUtils;
14+
import org.matsim.core.population.io.PopulationReader;
15+
import org.matsim.core.population.io.PopulationWriter;
16+
import org.matsim.core.scenario.ScenarioUtils;
17+
import org.matsim.vehicles.MatsimVehicleWriter;
18+
import org.matsim.vehicles.Vehicle;
19+
import org.matsim.vehicles.VehicleUtils;
20+
import org.matsim.vehicles.Vehicles;
21+
import org.matsim.vehicles.VehiclesFactory;
22+
23+
public class RunInsertVehicles {
24+
25+
static public void insertVehicles(Config config, Scenario scenario) {
26+
Vehicles vehicles = scenario.getVehicles();
27+
VehiclesFactory factory = vehicles.getFactory();
28+
29+
vehicles.addVehicleType(VehicleUtils.getDefaultVehicleType());
30+
for (Person person : scenario.getPopulation().getPersons().values()) {
31+
Map<String, Id<Vehicle>> personVehicles = new HashMap<>();
32+
33+
for (String mode : config.routing().getNetworkModes()) {
34+
Vehicle vehicle = factory.createVehicle(Id.createVehicleId(person.getId().toString() + ":" + mode),
35+
VehicleUtils.getDefaultVehicleType());
36+
vehicles.addVehicle(vehicle);
37+
38+
personVehicles.put(mode, vehicle.getId());
39+
}
40+
41+
VehicleUtils.insertVehicleIdsIntoPersonAttributes(person, personVehicles);
42+
}
43+
}
44+
45+
static public void main(String[] args) throws UncheckedIOException, ConfigurationException {
46+
CommandLine cmd = new CommandLine.Builder(args) //
47+
.requireOptions("config-path", "input-population-path", "output-vehicles-path",
48+
"output-population-path") //
49+
.build();
50+
51+
Config config = ConfigUtils.loadConfig(cmd.getOptionStrict("config-path"));
52+
Scenario scenario = ScenarioUtils.createScenario(ConfigUtils.createConfig());
53+
new PopulationReader(scenario).readFile(cmd.getOptionStrict("input-population-path"));
54+
55+
insertVehicles(config, scenario);
56+
57+
new MatsimVehicleWriter(scenario.getVehicles()).writeFile(cmd.getOptionStrict("output-vehicles-path"));
58+
new PopulationWriter(scenario.getPopulation()).write(cmd.getOptionStrict("output-population-path"));
59+
}
60+
}

core/src/main/java/org/eqasim/core/scenario/cutter/ConfigCutter.java

+1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ public void run(Config config) {
1616
config.households().setInputFile(prefix + "households.xml.gz");
1717
config.transit().setTransitScheduleFile(prefix + "transit_schedule.xml.gz");
1818
config.transit().setVehiclesFile(prefix + "transit_vehicles.xml.gz");
19+
config.vehicles().setVehiclesFile(prefix + "vehicles.xml.gz");
1920
}
2021
}

core/src/main/java/org/eqasim/core/scenario/cutter/RunScenarioCutter.java

+17-7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.eqasim.core.scenario.cutter.network.RoadNetwork;
1818
import org.eqasim.core.scenario.cutter.outside.OutsideActivityAdapter;
1919
import org.eqasim.core.scenario.cutter.population.CleanHouseholds;
20+
import org.eqasim.core.scenario.cutter.population.CleanVehicles;
2021
import org.eqasim.core.scenario.cutter.population.PopulationCutter;
2122
import org.eqasim.core.scenario.cutter.population.PopulationCutterModule;
2223
import org.eqasim.core.scenario.cutter.population.RemoveEmptyPlans;
@@ -27,6 +28,7 @@
2728
import org.eqasim.core.scenario.routing.PopulationRouter;
2829
import org.eqasim.core.scenario.routing.PopulationRouterModule;
2930
import org.eqasim.core.scenario.validation.ScenarioValidator;
31+
import org.eqasim.core.scenario.validation.VehiclesValidator;
3032
import org.eqasim.core.simulation.EqasimConfigurator;
3133
import org.eqasim.core.simulation.mode_choice.AbstractEqasimExtension;
3234
import org.eqasim.core.simulation.termination.EqasimTerminationModule;
@@ -43,10 +45,10 @@
4345
public class RunScenarioCutter {
4446

4547
public static final Collection<String> REQUIRED_ARGS = Set.of("config-path", "output-path", "extent-path");
46-
public static final Collection<String> OPTIONAL_ARGS = Set.of("threads", "prefix", "extent-attribute", "extent-value", "plans-path", "events-path", "skip-routing");
48+
public static final Collection<String> OPTIONAL_ARGS = Set.of("threads", "prefix", "extent-attribute",
49+
"extent-value", "plans-path", "events-path", "skip-routing");
4750

48-
static public void main(String[] args)
49-
throws ConfigurationException, IOException, InterruptedException {
51+
static public void main(String[] args) throws ConfigurationException, IOException, InterruptedException {
5052
CommandLine cmd = new CommandLine.Builder(args) //
5153
.requireOptions(REQUIRED_ARGS) //
5254
.allowOptions(OPTIONAL_ARGS) //
@@ -69,10 +71,12 @@ static public void main(String[] args)
6971
// Load scenario
7072
EqasimConfigurator configurator = new EqasimConfigurator();
7173
configurator.getModules().removeIf(m -> m instanceof EqasimTerminationModule);
72-
74+
7375
Config config = ConfigUtils.loadConfig(cmd.getOptionStrict("config-path"), configurator.getConfigGroups());
7476
cmd.applyConfiguration(config);
7577

78+
VehiclesValidator.validate(config);
79+
7680
Optional<String> plansPath = cmd.getOption("plans-path");
7781

7882
if (plansPath.isPresent()) {
@@ -106,7 +110,8 @@ static public void main(String[] args)
106110

107111
// Cut population
108112
Injector populationCutterInjector = new InjectorBuilder(scenario) //
109-
.addOverridingModules(configurator.getModules().stream().filter(module -> !(module instanceof AbstractEqasimExtension)).toList()) //
113+
.addOverridingModules(configurator.getModules().stream()
114+
.filter(module -> !(module instanceof AbstractEqasimExtension)).toList()) //
110115
.addOverridingModule(
111116
new PopulationCutterModule(extent, numberOfThreads, 40, cmd.getOption("events-path"))) //
112117
.addOverridingModule(new CutterTravelTimeModule(travelTime)) //
@@ -128,6 +133,10 @@ static public void main(String[] args)
128133
CleanHouseholds cleanHouseholds = new CleanHouseholds(scenario.getPopulation());
129134
cleanHouseholds.run(scenario.getHouseholds());
130135

136+
// .. and make vehicles consistent
137+
CleanVehicles cleanVehicles = new CleanVehicles(scenario.getPopulation());
138+
cleanVehicles.run(scenario.getVehicles());
139+
131140
// Cut transit
132141
StopSequenceCrossingPointFinder stopSequenceCrossingPointFinder = new DefaultStopSequenceCrossingPointFinder(
133142
extent);
@@ -159,15 +168,16 @@ static public void main(String[] args)
159168

160169
// Final routing
161170
Injector routingInjector = new InjectorBuilder(scenario) //
162-
.addOverridingModules(configurator.getModules().stream().filter(module -> !(module instanceof AbstractEqasimExtension)).toList()) //
171+
.addOverridingModules(configurator.getModules().stream()
172+
.filter(module -> !(module instanceof AbstractEqasimExtension)).toList()) //
163173
.addOverridingModule(new PopulationRouterModule(numberOfThreads, 100, false)) //
164174
.addOverridingModule(new CutterTravelTimeModule(travelTime)) //
165175
.addOverridingModule(new TimeInterpretationModule()) //
166176
.build();
167177

168178
boolean skipRouting = Boolean.parseBoolean(cmd.getOption("skip-routing").orElse("false"));
169179

170-
if(!skipRouting) {
180+
if (!skipRouting) {
171181
PopulationRouter router = routingInjector.getInstance(PopulationRouter.class);
172182
router.run(scenario.getPopulation());
173183
// Check validity after cutting

core/src/main/java/org/eqasim/core/scenario/cutter/RunScenarioCutterV2.java

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
package org.eqasim.core.scenario.cutter;
22

3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.nio.file.Paths;
6+
import java.util.ArrayList;
7+
import java.util.HashSet;
8+
import java.util.List;
9+
import java.util.Optional;
10+
import java.util.Set;
11+
312
import org.apache.commons.io.FileUtils;
413
import org.eqasim.core.scenario.cutter.extent.ScenarioExtent;
514
import org.eqasim.core.scenario.cutter.extent.ShapeScenarioExtent;
@@ -20,11 +29,6 @@
2029
import org.matsim.core.population.io.PopulationReader;
2130
import org.matsim.core.scenario.ScenarioUtils;
2231

23-
import java.io.File;
24-
import java.io.IOException;
25-
import java.nio.file.Paths;
26-
import java.util.*;
27-
2832
public class RunScenarioCutterV2 {
2933

3034
public static final String[] SHAPEFILE_EXTENSIONS = new String[]{".shp", ".cpg", ".dbf", ".qmd", ".shx", ".prj"};

core/src/main/java/org/eqasim/core/scenario/cutter/ScenarioWriter.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,8 @@ public void run(File outputDirectory) {
4242
.writeFile(new File(outputDirectory, prefix + "transit_schedule.xml.gz").toString());
4343
new MatsimVehicleWriter(scenario.getTransitVehicles())
4444
.writeFile(new File(outputDirectory, prefix + "transit_vehicles.xml.gz").toString());
45-
46-
if (config.vehicles().getVehiclesFile() != null) {
47-
new MatsimVehicleWriter(scenario.getVehicles())
48-
.writeFile(new File(outputDirectory, prefix + "vehicles.xml.gz").toString());
49-
}
50-
45+
new MatsimVehicleWriter(scenario.getVehicles())
46+
.writeFile(new File(outputDirectory, prefix + "vehicles.xml.gz").toString());
5147
}
5248

5349
static void checkOutputDirectory(File outputDirectory) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.eqasim.core.scenario.cutter.population;
2+
3+
import org.matsim.api.core.v01.IdSet;
4+
import org.matsim.api.core.v01.population.Person;
5+
import org.matsim.api.core.v01.population.Population;
6+
import org.matsim.vehicles.Vehicle;
7+
import org.matsim.vehicles.VehicleUtils;
8+
import org.matsim.vehicles.Vehicles;
9+
10+
public class CleanVehicles {
11+
private final IdSet<Vehicle> retainedIds = new IdSet<>(Vehicle.class);
12+
13+
public CleanVehicles(Population population) {
14+
for (Person person : population.getPersons().values()) {
15+
retainedIds.addAll(VehicleUtils.getVehicleIds(person).values());
16+
}
17+
}
18+
19+
public void run(Vehicles vehicles) {
20+
IdSet<Vehicle> removeIds = new IdSet<>(Vehicle.class);
21+
removeIds.addAll(vehicles.getVehicles().keySet());
22+
removeIds.removeAll(retainedIds);
23+
24+
removeIds.forEach(vehicles::removeVehicle);
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,22 @@
11
package org.eqasim.core.scenario.routing;
22

3-
import java.util.HashMap;
43
import java.util.HashSet;
5-
import java.util.Map;
64
import java.util.Set;
75

86
import org.eqasim.core.misc.InjectorBuilder;
7+
import org.eqasim.core.scenario.validation.VehiclesValidator;
98
import org.eqasim.core.simulation.EqasimConfigurator;
109
import org.eqasim.core.simulation.mode_choice.AbstractEqasimExtension;
1110
import org.eqasim.core.simulation.termination.EqasimTerminationConfigGroup;
12-
import org.matsim.api.core.v01.Id;
1311
import org.matsim.api.core.v01.Scenario;
14-
import org.matsim.api.core.v01.population.Leg;
15-
import org.matsim.api.core.v01.population.Person;
16-
import org.matsim.api.core.v01.population.Plan;
1712
import org.matsim.core.config.CommandLine;
1813
import org.matsim.core.config.CommandLine.ConfigurationException;
1914
import org.matsim.core.config.Config;
2015
import org.matsim.core.config.ConfigUtils;
21-
import org.matsim.core.config.groups.QSimConfigGroup.VehiclesSource;
2216
import org.matsim.core.population.io.PopulationWriter;
23-
import org.matsim.core.population.routes.NetworkRoute;
24-
import org.matsim.core.router.TripStructureUtils;
2517
import org.matsim.core.scenario.ScenarioUtils;
2618
import org.matsim.core.utils.timing.TimeInterpretationModule;
2719
import org.matsim.facilities.ActivityFacility;
28-
import org.matsim.vehicles.Vehicle;
29-
import org.matsim.vehicles.VehicleUtils;
30-
import org.matsim.vehicles.Vehicles;
31-
import org.matsim.vehicles.VehiclesFactory;
3220

3321
import com.google.inject.Injector;
3422

@@ -41,17 +29,17 @@ static public void main(String[] args) throws ConfigurationException, Interrupte
4129

4230
EqasimConfigurator configurator = new EqasimConfigurator();
4331
Config config = ConfigUtils.loadConfig(cmd.getOptionStrict("config-path"), configurator.getConfigGroups());
44-
config.getModules().remove(EqasimTerminationConfigGroup.GROUP_NAME);
32+
config.getModules().remove(EqasimTerminationConfigGroup.GROUP_NAME);
4533
configurator.addOptionalConfigGroups(config);
4634
cmd.applyConfiguration(config);
4735
config.replanning().clearStrategySettings();
36+
VehiclesValidator.validate(config);
4837

4938
int batchSize = cmd.getOption("batch-size").map(Integer::parseInt).orElse(100);
5039
int numberOfThreads = cmd.getOption("threads").map(Integer::parseInt)
5140
.orElse(Runtime.getRuntime().availableProcessors());
5241

5342
Scenario scenario = ScenarioUtils.loadScenario(config);
54-
insertVehicles(config, scenario);
5543

5644
if (scenario.getActivityFacilities() != null) {
5745
for (ActivityFacility facility : scenario.getActivityFacilities().getFacilities().values()) {
@@ -70,54 +58,14 @@ static public void main(String[] args) throws ConfigurationException, Interrupte
7058
}
7159

7260
Injector injector = new InjectorBuilder(scenario) //
73-
.addOverridingModules(configurator.getModules().stream().filter(module -> !(module instanceof AbstractEqasimExtension)).toList()) //
61+
.addOverridingModules(configurator.getModules().stream()
62+
.filter(module -> !(module instanceof AbstractEqasimExtension)).toList()) //
7463
.addOverridingModule(new PopulationRouterModule(numberOfThreads, batchSize, true, modes)) //
7564
.addOverridingModule(new TimeInterpretationModule()).build();
7665

7766
PopulationRouter populationRouter = injector.getInstance(PopulationRouter.class);
7867
populationRouter.run(scenario.getPopulation());
7968

80-
clearVehicles(config, scenario);
8169
new PopulationWriter(scenario.getPopulation()).write(cmd.getOptionStrict("output-path"));
8270
}
83-
84-
static public void insertVehicles(Config config, Scenario scenario) {
85-
if (config.qsim().getVehiclesSource().equals(VehiclesSource.defaultVehicle)) {
86-
Vehicles vehicles = scenario.getVehicles();
87-
VehiclesFactory factory = vehicles.getFactory();
88-
89-
vehicles.addVehicleType(VehicleUtils.getDefaultVehicleType());
90-
91-
for (Person person : scenario.getPopulation().getPersons().values()) {
92-
Map<String, Id<Vehicle>> personVehicles = new HashMap<>();
93-
94-
for (String mode : config.routing().getNetworkModes()) {
95-
Vehicle vehicle = factory.createVehicle(Id.createVehicleId(person.getId().toString() + ":" + mode),
96-
VehicleUtils.getDefaultVehicleType());
97-
vehicles.addVehicle(vehicle);
98-
99-
personVehicles.put(mode, vehicle.getId());
100-
}
101-
102-
VehicleUtils.insertVehicleIdsIntoAttributes(person, personVehicles);
103-
}
104-
}
105-
}
106-
107-
static public void clearVehicles(Config config, Scenario scenario) {
108-
if (config.qsim().getVehiclesSource().equals(VehiclesSource.defaultVehicle)) {
109-
for (Person person : scenario.getPopulation().getPersons().values()) {
110-
person.getAttributes().removeAttribute("vehicles");
111-
112-
for (Plan plan : person.getPlans()) {
113-
for (Leg leg : TripStructureUtils.getLegs(plan)) {
114-
if (leg.getRoute() instanceof NetworkRoute) {
115-
NetworkRoute route = (NetworkRoute) leg.getRoute();
116-
route.setVehicleId(null);
117-
}
118-
}
119-
}
120-
}
121-
}
122-
}
12371
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.eqasim.core.scenario.validation;
2+
3+
import org.matsim.core.config.Config;
4+
import org.matsim.core.config.groups.QSimConfigGroup.VehiclesSource;
5+
6+
public class VehiclesValidator {
7+
static public void validate(Config config) {
8+
boolean missingVehicles = config.vehicles().getVehiclesFile() == null;
9+
boolean wrongVehicleSource = !config.qsim().getVehiclesSource().equals(VehiclesSource.fromVehiclesData);
10+
11+
if (missingVehicles || wrongVehicleSource) {
12+
throw new IllegalStateException(
13+
"Eqasim now requires every scenario to provide a vehicles file and to use fromVehiclesData in qsim.vehiclesSource. See RunInsertVehicles to retrofit existing scenarios.");
14+
}
15+
}
16+
}

0 commit comments

Comments
 (0)