Skip to content

Commit f129993

Browse files
Merge pull request #133 from moia-oss/master
Update MATSim CW 7(2)
2 parents 00bb005 + c0a6c24 commit f129993

File tree

49 files changed

+895
-496
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+895
-496
lines changed

contribs/application/src/main/java/org/matsim/application/CommandRunner.java

+16-4
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77
import org.jgrapht.graph.DefaultEdge;
88
import org.jgrapht.graph.DirectedAcyclicGraph;
99
import org.jgrapht.traverse.BreadthFirstIterator;
10-
import org.matsim.application.options.CrsOptions;
11-
import org.matsim.application.options.InputOptions;
12-
import org.matsim.application.options.SampleOptions;
13-
import org.matsim.application.options.ShpOptions;
10+
import org.matsim.application.options.*;
1411

1512
import java.nio.file.Files;
1613
import java.nio.file.Path;
@@ -33,6 +30,7 @@ public final class CommandRunner {
3330
private String defaultShp = null;
3431
private String defaultCrs = null;
3532
private Double defaultSampleSize = null;
33+
private String configPath = null;
3634

3735

3836
/**
@@ -216,6 +214,13 @@ private String[] createArgs(Class<? extends MATSimAppCommand> command, String[]
216214
}
217215
}
218216

217+
if (ApplicationUtils.acceptsOptions(command, ConfigOptions.class) && !ArrayUtils.contains(existingArgs, "--config")) {
218+
if (configPath != null) {
219+
args.add("--config");
220+
args.add(configPath);
221+
}
222+
}
223+
219224
// Adds output arguments for this class
220225
for (String produce : spec.produces()) {
221226
String arg = "--output-" + InputOptions.argName(produce);
@@ -351,6 +356,13 @@ public void setCRS(String crs) {
351356
defaultCrs = crs;
352357
}
353358

359+
/**
360+
* Set a config path, which is passed to command using {@link ConfigOptions}.
361+
*/
362+
public void setConfigPath(String configPath) {
363+
this.configPath = configPath;
364+
}
365+
354366
/**
355367
* Set the default sample size that is passed as input to commands.
356368
*/

contribs/application/src/main/java/org/matsim/application/analysis/activity/ActivityCountAnalysis.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public class ActivityCountAnalysis implements MATSimAppCommand {
5656
/**
5757
* Specifies activity types that should be counted only once per agent per region.
5858
*/
59-
@CommandLine.Option(names = "--single-occurrence", description = "Activity types that are only counted once per agent")
59+
@CommandLine.Option(names = "--single-occurrence", description = "Activity types that are only counted once per agent", split = ";")
6060
private Set<String> singleOccurrence;
6161

6262
public static void main(String[] args) {

contribs/application/src/main/java/org/matsim/application/analysis/emissions/AirPollutionAnalysis.java

+5-6
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@
1919
import org.matsim.application.CommandSpec;
2020
import org.matsim.application.MATSimAppCommand;
2121
import org.matsim.application.avro.XYTData;
22-
import org.matsim.application.options.InputOptions;
23-
import org.matsim.application.options.OutputOptions;
24-
import org.matsim.application.options.SampleOptions;
25-
import org.matsim.application.options.ShpOptions;
22+
import org.matsim.application.options.*;
2623
import org.matsim.contrib.analysis.time.TimeBinMap;
2724
import org.matsim.contrib.emissions.EmissionModule;
2825
import org.matsim.contrib.emissions.Pollutant;
@@ -32,7 +29,6 @@
3229
import org.matsim.contrib.emissions.analysis.Raster;
3330
import org.matsim.core.api.experimental.events.EventsManager;
3431
import org.matsim.core.config.Config;
35-
import org.matsim.core.config.ConfigUtils;
3632
import org.matsim.core.controler.AbstractModule;
3733
import org.matsim.core.controler.Injector;
3834
import org.matsim.core.events.EventsUtils;
@@ -79,6 +75,9 @@ public class AirPollutionAnalysis implements MATSimAppCommand {
7975
@CommandLine.Mixin
8076
private final ShpOptions shp = new ShpOptions();
8177

78+
@CommandLine.Mixin
79+
private final ConfigOptions co = new ConfigOptions();
80+
8281
@CommandLine.Mixin
8382
private SampleOptions sample;
8483

@@ -155,7 +154,7 @@ public void install() {
155154
}
156155

157156
private Config prepareConfig() {
158-
Config config = ConfigUtils.loadConfig(ApplicationUtils.matchInput("config.xml", input.getRunDirectory()).toAbsolutePath().toString());
157+
Config config = co.loadConfig(input.getRunDirectory());
159158

160159
config.vehicles().setVehiclesFile(ApplicationUtils.matchInput("vehicles", input.getRunDirectory()).toAbsolutePath().toString());
161160
config.network().setInputFile(ApplicationUtils.matchInput("network", input.getRunDirectory()).toAbsolutePath().toString());

contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
import org.matsim.application.ApplicationUtils;
1212
import org.matsim.application.CommandSpec;
1313
import org.matsim.application.MATSimAppCommand;
14-
import org.matsim.application.options.InputOptions;
15-
import org.matsim.application.options.OutputOptions;
16-
import org.matsim.application.options.SampleOptions;
17-
import org.matsim.application.options.ShpOptions;
14+
import org.matsim.application.options.*;
1815
import org.matsim.contrib.noise.NoiseConfigGroup;
1916
import org.matsim.contrib.noise.NoiseOfflineCalculation;
2017
import org.matsim.contrib.noise.ProcessNoiseImmissions;
@@ -61,6 +58,9 @@ public class NoiseAnalysis implements MATSimAppCommand {
6158
@CommandLine.Mixin
6259
private final ShpOptions shp = new ShpOptions();
6360

61+
@CommandLine.Mixin
62+
private final ConfigOptions co = new ConfigOptions();
63+
6464
@CommandLine.Mixin
6565
private final SampleOptions sampleOptions = new SampleOptions();
6666

@@ -181,7 +181,7 @@ public Integer call() throws Exception {
181181
}
182182

183183
private Config prepareConfig() {
184-
Config config = ConfigUtils.loadConfig(ApplicationUtils.matchInput("config.xml", input.getRunDirectory()).toAbsolutePath().toString());
184+
Config config = co.loadConfig(input.getRunDirectory());
185185

186186
//it is important to match "output_vehicles.xml.gz" specifically, because otherwise dvrpVehicle files might be matched and the code crashes later
187187
config.vehicles().setVehiclesFile(ApplicationUtils.matchInput("output_vehicles.xml.gz", input.getRunDirectory()).toAbsolutePath().toString());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package org.matsim.application.analysis.pt;
2+
3+
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap;
4+
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
5+
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
6+
import it.unimi.dsi.fastutil.ints.IntSet;
7+
import it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap;
8+
import it.unimi.dsi.fastutil.objects.Object2IntMap;
9+
import org.matsim.api.core.v01.Id;
10+
import org.matsim.api.core.v01.events.ActivityEndEvent;
11+
import org.matsim.api.core.v01.events.PersonEntersVehicleEvent;
12+
import org.matsim.api.core.v01.events.TransitDriverStartsEvent;
13+
import org.matsim.api.core.v01.events.handler.ActivityEndEventHandler;
14+
import org.matsim.api.core.v01.events.handler.PersonEntersVehicleEventHandler;
15+
import org.matsim.api.core.v01.events.handler.TransitDriverStartsEventHandler;
16+
import org.matsim.core.router.TripStructureUtils;
17+
import org.matsim.pt.transitSchedule.api.TransitLine;
18+
import org.matsim.pt.transitSchedule.api.TransitSchedule;
19+
import org.matsim.vehicles.Vehicle;
20+
import org.matsim.vehicles.VehicleType;
21+
import org.matsim.vehicles.Vehicles;
22+
23+
import java.util.HashMap;
24+
import java.util.Map;
25+
26+
/**
27+
* Event handler to count the number of passengers using public transport services differentiated by vehicle type.
28+
* Passenger will be counted once per vehicle type per trip.
29+
*/
30+
public class PtPassengerCountsEventHandler implements PersonEntersVehicleEventHandler, TransitDriverStartsEventHandler, ActivityEndEventHandler {
31+
32+
private final TransitSchedule schedule;
33+
private final Vehicles vehicles;
34+
35+
/**
36+
* All driver ids.
37+
*/
38+
private final IntSet drivers = new IntOpenHashSet();
39+
40+
/**
41+
* Store which passengers have been counted for each vehicle type.
42+
*/
43+
private final Map<Id<VehicleType>, IntSet> byVehicle = new HashMap<>();
44+
45+
/**
46+
* Store mapping of vehicle to agency.
47+
*/
48+
private final Map<Id<Vehicle>, String> vehicleToAgency = new HashMap<>();
49+
50+
/**
51+
* Counts per vehicle type and hour.
52+
*/
53+
private final Int2ObjectMap<Object2IntMap<Id<VehicleType>>> counts = new Int2ObjectAVLTreeMap<>();
54+
55+
/**
56+
* Counts per vehicle type and hour.
57+
*/
58+
private final Int2ObjectMap<Object2IntMap<AgencyVehicleType>> agencyCounts = new Int2ObjectAVLTreeMap<>();
59+
60+
public PtPassengerCountsEventHandler(TransitSchedule schedule, Vehicles vehicles) {
61+
this.schedule = schedule;
62+
this.vehicles = vehicles;
63+
}
64+
65+
/**
66+
* Map containing the counts of passengers per vehicle type.
67+
*/
68+
public Int2ObjectMap<Object2IntMap<Id<VehicleType>>> getCounts() {
69+
return counts;
70+
}
71+
72+
/**
73+
* Map containing the counts of passengers per agency and vehicle type.
74+
* May be empty if the agency attribute is not used.
75+
*/
76+
public Int2ObjectMap<Object2IntMap<AgencyVehicleType>> getAgencyCounts() {
77+
return agencyCounts;
78+
}
79+
80+
@Override
81+
public void handleEvent(TransitDriverStartsEvent event) {
82+
drivers.add(event.getDriverId().index());
83+
84+
TransitLine line = schedule.getTransitLines().get(event.getTransitLineId());
85+
if (line != null) {
86+
Object gtfsAgencyId = line.getAttributes().getAttribute("gtfs_agency_id");
87+
if (gtfsAgencyId != null)
88+
vehicleToAgency.put(event.getVehicleId(), gtfsAgencyId.toString());
89+
}
90+
}
91+
92+
@Override
93+
public void handleEvent(PersonEntersVehicleEvent event) {
94+
95+
Id<Vehicle> vehicleId = event.getVehicleId();
96+
Vehicle vehicle = vehicles.getVehicles().get(vehicleId);
97+
98+
if (vehicle == null)
99+
return;
100+
101+
// Don't count drivers as passengers
102+
if (drivers.contains(event.getPersonId().index()))
103+
return;
104+
105+
VehicleType vehicleType = vehicle.getType();
106+
Id<VehicleType> id = vehicleType.getId();
107+
108+
IntSet counted = byVehicle.computeIfAbsent(id, k -> new IntOpenHashSet());
109+
110+
// Count passenger only once per vehicle type per trip
111+
if (!counted.contains(event.getPersonId().index())) {
112+
counted.add(event.getPersonId().index());
113+
114+
int hour = (int) (event.getTime() / 3600);
115+
116+
counts.computeIfAbsent(hour, k -> new Object2IntAVLTreeMap<>()).merge(id, 1, Integer::sum);
117+
118+
String agency = vehicleToAgency.get(vehicleId);
119+
if (agency != null) {
120+
agencyCounts.computeIfAbsent(hour, k -> new Object2IntAVLTreeMap<>()).merge(new AgencyVehicleType(agency, id), 1, Integer::sum);
121+
}
122+
}
123+
}
124+
125+
@Override
126+
public void handleEvent(ActivityEndEvent event) {
127+
128+
if (TripStructureUtils.isStageActivityType(event.getActType()))
129+
return;
130+
131+
// When trip is finished, a passenger can be counted again.
132+
byVehicle.values().forEach(p -> p.remove(event.getPersonId().index()));
133+
}
134+
135+
@Override
136+
public void reset(int iteration) {
137+
byVehicle.clear();
138+
counts.clear();
139+
agencyCounts.clear();
140+
drivers.clear();
141+
}
142+
143+
144+
public record AgencyVehicleType(String agency, Id<VehicleType> vehicleType) implements Comparable<AgencyVehicleType> {
145+
146+
@Override
147+
public int compareTo(AgencyVehicleType o) {
148+
int cmp = agency.compareTo(o.agency);
149+
if (cmp == 0)
150+
cmp = vehicleType.compareTo(o.vehicleType);
151+
return cmp;
152+
}
153+
}
154+
}

contribs/application/src/main/java/org/matsim/application/analysis/pt/PublicTransitAnalysis.java

+52-1
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,18 @@
1919

2020
package org.matsim.application.analysis.pt;
2121

22+
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
23+
import it.unimi.dsi.fastutil.objects.Object2IntMap;
24+
import org.apache.commons.csv.CSVFormat;
25+
import org.apache.commons.csv.CSVPrinter;
2226
import org.apache.logging.log4j.LogManager;
2327
import org.apache.logging.log4j.Logger;
2428
import org.matsim.analysis.pt.stop2stop.PtStop2StopAnalysis;
29+
import org.matsim.api.core.v01.Id;
2530
import org.matsim.api.core.v01.Scenario;
2631
import org.matsim.application.ApplicationUtils;
2732
import org.matsim.application.CommandSpec;
2833
import org.matsim.application.MATSimAppCommand;
29-
import org.matsim.application.analysis.emissions.AirPollutionAnalysis;
3034
import org.matsim.application.options.InputOptions;
3135
import org.matsim.application.options.OutputOptions;
3236
import org.matsim.application.options.SampleOptions;
@@ -36,15 +40,22 @@
3640
import org.matsim.core.events.EventsUtils;
3741
import org.matsim.core.events.MatsimEventsReader;
3842
import org.matsim.core.scenario.ScenarioUtils;
43+
import org.matsim.vehicles.VehicleType;
3944
import picocli.CommandLine;
4045

46+
import java.io.IOException;
47+
import java.nio.charset.StandardCharsets;
48+
import java.nio.file.Files;
49+
4150
@CommandLine.Command(
4251
name = "transit", description = "General public transit analysis.",
4352
mixinStandardHelpOptions = true, showDefaultValues = true
4453
)
4554
@CommandSpec(requireRunDirectory = true,
4655
produces = {
4756
"pt_pax_volumes.csv.gz",
57+
"pt_pax_per_hour_and_vehicle_type.csv",
58+
"pt_pax_per_hour_and_vehicle_type_and_agency.csv"
4859
}
4960
)
5061
public class PublicTransitAnalysis implements MATSimAppCommand {
@@ -53,8 +64,10 @@ public class PublicTransitAnalysis implements MATSimAppCommand {
5364

5465
@CommandLine.Mixin
5566
private final InputOptions input = InputOptions.ofCommand(PublicTransitAnalysis.class);
67+
5668
@CommandLine.Mixin
5769
private final OutputOptions output = OutputOptions.ofCommand(PublicTransitAnalysis.class);
70+
5871
@CommandLine.Mixin
5972
private SampleOptions sample;
6073

@@ -72,7 +85,11 @@ public Integer call() throws Exception {
7285
String eventsFile = ApplicationUtils.matchInput("events", input.getRunDirectory()).toString();
7386

7487
PtStop2StopAnalysis ptStop2StopEventHandler = new PtStop2StopAnalysis(scenario.getTransitVehicles(), sample.getUpscaleFactor());
88+
PtPassengerCountsEventHandler passengerCountsHandler = new PtPassengerCountsEventHandler(scenario.getTransitSchedule(), scenario.getTransitVehicles());
89+
7590
eventsManager.addHandler(ptStop2StopEventHandler);
91+
eventsManager.addHandler(passengerCountsHandler);
92+
7693
eventsManager.initProcessing();
7794
MatsimEventsReader matsimEventsReader = new MatsimEventsReader(eventsManager);
7895
matsimEventsReader.readFile(eventsFile);
@@ -84,9 +101,43 @@ public Integer call() throws Exception {
84101
ptStop2StopEventHandler.writeStop2StopEntriesByDepartureCsv(output.getPath("pt_pax_volumes.csv.gz"),
85102
",", ";");
86103

104+
writePassengerCounts(passengerCountsHandler);
105+
87106
return 0;
88107
}
89108

109+
private void writePassengerCounts(PtPassengerCountsEventHandler handler) {
110+
111+
try (CSVPrinter csv = new CSVPrinter(Files.newBufferedWriter(output.getPath("pt_pax_per_hour_and_vehicle_type.csv"), StandardCharsets.UTF_8), CSVFormat.DEFAULT)) {
112+
113+
csv.printRecord("vehicle_type", "hour", "passenger_count");
114+
for (Int2ObjectMap.Entry<Object2IntMap<Id<VehicleType>>> kv : handler.getCounts().int2ObjectEntrySet()) {
115+
for (Object2IntMap.Entry<Id<VehicleType>> vc : kv.getValue().object2IntEntrySet()) {
116+
csv.printRecord(vc.getKey(), kv.getIntKey(), vc.getIntValue() * sample.getUpscaleFactor());
117+
}
118+
}
119+
120+
} catch (IOException e) {
121+
log.error("Error writing passenger counts.", e);
122+
}
123+
124+
125+
try (CSVPrinter csv = new CSVPrinter(Files.newBufferedWriter(output.getPath("pt_pax_per_hour_and_vehicle_type_and_agency.csv"), StandardCharsets.UTF_8), CSVFormat.DEFAULT)) {
126+
127+
csv.printRecord("vehicle_type", "agency", "hour", "passenger_count");
128+
for (Int2ObjectMap.Entry<Object2IntMap<PtPassengerCountsEventHandler.AgencyVehicleType>> kv : handler.getAgencyCounts().int2ObjectEntrySet()) {
129+
for (Object2IntMap.Entry<PtPassengerCountsEventHandler.AgencyVehicleType> vc : kv.getValue().object2IntEntrySet()) {
130+
csv.printRecord(vc.getKey().vehicleType(), vc.getKey().agency(), kv.getIntKey(), vc.getIntValue() * sample.getUpscaleFactor());
131+
}
132+
}
133+
134+
} catch (IOException e) {
135+
log.error("Error writing passenger counts.", e);
136+
}
137+
138+
139+
}
140+
90141
private Config prepareConfig() {
91142
Config config = ConfigUtils.loadConfig(ApplicationUtils.matchInput("config.xml", input.getRunDirectory()).toAbsolutePath().toString());
92143

0 commit comments

Comments
 (0)