Skip to content

Commit 9a5f465

Browse files
Merge pull request #119 from moia-oss/master
update matsim CW45
2 parents a92bd23 + 263fd04 commit 9a5f465

File tree

191 files changed

+47266
-3617
lines changed

Some content is hidden

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

191 files changed

+47266
-3617
lines changed

contribs/application/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
<dependency>
8888
<groupId>com.github.matsim-org</groupId>
8989
<artifactId>gtfs2matsim</artifactId>
90-
<version>fc8b13954d</version>
90+
<version>0bd5850fd6</version>
9191
<exclusions>
9292
<!-- Exclude unneeded dependencies and these with known CVE -->
9393
<exclusion>

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

+8-3
Original file line numberDiff line numberDiff line change
@@ -440,12 +440,17 @@ public static Path matchInput(String name, Path dir) {
440440
if (path.isPresent())
441441
return path.get();
442442

443-
// Match more general pattern at last
444-
path = matchPattern(".+\\.[a-zA-Z0-9]*_" + name + "\\..+", dir);
443+
// Match more general pattern
444+
path = matchPattern(".+\\.[a-zA-Z0-9\\-]*_" + name + "\\..+", dir);
445445
if (path.isPresent())
446446
return path.get();
447447

448-
throw new IllegalArgumentException("Could not match input file: " + name);
448+
// Even more permissive pattern
449+
path = matchPattern(".+[a-zA-Z0-9_.\\-]*(_|\\.)" + name + ".+", dir);
450+
if (path.isPresent())
451+
return path.get();
452+
453+
throw new IllegalArgumentException("Could not match input file: %s (in %s)".formatted(name, dir));
449454
}
450455

451456
private static Optional<Path> matchSuffix(String suffix, Path dir) {

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

+13-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.locationtech.jts.geom.Envelope;
88
import org.matsim.api.core.v01.Coord;
99
import org.matsim.api.core.v01.Scenario;
10+
import org.matsim.api.core.v01.TransportMode;
1011
import org.matsim.application.ApplicationUtils;
1112
import org.matsim.application.CommandSpec;
1213
import org.matsim.application.MATSimAppCommand;
@@ -20,6 +21,7 @@
2021
import org.matsim.core.config.Config;
2122
import org.matsim.core.config.ConfigUtils;
2223
import org.matsim.core.scenario.ScenarioUtils;
24+
import org.matsim.core.utils.collections.CollectionUtils;
2325
import org.matsim.core.utils.geometry.CoordinateTransformation;
2426
import org.matsim.core.utils.io.IOUtils;
2527
import picocli.CommandLine;
@@ -28,10 +30,7 @@
2830
import java.nio.file.Path;
2931
import java.text.DecimalFormat;
3032
import java.text.DecimalFormatSymbols;
31-
import java.util.Locale;
32-
import java.util.Map;
33-
import java.util.Objects;
34-
import java.util.Set;
33+
import java.util.*;
3534

3635
@CommandLine.Command(
3736
name = "noise-analysis",
@@ -88,10 +87,18 @@ public Integer call() throws Exception {
8887
NoiseConfigGroup noiseParameters = ConfigUtils.addOrGetModule(config, NoiseConfigGroup.class);
8988

9089
if(overrideParameters){
91-
log.warn("no NoiseConfigGroup was configured before. Will set some standards. You should check the next lines in the log file!");
90+
log.warn("no NoiseConfigGroup was configured before. Will set some standards. You should check the next lines in the log file and the output_config.xml!");
9291
noiseParameters.setConsideredActivitiesForReceiverPointGridArray(considerActivities.toArray(String[]::new));
9392
noiseParameters.setConsideredActivitiesForDamageCalculationArray(considerActivities.toArray(String[]::new));
9493

94+
{
95+
Set<String> set = CollectionUtils.stringArrayToSet( new String[]{TransportMode.bike, TransportMode.walk, TransportMode.transit_walk, TransportMode.non_network_walk} );
96+
noiseParameters.setNetworkModesToIgnoreSet( set );
97+
}
98+
{
99+
String[] set = new String[]{"freight"};
100+
noiseParameters.setHgvIdPrefixesArray( set );
101+
}
95102
//use actual speed and not freespeed
96103
noiseParameters.setUseActualSpeedLevel(true);
97104
//use the valid speed range (recommended by IK)
@@ -181,7 +188,7 @@ private Config prepareConfig() {
181188
config.transit().setTransitScheduleFile(null);
182189
config.transit().setVehiclesFile(null);
183190
config.plans().setInputFile(ApplicationUtils.matchInput("plans", input.getRunDirectory()).toAbsolutePath().toString());
184-
config.facilities().setInputFile(null);
191+
config.facilities().setInputFile(ApplicationUtils.matchInput("facilities", input.getRunDirectory()).toAbsolutePath().toString());
185192
config.eventsManager().setNumberOfThreads(null);
186193
config.eventsManager().setEstimatedNumberOfEvents(null);
187194
//ts, aug '24: not sure if and why we need to set 1 thread

contribs/application/src/main/java/org/matsim/application/analysis/population/TripAnalysis.java

+94-24
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import it.unimi.dsi.fastutil.ints.IntArrayList;
44
import it.unimi.dsi.fastutil.ints.IntList;
5+
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
6+
import it.unimi.dsi.fastutil.ints.IntSet;
57
import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
68
import it.unimi.dsi.fastutil.objects.Object2IntMap;
79
import it.unimi.dsi.fastutil.objects.Object2LongMap;
@@ -15,6 +17,7 @@
1517
import org.locationtech.jts.geom.Geometry;
1618
import org.locationtech.jts.geom.GeometryFactory;
1719
import org.locationtech.jts.geom.Point;
20+
import org.matsim.application.ApplicationUtils;
1821
import org.matsim.application.CommandSpec;
1922
import org.matsim.application.MATSimAppCommand;
2023
import org.matsim.application.options.CsvOptions;
@@ -32,6 +35,7 @@
3235
import java.math.BigDecimal;
3336
import java.math.RoundingMode;
3437
import java.nio.file.Files;
38+
import java.nio.file.Path;
3539
import java.util.*;
3640
import java.util.stream.IntStream;
3741

@@ -43,48 +47,43 @@
4347
produces = {
4448
"mode_share.csv", "mode_share_per_dist.csv", "mode_users.csv", "trip_stats.csv",
4549
"mode_share_per_%s.csv", "population_trip_stats.csv", "trip_purposes_by_hour.csv",
46-
"mode_share_distance_distribution.csv",
50+
"mode_share_distance_distribution.csv", "mode_shift.csv",
4751
"mode_choices.csv", "mode_choice_evaluation.csv", "mode_choice_evaluation_per_mode.csv",
4852
"mode_confusion_matrix.csv", "mode_prediction_error.csv"
4953
}
5054
)
5155
public class TripAnalysis implements MATSimAppCommand {
5256

53-
private static final Logger log = LogManager.getLogger(TripAnalysis.class);
54-
5557
/**
5658
* Attributes which relates this person to a reference person.
5759
*/
58-
public static String ATTR_REF_ID = "ref_id";
60+
public static final String ATTR_REF_ID = "ref_id";
5961
/**
6062
* Person attribute that contains the reference modes of a person. Multiple modes are delimited by "-".
6163
*/
62-
public static String ATTR_REF_MODES = "ref_modes";
64+
public static final String ATTR_REF_MODES = "ref_modes";
6365
/**
6466
* Person attribute containing its weight for analysis purposes.
6567
*/
66-
public static String ATTR_REF_WEIGHT = "ref_weight";
67-
68+
public static final String ATTR_REF_WEIGHT = "ref_weight";
69+
private static final Logger log = LogManager.getLogger(TripAnalysis.class);
70+
@CommandLine.Option(names = "--person-filter", description = "Define which persons should be included into trip analysis. Map like: Attribute name (key), attribute value (value). " +
71+
"The attribute needs to be contained by output_persons.csv. Persons who do not match all filters are filtered out.", split = ",")
72+
private final Map<String, String> personFilters = new HashMap<>();
6873
@CommandLine.Mixin
6974
private InputOptions input = InputOptions.ofCommand(TripAnalysis.class);
7075
@CommandLine.Mixin
7176
private OutputOptions output = OutputOptions.ofCommand(TripAnalysis.class);
72-
7377
@CommandLine.Option(names = "--input-ref-data", description = "Optional path to reference data", required = false)
7478
private String refData;
75-
7679
@CommandLine.Option(names = "--match-id", description = "Pattern to filter agents by id")
7780
private String matchId;
78-
7981
@CommandLine.Option(names = "--dist-groups", split = ",", description = "List of distances for binning", defaultValue = "0,1000,2000,5000,10000,20000")
8082
private List<Long> distGroups;
81-
8283
@CommandLine.Option(names = "--modes", split = ",", description = "List of considered modes, if not set all will be used")
8384
private List<String> modeOrder;
84-
8585
@CommandLine.Option(names = "--shp-filter", description = "Define how the shp file filtering should work", defaultValue = "home")
8686
private LocationFilter filter;
87-
8887
@CommandLine.Mixin
8988
private ShpOptions shp;
9089

@@ -131,6 +130,20 @@ private static double[] calcHistogram(double[] data, double[] bins) {
131130
return hist;
132131
}
133132

133+
private static Map<String, ColumnType> getColumnTypes() {
134+
Map<String, ColumnType> columnTypes = new HashMap<>(Map.of("person", ColumnType.TEXT,
135+
"trav_time", ColumnType.STRING, "wait_time", ColumnType.STRING, "dep_time", ColumnType.STRING,
136+
"longest_distance_mode", ColumnType.STRING, "main_mode", ColumnType.STRING,
137+
"start_activity_type", ColumnType.TEXT, "end_activity_type", ColumnType.TEXT,
138+
"first_pt_boarding_stop", ColumnType.TEXT, "last_pt_egress_stop", ColumnType.TEXT));
139+
140+
// Map.of only has 10 argument max
141+
columnTypes.put("traveled_distance", ColumnType.LONG);
142+
columnTypes.put("euclidean_distance", ColumnType.LONG);
143+
144+
return columnTypes;
145+
}
146+
134147
@Override
135148
public Integer call() throws Exception {
136149

@@ -146,6 +159,43 @@ public Integer call() throws Exception {
146159
persons = persons.where(persons.textColumn("person").matchesRegex(matchId));
147160
}
148161

162+
// filter persons according to person (attribute) filter
163+
if (!personFilters.isEmpty()) {
164+
IntSet generalFilteredRowIds = null;
165+
for (Map.Entry<String, String> entry : personFilters.entrySet()) {
166+
if (!persons.containsColumn(entry.getKey())) {
167+
log.warn("Persons table does not contain column for filter attribute {}. Filter on {} will not be applied.", entry.getKey(), entry.getValue());
168+
continue;
169+
}
170+
log.info("Using person filter for attribute {} and value {}", entry.getKey(), entry.getValue());
171+
172+
IntSet filteredRowIds = new IntOpenHashSet();
173+
174+
for (int i = 0; i < persons.rowCount(); i++) {
175+
Row row = persons.row(i);
176+
String value = row.getString(entry.getKey());
177+
// only add value once
178+
if (value.equals(entry.getValue())) {
179+
filteredRowIds.add(i);
180+
}
181+
}
182+
183+
if (generalFilteredRowIds == null) {
184+
// If generalFilteredRowIds is empty, add all elements from filteredRowIds to generalFilteredRowIds
185+
generalFilteredRowIds = filteredRowIds;
186+
} else {
187+
// If generalFilteredRowIds is not empty, retain only the elements that are also in filteredRowIds
188+
generalFilteredRowIds.retainAll(filteredRowIds);
189+
}
190+
}
191+
192+
if (generalFilteredRowIds != null) {
193+
persons = persons.where(Selection.with(generalFilteredRowIds.intStream().toArray()));
194+
}
195+
}
196+
197+
log.info("Filtered {} out of {} persons", persons.rowCount(), total);
198+
149199
// Home filter by standard attribute
150200
if (shp.isDefined() && filter == LocationFilter.home) {
151201
Geometry geometry = shp.getGeometry();
@@ -166,18 +216,8 @@ public Integer call() throws Exception {
166216

167217
log.info("Filtered {} out of {} persons", persons.rowCount(), total);
168218

169-
Map<String, ColumnType> columnTypes = new HashMap<>(Map.of("person", ColumnType.TEXT,
170-
"trav_time", ColumnType.STRING, "wait_time", ColumnType.STRING, "dep_time", ColumnType.STRING,
171-
"longest_distance_mode", ColumnType.STRING, "main_mode", ColumnType.STRING,
172-
"start_activity_type", ColumnType.TEXT, "end_activity_type", ColumnType.TEXT,
173-
"first_pt_boarding_stop", ColumnType.TEXT, "last_pt_egress_stop", ColumnType.TEXT));
174-
175-
// Map.of only has 10 argument max
176-
columnTypes.put("traveled_distance", ColumnType.LONG);
177-
columnTypes.put("euclidean_distance", ColumnType.LONG);
178-
179219
Table trips = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(input.getPath("trips.csv")))
180-
.columnTypesPartial(columnTypes)
220+
.columnTypesPartial(getColumnTypes())
181221
.sample(false)
182222
.separator(CsvOptions.detectDelimiter(input.getPath("trips.csv"))).build());
183223

@@ -271,6 +311,8 @@ public Integer call() throws Exception {
271311

272312
writeTripDistribution(joined);
273313

314+
writeModeShift(joined);
315+
274316
return 0;
275317
}
276318

@@ -540,6 +582,34 @@ private void writeTripDistribution(Table trips) throws IOException {
540582
}
541583
}
542584

585+
private void writeModeShift(Table trips) throws IOException {
586+
Path path;
587+
try {
588+
Path dir = Path.of(input.getPath("trips.csv")).getParent().resolve("ITERS").resolve("it.0");
589+
path = ApplicationUtils.matchInput("trips.csv", dir);
590+
} catch (Exception e) {
591+
log.error("Could not find trips from 0th iteration.", e);
592+
return;
593+
}
594+
595+
Table originalTrips = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(path.toString()))
596+
.columnTypesPartial(getColumnTypes())
597+
.sample(false)
598+
.separator(CsvOptions.detectDelimiter(path.toString())).build());
599+
600+
// Use longest_distance_mode where main_mode is not present
601+
originalTrips.stringColumn("main_mode")
602+
.set(originalTrips.stringColumn("main_mode").isMissing(),
603+
originalTrips.stringColumn("longest_distance_mode"));
604+
605+
originalTrips.column("main_mode").setName("original_mode");
606+
607+
Table joined = new DataFrameJoiner(trips, "trip_id").inner(true, originalTrips);
608+
Table aggr = joined.summarize("trip_id", count).by("original_mode", "main_mode");
609+
610+
aggr.write().csv(output.getPath("mode_shift.csv").toFile());
611+
}
612+
543613
/**
544614
* How shape file filtering should be applied.
545615
*/

0 commit comments

Comments
 (0)