diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/population/ActivityLengthAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/population/ActivityLengthAnalysis.java new file mode 100644 index 00000000000..2e7418462fe --- /dev/null +++ b/contribs/application/src/main/java/org/matsim/application/analysis/population/ActivityLengthAnalysis.java @@ -0,0 +1,82 @@ +package org.matsim.application.analysis.population; + +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; +import org.matsim.api.core.v01.population.Activity; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.PlanElement; +import org.matsim.api.core.v01.population.Population; +import org.matsim.application.MATSimAppCommand; +import org.matsim.core.population.PopulationUtils; +import picocli.CommandLine; + +import java.io.FileWriter; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +@CommandLine.Command( + name = "activity-length-analysis", + description = "Analyze the length of activity" +) +public class ActivityLengthAnalysis implements MATSimAppCommand { + @CommandLine.Option(names = "--population", description = "Path to input population", required = true) + private String populationPath; + + @CommandLine.Option(names = "--reference-population", description = "Path to reference population", defaultValue = "") + private String referencePopulationPath; + + @CommandLine.Option(names = "--output-folder", description = "Path to analysis output folder", required = true) + private Path outputFolder; + + public static void main(String[] args) { + new ActivityLengthAnalysis().execute(args); + } + + @Override + public Integer call() throws Exception { + List activityDurations = new ArrayList<>(); + List referenceActivityDurations = new ArrayList<>(); + + Population population = PopulationUtils.readPopulation(populationPath); + for (Person person : population.getPersons().values()) { + for (PlanElement planElement : person.getSelectedPlan().getPlanElements()) { + if (planElement instanceof Activity) { + double startTime = ((Activity) planElement).getStartTime().orElse(0); + double endTime = ((Activity) planElement).getEndTime().orElse(30 * 3600); + double duration = endTime - startTime; + activityDurations.add(duration); + } + } + } + + CSVPrinter csvWriter = new CSVPrinter(new FileWriter(outputFolder + "/activity-length.csv"), CSVFormat.TDF); + csvWriter.printRecord("activity_duration_in_seconds"); + for (double activityDuration : activityDurations) { + csvWriter.printRecord(Double.toString(activityDuration)); + } + csvWriter.close(); + + if (!referencePopulationPath.equals("")) { + Population referencePopulation = PopulationUtils.readPopulation(referencePopulationPath); + for (Person person : referencePopulation.getPersons().values()) { + for (PlanElement planElement : person.getSelectedPlan().getPlanElements()) { + if (planElement instanceof Activity) { + double startTime = ((Activity) planElement).getStartTime().orElse(0); + double endTime = ((Activity) planElement).getEndTime().orElse(30 * 3600); + double duration = endTime - startTime; + referenceActivityDurations.add(duration); + } + } + } + + CSVPrinter csvWriter2 = new CSVPrinter(new FileWriter(outputFolder + "/reference-activity-length.csv"), CSVFormat.TDF); + csvWriter2.printRecord("activity_duration_in_seconds"); + for (double activityDuration : referenceActivityDurations) { + csvWriter2.printRecord(Double.toString(activityDuration)); + } + csvWriter2.close(); + } + return 0; + } +} diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/population/DepartureTimeAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/population/DepartureTimeAnalysis.java new file mode 100644 index 00000000000..04e800872b9 --- /dev/null +++ b/contribs/application/src/main/java/org/matsim/application/analysis/population/DepartureTimeAnalysis.java @@ -0,0 +1,133 @@ +package org.matsim.application.analysis.population; + +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; +import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.api.core.v01.population.Person; +import org.matsim.api.core.v01.population.Plan; +import org.matsim.api.core.v01.population.Population; +import org.matsim.application.MATSimAppCommand; +import org.matsim.core.population.PersonUtils; +import org.matsim.core.population.PopulationUtils; +import org.matsim.core.router.TripStructureUtils; +import picocli.CommandLine; + +import java.io.FileWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +@CommandLine.Command( + name = "analyze-departure-time", + description = "Analyze the departure time of the trips" +) +public class DepartureTimeAnalysis implements MATSimAppCommand { + + private static final Logger log = LogManager.getLogger(DepartureTimeAnalysis.class); + + @CommandLine.Option(names = "--plans", description = "Path to input population (plans) file", required = true) + private Path inputPlans; + + @CommandLine.Option(names = "--output-folder", description = "Path to analysis output folder", required = true) + private Path outputFolder; + + private static String[] ageGroups = new String[]{"0-17", "18-29", "30-49", "50-69", "70 or more"}; + + + public static void main(String[] args) { + new DepartureTimeAnalysis().execute(args); + } + + @Override + public Integer call() throws Exception { + Map> recordMap = initializeRecordMap(); + Population population = PopulationUtils.readPopulation(inputPlans.toString()); + + int processedPerson = 0; + int tripsDepartAfter24h = 0; + + for (Person person : population.getPersons().values()) { + //TODO potentially filter persons, e.g. by home location or by subpopulation + + processedPerson++; + int age = PersonUtils.getAge(person); + String ageGroup = determineAgeGroup(age); + Plan plan = person.getSelectedPlan(); + List trips = TripStructureUtils.getTrips(plan); + for (TripStructureUtils.Trip trip : trips) { + double departureTime = trip.getOriginActivity().getEndTime().seconds(); + // maybe the Math.floor operation is not needed? + int timeBin = (int) Math.floor(departureTime / 3600); + if (timeBin >= 24) { + tripsDepartAfter24h++; + continue; + } + // 1 time bin = 1 hour + recordMap.get(ageGroup).get(timeBin).increment(); + } + } + + // write results + if (!Files.exists(outputFolder)) { + Files.createDirectory(outputFolder); + } + CSVPrinter tsvWriter = new CSVPrinter(new FileWriter(outputFolder + "/departure_time_analysis.csv"), CSVFormat.TDF); + List titleRow = new ArrayList<>(); + titleRow.add("age_group"); + for (int i = 0; i < 24; i++) { + titleRow.add(Integer.toString(i)); + } + tsvWriter.printRecord(titleRow); + for (String ageGroup : ageGroups) { + List outputRow = new ArrayList<>(); + outputRow.add(ageGroup); + for (int i = 0; i < 24; i++) { + outputRow.add(Integer.toString(recordMap.get(ageGroup).get(i).intValue())); + } + tsvWriter.printRecord(outputRow); + } + tsvWriter.close(); + + log.info("Person processed (living within the area): {}", processedPerson); + log.info("Number of trips that depart after 24 hours is {}", tripsDepartAfter24h); + + return 0; + } + + private Map> initializeRecordMap() { + Map> recordMap = new HashMap<>(); + for (String ageGroup : ageGroups) { + recordMap.put(ageGroup, new HashMap<>()); + for (int i = 0; i < 24; i++) { + recordMap.get(ageGroup).put(i, new MutableInt(0)); + } + } + return recordMap; + } + + private String determineAgeGroup(int age) { + if (age <= 17) { + return ageGroups[0]; + } + + if (age <= 29) { + return ageGroups[1]; + } + + if (age <= 49) { + return ageGroups[2]; + } + + if (age <= 69) { + return ageGroups[3]; + } + + return ageGroups[4]; + } +}