From 1b641f8947d3c3aec2118a5671b2b1758b3f864a Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 18 Apr 2023 10:21:09 +0200 Subject: [PATCH 001/213] Score explanation functionality --- .../groups/PlanCalcScoreConfigGroup.java | 68 ++++++++++++------ .../core/scoring/NewScoreAssignerImpl.java | 11 +++ .../matsim/core/scoring/ScoringFunction.java | 19 ++++- .../core/scoring/SumScoringFunction.java | 30 ++++++-- .../CharyparNagelActivityScoring.java | 67 +++++++++++------ .../CharyparNagelAgentStuckScoring.java | 4 ++ .../functions/CharyparNagelLegScoring.java | 5 ++ .../functions/CharyparNagelMoneyScoring.java | 4 ++ .../scoring/functions/ScoreEventScoring.java | 4 ++ .../replanning/ReRoutingIT/plans.xml.gz | Bin 4641277 -> 4641245 bytes .../ReRoutingIT/plans_speedyALT.xml.gz | Bin 4641194 -> 4641164 bytes 11 files changed, 162 insertions(+), 50 deletions(-) diff --git a/matsim/src/main/java/org/matsim/core/config/groups/PlanCalcScoreConfigGroup.java b/matsim/src/main/java/org/matsim/core/config/groups/PlanCalcScoreConfigGroup.java index 973bb8890bc..51dd9d3dcbf 100644 --- a/matsim/src/main/java/org/matsim/core/config/groups/PlanCalcScoreConfigGroup.java +++ b/matsim/src/main/java/org/matsim/core/config/groups/PlanCalcScoreConfigGroup.java @@ -52,7 +52,7 @@ *
  • The parameter names in the config file are not changed in this way * since this would mean a public api change. kai, dec'10 * - * + * * @author nagel * */ @@ -78,8 +78,10 @@ public final class PlanCalcScoreConfigGroup extends ConfigGroup { private static final String UTL_OF_LINE_SWITCH = "utilityOfLineSwitch"; + private static final String EXPLAIN_SCORES = "explainScores"; + private final ReflectiveDelegate delegate = new ReflectiveDelegate(); - + private boolean usesDeprecatedSyntax = false ; public PlanCalcScoreConfigGroup() { @@ -177,13 +179,13 @@ public static String createStageActivityType( String mode ){ public String getValue(final String key) { throw new IllegalArgumentException(key + ": getValue access disabled; use direct getter"); } - + private static final String msg = " is deprecated config syntax; please use the more " + "modern hierarchical format; your output_config.xml " + "will be in the correct version; the old version will fail eventually, since we want to reduce the " + "workload on this backwards compatibility (look into " + "PlanCalcScoreConfigGroup or PlanCalcRouteConfigGroup if you want to know what we mean)."; - + @Override public void addParam(final String key, final String value) { testForLocked(); @@ -198,7 +200,7 @@ public void addParam(final String key, final String value) { else if (key.startsWith("activityType_")) { log.warn( key + msg ); usesDeprecatedSyntax = true ; - + ActivityParams actParams = getActivityTypeByNumber(key.substring("activityType_".length())); actParams.setActivityType(value); @@ -348,7 +350,7 @@ else if (Arrays // log.warn( key + msg ); // usesDeprecatedSyntax = true ; // this is the stuff with the default subpopulation - + getScoringParameters(null).addParam(key, value); } @@ -418,9 +420,12 @@ public final Map getComments() { map.put(WRITE_EXPERIENCED_PLANS, "write a plans file in each iteration directory which contains what each agent actually did, and the score it received."); + map.put(EXPLAIN_SCORES, + "Write detailed score composition into plan attributes after execution."); + return map; } - + /* * * @returns a list of all Activities over all Subpopulations (if existent) @@ -442,15 +447,15 @@ public Collection getActivityTypes() { public Collection getAllModes() { if (getScoringParameters(null) != null) { return getScoringParameters(null).getModes().keySet(); - + } else { Set modes = new HashSet<>(); getScoringParametersPerSubpopulation().values().forEach(item -> modes.addAll(item.getModes().keySet())); return modes; } - + } - + public Collection getActivityParams() { if (getScoringParameters(null) != null) return getScoringParameters(null).getActivityParams(); @@ -469,8 +474,8 @@ else if (getScoringParameters(DEFAULT_SUBPOPULATION) != null) throw new RuntimeException("Default subpopulation is not defined"); } - - + + public Map getScoringParametersPerSubpopulation() { @SuppressWarnings("unchecked") final Collection parameters = (Collection) getParameterSets( @@ -609,11 +614,11 @@ protected void checkParameterSet(final ConfigGroup module) { @Override protected final void checkConsistency(final Config config) { super.checkConsistency(config); - + if ( usesDeprecatedSyntax && !config.global().isInsistingOnDeprecatedConfigVersion() ) { throw new RuntimeException( msg ) ; } - + if (getScoringParametersPerSubpopulation().size()>1){ if (!getScoringParametersPerSubpopulation().containsKey(PlanCalcScoreConfigGroup.DEFAULT_SUBPOPULATION)){ throw new RuntimeException("Using several subpopulations in "+PlanCalcScoreConfigGroup.GROUP_NAME+" requires defining a \""+PlanCalcScoreConfigGroup.DEFAULT_SUBPOPULATION+" \" subpopulation." @@ -688,6 +693,14 @@ public void setBrainExpBeta(double brainExpBeta) { delegate.setBrainExpBeta(brainExpBeta); } + public void setExplainScores(boolean value) { + delegate.setExplainScores(value); + } + + public boolean isExplainScores() { + return delegate.isExplainScores(); + } + public double getPathSizeLogitBeta() { return delegate.getPathSizeLogitBeta(); } @@ -819,7 +832,7 @@ public static class ActivityParams extends ReflectiveConfigGroup implements Mats // ActivityParams. I will try to pass the locked setting through the getters. kai, jun'15 public final static String SET_TYPE = "activityParams"; - + // --- private static final String TYPICAL_DURATION_SCORE_COMPUTATION = "typicalDurationScoreComputation"; @@ -1070,7 +1083,7 @@ public ActivityParams setClosingTime(final double closingTime) { } // --- - + static final String SCORING_THIS_ACTIVITY_AT_ALL = "scoringThisActivityAtAll"; private boolean scoringThisActivityAtAll = true; @@ -1091,7 +1104,7 @@ public ActivityParams setScoringThisActivityAtAll(boolean scoringThisActivityAtA public static class ModeParams extends ReflectiveConfigGroup implements MatsimParameters { final static String SET_TYPE = "modeParams"; - + private static final String MONETARY_DISTANCE_RATE = "monetaryDistanceRate"; private static final String MONETARY_DISTANCE_RATE_CMT = "[unit_of_money/m] conversion of distance into money. Normally negative."; @@ -1101,12 +1114,12 @@ public static class ModeParams extends ReflectiveConfigGroup implements MatsimPa private static final String CONSTANT_CMT = "[utils] alternative-specific constant. Normally per trip, but that is probably buggy for multi-leg trips."; public static final String MODE = "mode"; - + private static final String DAILY_MONETARY_CONSTANT = "dailyMonetaryConstant"; private static final String DAILY_MONETARY_CONSTANT_CMT = "[unit_of_money/day] Fixed cost of mode, per day."; private static final String DAILY_UTILITY_CONSTANT = "dailyUtilityConstant"; - + private String mode = null; private double traveling = -6.0; private double distance = 0.0; @@ -1524,12 +1537,12 @@ public void addActivityParams(final ActivityParams params) { @Override public void checkConsistency(Config config) { super.checkConsistency(config); - - + + boolean hasOpeningAndClosingTime = false; boolean hasOpeningTimeAndLatePenalty = false; - + // This cannot be done in ActivityParams (where it would make more // sense), // because some global properties are also checked @@ -1585,6 +1598,8 @@ private ReflectiveDelegate() { private boolean usingOldScoringBelowZeroUtilityDuration = false; + private boolean explainScores = false; + @StringGetter(FRACTION_OF_ITERATIONS_TO_START_SCORE_MSA) public Double getFractionOfIterationsToStartScoreMSA() { return fractionOfIterationsToStartScoreMSA; @@ -1659,5 +1674,14 @@ public void setWriteExperiencedPlans(boolean writeExperiencedPlans) { this.writeExperiencedPlans = writeExperiencedPlans; } + @StringSetter(EXPLAIN_SCORES) + public void setExplainScores(boolean explainScores) { + this.explainScores = explainScores; + } + + @StringGetter(EXPLAIN_SCORES) + public boolean isExplainScores() { + return explainScores; + } } } diff --git a/matsim/src/main/java/org/matsim/core/scoring/NewScoreAssignerImpl.java b/matsim/src/main/java/org/matsim/core/scoring/NewScoreAssignerImpl.java index 9823d64f4f7..30cce975267 100644 --- a/matsim/src/main/java/org/matsim/core/scoring/NewScoreAssignerImpl.java +++ b/matsim/src/main/java/org/matsim/core/scoring/NewScoreAssignerImpl.java @@ -41,6 +41,7 @@ class NewScoreAssignerImpl implements NewScoreAssigner { private Map msaContributions = new HashMap<>() ; private Integer scoreMSAstartsAtIteration; private final double learningRate; + private final boolean explainScores; private double scoreSum = 0.0; private long scoreCount = 0; @@ -52,16 +53,26 @@ class NewScoreAssignerImpl implements NewScoreAssigner { * planCalcScoreConfigGroup.getFractionOfIterationsToStartScoreMSA() + controlerConfigGroup.getFirstIteration()); } learningRate = planCalcScoreConfigGroup.getLearningRate(); + explainScores = planCalcScoreConfigGroup.isExplainScores(); } public void assignNewScores(int iteration, ScoringFunctionsForPopulation scoringFunctionsForPopulation, Population population) { log.info("it: " + iteration + " msaStart: " + this.scoreMSAstartsAtIteration ); + StringBuilder explanation = new StringBuilder(); + for (Person person : population.getPersons().values()) { ScoringFunction sf = scoringFunctionsForPopulation.getScoringFunctionForAgent(person.getId()); double score = sf.getScore(); Plan plan = person.getSelectedPlan(); Double oldScore = plan.getScore(); + + if (explainScores) { + explanation.setLength(0); + sf.explainScore(explanation); + plan.getAttributes().putAttribute(ScoringFunction.SCORE_EXPLANATION, explanation.toString()); + } + if (oldScore == null) { plan.setScore(score); if ( plan.getScore().isNaN() ) { diff --git a/matsim/src/main/java/org/matsim/core/scoring/ScoringFunction.java b/matsim/src/main/java/org/matsim/core/scoring/ScoringFunction.java index a00ac3c8b7f..6dbdf82aaea 100644 --- a/matsim/src/main/java/org/matsim/core/scoring/ScoringFunction.java +++ b/matsim/src/main/java/org/matsim/core/scoring/ScoringFunction.java @@ -46,7 +46,7 @@ public interface ScoringFunction { * the agent is in when the simulation starts will have a startTime * of Time.getUndefinedTime(). The Activity which the agent is in when * the simulation ends will have an endTime of Time.getUndefinedTime(). - * It is up to the implementation what to make of this, + * It is up to the implementation what to make of this, * especially to "wrap" it "around". * @param activity */ @@ -103,10 +103,25 @@ public interface ScoringFunction { double getScore(); void handleEvent( Event event ) ; - + default void handleTrip( TripStructureUtils.Trip trip ) { // empty default implementation, since older implementations of the interface // don't have this method, and work happily without. kai, sep'18 } + /** + * Write detailed score explanation into the output {@code out}. Multiple value should be separated with {@link #SCORE_DELIMITER}. + */ + default void explainScore(StringBuilder out) { + } + + /** + * Delimiter used to separate scores in explanation string. + */ + String SCORE_DELIMITER = ";"; + /** + * The attribute that will be used for the score explanation. + */ + String SCORE_EXPLANATION = "scoreExplanation"; + } diff --git a/matsim/src/main/java/org/matsim/core/scoring/SumScoringFunction.java b/matsim/src/main/java/org/matsim/core/scoring/SumScoringFunction.java index 8a612a526a3..9096512dd9d 100644 --- a/matsim/src/main/java/org/matsim/core/scoring/SumScoringFunction.java +++ b/matsim/src/main/java/org/matsim/core/scoring/SumScoringFunction.java @@ -35,6 +35,12 @@ public final class SumScoringFunction implements ScoringFunction { public interface BasicScoring { void finish(); double getScore(); + + /** + * @see ScoringFunction#explainScore(StringBuilder). + */ + default void explainScore(StringBuilder out) { + } } public interface ActivityScoring extends BasicScoring { @@ -64,14 +70,14 @@ public interface AgentStuckScoring extends BasicScoring { } /** - * NOTE: Despite its somewhat misleading name, only Events that at the same time implement HasPersonId are passed + * NOTE: Despite its somewhat misleading name, only Events that at the same time implement HasPersonId are passed * through this interface. This excludes, in particular, LinkEnterEvent and LinkLeaveEvent. This was done for performance reasons, - * since passing those events to all handlers imposes a significant additional burden. See comments in - * and implementation of the handleEvent + * since passing those events to all handlers imposes a significant additional burden. See comments in + * and implementation of the handleEvent * method in {@link EventsToScore}. (yyyyyy Those comments, and possibly also the events filtering, have gone * from EventsToScore in commit e718809884cac6a86bdc35ea2a03c10195d37c69 . I don't know if the performance consequences - * were tested.) - * + * were tested.) + * * @author nagel */ public interface ArbitraryEventScoring extends BasicScoring { @@ -179,6 +185,20 @@ public double getScore() { return score; } + + @Override + public void explainScore(StringBuilder out) { + + for (BasicScoring s : basicScoringFunctions) { + + // If something was already written, a delimiter needs to be placed + if (out.length() != 0) + out.append(SCORE_DELIMITER); + + s.explainScore(out); + } + } + public void addScoringFunction(BasicScoring scoringFunction) { this.basicScoringFunctions.add(scoringFunction); diff --git a/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelActivityScoring.java b/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelActivityScoring.java index 4a05df8cc0b..20201d090a1 100644 --- a/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelActivityScoring.java +++ b/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelActivityScoring.java @@ -23,6 +23,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.population.Activity; +import org.matsim.core.scoring.ScoringFunction; import org.matsim.core.utils.misc.OptionalTime; /** @@ -34,8 +35,7 @@ public final class CharyparNagelActivityScoring implements org.matsim.core.scoring.SumScoringFunction.ActivityScoring { private static final double INITIAL_SCORE = 0.0; - private double score = INITIAL_SCORE; - + private Score score = new Score(); private static int firstLastActWarning = 0; private static short firstLastActOpeningTimesWarning = 0; @@ -71,10 +71,18 @@ public void finish() { @Override public double getScore() { - return this.score; + return this.score.act + this.score.actWaiting + this.score.actLateArrival + this.score.actEarlyDeparture; + } + + @Override + public void explainScore(StringBuilder out) { + out.append("act=").append(this.score.act).append(ScoringFunction.SCORE_DELIMITER); + out.append("actWaiting=").append(this.score.actWaiting).append(ScoringFunction.SCORE_DELIMITER); + out.append("actLateArrival=").append(this.score.actLateArrival).append(ScoringFunction.SCORE_DELIMITER); + out.append("actEarlyDeparture=").append(this.score.actEarlyDeparture); } - protected double calcActScore(final double arrivalTime, final double departureTime, final Activity act) { + protected Score calcActScore(final double arrivalTime, final double departureTime, final Activity act) { ActivityUtilityParameters actParams = this.params.utilParams.get(act.getType()); if (actParams == null) { @@ -82,7 +90,7 @@ protected double calcActScore(final double arrivalTime, final double departureTi "(module name=\"planCalcScore\" in the config file)."); } - double tmpScore = 0.0; + Score tmpScore = new Score(); if (actParams.isScoreAtAll()) { /* Calculate the times the agent actually performs the @@ -138,14 +146,14 @@ protected double calcActScore(final double arrivalTime, final double departureTi // disutility if too early if (arrivalTime < activityStart) { // agent arrives to early, has to wait - tmpScore += this.params.marginalUtilityOfWaiting_s * (activityStart - arrivalTime); + tmpScore.actWaiting += this.params.marginalUtilityOfWaiting_s * (activityStart - arrivalTime); } // disutility if too late OptionalTime latestStartTime = actParams.getLatestStartTime(); if (latestStartTime.isDefined() && (activityStart > latestStartTime.seconds())) { - tmpScore += this.params.marginalUtilityOfLateArrival_s * (activityStart - latestStartTime.seconds()); + tmpScore.actLateArrival += this.params.marginalUtilityOfLateArrival_s * (activityStart - latestStartTime.seconds()); } // utility of performing an action, duration is >= 1, thus log is no problem @@ -156,16 +164,16 @@ protected double calcActScore(final double arrivalTime, final double departureTi double utilPerf = this.params.marginalUtilityOfPerforming_s * typicalDuration * Math.log((duration / 3600.0) / actParams.getZeroUtilityDuration_h()); double utilWait = this.params.marginalUtilityOfWaiting_s * duration; - tmpScore += Math.max(0, Math.max(utilPerf, utilWait)); + tmpScore.act += Math.max(0, Math.max(utilPerf, utilWait)); } else { - tmpScore += 2*this.params.marginalUtilityOfLateArrival_s*Math.abs(duration); + tmpScore.actLateArrival += 2*this.params.marginalUtilityOfLateArrival_s*Math.abs(duration); } } else { if ( duration >= 3600.*actParams.getZeroUtilityDuration_h() ) { double utilPerf = this.params.marginalUtilityOfPerforming_s * typicalDuration * Math.log((duration / 3600.0) / actParams.getZeroUtilityDuration_h()); // also removing the "wait" alternative scoring. - tmpScore += utilPerf ; + tmpScore.act += utilPerf ; } else { // if ( wrnCnt < 1 ) { // wrnCnt++ ; @@ -188,7 +196,7 @@ protected double calcActScore(final double arrivalTime, final double departureTi if ( durationUnderrun < 0. ) { throw new RuntimeException( "durationUnderrun < 0; this should not happen ...") ; } - tmpScore -= slopeAtZeroUtility * durationUnderrun ; + tmpScore.act -= slopeAtZeroUtility * durationUnderrun ; } } @@ -196,18 +204,18 @@ protected double calcActScore(final double arrivalTime, final double departureTi // disutility if stopping too early OptionalTime earliestEndTime = actParams.getEarliestEndTime(); if ((earliestEndTime.isDefined()) && (activityEnd < earliestEndTime.seconds())) { - tmpScore += this.params.marginalUtilityOfEarlyDeparture_s * (earliestEndTime.seconds() - activityEnd); + tmpScore.actEarlyDeparture += this.params.marginalUtilityOfEarlyDeparture_s * (earliestEndTime.seconds() - activityEnd); } // disutility if going to away to late if (activityEnd < departureTime) { - tmpScore += this.params.marginalUtilityOfWaiting_s * (departureTime - activityEnd); + tmpScore.actWaiting += this.params.marginalUtilityOfWaiting_s * (departureTime - activityEnd); } // disutility if duration was too short OptionalTime minimalDuration = actParams.getMinimalDuration(); if ((minimalDuration.isDefined()) && (duration < minimalDuration.seconds())) { - tmpScore += this.params.marginalUtilityOfEarlyDeparture_s * (minimalDuration.seconds() - duration); + tmpScore.actEarlyDeparture += this.params.marginalUtilityOfEarlyDeparture_s * (minimalDuration.seconds() - duration); } } return tmpScore; @@ -236,9 +244,9 @@ private void handleOvernightActivity(Activity lastActivity) { } } - double calcActScore = calcActScore(lastActivity.getStartTime().seconds(), + Score calcActScore = calcActScore(lastActivity.getStartTime().seconds(), this.firstActivity.getEndTime().seconds() + 24 * 3600, lastActivity); - this.score += calcActScore; // SCENARIO_DURATION + this.score.add(calcActScore); // SCENARIO_DURATION } else { // the first Act and the last Act have NOT the same type: if (this.params.scoreActs) { @@ -257,10 +265,10 @@ private void handleOvernightActivity(Activity lastActivity) { } // score first activity - this.score += calcActScore(0.0, this.firstActivity.getEndTime().seconds(), firstActivity); + this.score.add(calcActScore(0.0, this.firstActivity.getEndTime().seconds(), firstActivity)); // score last activity - this.score += calcActScore(lastActivity.getStartTime().seconds(), - this.params.simulationPeriodInDays * 24 * 3600, lastActivity); + this.score.add(calcActScore(lastActivity.getStartTime().seconds(), + this.params.simulationPeriodInDays * 24 * 3600, lastActivity)); } } } @@ -268,7 +276,7 @@ private void handleOvernightActivity(Activity lastActivity) { private void handleMorningActivity() { assert firstActivity != null; // score first activity - this.score += calcActScore(0.0, this.firstActivity.getEndTime().seconds(), firstActivity); + this.score.add(calcActScore(0.0, this.firstActivity.getEndTime().seconds(), firstActivity)); } @Override @@ -279,7 +287,7 @@ public void handleFirstActivity(Activity act) { @Override public void handleActivity(Activity act) { - this.score += calcActScore(act.getStartTime().seconds(), act.getEndTime().seconds(), act); + this.score.add(calcActScore(act.getStartTime().seconds(), act.getEndTime().seconds(), act)); } @Override @@ -288,5 +296,22 @@ public void handleLastActivity(Activity act) { this.firstActivity = null; } + + private static final class Score { + + private double act = INITIAL_SCORE; + private double actWaiting = INITIAL_SCORE; + private double actLateArrival = INITIAL_SCORE; + private double actEarlyDeparture = INITIAL_SCORE; + + private void add(Score s) { + act += s.act; + actWaiting += s.actWaiting; + actLateArrival += s.actLateArrival; + actEarlyDeparture += s.actEarlyDeparture; + } + + } + } diff --git a/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelAgentStuckScoring.java b/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelAgentStuckScoring.java index b13af102485..fa636581d48 100644 --- a/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelAgentStuckScoring.java +++ b/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelAgentStuckScoring.java @@ -59,4 +59,8 @@ private double getStuckPenalty() { return this.params.abortedPlanScore; } + @Override + public void explainScore(StringBuilder out) { + out.append("agentStuck=").append(this.score); + } } diff --git a/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelLegScoring.java b/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelLegScoring.java index 8eaed1357e3..56c63df71df 100644 --- a/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelLegScoring.java +++ b/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelLegScoring.java @@ -99,6 +99,11 @@ public double getScore() { return this.score; } + @Override + public void explainScore(StringBuilder out) { + out.append("leg=").append(score); + } + private static int ccc=0 ; protected double calcLegScore(final double departureTime, final double arrivalTime, final Leg leg) { diff --git a/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelMoneyScoring.java b/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelMoneyScoring.java index 229ce6513ec..37352c8775f 100644 --- a/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelMoneyScoring.java +++ b/matsim/src/main/java/org/matsim/core/scoring/functions/CharyparNagelMoneyScoring.java @@ -56,4 +56,8 @@ public double getScore() { return this.score; } + @Override + public void explainScore(StringBuilder out) { + out.append("money=").append(score); + } } diff --git a/matsim/src/main/java/org/matsim/core/scoring/functions/ScoreEventScoring.java b/matsim/src/main/java/org/matsim/core/scoring/functions/ScoreEventScoring.java index 9e7b0695dde..fd6c028abbf 100644 --- a/matsim/src/main/java/org/matsim/core/scoring/functions/ScoreEventScoring.java +++ b/matsim/src/main/java/org/matsim/core/scoring/functions/ScoreEventScoring.java @@ -41,4 +41,8 @@ public double getScore() { return this.score; } + @Override + public void explainScore(StringBuilder out) { + out.append("scoreEvents=").append(score); + } } diff --git a/matsim/test/input/org/matsim/integration/replanning/ReRoutingIT/plans.xml.gz b/matsim/test/input/org/matsim/integration/replanning/ReRoutingIT/plans.xml.gz index 572027be93f936fe83252370108b8cdad1ba17d7..82d43e74de9dd9554d66a46101ef925e22cbd835 100644 GIT binary patch delta 4115843 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%0DC$g-(lHm_oG)Z!_Nz;U4L@D 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 wLShGsww6xxUrvj3Ij}XWfs3C=RO#&ICuraAv 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�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

    J(qm!Y+5h`4`vQZ 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[TmDo16p3hoI7AY#TMxT4^T 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%0A5^Kyxw;Eo?^OZ8R91zc9S!@e-)dx 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

  • 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 *

    xekGVa5i|bt@4_GEp8#bkP?VMgn&SN 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

  • Enter "Name of parameter set" and press "Calculate"
  • *
  • Save the two generated tables using "Results" > "Export" to the desired location
  • * - * + * * All these emission factor files need to be converted into *.txt or *.csv with ";" as delimiter. * Their column headers should automatically match the parser definition * in the respective method of the {@link org.matsim.contrib.emissions.EmissionModule}. @@ -44,7 +44,7 @@ *
  • roadTypeMappingFile: This file needs to map road types in your network to HBEFA 3.x road types. * Update (June'2018) one can now directly add HBEFA road type to link attributes using {@link org.matsim.contrib.emissions.EmissionUtils#setHbefaRoadType(org.matsim.api.core.v01.network.Link, java.lang.String)} * or see {@link org.matsim.contrib.emissions.utils.EmissionsConfigGroup} for a detailed description. - * + * *
  • emissionVehicleFile: This data type is defined in the EmissionsConfigGroup, * see {@link org.matsim.contrib.emissions.utils.EmissionsConfigGroup}. The following information is surrounded by {@link org.matsim.contrib.emissions.EmissionUtils.EmissionSpecificationMarker}. It is described as "definition of a vehicle * for every person (who is allowed to choose a vehicle in the simulation): @@ -61,7 +61,7 @@ *
      * *

      Model description

      - * + * *

      Emissions

      * The main package contains classes and methods to handle the emission input data and create * maps to associate the emissions with corresponding vehicle types, speed, parking time, ...
      @@ -86,7 +86,7 @@ * a distance, which is driven after parking and, again, vehicle attributes. * The cold/warm emission factor keys are mapped to the values of cold/warm emissions, the cold/warm emission factors. *

      - * + * * @author benjamin, julia */ diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionsFallbackBehaviour.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionsFallbackBehaviour.java index cef4618571e..d4816287c55 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionsFallbackBehaviour.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionsFallbackBehaviour.java @@ -76,9 +76,9 @@ public class TestColdEmissionsFallbackBehaviour { // --------- DetailedVsAverageLookupBehavior.onlyTryDetailedElseAbort) ----------- /** * vehicles information is complete - * + *

      * LookupBehavior: onlyTryDetailedElseAbort - * + *

      * -> should calculate value */ @Test @@ -86,7 +86,7 @@ void testColdDetailedValueOnlyDetailed() { EmissionModule emissionModule = setUpScenario( DetailedVsAverageLookupBehavior.onlyTryDetailedElseAbort ); Map coldEmissions = emissionModule.getColdEmissionAnalysisModule() - .checkVehicleInfoAndCalculateWColdEmissions(vehicleFull.getType(), vehicleFull.getId(), link.getId(), + .checkVehicleInfoAndCalculateWColdEmissions(vehicleFull.getType(), vehicleFull.getId(), link.getId(), startTime, parkingDuration, distance); Assertions.assertEquals(emissionsFactorInGrammPerKilometer_Detailed, coldEmissions.get(Pollutant.CO2_TOTAL ), MatsimTestUtils.EPSILON ); @@ -97,7 +97,7 @@ void testColdDetailedValueOnlyDetailed() { * * vehicles information is complete but fully specified entry is NOT available in detailed table * LookupBehavior: onlyTryDetailedElseAbort - * + *

      * -> should abort --> RuntimeException */ @Test @@ -114,9 +114,9 @@ void testCold_DetailedElseAbort_ShouldAbort1() { /** * vehicles information is complete but fully specified entry is NOT available in detailed table * HbefaTechnology is also not in detailed table -> fall back to technology average is NOT possible as well. - * + *

      * LookupBehavior: onlyTryDetailedElseAbort - * + *

      * -> should abort --> RuntimeException */ @Test @@ -135,7 +135,7 @@ void testCold_DetailedElseAbort_ShouldAbort2() { /** * vehicles information is complete * LookupBehavior: tryDetailedThenTechnologyAverageElseAbort - * + *

      * -> do NOT fall back to technology average * ---> should calculate value from detailed value */ @@ -144,7 +144,7 @@ void testCold_DetailedThenTechnologyAverageElseAbort_FallbackNotNeeded() { EmissionModule emissionModule = setUpScenario( DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageElseAbort ); Map coldEmissions = emissionModule.getColdEmissionAnalysisModule() - .checkVehicleInfoAndCalculateWColdEmissions(vehicleFull.getType(), vehicleFull.getId(), link.getId(), + .checkVehicleInfoAndCalculateWColdEmissions(vehicleFull.getType(), vehicleFull.getId(), link.getId(), startTime, parkingDuration, distance); Assertions.assertEquals(emissionsFactorInGrammPerKilometer_Detailed, coldEmissions.get(Pollutant.CO2_TOTAL ), MatsimTestUtils.EPSILON ); @@ -154,7 +154,7 @@ void testCold_DetailedThenTechnologyAverageElseAbort_FallbackNotNeeded() { /** * vehicles information is complete but fully specified entry is NOT available in detailed table * LookupBehavior: tryDetailedThenTechnologyAverageElseAbort - * + *

      * -> do fall back to technology average * ---> should calculate value from technology average */ @@ -173,9 +173,9 @@ void testCold_DetailedThenTechnologyAverageElseAbort_FallbackToTechnologyAverage /** * vehicles information is complete but fully specified entry is NOT available in detailed table * HbefaTechnology is also not in detailed table -> fall back to technology average is NOT possible as well. - * + *

      * LookupBehavior: onlyTryDetailedElseAbort - * + *

      * -> should abort --> RuntimeException */ @Test @@ -193,7 +193,7 @@ void testCold_DetailedThenTechnologyAverageElseAbort_ShouldAbort() { /** * vehicles information is complete * LookupBehavior: tryDetailedThenTechnologyAverageElseAbort - * + *

      * -> do NOT fall back to technology average or average table * ---> should calculate value from detailed value */ @@ -212,7 +212,7 @@ void testCold_DetailedThenTechnologyAverageThenAverageTable_FallbackNotNeeded() /** * vehicles information is complete but fully specified entry is NOT available in detailed table * LookupBehavior: tryDetailedThenTechnologyAverageElseAbort - * + *

      * -> do fall back to technology average; do NOT fall back to average table * ---> should calculate value from technology average */ @@ -230,9 +230,9 @@ void testCold_DetailedThenTechnologyAverageThenAverageTable_FallbackToTechnology /** * vehicles information is complete but fully specified entry is NOT available in detailed table * HbefaTechnology is also not in detailed table -> fall back to technology average is NOT possible as well. - * + *

      * LookupBehavior: tryDetailedThenTechnologyAverageThenAverageTable - * + *

      * -> do fall back to average table * ---> should calculate value from average table */ diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java index c8c39b2f3ad..9d6fc109be9 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java @@ -47,7 +47,7 @@ /* * test for playground.vsp.emissions.WarmEmissionAnalysisModule - * + *

      * WarmEmissionAnalysisModule (weam) * public methods and corresponding tests: * weamParameter - testWarmEmissionAnalysisParameter @@ -60,12 +60,12 @@ * get free flow km counter - testCounters*() * get top go km couter - testCounters*() * get warm emission event counter - testCounters*() - * + *

      * private methods and corresponding tests: * rescale warm emissions - rescaleWarmEmissionsTest() * calculate warm emissions - implicitly tested * convert string 2 tuple - implicitly tested - * + *

      * in all cases the needed tables are created manually by the setUp() method * see test methods for details on the particular test cases **/ diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionsFallbackBehaviour.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionsFallbackBehaviour.java index 4d7d500299e..35f4c8c2c47 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionsFallbackBehaviour.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionsFallbackBehaviour.java @@ -60,12 +60,12 @@ public class TestWarmEmissionsFallbackBehaviour { private final Vehicle vehicleFallbackToAverageTable = generateVehicleForFallbackToAverageTable(); -// --------- DetailedVsAverageLookupBehavior.onlyTryDetailedElseAbort) ----------- +// --------- DetailedVsAverageLookupBehavior.onlyTryDetailedElseAbort) ----------- /** * vehicles information is complete - * + *

      * LookupBehavior: onlyTryDetailedElseAbort - * + *

      * -> should calculate value */ @Test @@ -84,7 +84,7 @@ void testWarmDetailedValueOnlyDetailed() { * * vehicles information is complete but fully specified entry is NOT available in detailed table * LookupBehavior: onlyTryDetailedElseAbort - * + *

      * -> should abort --> RuntimeException */ @Test @@ -100,9 +100,9 @@ void testWarm_DetailedElseAbort_ShouldAbort1() { /** * vehicles information is complete but fully specified entry is NOT available in detailed table * HbefaTechnology is also not in detailed table -> fall back to technology average is NOT possible as well. - * + *

      * LookupBehavior: onlyTryDetailedElseAbort - * + *

      * -> should abort --> RuntimeException */ @Test @@ -116,11 +116,11 @@ void testWarm_DetailedElseAbort_ShouldAbort2() { } -// --------- DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageElseAbort) ----------- +// --------- DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageElseAbort) ----------- /** * vehicles information is complete * LookupBehavior: tryDetailedThenTechnologyAverageElseAbort - * + *

      * -> do NOT fall back to technology average * ---> should calculate value from detailed value */ @@ -139,7 +139,7 @@ void testWarm_DetailedThenTechnologyAverageElseAbort_FallbackNotNeeded() { /** * vehicles information is complete but fully specified entry is NOT available in detailed table * LookupBehavior: tryDetailedThenTechnologyAverageElseAbort - * + *

      * -> do fall back to technology average * ---> should calculate value from technology average */ @@ -157,9 +157,9 @@ void testWarm_DetailedThenTechnologyAverageElseAbort_FallbackToTechnologyAverage /** * vehicles information is complete but fully specified entry is NOT available in detailed table * HbefaTechnology is also not in detailed table -> fall back to technology average is NOT possible as well. - * + *

      * LookupBehavior: onlyTryDetailedElseAbort - * + *

      * -> should abort --> RuntimeException */ @Test @@ -172,11 +172,11 @@ void testWarm_DetailedThenTechnologyAverageElseAbort_ShouldAbort() { }); } -// --------- DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageThenAverageTable ----------- +// --------- DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageThenAverageTable ----------- /** * vehicles information is complete * LookupBehavior: tryDetailedThenTechnologyAverageElseAbort - * + *

      * -> do NOT fall back to technology average or average table * ---> should calculate value from detailed value */ @@ -195,7 +195,7 @@ void testWarm_DetailedThenTechnologyAverageThenAverageTable_FallbackNotNeeded() /** * vehicles information is complete but fully specified entry is NOT available in detailed table * LookupBehavior: tryDetailedThenTechnologyAverageElseAbort - * + *

      * -> do fall back to technology average; do NOT fall back to average table * ---> should calculate value from technology average */ @@ -213,9 +213,9 @@ void testWarm_DetailedThenTechnologyAverageThenAverageTable_FallbackToTechnology /** * vehicles information is complete but fully specified entry is NOT available in detailed table * HbefaTechnology is also not in detailed table -> fall back to technology average is NOT possible as well. - * + *

      * LookupBehavior: tryDetailedThenTechnologyAverageThenAverageTable - * + *

      * -> do fall back to average table * ---> should calculate value from average table */ @@ -233,7 +233,7 @@ void testWarm_DetailedThenTechnologyAverageThenAverageTable_FallbackToAverageTab -// ---------- setup and helper methods ------------- +// ---------- setup and helper methods ------------- /** * load and prepare the scenario, create the emissionsModule From fcd62efcdb66cb7f813f01ad8d7127b6c5a66303 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 12:20:06 +0200 Subject: [PATCH 143/213] javadoc: set link as a link --- .../contrib/emissions/analysis/FastEmissionGridAnalyzer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java index b036c3d9f72..5af1857ae90 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java @@ -54,7 +54,7 @@ public abstract class FastEmissionGridAnalyzer { * 2. The aggregated emissions for each link are rastered onto all the raster-cells covered by the link. * 3. In the smoothing step the emissions are blurred onto the surrounding raster-cells. *

      - * The blurring algorithm is a gaussian blur https://en.wikipedia.org/wiki/Gaussian_blur + * The blurring algorithm is a gaussian blur ... *

      * If only a certain area of the scenario is of interest for the analysis. The supplied network must be filtered beforehand. * The resulting raster's size depends on the bounding box of the supplied network. From 8de79dc8e089d5cd031eddcc324143fac40a630c Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 12:22:15 +0200 Subject: [PATCH 144/213] logging: use parameterized logging --- .../emissions/ColdEmissionAnalysisModule.java | 35 +++++++++--------- .../emissions/ColdEmissionHandler.java | 7 ++-- .../contrib/emissions/EmissionModule.java | 24 +++++-------- .../contrib/emissions/EmissionUtils.java | 4 +-- .../matsim/contrib/emissions/HbefaTables.java | 2 +- .../emissions/PositionEmissionsModule.java | 2 +- .../emissions/WarmEmissionAnalysisModule.java | 36 +++++++++---------- .../emissions/WarmEmissionHandler.java | 11 +++--- .../analysis/EmissionGridAnalyzer.java | 6 ++-- .../analysis/FastEmissionGridAnalyzer.java | 6 ++-- .../analysis/RawEmissionEventsReader.java | 2 +- .../emissions/utils/EmissionWriter.java | 2 +- .../emissions/utils/EmissionsConfigGroup.java | 8 ++--- .../TestColdEmissionAnalysisModuleCase1.java | 6 ++-- .../TestColdEmissionAnalysisModuleCase2.java | 4 +-- .../TestColdEmissionAnalysisModuleCase3.java | 6 ++-- .../TestColdEmissionAnalysisModuleCase4.java | 6 ++-- .../TestColdEmissionAnalysisModuleCase6.java | 6 ++-- .../TestHbefaWarmEmissionFactorKey.java | 4 +-- 19 files changed, 80 insertions(+), 97 deletions(-) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionAnalysisModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionAnalysisModule.java index 4e058d47451..6793d6dcaa1 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionAnalysisModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionAnalysisModule.java @@ -130,7 +130,7 @@ private Map calculateColdEmissions(Id vehicleId, dou final Map coldEmissionsOfEvent = new EnumMap<>( Pollutant.class ); - logger.debug("VehId: " + vehicleId + " ; Tuple.first = " +vehicleInformationTuple.getFirst()); + logger.debug("VehId: {} ; Tuple.first = {}", vehicleId, vehicleInformationTuple.getFirst()); // fallback vehicle types that we cannot or do not want to map onto a hbefa vehicle type: if ( vehicleInformationTuple.getFirst()==HbefaVehicleCategory.NON_HBEFA_VEHICLE ) { for ( Pollutant coldPollutant : coldPollutants) { @@ -218,8 +218,7 @@ private void changeVehCategory(HbefaColdEmissionFactorKey key, HbefaVehicleCateg // } if (vehInfoWarnHDVCnt < maxWarnCnt) { vehInfoWarnHDVCnt++; - logger.warn("Automagic changing of VehCategory is disabled. Please make sure that your table contains the " + - "necessary values for " + originVehCat.name()); + logger.warn("Automagic changing of VehCategory is disabled. Please make sure that your table contains the necessary values for {}", originVehCat.name()); if (vehInfoWarnHDVCnt == maxWarnCnt) logger.warn(Gbl.FUTURE_SUPPRESSED); } } @@ -241,7 +240,7 @@ private HbefaColdEmissionFactor getEmissionsFactor(Tuple; average; average'"); logger.warn(Gbl.ONLYONCE); logger.warn(Gbl.FUTURE_SUPPRESSED); @@ -306,7 +305,7 @@ private HbefaColdEmissionFactor getEmissionsFactor(Tuple; average; average" should, I think, just be entered as such. kai, feb'20 @@ -336,7 +335,7 @@ private HbefaColdEmissionFactor getEmissionsFactor(Tuple; average; average'"); logger.warn(Gbl.ONLYONCE); logger.warn(Gbl.FUTURE_SUPPRESSED); @@ -370,7 +369,7 @@ private HbefaColdEmissionFactor getEmissionsFactor(Tuple; average; average" should, I think, just be entered as such. kai, feb'20 @@ -387,7 +386,7 @@ private HbefaColdEmissionFactor getEmissionsFactor(Tuple list = new ArrayList<>(this.avgHbefaColdTable.keySet()); list.sort(Comparator.comparing(HbefaColdEmissionFactorKey::toString)); for (HbefaColdEmissionFactorKey key : list) { diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionHandler.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionHandler.java index 74dfec02974..97eeee4956b 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionHandler.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionHandler.java @@ -17,7 +17,7 @@ * (at your option) any later version. * * See also COPYING, LICENSE and WARRANTY file * * * - * + * * *********************************************************************** */ package org.matsim.contrib.emissions; @@ -134,8 +134,7 @@ static void handleNullVehicleECG(Id vehicleId, EmissionsConfigGroup emi + " Aborting..." ); case ignore: if ( noVehWarnCnt < 10 ){ - logger.warn( - "No vehicle defined for id " + vehicleId + ". The vehicle will be ignored." ); + logger.warn("No vehicle defined for id {}. The vehicle will be ignored.", vehicleId); noVehWarnCnt++; if ( noVehWarnCnt == 10 ) logger.warn( Gbl.FUTURE_SUPPRESSED ); } @@ -201,7 +200,7 @@ public void handleEvent(VehicleEntersTrafficEvent event) { private void warnIfZeroLinkLength(Id linkId, double linkLength) { if (linkLength == 0.) { if (zeroLinkLengthWarnCnt == 0) { - logger.warn("Length of the link " + linkId + " is zero. No emissions will be estimated for this link. Make sure, this is intentional."); + logger.warn("Length of the link {} is zero. No emissions will be estimated for this link. Make sure, this is intentional.", linkId); logger.warn(Gbl.ONLYONCE); zeroLinkLengthWarnCnt++; } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java index 842075c1ba9..e7eaec3a17c 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java @@ -103,27 +103,19 @@ public EventsManager getEmissionEventsManager() { } public void writeEmissionInformation() { - logger.info("Warm emissions were not calculated for " + warmEmissionHandler.getLinkLeaveWarnCnt() + " of " + - warmEmissionHandler.getLinkLeaveCnt() + " link leave events (no corresponding link enter event)."); + logger.info("Warm emissions were not calculated for {} of {} link leave events (no corresponding link enter event).", warmEmissionHandler.getLinkLeaveWarnCnt(), warmEmissionHandler.getLinkLeaveCnt()); int noVehicleLeavesTrafficEmissions = warmEmissionHandler.getSameLinkTrafficLeaveWarnCnt() + warmEmissionHandler.getUnusualTrafficLeaveWarnCnt(); - logger.info("Warm emissions were not calculated for " + noVehicleLeavesTrafficEmissions + " of " + warmEmissionHandler.getTrafficLeaveCnt() + - " vehicle leaves traffic events (no corresponding link enter event)."); + logger.info("Warm emissions were not calculated for {} of {} vehicle leaves traffic events (no corresponding link enter event).", noVehicleLeavesTrafficEmissions, warmEmissionHandler.getTrafficLeaveCnt()); if ( warmEmissionHandler.getUnusualTrafficLeaveWarnCnt() > 0 ) { - logger.info(warmEmissionHandler.getUnusualTrafficLeaveWarnCnt() + " events occurred where the vehicle left traffic without entering ANY link " + - "(no warm emissions calculated). These events might need to be investigated."); } + logger.info("{} events occurred where the vehicle left traffic without entering ANY link (no warm emissions calculated). These events might need to be investigated.", warmEmissionHandler.getUnusualTrafficLeaveWarnCnt()); } WarmEmissionAnalysisModule wam = warmEmissionHandler.getWarmEmissionAnalysisModule(); - logger.info("Emission calculation based on `Free flow only' occured for " + wam.getFreeFlowOccurences() + " of " + - wam.getWarmEmissionEventCounter() + " warm emission events."); - logger.info("Emission calculation based on `Stop&Go only' occured for " + wam.getStopGoOccurences() + " of " + - wam.getWarmEmissionEventCounter() + " warm emission events."); - logger.info("Emission calculation based on `Fractions' occured for " + wam.getFractionOccurences() + " of " + - wam.getWarmEmissionEventCounter() + " warm emission events."); - logger.info("Free flow occured on " + wam.getFreeFlowKmCounter() + " km of total " + - wam.getKmCounter() + " km, where emissions were calculated."); - logger.info("Stop&Go occured on " + wam.getStopGoKmCounter() + " km of total " + - wam.getKmCounter() + " km, where emissions were calculated."); + logger.info("Emission calculation based on `Free flow only' occured for {} of {} warm emission events.", wam.getFreeFlowOccurences(), wam.getWarmEmissionEventCounter()); + logger.info("Emission calculation based on `Stop&Go only' occured for {} of {} warm emission events.", wam.getStopGoOccurences(), wam.getWarmEmissionEventCounter()); + logger.info("Emission calculation based on `Fractions' occured for {} of {} warm emission events.", wam.getFractionOccurences(), wam.getWarmEmissionEventCounter()); + logger.info("Free flow occured on {} km of total {} km, where emissions were calculated.", wam.getFreeFlowKmCounter(), wam.getKmCounter()); + logger.info("Stop&Go occured on {} km of total {} km, where emissions were calculated.", wam.getStopGoKmCounter(), wam.getKmCounter()); logger.info("Emission calculation terminated. Emission events can be found in regular events file."); } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionUtils.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionUtils.java index 4b7ed17b902..e174e14192c 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionUtils.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionUtils.java @@ -225,7 +225,7 @@ static Tuple convertVehicleDescrip EngineInformation engineInformation; // get information from where it used to be in previous versions and move to where it should be now: - logger.debug("emissionsConfigGroup.getHbefaVehicleDescriptionSource=" + emissionsConfigGroup.getHbefaVehicleDescriptionSource()); + logger.debug("emissionsConfigGroup.getHbefaVehicleDescriptionSource={}", emissionsConfigGroup.getHbefaVehicleDescriptionSource()); switch( emissionsConfigGroup.getHbefaVehicleDescriptionSource() ) { case usingVehicleTypeId: // (v1, hbefa vehicle description is in vehicle type id. Copy to where it is expected now) @@ -320,7 +320,7 @@ public static HbefaVehicleCategory mapString2HbefaVehicleCategory(String string) try{ hbefaVehicleCategory = HbefaVehicleCategory.valueOf(string); } catch (IllegalArgumentException e) { - logger.warn("Could not map String " + string + " to any HbefaVehicleCategory; please check syntax in hbefa input file."); + logger.warn("Could not map String {} to any HbefaVehicleCategory; please check syntax in hbefa input file.", string); throw new RuntimeException(); } } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/HbefaTables.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/HbefaTables.java index b3d23dedb82..f01d42bb0f7 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/HbefaTables.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/HbefaTables.java @@ -125,7 +125,7 @@ private static HbefaTrafficSituation mapString2HbefaTrafficSituation(String stri else if (string.endsWith("St+Go")) return HbefaTrafficSituation.STOPANDGO; else if (string.endsWith("St+Go2")) return HbefaTrafficSituation.STOPANDGO_HEAVY; else { - logger.warn("Could not map String " + string + " to any HbefaTrafficSituation; please check syntax in hbefa input file."); + logger.warn("Could not map String {} to any HbefaTrafficSituation; please check syntax in hbefa input file.", string); throw new RuntimeException(); } } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/PositionEmissionsModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/PositionEmissionsModule.java index 4652c3d7339..1f6304d0ade 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/PositionEmissionsModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/PositionEmissionsModule.java @@ -290,7 +290,7 @@ private void computeCombinedEmissionEvent(PositionEvent event) { eventsManager.processEvent(new PositionEmissionEvent(event, combinedEmissions, "combined")); } else { - log.warn("speed was too fast: " + speed + "m/s Current time: " + event.getTime() + " prev time: " + previousPosition.getTime() + " current linkId: " + event.getLinkId() + " prev linkId: " + previousPosition.getLinkId() + " agentId: " + event.getPersonId()); + log.warn("speed was too fast: {}m/s Current time: {} prev time: {} current linkId: {} prev linkId: {} agentId: {}", speed, event.getTime(), previousPosition.getTime(), event.getLinkId(), previousPosition.getLinkId(), event.getPersonId()); } } else { // if the vehicle hasn't moved, issue an event with 0 emissions. This way there is an event for every timestep diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java index ff055cf31fd..33b43c8a9e1 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java @@ -275,7 +275,7 @@ Map calculateWarmEmissions(double travelTime_sec, String road } if ((averageSpeed_kmh - freeVelocity_ms * 3.6) > 1.0){ if (ecg.getHandleHighAverageSpeeds()) { - logger.warn("averageSpeed was capped from " + averageSpeed_kmh + " to" + freeVelocity_ms * 3.6 ); + logger.warn("averageSpeed was capped from {} to{}", averageSpeed_kmh, freeVelocity_ms * 3.6); averageSpeed_kmh = freeVelocity_ms * 3.6; } else { throw new RuntimeException("Average speed has been calculated to be greater than free flow speed; this might produce negative warm emissions. Aborting..."); @@ -307,7 +307,7 @@ Map calculateWarmEmissions(double travelTime_sec, String road // compute emissions from stop-go fraction: efkey.setTrafficSituation(STOPANDGO); efStopGo_gpkm = getEf(vehicleInformationTuple, efkey).getFactor(); - logger.debug("pollutant=" + warmPollutant + "; efStopGo=" + efStopGo_gpkm); + logger.debug("pollutant={}; efStopGo={}", warmPollutant, efStopGo_gpkm); } @@ -316,7 +316,7 @@ Map calculateWarmEmissions(double travelTime_sec, String road // compute emissions for free-flow fraction: efkey.setTrafficSituation(FREEFLOW); efFreeFlow_gpkm = getEf(vehicleInformationTuple, efkey).getFactor(); - logger.debug("pollutant=" + warmPollutant + "; efFreeFlow=" + efFreeFlow_gpkm); + logger.debug("pollutant={}; efFreeFlow={}", warmPollutant, efFreeFlow_gpkm); } // sum them up: @@ -379,7 +379,7 @@ private HbefaWarmEmissionFactor getEf(Tuple; average; average'" ); logger.warn( Gbl.ONLYONCE ); logger.warn( Gbl.FUTURE_SUPPRESSED ); @@ -444,7 +444,7 @@ private HbefaWarmEmissionFactor getEf(Tuple; average; average" should, I think, just be entered as such. kai, feb'20 @@ -462,7 +462,7 @@ private HbefaWarmEmissionFactor getEf(Tuple; average; average'" ); logger.warn( Gbl.ONLYONCE ); logger.warn( Gbl.FUTURE_SUPPRESSED ); @@ -496,7 +496,7 @@ private HbefaWarmEmissionFactor getEf(Tuple; average; average" should, I think, just be entered as such. kai, feb'20 @@ -513,7 +513,7 @@ private HbefaWarmEmissionFactor getEf(Tuple list = new ArrayList<>( this.avgHbefaWarmTable.keySet() ); list.sort( Comparator.comparing( HbefaWarmEmissionFactorKey::toString ) ); for ( HbefaWarmEmissionFactorKey key : list ) { diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionHandler.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionHandler.java index 8213320fdff..03a57d63b17 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionHandler.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionHandler.java @@ -123,12 +123,10 @@ public void handleEvent(VehicleLeavesTrafficEvent event) { handleNullVehicle(vehicleId); } } else if ( this.vehicleEntersTrafficMap.containsKey( vehicleId ) ) { - logger.warn("At time " + event.getTime() + ", vehicle " + event.getVehicleId() + " enters and leaves traffic without" + - " having entered link " + event.getLinkId() + ". Thus, no emissions are calculated for travel along this link."); + logger.warn("At time {}, vehicle {} enters and leaves traffic without having entered link {}. Thus, no emissions are calculated for travel along this link.", event.getTime(), event.getVehicleId(), event.getLinkId()); sameLinkTrafficLeaveWarnCnt++; } else { - logger.warn("At time " + event.getTime() + ", vehicle " + event.getVehicleId() + " left traffic without entering traffic " + - "or ANY link. Thus, no emissions are calculated for this unusual event."); + logger.warn("At time {}, vehicle {} left traffic without entering traffic or ANY link. Thus, no emissions are calculated for this unusual event.", event.getTime(), event.getVehicleId()); unusualTrafficLeaveWarnCnt++; } } @@ -191,7 +189,7 @@ private void emissionsCalculation(Id vehicleId, Vehicle vehicle, Link l private boolean linkLengthIsZero( Id linkId, double linkLength) { if (linkLength == 0.) { if (zeroLinkLengthWarnCnt == 0) { - logger.warn("Length of the link " + linkId + " is zero. No emissions will be estimated for this link. Make sure that this is intentional."); + logger.warn("Length of the link {} is zero. No emissions will be estimated for this link. Make sure that this is intentional.", linkId); logger.warn(Gbl.ONLYONCE); zeroLinkLengthWarnCnt++; } @@ -211,8 +209,7 @@ private void handleNullVehicle(Id vehicleId) { + " Aborting..."); } else if (this.warmEmissionAnalysisModule.getEcg().getNonScenarioVehicles().equals(NonScenarioVehicles.ignore)) { if (noVehWarnCnt < 10) { - logger.warn( - "No vehicle defined for id " + vehicleId + ". The vehicle will be ignored."); + logger.warn("No vehicle defined for id {}. The vehicle will be ignored.", vehicleId); noVehWarnCnt++; if (noVehWarnCnt == 10) logger.warn(Gbl.FUTURE_SUPPRESSED); } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/EmissionGridAnalyzer.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/EmissionGridAnalyzer.java index 1454c799a48..65586e05d91 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/EmissionGridAnalyzer.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/EmissionGridAnalyzer.java @@ -106,7 +106,7 @@ public TimeBinMap>> process(String eventsFile) { logger.info("Starting grid computation..."); for (var bin : timeBinsWithEmissions.getTimeBins()) { - logger.info("creating grid for time bin with start time: " + bin.getStartTime()); + logger.info("creating grid for time bin with start time: {}", bin.getStartTime()); Grid> grid = writeAllLinksToGrid(bin.getValue()); result.getTimeBin(bin.getStartTime()).setValue(grid); } @@ -153,7 +153,7 @@ public Tuple processNextTimeBin() { if (!this.timeBins.hasNext()) throw new RuntimeException("processNextTimeBin() was called too many times"); TimeBinMap.TimeBin, EmissionsByPollutant>> nextBin = this.timeBins.next(); - logger.info("creating grid for time bin with start time: " + nextBin.getStartTime()); + logger.info("creating grid for time bin with start time: {}", nextBin.getStartTime()); Grid> grid = writeAllLinksToGrid(nextBin.getValue()); @@ -224,7 +224,7 @@ private Grid> writeAllLinksToGrid(Map, Emissions .forEach(entry -> { var count = counter.incrementAndGet(); if (count % 10000 == 0) - logger.info("processing: " + count * 100 / linksWithEmissions.keySet().size() + "% done"); + logger.info("processing: {}% done", count * 100 / linksWithEmissions.keySet().size()); if (network.getLinks().containsKey(entry.getKey()) && isWithinBounds(network.getLinks().get(entry.getKey()))) { processLink(network.getLinks().get(entry.getKey()), entry.getValue(), grid); diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java index 5af1857ae90..fdff9835fa6 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java @@ -92,7 +92,7 @@ public static Map processEventsFile(final String eventsFile, logger.info("Start smoothing pollution."); return linkEmissionsByPollutant.entrySet().stream() .map(entry -> { - logger.info("Smoothing of: " + entry.getKey()); + logger.info("Smoothing of: {}", entry.getKey()); return Tuple.of(entry.getKey(), processLinkEmissions(entry.getValue(), network, cellSize, radius)); }) .collect(Collectors.toMap(Tuple::getFirst, Tuple::getSecond)); @@ -116,7 +116,7 @@ public static Map processHandlerEmissions(Map, Map

      { - logger.info("Smoothing of: " + entry.getKey()); + logger.info("Smoothing of: {}", entry.getKey()); return Tuple.of(entry.getKey(), processLinkEmissions(entry.getValue(), network, cellSize, radius)); }) .collect(Collectors.toMap(Tuple::getFirst, Tuple::getSecond)); @@ -192,7 +192,7 @@ public static Raster processLinkEmissions(final Map, Double> emissions, static Raster blur(Raster raster, int radius) { - logger.info("Creating Kernel with " + (radius * 2 + 1) + " taps"); + logger.info("Creating Kernel with {} taps", radius * 2 + 1); var kernel = createKernel(radius * 2 + 1); var result = new Raster(raster.getBounds(), raster.getCellSize()); diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReader.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReader.java index ff962f67cff..283d144e0bb 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReader.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReader.java @@ -103,7 +103,7 @@ private void handleEmissionEvent(Attributes atts) { // give some feedback about progress var currentCount = eventsCounter.incrementAndGet(); if (currentCount % 500000 == 0) { - logger.info("Emission Event # " + numberFormat.format(currentCount)); + logger.info("Emission Event # {}", numberFormat.format(currentCount)); } } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionWriter.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionWriter.java index 10ba02d6243..f402d16519f 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionWriter.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionWriter.java @@ -83,7 +83,7 @@ public void writeHomeLocation2TotalEmissions( } //Close the output stream out.close(); - logger.info("Finished writing output to " + outFile); + logger.info("Finished writing output to {}", outFile); } catch (Exception e){ throw new RuntimeException(e); } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionsConfigGroup.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionsConfigGroup.java index e64ef90be51..a5d366ae78f 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionsConfigGroup.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionsConfigGroup.java @@ -317,12 +317,8 @@ public void setEmissionsComputationMethod(EmissionsComputationMethod emissionsCo @Override protected final void checkConsistency(Config config){ switch( this.emissionsComputationMethod ){ - case StopAndGoFraction -> log.info( "Please note that with setting of emissionsComputationMethod " + EmissionsComputationMethod.StopAndGoFraction + "" + - " the emission factors for both freeFlow and StopAndGo fractions are looked up independently and are " + - "therefore following the fallback behaviour set in " + DETAILED_VS_AVERAGE_LOOKUP_BEHAVIOR + - " independently. --> Depending on the input, it may be that e.g. for ff the detailed value is taken, while for the stopAndGo part " + - "a less detailed value is used, because the value with the same level of detail is missing." ); - case AverageSpeed -> log.warn( "This setting of emissionsComputationMethod. " + EmissionsComputationMethod.AverageSpeed + " is not covered by many test cases." ); + case StopAndGoFraction -> log.info("Please note that with setting of emissionsComputationMethod {} the emission factors for both freeFlow and StopAndGo fractions are looked up independently and are therefore following the fallback behaviour set in " + DETAILED_VS_AVERAGE_LOOKUP_BEHAVIOR + " independently. --> Depending on the input, it may be that e.g. for ff the detailed value is taken, while for the stopAndGo part a less detailed value is used, because the value with the same level of detail is missing.", EmissionsComputationMethod.StopAndGoFraction); + case AverageSpeed -> log.warn("This setting of emissionsComputationMethod. {} is not covered by many test cases.", EmissionsComputationMethod.AverageSpeed); default -> throw new IllegalStateException( "Unexpected value: " + this.emissionsComputationMethod ); } } diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase1.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase1.java index 07da985b0a3..3dc63ebde3a 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase1.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase1.java @@ -107,13 +107,13 @@ void calculateColdEmissionsAndThrowEventTest_completeData() { // first case: complete data // corresponding entry in average table Collections.addAll(testCase1, "PASSENGER_CAR", petrol_technology, none_sizeClass, none_emConcept, averagePetrolFactor); - logger.info("Running testcase:" + testCase1); + logger.info("Running testcase:{}", testCase1); Id linkId = Id.create("linkId" + testCase1, Link.class); Id vehicleId = Id.create("vehicleId" + testCase1, Vehicle.class); Id vehicleTypeId = Id.create(testCase1.get(0) + ";" + testCase1.get(1) + ";" + testCase1.get(2) + ";" + testCase1.get(3), VehicleType.class); Vehicle vehicle = VehicleUtils.getFactory().createVehicle(vehicleId, VehicleUtils.getFactory().createVehicleType(vehicleTypeId)); - logger.info("VehicleId: " + vehicle.getId().toString()); - logger.info("VehicleTypeId: " + vehicle.getType().getId()); + logger.info("VehicleId: {}", vehicle.getId().toString()); + logger.info("VehicleTypeId: {}", vehicle.getType().getId()); final Map calculatedPollutants = coldEmissionAnalysisModule.checkVehicleInfoAndCalculateWColdEmissions(vehicle.getType(), vehicle.getId(), linkId, 0.0, parkingDuration, tableAccDistance); double sumOfEmissions = calculatedPollutants.values().stream().mapToDouble(Double::doubleValue).sum(); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase2.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase2.java index ccf34b068bd..c5ce8831a6a 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase2.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase2.java @@ -105,8 +105,8 @@ void calculateColdEmissionsAndThrowEventTest_completeData() { Id vehicleId = Id.create( "vehicleId" + testCase2 , Vehicle.class ); Id vehicleTypeId = Id.create( testCase2.get( 0 ) + ";" + testCase2.get( 1 ) + ";" + testCase2.get( 2 ) + ";" + testCase2.get( 3 ), VehicleType.class ); Vehicle vehicle = VehicleUtils.getFactory().createVehicle( vehicleId, VehicleUtils.getFactory().createVehicleType( vehicleTypeId ) ); - logger.info("VehicleId: " + vehicle.getId().toString()); - logger.info("VehicleTypeId: " + vehicle.getType().getId()); + logger.info("VehicleId: {}", vehicle.getId().toString()); + logger.info("VehicleTypeId: {}", vehicle.getType().getId()); Map calculatedPollutants = coldEmissionAnalysisModule.checkVehicleInfoAndCalculateWColdEmissions(vehicle.getType(), vehicle.getId(), linkId, 0.0, parkingDuration, tableAccDistance); double sumOfEmissions = calculatedPollutants.values().stream().mapToDouble(Double::doubleValue).sum(); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase3.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase3.java index fbebf02e2ce..52bee68cde3 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase3.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase3.java @@ -103,14 +103,14 @@ void calculateColdEmissionsAndThrowEventTest_completeData() { // error when using the average entry. Collections.addAll( testCase3, "PASSENGER_CAR", diesel_technology, geq2l_sizeClass, PC_D_Euro_3_emConcept, detailedDieselFactor ); - logger.info("Running testcase: " + testCase3); + logger.info("Running testcase: {}", testCase3); Id linkId = Id.create( "linkId" + testCase3 , Link.class ); Id vehicleId = Id.create( "vehicleId" + testCase3, Vehicle.class ); Id vehicleTypeId = Id.create( testCase3.get( 0 ) + ";" + testCase3.get( 1 ) + ";" + testCase3.get( 2 ) + ";" + testCase3.get( 3 ), VehicleType.class ); Vehicle vehicle = VehicleUtils.getFactory().createVehicle( vehicleId, VehicleUtils.getFactory().createVehicleType( vehicleTypeId ) ); - logger.info("VehicleId: " + vehicle.getId().toString()); - logger.info("VehicleTypeId: " + vehicle.getType().getId()); + logger.info("VehicleId: {}", vehicle.getId().toString()); + logger.info("VehicleTypeId: {}", vehicle.getType().getId()); Map calculatedPollutants = coldEmissionAnalysisModule.checkVehicleInfoAndCalculateWColdEmissions(vehicle.getType(), vehicle.getId(), linkId, 0.0, parkingDuration, tableAccDistance); double sumOfEmissions = calculatedPollutants.values().stream().mapToDouble(Double::doubleValue).sum(); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase4.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase4.java index c64e78372b8..021503fa903 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase4.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase4.java @@ -113,14 +113,14 @@ void calculateColdEmissionsAndThrowEventTest_completeData() { Collections.addAll( testCase4, "PASSENGER_CAR", "", "", "", averageAverageFactor ); - logger.info("Running testcase: " + testCase4.indexOf( 0 ) + " " + testCase4); + logger.info("Running testcase: {} {}", testCase4.indexOf(0), testCase4); Id linkId = Id.create( "linkId" + testCase4.indexOf( 0 ), Link.class ); Id vehicleId = Id.create( "vehicleId" + testCase4.indexOf( 0 ), Vehicle.class ); Id vehicleTypeId = Id.create( testCase4.get( 0 ) + ";" + testCase4.get( 1 ) + ";" + testCase4.get( 2 ) + ";" + testCase4.get( 3 ), VehicleType.class ); Vehicle vehicle = VehicleUtils.getFactory().createVehicle( vehicleId, VehicleUtils.getFactory().createVehicleType( vehicleTypeId ) ); - logger.info("VehicleId: " + vehicle.getId().toString()); - logger.info("VehicleTypeId: " + vehicle.getType().getId()); + logger.info("VehicleId: {}", vehicle.getId().toString()); + logger.info("VehicleTypeId: {}", vehicle.getType().getId()); Map calculatedPollutants = coldEmissionAnalysisModule.checkVehicleInfoAndCalculateWColdEmissions(vehicle.getType(), vehicle.getId(), linkId, 0.0, parkingDuration, tableAccDistance); double sumOfEmissions = calculatedPollutants.values().stream().mapToDouble(Double::doubleValue).sum(); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase6.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase6.java index d97ddf5162d..8013a55267b 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase6.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase6.java @@ -108,14 +108,14 @@ void calculateColdEmissionsAndThrowEventTest_completeData() { String heavygoodsvehicle = "HEAVY_GOODS_VEHICLE"; Collections.addAll( testCase6, heavygoodsvehicle, petrol_technology, none_sizeClass, none_emConcept, heavyGoodsFactor); - logger.info("Running testcase: " + testCase6 + " " + testCase6); + logger.info("Running testcase: {} {}", testCase6, testCase6); Id linkId = Id.create( "linkId" + testCase6, Link.class ); Id vehicleId = Id.create( "vehicleId" + testCase6, Vehicle.class ); Id vehicleTypeId = Id.create( testCase6.get( 0 ) + ";" + testCase6.get( 1 ) + ";" + testCase6.get( 2 ) + ";" + testCase6.get( 3 ), VehicleType.class ); Vehicle vehicle = VehicleUtils.getFactory().createVehicle( vehicleId, VehicleUtils.getFactory().createVehicleType( vehicleTypeId ) ); - logger.info("VehicleId: " + vehicle.getId().toString()); - logger.info("VehicleTypeId: " + vehicle.getType().getId()); + logger.info("VehicleId: {}", vehicle.getId().toString()); + logger.info("VehicleTypeId: {}", vehicle.getType().getId()); Map calculatedPollutants = coldEmissionAnalysisModule.checkVehicleInfoAndCalculateWColdEmissions(vehicle.getType(), vehicle.getId(), linkId, 0.0, parkingDuration, tableAccDistance); double sumOfEmissions = calculatedPollutants.values().stream().mapToDouble(Double::doubleValue).sum(); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaWarmEmissionFactorKey.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaWarmEmissionFactorKey.java index 947e985d7b3..b9bc83aa597 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaWarmEmissionFactorKey.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaWarmEmissionFactorKey.java @@ -121,8 +121,8 @@ final void testEqualsForIncompleteKeys_vehicleCategory() { noVehCat.setTrafficSituation(hbefaTrafficSituation); noVehCat.setVehicleAttributes(hbefaVehicleAttributes); - log.warn("normal=" + normal); - log.warn("noVehCat=" + noVehCat); + log.warn("normal={}", normal); + log.warn("noVehCat={}", noVehCat); var result = noVehCat.equals(normal); From f9ccc498b7f34c3b153346ead6117d362bd26ce6 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 12:25:25 +0200 Subject: [PATCH 145/213] add casting --- .../matsim/contrib/emissions/WarmEmissionAnalysisModule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java index 33b43c8a9e1..3b59b10d5a9 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java @@ -593,8 +593,8 @@ private void incrementCountersFractional(double linkLength_km, double fractionSt freeFlowKmCounter += linkLength_km * (1-fractionStopGo); stopGoKmCounter += linkLength_km * fractionStopGo; - freeFlowCounter += 1-fractionStopGo; - stopGoCounter += fractionStopGo; + freeFlowCounter += (int) (1-fractionStopGo); + stopGoCounter += (int) fractionStopGo; fractionCounter += (fractionStopGo < 1.0 && fractionStopGo > 0.0) ? 1 : 0; } From 268f609aac1a1334e87e087041cb847d0808732a Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 12:26:53 +0200 Subject: [PATCH 146/213] simplification --- .../emissions/analysis/EmissionsByPollutantTest.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionsByPollutantTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionsByPollutantTest.java index 635affd8832..208bd5e1328 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionsByPollutantTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionsByPollutantTest.java @@ -25,8 +25,7 @@ void initialize() { Map emissions = EmissionUtilsTest.createEmissions(); - Map map = new LinkedHashMap<>(); - emissions.forEach( map::put ) ; + Map map = new LinkedHashMap<>(emissions); EmissionsByPollutant linkEmissions = new EmissionsByPollutant( map ) ; @@ -47,7 +46,7 @@ void addEmission() { final double expectedValue = emissions.get(pollutant) + valueToAdd; Map map = new LinkedHashMap<>(); - emissions.forEach( map::put ) ; + map.putAll(emissions); EmissionsByPollutant emissionsByPollutant = new EmissionsByPollutant(map); @@ -80,12 +79,12 @@ void addEmissions() { Map emissions = EmissionUtilsTest.createEmissions(); Map map = new LinkedHashMap<>(); - emissions.forEach( map::put ) ; + map.putAll(emissions); EmissionsByPollutant linkEmissions = new EmissionsByPollutant(map); Map map2 = new LinkedHashMap<>(); - emissions.forEach( map2::put ) ; + map2.putAll(emissions); linkEmissions.addEmissions(map2); From 44713d945e1320f1912c52040b01f2dcb6ab6973 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 12:27:48 +0200 Subject: [PATCH 147/213] use 'append()' calls --- .../org/matsim/contrib/emissions/utils/EmissionWriter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionWriter.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionWriter.java index f402d16519f..ce87ab17cb0 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionWriter.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionWriter.java @@ -57,7 +57,7 @@ public void writeHomeLocation2TotalEmissions( BufferedWriter out = new BufferedWriter(fstream); out.append("personId \t xHome \t yHome \t"); for (String pollutant : pollutants){ - out.append(pollutant + "[g] \t"); + out.append(pollutant).append("[g] \t"); } out.append("\n"); @@ -69,12 +69,12 @@ public void writeHomeLocation2TotalEmissions( Double xHome = homeCoord.getX(); Double yHome = homeCoord.getY(); - out.append(personId + "\t" + xHome + "\t" + yHome + "\t"); + out.append(String.valueOf(personId)).append("\t").append(String.valueOf(xHome)).append("\t").append(String.valueOf(yHome)).append("\t"); Map emissionType2Value = totalEmissions.get(personId); for(String pollutant : pollutants){ if(emissionType2Value.get(pollutant) != null){ - out.append(emissionType2Value.get(pollutant) + "\t"); + out.append(String.valueOf(emissionType2Value.get(pollutant))).append("\t"); } else{ out.append("0.0" + "\t"); // TODO: do I still need this? } From 8fd0955d13b4feb87e3cfb479b9b6de48fb3f238 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 12:30:40 +0200 Subject: [PATCH 148/213] simplification by removing inaccessibly parts of if statements. --- .../contrib/emissions/example/CreateEmissionConfig.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/CreateEmissionConfig.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/CreateEmissionConfig.java index b0b73b6bd28..ee492e3bb25 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/CreateEmissionConfig.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/CreateEmissionConfig.java @@ -119,13 +119,7 @@ public static void main(String[] args) { // emission vehicles are now set in the default vehicle container config.vehicles().setVehiclesFile(emissionVehicleFile); - if ( (Boolean) false ==null ) { - ecg.setHbefaVehicleDescriptionSource( EmissionsConfigGroup.HbefaVehicleDescriptionSource.asEngineInformationAttributes ); - } else if ( false ) { - ecg.setHbefaVehicleDescriptionSource( EmissionsConfigGroup.HbefaVehicleDescriptionSource.usingVehicleTypeId ); - } else { - ecg.setHbefaVehicleDescriptionSource( EmissionsConfigGroup.HbefaVehicleDescriptionSource.fromVehicleTypeDescription ); - } + ecg.setHbefaVehicleDescriptionSource( EmissionsConfigGroup.HbefaVehicleDescriptionSource.fromVehicleTypeDescription ); ecg.setAverageWarmEmissionFactorsFile(averageFleetWarmEmissionFactorsFile); ecg.setAverageColdEmissionFactorsFile(averageFleetColdEmissionFactorsFile); From 1a8510d8421b8021c4f8998839d44fc80dd5ac60 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 12:34:01 +0200 Subject: [PATCH 149/213] remove duplicated setting of variable --- .../contrib/emissions/TestWarmEmissionAnalysisModule.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java index 9d6fc109be9..813cb15e28b 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java @@ -182,8 +182,6 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Ex excep = true; } Assertions.assertFalse(excep); - - excep=false; } @ParameterizedTest @@ -209,7 +207,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Ex }catch(Exception e){ excep = true; } - Assertions.assertTrue(excep); excep=false; + Assertions.assertTrue(excep); } @ParameterizedTest @@ -234,7 +232,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Ex }catch(Exception e){ excep = true; } - Assertions.assertTrue(excep); excep=false; + Assertions.assertTrue(excep); } @ParameterizedTest @@ -257,7 +255,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Ex }catch(Exception e){ excep = true; } - Assertions.assertTrue(excep); excep=false; + Assertions.assertTrue(excep); } From 3fa72e9774ef780074099e4bcb20d498c0fb0b1f Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 12:35:56 +0200 Subject: [PATCH 150/213] Simplify assertions --- .../TestHbefaColdEmissionFactorKey.java | 14 +++++++------- .../TestHbefaWarmEmissionFactorKey.java | 19 ++++++++++--------- .../emissions/utils/EmissionUtilsTest.java | 14 +++++++------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaColdEmissionFactorKey.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaColdEmissionFactorKey.java index e0181758ad3..d9475cdc817 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaColdEmissionFactorKey.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaColdEmissionFactorKey.java @@ -126,7 +126,7 @@ final void testEqualsForIncompleteKeys_vehicleCategory(){ noVehCat.setVehicleAttributes(hbefaVehicleAttributes); String message = "these two HbefaColdEmissionFactorKeys should not be the same: " + normal + " and " + noVehCat; - assertFalse(noVehCat.equals(normal), message); + assertNotEquals(noVehCat, normal, message); } @Test @@ -145,7 +145,7 @@ final void testEqualsForIncompleteKeys_pollutant(){ noColdPollutant.setVehicleAttributes(hbefaVehicleAttributes); String message = "these two HbefaColdEmissionFactorKeys should not be the same: " + normal.toString() + " and " + noColdPollutant; - assertFalse(noColdPollutant.equals(normal), message); + assertNotEquals(noColdPollutant, normal, message); } @Test @@ -164,7 +164,7 @@ final void testEqualsForIncompleteKeys_parkingTime() { noParkingTime.setVehicleAttributes(hbefaVehicleAttributes); String message = "these two HbefaColdEmissionFactorKeys should not be the same: " + normal.toString() + " and " + noParkingTime; - assertFalse(noParkingTime.equals(normal), message); + assertNotEquals(noParkingTime, normal, message); } @Test @@ -183,7 +183,7 @@ final void testEqualsForIncompleteKeys_distance() { noDistance.setVehicleAttributes(hbefaVehicleAttributes); String message = "these two HbefaColdEmissionFactorKeys should not be the same: " + normal.toString() + " and " + noDistance; - assertFalse(noDistance.equals(normal), message); + assertNotEquals(noDistance, normal, message); } @Test @@ -198,7 +198,7 @@ final void testEqualsForIncompleteKeys_emptyKey() { HbefaColdEmissionFactorKey emptyKey = new HbefaColdEmissionFactorKey(); String message = "these two HbefaColdEmissionFactorKeys should not be the same: " + normal.toString() + " and " + emptyKey; - assertFalse(emptyKey.equals(normal), message); + assertNotEquals(emptyKey, normal, message); } @Test @@ -225,7 +225,7 @@ final void testEqualsForIncompleteKeys_VehicleAttributes(){ noVehAtt.setVehicleCategory(hbefaVehCategory); String message = "these two HbefaColdEmissionFactorKeys should not be the same: " + normal + " and " + noVehAtt; - assertFalse(noVehAtt.equals(normal), message); + assertNotEquals(noVehAtt, normal, message); //set the vehicle attributes of the normal hbefaColdWmissionFactorKey to 'average' @@ -237,7 +237,7 @@ final void testEqualsForIncompleteKeys_VehicleAttributes(){ hbefaVehicleAttributesAverage.setHbefaTechnology("average"); normal.setVehicleAttributes(hbefaVehicleAttributesAverage); - Assertions.assertTrue(noVehAtt.equals(normal), message); + assertEquals(noVehAtt, normal, message); } } diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaWarmEmissionFactorKey.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaWarmEmissionFactorKey.java index b9bc83aa597..23ecb51b684 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaWarmEmissionFactorKey.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaWarmEmissionFactorKey.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.matsim.contrib.emissions.Pollutant.CO; import static org.matsim.contrib.emissions.Pollutant.FC; @@ -80,8 +81,8 @@ final void testEqualsForCompleteKeys(){ compare.setVehicleCategory(hbefaVehicleCategory); String message = "these two objects should be the same but are not: " + normal.toString() + " and " + compare; - Assertions.assertTrue(normal.equals(compare), message); - Assertions.assertTrue(compare.equals(normal), message); + Assertions.assertEquals(normal, compare, message); + Assertions.assertEquals(compare, normal, message); //two unequal but complete objects HbefaWarmEmissionFactorKey different = new HbefaWarmEmissionFactorKey(); @@ -97,8 +98,8 @@ final void testEqualsForCompleteKeys(){ message = "these two objects should not be the same: " + normal.toString() + " and " + different; - assertFalse(different.equals(normal), message); - assertFalse(normal.equals(different), message); + assertNotEquals(different, normal, message); + assertNotEquals(normal, different, message); } // the following tests each compare a incomplete key to a complete key @@ -170,7 +171,7 @@ final void testEqualsForIncompleteKeys_roadCategory() { String message = "these two HbefaWarmEmissionFactorKeys should not be the same: " + normal.toString() + " and " + noRoadCat; String message2 = "this key should not be comparable since no road category is set"; Assertions.assertTrue(equalErr, message2); - assertFalse(normal.equals(noRoadCat), message); + assertNotEquals(normal, noRoadCat, message); } @Test @@ -233,11 +234,11 @@ final void testEqualsForIncompleteKeys_vehicleAttributes(){ } String message = "these two HbefaWarmEmissionFactorKeys should not be the same: " + normal.toString() + " and " + noVehAtt; - assertFalse(noVehAtt.equals(normal), message); + assertNotEquals(noVehAtt, normal, message); assertFalse(equalErr); // veh attributes are allowed to be not initiated // therefore this should not throw a nullpointer but return false - assertFalse(normal.equals(noVehAtt), message); + assertNotEquals(normal, noVehAtt, message); //set the vehicle attributes of the normal hbefacoldemissionfactorkey to 'average' //then noVehAtt is equal to normal @@ -248,8 +249,8 @@ final void testEqualsForIncompleteKeys_vehicleAttributes(){ normal.setVehicleAttributes(hbefaVehicleAttributesAverage); message = "these two HbefaWarmEmissionFactorKeys should be the same: " + normal.toString() + " and " + noVehAtt; - Assertions.assertTrue(normal.equals(noVehAtt), message); - Assertions.assertTrue(noVehAtt.equals(normal), message); + Assertions.assertEquals(normal, noVehAtt, message); + Assertions.assertEquals(noVehAtt, normal, message); } diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java index 4f20dfbf78f..9d978f682e6 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java @@ -52,8 +52,8 @@ * missing data is not tested here * negative emission values are allowed * 1 test constructor - * 2 test sumUpEmissions - * 3 test sumUpEmissionPerId + * 2 test sumUpEmissions + * 3 test sumUpEmissionPerId * 4 test getTotalEmissions * 5 test SetNonCalculatedEmissionsForPopulation * - correct input - population does not match map of emissions - empty map of emissions @@ -430,7 +430,7 @@ final void testSetNonCalculatedEmissionsForPopulation_completeData(){ //check: all values for person 1 and 2 are not null or zero // and of type double for(Object id : finalMap.keySet()) { - Assertions.assertTrue(id instanceof Id); + Assertions.assertInstanceOf(Id.class, id); for (Object pollutant : finalMap.get(id).values()) { Assertions.assertSame(pollutant.getClass(), Double.class); Assertions.assertNotSame(0.0, pollutant); @@ -553,7 +553,7 @@ final void testSetNonCalculatedEmissionsForPopulation_nullEmissions(){ //test setNonCalculatedEmissionsForPopulation with 'null' // throw nullpointer exception setUpForNonCaculatedEmissions(); - + Id idp5 = Id.create("p5", Person.class); Person p5 = populationFactory.createPerson(idp5); pop.addPerson(p5); @@ -576,7 +576,7 @@ final void testSetNonCalculatedEmissionsForPopulation_emptyPopulation(){ // empty list should be returned setUpForNonCaculatedEmissions(); - //person 7 in totalEmissions but not in population + //person 7 in totalEmissions but not in population SortedMap p7Emissions = new TreeMap<>(); //complete list of all pollutants - missing data is not tested here p7Emissions.put( CO, .0 ); @@ -815,6 +815,6 @@ private void addLinksToNetwork(Scenario sc) { NetworkUtils.createAndAddLink(network, Id.create("link24", Link.class), node2, node4, 1000., 20., 3600, 2); NetworkUtils.createAndAddLink(network, Id.create("link34", Link.class), node3, node4, 1000., 20., 3600, 2); //w/o orig id and type } - + } - + From 04ad679817835d515dd0087d5ff0b7bdf9131b86 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 12:37:35 +0200 Subject: [PATCH 151/213] Simplify stream --- .../java/org/matsim/contrib/emissions/OsmHbefaMapping.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java index 27da7acf1be..f9de1d049b1 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java @@ -25,9 +25,9 @@ import org.matsim.api.core.v01.network.Link; import org.matsim.core.network.NetworkUtils; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.stream.Stream; /** * Created by molloyj on 01.12.2017. @@ -123,8 +123,7 @@ private String getHEBFAtype(String type, double speed) { //sometimes link type is smth like 'motorway_link' or 'living_street' or 'primary|railway.tram'. We only care about the first part, here - int idx = Arrays.asList(type.indexOf('.'), type.indexOf('|'), type.indexOf('_'), type.indexOf(',')) - .stream() + int idx = Stream.of(type.indexOf('.'), type.indexOf('|'), type.indexOf('_'), type.indexOf(',')) .filter(i -> i>= 0) //if chrc is not in String indexOf returns -1 .min(Integer::compare) .orElse(type.length()); From ebec8854866de9e1719935073978d49699f23bff Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 12:39:26 +0200 Subject: [PATCH 152/213] avoid casting --- .../contrib/emissions/utils/EmissionUtilsTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java index 9d978f682e6..b4404ed0bfb 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java @@ -487,10 +487,10 @@ final void testSetNonCalculatedEmissionsForPopulation_missingMap() { Assertions.assertEquals(pop.getPersons().keySet().size(), finalMap.keySet().size(), message); //check: all values for the this person are zero and of type double - for (Object pollutant : finalMap.get(idp3).values()) { - Assertions.assertSame(pollutant.getClass(), Double.class); - Assertions.assertEquals(0.0, (Double) pollutant, MatsimTestUtils.EPSILON); - Assertions.assertNotNull(pollutant); + for (Double pollutantValues : finalMap.get(idp3).values()) { + Assertions.assertSame(pollutantValues.getClass(), Double.class); + Assertions.assertEquals(0.0, pollutantValues, MatsimTestUtils.EPSILON); + Assertions.assertNotNull(pollutantValues); } //check: all types of emissions appear for (Pollutant emission : pollsFromEU) { @@ -625,9 +625,9 @@ final void testSetNonCalculatedEmissionsForPopulation_emptyEmissionMap() { //check: all values for all persons are zero and of type double for (Id id : finalMap.keySet()) { - for (Object pollutant : finalMap.get(id).values()) { + for (Double pollutant : finalMap.get(id).values()) { Assertions.assertSame(pollutant.getClass(), Double.class); - Assertions.assertEquals(0.0, (Double) pollutant, MatsimTestUtils.EPSILON, "map of pollutants was missing. Therefore all values should be set to zero."); + Assertions.assertEquals(0.0, pollutant, MatsimTestUtils.EPSILON, "map of pollutants was missing. Therefore all values should be set to zero."); Assertions.assertNotNull(pollutant); } //check: alle types of emissions appear From 0319babf6c31692315fba83e87d6c09b446b594d Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 12:42:44 +0200 Subject: [PATCH 153/213] suppress warning --- .../main/java/org/matsim/contrib/emissions/EmissionModule.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java index e7eaec3a17c..7f06339b8f6 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java @@ -77,11 +77,13 @@ public EmissionModule(final Scenario scenario, final EventsManager eventsManager // Event handlers are now added to the event manager inside the respective Handlers, jm march '18 } + @SuppressWarnings("ClassEscapesDefinedScope") public WarmEmissionAnalysisModule getWarmEmissionAnalysisModule() { // makes sense to have this public for externalization computations. kai, jan'20 return this.warmEmissionHandler.getWarmEmissionAnalysisModule(); } + @SuppressWarnings("ClassEscapesDefinedScope") public ColdEmissionAnalysisModule getColdEmissionAnalysisModule() { // makes sense to have this public for externalization computations. kai, jan'20 return this.coldEmissionHandler.getColdEmissionAnalysisModule(); From 597faae3962568c0534f39ead771c6eaaed14362 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 12:52:24 +0200 Subject: [PATCH 154/213] fix some (language) grammar --- .../java/org/matsim/contrib/emissions/EmissionModule.java | 7 ++++--- .../java/org/matsim/contrib/emissions/OsmHbefaMapping.java | 2 +- .../matsim/contrib/emissions/PositionEmissionsModule.java | 4 ++-- .../contrib/emissions/analysis/EmissionGridAnalyzer.java | 4 ++-- .../emissions/analysis/FastEmissionGridAnalyzer.java | 4 ++-- .../emissions/analysis/RawEmissionEventsReader.java | 2 +- .../example/RunAverageEmissionToolOfflineExample.java | 2 +- .../example/RunDetailedEmissionToolOfflineExample.java | 2 +- .../emissions/TestColdEmissionAnalysisModuleCase1.java | 2 +- .../emissions/TestColdEmissionAnalysisModuleCase4.java | 2 +- .../emissions/TestColdEmissionAnalysisModuleCase6.java | 2 +- .../emissions/TestColdEmissionsFallbackBehaviour.java | 2 +- .../contrib/emissions/TestHbefaColdEmissionFactorKey.java | 2 +- .../contrib/emissions/TestHbefaWarmEmissionFactorKey.java | 2 +- .../contrib/emissions/TestWarmEmissionAnalysisModule.java | 6 +++--- .../emissions/TestWarmEmissionAnalysisModuleCase1.java | 6 +++--- .../emissions/analysis/EmissionsByPollutantTest.java | 2 +- .../emissions/analysis/RawEmissionEventsReaderTest.java | 2 +- .../example/RunDetailedEmissionToolOfflineExampleIT.java | 6 +++--- .../RunDetailedEmissionToolOnlineExampleIT_vehTypeV1.java | 4 ++-- .../RunDetailedEmissionToolOnlineExampleIT_vehTypeV2.java | 4 ++-- .../matsim/contrib/emissions/utils/EmissionUtilsTest.java | 2 +- 22 files changed, 36 insertions(+), 35 deletions(-) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java index 7f06339b8f6..8b7004be8d7 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java @@ -165,9 +165,10 @@ private void createLookupTables() { if (shouldCreateAverageTables()) { this.avgHbefaColdTable = HbefaTables.loadAverageCold(emissionConfigGroup.getAverageColdEmissionFactorsFileURL(scenario.getConfig().getContext())); addPollutantsToMap(coldPollutants, avgHbefaColdTable.keySet()); - // yy The naming and signature of the above should presumably be changed: (1) addPollutantsToX implies signature (pollutants, - // X). But it is actually the other way round (even if it does not read that way. (2) "coldPollutants" is not a Map. Since - // this is a private method, maybe one could also have a method "memorizeColdPollutants" and then not have coldPollutants as + // yy The naming and signature of the above should presumably be changed: + // (1) addPollutantsToX implies signature (pollutants,X). But it is actually the other way round (even if it does not read that way.) + // (2) "coldPollutants" is not a Map. + // Since this is a private method, maybe one could also have a method "memorizeColdPollutants" and then not have coldPollutants as // field. kai, dec'22 this.avgHbefaWarmTable = HbefaTables.loadAverageWarm(emissionConfigGroup.getAverageWarmEmissionFactorsFileURL(scenario.getConfig().getContext())); diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java index f9de1d049b1..d09a01c2ed2 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java @@ -108,7 +108,7 @@ private String getHEBFAtype(String type, double speed) { /* * speed attributes are sometimes rounded beforehand. - * make sure the speed is a multiple of 10, as the HBEFA emission key factors are and otherwise we get problems later... + * make sure the speed is a multiple of 10, as the HBEFA emission key factors are, and otherwise we get problems later... */ freeVelocity_kmh = Math.round(freeVelocity_kmh/10.0) * 10; diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/PositionEmissionsModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/PositionEmissionsModule.java index 1f6304d0ade..df0a7c1144c 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/PositionEmissionsModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/PositionEmissionsModule.java @@ -111,7 +111,7 @@ Map calculateColdEmissions(Vehicle vehicle, double parkingDur } private Tuple getVehicleAttributes(Vehicle vehicle) { - // the following block fixes the vehicle types's emission information whenusing an old vehicle type format + // the following block fixes the vehicle type's emission information whenusing an old vehicle type format // the unit test I found uses an old format, so have it here. { String hbefaVehicleTypeDescription = EmissionUtils.getHbefaVehicleDescription(vehicle.getType(), emissionsConfigGroup); @@ -209,7 +209,7 @@ private void handlePositionEvent(PositionEvent event) { return; // only calculate emissions for cars if (!vehiclesInTraffic.containsKey(event.getVehicleId())) - return; // only collect positions if vehicle has entered traffic (if vehicle is wait2link its position is calculated but it hasn't entered traffic yet. + return; // only collect positions if vehicle has entered traffic (if vehicle is wait2link its position is calculated, but it hasn't entered traffic yet.) if (trajectories.containsKey(event.getVehicleId())) { computeCombinedEmissionEvent(event); diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/EmissionGridAnalyzer.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/EmissionGridAnalyzer.java index 65586e05d91..42003c91ffb 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/EmissionGridAnalyzer.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/EmissionGridAnalyzer.java @@ -57,7 +57,7 @@ /** * This class may be used to collect emission events of some events file and assign those emissions to a grid structure. - * Additionally those emissions are divided into time bins + * Additionally, those emissions are divided into time bins */ public class EmissionGridAnalyzer { @@ -316,7 +316,7 @@ public Builder withTimeBinSize(double size) { /** * Sets the used grid type. Default is Square * - * @param type The grid type. Currently either Square or Hexagonal + * @param type The grid type. Currently, either Square or Hexagonal * @return {@link org.matsim.contrib.emissions.analysis.EmissionGridAnalyzer.Builder} */ public Builder withGridType(GridType type) { diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java index fdff9835fa6..ea6d8ea92cc 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java @@ -59,8 +59,8 @@ public abstract class FastEmissionGridAnalyzer { * If only a certain area of the scenario is of interest for the analysis. The supplied network must be filtered beforehand. * The resulting raster's size depends on the bounding box of the supplied network. *

      - * Note: The algorithm is not accurate at the edges of the raster. The kernel is cut of a the edges meaning that emissions - * are underestimated at the edges of the raster. I didn't bother to implement this correctly. Otherwise the overall + * Note: The algorithm is not accurate at the edges of the raster. The kernel is cut of the edges meaning that emissions + * are underestimated at the edges of the raster. I didn't bother to implement this correctly. Otherwise, the overall * amount of emissions doesn't change. * * @param eventsFile The events file which contains the emission events diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReader.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReader.java index 283d144e0bb..811c3d49181 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReader.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReader.java @@ -57,7 +57,7 @@ class RawEmissionEventsReader extends MatsimXmlParser { RawEmissionEventsReader(HandleEmissionEvent handler) { super(ValidationType.NO_VALIDATION); this.handler = handler; - // events don't have dtd. Therefore validation is not possible + // events don't have dtd. Therefore, validation is not possible this.setValidating(false); } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunAverageEmissionToolOfflineExample.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunAverageEmissionToolOfflineExample.java index 5264f6d4b39..4361e146329 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunAverageEmissionToolOfflineExample.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunAverageEmissionToolOfflineExample.java @@ -49,7 +49,7 @@ public final class RunAverageEmissionToolOfflineExample{ public static final String emissionEventsFilename = "emission.events.offline.xml.gz"; - // (remove dependency of one test/execution path from other. kai/ihab, nov'18) + // (remove dependency of one test/execution path from others. kai/ihab, nov'18) private Config config; diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOfflineExample.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOfflineExample.java index 270b3bae7f2..cb999fd8d78 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOfflineExample.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOfflineExample.java @@ -48,7 +48,7 @@ public final class RunDetailedEmissionToolOfflineExample{ // private static final String configFile = "./scenarios/sampleScenario/testv2_Vehv1/config_detailed.xml"; // private static final String eventsFile = "./scenarios/sampleScenario/5.events.xml.gz"; - // (remove dependency of one test/execution path from other. kai/ihab, nov'18) + // (remove dependency of one test/execution path from others. kai/ihab, nov'18) // private static final String emissionEventOutputFileName = "5.emission.events.offline.xml.gz"; private Config config; diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase1.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase1.java index 3dc63ebde3a..4e06d69ec20 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase1.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase1.java @@ -135,7 +135,7 @@ private static ColdEmissionAnalysisModule setUp() { // This represents the previous behavior, which fallbacks to the average table, // if values are not found in the detailed table, kmt apr'20 - // This test seems to refer to an direct lookup in average table + // This test seems to refer to a direct lookup in average table ecg.setDetailedVsAverageLookupBehavior(EmissionsConfigGroup.DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageThenAverageTable); return new ColdEmissionAnalysisModule(avgHbefaColdTable, detailedHbefaColdTable, ecg, pollutants, emissionEventManager); } diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase4.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase4.java index 021503fa903..3f1b44dc470 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase4.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase4.java @@ -87,7 +87,7 @@ public class TestColdEmissionAnalysisModuleCase4 { // fifth case: cold emission factor not set // private static final String nullcase_emConcept = "nullCase"; - // this testcase does not exist any more. kai, jul'18 + // this testcase does not exist anymore. kai, jul'18 // emission factors for tables - no dublicates! private static final Double detailedPetrolFactor = 100.; diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase6.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase6.java index 8013a55267b..117c56e7da8 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase6.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase6.java @@ -147,7 +147,7 @@ private static void fillDetailedTable( Map Should be used, since HGV shpuld be supported and not fallback to average any more, kmt apr'20. + //(pre-existing comment: HEAVY_GOODS_VEHICLE;PC petrol;petrol; --> Should be used, since HGV shpuld be supported and not fallback to average anymore, kmt apr'20.) HbefaVehicleAttributes vehAtt = ColdEmissionAnalysisModule.createHbefaVehicleAttributes( petrol_technology, none_sizeClass, none_emConcept ); putIntoHbefaColdTable( detailedHbefaColdTable, vehAtt, new HbefaColdEmissionFactor(heavyGoodsFactor), HEAVY_GOODS_VEHICLE ); } diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionsFallbackBehaviour.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionsFallbackBehaviour.java index d4816287c55..f35050cc9e0 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionsFallbackBehaviour.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionsFallbackBehaviour.java @@ -65,7 +65,7 @@ public class TestColdEmissionsFallbackBehaviour { private static final Double parkingDuration = 1.; private static final int distance = 1; - //This are the expected values and extracted from "./scenarios/sampleScenario/sample_41_EFA_ColdStart_vehcat_2020average.csv" and + //These are the expected values and extracted from "./scenarios/sampleScenario/sample_41_EFA_ColdStart_vehcat_2020average.csv" and // "./scenarios/sampleScenario/sample_41_EFA_ColdStart_SubSegm_2020detailed.csv" //Both for AmbientConditionPattern 0-1h, 0-1km private final double emissionsFactorInGrammPerKilometer_Detailed = 3.337293625; //detailed table diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaColdEmissionFactorKey.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaColdEmissionFactorKey.java index d9475cdc817..810c11e8d2c 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaColdEmissionFactorKey.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaColdEmissionFactorKey.java @@ -104,7 +104,7 @@ final void testEqualsForCompleteKeys() { } } - // the following tests each compare a incomplete key to a complete key + // the following tests each compare an incomplete key to a complete key // wanted result: // completeData.equals(partialData) -> return false // uncompleteData.equals(completeData) -> throw nullpointer diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaWarmEmissionFactorKey.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaWarmEmissionFactorKey.java index 23ecb51b684..df5cf8fd2d7 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaWarmEmissionFactorKey.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestHbefaWarmEmissionFactorKey.java @@ -102,7 +102,7 @@ final void testEqualsForCompleteKeys(){ assertNotEquals(normal, different, message); } - // the following tests each compare a incomplete key to a complete key + // the following tests each compare an incomplete key to a complete key // wanted result: // completeData.equals(partialData) -> return false // uncompleteData.equals(completeData) -> throw nullpointer diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java index 813cb15e28b..ca302cd33ad 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java @@ -55,7 +55,7 @@ * check vehicle info and calculate warm emissions -testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent*, testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Exceptions * get free flow occurences - testCounters*() * get fraction occurences - testCounters*() - * get stop go occurences - testCounters*() + * get stop-go occurences - testCounters*() * get km counter - testCounters*() * get free flow km counter - testCounters*() * get top go km couter - testCounters*() @@ -102,7 +102,7 @@ public class TestWarmEmissionAnalysisModule { private final Double noeFreeSpeed = AVG_PASSENGER_CAR_SPEED_FF_KMH; - // case 6 - data in detailed table, stop go speed = free flow speed + // case 6 - data in detailed table, stop-go speed = free flow speed private final String sgffRoadCatgory = "URB_case7"; private final String sgffTechnology = "sg ff technology"; private final String sgffConcept = "sg ff concept"; @@ -265,7 +265,7 @@ void testCounters7(EmissionsConfigGroup.EmissionsComputationMethod emissionsComp setUp(emissionsComputationMethod); emissionsModule.reset(); - // case 10 - data in detailed table, stop go speed > free flow speed + // case 10 - data in detailed table, stop-go speed > free flow speed Id tableVehicleId = Id.create("vehicle 8", Vehicle.class); double tableLinkLength= 30.*1000; Id tableVehicleTypeId = Id.create( diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase1.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase1.java index 9fd1234d3bb..38330659906 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase1.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase1.java @@ -61,7 +61,7 @@ * check vehicle info and calculate warm emissions -testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent*, testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Exceptions * get free flow occurences - testCounters*() * get fraction occurences - testCounters*() - * get stop go occurences - testCounters*() + * get stop-go occurences - testCounters*() * get km counter - testCounters*() * get free flow km counter - testCounters*() * get top go km couter - testCounters*() @@ -149,7 +149,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent1(E /* * this test method creates a mock link and mock vehicle (petrol technology) with a complete vehicleTypId --> detailed values are used - * the counters for all possible combinations of avg, stop go and free flow speed are tested + * the counters for all possible combinations of avg, stop-go and free flow speed are tested * for the cases: > s&g speed, vehicleId = Id.create("vehicle 1", Vehicle.class); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionsByPollutantTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionsByPollutantTest.java index 208bd5e1328..114802a4de0 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionsByPollutantTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionsByPollutantTest.java @@ -17,7 +17,7 @@ public class EmissionsByPollutantTest { // The EmissionsByPollutant potentially adds up the same emissions coming from cold and warm. Thus, this cannot be combined into the enum approach // without some thinking. kai, jan'20 - // Quite possibly, should just combine them into an enum "pollutant"?! There is, anyways, the JM map of those emissions that are actually present in the + // Quite possibly, should just combine them into an enum "pollutant"?! There is, anyway, the JM map of those emissions that are actually present in the // input file. kai, jan'20 @Test diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReaderTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReaderTest.java index 4592d26ec17..5495783715a 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReaderTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReaderTest.java @@ -22,7 +22,7 @@ public class RawEmissionEventsReaderTest { @Test void handleNonEventNode() { - // read in an xml file which doesn't have events. It will parse the whole file but will not handle any of the + // read in a xml file which doesn't have events. It will parse the whole file but will not handle any of the // parsed nodes var networkUrl = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("equil"), "network.xml"); new RawEmissionEventsReader((time, linkId, vehicleId, pollutant, value) -> { diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOfflineExampleIT.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOfflineExampleIT.java index e2ed6c54bba..09d0e9bc5b0 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOfflineExampleIT.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOfflineExampleIT.java @@ -42,7 +42,7 @@ public class RunDetailedEmissionToolOfflineExampleIT { * * */ - // Expecting RuntimeException, because requested values are only in average file. Without fallback it has to fail! + // Expecting RuntimeException, because requested values are only in average file. Without fallback, it has to fail! // @Test(expected=RuntimeException.class) @Test final void testDetailed_vehTypeV1() { @@ -67,7 +67,7 @@ final void testDetailed_vehTypeV1() { Assertions.assertTrue( gotAnException ); } - // Expecting RuntimeException, because requested values are only in average file. Without fallback it has to fail! + // Expecting RuntimeException, because requested values are only in average file. Without fallback, it has to fail! // @Test(expected=RuntimeException.class) @Test final void testDetailed_vehTypeV2() { @@ -91,7 +91,7 @@ final void testDetailed_vehTypeV2() { Assertions.assertTrue( gotAnException ); } - // Expecting RuntimeException, because requested values are only in average file. Without fallback it has to fail! + // Expecting RuntimeException, because requested values are only in average file. Without fallback, it has to fail! // @Test(expected=RuntimeException.class) @Test final void testDetailed_vehTypeV2_HBEFA4() { diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOnlineExampleIT_vehTypeV1.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOnlineExampleIT_vehTypeV1.java index f52a038ddda..892803c548e 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOnlineExampleIT_vehTypeV1.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOnlineExampleIT_vehTypeV1.java @@ -46,8 +46,8 @@ public class RunDetailedEmissionToolOnlineExampleIT_vehTypeV1 { * This is by now (feb'20) the default. Setting it here for the tests explicitly * * */ -// @Test(expected=RuntimeException.class) // Expecting RuntimeException, because requested values are only in average file. Without fallback it has to fail! - @Disabled //Ignore this test, because the thrown exception during events handling does not always leads to an abort of the Simulation ->> Maybe a problem in @link{ParallelEventsManagerImpl.class}? +// @Test(expected=RuntimeException.class) // Expecting RuntimeException, because requested values are only in average file. Without fallback, it has to fail! + @Disabled //Ignore this test, because the thrown exception during events handling does not always lead to an abort of the Simulation ->> Maybe a problem in @link{ParallelEventsManagerImpl.class}? @Test final void testDetailed_vehTypeV1() { boolean gotAnException = false ; diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOnlineExampleIT_vehTypeV2.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOnlineExampleIT_vehTypeV2.java index 1a28fb39bf2..d6e33fc37f1 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOnlineExampleIT_vehTypeV2.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOnlineExampleIT_vehTypeV2.java @@ -40,8 +40,8 @@ public class RunDetailedEmissionToolOnlineExampleIT_vehTypeV2 { * Test method for {@link RunDetailedEmissionToolOnlineExample#main(String[])}. */ -// @Test(expected=RuntimeException.class) // Expecting RuntimeException, because requested values are only in average file. Without fallback it has to fail! - @Disabled //Ignore this test, because the thrown exception during events handling does not always leads to an abort of the Simulation ->> Maybe a problem in @link{ParallelEventsManagerImpl.class}? +// @Test(expected=RuntimeException.class) // Expecting RuntimeException, because requested values are only in average file. Without fallback, it has to fail! + @Disabled //Ignore this test, because the thrown exception during events handling does not always lead to an abort of the Simulation ->> Maybe a problem in @link{ParallelEventsManagerImpl.class}? @Test final void testDetailed_vehTypeV2() { boolean gotAnException = false ; diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java index b4404ed0bfb..121aabefc72 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java @@ -486,7 +486,7 @@ final void testSetNonCalculatedEmissionsForPopulation_missingMap() { message = "the calculated map should contain " + pop.getPersons().size() + " person(s) but contains " + finalMap.keySet().size() + "person(s)."; Assertions.assertEquals(pop.getPersons().keySet().size(), finalMap.keySet().size(), message); - //check: all values for the this person are zero and of type double + //check: all values for this person are zero and of type double for (Double pollutantValues : finalMap.get(idp3).values()) { Assertions.assertSame(pollutantValues.getClass(), Double.class); Assertions.assertEquals(0.0, pollutantValues, MatsimTestUtils.EPSILON); From d08aec145ba347da2737ef85c9f0ccf9bb455f22 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 13:48:50 +0200 Subject: [PATCH 155/213] fix some typos --- .../emissions/ColdEmissionAnalysisModule.java | 2 +- .../contrib/emissions/EmissionModule.java | 10 +++--- .../emissions/HbefaRoadTypeMapping.java | 4 +-- .../contrib/emissions/OsmHbefaMapping.java | 2 +- .../matsim/contrib/emissions/Pollutant.java | 6 ++-- .../emissions/PositionEmissionsModule.java | 10 +++--- .../emissions/VisumHbefaRoadTypeMapping.java | 2 +- .../emissions/VspHbefaRoadTypeMapping.java | 2 +- .../emissions/WarmEmissionAnalysisModule.java | 12 +++---- .../analysis/FastEmissionGridAnalyzer.java | 2 +- .../emissions/utils/EmissionsConfigGroup.java | 2 +- .../emissions/OsmHbefaMappingTest.java | 22 ++++++------- .../TestColdEmissionAnalysisModule.java | 2 +- .../TestColdEmissionAnalysisModuleCase1.java | 2 +- .../TestColdEmissionAnalysisModuleCase2.java | 2 +- .../TestColdEmissionAnalysisModuleCase3.java | 2 +- .../TestColdEmissionAnalysisModuleCase4.java | 2 +- .../TestColdEmissionAnalysisModuleCase6.java | 8 ++--- .../TestWarmEmissionAnalysisModule.java | 10 +++--- .../TestWarmEmissionAnalysisModuleCase1.java | 18 +++++------ .../TestWarmEmissionAnalysisModuleCase2.java | 32 +++++++++---------- .../TestWarmEmissionAnalysisModuleCase3.java | 24 +++++++------- .../TestWarmEmissionAnalysisModuleCase4.java | 20 ++++++------ .../TestWarmEmissionAnalysisModuleCase5.java | 12 +++---- ...issionAnalysisModuleTrafficSituations.java | 4 +-- .../TestWarmEmissionsFallbackBehaviour.java | 18 +++++------ .../VspHbefaRoadTypeMappingTest.java | 4 +-- .../analysis/EmissionGridAnalyzerTest.java | 4 +-- .../analysis/RawEmissionEventsReaderTest.java | 2 +- .../emissions/utils/EmissionUtilsTest.java | 6 ++-- 30 files changed, 124 insertions(+), 124 deletions(-) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionAnalysisModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionAnalysisModule.java index 6793d6dcaa1..bc201e3761c 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionAnalysisModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionAnalysisModule.java @@ -206,7 +206,7 @@ private Map calculateColdEmissions(Id vehicleId, dou * @param originVehCat * @param targetvehCat */ - //TODO Mabe make the behaviour settable by an enum? -> keep some kind of backwards capability or just return a 0.0 as it is for motorcycle? + //TODO Maybe make the behaviour settable by an enum? -> keep some kind of backwards capability or just return a 0.0 as it is for motorcycle? private void changeVehCategory(HbefaColdEmissionFactorKey key, HbefaVehicleCategory originVehCat, HbefaVehicleCategory targetvehCat) { // key.setVehicleCategory(targetvehCat); // if (vehInfoWarnHDVCnt < maxWarnCnt) { diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java index 8b7004be8d7..39e58239d09 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionModule.java @@ -113,11 +113,11 @@ public void writeEmissionInformation() { WarmEmissionAnalysisModule wam = warmEmissionHandler.getWarmEmissionAnalysisModule(); - logger.info("Emission calculation based on `Free flow only' occured for {} of {} warm emission events.", wam.getFreeFlowOccurences(), wam.getWarmEmissionEventCounter()); - logger.info("Emission calculation based on `Stop&Go only' occured for {} of {} warm emission events.", wam.getStopGoOccurences(), wam.getWarmEmissionEventCounter()); - logger.info("Emission calculation based on `Fractions' occured for {} of {} warm emission events.", wam.getFractionOccurences(), wam.getWarmEmissionEventCounter()); - logger.info("Free flow occured on {} km of total {} km, where emissions were calculated.", wam.getFreeFlowKmCounter(), wam.getKmCounter()); - logger.info("Stop&Go occured on {} km of total {} km, where emissions were calculated.", wam.getStopGoKmCounter(), wam.getKmCounter()); + logger.info("Emission calculation based on `Free flow only' occurred for {} of {} warm emission events.", wam.getFreeFlowOccurences(), wam.getWarmEmissionEventCounter()); + logger.info("Emission calculation based on `Stop&Go only' occurred for {} of {} warm emission events.", wam.getStopGoOccurences(), wam.getWarmEmissionEventCounter()); + logger.info("Emission calculation based on `Fractions' occurred for {} of {} warm emission events.", wam.getFractionOccurences(), wam.getWarmEmissionEventCounter()); + logger.info("Free flow occurred on {} km of total {} km, where emissions were calculated.", wam.getFreeFlowKmCounter(), wam.getKmCounter()); + logger.info("Stop&Go occurred on {} km of total {} km, where emissions were calculated.", wam.getStopGoKmCounter(), wam.getKmCounter()); logger.info("Emission calculation terminated. Emission events can be found in regular events file."); } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/HbefaRoadTypeMapping.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/HbefaRoadTypeMapping.java index bca754b259d..5074b708db5 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/HbefaRoadTypeMapping.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/HbefaRoadTypeMapping.java @@ -33,11 +33,11 @@ public void addHbefaMappings(Network network) { network.getLinks().values().parallelStream() .forEach(link -> { - String hbefaString = determineHebfaType(link); + String hbefaString = determineHbefaType(link); EmissionUtils.setHbefaRoadType(link, hbefaString); }); } - protected abstract String determineHebfaType(Link link); + protected abstract String determineHbefaType(Link link); } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java index d09a01c2ed2..ccce2492711 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/OsmHbefaMapping.java @@ -94,7 +94,7 @@ private void put(String s, Hbefa hbefa) { } @Override - public String determineHebfaType(Link link) { + public String determineHbefaType(Link link) { String roadType = NetworkUtils.getHighwayType(link); double allowedSpeed = NetworkUtils.getAllowedSpeed(link); diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/Pollutant.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/Pollutant.java index 7e0f815d747..2db4b9607e9 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/Pollutant.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/Pollutant.java @@ -33,11 +33,11 @@ public enum Pollutant{ NMHC, // non-methane hydro carbons NOx, // nitrogen oxide NO2, // provided as g/km, but based on %-values of NOx - PM, // = PM10 --> particulate matterof size below 10μm, i.e. equivalent to PM10. unit = g/km + PM, // = PM10 --> particulate matter of size below 10μm, i.e. equivalent to PM10. unit = g/km SO2, //sulphur dioxide FC_MJ, // fuel consumption in MJ/km - CO2_rep, // CO2(reported): = carbon dioxide “reported”, i.e. withoutthe biofuel share in the fuel -> input for CO2e calculation - CO2e, // CO2 equivalents (WTW basis), CO2 equivalents contain CO2, CH4 and N2O, i.e. the relevant greenhouse gases from thetransport sector,multiplied with their respective 100-year Global Warming Potentials and summed up. + CO2_rep, // CO2(reported): = carbon dioxide “reported”, i.e. without the biofuel share in the fuel -> input for CO2e calculation + CO2e, // CO2 equivalents (WTW basis), CO2 equivalents contain CO2, CH4 and N2O, i.e. the relevant greenhouse gases from the transport sector, multiplied with their respective 100-year Global Warming Potentials and summed up. PM2_5, // particle mass for particles < 2.5 µm. unit = g/km PM2_5_non_exhaust, // tire wear! PM_non_exhaust, // PM10 from non-exhaust sources(e.g. road, tyre wear) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/PositionEmissionsModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/PositionEmissionsModule.java index df0a7c1144c..d43d1f941e2 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/PositionEmissionsModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/PositionEmissionsModule.java @@ -111,7 +111,7 @@ Map calculateColdEmissions(Vehicle vehicle, double parkingDur } private Tuple getVehicleAttributes(Vehicle vehicle) { - // the following block fixes the vehicle type's emission information whenusing an old vehicle type format + // the following block fixes the vehicle type's emission information when using an old vehicle type format // the unit test I found uses an old format, so have it here. { String hbefaVehicleTypeDescription = EmissionUtils.getHbefaVehicleDescription(vehicle.getType(), emissionsConfigGroup); @@ -223,23 +223,23 @@ private void handlePositionEvent(PositionEvent event) { private Map computeColdEmissions(PositionEvent event, Vehicle vehicle, double distanceToLastPosition) { - // we remember the vehicles which are currently emmitting cold emissions if not stored here return nothing + // we remember the vehicles which are currently emitting cold emissions if not stored here return nothing if (!vehiclesEmittingColdEmissions.contains(vehicle.getId())) return emissionCalculator.getEmptyColdEmissions(); double distance = calculateTravelledDistance(event); // this model assumes vehicles to emmit cold emissions for the first 2000m of a trip remove a vehicle from - // the list of emmiting vehicles if the current trajectory is longer than 2000m + // the list of emitting vehicles if the current trajectory is longer than 2000m if (distance > 2000) { vehiclesEmittingColdEmissions.remove(vehicle.getId()); return emissionCalculator.getEmptyColdEmissions(); } - // HBEFA assumes a constantly decreasing ammount of cold emissions depending on the distance travelled + // HBEFA assumes a constantly decreasing amount of cold emissions depending on the distance travelled // the underlying emission module simplifies this into two steps. Between 0-1km and 1-2km. We use the same // classes here because we don't want to rewrite all the stuff. The cold emission module computes emissions - // for 1000m. We take these as is and muliply with distanceToLastPosition / 1000. This way we have the fraction + // for 1000m. We take these as is and multiply with distanceToLastPosition / 1000. This way we have the fraction // of cold emissions for the distance travelled during the last time step janek oct' 2021 int distanceClass = distance <= 1000 ? 1 : 2; diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/VisumHbefaRoadTypeMapping.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/VisumHbefaRoadTypeMapping.java index e822003f09f..1fce8b282cb 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/VisumHbefaRoadTypeMapping.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/VisumHbefaRoadTypeMapping.java @@ -46,7 +46,7 @@ private VisumHbefaRoadTypeMapping() { } @Override - public String determineHebfaType(Link link) { + public String determineHbefaType(Link link) { String roadType = NetworkUtils.getType(link); return mapping.get(roadType); } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/VspHbefaRoadTypeMapping.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/VspHbefaRoadTypeMapping.java index 12fb81ea572..8a990e6d5ab 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/VspHbefaRoadTypeMapping.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/VspHbefaRoadTypeMapping.java @@ -13,7 +13,7 @@ public VspHbefaRoadTypeMapping() { } @Override - protected String determineHebfaType(Link link) { + protected String determineHbefaType(Link link) { var freespeed = link.getFreespeed() <= 13.888889 ? link.getFreespeed() * 2 : link.getFreespeed(); diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java index 3b59b10d5a9..9da932e67a5 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java @@ -104,7 +104,7 @@ public WarmEmissionAnalysisModule( // The following tests if the detailed table is consistent, i.e. if there exist all combinations of entries. There used to be some test // cases where this was deliberately not the case, implying that this was assumed as plausible also for studies. This is now forbidding it. // If this causes too many problems, we could insert a switch (or attach it to the fallback behavior switch). kai, feb'20 - // Eventually vehicle category and vehicle attribute should be alligned in order to make the allCombinations setting useful + // Eventually vehicle category and vehicle attribute should be aligned in order to make the allCombinations setting useful // see discussion in https://github.com/matsim-org/matsim-libs/issues/1226 kturner, nov'20 Set roadCategories = new HashSet<>(); Set trafficSituations = EnumSet.noneOf(HbefaTrafficSituation.class); @@ -149,7 +149,7 @@ public WarmEmissionAnalysisModule( // conditions exist for a certain lookup. So we could still have some road categories, vehicle categories or vehicle attributes // where some detailed values exist and others don't. So the thing to check would be if for each existing // roadCategory x vehicleCategory x vehicleAttribute x pollutant - // there is a freeflow and a stopgo entry. Maybe something like this here: + // there is a freeflow and a stop-go entry. Maybe something like this here: Set freeflowSet = new HashSet<>(); Set stopgoSet = new HashSet<>(); for (HbefaWarmEmissionFactorKey key : detailedHbefaWarmTable.keySet()) { @@ -334,7 +334,7 @@ Map calculateWarmEmissions(double travelTime_sec, String road } // update counters: - // yy I don't now what this is good for; I would base downstream analysis rather on events. kai, jan'20 + // yy I don't know what this is good for; I would base downstream analysis rather on events. kai, jan'20 if (ecg.getEmissionsComputationMethod() == StopAndGoFraction) { incrementCountersFractional( linkLength_m / 1000, fractionStopGo ); } @@ -556,7 +556,7 @@ private HbefaTrafficSituation getTrafficSituation(HbefaWarmEmissionFactorKey efk HbefaRoadVehicleCategoryKey hbefaRoadVehicleCategoryKey = new HbefaRoadVehicleCategoryKey(efkey); Map trafficSpeeds = this.hbefaRoadTrafficSpeeds.get(hbefaRoadVehicleCategoryKey); - //TODO: Hier die Berechunung einfügen, die die trafficSpeedTabelle entsprechend aus den Werten erstellt? + //TODO: Hier die Berechnung einfügen, die die trafficSpeedTabelle entsprechend aus den Werten erstellt? //Frage Laufzeit: Einmal berechnen ha if (trafficSpeeds == null || !trafficSpeeds.containsKey(FREEFLOW)) { @@ -576,7 +576,7 @@ private HbefaTrafficSituation getTrafficSituation(HbefaWarmEmissionFactorKey efk trafficSituation = STOPANDGO; } } - /*FIXME The following lines should be added to account for the HBEFA 4.1's additiona traffic situation, + /*FIXME The following lines should be added to account for the HBEFA 4.1's additional traffic situation, but it currently causes a test failure (jwj, Nov'20) */ // if (trafficSpeeds.containsKey(STOPANDGO_HEAVY) && averageSpeed_kmh <= trafficSpeeds.get(STOPANDGO_HEAVY)) { // if (averageSpeed_kmh != trafficSpeeds.get(FREEFLOW)) { //handle case testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent6 @@ -626,7 +626,7 @@ private void incrementCountersAverage(HbefaTrafficSituation hbefaTrafficSituatio } } - //------ These (occurrences) seem do be used only for logging statements and tests. KMT/GR Jul'20 + //------ These (occurrences) seem to be used only for logging statements and tests. KMT/GR Jul'20 /*package-private*/ int getFreeFlowOccurences() { return freeFlowCounter; } diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java index ea6d8ea92cc..347fe2bb3eb 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/analysis/FastEmissionGridAnalyzer.java @@ -279,7 +279,7 @@ static Raster rasterizeNetwork(Network network, Map, Double> emissions, * Rasterizes links into squares. Uses Bresenham's line drawing algorithm, which is supposed to be fast * Maybe the result is too chunky, but it'll do as a first try * - * @param link Matsim network link + * @param link MATSim network link * @return number of cells the link is rastered to */ private static int rasterizeLink(Link link, double value, Raster raster) { diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionsConfigGroup.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionsConfigGroup.java index a5d366ae78f..cc958dc1a04 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionsConfigGroup.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/utils/EmissionsConfigGroup.java @@ -82,7 +82,7 @@ public enum HbefaTableConsistencyCheckingLevel { allCombinations, consistent, no private static final String EMISSION_FACTORS_COLD_FILE_DETAILED_CMT = "file with HBEFA detailed cold emission factors"; private static final String HBEFA_TABLE_CONSISTENCY_CHECKING_LEVEL_CMT = "Define on which level the entries in the provided hbefa tables are checked for consistency" + "\n\t\t\t" + HbefaTableConsistencyCheckingLevel.allCombinations.name() + " : check if entries for all combinations of HbefaTrafficSituation, HbefaVehicleCategory, HbefaVehicleAttributes, HbefaComponent. " + - "are available in the table. It only checks for paramters that are available in the table (e.g. if there is no HGV in the table, it can also pass. \n\t\t\t" + + "are available in the table. It only checks for parameters that are available in the table (e.g. if there is no HGV in the table, it can also pass. \n\t\t\t" + HbefaTableConsistencyCheckingLevel.consistent.name() + " : check if the entries for the two HbefaTrafficSituations 'StopAndGo' and 'FreeFlow' (nov 2020, may be subject to change) are consistently available in the table. \n\t\t\t" + //TODO HbefaTableConsistencyCheckingLevel.none.name() + " : There is no consistency check. This option is NOT recommended and only for backward capability to inputs from before spring 2020 . \n\t\t\t" + "Default is " + HbefaTableConsistencyCheckingLevel.allCombinations.name(); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/OsmHbefaMappingTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/OsmHbefaMappingTest.java index 195fc6e6fcb..10aff1cbe2a 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/OsmHbefaMappingTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/OsmHbefaMappingTest.java @@ -16,7 +16,7 @@ void testRegularMapping() { var mapping = OsmHbefaMapping.build(); var link = getTestLink("primary", 70 / 3.6); - var hbefaType = mapping.determineHebfaType(link); + var hbefaType = mapping.determineHbefaType(link); assertEquals("URB/Trunk-City/70", hbefaType); } @@ -27,7 +27,7 @@ void testMergedLinkTypeMapping() { var mapping = OsmHbefaMapping.build(); var link = getTestLink("primary|railway.tram", 70 / 3.6); - var hbefaType = mapping.determineHebfaType(link); + var hbefaType = mapping.determineHbefaType(link); assertEquals("URB/Trunk-City/70", hbefaType); } @@ -39,7 +39,7 @@ void testUnknownType() { var mapping = OsmHbefaMapping.build(); var link = getTestLink("unknown-tag", 100 / 3.6); - mapping.determineHebfaType(link); + mapping.determineHbefaType(link); fail("Expected Runtime Exception."); }); @@ -51,7 +51,7 @@ void testFastMotorway() { var mapping = OsmHbefaMapping.build(); var link = getTestLink("motorway", 100 / 3.6); - var hbefaType = mapping.determineHebfaType(link); + var hbefaType = mapping.determineHbefaType(link); assertEquals("URB/MW-Nat./100", hbefaType); } @@ -62,11 +62,11 @@ void testMotorwayWithNoExactSpeedTag() { var mapping = OsmHbefaMapping.build(); var link = getTestLink("motorway", 100.11 / 3.6); - var hbefaType = mapping.determineHebfaType(link); + var hbefaType = mapping.determineHbefaType(link); assertEquals("URB/MW-Nat./100", hbefaType); link = getTestLink("motorway", 86.11 / 3.6); - hbefaType = mapping.determineHebfaType(link); + hbefaType = mapping.determineHbefaType(link); assertEquals("URB/MW-Nat./90", hbefaType); } @@ -77,7 +77,7 @@ void testFastMotorwayLink() { var mapping = OsmHbefaMapping.build(); var link = getTestLink("motorway_link", 100 / 3.6); - var hbefaType = mapping.determineHebfaType(link); + var hbefaType = mapping.determineHbefaType(link); assertEquals("URB/MW-Nat./100", hbefaType); } @@ -87,7 +87,7 @@ void testLivingStreet() { var mapping = OsmHbefaMapping.build(); var link = getTestLink("living_street", 50 / 3.6); - var hbefaType = mapping.determineHebfaType(link); + var hbefaType = mapping.determineHbefaType(link); assertEquals("URB/Access/50", hbefaType); } @@ -98,7 +98,7 @@ void testUnclassified() { var mapping = OsmHbefaMapping.build(); var link = getTestLink("unclassified", 50 / 3.6); - var hbefaType = mapping.determineHebfaType(link); + var hbefaType = mapping.determineHbefaType(link); assertEquals("URB/Access/50", hbefaType); } @@ -109,7 +109,7 @@ void testNoHighwayType() { var mapping = OsmHbefaMapping.build(); var link = getTestLink(" ", 60 / 3.6); - var hbefaType = mapping.determineHebfaType(link); + var hbefaType = mapping.determineHbefaType(link); assertEquals("URB/Local/60", hbefaType); } @@ -121,7 +121,7 @@ void testNoAllowedSpeedTag() { var link = getTestLink("residential", 40 / 3.6); link.getAttributes().removeAttribute(NetworkUtils.ALLOWED_SPEED); - var hbefaType = mapping.determineHebfaType(link); + var hbefaType = mapping.determineHbefaType(link); assertEquals("URB/Access/40", hbefaType); } diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModule.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModule.java index 2ed3110e4a9..aa01f57e02d 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModule.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModule.java @@ -87,7 +87,7 @@ public class TestColdEmissionAnalysisModule { private static final String geq2l_sizeClass = ">=2L"; private static final String PC_D_Euro_3_emConcept = "PC-D-Euro-3"; - // emission factors for tables - no dublicates! + // emission factors for tables - no duplicates! private static final Double detailedPetrolFactor = 100.; private static final Double detailedDieselFactor = 10.; private static final Double averageAverageFactor = .1; diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase1.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase1.java index 4e06d69ec20..57aae0aee49 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase1.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase1.java @@ -92,7 +92,7 @@ public class TestColdEmissionAnalysisModuleCase1 { private static final String geq2l_sizeClass = ">=2L"; private static final String PC_D_Euro_3_emConcept = "PC-D-Euro-3"; - // emission factors for tables - no dublicates! + // emission factors for tables - no duplicates! private static final Double detailedPetrolFactor = 100.; private static final Double detailedDieselFactor = 10.; private static final Double averageAverageFactor = .1; diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase2.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase2.java index c5ce8831a6a..eba88366726 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase2.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase2.java @@ -84,7 +84,7 @@ public class TestColdEmissionAnalysisModuleCase2 { private static final String geq2l_sizeClass = ">=2L"; private static final String PC_D_Euro_3_emConcept = "PC-D-Euro-3"; - // emission factors for tables - no dublicates! + // emission factors for tables - no duplicates! private static final Double detailedPetrolFactor = 100.; private static final Double detailedDieselFactor = 10.; private static final Double averageAverageFactor = .1; diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase3.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase3.java index 52bee68cde3..6dd637c3be9 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase3.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase3.java @@ -85,7 +85,7 @@ public class TestColdEmissionAnalysisModuleCase3 { private static final String geq2l_sizeClass = ">=2L"; private static final String PC_D_Euro_3_emConcept = "PC-D-Euro-3"; - // emission factors for tables - no dublicates! + // emission factors for tables - no duplicates! private static final Double detailedPetrolFactor = 100.; private static final Double detailedDieselFactor = 10.; private static final Double averageAverageFactor = .1; diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase4.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase4.java index 3f1b44dc470..636b77c343d 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase4.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase4.java @@ -89,7 +89,7 @@ public class TestColdEmissionAnalysisModuleCase4 { // private static final String nullcase_emConcept = "nullCase"; // this testcase does not exist anymore. kai, jul'18 - // emission factors for tables - no dublicates! + // emission factors for tables - no duplicates! private static final Double detailedPetrolFactor = 100.; private static final Double detailedDieselFactor = 10.; private static final Double averageAverageFactor = .1; diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase6.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase6.java index 117c56e7da8..9f62e65442f 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase6.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestColdEmissionAnalysisModuleCase6.java @@ -83,7 +83,7 @@ public class TestColdEmissionAnalysisModuleCase6 { private static final String PC_D_Euro_3_emConcept = "PC-D-Euro-3"; - // emission factors for tables - no dublicates! + // emission factors for tables - no duplicates! private static final Double detailedPetrolFactor = 100.; private static final Double detailedDieselFactor = 10.; private static final Double averageAverageFactor = .1; @@ -105,8 +105,8 @@ void calculateColdEmissionsAndThrowEventTest_completeData() { // sixth case: heavy goods vehicle // -> throw warning -> use detailed or average table for passenger cars - String heavygoodsvehicle = "HEAVY_GOODS_VEHICLE"; - Collections.addAll( testCase6, heavygoodsvehicle, petrol_technology, none_sizeClass, none_emConcept, heavyGoodsFactor); + String heavyGoodsVehicle = "HEAVY_GOODS_VEHICLE"; + Collections.addAll( testCase6, heavyGoodsVehicle, petrol_technology, none_sizeClass, none_emConcept, heavyGoodsFactor); logger.info("Running testcase: {} {}", testCase6, testCase6); Id linkId = Id.create( "linkId" + testCase6, Link.class ); @@ -147,7 +147,7 @@ private static void fillDetailedTable( Map Should be used, since HGV shpuld be supported and not fallback to average anymore, kmt apr'20.) + //(pre-existing comment: HEAVY_GOODS_VEHICLE;PC petrol;petrol; --> Should be used, since HGV should be supported and not fallback to average anymore, kmt apr'20.) HbefaVehicleAttributes vehAtt = ColdEmissionAnalysisModule.createHbefaVehicleAttributes( petrol_technology, none_sizeClass, none_emConcept ); putIntoHbefaColdTable( detailedHbefaColdTable, vehAtt, new HbefaColdEmissionFactor(heavyGoodsFactor), HEAVY_GOODS_VEHICLE ); } diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java index ca302cd33ad..05ac81e5bce 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModule.java @@ -103,7 +103,7 @@ public class TestWarmEmissionAnalysisModule { private final Double noeFreeSpeed = AVG_PASSENGER_CAR_SPEED_FF_KMH; // case 6 - data in detailed table, stop-go speed = free flow speed - private final String sgffRoadCatgory = "URB_case7"; + private final String sgffRoadCategory = "URB_case7"; private final String sgffTechnology = "sg ff technology"; private final String sgffConcept = "sg ff concept"; private final String sgffSizeClass = "sg ff size class"; @@ -124,7 +124,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent6(E Id sgffVehicleId = Id.create("vehicle sg equals ff", Vehicle.class); double sgffLinklength = 4000.; Link sgflink = createMockLink("link sgf", sgffLinklength, AVG_PASSENGER_CAR_SPEED_FF_KMH / 3.6); - EmissionUtils.setHbefaRoadType(sgflink, sgffRoadCatgory); + EmissionUtils.setHbefaRoadType(sgflink, sgffRoadCategory); Id sgffVehicleTypeId = Id.create( PASSENGER_CAR + ";" + sgffTechnology + ";"+ sgffSizeClass + ";"+sgffConcept, VehicleType.class ); VehiclesFactory vehFac = VehicleUtils.getFactory(); @@ -344,7 +344,7 @@ private void fillDetailedTable( Map avgHbefaWarmTable ) { // entries for first case "petrol" should not be used since there are entries in the detailed table - // there should only average vehicle attributes in the avgHebfWarmTable jm oct'18 + // there should only average vehicle attributes in the avgHbefaWarmTable jm oct'18 HbefaVehicleAttributes vehAtt = new HbefaVehicleAttributes(); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase1.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase1.java index 38330659906..2a0382250ae 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase1.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase1.java @@ -59,12 +59,12 @@ * weamParameter - testWarmEmissionAnalysisParameter * throw warm EmissionEvent - testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent*, testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Exceptions * check vehicle info and calculate warm emissions -testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent*, testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Exceptions - * get free flow occurences - testCounters*() - * get fraction occurences - testCounters*() - * get stop-go occurences - testCounters*() + * get free flow occurrences - testCounters*() + * get fraction occurrences - testCounters*() + * get stop-go occurrences - testCounters*() * get km counter - testCounters*() * get free flow km counter - testCounters*() - * get top go km couter - testCounters*() + * get top go km counter - testCounters*() * get warm emission event counter - testCounters*() * * private methods and corresponding tests: @@ -241,9 +241,9 @@ void testCounters1(EmissionsConfigGroup.EmissionsComputationMethod emissionsComp /* - * this test method creates a incoff mock link and incoff mock vehicle (petrol technology) with a complete vehicleTypId --> detailed values are used - * for the computationMethod "Stop and Go" and "averageSpeed" the free flow occurences are tested - * the counters (StopGoOccurences, KmCounter, WarmEmissionEventCounter) are tested + * this test method creates an incoff mock link and incoff mock vehicle (petrol technology) with a complete vehicleTypId --> detailed values are used + * for the computationMethod "Stop and Go" and "averageSpeed" the free flow occurrences are tested + * the counters (StopGoOccurrences, KmCounter, WarmEmissionEventCounter) are tested * for the case average speed equals wrong free flow speed the counters are tested */ @@ -305,7 +305,7 @@ void testCounters1fractional(EmissionsConfigGroup.EmissionsComputationMethod emi // yyyyyy !!!!!! /* - * using the same case as above - case 1 and check the counters for all possible combinations of avg, stop go and free flow speed + * using the same case as above - case 1 and check the counters for all possible combinations of avg, stop-go and free flow speed */ Id vehicleId = Id.create("vehicle 1", Vehicle.class); @@ -376,7 +376,7 @@ void testCounters1fractional(EmissionsConfigGroup.EmissionsComputationMethod emi emissionsModule.reset(); emissionsModule.getEcg().setEmissionsComputationMethod(AverageSpeed ); - //@KMT it seems to me that copying the counters from above and chaning the expected values?? + //@KMT it seems to me that copying the counters from above and changing the expected values?? // yyyyyy !!!!!! } diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase2.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase2.java index 101c410289d..bb7beab4140 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase2.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase2.java @@ -44,7 +44,7 @@ * / /* - * Case 2 - free flow entry in both tables, stop go entry in average table -> use average + * Case 2 - free flow entry in both tables, stop-go entry in average table -> use average * see (*) below. kai, jan'20 */ @@ -56,12 +56,12 @@ * weamParameter - testWarmEmissionAnalysisParameter * throw warm EmissionEvent - testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent*, testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Exceptions * check vehicle info and calculate warm emissions -testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent*, testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Exceptions - * get free flow occurences - testCounters*() - * get fraction occurences - testCounters*() - * get stop go occurences - testCounters*() + * get free flow occurrences - testCounters*() + * get fraction occurrences - testCounters*() + * get stop-go occurrences - testCounters*() * get km counter - testCounters*() * get free flow km counter - testCounters*() - * get top go km couter - testCounters*() + * get top go km counter - testCounters*() * get warm emission event counter - testCounters*() * * private methods and corresponding tests: @@ -95,7 +95,7 @@ public class TestWarmEmissionAnalysisModuleCase2{ // vehicle information for regular test cases - // case 2 - free flow entry in both tables, stop go entry in average table -> use average (now fail) + // case 2 - free flow entry in both tables, stop-go entry in average table -> use average (now fail) private static final String PC_TECHNOLOGY = "PC petrol <1,4L lookUpBehaviour: tryDetailedThenTechnologyAverageThenAverageTable - * for two speed cases: avg speed = free flow speed & avg speed = stop go speed the NMHC warm emissions and emissions sum are computed using the two emissionsComputationMethods StopAndGoFraction & AverageSpeed + * for two speed cases: avg speed = free flow speed & avg speed = stop-go speed the NMHC warm emissions and emissions sum are computed using the two emissionsComputationMethods StopAndGoFraction & AverageSpeed */ @ParameterizedTest @@ -115,7 +115,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent2(E WarmEmissionAnalysisModule emissionsModule = setUp(emissionsComputationMethod); - // case 2 - free flow entry in both tables, stop go entry in average table -> use average + // case 2 - free flow entry in both tables, stop-go entry in average table -> use average // see (*) below. kai, jan'20 // create a link: @@ -128,7 +128,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent2(E VehiclesFactory vehFac = VehicleUtils.getFactory(); Vehicle pcVehicle = vehFac.createVehicle(pcVehicleId, vehFac.createVehicleType(pcVehicleTypeId)); - // sub case avg speed = free flow speed + // subcase avg speed = free flow speed { // compute warm emissions with travel time coming from free flow: warmEmissions = emissionsModule.checkVehicleInfoAndCalculateWarmEmissions( pcVehicle, pclink, pclinkLength / PC_FREE_VELOCITY_KMH * 3.6 ); @@ -137,8 +137,8 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent2(E // - DETAILED FreeFlow value is available in the table (1.0E-4 g/km); StopAndGo value is NOT available in the table // - AVERAGE FreeFlow value is available in the table (1.0 g/km) ; StopAndGo value is NOT available in the table ( 10.0 g/km) // --> It seems like it was intended (or only implemented) in a way, that if one of the detailed values is missing (FreeFlow or StopGo) there is a fallback to average. So the result of this would be 1.0 g/km * 0.1 km = 0.1 g/km - // --> Now, after implementing the new fallback behaviour, it is looking up both values (FreeFlow or StopGo) ways independently from each other. Therefore the result comes from the detailed table (1.0E-4 g/km) * * 0.1 km = 1.0E-5 g/km - // -----> We need a decision here, if we want allow that inconsistent(?) lookup of FreeFlow and Detailed values with different grade of detail or not. + // --> Now, after implementing the new fallback behaviour, it is looking up both values (FreeFlow or StopGo) ways independently of each other. Therefore, the result comes from the detailed table (1.0E-4 g/km) * * 0.1 km = 1.0E-5 g/km + // -----> We need a decision here, if we want to allow that inconsistent(?) lookup of FreeFlow and Detailed values with different grade of detail or not. // After discussion with Kai N. we decided to let it as it is for the time being. I will add a log.info in the consistency checker. KMT Jul'20 //results should be equal here, because in both cases only the freeflow value is relevant (100% freeflow, 0% stop&go). @@ -152,7 +152,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent2(E warmEmissions.clear(); } - // sub case avg speed = stop go speed + // subcase avg speed = stop-go speed { warmEmissions = emissionsModule.checkVehicleInfoAndCalculateWarmEmissions( pcVehicle, pclink, pclinkLength / PCSG_VELOCITY_KMH * 3.6 ); Assertions.assertEquals( AVG_PC_FACTOR_SG * pclinkLength / 1000., warmEmissions.get( NMHC ), MatsimTestUtils.EPSILON ); @@ -166,7 +166,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent2(E /* * this test method creates a vehicle and mock link - * for three cases: "current speed equals free flow speed" & "current speed equals stop go speed" & "current speed equals stop go speed" the counters are tested + * for three cases: "current speed equals free flow speed" & "current speed equals stop-go speed" & "current speed equals stop-go speed" the counters are tested * average values are used */ @ParameterizedTest @@ -175,7 +175,7 @@ void testCounters3(EmissionsConfigGroup.EmissionsComputationMethod emissionsComp WarmEmissionAnalysisModule emissionsModule = setUp(emissionsComputationMethod); - // case 2 - free flow entry in both tables, stop go entry in average table -> use average + // case 2 - free flow entry in both tables, stop-go entry in average table -> use average Id pcVehicleId = Id.create("vehicle 2", Vehicle.class); double pclinkLength= 20.*1000; Id pcVehicleTypeId = Id.create( PASSENGER_CAR + ";"+ PC_TECHNOLOGY + ";"+ PC_SIZE_CLASS +";"+ PC_CONCEPT, VehicleType.class ); @@ -183,7 +183,7 @@ void testCounters3(EmissionsConfigGroup.EmissionsComputationMethod emissionsComp Vehicle pcVehicle = vehFac.createVehicle(pcVehicleId, vehFac.createVehicleType(pcVehicleTypeId)); Link pclink = TestWarmEmissionAnalysisModule.createMockLink("link 2", pclinkLength, PC_FREE_VELOCITY_KMH / 3.6 ); - // sub case: current speed equals free flow speed + // subcase: current speed equals free flow speed warmEmissions = emissionsModule.checkVehicleInfoAndCalculateWarmEmissions(pcVehicle,pclink, pclinkLength/ PC_FREE_VELOCITY_KMH *3.6 ); Assertions.assertEquals(0, emissionsModule.getFractionOccurences() ); Assertions.assertEquals(pclinkLength/1000, emissionsModule.getFreeFlowKmCounter(), MatsimTestUtils.EPSILON ); @@ -194,7 +194,7 @@ void testCounters3(EmissionsConfigGroup.EmissionsComputationMethod emissionsComp Assertions.assertEquals(1, emissionsModule.getWarmEmissionEventCounter() ); emissionsModule.reset(); - // sub case: current speed equals stop go speed + // subcase: current speed equals stop-go speed warmEmissions = emissionsModule.checkVehicleInfoAndCalculateWarmEmissions(pcVehicle, pclink, pclinkLength/ PCSG_VELOCITY_KMH *3.6 ); Assertions.assertEquals(0, emissionsModule.getFractionOccurences() ); Assertions.assertEquals(0., emissionsModule.getFreeFlowKmCounter(), MatsimTestUtils.EPSILON ); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase3.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase3.java index 4a8f8f5827b..c0741ed1ced 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase3.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase3.java @@ -54,9 +54,9 @@ * weamParameter - testWarmEmissionAnalysisParameter * throw warm EmissionEvent - testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent*, testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Exceptions * check vehicle info and calculate warm emissions -testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent*, testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Exceptions - * get free flow occurences - testCounters*() - * get fraction occurences - testCounters*() - * get stop go occurences - testCounters*() + * get free flow occurrences - testCounters*() + * get fraction occurrences - testCounters*() + * get stop-go occurrences - testCounters*() * get km counter - testCounters*() * get free flow km counter - testCounters*() * get top go km counter - testCounters*() @@ -91,14 +91,14 @@ public class TestWarmEmissionAnalysisModuleCase3{ private static final Double AVG_PC_FACTOR_FF = 1.; private static final Double AVG_PC_FACTOR_SG = 10.; - // case 3 - stop go entry in both tables, free flow entry in average table -> use average (now fail) + // case 3 - stop-go entry in both tables, free flow entry in average table -> use average (now fail) private final String dieselTechnology = "PC diesel"; private final String dieselSizeClass = "diesel"; private final String dieselConcept = ">=2L"; /* * this test method creates a diesel vehicle and mock link - * for two cases: "avg speed = free flow speed" & "avg speed = stop go speed" the average values are used to calculate the PM warm emissions + * for two cases: "avg speed = free flow speed" & "avg speed = stop-go speed" the average values are used to calculate the PM warm emissions */ @ParameterizedTest @EnumSource(EmissionsConfigGroup.EmissionsComputationMethod.class) @@ -107,7 +107,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent3(E //-- set up tables, event handler, parameters, module WarmEmissionAnalysisModule emissionsModule = setUp(emissionsComputationMethod); - // case 3 - stop go entry in both tables, free flow entry in average table -> use average + // case 3 - stop-go entry in both tables, free flow entry in average table -> use average Id dieselVehicleId = Id.create("veh 3", Vehicle.class); double dieselLinkLength= 20.; Link diesellink = TestWarmEmissionAnalysisModule.createMockLink("link 3", dieselLinkLength, TestWarmEmissionAnalysisModule.AVG_PASSENGER_CAR_SPEED_FF_KMH / 3.6 ); @@ -117,7 +117,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent3(E VehiclesFactory vehFac = VehicleUtils.getFactory(); Vehicle dieselVehicle = vehFac.createVehicle(dieselVehicleId, vehFac.createVehicleType(dieselVehicleTypeId)); - // sub case avg speed = free flow speed + // subcase avg speed = free flow speed warmEmissions = emissionsModule.checkVehicleInfoAndCalculateWarmEmissions(dieselVehicle, diesellink, dieselLinkLength/ TestWarmEmissionAnalysisModule.AVG_PASSENGER_CAR_SPEED_FF_KMH *3.6 ); Assertions.assertEquals( AVG_PC_FACTOR_FF *dieselLinkLength/1000., warmEmissions.get(PM ), MatsimTestUtils.EPSILON ); emissionEventManager.reset(); @@ -126,7 +126,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent3(E emissionEventManager.reset(); warmEmissions.clear(); - // sub case avg speed = stop go speed + // subcase avg speed = stop-go speed warmEmissions = emissionsModule.checkVehicleInfoAndCalculateWarmEmissions(dieselVehicle, diesellink, dieselLinkLength/ TestWarmEmissionAnalysisModule.AVG_PASSENGER_CAR_SPEED_SG_KMH *3.6 ); Assertions.assertEquals( AVG_PC_FACTOR_SG *dieselLinkLength/1000., warmEmissions.get(PM ), MatsimTestUtils.EPSILON ); emissionEventManager.reset(); @@ -138,7 +138,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent3(E /* * this test method creates a diesel vehicle and mock link - * for two cases: "current speed equals free flow speed" & "current speed equals stop go speed" the counters are tested + * for two cases: "current speed equals free flow speed" & "current speed equals stop-go speed" the counters are tested */ @ParameterizedTest @EnumSource(EmissionsConfigGroup.EmissionsComputationMethod.class) @@ -146,7 +146,7 @@ void testCounters4(EmissionsConfigGroup.EmissionsComputationMethod emissionsComp WarmEmissionAnalysisModule emissionsModule = setUp(emissionsComputationMethod); - // case 3 - stop go entry in both tables, free flow entry in average table -> use average + // case 3 - stop-go entry in both tables, free flow entry in average table -> use average Id dieselVehicleId = Id.create("vehicle 3", Vehicle.class); double dieselLinkLength= 200.*1000; Id dieselVehicleTypeId = Id.create( @@ -155,7 +155,7 @@ void testCounters4(EmissionsConfigGroup.EmissionsComputationMethod emissionsComp Vehicle dieselVehicle = vehFac.createVehicle(dieselVehicleId, vehFac.createVehicleType(dieselVehicleTypeId)); Link diesellink = TestWarmEmissionAnalysisModule.createMockLink("link 3", dieselLinkLength, TestWarmEmissionAnalysisModule.AVG_PASSENGER_CAR_SPEED_FF_KMH / 3.6 ); - // sub case: current speed equals free flow speed + // subcase: current speed equals free flow speed warmEmissions = emissionsModule.checkVehicleInfoAndCalculateWarmEmissions(dieselVehicle, diesellink, dieselLinkLength/ TestWarmEmissionAnalysisModule.AVG_PASSENGER_CAR_SPEED_FF_KMH *3.6 ); Assertions.assertEquals(0, emissionsModule.getFractionOccurences() ); Assertions.assertEquals(dieselLinkLength/1000., emissionsModule.getFreeFlowKmCounter(), MatsimTestUtils.EPSILON ); @@ -166,7 +166,7 @@ void testCounters4(EmissionsConfigGroup.EmissionsComputationMethod emissionsComp Assertions.assertEquals(1, emissionsModule.getWarmEmissionEventCounter() ); emissionsModule.reset(); - // sub case: current speed equals stop go speed + // subcase: current speed equals stop-go speed warmEmissions = emissionsModule.checkVehicleInfoAndCalculateWarmEmissions(dieselVehicle, diesellink, dieselLinkLength/ TestWarmEmissionAnalysisModule.AVG_PASSENGER_CAR_SPEED_SG_KMH *3.6 ); Assertions.assertEquals(0, emissionsModule.getFractionOccurences() ); Assertions.assertEquals(0., emissionsModule.getFreeFlowKmCounter(), MatsimTestUtils.EPSILON ); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase4.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase4.java index f7a25a4d003..7f085baf2fb 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase4.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase4.java @@ -56,12 +56,12 @@ * weamParameter - testWarmEmissionAnalysisParameter * throw warm EmissionEvent - testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent*, testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Exceptions * check vehicle info and calculate warm emissions -testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent*, testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Exceptions - * get free flow occurences - testCounters*() - * get fraction occurences - testCounters*() - * get stop go occurences - testCounters*() + * get free flow occurrences - testCounters*() + * get fraction occurrences - testCounters*() + * get stop-go occurrences - testCounters*() * get km counter - testCounters*() * get free flow km counter - testCounters*() - * get top go km couter - testCounters*() + * get top go km counter - testCounters*() * get warm emission event counter - testCounters*() * * private methods and corresponding tests: @@ -104,7 +104,7 @@ public class TestWarmEmissionAnalysisModuleCase4{ /* * this test method creates a vehicle (lpg properties) and a mock link - * for two cases: "avg speed = stop go speed" & "avg speed = free flow speed" the PM warm Emissions and the Emissions "sum" are tested + * for two cases: "avg speed = stop-go speed" & "avg speed = free flow speed" the PM warm Emissions and the Emissions "sum" are tested * average values are used */ @ParameterizedTest @@ -122,7 +122,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent4(E VehiclesFactory vehFac = VehicleUtils.getFactory(); Vehicle lpgVehicle = vehFac.createVehicle(lpgVehicleId, vehFac.createVehicleType(lpgVehicleTypeId)); - // sub case avg speed = stop go speed + // subcase avg speed = stop-go speed warmEmissions = emissionsModule.checkVehicleInfoAndCalculateWarmEmissions(lpgVehicle, lpglink, lpgLinkLength/ SPEED_SG *3.6 ); Assertions.assertEquals( AVG_PC_FACTOR_SG *lpgLinkLength/1000., warmEmissions.get(PM), MatsimTestUtils.EPSILON ); emissionEventManager.reset(); @@ -131,7 +131,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent4(E emissionEventManager.reset(); warmEmissions.clear(); - // sub case avg speed = free flow speed + // subcase avg speed = free flow speed warmEmissions = emissionsModule.checkVehicleInfoAndCalculateWarmEmissions(lpgVehicle, lpglink, lpgLinkLength/ SPEED_FF *3.6 ); Assertions.assertEquals( AVG_PC_FACTOR_FF *lpgLinkLength/1000., warmEmissions.get(PM ), MatsimTestUtils.EPSILON ); emissionEventManager.reset(); @@ -143,7 +143,7 @@ void testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent4(E /* * this test method creates a vehicle and mock link - * for two cases: "avg speed = stop go speed" & "avg speed = free flow speed" the PM warm Emissions are tested + * for two cases: "avg speed = stop-go speed" & "avg speed = free flow speed" the PM warm Emissions are tested * average values are used */ @ParameterizedTest @@ -160,7 +160,7 @@ void testCounters2(EmissionsConfigGroup.EmissionsComputationMethod emissionsComp Link lpgLink = TestWarmEmissionAnalysisModule.createMockLink("link zero", lpgLinkLength, SPEED_FF / 3.6 ); - // sub case: current speed equals free flow speed + // subcase: current speed equals free flow speed warmEmissions = emissionsModule.checkVehicleInfoAndCalculateWarmEmissions(vehicle, lpgLink, lpgLinkLength/ SPEED_FF *3.6 ); Assertions.assertEquals(0, emissionsModule.getFractionOccurences() ); Assertions.assertEquals(lpgLinkLength/1000, emissionsModule.getFreeFlowKmCounter(), MatsimTestUtils.EPSILON ); @@ -171,7 +171,7 @@ void testCounters2(EmissionsConfigGroup.EmissionsComputationMethod emissionsComp Assertions.assertEquals(1, emissionsModule.getWarmEmissionEventCounter() ); emissionsModule.reset(); - // sub case: current speed equals free flow speed + // subcase: current speed equals free flow speed warmEmissions = emissionsModule.checkVehicleInfoAndCalculateWarmEmissions(vehicle, lpgLink, lpgLinkLength/ SPEED_SG *3.6 ); Assertions.assertEquals(0, emissionsModule.getFractionOccurences() ); Assertions.assertEquals(0., emissionsModule.getFreeFlowKmCounter(), MatsimTestUtils.EPSILON ); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase5.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase5.java index bbc1ce82970..a792d37d620 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase5.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleCase5.java @@ -43,7 +43,7 @@ */ /* - * Case 5 - data in detailed table, stop go speed zero + * Case 5 - data in detailed table, stop-go speed zero */ @@ -57,12 +57,12 @@ * testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Exceptions * check vehicle info and calculate warm emissions -testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent*, * testCheckVehicleInfoAndCalculateWarmEmissions_and_throwWarmEmissionEvent_Exceptions - * get free flow occurences - testCounters*() - * get fraction occurences - testCounters*() - * get stop go occurences - testCounters*() + * get free flow occurrences - testCounters*() + * get fraction occurrences - testCounters*() + * get stop-go occurrences - testCounters*() * get km counter - testCounters*() * get free flow km counter - testCounters*() - * get top go km couter - testCounters*() + * get top go km counter - testCounters*() * get warm emission event counter - testCounters*() * * private methods and corresponding tests: @@ -90,7 +90,7 @@ public class TestWarmEmissionAnalysisModuleCase5 { private final HandlerToTestEmissionAnalysisModules emissionEventManager = new HandlerToTestEmissionAnalysisModules(); // vehicle information for regular test cases - // case 5 - data in detailed table, stop go speed zero + // case 5 - data in detailed table, stop-go speed zero private final String zeroRoadCategory = "URB_case6"; private final String zeroTechnology = "zero technology"; private final String zeroConcept = "zero concept"; diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleTrafficSituations.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleTrafficSituations.java index 49f3a0494d9..6d65c3ea4f6 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleTrafficSituations.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/TestWarmEmissionAnalysisModuleTrafficSituations.java @@ -74,7 +74,7 @@ public class TestWarmEmissionAnalysisModuleTrafficSituations { private static final String petrolConcept ="<1,4L"; private static final double[] detailedPetrolFactor = {10, 100, 1000, 10000, 100000}; - // case 2 - free flow entry in both tables, stop go entry in average table -> use average + // case 2 - free flow entry in both tables, stop-go entry in average table -> use average private static final String pcTechnology = "PC petrol <1,4L warmEmissions = emissionModule.getWarmEmissionAnalysisModule().checkVehicleInfoAndCalculateWarmEmissions(vehicleFull, link, travelTimeOnLink); double expectedValue = 30.34984742; // = 200m * 151.7492371 g/km @@ -92,7 +92,7 @@ void testWarm_DetailedElseAbort_ShouldAbort1() { assertThrows(RuntimeException.class, () -> { EmissionModule emissionModule = setUpScenario(EmissionsConfigGroup.DetailedVsAverageLookupBehavior.onlyTryDetailedElseAbort); - double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72.. m/s) approx 20.57 s + double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72... m/s) approx 20.57 s emissionModule.getWarmEmissionAnalysisModule().checkVehicleInfoAndCalculateWarmEmissions(vehicleFallbackToTechnologyAverage, link, travelTimeOnLink); }); } @@ -110,7 +110,7 @@ void testWarm_DetailedElseAbort_ShouldAbort2() { assertThrows(RuntimeException.class, () -> { EmissionModule emissionModule = setUpScenario(EmissionsConfigGroup.DetailedVsAverageLookupBehavior.onlyTryDetailedElseAbort); - double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72.. m/s) approx 20.57 s + double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72... m/s) approx 20.57 s emissionModule.getWarmEmissionAnalysisModule().checkVehicleInfoAndCalculateWarmEmissions(vehicleFallbackToAverageTable, link, travelTimeOnLink); }); } @@ -128,7 +128,7 @@ void testWarm_DetailedElseAbort_ShouldAbort2() { void testWarm_DetailedThenTechnologyAverageElseAbort_FallbackNotNeeded() { EmissionModule emissionModule = setUpScenario(EmissionsConfigGroup.DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageElseAbort); - double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72.. m/s) approx 20.57 s + double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72... m/s) approx 20.57 s Map warmEmissions = emissionModule.getWarmEmissionAnalysisModule().checkVehicleInfoAndCalculateWarmEmissions(vehicleFull, link, travelTimeOnLink); double expectedValue = 30.34984742; // = 200m * 151.7492371 g/km @@ -147,7 +147,7 @@ void testWarm_DetailedThenTechnologyAverageElseAbort_FallbackNotNeeded() { void testWarm_DetailedThenTechnologyAverageElseAbort_FallbackToTechnologyAverage() { EmissionModule emissionModule = setUpScenario(EmissionsConfigGroup.DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageElseAbort); - double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72.. m/s) approx 20.57 s + double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72... m/s) approx 20.57 s Map warmEmissions = emissionModule.getWarmEmissionAnalysisModule().checkVehicleInfoAndCalculateWarmEmissions(vehicleFallbackToTechnologyAverage, link, travelTimeOnLink); double expectedValue = 31.53711548; // = 200m * 157.6855774 g/km @@ -167,7 +167,7 @@ void testWarm_DetailedThenTechnologyAverageElseAbort_ShouldAbort() { assertThrows(RuntimeException.class, () -> { EmissionModule emissionModule = setUpScenario(EmissionsConfigGroup.DetailedVsAverageLookupBehavior.onlyTryDetailedElseAbort); - double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72.. m/s) approx 20.57 s + double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72... m/s) approx 20.57 s emissionModule.getWarmEmissionAnalysisModule().checkVehicleInfoAndCalculateWarmEmissions(vehicleFallbackToAverageTable, link, travelTimeOnLink); }); } @@ -184,7 +184,7 @@ void testWarm_DetailedThenTechnologyAverageElseAbort_ShouldAbort() { void testWarm_DetailedThenTechnologyAverageThenAverageTable_FallbackNotNeeded() { EmissionModule emissionModule = setUpScenario(EmissionsConfigGroup.DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageThenAverageTable); - double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72.. m/s) approx 20.57 s + double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72... m/s) approx 20.57 s Map warmEmissions = emissionModule.getWarmEmissionAnalysisModule().checkVehicleInfoAndCalculateWarmEmissions(vehicleFull, link, travelTimeOnLink); double expectedValue = 30.34984742; // = 200m * 151.7492371 g/km @@ -203,7 +203,7 @@ void testWarm_DetailedThenTechnologyAverageThenAverageTable_FallbackNotNeeded() void testWarm_DetailedThenTechnologyAverageThenAverageTable_FallbackToTechnology() { EmissionModule emissionModule = setUpScenario(EmissionsConfigGroup.DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageThenAverageTable); - double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72.. m/s) approx 20.57 s + double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72... m/s) approx 20.57 s Map warmEmissions = emissionModule.getWarmEmissionAnalysisModule().checkVehicleInfoAndCalculateWarmEmissions(vehicleFallbackToTechnologyAverage, link, travelTimeOnLink); double expectedValue = 31.53711548; // = 200m * 157.6855774 g/km @@ -223,7 +223,7 @@ void testWarm_DetailedThenTechnologyAverageThenAverageTable_FallbackToTechnology void testWarm_DetailedThenTechnologyAverageThenAverageTable_FallbackToAverageTable() { EmissionModule emissionModule = setUpScenario(EmissionsConfigGroup.DetailedVsAverageLookupBehavior.tryDetailedThenTechnologyAverageThenAverageTable); - double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72.. m/s) approx 20.57 s + double travelTimeOnLink = 21; //sec. approx freeSpeed of link12 is : (200 m) / (9.72... m/s) approx 20.57 s Map warmEmissions = emissionModule.getWarmEmissionAnalysisModule().checkVehicleInfoAndCalculateWarmEmissions(vehicleFallbackToAverageTable, link, travelTimeOnLink); double expectedValue = 31.1947174; // = 200m * 155.973587 g/km diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/VspHbefaRoadTypeMappingTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/VspHbefaRoadTypeMappingTest.java index f0164d11e86..fb906ac6f63 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/VspHbefaRoadTypeMappingTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/VspHbefaRoadTypeMappingTest.java @@ -16,7 +16,7 @@ void testSimpleMapping() { var mapper = new VspHbefaRoadTypeMapping(); var link = getTestLink("", 70 / 3.6); - var result = mapper.determineHebfaType(link); + var result = mapper.determineHbefaType(link); assertEquals("URB/MW-Nat./80", result); } @@ -36,4 +36,4 @@ private static Link getTestLink(String osmRoadType, double allowedSpeed) { return link; } -} \ No newline at end of file +} diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionGridAnalyzerTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionGridAnalyzerTest.java index e000400d4ca..ef291d8d788 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionGridAnalyzerTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionGridAnalyzerTest.java @@ -386,9 +386,9 @@ private void writeGridToCSV(TimeBinMap>> bins, Strin } } - private void assertCsvValuesAreSame(Path expected, Path acutal) throws IOException { + private void assertCsvValuesAreSame(Path expected, Path actual) throws IOException { - try (FileReader expectedReader = new FileReader(expected.toString()); var actualReader = new FileReader(acutal.toString())) { + try (FileReader expectedReader = new FileReader(expected.toString()); var actualReader = new FileReader(actual.toString())) { var actualIterator = CSVFormat.TDF.withFirstRecordAsHeader().parse(actualReader).iterator(); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReaderTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReaderTest.java index 5495783715a..955c1d4313d 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReaderTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/RawEmissionEventsReaderTest.java @@ -36,7 +36,7 @@ void handleNonEventNode() { @Test void handleNonEmissionEvent() { - // read in events file wihtout emission events. Those events should be ignored + // read in events file without emission events. Those events should be ignored var eventsUrl = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("equil"), "output_events.xml.gz"); new RawEmissionEventsReader((time, linkId, vehicleId, pollutant, value) -> { // this method should not be called diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java index 121aabefc72..31eb7805137 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java @@ -292,7 +292,7 @@ final void testGetTotalEmissions_completeData() { //put some content into the list // no incorrect/incomplete input data here - // warm and cold emissions are already sumed up -> sumUpEmissionsPerId is tested seperatly + // warm and cold emissions are already summed up -> sumUpEmissionsPerId is tested separately //person1 SortedMap allEmissionsP1 = new TreeMap<>(); @@ -442,7 +442,7 @@ final void testSetNonCalculatedEmissionsForPopulation_completeData(){ } //nothing else in the list int numOfPolls = pollsFromEU.size(); - Assertions.assertEquals(numOfPolls, finalMap.get(id).keySet().size(), "the number of pullutants is " + finalMap.get(id).keySet().size() + " but should be" + numOfPolls); + Assertions.assertEquals(numOfPolls, finalMap.get(id).keySet().size(), "the number of pollutants is " + finalMap.get(id).keySet().size() + " but should be" + numOfPolls); } //check: values for all emissions are correct -person 1 @@ -498,7 +498,7 @@ final void testSetNonCalculatedEmissionsForPopulation_missingMap() { } //nothing else in the list int numOfPolls = pollsFromEU.size(); - message = "the number of pullutants is " + finalMap.get(idp3).keySet().size() + " but should be" + numOfPolls; + message = "the number of pollutants is " + finalMap.get(idp3).keySet().size() + " but should be" + numOfPolls; Assertions.assertEquals(numOfPolls, finalMap.get(idp3).keySet().size(), message); } From adcb9f828f4d1b3b8637c91227f8870337c92c1f Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 14:42:22 +0200 Subject: [PATCH 156/213] more simplifications --- .../emissions/ColdEmissionAnalysisModule.java | 49 ++++--------------- .../contrib/emissions/EmissionUtils.java | 3 +- 2 files changed, 10 insertions(+), 42 deletions(-) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionAnalysisModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionAnalysisModule.java index bc201e3761c..52ab385cf7d 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionAnalysisModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/ColdEmissionAnalysisModule.java @@ -155,20 +155,15 @@ private Map calculateColdEmissions(Id vehicleId, dou //HBEFA 3 provides cold start emissions for "pass. car" and Light_Commercial_Vehicles (LCV) only. //HBEFA 4.1 provides cold start emissions for "pass. car" and Light_Commercial_Vehicles (LCV) only. //see https://www.hbefa.net/e/documents/HBEFA41_Development_Report.pdf (WP 4 , page 23) kturner, may'20 - //Mapping everything except "motorcycle" to "pass.car", since this was done in the last years for HGV. - //This may can be improved: What should be better set to LGV or zero???? kturner, may'20 - if (vehicleInformationTuple.getFirst().equals(HbefaVehicleCategory.HEAVY_GOODS_VEHICLE)) { - changeVehCategory(key, HbefaVehicleCategory.HEAVY_GOODS_VEHICLE, HbefaVehicleCategory.PASSENGER_CAR); - } - if (vehicleInformationTuple.getFirst().equals(HbefaVehicleCategory.URBAN_BUS)) { - changeVehCategory(key, HbefaVehicleCategory.URBAN_BUS, HbefaVehicleCategory.PASSENGER_CAR ); - } - if (vehicleInformationTuple.getFirst().equals(HbefaVehicleCategory.COACH)) { - changeVehCategory(key, HbefaVehicleCategory.COACH, HbefaVehicleCategory.PASSENGER_CAR); - } - if (vehicleInformationTuple.getFirst().equals(HbefaVehicleCategory.MOTORCYCLE)){ - changeVehCategory(key, HbefaVehicleCategory.MOTORCYCLE, HbefaVehicleCategory.PASSENGER_CAR); - return coldEmissionsOfEvent; + if (vehicleInformationTuple.getFirst().equals(HbefaVehicleCategory.HEAVY_GOODS_VEHICLE) || + vehicleInformationTuple.getFirst().equals(HbefaVehicleCategory.COACH) || + vehicleInformationTuple.getFirst().equals(HbefaVehicleCategory.URBAN_BUS) || + vehicleInformationTuple.getFirst().equals(HbefaVehicleCategory.MOTORCYCLE)) { + if (vehInfoWarnHDVCnt < maxWarnCnt) { + vehInfoWarnHDVCnt++; + logger.warn("Automagic changing of VehCategory is disabled. Please make sure that your table contains the necessary values for {}", HbefaVehicleCategory.HEAVY_GOODS_VEHICLE.name()); + if (vehInfoWarnHDVCnt == maxWarnCnt) logger.warn(Gbl.FUTURE_SUPPRESSED); + } } if(this.detailedHbefaColdTable != null) { @@ -197,32 +192,6 @@ private Map calculateColdEmissions(Id vehicleId, dou return coldEmissionsOfEvent; } - /** - * Replace the vehicleCategory with HbefaVehicleCategory.PASSENGER_CAR - * This is the old behaviour as it was until Aug 21. - * (Aug'21, KMT) This does not help, since the emConcepts are not the same. So it is _not_ usable if using - * some kind of detailed values. - * @param key - * @param originVehCat - * @param targetvehCat - */ - //TODO Maybe make the behaviour settable by an enum? -> keep some kind of backwards capability or just return a 0.0 as it is for motorcycle? - private void changeVehCategory(HbefaColdEmissionFactorKey key, HbefaVehicleCategory originVehCat, HbefaVehicleCategory targetvehCat) { -// key.setVehicleCategory(targetvehCat); -// if (vehInfoWarnHDVCnt < maxWarnCnt) { -// vehInfoWarnHDVCnt++; -// logger.warn("HBEFA does not provide cold start emission factors for " + -// originVehCat + -// ". Setting vehicle category to " + targetvehCat + "..."); -// if (vehInfoWarnHDVCnt == maxWarnCnt) logger.warn(Gbl.FUTURE_SUPPRESSED); -// } - if (vehInfoWarnHDVCnt < maxWarnCnt) { - vehInfoWarnHDVCnt++; - logger.warn("Automagic changing of VehCategory is disabled. Please make sure that your table contains the necessary values for {}", originVehCat.name()); - if (vehInfoWarnHDVCnt == maxWarnCnt) logger.warn(Gbl.FUTURE_SUPPRESSED); - } - } - private HbefaColdEmissionFactor getEmissionsFactor(Tuple vehicleInformationTuple, int distance_km, HbefaColdEmissionFactorKey efkey, Pollutant coldPollutant) { efkey.setDistance(distance_km); diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionUtils.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionUtils.java index e174e14192c..bd28e89992c 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionUtils.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/EmissionUtils.java @@ -346,7 +346,7 @@ static Pollutant getPollutant( String pollutantString ){ // setCo2TotalKeys( Set keys ) // as we have it, e.g., with network modes. kai, feb'20 - Pollutant pollutant = switch (pollutantString) { + return switch (pollutantString) { case "CO2(total)" -> Pollutant.CO2_TOTAL; case "CO2(rep)" -> Pollutant.CO2_rep; case "PM2.5 (non-exhaust)" -> Pollutant.PM2_5_non_exhaust; @@ -360,7 +360,6 @@ static Pollutant getPollutant( String pollutantString ){ // (2) It is a different spelling of an already existing pollutant. In that case, see above. // kai, jan'20 }; - return pollutant; } /** From 2d5c06fcd9904e0ff89c6db8a8aca6fd18afdbc6 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 14:45:13 +0200 Subject: [PATCH 157/213] cleanup: remove commented out code --- .../contrib/emissions/WarmEmissionAnalysisModule.java | 4 ---- .../example/RunAverageEmissionToolOfflineExample.java | 6 +----- .../example/RunDetailedEmissionToolOfflineExample.java | 5 ----- ...ssionToolOnlineExampleIT_vehTypeV2FallbackToAverage.java | 3 --- .../matsim/contrib/emissions/utils/EmissionUtilsTest.java | 6 ------ 5 files changed, 1 insertion(+), 23 deletions(-) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java index 9da932e67a5..8eff2d52a29 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/WarmEmissionAnalysisModule.java @@ -63,10 +63,6 @@ public final class WarmEmissionAnalysisModule implements LinkEmissionsCalculator private int detailedFallbackAverageTableWarnCnt = 0; private int averageReadingInfoCnt = 0; - // The following was tested to slow down significantly, therefore counters were commented out: -// Set vehAttributesNotSpecified = Collections.synchronizedSet(new HashSet()); -// Set vehicleIdSet = Collections.synchronizedSet(new HashSet()); - private int freeFlowCounter = 0; private int saturatedCounter = 0; private int heavyFlowCounter = 0; diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunAverageEmissionToolOfflineExample.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunAverageEmissionToolOfflineExample.java index 4361e146329..c1f344dc331 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunAverageEmissionToolOfflineExample.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunAverageEmissionToolOfflineExample.java @@ -60,14 +60,10 @@ public static void main (String[] args){ emissionToolOfflineExampleV2.run(); } -// public Config prepareConfig() { -// config = ConfigUtils.loadConfig(configFile, new EmissionsConfigGroup()); -// return config; -// } - public Config prepareConfig(String args){ throw new RuntimeException("execution path no longer exists"); } + public Config prepareConfig(String [] args) { config = ConfigUtils.loadConfig(args, new EmissionsConfigGroup()); EmissionsConfigGroup ecg = ConfigUtils.addOrGetModule( config, EmissionsConfigGroup.class ); diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOfflineExample.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOfflineExample.java index cb999fd8d78..83d4499706a 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOfflineExample.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOfflineExample.java @@ -60,11 +60,6 @@ public static void main (String[] args){ emissionToolOfflineExampleV2Vehv1.run(); } -// public Config prepareConfig() { -// config = ConfigUtils.loadConfig(configFile, new EmissionsConfigGroup()); -// return config; -// } - public Config prepareConfig(String [] args) { config = ConfigUtils.loadConfig(args, new EmissionsConfigGroup()); return config; diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOnlineExampleIT_vehTypeV2FallbackToAverage.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOnlineExampleIT_vehTypeV2FallbackToAverage.java index 65f2c8a4850..2c89b956450 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOnlineExampleIT_vehTypeV2FallbackToAverage.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/example/RunDetailedEmissionToolOnlineExampleIT_vehTypeV2FallbackToAverage.java @@ -45,9 +45,6 @@ public class RunDetailedEmissionToolOnlineExampleIT_vehTypeV2FallbackToAverage { @Test final void testDetailed_vehTypeV2_FallbackToAverage() { try { -// RunDetailedEmissionToolOnlineExample onlineExample = new RunDetailedEmissionToolOnlineExample(); - -// Config config = onlineExample.prepareConfig( new String[]{"./scenarios/sampleScenario/testv2_Vehv2/config_detailed.xml"} ) ; var scenarioUrl = ExamplesUtils.getTestScenarioURL( "emissions-sampleScenario/testv2_Vehv2" ); var configUrl = IOUtils.extendUrl( scenarioUrl, "config_detailed.xml" ); Config config = RunDetailedEmissionToolOnlineExample.prepareConfig( new String [] { configUrl.toString() } ); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java index 31eb7805137..f71692faa5e 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/utils/EmissionUtilsTest.java @@ -74,8 +74,6 @@ public class EmissionUtilsTest { private boolean nullPointerEx; public static Map createUntypedEmissions() { -// return Arrays.asList("co2", CO, NOx, "NO", NO2, HC).stream() -// .collect(Collectors.toMap(p -> p, p -> Math.random())); return Stream.of(CO2_TOTAL, CO, NOx, NO2, HC) .collect(Collectors.toMap(p -> p, p -> Math.random())); } @@ -793,10 +791,6 @@ public static Map createEmissions() { return Arrays.stream( Pollutant.values() ).collect( Collectors.toMap( p -> p, p -> Math.random() ) ) ; } -// public static Map createEmissionsWithFixedValue(double value) { -// return Arrays.asList("co2", CO, NOx, "NO", NO2, HC).stream() -// .collect(Collectors.toMap(p -> p, p -> value)); -// } public static Map createEmissionsWithFixedValue( double value ) { return Arrays.stream( Pollutant.values() ).collect( Collectors.toMap( p -> p, p -> value ) ) ; } From dac7488fa93e8ac3b63d8efe4f8e4e62ecd53228 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Thu, 25 Jul 2024 14:55:03 +0200 Subject: [PATCH 158/213] small cleanups --- .../events/EmissionEventsReader.java | 18 ++++++++---- .../contrib/emissions/package-info.java | 3 +- .../analysis/EmissionsByPollutantTest.java | 9 ++---- .../events/TestColdEmissionEventImpl.java | 28 +++++++++---------- .../events/TestWarmEmissionEventImpl.java | 4 +-- 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/events/EmissionEventsReader.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/events/EmissionEventsReader.java index 83bf51bc0f2..11f73caf526 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/events/EmissionEventsReader.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/events/EmissionEventsReader.java @@ -67,9 +67,12 @@ public EmissionEventsReader( EventsManager events ){ case WarmEmissionEvent.ATTRIBUTE_LINK_ID -> linkId = Id.createLinkId(entry.getValue()); case WarmEmissionEvent.ATTRIBUTE_VEHICLE_ID -> vehicleId = Id.createVehicleId(entry.getValue()); case null, default -> { - String pollutant = entry.getKey().equals("NOX") ? - "NOx" : - entry.getKey(); // the previous versions would write NOX instead of NOx + String pollutant = null; // the previous versions would write NOX instead of NOx + if (entry.getKey() != null) { + pollutant = entry.getKey().equals("NOX") ? + "NOx" : + entry.getKey(); + } Double value = Double.parseDouble(entry.getValue()); warmEmissions.put(Pollutant.valueOf(pollutant), value); @@ -100,9 +103,12 @@ public EmissionEventsReader( EventsManager events ){ case ColdEmissionEvent.ATTRIBUTE_LINK_ID -> linkId = Id.createLinkId(entry.getValue()); case ColdEmissionEvent.ATTRIBUTE_VEHICLE_ID -> vehicleId = Id.createVehicleId(entry.getValue()); case null, default -> { - String pollutant = entry.getKey().equals("NOX") ? - "NOx" : - entry.getKey(); // the previous versions would write NOX instead of NOx + String pollutant = null; // the previous versions would write NOX instead of NOx + if (entry.getKey() != null) { + pollutant = entry.getKey().equals("NOX") ? + "NOx" : + entry.getKey(); + } Double value = Double.parseDouble(entry.getValue()); coldEmissions.put(Pollutant.valueOf(pollutant), value); diff --git a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/package-info.java b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/package-info.java index 2d954229c63..811d521cb60 100644 --- a/contribs/emissions/src/main/java/org/matsim/contrib/emissions/package-info.java +++ b/contribs/emissions/src/main/java/org/matsim/contrib/emissions/package-info.java @@ -46,7 +46,8 @@ * or see {@link org.matsim.contrib.emissions.utils.EmissionsConfigGroup} for a detailed description. * *

    • emissionVehicleFile: This data type is defined in the EmissionsConfigGroup, - * see {@link org.matsim.contrib.emissions.utils.EmissionsConfigGroup}. The following information is surrounded by {@link org.matsim.contrib.emissions.EmissionUtils.EmissionSpecificationMarker}. It is described as "definition of a vehicle + * see {@link org.matsim.contrib.emissions.utils.EmissionsConfigGroup}. + * The following information is surrounded by {@link org.matsim.contrib.emissions.EmissionUtils.EmissionSpecificationMarker}. It is described as "definition of a vehicle * for every person (who is allowed to choose a vehicle in the simulation): *
        *
      • REQUIRED: Vehicle description must start with the respective HbefaVehicleCategory followed by ";" diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionsByPollutantTest.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionsByPollutantTest.java index 114802a4de0..52ed3393a4f 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionsByPollutantTest.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/analysis/EmissionsByPollutantTest.java @@ -45,8 +45,7 @@ void addEmission() { final Pollutant pollutant = CO; final double expectedValue = emissions.get(pollutant) + valueToAdd; - Map map = new LinkedHashMap<>(); - map.putAll(emissions); + Map map = new LinkedHashMap<>(emissions); EmissionsByPollutant emissionsByPollutant = new EmissionsByPollutant(map); @@ -78,13 +77,11 @@ void addEmissions() { Map emissions = EmissionUtilsTest.createEmissions(); - Map map = new LinkedHashMap<>(); - map.putAll(emissions); + Map map = new LinkedHashMap<>(emissions); EmissionsByPollutant linkEmissions = new EmissionsByPollutant(map); - Map map2 = new LinkedHashMap<>(); - map2.putAll(emissions); + Map map2 = new LinkedHashMap<>(emissions); linkEmissions.addEmissions(map2); diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/events/TestColdEmissionEventImpl.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/events/TestColdEmissionEventImpl.java index 022265df9f0..9a3af2d8601 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/events/TestColdEmissionEventImpl.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/events/TestColdEmissionEventImpl.java @@ -62,7 +62,7 @@ final void testGetAttributesForCompleteEmissionMaps(){ Map coldEmissionsMap = new HashMap<>(); setColdEmissions(coldEmissionsMap); ColdEmissionEvent ce = new ColdEmissionEvent(0.0, linkId, vehicleId, coldEmissionsMap); - + Map ceg = ce.getAttributes(); Assertions.assertEquals(Double.parseDouble(ceg.get(CO.name())), co, MatsimTestUtils.EPSILON, "the CO value of this cold emission event was "+ Double.parseDouble(ceg.get(CO.name()))+ "but should have been "+ co); Assertions.assertEquals(Double.parseDouble(ceg.get(FC.name())), fc, MatsimTestUtils.EPSILON, "the FC value of this cold emission event was "+ Double.parseDouble(ceg.get(FC.name()))+ "but should have been "+ fc); @@ -71,7 +71,7 @@ final void testGetAttributesForCompleteEmissionMaps(){ Assertions.assertEquals(Double.parseDouble(ceg.get(NO2.name())), n2, MatsimTestUtils.EPSILON, "the NO2 value of this cold emission event was "+ Double.parseDouble(ceg.get(NO2.name()))+ "but should have been "+ n2); Assertions.assertEquals(Double.parseDouble(ceg.get(NOx.name())), nx, MatsimTestUtils.EPSILON, "the NOx value of this cold emission event was "+ Double.parseDouble(ceg.get(NOx.name()))+ "but should have been "+ nx); Assertions.assertEquals(Double.parseDouble(ceg.get(PM.name())), pm, MatsimTestUtils.EPSILON, "the PM value of this cold emission event was "+ Double.parseDouble(ceg.get(PM.name()))+ "but should have been "+ pm); - + } private void setColdEmissions( Map coldEmissionsMap ) { @@ -90,12 +90,12 @@ final void testGetAttributesForIncompleteMaps(){ //the getAttributesMethod should // - return null if the emission map is empty // - throw NullPointerExceptions if the emission values are not set - // - throw NullPointerExceptions if no emission map is assigned - + // - throw NullPointerExceptions if no emission map is assigned + //empty map Map emptyMap = new HashMap<>(); ColdEmissionEvent emptyMapEvent = new ColdEmissionEvent(22., linkId, vehicleId, emptyMap); - + //values not set Map valuesNotSet = new HashMap<>(); valuesNotSet.put(CO, null); @@ -106,30 +106,30 @@ final void testGetAttributesForIncompleteMaps(){ valuesNotSet.put(NOx, null); valuesNotSet.put(PM, null); ColdEmissionEvent valuesNotSetEvent = new ColdEmissionEvent(44., linkId, vehicleId, valuesNotSet); - + //no map ColdEmissionEvent noMap = new ColdEmissionEvent(50., linkId, vehicleId, null); - + int numberOfColdPollutants = coldPollutants.size(); int valNullPointers = 0, noMapNullPointers=0; - + for(Pollutant cp : coldPollutants){ //empty map - Assertions.assertNull(emptyMapEvent.getAttributes().get(cp)); - + Assertions.assertNull(emptyMapEvent.getAttributes().get(cp.name())); + //values not set try{ - valuesNotSetEvent.getAttributes().get(cp); + valuesNotSetEvent.getAttributes().get(cp.name()); } catch(NullPointerException e){ valNullPointers ++; } - + //no map try{ - noMap.getAttributes().get(cp); + noMap.getAttributes().get(cp.name()); } catch(NullPointerException e){ noMapNullPointers++; @@ -138,5 +138,5 @@ final void testGetAttributesForIncompleteMaps(){ Assertions.assertEquals(numberOfColdPollutants, valNullPointers); Assertions.assertEquals(numberOfColdPollutants, noMapNullPointers); } - + } diff --git a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/events/TestWarmEmissionEventImpl.java b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/events/TestWarmEmissionEventImpl.java index 2244cb6dde7..b203c8792ce 100644 --- a/contribs/emissions/src/test/java/org/matsim/contrib/emissions/events/TestWarmEmissionEventImpl.java +++ b/contribs/emissions/src/test/java/org/matsim/contrib/emissions/events/TestWarmEmissionEventImpl.java @@ -111,9 +111,7 @@ final void testGetAttributesForIncompleteMaps(){ valuesNotSet.put(NOx, null); valuesNotSet.put(PM, null); - Map map = new LinkedHashMap<>(); - valuesNotSet.forEach(map::put); - // (this could be made more direct) + Map map = new LinkedHashMap<>(valuesNotSet); WarmEmissionEvent valuesNotSetEvent = new WarmEmissionEvent(44., linkId, vehicleId, map); From 96b14eea07da6bbb5e2e1d611fe4b2ee69ef3df1 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Thu, 25 Jul 2024 17:21:28 +0200 Subject: [PATCH 159/213] fix test failures by disable net consistency check --- matsim/src/test/java/org/matsim/core/controler/ControlerIT.java | 1 + .../invertednetworks/InvertedNetworkRoutingTestFixture.java | 2 ++ .../integration/population/NonAlternatingPlanElementsIT.java | 2 ++ 3 files changed, 5 insertions(+) diff --git a/matsim/src/test/java/org/matsim/core/controler/ControlerIT.java b/matsim/src/test/java/org/matsim/core/controler/ControlerIT.java index 2a735f508af..703ea500d06 100644 --- a/matsim/src/test/java/org/matsim/core/controler/ControlerIT.java +++ b/matsim/src/test/java/org/matsim/core/controler/ControlerIT.java @@ -1018,6 +1018,7 @@ private static class Fixture { Link link3 = null; protected Fixture(final Config config) { + config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable); this.scenario = ScenarioUtils.createScenario(config); this.network = this.scenario.getNetwork(); diff --git a/matsim/src/test/java/org/matsim/integration/invertednetworks/InvertedNetworkRoutingTestFixture.java b/matsim/src/test/java/org/matsim/integration/invertednetworks/InvertedNetworkRoutingTestFixture.java index e63fb5115fa..4a0a6ef92bd 100644 --- a/matsim/src/test/java/org/matsim/integration/invertednetworks/InvertedNetworkRoutingTestFixture.java +++ b/matsim/src/test/java/org/matsim/integration/invertednetworks/InvertedNetworkRoutingTestFixture.java @@ -38,6 +38,7 @@ import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; import org.matsim.core.config.groups.QSimConfigGroup; +import org.matsim.core.config.groups.RoutingConfigGroup; import org.matsim.core.config.groups.ScoringConfigGroup.ActivityParams; import org.matsim.core.config.groups.ReplanningConfigGroup.StrategySettings; import org.matsim.core.replanning.strategies.DefaultPlanStrategiesModule; @@ -78,6 +79,7 @@ public class InvertedNetworkRoutingTestFixture { public InvertedNetworkRoutingTestFixture(boolean doCreateModes, boolean doCreateLanes, boolean doCreateSignals) { Config config = ConfigUtils.createConfig(); + config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable); config.controller().setLastIteration(0); config.controller().setLinkToLinkRoutingEnabled(true); config.travelTimeCalculator().setCalculateLinkToLinkTravelTimes(true); diff --git a/matsim/src/test/java/org/matsim/integration/population/NonAlternatingPlanElementsIT.java b/matsim/src/test/java/org/matsim/integration/population/NonAlternatingPlanElementsIT.java index 033857c8a4c..d4caf530dc0 100644 --- a/matsim/src/test/java/org/matsim/integration/population/NonAlternatingPlanElementsIT.java +++ b/matsim/src/test/java/org/matsim/integration/population/NonAlternatingPlanElementsIT.java @@ -37,6 +37,7 @@ import org.matsim.core.config.Config; import org.matsim.core.config.groups.FacilitiesConfigGroup; import org.matsim.core.config.groups.PlansConfigGroup.HandlingOfPlansWithoutRoutingMode; +import org.matsim.core.config.groups.RoutingConfigGroup; import org.matsim.core.controler.Controler; import org.matsim.core.network.io.MatsimNetworkReader; import org.matsim.core.population.routes.NetworkRoute; @@ -97,6 +98,7 @@ void test_Controler_QSim_Routechoice_acts() { @Test void test_Controler_QSim_Routechoice_legs() { Config config = this.utils.loadConfig("test/scenarios/equil/config.xml"); + config.routing().setNetworkRouteConsistencyCheck(RoutingConfigGroup.NetworkRouteConsistencyCheck.disable); config.controller().setMobsim("qsim"); config.controller().setLastIteration(10); config.plans().setHandlingOfPlansWithoutRoutingMode(HandlingOfPlansWithoutRoutingMode.useMainModeIdentifier); From 213fae045ebc45a9adda8941d87b7afee170a338 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Sat, 27 Jul 2024 21:26:29 +0200 Subject: [PATCH 160/213] optimize h3 zone system initialization; move h3 test to common module --- .../zones/systems/grid/h3/H3ZoneSystem.java | 63 ++++++++++--------- .../grid/square/SquareGridZoneSystem.java | 4 +- .../systems/h3}/H3DrtZonalSystemTest.java | 62 +++++++++--------- 3 files changed, 65 insertions(+), 64 deletions(-) rename contribs/{drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/drtZone => common/src/test/java/org/matsim/contrib/common/zones/systems/h3}/H3DrtZonalSystemTest.java (55%) diff --git a/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/h3/H3ZoneSystem.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/h3/H3ZoneSystem.java index e9c84bccc4a..286bc9a09ca 100644 --- a/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/h3/H3ZoneSystem.java +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/h3/H3ZoneSystem.java @@ -13,8 +13,12 @@ import org.matsim.core.utils.geometry.CoordinateTransformation; import org.matsim.core.utils.geometry.transformations.TransformationFactory; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * @author nkuehnel / MOIA @@ -39,41 +43,38 @@ public H3ZoneSystem(String crs, int resolution, Network network, Predicate this.resolution = resolution; this.network = network; this.filter = filter; - this.network.getLinks().values().forEach(l -> getZoneForCoord(l.getToNode().getCoord())); + init(); } - - @Override - public Optional getZoneForCoord(Coord coord) { - - long h3Address = getH3Cell(coord); - Id zoneId = Id.create(h3Address, Zone.class); - - if(zones.containsKey(zoneId)) { - return Optional.of(zones.get(zoneId)); - } else { - Optional zone = H3Utils.createZone(h3Address, fromLatLong); - if(zone.isPresent() && filter.test(zone.get())) { - initZone(zone.get(), h3Address); - return zone; - } else { - return Optional.empty(); - } + private void init() { + Map> linksToH3 = + this.network.getLinks().values() + .stream() + .collect(Collectors.groupingBy(link -> getH3Cell(link.getToNode().getCoord()))); + for (Map.Entry> linksH3 : linksToH3.entrySet()) { + Optional maybeZone = createZone(linksH3.getKey()); + maybeZone.ifPresent(z -> { + zones.put(z.getId(), z); + zoneToLinksMap.put(z.getId(), linksH3.getValue()); + }); } } - private void initZone(Zone zone, long h3Address) { - if(filter.test(zone)) { - zones.put(zone.getId(), zone); - for (Link link : network.getLinks().values()) { - long linkH3Address = getH3Cell(link.getToNode().getCoord()); - - if (linkH3Address == h3Address) { - List links = zoneToLinksMap.computeIfAbsent(zone.getId(), id -> new ArrayList<>()); - links.add(link); - } - } + private Optional createZone(Long h3) { + Optional zone = H3Utils.createZone(h3, fromLatLong); + if(zone.isPresent() && filter.test(zone.get())) { + return zone; } + return Optional.empty(); + } + + @Override + public Optional getZoneForCoord(Coord coord) { + long h3Address = getH3Cell(coord); + Id zoneId = Id.create(h3Address, Zone.class); + // create new zone if absent, should not be linked to existing links in the network, + // as all of them are covered in the init() phase. + return Optional.ofNullable(zones.computeIfAbsent(zoneId, id -> createZone(h3Address).orElse(null))); } private long getH3Cell(Coord coord) { @@ -106,4 +107,4 @@ public List getLinksForZoneId(Id zone) { public Map, Zone> getZones() { return Collections.unmodifiableMap(zones); } -} +} \ No newline at end of file diff --git a/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/square/SquareGridZoneSystem.java b/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/square/SquareGridZoneSystem.java index f11fa58f614..b1319fed1a9 100644 --- a/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/square/SquareGridZoneSystem.java +++ b/contribs/common/src/main/java/org/matsim/contrib/common/zones/systems/grid/square/SquareGridZoneSystem.java @@ -66,11 +66,11 @@ public SquareGridZoneSystem(Network network, double cellSize, Predicate zo } public SquareGridZoneSystem(Network network, double cellSize, boolean filterByNetwork, Predicate zoneFilter) { this.zoneFilter = zoneFilter; - Preconditions.checkArgument(!network.getNodes().isEmpty(), "Cannot create SquareGrid if no nodes"); - this.network = network; this.cellSize = cellSize; + Preconditions.checkArgument(!network.getNodes().isEmpty(), "Cannot create SquareGrid if no nodes"); + initBounds(); this.rows = Math.max(1, (int) Math.ceil((maxY - minY) / cellSize)); diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/drtZone/H3DrtZonalSystemTest.java b/contribs/common/src/test/java/org/matsim/contrib/common/zones/systems/h3/H3DrtZonalSystemTest.java similarity index 55% rename from contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/drtZone/H3DrtZonalSystemTest.java rename to contribs/common/src/test/java/org/matsim/contrib/common/zones/systems/h3/H3DrtZonalSystemTest.java index 3724d5d8eac..723e4026825 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/h3/drtZone/H3DrtZonalSystemTest.java +++ b/contribs/common/src/test/java/org/matsim/contrib/common/zones/systems/h3/H3DrtZonalSystemTest.java @@ -18,7 +18,7 @@ * *********************************************************************** * */ -package org.matsim.contrib.drt.extension.h3.drtZone; +package org.matsim.contrib.common.zones.systems.h3; import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; @@ -48,20 +48,20 @@ void test_Holzkirchen_Resolution3() { Network network = getNetwork(); String crs = TransformationFactory.DHDN_GK4; int resolution = 3; - ZoneSystem drtZonalSystem = new H3ZoneSystem(crs, resolution, network, z -> true); + ZoneSystem zoneSystem = new H3ZoneSystem(crs, resolution, network, z -> true); - assertThat(drtZonalSystem.getZones().containsKey(createZoneId("590526392240701439"))).isTrue(); + assertThat(zoneSystem.getZones().containsKey(createZoneId("590526392240701439"))).isTrue(); // center of Holzkirchen - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("590526667118608383")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("590526667118608383")); // Thanning (Western border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("590526667118608383")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("590526667118608383")); // between Gross- and Kleinpienzenau (Southeastern border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("590526392240701439")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("590526392240701439")); //check all links are mapped for (Link link : network.getLinks().values()) { - assertNotNull(drtZonalSystem.getZoneForLinkId(link.getId())); + assertNotNull(zoneSystem.getZoneForLinkId(link.getId())); } } @@ -71,23 +71,23 @@ void test_Holzkirchen_Resolution5() { String crs = TransformationFactory.DHDN_GK4; int resolution = 5; - ZoneSystem drtZonalSystem = new H3ZoneSystem(crs, resolution, network, z -> true); + ZoneSystem zoneSystem = new H3ZoneSystem(crs, resolution, network, z -> true); - assertThat(drtZonalSystem.getZones().containsKey(createZoneId("599533579684282367"))).isTrue(); - assertThat(drtZonalSystem.getZones().containsKey(createZoneId("599533826644901887"))).isTrue(); - assertThat(drtZonalSystem.getZones().containsKey(createZoneId("599533499153645567"))).isTrue(); - assertThat(drtZonalSystem.getZones().containsKey(createZoneId("599533503448612863"))).isTrue(); + assertThat(zoneSystem.getZones().containsKey(createZoneId("599533579684282367"))).isTrue(); + assertThat(zoneSystem.getZones().containsKey(createZoneId("599533826644901887"))).isTrue(); + assertThat(zoneSystem.getZones().containsKey(createZoneId("599533499153645567"))).isTrue(); + assertThat(zoneSystem.getZones().containsKey(createZoneId("599533503448612863"))).isTrue(); // center of Holzkirchen - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("599533826644901887")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("599533826644901887")); // Thanning (Western border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("599533503448612863")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("599533503448612863")); // between Gross- and Kleinpienzenau (Southeastern border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("599533579684282367")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("599533579684282367")); //check all links are mapped for (Link link : network.getLinks().values()) { - assertNotNull(drtZonalSystem.getZoneForLinkId(link.getId())); + assertNotNull(zoneSystem.getZoneForLinkId(link.getId())); } } @@ -97,18 +97,18 @@ void test_Holzkirchen_Resolution6() { String crs = TransformationFactory.DHDN_GK4; int resolution = 6; - ZoneSystem drtZonalSystem = new H3ZoneSystem(crs, resolution, network, z -> true); + ZoneSystem zoneSystem = new H3ZoneSystem(crs, resolution, network, z -> true); // center of Holzkirchen - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("604037425601183743")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("604037425601183743")); // Thanning (Western border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("604037102136459263")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("604037102136459263")); // between Gross- and Kleinpienzenau (Southeastern border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("604037178372128767")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("604037178372128767")); //check all links are mapped for (Link link : network.getLinks().values()) { - assertNotNull(drtZonalSystem.getZoneForLinkId(link.getId())); + assertNotNull(zoneSystem.getZoneForLinkId(link.getId())); } } @@ -117,18 +117,18 @@ void test_Holzkirchen_Resolution10() { Network network = getNetwork(); String crs = TransformationFactory.DHDN_GK4; int resolution = 10; - ZoneSystem drtZonalSystem = new H3ZoneSystem(crs, resolution, network, z -> true); + ZoneSystem zoneSystem = new H3ZoneSystem(crs, resolution, network, z -> true); // center of Holzkirchen - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("622051824027533311")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("622051824027533311")); // Thanning (Western border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("622051500514213887")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("622051500514213887")); // between Gross- and Kleinpienzenau (Southeastern border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("622051576862081023")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("622051576862081023")); //check all links are mapped for (Link link : network.getLinks().values()) { - assertNotNull(drtZonalSystem.getZoneForLinkId(link.getId())); + assertNotNull(zoneSystem.getZoneForLinkId(link.getId())); } } @@ -138,19 +138,19 @@ void test_Holzkirchen_Resolution12() { String crs = TransformationFactory.DHDN_GK4; int resolution = 12; - ZoneSystem drtZonalSystem = new H3ZoneSystem(crs, resolution, network, z -> true); + ZoneSystem zoneSystem = new H3ZoneSystem(crs, resolution, network, z -> true); // center of Holzkirchen - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("631059023282267135")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(358598)).orElseThrow().getId()).isEqualTo(createZoneId("631059023282267135")); // Thanning (Western border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("631058699768943103")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(78976)).orElseThrow().getId()).isEqualTo(createZoneId("631058699768943103")); // between Gross- and Kleinpienzenau (Southeastern border of network) - assertThat(drtZonalSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("631058776116789759")); + assertThat(zoneSystem.getZoneForLinkId(Id.createLinkId(59914)).orElseThrow().getId()).isEqualTo(createZoneId("631058776116789759")); //check all links are mapped for (Link link : network.getLinks().values()) { - assertNotNull(drtZonalSystem.getZoneForLinkId(link.getId())); + assertNotNull(zoneSystem.getZoneForLinkId(link.getId())); } } From 8caaa375a2b75a021b69b88f638e6a3f39b9be69 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Mon, 29 Jul 2024 14:08:34 +0200 Subject: [PATCH 161/213] shift drt maintenance; fix bug for prebooked e-drt scenarios that need shifts to be assignable to requests in advance; change priority queues in shift dispatcher to sorted sets to ensure correct iteration order --- .../scheduler/EShiftTaskScheduler.java | 70 +++- .../dispatcher/DrtShiftDispatcherImpl.java | 305 +++++++++--------- 2 files changed, 210 insertions(+), 165 deletions(-) diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java index dc053728a40..a87c54a1be8 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java @@ -6,6 +6,7 @@ import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.drt.extension.operations.eshifts.schedule.EDrtShiftChangeoverTaskImpl; +import org.matsim.contrib.drt.extension.operations.eshifts.schedule.EDrtWaitForShiftTask; import org.matsim.contrib.drt.extension.operations.eshifts.schedule.ShiftEDrtTaskFactoryImpl; import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacilities; import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacility; @@ -22,10 +23,7 @@ import org.matsim.contrib.dvrp.fleet.Fleet; import org.matsim.contrib.dvrp.path.VrpPathWithTravelData; import org.matsim.contrib.dvrp.path.VrpPaths; -import org.matsim.contrib.dvrp.schedule.DriveTask; -import org.matsim.contrib.dvrp.schedule.Schedule; -import org.matsim.contrib.dvrp.schedule.StayTask; -import org.matsim.contrib.dvrp.schedule.Task; +import org.matsim.contrib.dvrp.schedule.*; import org.matsim.contrib.dvrp.tracker.OnlineDriveTaskTracker; import org.matsim.contrib.dvrp.util.LinkTimePair; import org.matsim.contrib.ev.charging.BatteryCharging; @@ -348,16 +346,20 @@ private void appendShiftChange(DvrpVehicle vehicle, DrtShift shift, OperationFac link, breakFacility)); } + @Override public void startShift(ShiftDvrpVehicle vehicle, double now, DrtShift shift) { - Schedule schedule = vehicle.getSchedule(); - StayTask stayTask = (StayTask) schedule.getCurrentTask(); - if (stayTask instanceof WaitForShiftTask) { - ((WaitForShiftTask) stayTask).getFacility().deregisterVehicle(vehicle.getId()); - stayTask.setEndTime(now); - schedule.addTask(taskFactory.createStayTask(vehicle, now, shift.getEndTime(), stayTask.getLink())); - } else { - throw new IllegalStateException("Vehicle cannot start shift during task:" + stayTask.getTaskType().name()); - } + Schedule schedule = vehicle.getSchedule(); + StayTask stayTask = (StayTask) schedule.getCurrentTask(); + if (stayTask instanceof WaitForShiftTask) { + ((WaitForShiftTask) stayTask).getFacility().deregisterVehicle(vehicle.getId()); + stayTask.setEndTime(now); + if(Schedules.getLastTask(schedule).equals(stayTask)) { + //nothing planned yet. + schedule.addTask(taskFactory.createStayTask(vehicle, now, shift.getEndTime(), stayTask.getLink())); + } + } else { + throw new IllegalStateException("Vehicle cannot start shift during task:" + stayTask.getTaskType().name()); + } } public boolean updateShiftChange(ShiftDvrpVehicle vehicle, Link link, DrtShift shift, @@ -379,17 +381,51 @@ public boolean updateShiftChange(ShiftDvrpVehicle vehicle, Link link, DrtShift s public void planAssignedShift(ShiftDvrpVehicle vehicle, double timeStep, DrtShift shift) { Schedule schedule = vehicle.getSchedule(); StayTask stayTask = (StayTask) schedule.getCurrentTask(); - if (stayTask instanceof WaitForShiftTask) { - stayTask.setEndTime(Math.max(timeStep, shift.getStartTime())); + if (stayTask instanceof WaitForShiftTask waitForShiftTask) { + if(waitForShiftTask instanceof EDrtWaitForShiftTask eDrtWaitForShiftTask) { + if(eDrtWaitForShiftTask.getChargingTask() != null) { + Task nextTask = Schedules.getNextTask(vehicle.getSchedule()); + if(nextTask instanceof WaitForShiftTask) { + // set +1 to ensure this update happens after next shift start check + nextTask.setEndTime(Math.max(timeStep + 1, shift.getStartTime())); + //append stay task if required + if(Schedules.getLastTask(schedule).equals(nextTask)) { + schedule.addTask(taskFactory.createStayTask(vehicle, nextTask.getEndTime(), shift.getEndTime(), ((WaitForShiftTask) nextTask).getLink())); + } + } else { + throw new RuntimeException(); + } + } else { + stayTask.setEndTime(Math.max(timeStep +1 , shift.getStartTime())); + //append stay task if required + if(Schedules.getLastTask(schedule).equals(stayTask)) { + schedule.addTask(taskFactory.createStayTask(vehicle, stayTask.getEndTime(), shift.getEndTime(), stayTask.getLink())); + } + } + } } } + @Override public void cancelAssignedShift(ShiftDvrpVehicle vehicle, double timeStep, DrtShift shift) { Schedule schedule = vehicle.getSchedule(); StayTask stayTask = (StayTask) schedule.getCurrentTask(); - if (stayTask instanceof WaitForShiftTask) { - stayTask.setEndTime(vehicle.getServiceEndTime()); + if (stayTask instanceof WaitForShiftTask waitForShiftTask) { + if(waitForShiftTask instanceof EDrtWaitForShiftTask eDrtWaitForShiftTask) { + if(eDrtWaitForShiftTask.getChargingTask() != null) { + Task nextTask = Schedules.getNextTask(vehicle.getSchedule()); + if(nextTask instanceof WaitForShiftTask) { + nextTask.setEndTime(vehicle.getServiceEndTime()); + } else { + throw new RuntimeException(); + } + } else { + stayTask.setEndTime(vehicle.getServiceEndTime()); + } + } + } else { + throw new IllegalStateException("Vehicle should be in WaitForShiftTask"); } } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java index 5d983e81f05..6e082f6f7d5 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java @@ -51,10 +51,10 @@ public class DrtShiftDispatcherImpl implements DrtShiftDispatcher { private final String mode; - private Queue unscheduledShifts; - private Queue assignedShifts; - private Queue activeShifts; - private Queue endingShifts; + private SortedSet unscheduledShifts; + private SortedSet assignedShifts; + private SortedSet activeShifts; + private SortedSet endingShifts; private Map, Queue> idleVehiclesQueues; @@ -63,8 +63,8 @@ public class DrtShiftDispatcherImpl implements DrtShiftDispatcher { private final MobsimTimer timer; - private final OperationFacilities operationFacilities; - private final OperationFacilityFinder breakFacilityFinder; + private final OperationFacilities operationFacilities; + private final OperationFacilityFinder breakFacilityFinder; private final ShiftTaskScheduler shiftTaskScheduler; private final Network network; @@ -73,8 +73,8 @@ public class DrtShiftDispatcherImpl implements DrtShiftDispatcher { private final ShiftsParams drtShiftParams; - private final ShiftStartLogic shiftStartLogic; - private final AssignShiftToVehicleLogic assignShiftToVehicleLogic; + private final ShiftStartLogic shiftStartLogic; + private final AssignShiftToVehicleLogic assignShiftToVehicleLogic; public DrtShiftDispatcherImpl(String mode, DrtShifts shifts, Fleet fleet, MobsimTimer timer, OperationFacilities operationFacilities, OperationFacilityFinder breakFacilityFinder, ShiftTaskScheduler shiftTaskScheduler, @@ -84,54 +84,56 @@ public DrtShiftDispatcherImpl(String mode, DrtShifts shifts, Fleet fleet, Mobsim this.shifts = shifts; this.fleet = fleet; this.timer = timer; - this.operationFacilities = operationFacilities; - this.breakFacilityFinder = breakFacilityFinder; + this.operationFacilities = operationFacilities; + this.breakFacilityFinder = breakFacilityFinder; this.shiftTaskScheduler = shiftTaskScheduler; this.network = network; this.eventsManager = eventsManager; this.drtShiftParams = drtShiftParams; - this.shiftStartLogic = shiftStartLogic; - this.assignShiftToVehicleLogic = assignShiftToVehicleLogic; + this.shiftStartLogic = shiftStartLogic; + this.assignShiftToVehicleLogic = assignShiftToVehicleLogic; } - @Override - public void initialize() { + @Override + public void initialize() { - unscheduledShifts = new PriorityQueue<>(Comparator.comparingDouble(DrtShift::getStartTime)); + unscheduledShifts = new TreeSet<>(Comparator.comparingDouble(DrtShift::getStartTime)); unscheduledShifts.addAll(shifts.getShifts().values()); - assignedShifts = new PriorityQueue<>(Comparator.comparingDouble(v -> v.shift().getStartTime())); + assignedShifts = new TreeSet<>(Comparator.comparingDouble(v -> v.shift().getStartTime())); idleVehiclesQueues = new LinkedHashMap<>(); - for(OperationFacility facility: operationFacilities.getDrtOperationFacilities().values()) { - PriorityQueue queue = new PriorityQueue<>((v1, v2) -> String.CASE_INSENSITIVE_ORDER.compare(v1.getId().toString(), v2.getId().toString())); - Set> registeredVehicles = facility.getRegisteredVehicles(); - for (Id registeredVehicle : registeredVehicles) { - queue.add((ShiftDvrpVehicle) fleet.getVehicles().get(registeredVehicle)); - } - idleVehiclesQueues.put( - facility.getId(), - queue - ); - } - activeShifts = new PriorityQueue<>(Comparator.comparingDouble(v -> v.shift().getEndTime())); - endingShifts = new PriorityQueue<>(Comparator.comparingDouble(v -> v.shift().getEndTime())); + for(OperationFacility facility: operationFacilities.getDrtOperationFacilities().values()) { + PriorityQueue queue = new PriorityQueue<>((v1, v2) -> String.CASE_INSENSITIVE_ORDER.compare(v1.getId().toString(), v2.getId().toString())); + Set> registeredVehicles = facility.getRegisteredVehicles(); + for (Id registeredVehicle : registeredVehicles) { + queue.add((ShiftDvrpVehicle) fleet.getVehicles().get(registeredVehicle)); + } + idleVehiclesQueues.put( + facility.getId(), + queue + ); + } + activeShifts = new TreeSet<>(Comparator.comparingDouble(v -> v.shift().getEndTime())); + endingShifts = new TreeSet<>(Comparator.comparingDouble(v -> v.shift().getEndTime())); } - @Override + @Override public void dispatch(double timeStep) { - if(timeStep % drtShiftParams.loggingInterval == 0) { - logger.info(String.format("Active shifts: %s | Assigned shifts: %s | Unscheduled shifts: %s", - activeShifts.size(), assignedShifts.size(), unscheduledShifts.size())); - for (Map.Entry, Queue> queueEntry : idleVehiclesQueues.entrySet()) { - logger.info(String.format("Idle vehicles at facility %s: %d", queueEntry.getKey().toString(), queueEntry.getValue().size())); - } - } + if(timeStep % drtShiftParams.loggingInterval == 0) { + logger.info(String.format("Active shifts: %s | Assigned shifts: %s | Unscheduled shifts: %s", + activeShifts.size(), assignedShifts.size(), unscheduledShifts.size())); + StringJoiner print = new StringJoiner(" | "); + for (Map.Entry, Queue> queueEntry : idleVehiclesQueues.entrySet()) { + print.add(String.format("Idle vehicles at facility %s: %d", queueEntry.getKey().toString(), queueEntry.getValue().size())); + } + logger.info(print.toString()); + } endShifts(timeStep); - if (timeStep % (drtShiftParams.updateShiftEndInterval) == 0) { - updateShiftEnds(timeStep); - } - assignShifts(timeStep); + if (timeStep % (drtShiftParams.updateShiftEndInterval) == 0) { + updateShiftEnds(timeStep); + } + assignShifts(timeStep); startShifts(timeStep); checkBreaks(); } @@ -166,13 +168,13 @@ private void startShifts(double timeStep) { final ShiftEntry assignedShiftEntry = iterator.next(); if (assignedShiftEntry.shift().getStartTime() > timeStep) { shiftTaskScheduler.planAssignedShift(assignedShiftEntry.vehicle(), timeStep, assignedShiftEntry.shift()); - break; + continue; } else if (assignedShiftEntry.shift().getEndTime() < timeStep) { logger.warn("Too late to start shift " + assignedShiftEntry.shift().getId()); shiftTaskScheduler.cancelAssignedShift(assignedShiftEntry.vehicle(), timeStep, assignedShiftEntry.shift()); assignedShiftEntry.vehicle().getShifts().remove(assignedShiftEntry.shift()); iterator.remove(); - continue; + continue; } if (shiftStartLogic.shiftStarts(assignedShiftEntry)) { @@ -193,17 +195,24 @@ private void startShifts(double timeStep) { private void assignShifts(double timeStep) { // Remove elapsed shifts unscheduledShifts.removeIf(shift -> { - if (shift.getStartTime() + drtShiftParams.maxUnscheduledShiftDelay < timeStep ) { - logger.warn("Shift with ID " + shift.getId() + " could not be assigned and is being removed as start time is longer in the past than defined by maxUnscheduledShiftDelay."); + if (shift.getStartTime() + drtShiftParams.maxUnscheduledShiftDelay < timeStep ) { + logger.warn("Shift with ID " + shift.getId() + " could not be assigned and is being removed as start time is longer in the past than defined by maxUnscheduledShiftDelay."); return true; - } - return false; - }); + } + return false; + }); // Assign shifts Set assignableShifts = new LinkedHashSet<>(); - while (!this.unscheduledShifts.isEmpty() && isSchedulable(this.unscheduledShifts.peek(), timeStep)) { - assignableShifts.add(this.unscheduledShifts.poll()); + Iterator unscheduledShiftsIterator = unscheduledShifts.iterator(); + while(unscheduledShiftsIterator.hasNext()) { + DrtShift unscheduledShift = unscheduledShiftsIterator.next(); + if(isSchedulable(unscheduledShift, timeStep)) { + assignableShifts.add(unscheduledShift); + unscheduledShiftsIterator.remove(); + } else { + break; + } } for (DrtShift shift : assignableShifts) { @@ -213,24 +222,24 @@ private void assignShifts(double timeStep) { if (active.shift().getEndTime() > shift.getStartTime()) { break; } - if(shift.getOperationFacilityId().isPresent()) { - //we have to check that the vehicle ends the previous shift at the same facility where - //the new shift is to start. - if(active.shift().getOperationFacilityId().isPresent()) { - if(!active.shift().getOperationFacilityId().get().equals(shift.getOperationFacilityId().get())) { - continue; - } - } else { - Optional nextShiftChangeover = ShiftSchedules.getNextShiftChangeover(active.vehicle().getSchedule()); - if(nextShiftChangeover.isPresent()) { - Verify.verify(nextShiftChangeover.get().getShift().equals(active.shift())); - if(!nextShiftChangeover.get().getFacility().getId().equals(shift.getOperationFacilityId().get())) { - // there is already a shift changeover scheduled elsewhere - continue; - } - } - } - } + if(shift.getOperationFacilityId().isPresent()) { + //we have to check that the vehicle ends the previous shift at the same facility where + //the new shift is to start. + if(active.shift().getOperationFacilityId().isPresent()) { + if(!active.shift().getOperationFacilityId().get().equals(shift.getOperationFacilityId().get())) { + continue; + } + } else { + Optional nextShiftChangeover = ShiftSchedules.getNextShiftChangeover(active.vehicle().getSchedule()); + if(nextShiftChangeover.isPresent()) { + Verify.verify(nextShiftChangeover.get().getShift().equals(active.shift())); + if(!nextShiftChangeover.get().getFacility().getId().equals(shift.getOperationFacilityId().get())) { + // there is already a shift changeover scheduled elsewhere + continue; + } + } + } + } if (assignShiftToVehicleLogic.canAssignVehicleToShift(active.vehicle(), shift)) { vehicle = active.vehicle(); break; @@ -238,29 +247,29 @@ private void assignShifts(double timeStep) { } if (vehicle == null) { - final Iterator iterator; - - if(shift.getOperationFacilityId().isPresent()) { - //shift has to start at specific hub/facility - iterator = idleVehiclesQueues.get(shift.getOperationFacilityId().get()).iterator(); - } else { - //shift can start at random location - IteratorChain iteratorChain = new IteratorChain<>(); - for (Queue value : idleVehiclesQueues.values()) { - iteratorChain.addIterator(value.iterator()); - } - iterator = iteratorChain; - } - - while (iterator.hasNext()) { - final ShiftDvrpVehicle next = iterator.next(); - if (assignShiftToVehicleLogic.canAssignVehicleToShift(next, shift)) { - vehicle = next; - iterator.remove(); - break; - } - } - } + final Iterator iterator; + + if(shift.getOperationFacilityId().isPresent()) { + //shift has to start at specific hub/facility + iterator = idleVehiclesQueues.get(shift.getOperationFacilityId().get()).iterator(); + } else { + //shift can start at random location + IteratorChain iteratorChain = new IteratorChain<>(); + for (Queue value : idleVehiclesQueues.values()) { + iteratorChain.addIterator(value.iterator()); + } + iterator = iteratorChain; + } + + while (iterator.hasNext()) { + final ShiftDvrpVehicle next = iterator.next(); + if (assignShiftToVehicleLogic.canAssignVehicleToShift(next, shift)) { + vehicle = next; + iterator.remove(); + break; + } + } + } if (vehicle != null) { logger.debug("Shift assigned"); @@ -297,37 +306,37 @@ private void endShifts(double timeStep) { throw new IllegalStateException("Shifts don't match!"); } - logger.debug("Scheduling shift end for shift " + next.shift().getId() + " of vehicle " + next.vehicle().getId()); - scheduleShiftEnd(next); - endingShifts.add(next); - iterator.remove(); + logger.debug("Scheduling shift end for shift " + next.shift().getId() + " of vehicle " + next.vehicle().getId()); + scheduleShiftEnd(next); + endingShifts.add(next); + iterator.remove(); + } + } + + private void updateShiftEnds(double timeStep) { + final Iterator endingShiftsIterator = this.endingShifts.iterator(); + while (endingShiftsIterator.hasNext()) { + final ShiftEntry next = endingShiftsIterator.next(); + if (next.shift().isEnded()) { + endingShiftsIterator.remove(); + continue; + } + if (timeStep + drtShiftParams.shiftEndRescheduleLookAhead > next.shift().getEndTime()) { + if (next.vehicle().getShifts().size() > 1) { + updateShiftEnd(next); + } + } else { + break; + } + } + } + + private void updateShiftEnd(ShiftEntry next) { + + if(next.shift().getOperationFacilityId().isPresent()) { + //start and end facility are fixed + return; } - } - - private void updateShiftEnds(double timeStep) { - final Iterator endingShiftsIterator = this.endingShifts.iterator(); - while (endingShiftsIterator.hasNext()) { - final ShiftEntry next = endingShiftsIterator.next(); - if (next.shift().isEnded()) { - endingShiftsIterator.remove(); - continue; - } - if (timeStep + drtShiftParams.shiftEndRescheduleLookAhead > next.shift().getEndTime()) { - if (next.vehicle().getShifts().size() > 1) { - updateShiftEnd(next); - } - } else { - break; - } - } - } - - private void updateShiftEnd(ShiftEntry next) { - - if(next.shift().getOperationFacilityId().isPresent()) { - //start and end facility are fixed - return; - } final List tasks = next.vehicle().getSchedule().getTasks(); @@ -415,31 +424,31 @@ private void scheduleShiftEnd(ShiftEntry endingShift) { } final Coord coord = lastLink.getCoord(); - OperationFacility shiftChangeoverFacility = null; - - //check whether current shift has to end at specific facility - if(endingShift.shift().getOperationFacilityId().isPresent()) { - shiftChangeoverFacility = operationFacilities - .getDrtOperationFacilities() - .get(endingShift.shift().getOperationFacilityId().get()); - } else { - //check whether next shift has to start at specific facility - for (DrtShift shift : endingShift.vehicle().getShifts()) { - if (shift != endingShift.shift()) { - if (shift.getOperationFacilityId().isPresent()) { - shiftChangeoverFacility = operationFacilities - .getDrtOperationFacilities() - .get(shift.getOperationFacilityId().get()); - } - break; - } - } - } - - if(shiftChangeoverFacility == null) { - shiftChangeoverFacility = breakFacilityFinder.findFacilityOfType(coord, - OperationFacilityType.hub).orElseThrow(() -> new RuntimeException("Could not find shift end location!")); - } + OperationFacility shiftChangeoverFacility = null; + + //check whether current shift has to end at specific facility + if(endingShift.shift().getOperationFacilityId().isPresent()) { + shiftChangeoverFacility = operationFacilities + .getDrtOperationFacilities() + .get(endingShift.shift().getOperationFacilityId().get()); + } else { + //check whether next shift has to start at specific facility + for (DrtShift shift : endingShift.vehicle().getShifts()) { + if (shift != endingShift.shift()) { + if (shift.getOperationFacilityId().isPresent()) { + shiftChangeoverFacility = operationFacilities + .getDrtOperationFacilities() + .get(shift.getOperationFacilityId().get()); + } + break; + } + } + } + + if(shiftChangeoverFacility == null) { + shiftChangeoverFacility = breakFacilityFinder.findFacilityOfType(coord, + OperationFacilityType.hub).orElseThrow(() -> new RuntimeException("Could not find shift end location!")); + } Verify.verify(shiftChangeoverFacility.register(endingShift.vehicle().getId()), "Could not register vehicle at facility."); @@ -488,14 +497,14 @@ public void endBreak(ShiftDvrpVehicle vehicle, ShiftBreakTask previousTask) { new VehicleLeftShiftFacilityEvent(timer.getTimeOfDay(), mode, vehicle.getId(), facility.getId())); eventsManager.processEvent( new DrtShiftBreakEndedEvent(timer.getTimeOfDay(), mode, vehicle.getShifts().peek().getId(), - vehicle.getId(), previousTask.getFacility().getLinkId()) + vehicle.getId(), previousTask.getFacility().getLinkId()) ); } public void startBreak(ShiftDvrpVehicle vehicle, Id linkId) { eventsManager.processEvent( new DrtShiftBreakStartedEvent(timer.getTimeOfDay(), mode, - vehicle.getShifts().peek().getId(), vehicle.getId(), linkId) + vehicle.getShifts().peek().getId(), vehicle.getId(), linkId) ); } From 3af17e545de4acf1ad4f322a50e11e520d0dee7f Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Mon, 29 Jul 2024 15:18:50 +0200 Subject: [PATCH 162/213] make FISS integration test less sensible to smaller changes in link events --- .../matsim/contrib/drt/extension/fiss/RunFissDrtScenarioIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/fiss/RunFissDrtScenarioIT.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/fiss/RunFissDrtScenarioIT.java index fc58f3b3b63..120cff4f5a3 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/fiss/RunFissDrtScenarioIT.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/fiss/RunFissDrtScenarioIT.java @@ -184,7 +184,7 @@ public void install() { } run.run(); - Assertions.assertEquals(20842, linkCounter.getLinkLeaveCount()); + Assertions.assertEquals(20000, linkCounter.getLinkLeaveCount(), 2000); } static class LinkCounter implements LinkLeaveEventHandler { From 4fa6530cc84ec4e37e3179745bcc87311c6bd73e Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Mon, 29 Jul 2024 16:06:14 +0200 Subject: [PATCH 163/213] set level of some logging's back from WARN to DEBUG --- .../org/matsim/freight/carriers/controler/CarrierAgent.java | 2 +- .../matsim/freight/carriers/controler/FreightAgentSource.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierAgent.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierAgent.java index 88423d00a1f..da31ae5637d 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierAgent.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierAgent.java @@ -179,7 +179,7 @@ void scoreSelectedPlan() { } scoringFunction.finish(); final double score = scoringFunction.getScore(); - log.warn("score={}", score); + log.debug("score of carrier {} = {}", carrier.getId(), score); carrier.getSelectedPlan().setScore( score ); } void handleEvent(Event event, Id driverId) { diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/FreightAgentSource.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/FreightAgentSource.java index 6b60f14d91b..f5613f1a961 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/FreightAgentSource.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/FreightAgentSource.java @@ -83,7 +83,7 @@ public final class FreightAgentSource implements AgentSource { vehicle = CarriersUtils.getVehicle( freightDriverPlan ); } - log.warn("inserting vehicleId={} into mobsim.", vehicle.getId()); + log.debug("inserting vehicleId={} into mobsim.", vehicle.getId()); qsim.addParkedVehicle( new QVehicleImpl( vehicle ), agent.getCurrentLinkId() ); // yyyyyy should rather use QVehicleFactory. kai, nov'18 From 33d857b6cc5af6d309f02c41fb578e432dc0a905 Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 30 Jul 2024 20:02:48 +0200 Subject: [PATCH 164/213] SimWrapper Dashboard features (#3381) * add explanations to the traffic dashboard, add pt viewer dashboard * add additional description * add avg beeline speed to trip dashboard * added mode share distance distribution * added plot for detailed distance distribution * upscale emission dashboard with sample size --- .../emissions/AirPollutionAnalysis.java | 15 +- .../analysis/population/TripAnalysis.java | 82 +++++ .../traffic/TrafficStatsCalculator.java | 2 +- .../application/options/SampleOptions.java | 7 + .../simwrapper/DefaultDashboardProvider.java | 9 +- .../dashboard/EmissionsDashboard.java | 2 +- .../dashboard/PublicTransitDashboard.java | 28 ++ .../dashboard/TrafficCountsDashboard.java | 2 +- .../dashboard/TrafficDashboard.java | 18 +- .../simwrapper/dashboard/TripDashboard.java | 66 +++- .../matsim/simwrapper/viz/TransitViewer.java | 19 ++ .../simwrapper/dashboard/DashboardTests.java | 1 + .../mode_share_distance_distribution.csv | 300 ++++++++++++++++++ 13 files changed, 533 insertions(+), 18 deletions(-) create mode 100644 contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/PublicTransitDashboard.java create mode 100644 contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/TransitViewer.java create mode 100644 contribs/simwrapper/src/test/resources/mode_share_distance_distribution.csv diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/emissions/AirPollutionAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/emissions/AirPollutionAnalysis.java index dbf40292057..4b54cb14200 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/emissions/AirPollutionAnalysis.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/emissions/AirPollutionAnalysis.java @@ -205,11 +205,11 @@ private void writeOutput(Network network, EmissionsOnLinkEventHandler emissionsE if (link2pollutants.get(linkId).get(pollutant) != null) { emissionValue = link2pollutants.get(linkId).get(pollutant); } - absolute.print(nf.format(emissionValue)); + absolute.print(nf.format(emissionValue * sample.getUpscaleFactor())); Link link = network.getLinks().get(linkId); double emissionPerM = emissionValue / link.getLength(); - perMeter.print(nf.format(emissionPerM)); + perMeter.print(nf.format(emissionPerM * sample.getUpscaleFactor())); } absolute.println(); @@ -246,7 +246,7 @@ private void writeTotal(Network network, EmissionsOnLinkEventHandler emissionsEv total.printRecord("Pollutant", "kg"); for (Pollutant p : Pollutant.values()) { - double val = (sum.getDouble(p) / sample.getSample()) / 1000; + double val = (sum.getDouble(p) * sample.getUpscaleFactor()) / 1000; total.printRecord(p, val < 100_000 && val > 100 ? simple.format(val) : scientific.format(val)); } @@ -286,7 +286,7 @@ private void writeAvroRaster(Network network, Config config, EmissionsOnLinkEven for (int xi = 0; xi < xLength.get(0); xi++) { for (int yi = 0; yi < yLength.get(0); yi++) { Coord coord = raster.getCoordForIndex(xi, yi); - double value = rasterMap.get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi); + double value = rasterMap.get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi) * sample.getUpscaleFactor(); if (xi == 0) yCoords.add((float) coord.getY()); if (yi == 0) xCoords.add((float) coord.getX()); valuesList.add((float) value); @@ -349,7 +349,7 @@ private void writeRaster(Network network, Config config, EmissionsOnLinkEventHan for (int yi = 0; yi < yLength.get(0); yi++) { Coord coord = raster.getCoordForIndex(xi, yi); - double value = rasterMap.get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi); + double value = rasterMap.get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi) * sample.getUpscaleFactor(); if (value == 0) continue; @@ -406,7 +406,7 @@ private void writeTimeDependentRaster(Network network, Config config, EmissionsO for (TimeBinMap.TimeBin> timeBin : timeBinMap.getTimeBins()) { Coord coord = raster.getCoordForIndex(xi, yi); - double value = timeBin.getValue().get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi); + double value = timeBin.getValue().get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi) * sample.getUpscaleFactor(); if (value == 0) continue; @@ -467,7 +467,8 @@ private void writeTimeDependentAvroRaster(Network network, Config config, Emissi if (yi == 0 && isFirst) xCoords.add((float) coord.getX()); - valuesList.add((float) timeBin.getValue().get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi)); + double value = timeBin.getValue().get(Pollutant.CO2_TOTAL).getValueByIndex(xi, yi) * sample.getUpscaleFactor(); + valuesList.add((float) value); } } } diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/population/TripAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/population/TripAnalysis.java index 4da59a48294..6d6ee80f8c1 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/population/TripAnalysis.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/population/TripAnalysis.java @@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; +import org.apache.commons.math3.analysis.interpolation.LoessInterpolator; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.locationtech.jts.geom.Coordinate; @@ -32,6 +33,7 @@ import java.math.RoundingMode; import java.nio.file.Files; import java.util.*; +import java.util.stream.IntStream; import static tech.tablesaw.aggregate.AggregateFunctions.count; @@ -41,6 +43,7 @@ produces = { "mode_share.csv", "mode_share_per_dist.csv", "mode_users.csv", "trip_stats.csv", "mode_share_per_%s.csv", "population_trip_stats.csv", "trip_purposes_by_hour.csv", + "mode_share_distance_distribution.csv", "mode_choices.csv", "mode_choice_evaluation.csv", "mode_choice_evaluation_per_mode.csv", "mode_confusion_matrix.csv", "mode_prediction_error.csv" } @@ -109,6 +112,25 @@ private static int durationToSeconds(String d) { return (Integer.parseInt(split[0]) * 60 * 60) + (Integer.parseInt(split[1]) * 60) + Integer.parseInt(split[2]); } + private static double[] calcHistogram(double[] data, double[] bins) { + + double[] hist = new double[bins.length - 1]; + + for (int i = 0; i < bins.length - 1; i++) { + + double binStart = bins[i]; + double binEnd = bins[i + 1]; + + // The last right bin edge is inclusive, which is consistent with the numpy implementation + if (i == bins.length - 2) + hist[i] = Arrays.stream(data).filter(d -> d >= binStart && d <= binEnd).count(); + else + hist[i] = Arrays.stream(data).filter(d -> d >= binStart && d < binEnd).count(); + } + + return hist; + } + @Override public Integer call() throws Exception { @@ -247,6 +269,8 @@ public Integer call() throws Exception { writeTripPurposes(joined); + writeTripDistribution(joined); + return 0; } @@ -293,6 +317,7 @@ private void writeTripStats(Table trips) throws IOException { Object2IntMap n = new Object2IntLinkedOpenHashMap<>(); Object2LongMap travelTime = new Object2LongOpenHashMap<>(); Object2LongMap travelDistance = new Object2LongOpenHashMap<>(); + Object2LongMap beelineDistance = new Object2LongOpenHashMap<>(); for (Row trip : trips) { String mainMode = trip.getString("main_mode"); @@ -300,6 +325,7 @@ private void writeTripStats(Table trips) throws IOException { n.mergeInt(mainMode, 1, Integer::sum); travelTime.mergeLong(mainMode, durationToSeconds(trip.getString("trav_time")), Long::sum); travelDistance.mergeLong(mainMode, trip.getLong("traveled_distance"), Long::sum); + beelineDistance.mergeLong(mainMode, trip.getLong("euclidean_distance"), Long::sum); } try (CSVPrinter printer = new CSVPrinter(Files.newBufferedWriter(output.getPath("trip_stats.csv")), CSVFormat.DEFAULT)) { @@ -338,6 +364,13 @@ private void writeTripStats(Table trips) throws IOException { } printer.println(); + printer.print("Avg. beeline speed [km/h]"); + for (String m : modeOrder) { + double speed = (beelineDistance.getLong(m) / 1000d) / (travelTime.getLong(m) / (60d * 60d)); + printer.print(new BigDecimal(speed).setScale(2, RoundingMode.HALF_UP)); + } + printer.println(); + printer.print("Avg. distance per trip [km]"); for (String m : modeOrder) { double avg = (travelDistance.getLong(m) / 1000d) / (n.getInt(m)); @@ -458,6 +491,55 @@ private void writeTripPurposes(Table trips) { } + private void writeTripDistribution(Table trips) throws IOException { + + Map dists = new LinkedHashMap<>(); + + // Note that the results of this interpolator are consistent with the one performed in matsim-python-tools + // This makes the results comparable with reference data, changes here will also require changes in the python package + LoessInterpolator inp = new LoessInterpolator(0.05, 0); + + long max = distGroups.get(distGroups.size() - 3) + distGroups.get(distGroups.size() - 2); + + double[] bins = IntStream.range(0, (int) (max / 100)).mapToDouble(i -> i * 100).toArray(); + double[] x = Arrays.copyOf(bins, bins.length - 1); + + for (String mode : modeOrder) { + double[] distances = trips.where( + trips.stringColumn("main_mode").equalsIgnoreCase(mode)) + .numberColumn("traveled_distance").asDoubleArray(); + + double[] hist = calcHistogram(distances, bins); + + double[] y = inp.smooth(x, hist); + dists.put(mode, y); + } + + try (CSVPrinter printer = new CSVPrinter(Files.newBufferedWriter(output.getPath("mode_share_distance_distribution.csv")), CSVFormat.DEFAULT)) { + + printer.print("dist"); + for (String s : modeOrder) { + printer.print(s); + } + printer.println(); + + for (int i = 0; i < x.length; i++) { + + double sum = 0; + for (String s : modeOrder) { + sum += Math.max(0, dists.get(s)[i]); + } + + printer.print(x[i]); + for (String s : modeOrder) { + double value = Math.max(0, dists.get(s)[i]) / sum; + printer.print(value); + } + printer.println(); + } + } + } + /** * How shape file filtering should be applied. */ diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/traffic/TrafficStatsCalculator.java b/contribs/application/src/main/java/org/matsim/application/analysis/traffic/TrafficStatsCalculator.java index b6d29a5319b..f24ad081146 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/traffic/TrafficStatsCalculator.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/traffic/TrafficStatsCalculator.java @@ -13,7 +13,7 @@ /** * Class to calculate the traffic congestion index based on the paper - * "A Traffic Congestion Assessment Method for Urban Road Networks Based on Speed Performance Index" by Feifei He, Xuedong Yan*, Yang Liu, Lu Ma. + * "A Traffic Congestion Assessment Method for Urban Road Networks Based on Speed Performance Index" by Feifei He, Xuedong Yan, Yang Liu, Lu Ma. */ public final class TrafficStatsCalculator { diff --git a/contribs/application/src/main/java/org/matsim/application/options/SampleOptions.java b/contribs/application/src/main/java/org/matsim/application/options/SampleOptions.java index 6a1cba85545..f9ac12190a9 100644 --- a/contribs/application/src/main/java/org/matsim/application/options/SampleOptions.java +++ b/contribs/application/src/main/java/org/matsim/application/options/SampleOptions.java @@ -124,6 +124,13 @@ public double getSample() { return sample; } + /** + * Return factor that is used to upscale the sample size. + */ + public double getUpscaleFactor() { + return 1.0 / sample; + } + private void setSize(double sample) { this.set = true; this.sample = sample; diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/DefaultDashboardProvider.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/DefaultDashboardProvider.java index d7befe82fc0..9a6f00f9520 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/DefaultDashboardProvider.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/DefaultDashboardProvider.java @@ -19,10 +19,13 @@ public List getDashboards(Config config, SimWrapper simWrapper) { List result = new ArrayList<>(List.of( new OverviewDashboard(), new TripDashboard(), - new TrafficDashboard(), - new StuckAgentDashboard() + new TrafficDashboard() )); + if (config.transit().isUseTransit()) { + result.add(new PublicTransitDashboard()); + } + if (config.counts().getCountsFileName() != null) { result.add(new TrafficCountsDashboard()); } @@ -35,6 +38,8 @@ public List getDashboards(Config config, SimWrapper simWrapper) { result.add(new NoiseDashboard()); } + result.add(new StuckAgentDashboard()); + return result; } diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/EmissionsDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/EmissionsDashboard.java index b12052b7c7a..a7487fd625b 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/EmissionsDashboard.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/EmissionsDashboard.java @@ -20,7 +20,7 @@ public class EmissionsDashboard implements Dashboard { public void configure(Header header, Layout layout) { header.title = "Emissions"; - header.description = "Shows the emissions footprint and spatial distribution."; + header.description = "Shows the emissions footprint and spatial distribution. Shown values are already upscaled from simulated sample size."; layout.row("links") diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/PublicTransitDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/PublicTransitDashboard.java new file mode 100644 index 00000000000..6903902d098 --- /dev/null +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/PublicTransitDashboard.java @@ -0,0 +1,28 @@ +package org.matsim.simwrapper.dashboard; + +import org.matsim.simwrapper.Dashboard; +import org.matsim.simwrapper.Header; +import org.matsim.simwrapper.Layout; +import org.matsim.simwrapper.viz.TransitViewer; + +/** + * Standard dashboard for public transit. + */ +public class PublicTransitDashboard implements Dashboard { + + @Override + public void configure(Header header, Layout layout) { + + header.title = "Public Transit"; + header.tab = "PT"; + header.triggerPattern = "*output_transitSchedule*xml*"; + + layout.row("viewer").el(TransitViewer.class, (viz, data) -> { + viz.title = "Transit Viewer"; + viz.height = 12d; + viz.description = "Visualize the transit schedule."; + viz.network = "*output_network.xml.gz"; + viz.transitSchedule = data.output("*output_transitSchedule.xml.gz"); + }); + } +} diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/TrafficCountsDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/TrafficCountsDashboard.java index 2bd83f1baba..8b65fba29ec 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/TrafficCountsDashboard.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/TrafficCountsDashboard.java @@ -69,7 +69,7 @@ public TrafficCountsDashboard withQualityLabels(List limits, List { + viz.backgroundColor = "transparent"; + viz.content = """ + ### Notes + - The speed performance index is the ratio of average travel speed and the maximum permissible road speed. + A performance index of 0.5, means that the average speed is half of the maximum permissible speed. A road with a performance index below 0.5 is considered to be in a congested state. + - The congestion index is the ratio of time a road is in an uncongested state. 0.5 means that a road is congested half of the time. A road with 1.0 is always uncongested. + + cf. *A Traffic Congestion Assessment Method for Urban Road Networks Based on Speed Performance Index* by Feifei He, Xuedong Yan*, Yang Liu, Lu Ma. + """; + }); + } } diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/TripDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/TripDashboard.java index 28078cbd24b..7603da2b791 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/TripDashboard.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/TripDashboard.java @@ -11,7 +11,9 @@ import org.matsim.simwrapper.Layout; import org.matsim.simwrapper.viz.*; import tech.tablesaw.plotly.components.Axis; +import tech.tablesaw.plotly.components.Line; import tech.tablesaw.plotly.traces.BarTrace; +import tech.tablesaw.plotly.traces.ScatterTrace; import javax.annotation.Nullable; import java.io.BufferedReader; @@ -40,6 +42,8 @@ public class TripDashboard implements Dashboard { private String groupedRefCsv; @Nullable private String[] categories; + @Nullable + private String distanceRefCsv; private String[] args; @@ -83,6 +87,14 @@ private static String[] detectCategories(String groupedRefCsv) { } } + /** + * This enables detailed analysis of the distance distribution. + */ + public TripDashboard withDistanceDistribution(String modeShareDistRefCsv) { + this.distanceRefCsv = modeShareDistRefCsv; + return this; + } + /** * Set grouped reference data. Will enable additional tab with analysis for subgroups of the population. * @@ -257,6 +269,7 @@ public void configure(Header header, Layout layout) { }); + createDistancePlot(layout, args, tab); layout.row("departures", tab).el(Plotly.class, (viz, data) -> { @@ -306,6 +319,57 @@ public void configure(Header header, Layout layout) { } + private void createDistancePlot(Layout layout, String[] args, String tab) { + + layout.row("dist-dist", tab).el(Plotly.class, (viz, data) -> { + + viz.title = "Detailed distance distribution"; + viz.description = "by mode."; + viz.layout = tech.tablesaw.plotly.components.Layout.builder() + .xAxis(Axis.builder().title("Distance [m]").build()) + .yAxis(Axis.builder().title("Share").build()) + .showLegend(false) + .build(); + + viz.colorRamp = ColorScheme.Viridis; + viz.interactive = Plotly.Interactive.dropdown; + + Plotly.DataSet ds = viz.addDataset(data.compute(TripAnalysis.class, "mode_share_distance_distribution.csv", args)) + .pivot(List.of("dist"), "main_mode", "share") + .constant("source", "Sim"); + + viz.addTrace(ScatterTrace.builder(Plotly.INPUT, Plotly.INPUT) + .mode(ScatterTrace.Mode.LINE) + .build(), + ds.mapping() + .name("main_mode") + .x("dist") + .y("share") + ); + + if (distanceRefCsv != null) { + viz.description += " Dashed line represents the reference data."; + + Plotly.DataSet ref = viz.addDataset(data.resource(distanceRefCsv)) + .pivot(List.of("dist"), "main_mode", "share") + .constant("source", "Ref"); + + viz.addTrace(ScatterTrace.builder(Plotly.INPUT, Plotly.INPUT) + .mode(ScatterTrace.Mode.LINE) + .line(Line.builder().dash(Line.Dash.DASH).color("black").build()) + .build(), + ref.mapping() + .name("main_mode") + .text("source") + .x("dist") + .y("share") + ); + } + + }); + + } + private void createChoiceTab(Layout layout, String[] args) { layout.row("choice-intro", "Mode Choice").el(TextBlock.class, (viz, data) -> { @@ -421,8 +485,6 @@ private void createGroupedTab(Layout layout, String[] args) { viz.interactive = Plotly.Interactive.dropdown; - // TODO: modes are not separated into different traces - // probably dropdown config in plotly needs to be extended Plotly.DataMapping ds = viz.addDataset(data.computeWithPlaceholder(TripAnalysis.class, "mode_share_per_%s.csv", cat)) .pivot(List.of("main_mode", "dist_group", cat), "source", "share") .normalize(List.of("dist_group", "source", cat), "share") diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/TransitViewer.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/TransitViewer.java new file mode 100644 index 00000000000..ff9e8176b60 --- /dev/null +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/TransitViewer.java @@ -0,0 +1,19 @@ +package org.matsim.simwrapper.viz; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Transit viewer for pt schedules. + */ +public class TransitViewer extends Viz { + + @JsonProperty(required = true) + public String network; + + @JsonProperty(required = true) + public String transitSchedule; + + public TransitViewer() { + super("transit"); + } +} diff --git a/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java b/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java index 0f5b273b809..2a248f2e1ea 100644 --- a/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java +++ b/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/DashboardTests.java @@ -79,6 +79,7 @@ void tripRef() { TripDashboard dashboard = new TripDashboard("mode_share_ref.csv", "mode_share_per_dist_ref.csv", "mode_users_ref.csv") .withGroupedRefData("mode_share_per_group_dist_ref.csv") + .withDistanceDistribution("mode_share_distance_distribution.csv") .withChoiceEvaluation(true); run(dashboard); diff --git a/contribs/simwrapper/src/test/resources/mode_share_distance_distribution.csv b/contribs/simwrapper/src/test/resources/mode_share_distance_distribution.csv new file mode 100644 index 00000000000..fd654629c14 --- /dev/null +++ b/contribs/simwrapper/src/test/resources/mode_share_distance_distribution.csv @@ -0,0 +1,300 @@ +dist,car,bike,pt,ride,walk +0,0.003944185709709211,0.03574277628200462,0.0,0.00037518566775610664,0.9599378523405301 +100,0.011701245224666933,0.06340817090597038,0.0001121407069974153,0.0042250894716089485,0.9205533536907563 +200,0.019169744514796645,0.0893122044564802,0.0029477228742061396,0.007943944214489625,0.8806263839400273 +300,0.026454120383840485,0.11387016806273764,0.005852946985418339,0.01157440300941457,0.8422483615585888 +400,0.03358969683040535,0.13726864579468073,0.00883146182418116,0.01512659005423139,0.8051836054965014 +500,0.04061323303247179,0.1597872858612186,0.011867749118957528,0.018614271787587497,0.7691174601997646 +600,0.04784678709775937,0.18276920810315928,0.015044169123967811,0.022210598702522306,0.7321292369725912 +700,0.05734213014395564,0.2063976466031354,0.020761095019876587,0.027226351467094633,0.6882727767659378 +800,0.06816214612398162,0.23075623072886828,0.02809996433770487,0.03334978383688804,0.6396318749725572 +900,0.08024003137598233,0.2537713669048177,0.03722715420046467,0.04053105229077874,0.5882303952279565 +1000,0.09364179803228202,0.27369856857082314,0.04819638462547296,0.04853551992162743,0.5359277288497946 +1100,0.10815209473295054,0.2896612754900817,0.061088691181933455,0.05700637493902756,0.48409156365600664 +1200,0.1232212719481538,0.3019622446542897,0.07559986698022046,0.06546549661451352,0.4337511198028226 +1300,0.13836634275344512,0.3108373606129935,0.09091282143275427,0.07344298190904162,0.3864404932917656 +1400,0.15305940553232467,0.3166167362865903,0.106622022782901,0.08054229035462031,0.34315954504356383 +1500,0.16718472705231266,0.3196662233207097,0.12243086717410893,0.0866287797100008,0.30408940274286794 +1600,0.18074160725323074,0.31998662551253926,0.13803737572256664,0.09151578936071274,0.26971860215095056 +1700,0.1935482723020434,0.31817337820339026,0.15321472621092924,0.09518315363206561,0.23988046965157156 +1800,0.20532034709529492,0.31611869272157034,0.1679915712780288,0.09760140565798013,0.21296798324712582 +1900,0.21580176882702776,0.3146373506893864,0.18231537962307767,0.09915606961335534,0.18808943124715283 +2000,0.22468765695699847,0.3135340991553317,0.19583828064196956,0.10039147352520297,0.1655484897204973 +2100,0.2320390038133107,0.3116926400097604,0.20855096231240602,0.10166512340515747,0.14605227045936547 +2200,0.2380819792506679,0.30869778321984614,0.22053019447943822,0.10310428120772884,0.12958576184231907 +2300,0.24319551277452806,0.30508552753141654,0.2313966740266772,0.1046602681206329,0.11566201754674531 +2400,0.24740978487991802,0.3017946569397511,0.24027214876964206,0.10619319093791682,0.10433021847277195 +2500,0.25147380264601127,0.29858419290780464,0.24745094294156134,0.10784057535174722,0.09465048615287541 +2600,0.2557081800597713,0.2944242245483245,0.254338405626125,0.10983364707192515,0.08569554269385418 +2700,0.26005333523487556,0.28838565315986364,0.26158066268749924,0.11234778706359465,0.07763256185416688 +2800,0.26438416817880983,0.280611150092087,0.26888318706237135,0.11521145502857368,0.07091003963815808 +2900,0.2682783800528302,0.2726124724825396,0.2756396595690925,0.11833178417595261,0.06513770371958504 +3000,0.27132169151827706,0.26621281194912927,0.281363176346151,0.12160735741899721,0.05949496276744551 +3100,0.2737623173544646,0.2613722495444328,0.28602764052844565,0.12465212676448884,0.054185665808168096 +3200,0.2752050644701451,0.25765183237406514,0.29053676388248717,0.12692664007901375,0.0496796991942889 +3300,0.2755335668276074,0.25414256527537704,0.2961907003290296,0.12822749403075626,0.045905673537229595 +3400,0.27546962770627187,0.24959144103020722,0.3038254719339772,0.128650706320345,0.04246275300919872 +3500,0.275852888106488,0.24461016400363972,0.31218634809445833,0.12807332486763146,0.03927727492778241 +3600,0.2767344858836351,0.24055620257468846,0.319580451397353,0.12682070092540043,0.03630815921892315 +3700,0.27805269721474923,0.23775684456973434,0.32586250733517447,0.12497622419270152,0.033351726687640526 +3800,0.27990378773934443,0.23490832801299452,0.331806257334882,0.12301388863447164,0.03036773827830728 +3900,0.2824088112165455,0.2310003638838484,0.33771130717376985,0.12131495561119951,0.027564562114636655 +4000,0.2852664175352708,0.22624522603645245,0.3435830853261446,0.11963105302180563,0.025274218080326673 +4100,0.28757227850383676,0.22219425556166225,0.34895088956114434,0.11810340256156933,0.023179173811787322 +4200,0.2892860820110079,0.21950746602333254,0.35266462797361464,0.11730689319530663,0.021234930796738084 +4300,0.2905846066726926,0.21817348003240541,0.3544434350048095,0.11696017192331501,0.01983830636677753 +4400,0.29079767729915024,0.21832389444644654,0.3552632635110481,0.11671696692773488,0.01889819781562023 +4500,0.29054464552643655,0.2187565545308431,0.35621331692068825,0.11644817822293935,0.01803730479909268 +4600,0.29071376079094585,0.21815056970721644,0.35814530168997827,0.11602278248671279,0.016967585325146833 +4700,0.29149314706948726,0.21628524084231726,0.3611948723023975,0.11521754980569271,0.01580918998010539 +4800,0.2927416557039059,0.21329664797980755,0.36484248837838756,0.11448678443678055,0.014632423501118458 +4900,0.2939283284766885,0.2093825114338426,0.36909058733655126,0.11419257101424245,0.01340600173867514 +5000,0.2943703318843527,0.20503505319621854,0.3740579024965238,0.11425386578069209,0.012282846642212707 +5100,0.2947281320102329,0.20064785365238091,0.37920970585179475,0.11399087352866029,0.011423434956931168 +5200,0.2952005810632277,0.1966183253462185,0.3842091954611987,0.11297690633918127,0.010994991790173709 +5300,0.2954694412637997,0.19305650254355664,0.38862751336965484,0.11200435977565158,0.01084218304733732 +5400,0.2956013995192241,0.19003237035082865,0.39145872828055284,0.11198568246374727,0.010921819385647139 +5500,0.295920289526642,0.18765361137233574,0.3928612135544049,0.11245785812593388,0.01110702742068355 +5600,0.29620274791867335,0.18602174454261,0.3939712285519109,0.11278590827065553,0.011018370716150317 +5700,0.29700022366082723,0.18460542080407022,0.3953244047532656,0.1124379144039675,0.010632036377869396 +5800,0.2991712652148869,0.18316762386679863,0.3956759916902435,0.11177576119688537,0.010209358031185575 +5900,0.30281068623960566,0.18107647112858022,0.3948546754217751,0.1112549206294131,0.010003246580626022 +6000,0.30760418385322613,0.17801668245256075,0.39340985019348257,0.11105953395226086,0.009909749548469605 +6100,0.3120780594034644,0.17430955427982733,0.39273877608556473,0.1112310729291791,0.009642537301964448 +6200,0.3149138339517079,0.17060832803704515,0.39421250391680623,0.11101290406126946,0.009252430033171307 +6300,0.3163211386544086,0.16688128870624544,0.39833815779540177,0.10963883358605299,0.008820581257890986 +6400,0.3168885716270779,0.1631029587545106,0.4039846665931847,0.10748564138323057,0.008538161641996302 +6500,0.3163853132336465,0.1601672329456284,0.40972902212947393,0.10514820322266033,0.008570228468590872 +6600,0.3146552775257205,0.15894417720988466,0.4148907108245583,0.1029047418962418,0.008605092543594872 +6700,0.31178450759837123,0.1589825476919096,0.42054070390500253,0.10040983964878102,0.008282401155935619 +6800,0.30765869257616435,0.15897938297567632,0.42790233035724856,0.09788817923493068,0.007571414855980117 +6900,0.3031234488944087,0.15835248013794465,0.43562916456461576,0.09608202872773462,0.006812877675296376 +7000,0.30059353222822577,0.15649830655749544,0.4406048531416794,0.09599479772562099,0.00630851034697845 +7100,0.30147734178805335,0.15348495830904818,0.44207247110851283,0.09697598730724549,0.005989241487140272 +7200,0.30477037670371454,0.15043709304413938,0.44132338730885484,0.09798080768138748,0.005488335261903595 +7300,0.30931379002328574,0.14744495887545409,0.4391650248839597,0.09926294271788191,0.004813283499418607 +7400,0.3145250031363783,0.1441665231160985,0.4361382426512812,0.10084213626174753,0.00432809483449452 +7500,0.3199953787910249,0.1399930976671494,0.4335633611166701,0.1022618051664066,0.004186357258748942 +7600,0.3255444419424304,0.13491940666015817,0.4318459378422744,0.10330157780809669,0.004388635747040414 +7700,0.33066978269969555,0.1303864944222729,0.4305132883122282,0.10356744233071624,0.004862992235087065 +7800,0.3346043891458717,0.1269827960715251,0.4302755165111089,0.10296319610511989,0.005174102166374413 +7900,0.3360715638175254,0.12519883396270184,0.43200679058006564,0.10144914081550105,0.005273670824206123 +8000,0.334640790446691,0.12477426399902476,0.43573008222127113,0.09924847720302252,0.005606386129990566 +8100,0.33213142714296695,0.12443653103813718,0.4395962197986949,0.0976268418752624,0.0062089801449385406 +8200,0.33107092875929944,0.12301440992229622,0.4416068653574643,0.09738599288239812,0.006921803078541837 +8300,0.3322562552375935,0.12071335448683616,0.44175999507415387,0.09785345887779752,0.007416936323619015 +8400,0.3343026623829796,0.11857176277621778,0.44152588643373936,0.09815898784420019,0.007440700562863161 +8500,0.33674968239776865,0.11653183762443622,0.4408253211737455,0.09863097778223112,0.007262181021818691 +8600,0.33912167321391457,0.11504978101230556,0.4399428826279596,0.098746063513719,0.007139599632101268 +8700,0.34161552574285703,0.11377864300132756,0.43921050150302954,0.09829491376650987,0.007100415986275998 +8800,0.34345221253717667,0.11244637975200669,0.43954782701958567,0.09736731572590539,0.007186264965325571 +8900,0.34396420494945923,0.11150514754309751,0.4412610391057008,0.09613948545629122,0.007130122945451008 +9000,0.3427447518662358,0.11145571035801106,0.44449734501386234,0.09452926480212648,0.00677292795976445 +9100,0.33889285241848643,0.11253183053236336,0.45031265872217896,0.09196385741190528,0.006298800915065851 +9200,0.3336669482783479,0.1134892023479546,0.45865681683120374,0.08819420623329507,0.005992826309198492 +9300,0.3289025705331273,0.11348663993291781,0.46731014926673503,0.08447376399968726,0.005826876267532717 +9400,0.32493268245886175,0.11252817183693045,0.4750992797553844,0.08170200775760447,0.0057378581912189775 +9500,0.32214693234402464,0.1106579594925726,0.48173691905293803,0.07995360401807224,0.005504585092392341 +9600,0.3212856976546727,0.10798132357698269,0.4866778855681674,0.07888060651350967,0.005174486686667575 +9700,0.3231233065511186,0.10451121792877666,0.4882523772684013,0.0790186948898093,0.005094403361894107 +9800,0.326591288702599,0.10233748770925298,0.4867177339140384,0.07934799272908354,0.005005496945026043 +9900,0.33033199309304595,0.10223317100731696,0.48295479127151086,0.07964759443149812,0.004832450196628059 +10000,0.332623476986607,0.10392322548495701,0.47831054579067794,0.08034515909139255,0.004797592646365311 +10100,0.33349673860375345,0.1064764414583982,0.4736181791737175,0.08136887706342233,0.0050397637007084245 +10200,0.33432874916821775,0.10839986317417392,0.46940861773685993,0.08239100408191506,0.0054717658388332285 +10300,0.33663453365083645,0.10770460087860513,0.46633675581615114,0.08337864074198886,0.0059454689124185025 +10400,0.3404049839843345,0.10441995340275494,0.46428750916833894,0.08460044534143857,0.0062871081031330295 +10500,0.34365790107945965,0.09964272875511318,0.46364958750285873,0.08671726100033575,0.006332521662232755 +10600,0.34552044112406316,0.09458183118584063,0.4651552779891012,0.0887975232378272,0.005944926463167861 +10700,0.3466808424969561,0.08992592353099621,0.46809316115262406,0.09004150177341785,0.005258571046005839 +10800,0.3476540383110092,0.08531568124768088,0.4715528688669912,0.09077744628192347,0.004699965292395249 +10900,0.3487618868010548,0.08021569909171704,0.47450283652222763,0.09179030665719705,0.0047292709278034875 +11000,0.34981810379387535,0.0756182560815686,0.4766986605697859,0.09269930852597585,0.005165671028794336 +11100,0.35069008988381656,0.07199811807143205,0.4781583176488935,0.09344522991095218,0.005708244484905714 +11200,0.3512373404433965,0.07004144053928892,0.47918590883550166,0.09311988712594702,0.0064154230558660305 +11300,0.3510728703568192,0.06988528846316891,0.4814511810046708,0.09042664919057947,0.007164010984761484 +11400,0.3501659797384926,0.07119782536102774,0.4849013222420671,0.08594282610847258,0.0077920465499397755 +11500,0.3502266428625708,0.07244678514010582,0.48726891172242254,0.08172118958629243,0.008336470688608292 +11600,0.3515476656858425,0.07332265456510285,0.48723536488396574,0.07919064759050176,0.0087036672745871 +11700,0.35280716517037564,0.07392414008446771,0.48688809612729905,0.07788442160756133,0.008496177010296136 +11800,0.3535518317940175,0.07488697212045167,0.4877126534366569,0.07622975764465151,0.007618785004222498 +11900,0.3532559622571539,0.07630204763313102,0.48968744124971497,0.07443407018363783,0.006320478676362388 +12000,0.3515930492142177,0.07766164992831871,0.4925650844213227,0.07325799694409808,0.004922219492042807 +12100,0.3486746530901627,0.0786184358762612,0.49575026770104924,0.07322696307157492,0.0037296802609520364 +12200,0.3459631830156185,0.07910539121020793,0.49734216915848095,0.07471306045813585,0.0028761961575567967 +12300,0.34515164645623286,0.07852330317132618,0.497099722911959,0.07690528383052488,0.002320043629957131 +12400,0.3459692806589574,0.07614271216448953,0.49751775821913646,0.07829200754828933,0.0020782414091272796 +12500,0.3473294269536054,0.07284667617898927,0.49909875988414526,0.078785545697462,0.0019395912857979472 +12600,0.3492697734782812,0.07055652236622659,0.4993771084837752,0.07887081410385641,0.0019257815678606154 +12700,0.35165913759661094,0.06930984359987807,0.49734401770347036,0.0793690132210364,0.0023179878790042198 +12800,0.3534330142705426,0.0685168380910896,0.4942301979699518,0.08060951994893653,0.0032104297194793657 +12900,0.35421885101175854,0.06776758717632732,0.49180707969249465,0.0819005661128331,0.004305916006586208 +13000,0.3540822179979868,0.0661512996857427,0.4919734187183986,0.08253613716916212,0.005256926428709651 +13100,0.35342829486563304,0.06405367530755271,0.49394237720987055,0.08266669727070296,0.005908955346240877 +13200,0.3527830056486237,0.062079886000871755,0.49724567618502824,0.08170438670049396,0.006187045464982326 +13300,0.35118847649542645,0.060669747155702516,0.5014068771485422,0.08043809680516903,0.006296802395159802 +13400,0.3496204769128433,0.05942459609269626,0.5049403839900514,0.07963710509984248,0.006377437904566406 +13500,0.3495314643746348,0.057607537059823515,0.5070270014551675,0.07942874580916505,0.006405251301209198 +13600,0.3512771833636974,0.05467792754601138,0.5088506982237178,0.0792095850794595,0.005984605787114015 +13700,0.3536751452904462,0.05190061697309672,0.5107738723328092,0.0786834845029321,0.004966880900715792 +13800,0.354742578974646,0.05086258511488499,0.5128743614793818,0.07780940769315979,0.00371106673792734 +13900,0.35337846055225414,0.05129948384736346,0.5141394594794085,0.07826314837774705,0.0029194477432267353 +14000,0.3502608353310682,0.05176879006408448,0.5146490409198109,0.08031357999632413,0.0030077536887120047 +14100,0.3479646876052328,0.052001256018598334,0.5126737098783506,0.08369621619637188,0.0036641303014464765 +14200,0.3467724704687371,0.05234536611327431,0.5094025274461869,0.08721332470421704,0.004266311267584765 +14300,0.3458939420186927,0.05283868653849691,0.5069653056867282,0.08982480736812844,0.004477258387953727 +14400,0.34419383949094845,0.05317154579641435,0.5077953632376326,0.09054675442316235,0.0042924970518421 +14500,0.34206579427473216,0.0533915811873866,0.5105773837658292,0.0900344684454732,0.003930772326578891 +14600,0.34096457737932545,0.0531642950978982,0.5137539489580658,0.08847091840444228,0.003646260160268298 +14700,0.34185829504357707,0.05206629441210561,0.5153786536953597,0.08705653960769522,0.0036402172412623502 +14800,0.3451136746853569,0.051363986408669876,0.5139185494433137,0.08605099480616986,0.0035527946564896744 +14900,0.34876836765395003,0.05134269666917897,0.5119371007087012,0.0848413259434568,0.003110509024712872 +15000,0.34987479519923204,0.051848430797233586,0.5123654205637322,0.08354519285053809,0.0023661605892641006 +15100,0.35073491475575935,0.05160374430672114,0.5132647067219768,0.08266891528617965,0.0017277189293630518 +15200,0.3533769908219431,0.04982294800478374,0.51286121936596,0.0824108546089649,0.0015279871983482267 +15300,0.35829879100781925,0.047619887984084106,0.5081203160440892,0.0843046766430162,0.0016563283209913118 +15400,0.36438903901491226,0.046767064832046214,0.4994026972613257,0.08769563691522099,0.0017455619764948213 +15500,0.3703076027775079,0.04560064577822244,0.4919479639255102,0.09047439801465251,0.0016693895041069008 +15600,0.37644880054132307,0.043149337858934884,0.48747282882555154,0.0914725597900988,0.0014564729840916718 +15700,0.3832533527154736,0.03987087187931813,0.4846315317068988,0.09105568446572862,0.001188559232580744 +15800,0.38911481145173965,0.036635718038923376,0.483185340127183,0.09012260707422778,0.0009415233079263451 +15900,0.39333782273404705,0.034346239793475515,0.48148048326239373,0.09007831588833208,0.0007571383217516961 +16000,0.39671288097581386,0.03387630220257963,0.47827303537421684,0.09060979644498543,0.0005279850024043422 +16100,0.3998092415304151,0.03369447134976605,0.4757602526959003,0.09048109019026992,0.00025494423364862264 +16200,0.40144457611037515,0.03301595193542206,0.47597561517437054,0.08951300056839265,5.085621143955609e-05 +16300,0.40307373382750894,0.0317049768812926,0.47757465657186055,0.087646632719338,0.0 +16400,0.40567004311313576,0.030514899198242473,0.4782678421523515,0.08554721553627018,0.0 +16500,0.40777822694196014,0.030177353127346283,0.47763707434011793,0.08440734559057571,0.0 +16600,0.4081581418343006,0.030722333058722327,0.47742204736276,0.0836974777442171,0.0 +16700,0.4072558170344897,0.03105266190784093,0.47890330589226493,0.08273236764788475,5.584751751956769e-05 +16800,0.4077100348839108,0.030938097193742294,0.479310621620526,0.08175182762701788,0.00028941867480312245 +16900,0.4090694716869422,0.03141730714937055,0.4779228616654376,0.08096905727333781,0.00062130222491177 +17000,0.4096325774592674,0.03317240921254907,0.4765725189111758,0.0796999429999717,0.0009225514170361303 +17100,0.409318950129627,0.036416273191669915,0.4759463860501217,0.0772010848219748,0.0011173058066065345 +17200,0.4091322273159482,0.03971971816744722,0.4761228299047345,0.07382438051613933,0.0012008440957308444 +17300,0.40917878287625953,0.041376286772682035,0.47732946132916715,0.07089644446189847,0.0012190245599926076 +17400,0.40796678344949716,0.04134184760987771,0.4808650383610144,0.06860969238333003,0.0012166381962804955 +17500,0.4069055769398501,0.040259317584171485,0.48534215525436136,0.0663396391468098,0.0011533110748072363 +17600,0.4073714217435671,0.03867637636174271,0.48873322626000065,0.06424237237588457,0.0009766032588049169 +17700,0.4082070183450192,0.03681720852155175,0.4917890615422369,0.06251096202188594,0.0006757495693060654 +17800,0.40851930992274343,0.03405948660427341,0.4956107932771341,0.06148761266152315,0.00032279753432586496 +17900,0.40834638056816525,0.030057523585525523,0.4992926369932518,0.062175477327735026,0.00012798152532237834 +18000,0.40869966431198385,0.025485516620014383,0.5007566895943754,0.06473163216966882,0.00032649730395761193 +18100,0.4103114989276243,0.02206435248347342,0.4990825597685239,0.0678483880870413,0.0006932007333369842 +18200,0.4125275955278045,0.020471448306712096,0.4962059690581323,0.06977318455160707,0.0010218025557439737 +18300,0.41556837263605517,0.0206159334052642,0.49291632607629127,0.06966729786541252,0.0012320700169767373 +18400,0.41922344744217654,0.021424654150831928,0.4895518490887264,0.06847296087200397,0.001327088446261135 +18500,0.42232284778449486,0.0217839827158899,0.4867244275846881,0.06780939466890122,0.0013593472460257043 +18600,0.4233615462574494,0.022240682195265638,0.4854909346659724,0.06753024566346263,0.0013765912178499511 +18700,0.42221463009837973,0.023175998277689874,0.4862114474386642,0.06706868155366034,0.0013292426316058692 +18800,0.41938452682387994,0.024671257246244315,0.48845387119608186,0.06634303755896588,0.0011473071748282068 +18900,0.4162698274751706,0.02606826102222086,0.4918802760301444,0.0649713055171278,0.0008103299553361399 +19000,0.41370970500856974,0.02619427177378781,0.49541371836161135,0.06428721934177216,0.00039508551425894553 +19100,0.4111836219465369,0.024935190838525294,0.49810665113387514,0.06569494066032154,7.959542074096334e-05 +19200,0.40900764184359,0.023272440638810805,0.500030017898224,0.06768989961937528,0.0 +19300,0.4077586478909343,0.021863494759432046,0.5012108598178834,0.06916699753175017,0.0 +19400,0.408311133192338,0.02043513389032554,0.5000603914760281,0.07094521295009655,0.0002481284912116819 +19500,0.410657267981849,0.018745544224635223,0.4962127982796929,0.07311330075798793,0.001271088755835052 +19600,0.4129873601348296,0.017541385732083054,0.491204116898825,0.0755496223485488,0.0027175148857134764 +19700,0.4155038566448603,0.01783483589445665,0.48429098444630636,0.0783316029268498,0.004038720087526871 +19800,0.4194232425491414,0.019943310031264753,0.4745851157306195,0.0811460202126344,0.00490231147634016 +19900,0.4237634410357246,0.02274289988633667,0.46453684930906475,0.08366798824179451,0.005288821527079398 +20000,0.42924811067875895,0.025272981164161663,0.45383841362633387,0.08624649868021858,0.005393995850526764 +20100,0.435043355622225,0.02711028131661334,0.44499696189855414,0.08742500693034187,0.005424394232265606 +20200,0.4381158298860281,0.028752098345993304,0.4412202762654395,0.08670593887789967,0.0052058566246392666 +20300,0.43629361335970757,0.030858715295792465,0.44443228092985504,0.08395950185201377,0.004455888562631062 +20400,0.4301135651058379,0.03229097649863405,0.45497696288948875,0.07952490603192432,0.0030935894741149603 +20500,0.4229102459145983,0.03199253408632643,0.4681190576986417,0.07549949461909383,0.001478667681339733 +20600,0.4158022740307024,0.029769281238211487,0.48033066235687283,0.07370570116985865,0.0003920812043545203 +20700,0.4070478601985252,0.027064485172408996,0.49220904618105293,0.073174473103939,0.0005041353440738187 +20800,0.39614273429614333,0.025981097158521337,0.5027713369503549,0.07402198766670785,0.001082843928272513 +20900,0.3872177116718546,0.026557635242180744,0.5087847224084467,0.0758282435040628,0.0016116871734550978 +21000,0.38398482616329394,0.027228215559169877,0.5085444034607474,0.07829032074796632,0.00195223406882252 +21100,0.3875603035923633,0.02685374484593285,0.5021392195650695,0.08134417588854626,0.0021025561080882244 +21200,0.3978927373794572,0.02541002434753572,0.4902379575422398,0.08432013650391704,0.002139144226850326 +21300,0.41151318116860797,0.02372890718179091,0.4770756142023481,0.08543752773436995,0.0022447697128831837 +21400,0.42436562739417444,0.0227365967225967,0.4653685865307477,0.08493939959299171,0.0025897897594894764 +21500,0.4358877624320956,0.02220953030988447,0.45558016303078025,0.08340550425415166,0.002917039973088014 +21600,0.44642680413653185,0.021174874782133524,0.4482061421154049,0.08122859103575707,0.0029635879301725993 +21700,0.45775849923504686,0.019856265060823254,0.44139246353032185,0.07826547741833999,0.0027272947554679993 +21800,0.4658513182991035,0.019149391365781768,0.4374855081463585,0.07505499949051757,0.002458782698238717 +21900,0.46881670530836345,0.019440780279391227,0.4373238344796474,0.07198624195049307,0.0024324379821049984 +22000,0.4681729774766497,0.02094882734441416,0.4379040741275592,0.07048253252957828,0.0024915885217985647 +22100,0.4653750905928244,0.023669971931632054,0.4376461934110921,0.07089950364094785,0.002409240423503521 +22200,0.46265914347386955,0.026838523765721486,0.43511445967853835,0.07332780925396575,0.0020600638279048757 +22300,0.4618967857243901,0.029186048225720025,0.43049337975308427,0.07698764200459184,0.001436144292213776 +22400,0.45995327004306485,0.030540930532941254,0.4275623253211247,0.08125460241384186,0.0006888716890271567 +22500,0.45575973471448344,0.031464642145538894,0.4286101753494344,0.08402988505949326,0.00013556273105010428 +22600,0.4520944155950475,0.03200617677241399,0.4305683798237246,0.08533102780881391,0.0 +22700,0.4518830954733447,0.03168387156406179,0.4312106796254198,0.0852223533371737,0.0 +22800,0.45458546969373964,0.030382457343753496,0.43228790023171615,0.08274417273079053,0.0 +22900,0.46001913818967993,0.02936451405390396,0.4330924556750935,0.07752389208132256,0.0 +23000,0.46778067441738336,0.028956505216714695,0.4309893167285267,0.07227350363737518,0.0 +23100,0.47627422783211293,0.028237285206726033,0.4271334384627051,0.06820951467957559,0.00014553381888040876 +23200,0.48290756775606597,0.02775470136824582,0.4231227486653074,0.06545419917490443,0.0007607830354762156 +23300,0.4858705505533305,0.0279681679700472,0.4202439721647368,0.06427099024193132,0.0016463190699540669 +23400,0.48584305871213085,0.02736877345662722,0.4190982807641512,0.06522977243789538,0.0024601146291954703 +23500,0.4864184247251404,0.02574038245309708,0.4167272558732944,0.0681033683903014,0.0030105685581667432 +23600,0.4905049504365615,0.024752648848085798,0.40830015068507347,0.07316042974375656,0.0032818202865225665 +23700,0.49652123563701683,0.024465530904079637,0.39672567713807644,0.0789294495175657,0.0033581068032613455 +23800,0.5011079550606421,0.022760950317863304,0.3883145259103277,0.08446151073270322,0.0033550579784637157 +23900,0.5019675996278283,0.019104984769266125,0.3877078559911522,0.08802584180783582,0.0031937178039173823 +24000,0.49892111687839974,0.014672586175812668,0.395172204172851,0.08851029255439923,0.002723800218537321 +24100,0.4970959884538086,0.011589232340675552,0.4039045212229103,0.08550835133123207,0.001901906651373451 +24200,0.5008157494993369,0.010812911777747219,0.4068400063549502,0.08060889903084516,0.0009224333371204349 +24300,0.5055672381199657,0.011139838890019089,0.40845148254600955,0.07465550386400038,0.00018593658000528064 +24400,0.5058483546632243,0.011631946219614176,0.4133992078890603,0.0691204912281013,0.0 +24500,0.500471052955471,0.011010559715707507,0.4218404344311667,0.06667795289765487,0.0 +24600,0.49201847943224153,0.009367474600624778,0.4297153384224725,0.06889870754466125,0.0 +24700,0.4840179911951928,0.008072269168697499,0.4352122514459639,0.07269748819014586,0.0 +24800,0.4777419954944325,0.008583703565690076,0.439012971058813,0.07466132988106439,0.0 +24900,0.4743511229403143,0.00993515341935268,0.4400404773560362,0.07567324628429696,0.0 +25000,0.4734263239294324,0.011154329451766821,0.4372720195216476,0.07814732709715325,0.0 +25100,0.47214954717521307,0.012671469202629534,0.4328887995120403,0.08229018411011717,0.0 +25200,0.4690412224027795,0.01458640258016774,0.4293233325637628,0.08685261919026369,0.00019642326302624378 +25300,0.46541516194794424,0.01676258867265909,0.4270562982545973,0.0897400434602404,0.0010259076645590048 +25400,0.46371117679792273,0.019231579596808768,0.4245349273933989,0.090290016396749,0.002232299815120635 +25500,0.46548730579355985,0.02080148751916184,0.42241703205340264,0.0879314977338606,0.0033626769000151876 +25600,0.4702117449491536,0.020905075354453503,0.4202569994500889,0.08426106329527593,0.004365116951028285 +25700,0.47452820586510747,0.019811697793625436,0.41893292325246656,0.08098069950856415,0.005746473580236355 +25800,0.4787973600696003,0.017579398694637944,0.4171538855568278,0.07906001982355138,0.007409335855382714 +25900,0.48142864162616433,0.0140995800494763,0.41736066595998533,0.07793627260616152,0.009174839758212388 +26000,0.48319206932827824,0.00987895547419868,0.41961113811415,0.07634724309639615,0.010970593986977013 +26100,0.4890404081481975,0.005766224994094788,0.41821353168396563,0.07488991983456728,0.012089915339174813 +26200,0.4967791938836907,0.0032090395745093155,0.4136953061633807,0.07421000404663687,0.012106456331782424 +26300,0.5013375254417362,0.003071183723581195,0.4098453014258729,0.07437963568018743,0.011366353728622328 +26400,0.5020974566982717,0.004384168111285972,0.40774669367025057,0.07538033902354604,0.01039134249664566 +26500,0.49960899714016527,0.0063583787595273295,0.4041740782314293,0.08032433322189636,0.00953421264698191 +26600,0.49686458348494156,0.008269567304640532,0.3975788568737938,0.08901742503198401,0.008269567304640181 +26700,0.4928365318579985,0.009846004085564072,0.39367858516160126,0.09725443409512388,0.006384444799712293 +26800,0.48747500664289206,0.011578157452110837,0.39256459798642773,0.10395896155580454,0.004423276362764687 +26900,0.4834007422248019,0.013139469962275342,0.39266560606065687,0.10792090861600813,0.0028732731362576393 +27000,0.48407554133299224,0.014070101502755429,0.39053714985592974,0.1099082970620983,0.0014089102462242521 +27100,0.48654607843642134,0.014122168992316735,0.3872612525025102,0.11177922787737984,0.0002912721913718988 +27200,0.4905762986614257,0.013528898298745684,0.3835451153836923,0.11234968765613614,0.0 +27300,0.4984953521662186,0.013791622013005763,0.37847502002558253,0.10923800579519302,0.0 +27400,0.5089467922889178,0.01658631168041578,0.37301284841924776,0.10145404761141844,0.0 +27500,0.5158703347160895,0.021859211399435936,0.3729749087785873,0.08929554510588739,0.0 +27600,0.5174345326831371,0.027735182067464833,0.3798964310884988,0.07493385416089918,0.0 +27700,0.5146615220449425,0.032430250232968555,0.38999249050927554,0.06291573721281346,0.0 +27800,0.5084072214615385,0.034526829449010144,0.4005966001108651,0.05646934897858625,0.0 +27900,0.4993792257376335,0.035369599090715895,0.4103442288046927,0.05490694636695788,0.0 +28000,0.4938930436802014,0.03587908059151177,0.4147284268946161,0.05549944883367072,0.0 +28100,0.49464245824154235,0.03456594206602891,0.4154814030969438,0.05531019659548498,0.0 +28200,0.5000885569959538,0.030255552773458236,0.4139605901258766,0.05569530010471126,0.0 +28300,0.508379706466494,0.023529079170246145,0.4109854898982044,0.05710572446505556,0.0 +28400,0.5233670056598699,0.01622321288261602,0.4004475127001733,0.0599622687573406,0.0 +28500,0.5415726575196643,0.010398382390995853,0.38416610897816433,0.06386285111117565,0.0 +28600,0.55688077321784,0.006860667426251073,0.36852746617331844,0.06773109318259067,0.0 +28700,0.5647665244047986,0.0052126390629984,0.3603799461996729,0.06964089033253007,0.0 +28800,0.567739962595055,0.003645132545491197,0.3593266707328587,0.06928823412659503,0.0 +28900,0.5668082797742972,0.001788159879239637,0.36319936083069615,0.06820419951576714,0.0 +29000,0.5599182873353039,0.0003668955119694547,0.37100035436052825,0.0687144627921983,0.0 +29100,0.5492079709954166,0.0,0.38185387719312813,0.06893815181145525,0.0 +29200,0.5367564900298941,0.0,0.39640774923272315,0.0668357607373827,0.0 +29300,0.5226709898915272,0.0,0.41003116124743305,0.06729784886103982,0.0 +29400,0.5074946096335676,0.0,0.423084416065869,0.06942097430056333,0.0 +29500,0.4929595511904631,0.0,0.4353468944442865,0.07169355436525046,0.0 +29600,0.4797674757805357,0.0,0.446112691496679,0.07411983272278536,0.0 +29700,0.4683000690972654,0.0,0.45483607519171604,0.07686385571101863,0.0 +29800,0.4583692388607079,0.0,0.46146753125899365,0.08016322988029849,0.0 From ec12c86f97b0f0918036b9b65f94340d41ffc723 Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Thu, 1 Aug 2024 15:41:27 +0200 Subject: [PATCH 165/213] Update GenerateFreightPlans.java (#3387) Fixing one typo in "GenerateFreightPlans.java" and some minor updates in the input sample size interpretation and output naming. No changes in the functionality. --- .../freight/tripGeneration/GenerateFreightPlans.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/application/prepare/freight/tripGeneration/GenerateFreightPlans.java b/contribs/application/src/main/java/org/matsim/application/prepare/freight/tripGeneration/GenerateFreightPlans.java index 0d4fa163ee1..e79d06632d6 100644 --- a/contribs/application/src/main/java/org/matsim/application/prepare/freight/tripGeneration/GenerateFreightPlans.java +++ b/contribs/application/src/main/java/org/matsim/application/prepare/freight/tripGeneration/GenerateFreightPlans.java @@ -35,7 +35,7 @@ public class GenerateFreightPlans implements MATSimAppCommand { defaultValue = "https://svn.vsp.tu-berlin.de/repos/public-svn/matsim/scenarios/countries/de/german-wide-freight/v2/germany-europe-network.xml.gz") private String networkPath; - @CommandLine.Option(names = "--nuts", description = "Path to desired network file", required = true) + @CommandLine.Option(names = "--nuts", description = "Path to NUTS file (available on SVN: )", required = true) // TODO Change this to URL pointing to SVN--> need to update the Location calculator private Path shpPath; @@ -48,8 +48,8 @@ public class GenerateFreightPlans implements MATSimAppCommand { @CommandLine.Option(names = "--working-days", defaultValue = "260", description = "Number of working days in a year") private int workingDays; - @CommandLine.Option(names = "--sample", defaultValue = "1", description = "Scaling factor of the freight traffic (0, 1)") - private double sample; + @CommandLine.Option(names = "--sample", defaultValue = "100", description = "Sample size of the freight plans (0, 100]") + private double pct; @CommandLine.Mixin private LanduseOptions landuse = new LanduseOptions(); @@ -60,7 +60,7 @@ public Integer call() throws Exception { log.info("Network successfully loaded!"); log.info("preparing freight agent generator..."); - FreightAgentGenerator freightAgentGenerator = new FreightAgentGenerator(network, shpPath, landuse, averageTruckLoad, workingDays, sample); + FreightAgentGenerator freightAgentGenerator = new FreightAgentGenerator(network, shpPath, landuse, averageTruckLoad, workingDays, pct / 100); log.info("Freight agent generator successfully created!"); log.info("Reading trip relations..."); @@ -84,7 +84,7 @@ public Integer call() throws Exception { Files.createDirectory(output); } - String outputPlansPath = output.toString() + "/german_freight.25pct.plans.xml.gz"; + String outputPlansPath = output.toString() + "/german_freight." + pct + "pct.plans.xml.gz"; PopulationWriter populationWriter = new PopulationWriter(outputPopulation); populationWriter.write(outputPlansPath); From 8dc0f7397154a42ad7108998dcd0240aba8e1be3 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Thu, 1 Aug 2024 15:54:03 +0200 Subject: [PATCH 166/213] add events files comparison --- .../matsim/examples/ModeRestrictionTest.java | 26 +++++++++- .../org/matsim/testcases/MatsimTestUtils.java | 47 +++++++++++++++--- .../bike/output_events.xml.gz | Bin 0 -> 854 bytes .../car/output_events.xml.gz | Bin 0 -> 864 bytes .../bike/output_events.xml.gz | Bin 0 -> 854 bytes .../car/output_events.xml.gz | Bin 0 -> 867 bytes .../15_bike/output_events.xml.gz | Bin 0 -> 686 bytes .../15_car/output_events.xml.gz | Bin 0 -> 686 bytes .../20_bike/output_events.xml.gz | Bin 0 -> 686 bytes .../20_car/output_events.xml.gz | Bin 0 -> 686 bytes .../6_bike/output_events.xml.gz | Bin 0 -> 686 bytes .../6_car/output_events.xml.gz | Bin 0 -> 686 bytes .../bike/output_events.xml.gz | Bin 0 -> 972 bytes .../car/output_events.xml.gz | Bin 0 -> 982 bytes 14 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 matsim/test/input/org/matsim/examples/ModeRestrictionTest/testCleanNetworkAndRerouteBeforeSim_fromActNotPossible_withConsistencyCheck_ok/bike/output_events.xml.gz create mode 100644 matsim/test/input/org/matsim/examples/ModeRestrictionTest/testCleanNetworkAndRerouteBeforeSim_fromActNotPossible_withConsistencyCheck_ok/car/output_events.xml.gz create mode 100644 matsim/test/input/org/matsim/examples/ModeRestrictionTest/testCleanNetworkAndRerouteBeforeSim_toActNotPossible_withConsistencyCheck_ok/bike/output_events.xml.gz create mode 100644 matsim/test/input/org/matsim/examples/ModeRestrictionTest/testCleanNetworkAndRerouteBeforeSim_toActNotPossible_withConsistencyCheck_ok/car/output_events.xml.gz create mode 100644 matsim/test/input/org/matsim/examples/ModeRestrictionTest/testNoRouteChange_noConsistencyCheck_ok/15_bike/output_events.xml.gz create mode 100644 matsim/test/input/org/matsim/examples/ModeRestrictionTest/testNoRouteChange_noConsistencyCheck_ok/15_car/output_events.xml.gz create mode 100644 matsim/test/input/org/matsim/examples/ModeRestrictionTest/testNoRouteChange_noConsistencyCheck_ok/20_bike/output_events.xml.gz create mode 100644 matsim/test/input/org/matsim/examples/ModeRestrictionTest/testNoRouteChange_noConsistencyCheck_ok/20_car/output_events.xml.gz create mode 100644 matsim/test/input/org/matsim/examples/ModeRestrictionTest/testNoRouteChange_noConsistencyCheck_ok/6_bike/output_events.xml.gz create mode 100644 matsim/test/input/org/matsim/examples/ModeRestrictionTest/testNoRouteChange_noConsistencyCheck_ok/6_car/output_events.xml.gz create mode 100644 matsim/test/input/org/matsim/examples/ModeRestrictionTest/testRerouteBeforeSim_actOnRestrictedLinkWithCoords_ok/bike/output_events.xml.gz create mode 100644 matsim/test/input/org/matsim/examples/ModeRestrictionTest/testRerouteBeforeSim_actOnRestrictedLinkWithCoords_ok/car/output_events.xml.gz diff --git a/matsim/src/test/java/org/matsim/examples/ModeRestrictionTest.java b/matsim/src/test/java/org/matsim/examples/ModeRestrictionTest.java index a1bb8fb9c6b..dee40f8f38d 100644 --- a/matsim/src/test/java/org/matsim/examples/ModeRestrictionTest.java +++ b/matsim/src/test/java/org/matsim/examples/ModeRestrictionTest.java @@ -29,11 +29,13 @@ import org.matsim.core.config.groups.ScoringConfigGroup; import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.Controler; +import org.matsim.core.events.EventsUtils; import org.matsim.core.network.NetworkUtils; import org.matsim.core.population.PopulationUtils; import org.matsim.core.router.util.TravelTime; import org.matsim.core.scenario.ScenarioUtils; import org.matsim.testcases.MatsimTestUtils; +import org.matsim.utils.eventsfilecomparison.ComparisonResult; import org.matsim.vehicles.Vehicle; import java.util.*; @@ -78,6 +80,7 @@ void testNoRouteChange_noConsistencyCheck_ok(String link, String restrictedMode) Map.of(Id.createPersonId("car"), List.of(linkId), Id.createPersonId("bike"), List.of(linkId))); runController(scenario, firstLegRouteCheck); firstLegRouteCheck.assertActualContainsExpected(); + assertEventFilesSame(); } /** @@ -96,7 +99,7 @@ void testNoRouteChange_withConsistencyCheck_throws(String link, String restricte FirstLegVisitedLinksCheck firstLegRouteCheck = new FirstLegVisitedLinksCheck(); RuntimeException exception = Assertions.assertThrows(RuntimeException.class, () -> runController(scenario, firstLegRouteCheck)); - Assertions.assertTrue(exception instanceof ProvisionException); + Assertions.assertInstanceOf(ProvisionException.class, exception); Assertions.assertTrue(((ProvisionException) exception).getErrorMessages().stream() .map(Message::getMessage) .anyMatch(m -> m.equals("java.lang.RuntimeException: Network for mode '" + restrictedMode + "' has unreachable links and nodes. This may be caused by mode restrictions on certain links. Aborting."))); @@ -169,6 +172,7 @@ void testCleanNetworkAndRerouteBeforeSim_toActNotPossible_withConsistencyCheck_o FirstLegVisitedLinksCheck firstLegRouteCheck = new FirstLegVisitedLinksCheck(Map.of(Id.createPersonId(restrictedMode), newRoute, Id.createPersonId(other), oldRoute)); runController(scenario, firstLegRouteCheck); firstLegRouteCheck.assertActualEqualsExpected(); + assertEventFilesSame(); } /** @@ -196,6 +200,7 @@ void testCleanNetworkAndRerouteBeforeSim_fromActNotPossible_withConsistencyCheck FirstLegVisitedLinksCheck firstLegRouteCheck = new FirstLegVisitedLinksCheck(Map.of(Id.createPersonId(restrictedMode), newRoute, Id.createPersonId(other), oldRoute)); runController(scenario, firstLegRouteCheck); firstLegRouteCheck.assertActualEqualsExpected(); + assertEventFilesSame(); } /** @@ -219,6 +224,7 @@ void testRerouteBeforeSim_actOnRestrictedLinkWithCoords_ok(String restrictedMode FirstLegVisitedLinksCheck firstLegRouteCheck = new FirstLegVisitedLinksCheck(Map.of(Id.createPersonId(restrictedMode), newRoute, Id.createPersonId(other), oldRoute)); runController(scenario, firstLegRouteCheck); firstLegRouteCheck.assertActualEqualsExpected(); + assertEventFilesSame(); } /** @@ -243,7 +249,7 @@ void testRerouteBeforeSim_actOnRestrictedLinkWithoutCoord_throws(String restrict } private Config prepareConfig(String plansFile, RoutingConfigGroup.NetworkRouteConsistencyCheck consistencyCheck) { - final Config config = utils.loadConfig(utils.getClassInputDirectory() + "config.xml"); + final Config config = utils.loadConfig(utils.getClassInputDirectory() + "config.xml", MatsimTestUtils.TestMethodType.Parameterized); config.routing().setNetworkRouteConsistencyCheck(consistencyCheck); config.plans().setInputFile(plansFile); @@ -367,4 +373,20 @@ private static class BikeTravelTime implements TravelTime { return 1. ; } } + + /** + * Note that this method alone would be sufficient to check the simulation behaviour. But since I have already written the eventHandler, I will use it as well. + * If at some point it is too nervig, to maintain both test methodologies here, the eventHandler can be removed. + * But, I think it makes clearer what is the relevant thing to check. paul aug '24 + */ + private void assertEventFilesSame() { + String fileName = "output_events.xml.gz"; + + String inputFile = utils.getInputDirectory() + utils.getParameterizedTestInputString() + "/" + fileName; + String outputFile = utils.getOutputDirectory() + "/" + fileName; + + ComparisonResult comparisonResult = EventsUtils.compareEventsFiles(inputFile, outputFile); + if (comparisonResult != ComparisonResult.FILES_ARE_EQUAL) + Assertions.fail("Event files are not equal: " + comparisonResult); + } } diff --git a/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java b/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java index 112bcaaddaf..287858329cb 100644 --- a/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java +++ b/matsim/src/test/java/org/matsim/testcases/MatsimTestUtils.java @@ -51,6 +51,10 @@ public final class MatsimTestUtils implements BeforeEachCallback, AfterEachCallback { private static final Logger log = LogManager.getLogger(MatsimTestUtils.class); + public enum TestMethodType { + Normal, Parameterized + } + /** * A constant for the exactness when comparing doubles. */ @@ -79,6 +83,7 @@ public final class MatsimTestUtils implements BeforeEachCallback, AfterEachCallb private Class testClass = null; private String testMethodName = null; + private String testDisplayName = null; public MatsimTestUtils() { MatsimRandom.reset(); @@ -88,6 +93,7 @@ public MatsimTestUtils() { public void beforeEach(ExtensionContext extensionContext) { this.testClass = extensionContext.getTestClass().orElseThrow(); this.testMethodName = extensionContext.getRequiredTestMethod().getName(); + this.testDisplayName = extensionContext.getDisplayName(); } @Override @@ -163,37 +169,62 @@ public Config createConfig(URL context) { return config; } - /** - * Loads a configuration from file (or the default config if configfile is null). + * Loads a configuration from file (or the default config if configfile is null) + * and sets the output directory to {classPath}/{methodName}/. For parameterized tests, the output directory is {classPath}/{methodName}/{parameters}/. * * @param configfile The path/filename of a configuration file, or null to load the default configuration. * @return The loaded configuration. */ - public Config loadConfig(final String configfile, final ConfigGroup... customGroups) { + public Config loadConfig(final String configfile, TestMethodType testMethodType, final ConfigGroup... customGroups) { Config config; if (configfile != null) { config = ConfigUtils.loadConfig(configfile, customGroups); } else { config = ConfigUtils.createConfig( customGroups ); } - this.outputDirectory = getOutputDirectory(); - config.controller().setOutputDirectory(this.outputDirectory); - return config; + return setOutputDirectory(config, testMethodType); } - public Config loadConfig(final URL configfile, final ConfigGroup... customGroups) { + public Config loadConfig(final String configfile, final ConfigGroup... customGroups) { + return loadConfig(configfile, TestMethodType.Normal, customGroups); + } + + public Config loadConfig(final URL configfile, TestMethodType testMethodType, final ConfigGroup... customGroups) { Config config; if (configfile != null) { config = ConfigUtils.loadConfig(configfile, customGroups); } else { config = ConfigUtils.createConfig( customGroups ); } - this.outputDirectory = getOutputDirectory(); + return setOutputDirectory(config, testMethodType); + } + + public Config loadConfig(final URL configfile, final ConfigGroup... customGroups) { + return loadConfig(configfile, TestMethodType.Normal, customGroups); + } + + /** + * Sets the output directory to {classPath}/{methodName}/{subDir}. For normal tests, there is no {subDir}. + * For parameterized tests, {subDir} is a slightly adapted test input parameter string (aka display name of JUnit 5). + * E.g.: "[1] car, 6" will be transformed to "car_6". + */ + private Config setOutputDirectory(Config config, TestMethodType testMethodType) { + String subDirectory = switch (testMethodType) { + case Normal -> ""; + case Parameterized -> getParameterizedTestInputString(); + }; + this.outputDirectory = getOutputDirectory(subDirectory); config.controller().setOutputDirectory(this.outputDirectory); return config; } + public String getParameterizedTestInputString() { + String parameters = this.testDisplayName.replaceFirst("^.*?\\]", "").trim(); + parameters = parameters.replaceAll(" ", "").replaceAll("[^a-zA-Z0-9]", "_"); + return parameters; + } + public Config createConfig(final ConfigGroup... customGroups) { Config config = ConfigUtils.createConfig( customGroups ); this.outputDirectory = getOutputDirectory(); diff --git a/matsim/test/input/org/matsim/examples/ModeRestrictionTest/testCleanNetworkAndRerouteBeforeSim_fromActNotPossible_withConsistencyCheck_ok/bike/output_events.xml.gz b/matsim/test/input/org/matsim/examples/ModeRestrictionTest/testCleanNetworkAndRerouteBeforeSim_fromActNotPossible_withConsistencyCheck_ok/bike/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..b310d236f60666334525ab3d0c3b0f9e477e85c2 GIT binary patch literal 854 zcmV-c1F8HUiwFP!00000|Gk-AZ<{a_hOgIOfw=E#K1-w|z1rO-RnxTFiGkCiI1mws zwEunvx)vKaJ|@tsC=Pz!<71x>ll8;PfmszTPg#*~Z09SnEt)4qn&nR$`^v!<;WSTe>nP^bQ zkaoiB#%?~vlwZxC>E&t=Wn*BOFKx>c=ymHW_!p*?L4jGn+L=Rs=Z|KGT!a7 zWNd$Af8~^4igMrCl9DoEOGO`xQ^r4z=dcydhZT(Oc%w3^rA0Igps7R&5fs8-sW@5{=^1BU?@OwoWqrJ8+&4hBEh)2Spop9(hURrL?4{#%= z=k+`>)P0WD#rk0@s}HUi66XV_sO@&=)H7&)+wlp_udE1G=9ck(`s=TMAg)1yR+crS zAw_sQgb#6H4OFN{B({_dJb> zTyvllbHJKm5;h7KOqun%l=#;J!JJtWMG_mW9+(u?7aUEQ3&?3QrsT4z?+bj_?Mlv8 zE)_1g_aUNOsyuM(C*2~2@3DJ52Vb+feV>@`ZQw+U?5)DZ$2AtXcwF}d7maI0&Lpm< zwnB>JY^_ku4f>@E(+Vw7x@vR4n<%;_Dd5bP=f199(-OYwH zq-1CD!QIW5e%)imk!;b*k1=im?ES>QrWqq;j=U4!({9Pq8hNxR4}3TB-nQs=72$rv z`xbSde9O;n?+fz0I|n}}r?h65nwUgT^8CHZ`IE0HJs>Zuj;9Mt8P`9hKdKAkCicH~ z+nn-bd;Sy$va~^xj1P3&~iMzeG>O2S^N`Y<%7CY0OSkf-Wguupf@YvX@vL&=_X!W<%=LjMX}N?skOpj zSQ6sUqSj=RRxNmbU5CT6!Cj~!loGjV$O|6yWyYU~qyG8hpsqWyN)ocR32vN{gEXCu zF-P!cy`nudzQWxbCePJJ%_t4tRdvhbn<`P9H92*N4^OfHM`R_@7!fX{qizMBjn?*T zq{wn2w2=j&tgQ)XJVKig0rmvgk8C+-0>haEjhGNewnG7DEQzF5Xa$GGL+e~E;lOoO zqp$E?Neyc+2ntCFXv@E?A!0^x<81l2|yU94nJ9jl4o4fv>%-vriVr@eC8~^}QvYmDS literal 0 HcmV?d00001 diff --git a/matsim/test/input/org/matsim/examples/ModeRestrictionTest/testCleanNetworkAndRerouteBeforeSim_toActNotPossible_withConsistencyCheck_ok/bike/output_events.xml.gz b/matsim/test/input/org/matsim/examples/ModeRestrictionTest/testCleanNetworkAndRerouteBeforeSim_toActNotPossible_withConsistencyCheck_ok/bike/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..42ba2aa5fe1580b81af3663b1b629f3f4d274fc2 GIT binary patch literal 854 zcmV-c1F8HUiwFP!00000|Gk-AZ<{a_hOgIOfw=E#%twfnq*uG!q-vUWJ27xt6ao=( zNc-<+plY#!<6{E5isInsJwEpNFxfo59y6OKC~Zq zcN(;)f zK4~YsZSCe$O!?K!eX%X;LBmhjDJuD;WMdK;d;U=*?0q;cj;9NcxG+D;eij!lR@nJj zEBDlBe9O7`{LNm{I8%kIb`%R#{qr|Hu%#WOXnc6+8f6E_MeRJT;=2dL397wh@iN-) z(|BxuWPjz1UyJh4*^-iF!j_6X73Y+H9?xMboKGttHB^XTL zdw?ku7=xx@(xUJ9K4gkHW6%_ezyxa&K&F^822F7hn3YFXkSXSj!90(lth*GGG(TtT z$X3jdW8hgKDc5?oDZC$w&$Hw&!7cv$0xMFvLaXzTgJ!fufP6*xDLK9D$5$u zkRrSt!iTu92I_1_B(O8o1AV9u`gtQ*znVw+0@iUCG(X zrNV{FrH`nWDiE%hlkRWA``F!{ML<^(`))DcU*8EA*-WnSrX5Ea>9(Fey zQjwgU#T$1w-`eXA%Z_A=R&I!K4PYN9{xwb*$y4N<_?mi25|_xKS$^QFk@LPqx2piR z3qH1}`Q%G}Hf!II zgHdBaDx=&04D$up{|84&ToK!Y(}+xZa-uoy`Fv`OnRY%!Zd{gG6;r)mQlQy^2|F_$ zym}%}4=&bahpSQ|^d$*>`k6z(mVWx%G9v$olJn&skvk~=EOCsvIi4v2!Q)dTse*ll z!LZ23zQL@~B&AvKEW7r*#e+Ysicm`A)*;P!h~){tBMjR6kDcmn#r9&}*euv_y@*%z zH`;jQ_c~d0CeFAKy*fg3xVHUfye#Y zH`e%`mKC9lEC^+7OhCgC$~FVwkB8mBlygQftVvLd@o`|<6mZ6pNJ@iNa9G&&&eno; zj&9%S31?R_!`OO(LQ(>n@^9^km{IIFQ~s@aJSA$UF+f7>%jweZ{9@+pD{R)t(bl{7 zacBw!_~{i%%24pYu*mQ3!(5$!gf(^o0iYF-dB#>?RBP_>DsXRlKJYCSNy;=1W%0@c zjEQkxOMFWc(tlEe!@zfi%^5WP&ObFs*335iN?h~s3z&Uno_Y2i^=8bE@DhnY!h%Z@ zl(%qA>dP%ylO(YLHEG;PAn8pX32I=_4{pFnFl%2`n_(=qfX-E7SjTNGCJ2mGWjMpy z`f4x%_HYDkKwu1O>!HO&cnz(!Fovzl>L{+)r3{z^<{V-rE2a+u5)k?#21r}_JxpJ3 t$@egl+T#Cl1#7pfH&>yRuv6c?$vDU}w>2D_yY@fL-Cy(t-dzJ7002pLtq}kK literal 0 HcmV?d00001 diff --git a/matsim/test/input/org/matsim/examples/ModeRestrictionTest/testNoRouteChange_noConsistencyCheck_ok/15_bike/output_events.xml.gz b/matsim/test/input/org/matsim/examples/ModeRestrictionTest/testNoRouteChange_noConsistencyCheck_ok/15_bike/output_events.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..c6c664e79df325ee9f407712f85dd33c6def4622 GIT binary patch literal 686 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 E0OT0pq5uE@ literal 0 HcmV?d00001 From 7dd60f1552ba5c527b740694c5e4766029423229 Mon Sep 17 00:00:00 2001 From: Kai Nagel Date: Fri, 2 Aug 2024 19:35:34 +0200 Subject: [PATCH 167/213] more (javadoc) comments --- .../matsim/application/MATSimApplication.java | 53 ++++++++++++++----- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java b/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java index 7d63518e323..4e4c6860d63 100644 --- a/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java +++ b/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java @@ -153,7 +153,14 @@ public Integer call() throws Exception { // load config if not present yet. if (config == null) { - config = loadConfig(Objects.requireNonNull( configPath, "No default scenario location given" ).getAbsoluteFile().toString() ); + String path = Objects.requireNonNull( configPath, "No default scenario location given" ).getAbsoluteFile().toString(); + List customModules = getCustomModules(); + + final Config config1 = ConfigUtils.loadConfig(path, customModules.toArray(new ConfigGroup[0] ) ); + Config prepared = prepareConfig( config1 ); + + config = prepared != null ? prepared : config1; + // (The above lines of code come from inlining so maybe it happened there: I cannot see how prepared could be null but config1 not except if user code returns null which I would consider a bug. kai, aug'24) } else { Config tmp = prepareConfig(config); config = tmp != null ? tmp : config; @@ -306,15 +313,6 @@ protected final void addRunOption(Config config, String option) { addRunOption(config, option, ""); } - private Config loadConfig(String path) { - List customModules = getCustomModules(); - - final Config config = ConfigUtils.loadConfig(path, customModules.toArray(new ConfigGroup[0])); - Config prepared = prepareConfig(config); - - return prepared != null ? prepared : config; - } - @Override public String defaultValue(CommandLine.Model.ArgSpec argSpec) throws Exception { Object obj = argSpec.userObject(); @@ -374,8 +372,39 @@ public static void run(Class clazz, String... args) } /** - * Convenience method to run a scenario from code or automatically with gui when desktop application is detected. - * This method may also be used to predefine some default arguments. + *

        Convenience method to run a scenario from code or automatically with gui when desktop application is detected. + * This method may also be used to predefine some default arguments.

        + * + *

        With respect to args it looks like arguments are treated in the following sequence (programmed in the run method): + *

          + *
        • ConfigUtils.loadConfig without args
        • + *
        • prepareConfig which is usually overwritten
        • + *
        • config options from some yaml file which can be provided as a command line option
        • + *
        • config options on command line
        • + *

        + * + *

        defaultArgs could be used to provide defaults when calling this method here; they would go in addition to what is coming in from "upstream" which is typically the command line.

        + * + *

        There are many execution paths that can be reached from this class, but a typical one for matsim-scenarios seems to be:

          + *
        • This method runs MATSimApplication.run( TheScenarioClass.class , args ).
        • + *
        • That run class will instantiate an instance of TheScenarioClass (*), then do some args consistenty checking, then call the piccoli execute method.
        • + *
        • The piccoli execute method will essentially call the "call" method of MATSimApplication.
        • + *
        • I think that in the described execution path, this.config in that call method will initially be null. (The ctor of MATSimApplication was called via reflection at (*); I think that it was called there without a config argument.)
        • + *
        • This call method then will do:
            + *
          • getCustomModules() (which is empty by default but can be overriden)
          • + *
          • ConfigUtils.loadConfig(...) _without_ passing on the args
          • + *
          • prepareConfig(...) (which is empty by default but is typically overridden, in this case in OpenBerlinScenario). In our case, this sets the typical scoring params and the typical replanning strategies. + *
          • next one can override the config from some yaml file provided as a commandline option + *
          • next args is parsed and set + *
          • then some standard CL options are detected and set + *
          • then createScenario(config) is called (which can be overwritten but is not) + *
          • then prepareScenario(scenario) is called (which can be overwritten but is not) + *
          • then a standard controler is created from scenario + *
          • then prepareControler is called which can be overwritten + *
          + *
        + *

        + * * @param clazz class of the scenario to run * @param args pass arguments from the main method * @param defaultArgs predefined default arguments that will always be present From d4a2962d3217da15a6265f77604800e4471c1584 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Sun, 4 Aug 2024 22:00:37 +0200 Subject: [PATCH 168/213] add test which includes tolling. One test is failing, because it is not possible to create different schemes for the different types. --- .../NetworkBasedTransportCostsTest.java | 174 ++++++++++++++++-- 1 file changed, 163 insertions(+), 11 deletions(-) diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java index ccdb7095162..63870ca8ed3 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java @@ -30,9 +30,13 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.network.Network; +import org.matsim.contrib.roadpricing.RoadPricingScheme; +import org.matsim.contrib.roadpricing.RoadPricingSchemeImpl; +import org.matsim.contrib.roadpricing.RoadPricingUtils; import org.matsim.core.config.Config; import org.matsim.core.network.io.MatsimNetworkReader; import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.misc.Time; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.CostInformation; import org.matsim.vehicles.VehicleType; @@ -47,6 +51,8 @@ public class NetworkBasedTransportCostsTest { + private static final String TYPE_1 = "type1"; + private static final String TYPE_2 = "type2"; @RegisterExtension public final MatsimTestUtils utils = new MatsimTestUtils(); @@ -60,21 +66,21 @@ void test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem(){ Network network = scenario.getNetwork(); NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(network); - builder.addVehicleTypeSpecificCosts("type1", 10.0, 0.0, 2.0); - builder.addVehicleTypeSpecificCosts("type2", 20.0, 0.0, 4.0); + builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); + builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); NetworkBasedTransportCosts c = builder.build(); Vehicle vehicle1 = mock(Vehicle.class); com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); when(type1.getMaxVelocity()).thenReturn(5.0); - when(type1.getTypeId()).thenReturn("type1"); + when(type1.getTypeId()).thenReturn(TYPE_1); when(vehicle1.getType()).thenReturn(type1); when(vehicle1.getId()).thenReturn("vehicle1"); Vehicle vehicle2 = mock(Vehicle.class); com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); when(type2.getMaxVelocity()).thenReturn(5.0); - when(type2.getTypeId()).thenReturn("type2"); + when(type2.getTypeId()).thenReturn(TYPE_2); when(vehicle2.getType()).thenReturn(type2); when(vehicle2.getId()).thenReturn("vehicle2"); @@ -94,8 +100,8 @@ void test_whenVehicleTypeNotKnow_throwException(){ Network network = scenario.getNetwork(); NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(network); - builder.addVehicleTypeSpecificCosts("type1", 10.0, 0.0, 2.0); - builder.addVehicleTypeSpecificCosts("type2", 20.0, 0.0, 4.0); + builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); + builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); NetworkBasedTransportCosts c = builder.build(); Vehicle vehicle2 = mock(Vehicle.class); @@ -120,14 +126,14 @@ void test_whenAddingTwoVehicleTypesViaConstructor_itMustAccountForThat(){ String NETWORK_FILENAME = utils.getClassInputDirectory() + "network.xml"; new MatsimNetworkReader(scenario.getNetwork()).readFile(NETWORK_FILENAME); - VehicleType vehType1 = VehicleUtils.getFactory().createVehicleType(Id.create( "type1", VehicleType.class )); + VehicleType vehType1 = VehicleUtils.getFactory().createVehicleType(Id.create(TYPE_1, VehicleType.class )); CostInformation costInformation1 = vehType1.getCostInformation() ; costInformation1.setFixedCost( 0.0 ); costInformation1.setCostsPerMeter( 2.0 ); costInformation1.setCostsPerSecond( 0.0 ); - VehicleType vehType2 = VehicleUtils.getFactory().createVehicleType(Id.create( "type2", VehicleType.class )); + VehicleType vehType2 = VehicleUtils.getFactory().createVehicleType(Id.create(TYPE_2, VehicleType.class )); CostInformation costInformation = vehType2.getCostInformation() ; costInformation.setFixedCost( 0.0 ); @@ -136,20 +142,20 @@ void test_whenAddingTwoVehicleTypesViaConstructor_itMustAccountForThat(){ Network network = scenario.getNetwork(); NetworkBasedTransportCosts.Builder builder = - NetworkBasedTransportCosts.Builder.newInstance(network,Arrays.asList(vehType1,vehType2)); + NetworkBasedTransportCosts.Builder.newInstance(network,Arrays.asList(vehType1,vehType2)); NetworkBasedTransportCosts networkBasedTransportCosts = builder.build(); Vehicle vehicle1 = mock(Vehicle.class); com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); when(type1.getMaxVelocity()).thenReturn(5.0); - when(type1.getTypeId()).thenReturn("type1"); + when(type1.getTypeId()).thenReturn(TYPE_1); when(vehicle1.getType()).thenReturn(type1); when(vehicle1.getId()).thenReturn("vehicle1"); Vehicle vehicle2 = mock(Vehicle.class); com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); when(type2.getMaxVelocity()).thenReturn(5.0); - when(type2.getTypeId()).thenReturn("type2"); + when(type2.getTypeId()).thenReturn(TYPE_2); when(vehicle2.getType()).thenReturn(type2); when(vehicle2.getId()).thenReturn("vehicle2"); @@ -159,4 +165,150 @@ void test_whenAddingTwoVehicleTypesViaConstructor_itMustAccountForThat(){ Assertions.assertEquals(20000.0, networkBasedTransportCosts.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); } + /** + * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} + * In addition, there is added a road pricing scheme. + * The scheme is only set for one vehicle type: type1. + * So, only the vehicle using that type (vehicle1) should be tolled, the other (vehicle2) not. + * + */ + @Test + void test_whenAddingTwoDifferentVehicleTypes_tollOneType(){ + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(utils.getClassInputDirectory() + "network.xml"); + + //Create Rp Scheme from code. + RoadPricingSchemeImpl scheme = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); + /* Configure roadpricing scheme. */ + RoadPricingUtils.setName(scheme, "DemoToll4Test"); + RoadPricingUtils.setType(scheme, RoadPricingScheme.TOLL_TYPE_LINK); + RoadPricingUtils.setDescription(scheme, "Tolling scheme for test."); + + /* Add general link based toll for one link */ + RoadPricingUtils.addLink(scheme, Id.createLinkId("21")); + RoadPricingUtils.createAndAddGeneralCost(scheme, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99); + + /* Create the rpCalculator based on the scheme. + * Here, only for one type, the see the vehicleType dependent work of it + * */ + VehicleTypeDependentRoadPricingCalculator roadPricingCalculator = new VehicleTypeDependentRoadPricingCalculator(); + roadPricingCalculator.addPricingScheme(TYPE_1, scheme); + ///___ End creating from Code + + NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork()); + builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); + builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); + builder.setRoadPricingCalculator(roadPricingCalculator); //add the rpCalculator to activite the tolling. + NetworkBasedTransportCosts c = builder.build(); + + Vehicle vehicle1 = mock(Vehicle.class); + com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); + when(type1.getMaxVelocity()).thenReturn(5.0); + when(type1.getTypeId()).thenReturn(TYPE_1); + when(vehicle1.getType()).thenReturn(type1); + when(vehicle1.getId()).thenReturn("vehicle1"); + + Vehicle vehicle2 = mock(Vehicle.class); + com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); + when(type2.getMaxVelocity()).thenReturn(5.0); + when(type2.getTypeId()).thenReturn(TYPE_2); + when(vehicle2.getType()).thenReturn(type2); + when(vehicle2.getId()).thenReturn("vehicle2"); + + //vehicle1: includes toll + Assertions.assertEquals(20099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle1), 0.01); + Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle1), 0.01); + + //vehicle 2: no toll + Assertions.assertEquals(40000.0, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle2), 0.01); + Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); + } + + /** + * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} + * In addition, there is added a road pricing scheme. + * Two different schemes are created to toll the two different vehicle types differently. + */ + @Test + void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferently(){ + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(utils.getClassInputDirectory() + "network.xml"); + + //Create Rp Scheme from code. + RoadPricingSchemeImpl scheme1 = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); + /* Configure roadpricing scheme. */ + RoadPricingUtils.setName(scheme1, "DemoToll4TestType1"); + RoadPricingUtils.setType(scheme1, RoadPricingScheme.TOLL_TYPE_LINK); + RoadPricingUtils.setDescription(scheme1, "Tolling scheme for test."); + + /* Add general link based toll for one link */ + RoadPricingUtils.addLink(scheme1, Id.createLinkId("21")); + RoadPricingUtils.createAndAddGeneralCost(scheme1, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99); + + //Create Rp Scheme from code. + //Fixme: The following does not work as one may expect: In the end, both schemes are the same object. + // --> It is just added a second entry to the costs, which is not taken into account anyways... + // Questions: + // 1.) How to build ab a second scheme, that is "independently" settable? Currently no new RoadPricingSchemeImpl() can be created without + // the addOrGet methods provided in {@link RoadPricingUtils}. + // 2.) Why does not both costs are summede up in the current behavior, so, the toll is 99.99 + 42.42 = 142.41? + // --> Which one is choose? The first? The higher one?...??? + // One solution might be to use the "withTollFactor" approach. --> Todo write an additional test for it. + // Nevertheless, the current approach leads IMO (KMT) easily to unintentional mistakes. + //kmt, Aug'24 + RoadPricingSchemeImpl scheme2 = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); + /* Configure roadpricing scheme. */ + RoadPricingUtils.setName(scheme2, "DemoToll4TestType1"); + RoadPricingUtils.setType(scheme2, RoadPricingScheme.TOLL_TYPE_LINK); + RoadPricingUtils.setDescription(scheme2, "Tolling scheme for test."); + + /* Add general link based toll for one link */ + RoadPricingUtils.addLink(scheme2, Id.createLinkId("21")); + RoadPricingUtils.createAndAddGeneralCost(scheme2, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 42.42); + + + /* Create the rpCalculator based on the scheme. + * Each vehicle type gets affected by a different tolling scheme. + * */ + //FIXME: See above/below: schem1 and scheme2 are the same object.... + VehicleTypeDependentRoadPricingCalculator roadPricingCalculator = new VehicleTypeDependentRoadPricingCalculator(); + roadPricingCalculator.addPricingScheme(TYPE_1, scheme1); + roadPricingCalculator.addPricingScheme(TYPE_2, scheme2); + + ///___ End creating from Code + + NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork()); + builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); + builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); + builder.setRoadPricingCalculator(roadPricingCalculator); //add the rpCalculator to activate the tolling. + NetworkBasedTransportCosts c = builder.build(); + + Vehicle vehicle1 = mock(Vehicle.class); + com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); + when(type1.getMaxVelocity()).thenReturn(5.0); + when(type1.getTypeId()).thenReturn(TYPE_1); + when(vehicle1.getType()).thenReturn(type1); + when(vehicle1.getId()).thenReturn("vehicle1"); + + Vehicle vehicle2 = mock(Vehicle.class); + com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); + when(type2.getMaxVelocity()).thenReturn(5.0); + when(type2.getTypeId()).thenReturn(TYPE_2); + when(vehicle2.getType()).thenReturn(type2); + when(vehicle2.getId()).thenReturn("vehicle2"); + + //vehicle1: includes toll of 99.99 for entering the final link + Assertions.assertEquals(20099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle1), 0.01); + Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle1), 0.01); + + //vehicle 2: includes toll of 42.42 for entering the final link + //Fixme: This currently fails... see comments above. + Assertions.assertEquals(40042.42, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle2), 0.01); + Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); + } + } From 3b7896d47256e7fc05cbf7550c6113608d45961e Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Sun, 4 Aug 2024 22:06:31 +0200 Subject: [PATCH 169/213] WIP: Prepare test for tolling with factor. Not implemented to the end now -> Disabled. --- .../NetworkBasedTransportCostsTest.java | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java index 63870ca8ed3..1b7ce8fe5e3 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java @@ -25,6 +25,7 @@ import com.graphhopper.jsprit.core.problem.driver.Driver; import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Id; @@ -270,7 +271,6 @@ void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferently(){ RoadPricingUtils.addLink(scheme2, Id.createLinkId("21")); RoadPricingUtils.createAndAddGeneralCost(scheme2, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 42.42); - /* Create the rpCalculator based on the scheme. * Each vehicle type gets affected by a different tolling scheme. * */ @@ -311,4 +311,68 @@ void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferently(){ Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); } + /** + * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} + * In addition, there is added a road pricing scheme. + * Two different schemes are created to toll the two different vehicle types differently. + * Here the approach using a factor is used to take into account the different types. + * //TODO: Write it completely + */ + @Test + @Disabled + void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferentlyWithFactor(){ + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(utils.getClassInputDirectory() + "network.xml"); + + //Create Rp Scheme from code. + RoadPricingSchemeImpl scheme1 = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); + /* Configure roadpricing scheme. */ + RoadPricingUtils.setName(scheme1, "DemoToll4TestType1"); + RoadPricingUtils.setType(scheme1, RoadPricingScheme.TOLL_TYPE_LINK); + RoadPricingUtils.setDescription(scheme1, "Tolling scheme for test."); + + /* Add general link based toll for one link */ + RoadPricingUtils.addLink(scheme1, Id.createLinkId("21")); + RoadPricingUtils.createAndAddGeneralCost(scheme1, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99); + + //Use a factor to take into account the differnt types. type2 gehts tolled with 50% of the toll of type1 + //TODO: Include factor + + VehicleTypeDependentRoadPricingCalculator roadPricingCalculator = new VehicleTypeDependentRoadPricingCalculator(); + roadPricingCalculator.addPricingScheme(TYPE_1, scheme1); + + ///___ End creating from Code + + NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork()); + builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); + builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); + builder.setRoadPricingCalculator(roadPricingCalculator); //add the rpCalculator to activate the tolling. + NetworkBasedTransportCosts c = builder.build(); + + Vehicle vehicle1 = mock(Vehicle.class); + com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); + when(type1.getMaxVelocity()).thenReturn(5.0); + when(type1.getTypeId()).thenReturn(TYPE_1); + when(vehicle1.getType()).thenReturn(type1); + when(vehicle1.getId()).thenReturn("vehicle1"); + + Vehicle vehicle2 = mock(Vehicle.class); + com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); + when(type2.getMaxVelocity()).thenReturn(5.0); + when(type2.getTypeId()).thenReturn(TYPE_2); + when(vehicle2.getType()).thenReturn(type2); + when(vehicle2.getId()).thenReturn("vehicle2"); + + //vehicle1: includes toll of 99.99 for entering the final link + Assertions.assertEquals(20099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle1), 0.01); + Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle1), 0.01); + + //vehicle 2: includes toll of 49.995 (50% of 99.99) for entering the final link + //Fixme: This currently fails... see comments above. + Assertions.assertEquals(40049.995, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle2), 0.01); + Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); + } + } From 40240461c419d161c9b1850602bd9d8af2ea0acb Mon Sep 17 00:00:00 2001 From: Kai Nagel Date: Sun, 4 Aug 2024 23:30:50 +0200 Subject: [PATCH 170/213] replace self-build RoadPricingCalculator with official RoadPricingScheme --- .../controler/CarrierVehicleReRouter.java | 7 ++-- .../jsprit/NetworkBasedTransportCosts.java | 37 +++++++++++-------- ...cleTypeDependentRoadPricingCalculator.java | 1 + .../NetworkBasedTransportCostsTest.java | 33 +++++++++++++---- 4 files changed, 51 insertions(+), 27 deletions(-) diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierVehicleReRouter.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierVehicleReRouter.java index 4a75e5c607d..cd03cb5fd94 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierVehicleReRouter.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/controler/CarrierVehicleReRouter.java @@ -36,6 +36,7 @@ import com.graphhopper.jsprit.io.algorithm.AlgorithmConfigXmlReader; import com.graphhopper.jsprit.io.algorithm.VehicleRoutingAlgorithms; import org.matsim.api.core.v01.network.Network; +import org.matsim.contrib.roadpricing.RoadPricingScheme; import org.matsim.core.replanning.ReplanningContext; import org.matsim.core.replanning.modules.GenericPlanStrategyModule; import org.matsim.core.router.util.TravelTime; @@ -58,7 +59,7 @@ class CarrierVehicleReRouter implements GenericPlanStrategyModule{ private final VehicleRoutingActivityCosts vehicleRoutingActivityCosts; - public CarrierVehicleReRouter( Network network, CarrierVehicleTypes vehicleTypes, TravelTime travelTimes, String vrpAlgoConfigFile, VehicleTypeDependentRoadPricingCalculator roadPricing ) { + public CarrierVehicleReRouter( Network network, CarrierVehicleTypes vehicleTypes, TravelTime travelTimes, String vrpAlgoConfigFile, RoadPricingScheme roadPricing ) { this.network = network; vehicleRoutingTransportCosts = getNetworkBasedTransportCosts(network,vehicleTypes,travelTimes,roadPricing); vehicleRoutingActivityCosts = new VehicleRoutingActivityCosts() { @@ -146,7 +147,7 @@ public void handlePlan(CarrierPlan carrierPlan) { } - private NetworkBasedTransportCosts getNetworkBasedTransportCosts(Network network, CarrierVehicleTypes vehicleTypes, TravelTime travelTimes, VehicleTypeDependentRoadPricingCalculator roadPricing) { + private NetworkBasedTransportCosts getNetworkBasedTransportCosts(Network network, CarrierVehicleTypes vehicleTypes, TravelTime travelTimes, RoadPricingScheme roadPricing ) { //****** //Define transport-costs //****** @@ -157,7 +158,7 @@ private NetworkBasedTransportCosts getNetworkBasedTransportCosts(Network network //sets time-dependent travelTimes tpcostsBuilder.setTravelTime(travelTimes); - if(roadPricing != null) tpcostsBuilder.setRoadPricingCalculator(roadPricing); + if(roadPricing != null) tpcostsBuilder.setRoadPricingScheme(roadPricing ); //sets time-slice to build time-dependent tpcosts and travelTime matrices tpcostsBuilder.setTimeSliceWidth(900); diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java index f332b84cb0b..6ad51d3f5bc 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java @@ -30,6 +30,8 @@ import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.population.Person; +import org.matsim.contrib.roadpricing.RoadPricingScheme; +import org.matsim.contrib.roadpricing.RoadPricingSchemeImpl; import org.matsim.core.router.speedy.SpeedyALTFactory; import org.matsim.core.router.util.LeastCostPathCalculator; import org.matsim.core.router.util.LeastCostPathCalculator.Path; @@ -83,6 +85,8 @@ */ public class NetworkBasedTransportCosts implements VRPTransportCosts { + private final RoadPricingScheme roadPricingScheme; + public interface InternalLeastCostPathCalculatorListener { void startCalculation(long routerId); @@ -320,13 +324,13 @@ static class VehicleTransportCostsIncludingToll implements TravelDisutility { private final TravelDisutility baseTransportDisutility; - private final VehicleTypeDependentRoadPricingCalculator vehicleTypeDependentPricingCalculator; + private final RoadPricingScheme roadPricingScheme; - public VehicleTransportCostsIncludingToll(TravelDisutility baseTransportDisutility, - VehicleTypeDependentRoadPricingCalculator vehicleTypeDependentPricingCalculator) { + public VehicleTransportCostsIncludingToll( TravelDisutility baseTransportDisutility, + RoadPricingScheme roadPricingScheme ) { super(); this.baseTransportDisutility = baseTransportDisutility; - this.vehicleTypeDependentPricingCalculator = vehicleTypeDependentPricingCalculator; + this.roadPricingScheme = roadPricingScheme; // System.out.println("huuuuuuuuuuuuuuuuuuuu - initialize transport costs with toll"); } @@ -334,8 +338,10 @@ public VehicleTransportCostsIncludingToll(TravelDisutility baseTransportDisutili public double getLinkTravelDisutility(Link link, double time, Person person, org.matsim.vehicles.Vehicle vehicle) { double costs = baseTransportDisutility.getLinkTravelDisutility(link, time, person, vehicle); - Id typeId = vehicle.getType().getId(); - double toll = vehicleTypeDependentPricingCalculator.getTollAmount(typeId, link, time); +// Id typeId = vehicle.getType().getId(); +// double toll = roadPricingScheme.getTollAmount(typeId, link, time ); + RoadPricingSchemeImpl.Cost costInfo = roadPricingScheme.getLinkCostInfo( link.getId(), time, person.getId(), vehicle.getId() ); + double toll = costInfo.amount; // System.out.println("huuuuuuuuuuuuuuuuuuuu - paid toll"); return costs + toll; } @@ -377,7 +383,8 @@ public static Builder newInstance(Network network) { private LeastCostPathCalculatorFactory leastCostPathCalculatorFactory = (network, travelCosts, travelTimes) -> new SpeedyALTFactory().createPathCalculator(network, travelCosts, travelTime); - private VehicleTypeDependentRoadPricingCalculator roadPricingCalculator = new VehicleTypeDependentRoadPricingCalculator(); +// private VehicleTypeDependentRoadPricingCalculator roadPricingScheme = new VehicleTypeDependentRoadPricingCalculator(); + private RoadPricingScheme roadPricingScheme; private boolean withToll = false; @@ -472,9 +479,9 @@ public Builder setThreadSafeLeastCostPathCalculatorFactory( return this; } - public Builder setRoadPricingCalculator(VehicleTypeDependentRoadPricingCalculator calculator) { + public Builder setRoadPricingScheme( RoadPricingScheme roadPricingScheme) { withToll = true; - this.roadPricingCalculator = calculator; + this.roadPricingScheme = roadPricingScheme; return this; } @@ -501,7 +508,7 @@ public NetworkBasedTransportCosts build() { baseDisutility = new BaseVehicleTransportCosts(typeSpecificCosts, travelTime); } if (withToll) { - finalDisutility = new VehicleTransportCostsIncludingToll(baseDisutility, roadPricingCalculator); + finalDisutility = new VehicleTransportCostsIncludingToll(baseDisutility, roadPricingScheme ); } else finalDisutility = baseDisutility; return new NetworkBasedTransportCosts(this); @@ -551,8 +558,6 @@ public void addVehicleTypeSpecificCosts(String typeId, double fix, double perSec private final Map matsimVehicles = new HashMap<>(); - private final VehicleTypeDependentRoadPricingCalculator roadPricingCalc; - /** * by default sets the {@link SpeedyALTFactory} */ @@ -568,7 +573,7 @@ private NetworkBasedTransportCosts(Builder builder) { this.travelTime = builder.travelTime; this.network = builder.network; this.leastCostPathCalculatorFactory = builder.leastCostPathCalculatorFactory; - this.roadPricingCalc = builder.roadPricingCalculator; + this.roadPricingScheme = builder.roadPricingScheme; this.timeSliceWidth = builder.timeSliceWidth; this.defaultTypeId = builder.defaultTypeId; this.ttMemorizedCounter = new Counter("#TransportCostValues cached "); @@ -882,8 +887,8 @@ public TravelTime getTravelTime() { * * @return {@link VehicleTypeDependentRoadPricingCalculator} */ - public VehicleTypeDependentRoadPricingCalculator getRoadPricingCalculator() { - return roadPricingCalc; - } +// public VehicleTypeDependentRoadPricingCalculator getRoadPricingCalculator() { +// return roadPricingCalc; +// } } diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VehicleTypeDependentRoadPricingCalculator.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VehicleTypeDependentRoadPricingCalculator.java index ed5d3694720..6175780ab9a 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VehicleTypeDependentRoadPricingCalculator.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/VehicleTypeDependentRoadPricingCalculator.java @@ -35,6 +35,7 @@ * @author stefan schröder * */ +@Deprecated // use RoadPricingScheme public class VehicleTypeDependentRoadPricingCalculator { interface TollCalculator { diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java index 1b7ce8fe5e3..cb90a059a6e 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java @@ -30,10 +30,10 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; +import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; -import org.matsim.contrib.roadpricing.RoadPricingScheme; -import org.matsim.contrib.roadpricing.RoadPricingSchemeImpl; -import org.matsim.contrib.roadpricing.RoadPricingUtils; +import org.matsim.api.core.v01.population.Person; +import org.matsim.contrib.roadpricing.*; import org.matsim.core.config.Config; import org.matsim.core.network.io.MatsimNetworkReader; import org.matsim.core.scenario.ScenarioUtils; @@ -44,6 +44,9 @@ import org.matsim.vehicles.VehicleUtils; import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -194,14 +197,28 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneType(){ /* Create the rpCalculator based on the scheme. * Here, only for one type, the see the vehicleType dependent work of it * */ - VehicleTypeDependentRoadPricingCalculator roadPricingCalculator = new VehicleTypeDependentRoadPricingCalculator(); - roadPricingCalculator.addPricingScheme(TYPE_1, scheme); +// VehicleTypeDependentRoadPricingCalculator roadPricingScheme = new VehicleTypeDependentRoadPricingCalculator(); +// roadPricingScheme.addPricingScheme(TYPE_1, scheme); ///___ End creating from Code + TollFactor tollFactor = new TollFactor(){ + @Override public double getTollFactor( Id personId, Id vehicleId, Id linkId, double time ){ + double tollFactor = 1.; + // find vehicle: + org.matsim.vehicles.Vehicle vehicle = scenario.getVehicles().getVehicles().get( vehicleId ); // das ist schlussendlich ziemlich dumm, aber so ist die Schnittstelle im Moment + VehicleType type = vehicle.getType(); + if ( type......) { + tollFactor = 2.; + } + return tollFactor; + } + }; + RoadPricingScheme schemeUsingTollFactor = new RoadPricingSchemeUsingTollFactor( scheme , tollFactor ); + NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork()); builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); - builder.setRoadPricingCalculator(roadPricingCalculator); //add the rpCalculator to activite the tolling. + builder.setRoadPricingScheme(schemeUsingTollFactor ); NetworkBasedTransportCosts c = builder.build(); Vehicle vehicle1 = mock(Vehicle.class); @@ -284,7 +301,7 @@ void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferently(){ NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork()); builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); - builder.setRoadPricingCalculator(roadPricingCalculator); //add the rpCalculator to activate the tolling. + builder.setRoadPricingScheme(roadPricingCalculator ); //add the rpCalculator to activate the tolling. NetworkBasedTransportCosts c = builder.build(); Vehicle vehicle1 = mock(Vehicle.class); @@ -348,7 +365,7 @@ void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferentlyWithFactor( NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork()); builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); - builder.setRoadPricingCalculator(roadPricingCalculator); //add the rpCalculator to activate the tolling. + builder.setRoadPricingScheme(roadPricingCalculator ); //add the rpCalculator to activate the tolling. NetworkBasedTransportCosts c = builder.build(); Vehicle vehicle1 = mock(Vehicle.class); From ae8aa5ab28408b6343cac852f528f38e08902495 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Mon, 5 Aug 2024 23:09:03 +0200 Subject: [PATCH 171/213] adapt test: use tollFactor --- .../NetworkBasedTransportCostsTest.java | 203 +++++++++--------- 1 file changed, 106 insertions(+), 97 deletions(-) diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java index cb90a059a6e..58681271e6a 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java @@ -203,12 +203,16 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneType(){ TollFactor tollFactor = new TollFactor(){ @Override public double getTollFactor( Id personId, Id vehicleId, Id linkId, double time ){ - double tollFactor = 1.; - // find vehicle: - org.matsim.vehicles.Vehicle vehicle = scenario.getVehicles().getVehicles().get( vehicleId ); // das ist schlussendlich ziemlich dumm, aber so ist die Schnittstelle im Moment - VehicleType type = vehicle.getType(); - if ( type......) { - tollFactor = 2.; + double tollFactor = 0.; + + var vehTypeIdString = VehicleUtils.findVehicle(vehicleId, scenario).getType().getId().toString(); + +// // find vehicle: +// org.matsim.vehicles.Vehicle vehicle = scenario.getVehicles().getVehicles().get( vehicleId ); // das ist schlussendlich ziemlich dumm, aber so ist die Schnittstelle im Moment +// VehicleType type = vehicle.getType(); +// if (TYPE_1.equals(type.getId().toString())) { + if (TYPE_1.equals(vehTypeIdString)) { + tollFactor = 1.; } return tollFactor; } @@ -244,89 +248,89 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneType(){ Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); } - /** - * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} - * In addition, there is added a road pricing scheme. - * Two different schemes are created to toll the two different vehicle types differently. - */ - @Test - void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferently(){ - Config config = new Config(); - config.addCoreModules(); - Scenario scenario = ScenarioUtils.createScenario(config); - new MatsimNetworkReader(scenario.getNetwork()).readFile(utils.getClassInputDirectory() + "network.xml"); - - //Create Rp Scheme from code. - RoadPricingSchemeImpl scheme1 = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); - /* Configure roadpricing scheme. */ - RoadPricingUtils.setName(scheme1, "DemoToll4TestType1"); - RoadPricingUtils.setType(scheme1, RoadPricingScheme.TOLL_TYPE_LINK); - RoadPricingUtils.setDescription(scheme1, "Tolling scheme for test."); - - /* Add general link based toll for one link */ - RoadPricingUtils.addLink(scheme1, Id.createLinkId("21")); - RoadPricingUtils.createAndAddGeneralCost(scheme1, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99); - - //Create Rp Scheme from code. - //Fixme: The following does not work as one may expect: In the end, both schemes are the same object. - // --> It is just added a second entry to the costs, which is not taken into account anyways... - // Questions: - // 1.) How to build ab a second scheme, that is "independently" settable? Currently no new RoadPricingSchemeImpl() can be created without - // the addOrGet methods provided in {@link RoadPricingUtils}. - // 2.) Why does not both costs are summede up in the current behavior, so, the toll is 99.99 + 42.42 = 142.41? - // --> Which one is choose? The first? The higher one?...??? - // One solution might be to use the "withTollFactor" approach. --> Todo write an additional test for it. - // Nevertheless, the current approach leads IMO (KMT) easily to unintentional mistakes. - //kmt, Aug'24 - RoadPricingSchemeImpl scheme2 = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); - /* Configure roadpricing scheme. */ - RoadPricingUtils.setName(scheme2, "DemoToll4TestType1"); - RoadPricingUtils.setType(scheme2, RoadPricingScheme.TOLL_TYPE_LINK); - RoadPricingUtils.setDescription(scheme2, "Tolling scheme for test."); - - /* Add general link based toll for one link */ - RoadPricingUtils.addLink(scheme2, Id.createLinkId("21")); - RoadPricingUtils.createAndAddGeneralCost(scheme2, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 42.42); - - /* Create the rpCalculator based on the scheme. - * Each vehicle type gets affected by a different tolling scheme. - * */ - //FIXME: See above/below: schem1 and scheme2 are the same object.... - VehicleTypeDependentRoadPricingCalculator roadPricingCalculator = new VehicleTypeDependentRoadPricingCalculator(); - roadPricingCalculator.addPricingScheme(TYPE_1, scheme1); - roadPricingCalculator.addPricingScheme(TYPE_2, scheme2); - - ///___ End creating from Code - - NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork()); - builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); - builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); - builder.setRoadPricingScheme(roadPricingCalculator ); //add the rpCalculator to activate the tolling. - NetworkBasedTransportCosts c = builder.build(); - - Vehicle vehicle1 = mock(Vehicle.class); - com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); - when(type1.getMaxVelocity()).thenReturn(5.0); - when(type1.getTypeId()).thenReturn(TYPE_1); - when(vehicle1.getType()).thenReturn(type1); - when(vehicle1.getId()).thenReturn("vehicle1"); - - Vehicle vehicle2 = mock(Vehicle.class); - com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); - when(type2.getMaxVelocity()).thenReturn(5.0); - when(type2.getTypeId()).thenReturn(TYPE_2); - when(vehicle2.getType()).thenReturn(type2); - when(vehicle2.getId()).thenReturn("vehicle2"); - - //vehicle1: includes toll of 99.99 for entering the final link - Assertions.assertEquals(20099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle1), 0.01); - Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle1), 0.01); - - //vehicle 2: includes toll of 42.42 for entering the final link - //Fixme: This currently fails... see comments above. - Assertions.assertEquals(40042.42, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle2), 0.01); - Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); - } +// /** +// * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} +// * In addition, there is added a road pricing scheme. +// * Two different schemes are created to toll the two different vehicle types differently. +// */ +// @Test +// void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferently(){ +// Config config = new Config(); +// config.addCoreModules(); +// Scenario scenario = ScenarioUtils.createScenario(config); +// new MatsimNetworkReader(scenario.getNetwork()).readFile(utils.getClassInputDirectory() + "network.xml"); +// +// //Create Rp Scheme from code. +// RoadPricingSchemeImpl scheme1 = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); +// /* Configure roadpricing scheme. */ +// RoadPricingUtils.setName(scheme1, "DemoToll4TestType1"); +// RoadPricingUtils.setType(scheme1, RoadPricingScheme.TOLL_TYPE_LINK); +// RoadPricingUtils.setDescription(scheme1, "Tolling scheme for test."); +// +// /* Add general link based toll for one link */ +// RoadPricingUtils.addLink(scheme1, Id.createLinkId("21")); +// RoadPricingUtils.createAndAddGeneralCost(scheme1, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99); +// +// //Create Rp Scheme from code. +// //Fixme: The following does not work as one may expect: In the end, both schemes are the same object. +// // --> It is just added a second entry to the costs, which is not taken into account anyways... +// // Questions: +// // 1.) How to build ab a second scheme, that is "independently" settable? Currently no new RoadPricingSchemeImpl() can be created without +// // the addOrGet methods provided in {@link RoadPricingUtils}. +// // 2.) Why does not both costs are summede up in the current behavior, so, the toll is 99.99 + 42.42 = 142.41? +// // --> Which one is choose? The first? The higher one?...??? +// // One solution might be to use the "withTollFactor" approach. --> Todo write an additional test for it. +// // Nevertheless, the current approach leads IMO (KMT) easily to unintentional mistakes. +// //kmt, Aug'24 +// RoadPricingSchemeImpl scheme2 = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); +// /* Configure roadpricing scheme. */ +// RoadPricingUtils.setName(scheme2, "DemoToll4TestType1"); +// RoadPricingUtils.setType(scheme2, RoadPricingScheme.TOLL_TYPE_LINK); +// RoadPricingUtils.setDescription(scheme2, "Tolling scheme for test."); +// +// /* Add general link based toll for one link */ +// RoadPricingUtils.addLink(scheme2, Id.createLinkId("21")); +// RoadPricingUtils.createAndAddGeneralCost(scheme2, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 42.42); +// +// /* Create the rpCalculator based on the scheme. +// * Each vehicle type gets affected by a different tolling scheme. +// * */ +// //FIXME: See above/below: schem1 and scheme2 are the same object.... +// VehicleTypeDependentRoadPricingCalculator roadPricingCalculator = new VehicleTypeDependentRoadPricingCalculator(); +// roadPricingCalculator.addPricingScheme(TYPE_1, scheme1); +// roadPricingCalculator.addPricingScheme(TYPE_2, scheme2); +// +// ///___ End creating from Code +// +// NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork()); +// builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); +// builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); +// builder.setRoadPricingScheme(roadPricingCalculator ); //add the rpCalculator to activate the tolling. +// NetworkBasedTransportCosts c = builder.build(); +// +// Vehicle vehicle1 = mock(Vehicle.class); +// com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); +// when(type1.getMaxVelocity()).thenReturn(5.0); +// when(type1.getTypeId()).thenReturn(TYPE_1); +// when(vehicle1.getType()).thenReturn(type1); +// when(vehicle1.getId()).thenReturn("vehicle1"); +// +// Vehicle vehicle2 = mock(Vehicle.class); +// com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); +// when(type2.getMaxVelocity()).thenReturn(5.0); +// when(type2.getTypeId()).thenReturn(TYPE_2); +// when(vehicle2.getType()).thenReturn(type2); +// when(vehicle2.getId()).thenReturn("vehicle2"); +// +// //vehicle1: includes toll of 99.99 for entering the final link +// Assertions.assertEquals(20099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle1), 0.01); +// Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle1), 0.01); +// +// //vehicle 2: includes toll of 42.42 for entering the final link +// //Fixme: This currently fails... see comments above. +// Assertions.assertEquals(40042.42, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle2), 0.01); +// Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); +// } /** * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} @@ -336,7 +340,6 @@ void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferently(){ * //TODO: Write it completely */ @Test - @Disabled void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferentlyWithFactor(){ Config config = new Config(); config.addCoreModules(); @@ -355,17 +358,24 @@ void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferentlyWithFactor( RoadPricingUtils.createAndAddGeneralCost(scheme1, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99); //Use a factor to take into account the differnt types. type2 gehts tolled with 50% of the toll of type1 - //TODO: Include factor - - VehicleTypeDependentRoadPricingCalculator roadPricingCalculator = new VehicleTypeDependentRoadPricingCalculator(); - roadPricingCalculator.addPricingScheme(TYPE_1, scheme1); + TollFactor tollFactor = (personId, vehicleId, linkId, time) -> { + var vehTypeIdString = VehicleUtils.findVehicle(vehicleId, scenario).getType().getId().toString(); + if (TYPE_1.equals(vehTypeIdString)) { + return 1; + } else if (TYPE_2.equals(vehTypeIdString)) { + return 0.5; + } else { + return 0; + } + }; + RoadPricingSchemeUsingTollFactor rpSchemeWTollFactor = new RoadPricingSchemeUsingTollFactor( scheme1 , tollFactor ); - ///___ End creating from Code + ///___ End creating toll scheme from code NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork()); builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); - builder.setRoadPricingScheme(roadPricingCalculator ); //add the rpCalculator to activate the tolling. + builder.setRoadPricingScheme(rpSchemeWTollFactor); //add the rpCalculator to activate the tolling. NetworkBasedTransportCosts c = builder.build(); Vehicle vehicle1 = mock(Vehicle.class); @@ -387,7 +397,6 @@ void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferentlyWithFactor( Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle1), 0.01); //vehicle 2: includes toll of 49.995 (50% of 99.99) for entering the final link - //Fixme: This currently fails... see comments above. Assertions.assertEquals(40049.995, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle2), 0.01); Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); } From 3bc9b188fb6d1e61d49291545ccaa486ddc09916 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Mon, 5 Aug 2024 23:09:32 +0200 Subject: [PATCH 172/213] add option if person==null --- .../carriers/jsprit/NetworkBasedTransportCosts.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java index 6ad51d3f5bc..df48a3e6451 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java @@ -340,7 +340,12 @@ public double getLinkTravelDisutility(Link link, double time, Person person, double costs = baseTransportDisutility.getLinkTravelDisutility(link, time, person, vehicle); // Id typeId = vehicle.getType().getId(); // double toll = roadPricingScheme.getTollAmount(typeId, link, time ); - RoadPricingSchemeImpl.Cost costInfo = roadPricingScheme.getLinkCostInfo( link.getId(), time, person.getId(), vehicle.getId() ); + RoadPricingSchemeImpl.Cost costInfo; + if (person == null) { + costInfo = roadPricingScheme.getLinkCostInfo( link.getId(), time, null, vehicle.getId() ); + } else { + costInfo = roadPricingScheme.getLinkCostInfo( link.getId(), time, person.getId(), vehicle.getId() ); + } double toll = costInfo.amount; // System.out.println("huuuuuuuuuuuuuuuuuuuu - paid toll"); return costs + toll; From f051660abb897ac0b5bebf44db93066405e030ca Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Tue, 6 Aug 2024 09:14:53 +0200 Subject: [PATCH 173/213] more tests --- .../NetworkBasedTransportCostsTest.java | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java index 58681271e6a..7de43a75c87 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java @@ -169,6 +169,60 @@ void test_whenAddingTwoVehicleTypesViaConstructor_itMustAccountForThat(){ Assertions.assertEquals(20000.0, networkBasedTransportCosts.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); } + + /** + * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} + * In addition, there is added a road pricing scheme. + * The scheme is only set for one vehicle type: type1. + * So, only the vehicle using that type (vehicle1) should be tolled, the other (vehicle2) not. + * + */ + @Test + void test_whenAddingTwoDifferentVehicleTypes_tollAllTypes(){ + Config config = new Config(); + config.addCoreModules(); + Scenario scenario = ScenarioUtils.createScenario(config); + new MatsimNetworkReader(scenario.getNetwork()).readFile(utils.getClassInputDirectory() + "network.xml"); + + //Create Rp Scheme from code. + RoadPricingSchemeImpl scheme = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); + /* Configure roadpricing scheme. */ + RoadPricingUtils.setName(scheme, "DemoToll4Test"); + RoadPricingUtils.setType(scheme, RoadPricingScheme.TOLL_TYPE_LINK); + RoadPricingUtils.setDescription(scheme, "Tolling scheme for test."); + + /* Add general link based toll for one link */ + RoadPricingUtils.addLink(scheme, Id.createLinkId("21")); + RoadPricingUtils.createAndAddGeneralCost(scheme, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99); + + NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork()); + builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); + builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); + builder.setRoadPricingScheme(scheme); + NetworkBasedTransportCosts c = builder.build(); + + Vehicle vehicle1 = mock(Vehicle.class); + com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); + when(type1.getMaxVelocity()).thenReturn(5.0); + when(type1.getTypeId()).thenReturn(TYPE_1); + when(vehicle1.getType()).thenReturn(type1); + when(vehicle1.getId()).thenReturn("vehicle1"); + + Vehicle vehicle2 = mock(Vehicle.class); + com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); + when(type2.getMaxVelocity()).thenReturn(5.0); + when(type2.getTypeId()).thenReturn(TYPE_2); + when(vehicle2.getType()).thenReturn(type2); + when(vehicle2.getId()).thenReturn("vehicle2"); + + //vehicle1: includes toll + Assertions.assertEquals(20099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle1), 0.01); + Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle1), 0.01); + + //vehicle 2: no toll + Assertions.assertEquals(40099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle2), 0.01); + Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); + } /** * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} * In addition, there is added a road pricing scheme. @@ -177,7 +231,7 @@ void test_whenAddingTwoVehicleTypesViaConstructor_itMustAccountForThat(){ * */ @Test - void test_whenAddingTwoDifferentVehicleTypes_tollOneType(){ + void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){ Config config = new Config(); config.addCoreModules(); Scenario scenario = ScenarioUtils.createScenario(config); From 99f008a937b17517515066f7826b66b474123272 Mon Sep 17 00:00:00 2001 From: Kai Nagel Date: Tue, 6 Aug 2024 09:54:59 +0200 Subject: [PATCH 174/213] more steps forward --- .../jsprit/NetworkBasedTransportCosts.java | 5 +- .../NetworkBasedTransportCostsTest.java | 46 ++++++++++++++----- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java index df48a3e6451..e12b8b1b1e3 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java @@ -346,7 +346,10 @@ public double getLinkTravelDisutility(Link link, double time, Person person, } else { costInfo = roadPricingScheme.getLinkCostInfo( link.getId(), time, person.getId(), vehicle.getId() ); } - double toll = costInfo.amount; + double toll=0.; + if ( costInfo != null ){ + toll = costInfo.amount; + } // System.out.println("huuuuuuuuuuuuuuuuuuuu - paid toll"); return costs + toll; } diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java index 7de43a75c87..f4049d554a1 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java @@ -28,6 +28,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.network.Link; @@ -38,10 +39,12 @@ import org.matsim.core.network.io.MatsimNetworkReader; import org.matsim.core.scenario.ScenarioUtils; import org.matsim.core.utils.misc.Time; +import org.matsim.freight.carriers.CarrierVehicle; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.CostInformation; import org.matsim.vehicles.VehicleType; import org.matsim.vehicles.VehicleUtils; +import org.matsim.vehicles.VehiclesFactory; import java.util.Arrays; import java.util.List; @@ -279,19 +282,38 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){ builder.setRoadPricingScheme(schemeUsingTollFactor ); NetworkBasedTransportCosts c = builder.build(); - Vehicle vehicle1 = mock(Vehicle.class); - com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); - when(type1.getMaxVelocity()).thenReturn(5.0); - when(type1.getTypeId()).thenReturn(TYPE_1); - when(vehicle1.getType()).thenReturn(type1); - when(vehicle1.getId()).thenReturn("vehicle1"); + VehiclesFactory vf = scenario.getVehicles().getFactory(); + final Vehicle vehicle1; + { + VehicleType vehType1 = vf.createVehicleType( Id.create( TYPE_1, VehicleType.class ) ); + scenario.getVehicles().addVehicleType( vehType1 ); +// org.matsim.vehicles.Vehicle matsimVehicle1 = vf.createVehicle( Id.createVehicleId( "vehicle1" ), vehType1 ); + CarrierVehicle matsimVehicle1 = CarrierVehicle.newInstance( Id.createVehicleId( "vehicle1" ), null, vehType1 ); + scenario.getVehicles().addVehicle( matsimVehicle1 ); + vehicle1 = MatsimJspritFactory.createJspritVehicle( matsimVehicle1, new Coord() ); + } + VehicleType vehType2 = vf.createVehicleType( Id.create( TYPE_2, VehicleType.class ) ); + scenario.getVehicles().addVehicleType( vehType2 ); +// org.matsim.vehicles.Vehicle matsimVehicle2 = vf.createVehicle( Id.createVehicleId( "vehicle2" ), vehType2 ); + CarrierVehicle matsimVehicle2 = CarrierVehicle.newInstance( Id.createVehicleId( "vehicle2" ), null, vehType2 ); + scenario.getVehicles().addVehicle( matsimVehicle2 ); - Vehicle vehicle2 = mock(Vehicle.class); - com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); - when(type2.getMaxVelocity()).thenReturn(5.0); - when(type2.getTypeId()).thenReturn(TYPE_2); - when(vehicle2.getType()).thenReturn(type2); - when(vehicle2.getId()).thenReturn("vehicle2"); + Vehicle vehicle2 = MatsimJspritFactory.createJspritVehicle( matsimVehicle2, new Coord() ); + +// // for the following rather use the MatsimJspritFactory#createCarrierVehicle +// Vehicle vehicle1 = mock(Vehicle.class); +// com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); +// when(type1.getMaxVelocity()).thenReturn(5.0); +// when(type1.getTypeId()).thenReturn(TYPE_1); +// when(vehicle1.getType()).thenReturn(type1); +// when(vehicle1.getId()).thenReturn("vehicle1"); +// +// Vehicle vehicle2 = mock(Vehicle.class); +// com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); +// when(type2.getMaxVelocity()).thenReturn(5.0); +// when(type2.getTypeId()).thenReturn(TYPE_2); +// when(vehicle2.getType()).thenReturn(type2); +// when(vehicle2.getId()).thenReturn("vehicle2"); //vehicle1: includes toll Assertions.assertEquals(20099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle1), 0.01); From 9b3f81881594988eedbd5082889e820c70b345c4 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Tue, 6 Aug 2024 11:12:29 +0200 Subject: [PATCH 175/213] fix one test: Use MATSim's vehicles --- .../NetworkBasedTransportCostsTest.java | 168 ++++-------------- 1 file changed, 34 insertions(+), 134 deletions(-) diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java index f4049d554a1..d1a8a5107bc 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java @@ -40,6 +40,7 @@ import org.matsim.core.scenario.ScenarioUtils; import org.matsim.core.utils.misc.Time; import org.matsim.freight.carriers.CarrierVehicle; +import org.matsim.freight.carriers.CarriersUtils; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.CostInformation; import org.matsim.vehicles.VehicleType; @@ -240,7 +241,7 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){ Scenario scenario = ScenarioUtils.createScenario(config); new MatsimNetworkReader(scenario.getNetwork()).readFile(utils.getClassInputDirectory() + "network.xml"); - //Create Rp Scheme from code. + //Create RoadPricing Scheme from code. RoadPricingSchemeImpl scheme = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); /* Configure roadpricing scheme. */ RoadPricingUtils.setName(scheme, "DemoToll4Test"); @@ -251,69 +252,51 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){ RoadPricingUtils.addLink(scheme, Id.createLinkId("21")); RoadPricingUtils.createAndAddGeneralCost(scheme, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99); - /* Create the rpCalculator based on the scheme. - * Here, only for one type, the see the vehicleType dependent work of it - * */ -// VehicleTypeDependentRoadPricingCalculator roadPricingScheme = new VehicleTypeDependentRoadPricingCalculator(); -// roadPricingScheme.addPricingScheme(TYPE_1, scheme); - ///___ End creating from Code - - TollFactor tollFactor = new TollFactor(){ - @Override public double getTollFactor( Id personId, Id vehicleId, Id linkId, double time ){ - double tollFactor = 0.; - - var vehTypeIdString = VehicleUtils.findVehicle(vehicleId, scenario).getType().getId().toString(); - -// // find vehicle: -// org.matsim.vehicles.Vehicle vehicle = scenario.getVehicles().getVehicles().get( vehicleId ); // das ist schlussendlich ziemlich dumm, aber so ist die Schnittstelle im Moment -// VehicleType type = vehicle.getType(); -// if (TYPE_1.equals(type.getId().toString())) { - if (TYPE_1.equals(vehTypeIdString)) { - tollFactor = 1.; - } - return tollFactor; + //Use toll factor to only toll vehicles of type1. + TollFactor tollFactor = (personId, vehicleId, linkId, time) -> { + double tollFactor1 = 0.; + var vehTypeIdString = VehicleUtils.findVehicle(vehicleId, scenario).getType().getId().toString(); + if (TYPE_1.equals(vehTypeIdString)) { + tollFactor1 = 1.; } + return tollFactor1; }; RoadPricingScheme schemeUsingTollFactor = new RoadPricingSchemeUsingTollFactor( scheme , tollFactor ); - NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork()); - builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); - builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); - builder.setRoadPricingScheme(schemeUsingTollFactor ); - NetworkBasedTransportCosts c = builder.build(); + /// End creating roadPricing scheme from Code + //Build MATSim vehicles and convert them to jsprit Vehicles ... just to see, that this works across the whole chain and + //that we can filter/search by (MATSim) vehicle types in Toll Factor usage VehiclesFactory vf = scenario.getVehicles().getFactory(); final Vehicle vehicle1; { VehicleType vehType1 = vf.createVehicleType( Id.create( TYPE_1, VehicleType.class ) ); + vehType1.getCostInformation().setFixedCost(10.0); + vehType1.getCostInformation().setCostsPerSecond(0.0); + vehType1.getCostInformation().setCostsPerMeter(2.0); scenario.getVehicles().addVehicleType( vehType1 ); -// org.matsim.vehicles.Vehicle matsimVehicle1 = vf.createVehicle( Id.createVehicleId( "vehicle1" ), vehType1 ); - CarrierVehicle matsimVehicle1 = CarrierVehicle.newInstance( Id.createVehicleId( "vehicle1" ), null, vehType1 ); + CarrierVehicle matsimVehicle1 = CarrierVehicle.newInstance( Id.createVehicleId( "vehicle1" ), Id.createLinkId("20"), vehType1 ); scenario.getVehicles().addVehicle( matsimVehicle1 ); vehicle1 = MatsimJspritFactory.createJspritVehicle( matsimVehicle1, new Coord() ); } - VehicleType vehType2 = vf.createVehicleType( Id.create( TYPE_2, VehicleType.class ) ); - scenario.getVehicles().addVehicleType( vehType2 ); -// org.matsim.vehicles.Vehicle matsimVehicle2 = vf.createVehicle( Id.createVehicleId( "vehicle2" ), vehType2 ); - CarrierVehicle matsimVehicle2 = CarrierVehicle.newInstance( Id.createVehicleId( "vehicle2" ), null, vehType2 ); - scenario.getVehicles().addVehicle( matsimVehicle2 ); - - Vehicle vehicle2 = MatsimJspritFactory.createJspritVehicle( matsimVehicle2, new Coord() ); - -// // for the following rather use the MatsimJspritFactory#createCarrierVehicle -// Vehicle vehicle1 = mock(Vehicle.class); -// com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); -// when(type1.getMaxVelocity()).thenReturn(5.0); -// when(type1.getTypeId()).thenReturn(TYPE_1); -// when(vehicle1.getType()).thenReturn(type1); -// when(vehicle1.getId()).thenReturn("vehicle1"); -// -// Vehicle vehicle2 = mock(Vehicle.class); -// com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); -// when(type2.getMaxVelocity()).thenReturn(5.0); -// when(type2.getTypeId()).thenReturn(TYPE_2); -// when(vehicle2.getType()).thenReturn(type2); -// when(vehicle2.getId()).thenReturn("vehicle2"); + + final Vehicle vehicle2; + { + VehicleType vehType2 = vf.createVehicleType(Id.create(TYPE_2, VehicleType.class)); + vehType2.getCostInformation().setFixedCost(20.0); + vehType2.getCostInformation().setCostsPerSecond(0.0); + vehType2.getCostInformation().setCostsPerMeter(4.0); + scenario.getVehicles().addVehicleType(vehType2); + + CarrierVehicle matsimVehicle2 = CarrierVehicle.newInstance(Id.createVehicleId("vehicle2"), Id.createLinkId("20"), vehType2); + scenario.getVehicles().addVehicle(matsimVehicle2); + vehicle2 = MatsimJspritFactory.createJspritVehicle(matsimVehicle2, new Coord()); + } + + //Build the NetbasedTransportCosts opbejct with the roadpricing scheme. + NetworkBasedTransportCosts c = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork(), scenario.getVehicles().getVehicleTypes().values() ) + .setRoadPricingScheme(schemeUsingTollFactor) + .build() ; //vehicle1: includes toll Assertions.assertEquals(20099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle1), 0.01); @@ -324,89 +307,6 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){ Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); } -// /** -// * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} -// * In addition, there is added a road pricing scheme. -// * Two different schemes are created to toll the two different vehicle types differently. -// */ -// @Test -// void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferently(){ -// Config config = new Config(); -// config.addCoreModules(); -// Scenario scenario = ScenarioUtils.createScenario(config); -// new MatsimNetworkReader(scenario.getNetwork()).readFile(utils.getClassInputDirectory() + "network.xml"); -// -// //Create Rp Scheme from code. -// RoadPricingSchemeImpl scheme1 = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); -// /* Configure roadpricing scheme. */ -// RoadPricingUtils.setName(scheme1, "DemoToll4TestType1"); -// RoadPricingUtils.setType(scheme1, RoadPricingScheme.TOLL_TYPE_LINK); -// RoadPricingUtils.setDescription(scheme1, "Tolling scheme for test."); -// -// /* Add general link based toll for one link */ -// RoadPricingUtils.addLink(scheme1, Id.createLinkId("21")); -// RoadPricingUtils.createAndAddGeneralCost(scheme1, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99); -// -// //Create Rp Scheme from code. -// //Fixme: The following does not work as one may expect: In the end, both schemes are the same object. -// // --> It is just added a second entry to the costs, which is not taken into account anyways... -// // Questions: -// // 1.) How to build ab a second scheme, that is "independently" settable? Currently no new RoadPricingSchemeImpl() can be created without -// // the addOrGet methods provided in {@link RoadPricingUtils}. -// // 2.) Why does not both costs are summede up in the current behavior, so, the toll is 99.99 + 42.42 = 142.41? -// // --> Which one is choose? The first? The higher one?...??? -// // One solution might be to use the "withTollFactor" approach. --> Todo write an additional test for it. -// // Nevertheless, the current approach leads IMO (KMT) easily to unintentional mistakes. -// //kmt, Aug'24 -// RoadPricingSchemeImpl scheme2 = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); -// /* Configure roadpricing scheme. */ -// RoadPricingUtils.setName(scheme2, "DemoToll4TestType1"); -// RoadPricingUtils.setType(scheme2, RoadPricingScheme.TOLL_TYPE_LINK); -// RoadPricingUtils.setDescription(scheme2, "Tolling scheme for test."); -// -// /* Add general link based toll for one link */ -// RoadPricingUtils.addLink(scheme2, Id.createLinkId("21")); -// RoadPricingUtils.createAndAddGeneralCost(scheme2, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 42.42); -// -// /* Create the rpCalculator based on the scheme. -// * Each vehicle type gets affected by a different tolling scheme. -// * */ -// //FIXME: See above/below: schem1 and scheme2 are the same object.... -// VehicleTypeDependentRoadPricingCalculator roadPricingCalculator = new VehicleTypeDependentRoadPricingCalculator(); -// roadPricingCalculator.addPricingScheme(TYPE_1, scheme1); -// roadPricingCalculator.addPricingScheme(TYPE_2, scheme2); -// -// ///___ End creating from Code -// -// NetworkBasedTransportCosts.Builder builder = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork()); -// builder.addVehicleTypeSpecificCosts(TYPE_1, 10.0, 0.0, 2.0); -// builder.addVehicleTypeSpecificCosts(TYPE_2, 20.0, 0.0, 4.0); -// builder.setRoadPricingScheme(roadPricingCalculator ); //add the rpCalculator to activate the tolling. -// NetworkBasedTransportCosts c = builder.build(); -// -// Vehicle vehicle1 = mock(Vehicle.class); -// com.graphhopper.jsprit.core.problem.vehicle.VehicleType type1 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); -// when(type1.getMaxVelocity()).thenReturn(5.0); -// when(type1.getTypeId()).thenReturn(TYPE_1); -// when(vehicle1.getType()).thenReturn(type1); -// when(vehicle1.getId()).thenReturn("vehicle1"); -// -// Vehicle vehicle2 = mock(Vehicle.class); -// com.graphhopper.jsprit.core.problem.vehicle.VehicleType type2 = mock( com.graphhopper.jsprit.core.problem.vehicle.VehicleType.class ); -// when(type2.getMaxVelocity()).thenReturn(5.0); -// when(type2.getTypeId()).thenReturn(TYPE_2); -// when(vehicle2.getType()).thenReturn(type2); -// when(vehicle2.getId()).thenReturn("vehicle2"); -// -// //vehicle1: includes toll of 99.99 for entering the final link -// Assertions.assertEquals(20099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle1), 0.01); -// Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle1), 0.01); -// -// //vehicle 2: includes toll of 42.42 for entering the final link -// //Fixme: This currently fails... see comments above. -// Assertions.assertEquals(40042.42, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle2), 0.01); -// Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); -// } /** * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} From 8a3cd452528f9da7486fff38613d09e9fa2da517 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Tue, 6 Aug 2024 11:27:02 +0200 Subject: [PATCH 176/213] fix the last test: Building the netbased costs without MATSim's vehicle types --- .../NetworkBasedTransportCostsTest.java | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java index d1a8a5107bc..65b691b5737 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java @@ -25,7 +25,6 @@ import com.graphhopper.jsprit.core.problem.driver.Driver; import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.api.core.v01.Coord; @@ -40,7 +39,6 @@ import org.matsim.core.scenario.ScenarioUtils; import org.matsim.core.utils.misc.Time; import org.matsim.freight.carriers.CarrierVehicle; -import org.matsim.freight.carriers.CarriersUtils; import org.matsim.testcases.MatsimTestUtils; import org.matsim.vehicles.CostInformation; import org.matsim.vehicles.VehicleType; @@ -48,9 +46,6 @@ import org.matsim.vehicles.VehiclesFactory; import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -176,10 +171,7 @@ void test_whenAddingTwoVehicleTypesViaConstructor_itMustAccountForThat(){ /** * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} - * In addition, there is added a road pricing scheme. - * The scheme is only set for one vehicle type: type1. - * So, only the vehicle using that type (vehicle1) should be tolled, the other (vehicle2) not. - * + * In addition, there is added a road pricing scheme to toll all vehicles */ @Test void test_whenAddingTwoDifferentVehicleTypes_tollAllTypes(){ @@ -227,12 +219,14 @@ void test_whenAddingTwoDifferentVehicleTypes_tollAllTypes(){ Assertions.assertEquals(40099.99, c.getTransportCost(Location.newInstance("20"), Location.newInstance("21"), 0.0, mock(Driver.class), vehicle2), 0.01); Assertions.assertEquals(20000.0, c.getDistance(Location.newInstance("6"), Location.newInstance("21"), 0.0, vehicle2), 0.01); } + /** * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} * In addition, there is added a road pricing scheme. * The scheme is only set for one vehicle type: type1. * So, only the vehicle using that type (vehicle1) should be tolled, the other (vehicle2) not. - * + * This test is build, in a way, that it uses the MATSim infrastructure for filtering the vehicles in the toll factor. + * To see it just on jsprit setting, please refer to {@link #test_whenAddingTwoDifferentVehicleTypes_tollBasedOnVehicleId} */ @Test void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){ @@ -255,7 +249,7 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){ //Use toll factor to only toll vehicles of type1. TollFactor tollFactor = (personId, vehicleId, linkId, time) -> { double tollFactor1 = 0.; - var vehTypeIdString = VehicleUtils.findVehicle(vehicleId, scenario).getType().getId().toString(); + var vehTypeIdString = VehicleUtils.findVehicle(vehicleId, scenario).getType().getId().toString(); //This needs, the vehicles registered in the scenario. if (TYPE_1.equals(vehTypeIdString)) { tollFactor1 = 1.; } @@ -266,7 +260,7 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){ /// End creating roadPricing scheme from Code //Build MATSim vehicles and convert them to jsprit Vehicles ... just to see, that this works across the whole chain and - //that we can filter/search by (MATSim) vehicle types in Toll Factor usage + //that we can filter/search by (MATSim) vehicle types in TollFactor usage VehiclesFactory vf = scenario.getVehicles().getFactory(); final Vehicle vehicle1; { @@ -294,7 +288,9 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){ } //Build the NetbasedTransportCosts opbejct with the roadpricing scheme. - NetworkBasedTransportCosts c = NetworkBasedTransportCosts.Builder.newInstance(scenario.getNetwork(), scenario.getVehicles().getVehicleTypes().values() ) + NetworkBasedTransportCosts c = NetworkBasedTransportCosts.Builder.newInstance( + scenario.getNetwork(), + scenario.getVehicles().getVehicleTypes().values() ) .setRoadPricingScheme(schemeUsingTollFactor) .build() ; @@ -311,12 +307,12 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){ /** * This test is a modified version of {@link #test_whenAddingTwoDifferentVehicleTypes_itMustAccountForThem} * In addition, there is added a road pricing scheme. - * Two different schemes are created to toll the two different vehicle types differently. - * Here the approach using a factor is used to take into account the different types. - * //TODO: Write it completely + * With using a toll factor, the tolling can be set differently for the two vehicles. + * This test is build, in a way, that it uses the JSPRIT vehicle directly. + * To see it with the MATSim settings, please refer to {@link #test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor()} */ @Test - void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferentlyWithFactor(){ + void test_whenAddingTwoDifferentVehicleTypes_tollBasedOnVehicleId(){ Config config = new Config(); config.addCoreModules(); Scenario scenario = ScenarioUtils.createScenario(config); @@ -334,14 +330,19 @@ void test_whenAddingTwoDifferentVehicleTypes_tollBothTypesDifferentlyWithFactor( RoadPricingUtils.createAndAddGeneralCost(scheme1, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99); //Use a factor to take into account the differnt types. type2 gehts tolled with 50% of the toll of type1 - TollFactor tollFactor = (personId, vehicleId, linkId, time) -> { - var vehTypeIdString = VehicleUtils.findVehicle(vehicleId, scenario).getType().getId().toString(); - if (TYPE_1.equals(vehTypeIdString)) { - return 1; - } else if (TYPE_2.equals(vehTypeIdString)) { - return 0.5; - } else { - return 0; + TollFactor tollFactor = new TollFactor() { + @Override + public double getTollFactor(Id personId, Id vehicleId, Id linkId, double time) { + //No information about the vehicleType available anywhere, because is is nowhere registered centrally, + // -> Use the vehicleId to distinguish the types. + var vehTypeIdString = vehicleId.toString(); + if (vehTypeIdString.equals("vehicle1")) { + return 1; + } else if (vehTypeIdString.equals("vehicle2")) { + return 0.5; + } else { + return 0; + } } }; RoadPricingSchemeUsingTollFactor rpSchemeWTollFactor = new RoadPricingSchemeUsingTollFactor( scheme1 , tollFactor ); From 883f2d34fbfa617038acefd8a51a02e3a4207a62 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Tue, 6 Aug 2024 11:37:37 +0200 Subject: [PATCH 177/213] some cleanup and javadoc --- .../jsprit/NetworkBasedTransportCosts.java | 44 +++++++------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java index e12b8b1b1e3..e6d8e1a0e45 100644 --- a/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java +++ b/contribs/freight/src/main/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCosts.java @@ -320,7 +320,6 @@ private static class VehicleTypeVarCosts { */ static class VehicleTransportCostsIncludingToll implements TravelDisutility { -// private static Logger logger = LogManager.getLogger(VehicleTransportCostsIncludingToll.class); private final TravelDisutility baseTransportDisutility; @@ -331,26 +330,24 @@ public VehicleTransportCostsIncludingToll( TravelDisutility baseTransportDisutil super(); this.baseTransportDisutility = baseTransportDisutility; this.roadPricingScheme = roadPricingScheme; -// System.out.println("huuuuuuuuuuuuuuuuuuuu - initialize transport costs with toll"); } @Override public double getLinkTravelDisutility(Link link, double time, Person person, org.matsim.vehicles.Vehicle vehicle) { double costs = baseTransportDisutility.getLinkTravelDisutility(link, time, person, vehicle); -// Id typeId = vehicle.getType().getId(); -// double toll = roadPricingScheme.getTollAmount(typeId, link, time ); + RoadPricingSchemeImpl.Cost costInfo; if (person == null) { costInfo = roadPricingScheme.getLinkCostInfo( link.getId(), time, null, vehicle.getId() ); } else { costInfo = roadPricingScheme.getLinkCostInfo( link.getId(), time, person.getId(), vehicle.getId() ); } - double toll=0.; + + double toll = 0.; if ( costInfo != null ){ toll = costInfo.amount; } -// System.out.println("huuuuuuuuuuuuuuuuuuuu - paid toll"); return costs + toll; } @@ -408,7 +405,7 @@ public static Builder newInstance(Network network) { * Creates the builder requiring {@link Network} and a collection of * {@link VehicleType}. * - * @param network + * @param network the MATSim network * @param vehicleTypes must be all vehicleTypes and their assigned * costInformation in the system. */ @@ -429,7 +426,7 @@ private void retrieveTypeSpecificCosts(Collection vehicleTypes) { * Sets the travelTime. By default, travelTime is based on * link.getFreespeed();. * - * @param travelTime + * @param travelTime the travelTime to set * @return this builder */ public Builder setTravelTime(TravelTime travelTime) { @@ -478,7 +475,7 @@ public Builder setFIFO(boolean isFIFO) { *

        * By default, it use {@link SpeedyALTFactory} * - * @param {@link {@link LeastCostPathCalculatorFactory} + * @param leastCostPathCalcFactory {@link LeastCostPathCalculatorFactory} * @return this builder */ public Builder setThreadSafeLeastCostPathCalculatorFactory( @@ -526,10 +523,10 @@ public NetworkBasedTransportCosts build() { * Adds type-specific costs. If typeId already exists, existing entry is * overwritten. * - * @param typeId - * @param fix - * @param perSecond - * @param perMeter + * @param typeId the vehicleType-id as String + * @param fix fix costs for the vehicle + * @param perSecond variable costs per second + * @param perMeter variable costs per meter */ public void addVehicleTypeSpecificCosts(String typeId, double fix, double perSecond, double perMeter) { typeSpecificCosts.put(typeId, new VehicleTypeVarCosts(perMeter, perSecond)); @@ -598,7 +595,7 @@ private NetworkBasedTransportCosts(Builder builder) { * cached travel-time. If not, it computes and caches new values with the * leastCostPathCalc defined in here. * - * @Throws {@link IllegalStateException} if vehicle is null + * @exception IllegalStateException if vehicle is null */ @Override public double getTransportTime(Location fromId, Location toId, double departureTime, Driver driver, @@ -679,7 +676,7 @@ private void informStartCalc() { * cached travel-cost value. If not, it computes and caches new values with the * leastCostPathCalc defined in here. * - * @Throws {@link IllegalStateException} if vehicle is null + * @exception IllegalStateException if vehicle is null */ @Override public double getTransportCost(Location fromId, Location toId, double departureTime, Driver driver, @@ -747,7 +744,7 @@ public double getTransportCost(Location fromId, Location toId, double departureT * cached distance. If not, it computes and caches new values with the * leastCostPathCalc defined in here. * - * @Throws {@link IllegalStateException} if vehicle is null + * @exception IllegalStateException if vehicle is null */ @Override public double getDistance(Location fromId, Location toId, double departureTime, Vehicle vehicle) { @@ -812,7 +809,7 @@ public Collection getInternalListeners( * This is a rather bad approximation. If you require this, you should implement * another {@link VehicleRoutingTransportCosts} * - * @Throws {@link IllegalStateException} if vehicle is null + * @exception IllegalStateException if vehicle is null */ @Override public double getBackwardTransportCost(Location fromId, Location toId, double arrivalTime, Driver driver, @@ -828,7 +825,7 @@ public double getBackwardTransportCost(Location fromId, Location toId, double ar * This is a rather bad approximation. If you require this, you should implement * another {@link VehicleRoutingTransportCosts}. * - * @Throws {@link IllegalStateException} if vehicle is null + * @exception IllegalStateException if vehicle is null */ @Override public double getBackwardTransportTime(Location fromId, Location toId, double arrivalTime, Driver driver, @@ -875,7 +872,7 @@ private int getTimeSlice(double time) { /** * Gets the network the calculation is based on. * - * @return + * @return the network */ public Network getNetwork() { return network; @@ -890,13 +887,4 @@ public TravelTime getTravelTime() { return travelTime; } - /** - * Gets the {@link VehicleTypeDependentRoadPricingCalculator} - * - * @return {@link VehicleTypeDependentRoadPricingCalculator} - */ -// public VehicleTypeDependentRoadPricingCalculator getRoadPricingCalculator() { -// return roadPricingCalc; -// } - } From 307c602ab7577fd5bcebb7fc7d9c285b8de70b67 Mon Sep 17 00:00:00 2001 From: Kai Martins-Turner Date: Tue, 6 Aug 2024 11:42:33 +0200 Subject: [PATCH 178/213] fix typos, internal renaming --- .../NetworkBasedTransportCostsTest.java | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java index 65b691b5737..64e7eeba641 100644 --- a/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java +++ b/contribs/freight/src/test/java/org/matsim/freight/carriers/jsprit/NetworkBasedTransportCostsTest.java @@ -30,9 +30,7 @@ import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; -import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; -import org.matsim.api.core.v01.population.Person; import org.matsim.contrib.roadpricing.*; import org.matsim.core.config.Config; import org.matsim.core.network.io.MatsimNetworkReader; @@ -255,7 +253,7 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){ } return tollFactor1; }; - RoadPricingScheme schemeUsingTollFactor = new RoadPricingSchemeUsingTollFactor( scheme , tollFactor ); + RoadPricingScheme rpSchemeWTollFactor = new RoadPricingSchemeUsingTollFactor( scheme , tollFactor ); /// End creating roadPricing scheme from Code @@ -287,11 +285,11 @@ void test_whenAddingTwoDifferentVehicleTypes_tollOneTypeTollFactor(){ vehicle2 = MatsimJspritFactory.createJspritVehicle(matsimVehicle2, new Coord()); } - //Build the NetbasedTransportCosts opbejct with the roadpricing scheme. + //Build the NetbasedTransportCosts object with the roadpricing scheme. NetworkBasedTransportCosts c = NetworkBasedTransportCosts.Builder.newInstance( scenario.getNetwork(), scenario.getVehicles().getVehicleTypes().values() ) - .setRoadPricingScheme(schemeUsingTollFactor) + .setRoadPricingScheme(rpSchemeWTollFactor) .build() ; //vehicle1: includes toll @@ -319,33 +317,30 @@ void test_whenAddingTwoDifferentVehicleTypes_tollBasedOnVehicleId(){ new MatsimNetworkReader(scenario.getNetwork()).readFile(utils.getClassInputDirectory() + "network.xml"); //Create Rp Scheme from code. - RoadPricingSchemeImpl scheme1 = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); + RoadPricingSchemeImpl scheme = RoadPricingUtils.addOrGetMutableRoadPricingScheme(scenario ); /* Configure roadpricing scheme. */ - RoadPricingUtils.setName(scheme1, "DemoToll4TestType1"); - RoadPricingUtils.setType(scheme1, RoadPricingScheme.TOLL_TYPE_LINK); - RoadPricingUtils.setDescription(scheme1, "Tolling scheme for test."); + RoadPricingUtils.setName(scheme, "DemoToll4TestType1"); + RoadPricingUtils.setType(scheme, RoadPricingScheme.TOLL_TYPE_LINK); + RoadPricingUtils.setDescription(scheme, "Tolling scheme for test."); /* Add general link based toll for one link */ - RoadPricingUtils.addLink(scheme1, Id.createLinkId("21")); - RoadPricingUtils.createAndAddGeneralCost(scheme1, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99); - - //Use a factor to take into account the differnt types. type2 gehts tolled with 50% of the toll of type1 - TollFactor tollFactor = new TollFactor() { - @Override - public double getTollFactor(Id personId, Id vehicleId, Id linkId, double time) { - //No information about the vehicleType available anywhere, because is is nowhere registered centrally, - // -> Use the vehicleId to distinguish the types. - var vehTypeIdString = vehicleId.toString(); - if (vehTypeIdString.equals("vehicle1")) { - return 1; - } else if (vehTypeIdString.equals("vehicle2")) { - return 0.5; - } else { - return 0; - } + RoadPricingUtils.addLink(scheme, Id.createLinkId("21")); + RoadPricingUtils.createAndAddGeneralCost(scheme, Time.parseTime("00:00:00"), Time.parseTime("72:00:00"), 99.99); + + //Use a factor to take into account the different types. type2 gehts tolled with 50% of the toll of type1 + TollFactor tollFactor = (personId, vehicleId, linkId, time) -> { + //No information about the vehicleType available anywhere, because it is not registered centrally. + // -> Use the vehicleId to distinguish the types. + var vehTypeIdString = vehicleId.toString(); + if (vehTypeIdString.equals("vehicle1")) { + return 1; + } else if (vehTypeIdString.equals("vehicle2")) { + return 0.5; + } else { + return 0; } }; - RoadPricingSchemeUsingTollFactor rpSchemeWTollFactor = new RoadPricingSchemeUsingTollFactor( scheme1 , tollFactor ); + RoadPricingSchemeUsingTollFactor rpSchemeWTollFactor = new RoadPricingSchemeUsingTollFactor( scheme , tollFactor ); ///___ End creating toll scheme from code From 71c63dbac2f19d82e022c73a403c3ec8f029c09e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 11:41:11 +0000 Subject: [PATCH 179/213] Bump org.apache.maven.plugins:maven-surefire-report-plugin Bumps [org.apache.maven.plugins:maven-surefire-report-plugin](https://github.com/apache/maven-surefire) from 3.3.0 to 3.3.1. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.3.0...surefire-3.3.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-report-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- matsim/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matsim/pom.xml b/matsim/pom.xml index 17556c8ac08..3f2321ada6d 100644 --- a/matsim/pom.xml +++ b/matsim/pom.xml @@ -118,7 +118,7 @@ org.apache.maven.plugins maven-surefire-report-plugin - 3.3.0 + 3.3.1 From 79c687fce1bdd909e2a2e0b233f348bbd220a6a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:14:38 +0000 Subject: [PATCH 180/213] Bump io.grpc:grpc-all from 1.65.0 to 1.65.1 Bumps [io.grpc:grpc-all](https://github.com/grpc/grpc-java) from 1.65.0 to 1.65.1. - [Release notes](https://github.com/grpc/grpc-java/releases) - [Commits](https://github.com/grpc/grpc-java/compare/v1.65.0...v1.65.1) --- updated-dependencies: - dependency-name: io.grpc:grpc-all dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- contribs/hybridsim/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/hybridsim/pom.xml b/contribs/hybridsim/pom.xml index 5917f032e3e..f58a572c939 100644 --- a/contribs/hybridsim/pom.xml +++ b/contribs/hybridsim/pom.xml @@ -11,7 +11,7 @@ 4.27.2 - 1.65.0 + 1.65.1 From b0a5f3d57d3db96989c1fc5a9674f08b82539094 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:14:40 +0000 Subject: [PATCH 181/213] Bump org.apache.maven.plugins:maven-surefire-plugin from 3.3.0 to 3.3.1 Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.3.0 to 3.3.1. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.3.0...surefire-3.3.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d03e82ea2be..995cc8c2bd8 100644 --- a/pom.xml +++ b/pom.xml @@ -420,7 +420,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.3.0 + 3.3.1 org.apache.maven.plugins From 0ab26476a926ac768f27df7849e2b9468c99dbe9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 13:42:09 +0000 Subject: [PATCH 182/213] Bump commons-codec:commons-codec from 1.17.0 to 1.17.1 Bumps [commons-codec:commons-codec](https://github.com/apache/commons-codec) from 1.17.0 to 1.17.1. - [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-codec/compare/rel/commons-codec-1.17.0...rel/commons-codec-1.17.1) --- updated-dependencies: - dependency-name: commons-codec:commons-codec dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 995cc8c2bd8..404796a50b1 100644 --- a/pom.xml +++ b/pom.xml @@ -128,7 +128,7 @@ commons-codec commons-codec - 1.17.0 + 1.17.1 org.apache.commons From 43b3bcb411c9fddc0bfb9a3fee9480a63c930804 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:33:54 +0000 Subject: [PATCH 183/213] Bump it.unimi.dsi:fastutil-core from 8.5.13 to 8.5.14 Bumps [it.unimi.dsi:fastutil-core](https://github.com/vigna/fastutil) from 8.5.13 to 8.5.14. - [Changelog](https://github.com/vigna/fastutil/blob/master/CHANGES) - [Commits](https://github.com/vigna/fastutil/commits/8.5.14) --- updated-dependencies: - dependency-name: it.unimi.dsi:fastutil-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- matsim/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matsim/pom.xml b/matsim/pom.xml index 3f2321ada6d..7f768fffe76 100644 --- a/matsim/pom.xml +++ b/matsim/pom.xml @@ -127,7 +127,7 @@ it.unimi.dsi fastutil-core - 8.5.13 + 8.5.14 org.geotools From 799bf544ebe9b3a0418602751c60549d19ddbb8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:34:09 +0000 Subject: [PATCH 184/213] Bump geotools.version from 31.2 to 31.3 Bumps `geotools.version` from 31.2 to 31.3. Updates `org.geotools:gt-main` from 31.2 to 31.3 Updates `org.geotools:gt-referencing` from 31.2 to 31.3 Updates `org.geotools:gt-shapefile` from 31.2 to 31.3 Updates `org.geotools:gt-epsg-hsql` from 31.2 to 31.3 Updates `org.geotools:gt-epsg-extension` from 31.2 to 31.3 Updates `org.geotools:gt-api` from 31.2 to 31.3 Updates `org.geotools.jdbc:gt-jdbc-postgis` from 31.2 to 31.3 Updates `org.geotools:gt-geopkg` from 31.2 to 31.3 Updates `org.geotools:gt-geotiff` from 31.2 to 31.3 Updates `org.geotools:gt-geojson` from 31.2 to 31.3 Updates `org.geotools:gt-coverage` from 31.2 to 31.3 --- updated-dependencies: - dependency-name: org.geotools:gt-main dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.geotools:gt-referencing dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.geotools:gt-shapefile dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.geotools:gt-epsg-hsql dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.geotools:gt-epsg-extension dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.geotools:gt-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.geotools.jdbc:gt-jdbc-postgis dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.geotools:gt-geopkg dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.geotools:gt-geotiff dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.geotools:gt-geojson dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.geotools:gt-coverage dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 404796a50b1..a049d60560f 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ 2.23.1 - 31.2 + 31.3 0.49.2 1.19.0 7.0.0 From 5bf784e34d408d34d607c9acd4e85d305e53d348 Mon Sep 17 00:00:00 2001 From: rakow Date: Tue, 6 Aug 2024 17:16:37 +0200 Subject: [PATCH 185/213] Preserve the working directory when gui is run from cli (#3391) --- .../org/matsim/application/MATSimApplication.java | 2 ++ .../main/java/org/matsim/application/ShowGUI.java | 7 +++++++ matsim/src/main/java/org/matsim/run/gui/Gui.java | 14 ++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java b/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java index 4e4c6860d63..2425a0f1491 100644 --- a/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java +++ b/contribs/application/src/main/java/org/matsim/application/MATSimApplication.java @@ -413,6 +413,8 @@ public static void runWithDefaults(Class clazz, Str if (ApplicationUtils.isRunFromDesktop() && args.length == 0) { + System.setProperty("MATSIM_GUI_DESKTOP", "true"); + if (defaultArgs.length > 0) { String value = String.join(ARGS_DELIMITER, defaultArgs); System.setProperty("MATSIM_GUI_ARGS", value); diff --git a/contribs/application/src/main/java/org/matsim/application/ShowGUI.java b/contribs/application/src/main/java/org/matsim/application/ShowGUI.java index e394bfd7b79..6400262eb95 100644 --- a/contribs/application/src/main/java/org/matsim/application/ShowGUI.java +++ b/contribs/application/src/main/java/org/matsim/application/ShowGUI.java @@ -40,6 +40,13 @@ public Integer call() throws Exception { Gui gui = f.get(); + // Set the current working directory to be used in the gui, when run from the command line + // If the gui is run from desktop, the working directory is not overwritten + + // Assumption is that starting something from command line, the user expects that the working directory remains the same + if (!System.getProperty("MATSIM_GUI_DESKTOP", "false").equals("true")) + gui.setWorkingDirectory(new File("")); + while (gui.isShowing()) Thread.sleep(250); diff --git a/matsim/src/main/java/org/matsim/run/gui/Gui.java b/matsim/src/main/java/org/matsim/run/gui/Gui.java index 4b826b14842..1ca4a9afc8d 100644 --- a/matsim/src/main/java/org/matsim/run/gui/Gui.java +++ b/matsim/src/main/java/org/matsim/run/gui/Gui.java @@ -91,6 +91,11 @@ public class Gui extends JFrame { private File configFile; private File lastUsedDirectory; + + /** + * This is the working directory for the simulation. If it is null, the working directory is the directory of the config file. + */ + private File workingDirectory = null; private ConfigEditor editor = null; private ScheduleValidatorWindow transitValidator = null; @@ -439,6 +444,8 @@ private void startMATSim() { textStdOut.setText(""); textErrOut.setText(""); + String cwd = workingDirectory == null ? new File(txtConfigfilename.getText()).getParent() : workingDirectory.getAbsolutePath(); + new Thread(() -> { String classpath = System.getProperty("java.class.path"); String[] cpParts = classpath.split(File.pathSeparator); @@ -457,8 +464,7 @@ private void startMATSim() { "--add-exports", "java.desktop/sun.java2d=ALL-UNNAMED", mainClass, txtConfigfilename.getText() }; // see https://jogamp.org/bugzilla/show_bug.cgi?id=1317#c21 and/or https://github.com/matsim-org/matsim-libs/pull/2940 - exeRunner = ExeRunner.run(cmdArgs, textStdOut, textErrOut, - new File(txtConfigfilename.getText()).getParent()); + exeRunner = ExeRunner.run(cmdArgs, textStdOut, textErrOut, cwd); int exitcode = exeRunner.waitForFinish(); exeRunner = null; @@ -575,6 +581,10 @@ public static void main(String[] args) { Gui.show("MATSim", RunMatsim.class, args.length == 1 ? new File(args[0]) : null); } + public void setWorkingDirectory(File cwd) { + this.workingDirectory = cwd; + } + // Is it a problem to make the following available to the outside? If so, why? Would it // be better to rather copy/paste the above code and start from there? kai, jun/aug'18 From 4e4afdcb6822f294685f67ccc8b039b15744f176 Mon Sep 17 00:00:00 2001 From: schlenther Date: Wed, 7 Aug 2024 16:36:03 +0200 Subject: [PATCH 186/213] use asterisk for act type default --- .../org/matsim/application/analysis/noise/NoiseAnalysis.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java index c5927fcdb04..7cd5fea5502 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java @@ -46,7 +46,8 @@ public class NoiseAnalysis implements MATSimAppCommand { @CommandLine.Mixin private final ShpOptions shp = new ShpOptions(); - @CommandLine.Option(names = "--consider-activities", split = ",", description = "Considered activities for noise calculation", defaultValue = "h,w,home,work") + @CommandLine.Option(names = "--consider-activities", split = ",", description = "Considered activities for noise calculation." + + " Use asterisk ('*') for acttype prefixes, if all such acts shall be considered.", defaultValue = "h,w,home*,work*") private Set considerActivities; @CommandLine.Option(names = "--noise-barrier", description = "Path to the noise barrier File", defaultValue = "") From 6a30c28d370e72729199eee0d9a48741f9cc98d8 Mon Sep 17 00:00:00 2001 From: schlenther Date: Wed, 7 Aug 2024 17:24:55 +0200 Subject: [PATCH 187/213] NoiseAnalysis: set the scale factor for according to sample size --- .../analysis/noise/NoiseAnalysis.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java index 7cd5fea5502..6730cae8996 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java @@ -1,5 +1,7 @@ package org.matsim.application.analysis.noise; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.locationtech.jts.geom.Envelope; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Scenario; @@ -8,6 +10,7 @@ import org.matsim.application.MATSimAppCommand; import org.matsim.application.options.InputOptions; import org.matsim.application.options.OutputOptions; +import org.matsim.application.options.SampleOptions; import org.matsim.application.options.ShpOptions; import org.matsim.contrib.noise.NoiseConfigGroup; import org.matsim.contrib.noise.NoiseOfflineCalculation; @@ -38,6 +41,8 @@ ) public class NoiseAnalysis implements MATSimAppCommand { + private static final Logger log = LogManager.getLogger(NoiseAnalysis.class); + @CommandLine.Mixin private final InputOptions input = InputOptions.ofCommand(NoiseAnalysis.class); @CommandLine.Mixin @@ -46,6 +51,9 @@ public class NoiseAnalysis implements MATSimAppCommand { @CommandLine.Mixin private final ShpOptions shp = new ShpOptions(); + @CommandLine.Mixin + private final SampleOptions sampleOptions = new SampleOptions(); + @CommandLine.Option(names = "--consider-activities", split = ",", description = "Considered activities for noise calculation." + " Use asterisk ('*') for acttype prefixes, if all such acts shall be considered.", defaultValue = "h,w,home*,work*") private Set considerActivities; @@ -89,6 +97,16 @@ public Integer call() throws Exception { noiseParameters.setNoiseBarriersFilePath(noiseBarrierFile); } + if(! sampleOptions.isSet() && noiseParameters.getScaleFactor() == 1d){ + log.warn("You didn't provide the simulation sample size via command line option --sample-size! This means, noise damages are not scaled!!!"); + } else if (noiseParameters.getScaleFactor() == 1d){ + if (sampleOptions.getSample() == 1d){ + log.warn("Be aware that the noise output is not scaled. This might be unintended. If so, assure to provide the sample size via command line option --sample-size, in the SimWrapperConfigGroup," + + "or provide the scaleFactor (the inverse of the sample size) in the NoiseConfigGroup!!!"); + } + noiseParameters.setScaleFactor(sampleOptions.getUpscaleFactor()); + } + Scenario scenario = ScenarioUtils.loadScenario(config); String outputFilePath = output.getPath().getParent() == null ? "." : output.getPath().getParent().toString(); @@ -120,6 +138,7 @@ private Config prepareConfig() { config.facilities().setInputFile(null); config.eventsManager().setNumberOfThreads(null); config.eventsManager().setEstimatedNumberOfEvents(null); + //ts, aug '24: not sure if and why we need to set 1 thread config.global().setNumberOfThreads(1); return config; From ea1f72cef8315e9d253fde79198ffaa471c96ceb Mon Sep 17 00:00:00 2001 From: simei94 <67737999+simei94@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:09:32 +0200 Subject: [PATCH 188/213] add fare zone based pt pricing (#3382) * first try to implement fare zone based pt pricing, deutschlandtarif numbers still missing * put deutschlandtarif price linear functions into code * unit test for FareZoneBasedPtFareHandler --- .../pt/fare/DistanceBasedPtFareParams.java | 13 ++ .../pt/fare/FareZoneBasedPtFareHandler.java | 163 ++++++++++++++++++ .../vsp/pt/fare/PtFareConfigGroup.java | 2 +- .../playground/vsp/pt/fare/PtFareModule.java | 11 +- .../fare/FareZoneBasedPtFareHandlerTest.java | 124 +++++++++++++ .../scenarios/kelheim/ptTestArea/pt-area.cpg | 1 + .../scenarios/kelheim/ptTestArea/pt-area.dbf | Bin 0 -> 330 bytes .../scenarios/kelheim/ptTestArea/pt-area.prj | 1 + .../scenarios/kelheim/ptTestArea/pt-area.shp | Bin 0 -> 348 bytes .../scenarios/kelheim/ptTestArea/pt-area.shx | Bin 0 -> 108 bytes 10 files changed, 310 insertions(+), 5 deletions(-) create mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandler.java create mode 100644 contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java create mode 100644 examples/scenarios/kelheim/ptTestArea/pt-area.cpg create mode 100644 examples/scenarios/kelheim/ptTestArea/pt-area.dbf create mode 100644 examples/scenarios/kelheim/ptTestArea/pt-area.prj create mode 100644 examples/scenarios/kelheim/ptTestArea/pt-area.shp create mode 100644 examples/scenarios/kelheim/ptTestArea/pt-area.shx diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java index a86cd173c14..442d956bf3c 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java @@ -22,6 +22,7 @@ public class DistanceBasedPtFareParams extends ReflectiveConfigGroup { public static final String LONG_DISTANCE_TRIP_THRESHOLD = "longDistanceTripThreshold"; public static final String LONG_DISTANCE_TRIP_SLOPE = "longDistanceTripSlope"; public static final String LONG_DISTANCE_TRIP_INTERCEPT = "longDistanceTripIntercept"; + public static final String FARE_ZONE_SHP = "fareZoneShp"; @PositiveOrZero private double minFare = 2.0; @@ -35,6 +36,7 @@ public class DistanceBasedPtFareParams extends ReflectiveConfigGroup { private double longDistanceTripIntercept = 30.0; @PositiveOrZero private double longDistanceTripSlope = 0.00025; + private String fareZoneShp; public DistanceBasedPtFareParams() { super(SET_NAME); @@ -52,6 +54,7 @@ public Map getComments() { map.put(LONG_DISTANCE_TRIP_THRESHOLD, "Threshold of the long trips in meters. Below this value, " + "the trips are considered as normal trips. Above this value, the trips are considered as " + "inter-city trips"); + map.put(FARE_ZONE_SHP, "Shp file with fare zone(s). This parameter is only used for PtFareCalculationModel 'fareZoneBased'."); return map; } @@ -114,4 +117,14 @@ public double getLongDistanceTripThreshold() { public void setLongDistanceTripThreshold(double longDistanceTripThreshold) { this.longDistanceTripThreshold = longDistanceTripThreshold; } + + @StringGetter(FARE_ZONE_SHP) + public String getFareZoneShp() { + return fareZoneShp; + } + + @StringSetter(FARE_ZONE_SHP) + public void setFareZoneShp(String fareZoneShp) { + this.fareZoneShp = fareZoneShp; + } } diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandler.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandler.java new file mode 100644 index 00000000000..962a18fac57 --- /dev/null +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandler.java @@ -0,0 +1,163 @@ +package playground.vsp.pt.fare; + +import com.google.inject.Inject; +import org.apache.commons.math.stat.regression.SimpleRegression; +import org.geotools.api.feature.simple.SimpleFeature; +import org.locationtech.jts.geom.Geometry; +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.ActivityStartEvent; +import org.matsim.api.core.v01.events.PersonMoneyEvent; +import org.matsim.api.core.v01.events.handler.ActivityStartEventHandler; +import org.matsim.api.core.v01.population.Person; +import org.matsim.application.options.ShpOptions; +import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.router.StageActivityTypeIdentifier; +import org.matsim.core.utils.geometry.CoordUtils; +import org.matsim.core.utils.geometry.geotools.MGC; +import org.matsim.pt.PtConstants; + +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FareZoneBasedPtFareHandler implements ActivityStartEventHandler { + @Inject + private EventsManager events; + + public static final String FARE = "fare"; + public static final String PT_FARE_ZONE_BASED = "fare zone based pt fare"; + public static final String PT_GERMANWIDE_FARE_BASED = "german-wide fare based pt fare"; + + private final ShpOptions shp; + + private final Map, Coord> personDepartureCoordMap = new HashMap<>(); + private final Map, Coord> personArrivalCoordMap = new HashMap<>(); + + public FareZoneBasedPtFareHandler(DistanceBasedPtFareParams params) { + this.shp = new ShpOptions(params.getFareZoneShp(), null, null); + } + + @Override + public void handleEvent(ActivityStartEvent event) { + + if (event.getActType().equals(PtConstants.TRANSIT_ACTIVITY_TYPE)) { + personDepartureCoordMap.computeIfAbsent(event.getPersonId(), c -> event.getCoord()); // The departure place is fixed to the place of first pt interaction an agent has in the whole leg + personArrivalCoordMap.put(event.getPersonId(), event.getCoord()); // The arrival stop will keep updating until the agent start a real activity (i.e. finish the leg) + } + + if (!StageActivityTypeIdentifier.isStageActivity(event.getActType())) { + Id personId = event.getPersonId(); + if (personDepartureCoordMap.containsKey(personId)) { + double distance = CoordUtils.calcEuclideanDistance + (personDepartureCoordMap.get(personId), personArrivalCoordMap.get(personId)); + + SimpleFeature departureZone = determineFareZone(personDepartureCoordMap.get(personId), shp.readFeatures()); + SimpleFeature arrivalZone = determineFareZone(personArrivalCoordMap.get(personId), shp.readFeatures()); + + Map.Entry fareEntry = computeFare(distance, departureZone, arrivalZone); + // charge fare to the person + events.processEvent( + new PersonMoneyEvent(event.getTime(), event.getPersonId(), -fareEntry.getValue(), + PtFareConfigGroup.PT_FARE, fareEntry.getKey(), event.getPersonId().toString())); + + personDepartureCoordMap.remove(personId); + personArrivalCoordMap.remove(personId); + } + } + } + + public static Map.Entry computeFare(double distance, SimpleFeature departureZone, SimpleFeature arrivalZone) { + + if (departureZone != null && arrivalZone != null) { +// if both zones are not null -> departure and arrival point are inside of one of the tarifzonen + if (departureZone.getID().equals(arrivalZone.getID())) { + return new AbstractMap.SimpleEntry<>(PT_FARE_ZONE_BASED ,(double) departureZone.getAttribute(FARE)); + } + } +// in every other case return german wide fare / Deutschlandtarif + return getGermanWideFare(distance); + } + + private static Map.Entry getGermanWideFare(double distance) { + + SimpleRegression regression = new SimpleRegression(); + +// in Deutschlandtarif, the linear function for the prices above 100km seem to have a different steepness +// hence the following difference in data points +// prices taken from https://deutschlandtarifverbund.de/wp-content/uploads/2024/07/20231201_TBDT_J_10_Preisliste_V07.pdf + if (distance / 1000 <= 100.) { + regression.addData(1, 1.70); + regression.addData(2,1.90); + regression.addData(3,2.00); + regression.addData(4,2.10); + regression.addData(5,2.20); + regression.addData(6,3.20); + regression.addData(7,3.70); + regression.addData(8,3.80); + regression.addData(9,3.90); + regression.addData(10,4.10); + regression.addData(11,5.00); + regression.addData(12,5.40); + regression.addData(13,5.60); + regression.addData(14,5.80); + regression.addData(15,5.90); + regression.addData(16,6.40); + regression.addData(17,6.50); + regression.addData(18,6.60); + regression.addData(19,6.70); + regression.addData(20,6.90); + regression.addData(30,9.90); + regression.addData(40,13.70); + regression.addData(50,16.30); + regression.addData(60,18.10); + regression.addData(70,20.10); + regression.addData(80,23.20); + regression.addData(90,26.20); + regression.addData(100,28.10); + } else { + regression.addData(100,28.10); + regression.addData(200,47.20); + regression.addData(300,59.70); + regression.addData(400,71.70); + regression.addData(500,83.00); + regression.addData(600,94.60); + regression.addData(700,106.30); + regression.addData(800,118.20); + regression.addData(900,130.10); + regression.addData(1000,141.00); + regression.addData(1100,148.60); + regression.addData(1200,158.10); + regression.addData(1300,169.20); + regression.addData(1400,179.80); + regression.addData(1500,190.10); + regression.addData(1600,201.50); + regression.addData(1700,212.80); + regression.addData(1800,223.30); + regression.addData(1900,233.90); + regression.addData(2000,244.00); + } + return new AbstractMap.SimpleEntry<>(PT_GERMANWIDE_FARE_BASED, regression.getSlope() * distance / 1000 + regression.getIntercept()); + } + + static SimpleFeature determineFareZone(Coord coord, List features) { + SimpleFeature zone = null; + + for (SimpleFeature ft : features) { + Geometry geom = (Geometry) ft.getDefaultGeometry(); + + if (MGC.coord2Point(coord).within(geom)) { + zone = ft; + break; + } + } + return zone; + } + + @Override + public void reset(int iteration) { + personArrivalCoordMap.clear(); + personDepartureCoordMap.clear(); + } +} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java index 20c9291dc1b..8abf76dcb37 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java @@ -13,7 +13,7 @@ public class PtFareConfigGroup extends ReflectiveConfigGroup { public static final String APPLY_UPPER_BOUND = "applyUpperBound"; public static final String UPPER_BOUND_FACTOR = "upperBoundFactor"; - public enum PtFareCalculationModels {distanceBased} // More to come (e.g. zone based, hybrid...) + public enum PtFareCalculationModels {distanceBased, fareZoneBased} // More to come (e.g. zone based, hybrid...) private static final String PT_FARE_CALCULATION_CMT = "PT fare calculation scheme. Current implementation: distanceBased (more to come...)"; public static final String UPPER_BOUND_FACTOR_CMT = "When upper bound is applied, upperBound = upperBoundFactor * max Fare of the day. " + diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java index 9bd25cc81f4..4da41c16612 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java @@ -11,12 +11,15 @@ public void install() { getConfig().scoring().getModes().get(TransportMode.pt).setDailyMonetaryConstant(0); getConfig().scoring().getModes().get(TransportMode.pt).setMarginalUtilityOfDistance(0); PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(this.getConfig(), PtFareConfigGroup.class); + DistanceBasedPtFareParams distanceBasedPtFareParams = ConfigUtils.addOrGetModule(this.getConfig(), DistanceBasedPtFareParams.class); + if (ptFareConfigGroup.getPtFareCalculation() == PtFareConfigGroup.PtFareCalculationModels.distanceBased) { - DistanceBasedPtFareParams distanceBasedPtFareParams = ConfigUtils.addOrGetModule(this.getConfig(), DistanceBasedPtFareParams.class); - addEventHandlerBinding().toInstance(new DistanceBasedPtFareHandler(distanceBasedPtFareParams)); - } else { + addEventHandlerBinding().toInstance(new DistanceBasedPtFareHandler(distanceBasedPtFareParams)); + } else if (ptFareConfigGroup.getPtFareCalculation() == PtFareConfigGroup.PtFareCalculationModels.fareZoneBased) { + addEventHandlerBinding().toInstance(new FareZoneBasedPtFareHandler(distanceBasedPtFareParams)); + } else { throw new RuntimeException("Please choose from the following fare Calculation method: [" + - PtFareConfigGroup.PtFareCalculationModels.distanceBased + "]"); + PtFareConfigGroup.PtFareCalculationModels.distanceBased + ", " + PtFareConfigGroup.PtFareCalculationModels.fareZoneBased + "]"); } if (ptFareConfigGroup.getApplyUpperBound()) { diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java b/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java new file mode 100644 index 00000000000..ec486ec2cee --- /dev/null +++ b/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java @@ -0,0 +1,124 @@ +package playground.vsp.pt.fare; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.matsim.analysis.personMoney.PersonMoneyEventsAnalysisModule; +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.population.*; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.ScoringConfigGroup; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.controler.OutputDirectoryHierarchy; +import org.matsim.core.scenario.MutableScenario; +import org.matsim.core.scenario.ScenarioUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.testcases.MatsimTestUtils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import static org.matsim.application.ApplicationUtils.globFile; + +public class FareZoneBasedPtFareHandlerTest { + + @RegisterExtension + private MatsimTestUtils utils = new MatsimTestUtils(); + + @Test + void testFareZoneBasedPtFareHandler() { + + URL context = ExamplesUtils.getTestScenarioURL("kelheim"); + Config config = ConfigUtils.loadConfig(IOUtils.extendUrl(context, "config.xml")); + config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + config.controller().setLastIteration(0); + + PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(config, PtFareConfigGroup.class); + ptFareConfigGroup.setPtFareCalculationModel(PtFareConfigGroup.PtFareCalculationModels.fareZoneBased); + + DistanceBasedPtFareParams fareParams = ConfigUtils.addOrGetModule(config, DistanceBasedPtFareParams.class); + fareParams.setFareZoneShp(IOUtils.extendUrl(context, "ptTestArea/pt-area.shp").toString()); + + + ScoringConfigGroup scoring = ConfigUtils.addOrGetModule(config, ScoringConfigGroup.class); + + ScoringConfigGroup.ActivityParams homeParams = new ScoringConfigGroup.ActivityParams("home"); + ScoringConfigGroup.ActivityParams workParams = new ScoringConfigGroup.ActivityParams("work"); + homeParams.setTypicalDuration(8 * 3600.); + workParams.setTypicalDuration(8 * 3600.); + scoring.addActivityParams(homeParams); + scoring.addActivityParams(workParams); + + + MutableScenario scenario = (MutableScenario) ScenarioUtils.loadScenario(config); + + Population population = ScenarioUtils.createScenario(ConfigUtils.createConfig()).getPopulation(); + PopulationFactory fac = population.getFactory(); + + Person person = fac.createPerson(Id.createPersonId("fareTestPerson")); + Plan plan = fac.createPlan(); + + Activity home = fac.createActivityFromCoord("home", new Coord(710300.624,5422165.737)); +// bus to Saal (Donau) work location departs at 09:14 + home.setEndTime(9 * 3600.); + Activity work = fac.createActivityFromCoord("work", new Coord(714940.65,5420707.78)); +// rb17 to regensburg 2nd home location departs at 13:59 + work.setEndTime(13 * 3600. + 45 * 60); + Activity home2 = fac.createActivityFromCoord("home", new Coord(726634.40,5433508.07)); + + Leg leg = fac.createLeg(TransportMode.pt); + + plan.addActivity(home); + plan.addLeg(leg); + plan.addActivity(work); + plan.addLeg(leg); + plan.addActivity(home2); + + person.addPlan(plan); + population.addPerson(person); + scenario.setPopulation(population); + + Controler controler = new Controler(scenario); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new PtFareModule()); + install(new PersonMoneyEventsAnalysisModule()); + } + }); + controler.run(); + + Assertions.assertTrue(Files.exists(Path.of(utils.getOutputDirectory()))); + +// read personMoneyEvents.tsv and check if both fare entries do have the correct fare type + String filePath = globFile(Path.of(utils.getOutputDirectory()), "*output_personMoneyEvents.tsv*").toString(); + String line; + List events = new ArrayList<>(); + + try (BufferedReader br = IOUtils.getBufferedReader(filePath)) { +// skip header + br.readLine(); + + while ((line = br.readLine()) != null) { + events.add(line.split(";")); + } + } catch (IOException e) { + e.printStackTrace(); + } + + Assertions.assertEquals(2, events.size()); + Assertions.assertEquals(FareZoneBasedPtFareHandler.PT_FARE_ZONE_BASED, events.get(0)[4]); + Assertions.assertEquals(FareZoneBasedPtFareHandler.PT_GERMANWIDE_FARE_BASED, events.get(1)[4]); + } +} diff --git a/examples/scenarios/kelheim/ptTestArea/pt-area.cpg b/examples/scenarios/kelheim/ptTestArea/pt-area.cpg new file mode 100644 index 00000000000..3ad133c048f --- /dev/null +++ b/examples/scenarios/kelheim/ptTestArea/pt-area.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/examples/scenarios/kelheim/ptTestArea/pt-area.dbf b/examples/scenarios/kelheim/ptTestArea/pt-area.dbf new file mode 100644 index 0000000000000000000000000000000000000000..e17541dab999012ee260f988c47319e51b56771b GIT binary patch literal 330 zcmZRs;b3KCU|=}N&;cYdL1qeE%n!ukf^#7ZKSy6zsE{*=4uEoClw**qBa{u+FToF! zfzY}6DXCBquzqy&(-Mnd@?ibk%&7W#72v?oB`8GKzaX_Ju_QA;PuH<1H4!dH7DEdM QNGU2oG0#xX)WARr09(r;z5oCK literal 0 HcmV?d00001 diff --git a/examples/scenarios/kelheim/ptTestArea/pt-area.prj b/examples/scenarios/kelheim/ptTestArea/pt-area.prj new file mode 100644 index 00000000000..bd846aeb220 --- /dev/null +++ b/examples/scenarios/kelheim/ptTestArea/pt-area.prj @@ -0,0 +1 @@ +PROJCS["ETRS_1989_UTM_Zone_32N",GEOGCS["GCS_ETRS_1989",DATUM["D_ETRS_1989",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",9.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/examples/scenarios/kelheim/ptTestArea/pt-area.shp b/examples/scenarios/kelheim/ptTestArea/pt-area.shp new file mode 100644 index 0000000000000000000000000000000000000000..a798ec1b8bf6937c07c6ae55c679a3412e7ed06c GIT binary patch literal 348 zcmZQzQ0HR64%WS3W?*0i$~B%pRI_f5s-x}KoKT)MA&w%6yXAh}RdtN$O*Qq|6yk_o zJBlbHkXJ#BSs;ZxP_0`Ue5%7&A?(@l?+fR%4XTbAo*xc~1MPM7dbfGwSye}!_#c^8 z8$ulKPBn4ceM8kzTFdgwi**QhZY(?{Vzf5IanJUzBC~I*Iwo!6?6wB_c)s#!Nj)zS8APAJcs5J!>3-EzO~syasWrkeU}3US1) L9Yxd#$g2PVpUn^* literal 0 HcmV?d00001 From e981bde003b91aa599b51cac12c43d36ea35ed6a Mon Sep 17 00:00:00 2001 From: schlenther Date: Thu, 8 Aug 2024 16:34:20 +0200 Subject: [PATCH 189/213] better defaults for NoiseDashboard --- .../org/matsim/simwrapper/dashboard/NoiseDashboard.java | 8 ++++---- .../main/java/org/matsim/simwrapper/viz/ColorScheme.java | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java index dc934e6c2e2..b502f3fbf57 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java @@ -42,7 +42,7 @@ public void configure(Header header, Layout layout) { viz.maxHeight = 20; viz.center = data.context().getCenter(); viz.zoom = data.context().mapZoomLevel; - viz.setColorRamp(new double[]{40, 50, 60}, new String[]{"#1175b3", "#95c7df", "#f4a986", "#cc0c27"}); + viz.setColorRamp(new double[]{30, 40, 50, 60, 70}, new String[]{"#1175b3", "#95c7df", "#dfdb95", "#dfb095", "#f4a986", "#cc0c27"}); viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "immission_per_day.%s", "avro"); }) .el(MapPlot.class, (viz, data) -> { @@ -58,8 +58,8 @@ public void configure(Header header, Layout layout) { viz.display.lineColor.dataset = "noise"; viz.display.lineColor.columnName = "value"; viz.display.lineColor.join = "Link Id"; - viz.display.lineColor.fixedColors = new String[]{"#1175b3", "#95c7df", "#f4a986", "#cc0c27"}; - viz.display.lineColor.setColorRamp(ColorScheme.RdYlBu, 4, true, "45, 55, 65"); + //viz.display.lineColor.fixedColors = new String[]{"#1175b3", "#95c7df", "#f4a986", "#cc0c27"}; + viz.display.lineColor.setColorRamp(ColorScheme.Oranges, 8, false, "35, 45, 55, 65, 75, 85, 95"); viz.display.lineWidth.dataset = "noise"; viz.display.lineWidth.columnName = "value"; viz.display.lineWidth.scaleFactor = 8d; @@ -75,7 +75,7 @@ public void configure(Header header, Layout layout) { viz.maxHeight = 20; viz.center = data.context().getCenter(); viz.zoom = data.context().mapZoomLevel; - viz.setColorRamp(new double[]{40, 50, 60}, new String[]{"#1175b3", "#95c7df", "#f4a986", "#cc0c27"}); + viz.setColorRamp(new double[]{30, 40, 50, 60, 70}, new String[]{"#1175b3", "#95c7df", "#dfdb95", "#dfb095", "#f4a986", "#cc0c27"}); viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "immission_per_hour.%s", "avro"); }); } diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/ColorScheme.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/ColorScheme.java index 37e31cc97ca..df8f6410679 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/ColorScheme.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/viz/ColorScheme.java @@ -27,6 +27,7 @@ public final class ColorScheme { public static final String Inferne = "Inferne"; public static final String Cividis = "Cividis"; public static final String Rainbow = "Rainbow"; + public static final String Oranges = "Oranges"; private ColorScheme() { From cdfe0bc6de01513c198ed851e089a212e2da2b11 Mon Sep 17 00:00:00 2001 From: Ricardo Ewert Date: Thu, 8 Aug 2024 17:02:45 +0200 Subject: [PATCH 190/213] remove the static --- .../prepare/CreateDataDistributionOfStructureData.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/prepare/CreateDataDistributionOfStructureData.java b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/prepare/CreateDataDistributionOfStructureData.java index 477231505c1..dcd4c3732d9 100644 --- a/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/prepare/CreateDataDistributionOfStructureData.java +++ b/contribs/small-scale-traffic-generation/src/main/java/org/matsim/smallScaleCommercialTrafficGeneration/prepare/CreateDataDistributionOfStructureData.java @@ -29,7 +29,7 @@ public class CreateDataDistributionOfStructureData implements MATSimAppCommand { private static final Logger log = LogManager.getLogger(CreateDataDistributionOfStructureData.class); - private static LanduseDataConnectionCreator landuseDataConnectionCreator; + private final LanduseDataConnectionCreator landuseDataConnectionCreator; private enum LanduseConfiguration { useOnlyOSMLanduse, useOSMBuildingsAndLanduse @@ -78,16 +78,16 @@ private enum LanduseConfiguration { private final Map>> buildingsPerZone = new HashMap<>(); public CreateDataDistributionOfStructureData(LanduseDataConnectionCreator landuseDataConnectionCreator) { - CreateDataDistributionOfStructureData.landuseDataConnectionCreator = landuseDataConnectionCreator; + this.landuseDataConnectionCreator = landuseDataConnectionCreator; log.info("Using LanduseDataConnectionCreator {} to connect the types of the landuse data to the categories of the small scale commercial traffic generation", landuseDataConnectionCreator.getClass().getSimpleName()); } public CreateDataDistributionOfStructureData() { - landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data(); + this.landuseDataConnectionCreator = new LanduseDataConnectionCreatorForOSM_Data(); log.info("Using default LanduseDataConnectionCreatorForOSM_Data to connect the types of the landuse data to the categories of the small scale commercial traffic generation"); } public static void main(String[] args) { - System.exit(new CommandLine(new CreateDataDistributionOfStructureData(landuseDataConnectionCreator)).execute(args)); + System.exit(new CommandLine(new CreateDataDistributionOfStructureData()).execute(args)); } @Override From 624ca13d060c4313c753868fc14f5c947da6d845 Mon Sep 17 00:00:00 2001 From: schlenther Date: Thu, 8 Aug 2024 18:05:56 +0200 Subject: [PATCH 191/213] NoiseAnalysis: more explicit parameter settings + bug fix in MergeNoiseOutput --- .../analysis/noise/MergeNoiseOutput.java | 14 ++-- .../analysis/noise/NoiseAnalysis.java | 67 +++++++++++++------ .../contrib/noise/NoiseConfigGroup.java | 4 +- .../simwrapper/dashboard/NoiseDashboard.java | 4 +- 4 files changed, 60 insertions(+), 29 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java b/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java index aef1ec23d05..88f8f9354e5 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java @@ -118,6 +118,7 @@ public void run() { * @param output */ private void writeAvro(XYTData xytData, File output) { + log.info(String.format("Start writing avro file to %s", output.toString() )); DatumWriter datumWriter = new SpecificDatumWriter<>(XYTData.class); try (DataFileWriter dataFileWriter = new DataFileWriter<>(datumWriter)) { dataFileWriter.setCodec(CodecFactory.deflateCodec(9)); @@ -143,9 +144,8 @@ private void mergeEmissions(String pathParameter, String label) { .separator(';').build()); for (Row row : table) { - // index for Noise Emission xx:xx:xx -> 7 String linkId = row.getString("Link Id"); - double value = row.getDouble(7); + double value = row.getDouble(row.columnCount() - 1); mergedData.mergeDouble(linkId, value, Double::max); } @@ -188,7 +188,10 @@ private void mergeImissions(String pathParameter, String label) { // Read the file Table table = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(path)) - .columnTypesPartial(Map.of("x", ColumnType.FLOAT, "y", ColumnType.FLOAT, "Receiver Point Id", ColumnType.INTEGER, "t", ColumnType.DOUBLE)) + .columnTypesPartial(Map.of("x", ColumnType.FLOAT, + "y", ColumnType.FLOAT, + "Receiver Point Id", ColumnType.INTEGER, + "t", ColumnType.DOUBLE)) .sample(false) .separator(';').build()); @@ -278,7 +281,10 @@ private void mergeImmissionsCSV(String pathParameter, String label) { // Read the file Table table = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(path)) - .columnTypesPartial(Map.of("x", ColumnType.DOUBLE, "y", ColumnType.DOUBLE, "Receiver Point Id", ColumnType.INTEGER, "t", ColumnType.DOUBLE)) + .columnTypesPartial(Map.of("x", ColumnType.DOUBLE, + "y", ColumnType.DOUBLE, + "Receiver Point Id", ColumnType.INTEGER, + "t", ColumnType.DOUBLE)) .sample(false) .separator(';').build()); diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java index 6730cae8996..02d6337de15 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java @@ -55,7 +55,7 @@ public class NoiseAnalysis implements MATSimAppCommand { private final SampleOptions sampleOptions = new SampleOptions(); @CommandLine.Option(names = "--consider-activities", split = ",", description = "Considered activities for noise calculation." + - " Use asterisk ('*') for acttype prefixes, if all such acts shall be considered.", defaultValue = "h,w,home*,work*") + " Use asterisk ('*') for acttype prefixes, if all such acts shall be considered.", defaultValue = "home*,work*,educ*,leisure*") private Set considerActivities; @CommandLine.Option(names = "--noise-barrier", description = "Path to the noise barrier File", defaultValue = "") @@ -71,32 +71,55 @@ public Integer call() throws Exception { config.controller().setOutputDirectory(input.getRunDirectory().toString()); - // adjust the default noise parameters + //trying to set noise parameters more explicitly, here... + //if NoiseConfigGroup was added before. do not override (most) parameters + boolean overrideParameters = ! ConfigUtils.hasModule(config, NoiseConfigGroup.class); NoiseConfigGroup noiseParameters = ConfigUtils.addOrGetModule(config, NoiseConfigGroup.class); - noiseParameters.setConsideredActivitiesForReceiverPointGridArray(considerActivities.toArray(String[]::new)); - noiseParameters.setConsideredActivitiesForDamageCalculationArray(considerActivities.toArray(String[]::new)); - if (shp.getShapeFile() != null) { - CoordinateTransformation ct = shp.createInverseTransformation(config.global().getCoordinateSystem()); - Envelope bbox = shp.getGeometry().getEnvelopeInternal(); + if(overrideParameters){ + log.warn("no NoiseConfigGroup was configured before. Will set som estandards. You should check the next lines in the log file!"); + noiseParameters.setConsideredActivitiesForReceiverPointGridArray(considerActivities.toArray(String[]::new)); + noiseParameters.setConsideredActivitiesForDamageCalculationArray(considerActivities.toArray(String[]::new)); - Coord minCoord = ct.transform(new Coord(bbox.getMinX(), bbox.getMinY())); - Coord maxCoord = ct.transform(new Coord(bbox.getMaxX(), bbox.getMaxY())); + //use actual speed and not freespeed + noiseParameters.setUseActualSpeedLevel(true); + //use the valid speed range (recommended by IK) + noiseParameters.setAllowForSpeedsOutsideTheValidRange(false); - noiseParameters.setReceiverPointsGridMinX(minCoord.getX()); - noiseParameters.setReceiverPointsGridMinY(minCoord.getY()); - noiseParameters.setReceiverPointsGridMaxX(maxCoord.getX()); - noiseParameters.setReceiverPointsGridMaxY(maxCoord.getY()); - } + if (shp.getShapeFile() != null) { + CoordinateTransformation ct = shp.createInverseTransformation(config.global().getCoordinateSystem()); + + Envelope bbox = shp.getGeometry().getEnvelopeInternal(); + + Coord minCoord = ct.transform(new Coord(bbox.getMinX(), bbox.getMinY())); + Coord maxCoord = ct.transform(new Coord(bbox.getMaxX(), bbox.getMaxY())); + + noiseParameters.setReceiverPointsGridMinX(minCoord.getX()); + noiseParameters.setReceiverPointsGridMinY(minCoord.getY()); + noiseParameters.setReceiverPointsGridMaxX(maxCoord.getX()); + noiseParameters.setReceiverPointsGridMaxY(maxCoord.getY()); + } - noiseParameters.setNoiseComputationMethod(NoiseConfigGroup.NoiseComputationMethod.RLS19); + noiseParameters.setNoiseComputationMethod(NoiseConfigGroup.NoiseComputationMethod.RLS19); - if (!Objects.equals(noiseBarrierFile, "")) { - noiseParameters.setNoiseBarriersSourceCRS(config.global().getCoordinateSystem()); - noiseParameters.setConsiderNoiseBarriers(true); - noiseParameters.setNoiseBarriersFilePath(noiseBarrierFile); + if (!Objects.equals(noiseBarrierFile, "")) { + noiseParameters.setNoiseBarriersSourceCRS(config.global().getCoordinateSystem()); + noiseParameters.setConsiderNoiseBarriers(true); + noiseParameters.setNoiseBarriersFilePath(noiseBarrierFile); + } + } else { + log.warn("will override a few settings in NoiseConfigGroup, as we are now doing postprocessing and do not want any internalization etc." + + " You should check the next lines in the log file!"); } + // we only mean to do postprocessing here, thus no internalization etc + noiseParameters.setInternalizeNoiseDamages(false); + noiseParameters.setComputeCausingAgents(false); + //we don't need events (for Dashboard) - spare disk space. + noiseParameters.setThrowNoiseEventsAffected(false); + noiseParameters.setThrowNoiseEventsCaused(false); + noiseParameters.setComputeNoiseDamages(true); + if(! sampleOptions.isSet() && noiseParameters.getScaleFactor() == 1d){ log.warn("You didn't provide the simulation sample size via command line option --sample-size! This means, noise damages are not scaled!!!"); } else if (noiseParameters.getScaleFactor() == 1d){ @@ -111,6 +134,9 @@ public Integer call() throws Exception { String outputFilePath = output.getPath().getParent() == null ? "." : output.getPath().getParent().toString(); + log.info("starting " + NoiseOfflineCalculation.class + " with the following parameters:\n" + + noiseParameters); + NoiseOfflineCalculation noiseCalculation = new NoiseOfflineCalculation(scenario, outputFilePath); outputFilePath += "/noise-analysis"; noiseCalculation.run(); @@ -122,12 +148,11 @@ public Integer call() throws Exception { MergeNoiseOutput mergeNoiseOutput = new MergeNoiseOutput(paths, Path.of(outputFilePath), config.global().getCoordinateSystem()); mergeNoiseOutput.run(); - return 0; } private Config prepareConfig() { - Config config = ConfigUtils.loadConfig(ApplicationUtils.matchInput("config.xml", input.getRunDirectory()).toAbsolutePath().toString(), new NoiseConfigGroup()); + Config config = ConfigUtils.loadConfig(ApplicationUtils.matchInput("config.xml", input.getRunDirectory()).toAbsolutePath().toString()); //it is important to match "output_vehicles.xml.gz" specifically, because otherwise dvrpVehicle files might be matched and the code crashes later config.vehicles().setVehiclesFile(ApplicationUtils.matchInput("output_vehicles.xml.gz", input.getRunDirectory()).toAbsolutePath().toString()); diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseConfigGroup.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseConfigGroup.java index cd7b2a500ab..06e793c85d9 100644 --- a/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseConfigGroup.java +++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseConfigGroup.java @@ -95,8 +95,8 @@ public NoiseConfigGroup() { private double receiverPointGap = 250.; - private String[] consideredActivitiesForReceiverPointGrid = {"home", "work"}; - private String[] consideredActivitiesForDamageCalculation = {"home", "work"}; + private String[] consideredActivitiesForReceiverPointGrid = {"home*", "work*"}; + private String[] consideredActivitiesForDamageCalculation = {"home*", "work*"}; private double receiverPointsGridMinX = 0.; private double receiverPointsGridMinY = 0.; diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java index b502f3fbf57..036b3c5a718 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java @@ -35,7 +35,7 @@ public void configure(Header header, Layout layout) { layout.row("aggregate noise") .el(GridMap.class, (viz, data) -> { viz.title = "Noise Immissions (Grid)"; - viz.description = "Aggregate Noise Immissions per day"; + viz.description = "Total Noise Immissions per day"; viz.height = 12.0; viz.cellSize = 250; viz.opacity = 0.2; @@ -47,7 +47,7 @@ public void configure(Header header, Layout layout) { }) .el(MapPlot.class, (viz, data) -> { viz.title = "Noise Emissions (Link)"; - viz.description = "Aggregate Noise Emissions per day"; + viz.description = "Maximum Noise Level per day [dB]"; viz.height = 12.0; viz.center = data.context().getCenter(); viz.zoom = data.context().mapZoomLevel; From a455df3d4280aeced29d55a5044014b8e61eb995 Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Fri, 9 Aug 2024 10:26:20 +0200 Subject: [PATCH 192/213] Update DRT estimate and teleport module (#3333) Re-organizing the DRT estimation scripts. For more details, please see detailed description above. --- .../MultiModalDrtLegEstimatorTest.java | 4 +- .../impl/DetourBasedDrtEstimator.java | 76 ---------- .../impl/DirectTripBasedDrtEstimator.java | 130 ++++++++++++++++++ .../EuclideanDistanceBasedDrtEstimator.java | 65 ++++----- ...stimator.java => ExampleDrtEstimator.java} | 6 +- ...=> OnlineSimulationBasedDrtEstimator.java} | 11 +- .../distribution/DistributionGenerator.java | 10 ++ .../LogNormalDistributionGenerator.java | 35 +++++ .../impl/distribution/NoDistribution.java | 8 ++ .../NormalDistributionGenerator.java | 34 +++++ .../ConstantRideDurationEstimator.java | 20 +++ .../RideDurationEstimator.java | 11 ++ .../ConstantWaitingTimeEstimator.java | 18 +++ .../ShapeFileBasedWaitingTimeEstimator.java | 63 +++++++++ .../WaitingTimeEstimator.java | 9 ++ .../estimator/DrtEstimateAndTeleportTest.java | 59 ++++++++ .../DrtTeleportationWithModeChoiceTest.java | 3 - 17 files changed, 441 insertions(+), 121 deletions(-) delete mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DirectTripBasedDrtEstimator.java rename contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/{ConstantDrtEstimator.java => ExampleDrtEstimator.java} (82%) rename contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/{BasicDrtEstimator.java => OnlineSimulationBasedDrtEstimator.java} (90%) create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/DistributionGenerator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/LogNormalDistributionGenerator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NoDistribution.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NormalDistributionGenerator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/ConstantRideDurationEstimator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/RideDurationEstimator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ConstantWaitingTimeEstimator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ShapeFileBasedWaitingTimeEstimator.java create mode 100644 contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/WaitingTimeEstimator.java create mode 100644 contribs/drt/src/test/java/org/matsim/contrib/drt/estimator/DrtEstimateAndTeleportTest.java diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java index f925ed604dd..d5e606ed980 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/estimator/MultiModalDrtLegEstimatorTest.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.matsim.application.MATSimApplication; import org.matsim.contrib.drt.estimator.DrtEstimatorModule; -import org.matsim.contrib.drt.estimator.impl.ConstantDrtEstimator; +import org.matsim.contrib.drt.estimator.impl.ExampleDrtEstimator; import org.matsim.contrib.drt.extension.DrtTestScenario; import org.matsim.contrib.drt.extension.modechoice.MultiModalDrtLegEstimator; import org.matsim.contrib.drt.run.DrtConfigGroup; @@ -51,7 +51,7 @@ public void install() { for (DrtConfigGroup el : drtConfig.getModalElements()) { install(new DrtEstimatorModule(el.mode, el, el.getDrtEstimatorParams().get())); - DrtEstimatorModule.bindEstimator(binder(), el.mode).toInstance(new ConstantDrtEstimator(1.05, 300)); + DrtEstimatorModule.bindEstimator(binder(), el.mode).toInstance(new ExampleDrtEstimator(1.05, 300)); } } }); diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java deleted file mode 100644 index e85e5595930..00000000000 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DetourBasedDrtEstimator.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.matsim.contrib.drt.estimator.impl; - -import org.matsim.contrib.drt.estimator.DrtEstimator; -import org.matsim.contrib.drt.routing.DrtRoute; -import org.matsim.core.utils.misc.OptionalTime; - -import java.util.Random; - -/** - * A simple DRT estimator that uses normal distributions to estimate the ride time, wait time, ride distance and acceptance. - */ -public final class DetourBasedDrtEstimator implements DrtEstimator { - - private final NormalDistributionGenerator distributionGenerator; - - private DetourBasedDrtEstimator(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime, - double waitTimeStd) { - this.distributionGenerator = new NormalDistributionGenerator(estRideTimeAlpha, estRideTimeBeta, rideTimeStd, estMeanWaitTime, waitTimeStd); - } - - public static DetourBasedDrtEstimator normalDistributed(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime, - double waitTimeStd) { - return new DetourBasedDrtEstimator(estRideTimeAlpha, estRideTimeBeta, rideTimeStd, estMeanWaitTime, waitTimeStd); - } - - @Override - public Estimate estimate(DrtRoute route, OptionalTime departureTime) { - double directRideTIme = route.getDirectRideTime(); - double directDistance = route.getDistance(); - double waitTime = distributionGenerator.generateWaitTime(); - double rideTime = distributionGenerator.generateRideTime(directRideTIme); - double rideDistance = distributionGenerator.generateRideDistance(rideTime, directRideTIme, directDistance); - double acceptanceRate = distributionGenerator.generateAcceptanceRate(); - - return new Estimate(rideDistance, waitTime + rideTime, waitTime, acceptanceRate); - } - - private static class NormalDistributionGenerator { - private final Random random = new Random(4711); - private final double estRideTimeAlpha; - private final double estRideTimeBeta; - private final double rideTimeStd; - private final double estMeanWaitTime; - private final double waitTimeStd; - - public NormalDistributionGenerator(double estRideTimeAlpha, double estRideTimeBeta, double rideTimeStd, double estMeanWaitTime, - double waitTimeStd) { - this.estRideTimeAlpha = estRideTimeAlpha; - this.estRideTimeBeta = estRideTimeBeta; - this.rideTimeStd = rideTimeStd; - this.estMeanWaitTime = estMeanWaitTime; - this.waitTimeStd = waitTimeStd; - } - - public double generateRideTime(double directRideTime) { - // TODO improve this distribution - double estMeanRideTime = estRideTimeAlpha * directRideTime + estRideTimeBeta; - return Math.max(directRideTime, estMeanRideTime * (1 + random.nextGaussian() * rideTimeStd)); - } - - public double generateRideDistance(double estRideTime, double directRideTime, double directRideDistance) { - // TODO Currently, same ratio is used as in the ride time estimation; improve this distribution - double ratio = estRideTime / directRideTime; - return ratio * directRideDistance; - } - - public double generateWaitTime() { - // TODO improve this distribution - return Math.max(estMeanWaitTime * (1 + random.nextGaussian() * waitTimeStd), 0); - } - - public double generateAcceptanceRate() { - return 1; - } - } -} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DirectTripBasedDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DirectTripBasedDrtEstimator.java new file mode 100644 index 00000000000..08ae52d5a0a --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/DirectTripBasedDrtEstimator.java @@ -0,0 +1,130 @@ +package org.matsim.contrib.drt.estimator.impl; + +import org.checkerframework.checker.units.qual.C; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.contrib.drt.estimator.DrtEstimator; +import org.matsim.contrib.drt.estimator.impl.distribution.DistributionGenerator; +import org.matsim.contrib.drt.estimator.impl.distribution.LogNormalDistributionGenerator; +import org.matsim.contrib.drt.estimator.impl.distribution.NoDistribution; +import org.matsim.contrib.drt.estimator.impl.distribution.NormalDistributionGenerator; +import org.matsim.contrib.drt.estimator.impl.trip_estimation.ConstantRideDurationEstimator; +import org.matsim.contrib.drt.estimator.impl.trip_estimation.RideDurationEstimator; +import org.matsim.contrib.drt.estimator.impl.waiting_time_estimation.ConstantWaitingTimeEstimator; +import org.matsim.contrib.drt.estimator.impl.waiting_time_estimation.WaitingTimeEstimator; +import org.matsim.contrib.drt.routing.DrtRoute; +import org.matsim.core.utils.misc.OptionalTime; + +/** + * DRT estimator that uses available data (e.g., real-world operational data, simulation-based data) to provide estimated data for DRT trips. + */ +public final class DirectTripBasedDrtEstimator implements DrtEstimator { + private final RideDurationEstimator rideDurationEstimator; + private final WaitingTimeEstimator waitingTimeEstimator; + private final DistributionGenerator waitingTimeDistributionGenerator; + private final DistributionGenerator rideTimeDistributionGenerator; + + public static class Builder { + // Initialize with default estimation + private RideDurationEstimator rideDurationEstimator = new ConstantRideDurationEstimator(1.25, 300); + private WaitingTimeEstimator waitingTimeEstimator = new ConstantWaitingTimeEstimator(300); + private DistributionGenerator waitingTimeDistributionGenerator = new NoDistribution(); + private DistributionGenerator rideTimeDistributionGenerator = new NoDistribution(); + + public Builder setRideDurationEstimator(RideDurationEstimator rideDurationEstimator) { + this.rideDurationEstimator = rideDurationEstimator; + return this; + } + + public Builder setWaitingTimeEstimator(WaitingTimeEstimator waitingTimeEstimator) { + this.waitingTimeEstimator = waitingTimeEstimator; + return this; + } + + public Builder setRideDurationDistributionGenerator(DistributionGenerator rideTimeDistributionGenerator) { + this.rideTimeDistributionGenerator = rideTimeDistributionGenerator; + return this; + } + + public Builder setWaitingTimeDistributionGenerator(DistributionGenerator waitingTimeDistributionGenerator) { + this.waitingTimeDistributionGenerator = waitingTimeDistributionGenerator; + return this; + } + + public DirectTripBasedDrtEstimator build() { + return new DirectTripBasedDrtEstimator(rideDurationEstimator, waitingTimeEstimator, rideTimeDistributionGenerator, waitingTimeDistributionGenerator); + } + + } + + public DirectTripBasedDrtEstimator(RideDurationEstimator rideDurationEstimator, WaitingTimeEstimator waitingTimeEstimator, + DistributionGenerator rideTimeDistribution, DistributionGenerator waitTimeDistribution) { + this.rideDurationEstimator = rideDurationEstimator; + this.waitingTimeEstimator = waitingTimeEstimator; + this.rideTimeDistributionGenerator = rideTimeDistribution; + this.waitingTimeDistributionGenerator = waitTimeDistribution; + } + + /** + * Example DRT estimator based on the normal distributed ride time and waiting time + * @param estRideTimeAlpha typical ride duration = alpha * direct ride time + beta, alpha is specified here + * @param estRideTimeBeta typical ride duration = alpha * direct ride time + beta, beta is specified here + * @param rideTimeStd standard deviation of ride duration (normalized to 1) + * @param estMeanWaitTime estimated waiting time (i.e., mean wait time) + * @param waitTimeStd standard deviation of waiting time (normalized to 1) + * @return NetworkBasedDrtEstimator + */ + public static DirectTripBasedDrtEstimator normalDistributedNetworkBasedDrtEstimator(double estRideTimeAlpha, double estRideTimeBeta, + double rideTimeStd, double estMeanWaitTime, + double waitTimeStd) { + return new Builder() + .setWaitingTimeEstimator(new ConstantWaitingTimeEstimator(estMeanWaitTime)) + .setRideDurationEstimator(new ConstantRideDurationEstimator(estRideTimeAlpha, estRideTimeBeta)) + .setWaitingTimeDistributionGenerator(new NormalDistributionGenerator(1, waitTimeStd)) + .setRideDurationDistributionGenerator(new NormalDistributionGenerator(2, rideTimeStd)) + .build(); + } + + /** + * Example DRT estimator based on the log-normal distributed ride time and normal distributed waiting time + * @param estRideTimeAlpha typical ride duration = alpha * direct ride time + beta, alpha is specified here + * @param estRideTimeBeta typical ride duration = alpha * direct ride time + beta, beta is specified here + * @param mu log-normal distribution parameter for ride duration (normalized to typical ride duration) + * @param sigma log-normal distribution parameter for ride duration (normalized to typical ride duration) + * @param estMeanWaitTime estimated waiting time (i.e., mean wait time) + * @param waitTimeStd standard deviation of waiting time (normalized to 1) + * @return NetworkBasedDrtEstimator + */ + public static DirectTripBasedDrtEstimator mixDistributedNetworkBasedDrtEstimator(double estRideTimeAlpha, double estRideTimeBeta, + double mu, double sigma, double estMeanWaitTime, + double waitTimeStd) { + return new Builder() + .setWaitingTimeEstimator(new ConstantWaitingTimeEstimator(estMeanWaitTime)) + .setRideDurationEstimator(new ConstantRideDurationEstimator(estRideTimeAlpha, estRideTimeBeta)) + .setWaitingTimeDistributionGenerator(new NormalDistributionGenerator(1, waitTimeStd)) + .setRideDurationDistributionGenerator(new LogNormalDistributionGenerator(2, mu, sigma)) + .build(); + } + + @Override + public Estimate estimate(DrtRoute route, OptionalTime departureTime) { + double directRideTIme = route.getDirectRideTime(); + double directDistance = route.getDistance(); + Id fromLinkId = route.getStartLinkId(); + Id toLinkId = route.getEndLinkId(); + double typicalRideDuration = rideDurationEstimator.getEstimatedRideDuration(fromLinkId, toLinkId, departureTime, directRideTIme); + double typicalRideDistance = (typicalRideDuration / directRideTIme) * directDistance; + double typicalWaitingTime = waitingTimeEstimator.estimateWaitTime(fromLinkId, toLinkId, departureTime); + + double estimatedWaitingTime = typicalWaitingTime * waitingTimeDistributionGenerator.generateRandomValue(); + + double detourRandomFactor = rideTimeDistributionGenerator.generateRandomValue(); + double estimatedRideDuration = detourRandomFactor * typicalRideDuration; + double estimatedRideDistance = detourRandomFactor * typicalRideDistance; + + double acceptanceRate = 1.0; + + return new Estimate(estimatedRideDistance, estimatedRideDuration, estimatedWaitingTime, acceptanceRate); + } + +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/EuclideanDistanceBasedDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/EuclideanDistanceBasedDrtEstimator.java index dd3a2492ce9..8b617888084 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/EuclideanDistanceBasedDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/EuclideanDistanceBasedDrtEstimator.java @@ -3,12 +3,18 @@ import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.drt.estimator.DrtEstimator; +import org.matsim.contrib.drt.estimator.impl.distribution.DistributionGenerator; +import org.matsim.contrib.drt.estimator.impl.distribution.LogNormalDistributionGenerator; +import org.matsim.contrib.drt.estimator.impl.distribution.NormalDistributionGenerator; +import org.matsim.contrib.drt.estimator.impl.trip_estimation.ConstantRideDurationEstimator; +import org.matsim.contrib.drt.estimator.impl.trip_estimation.RideDurationEstimator; +import org.matsim.contrib.drt.estimator.impl.waiting_time_estimation.ConstantWaitingTimeEstimator; +import org.matsim.contrib.drt.estimator.impl.waiting_time_estimation.WaitingTimeEstimator; import org.matsim.contrib.drt.routing.DrtRoute; +import org.matsim.core.utils.collections.Tuple; import org.matsim.core.utils.geometry.CoordUtils; import org.matsim.core.utils.misc.OptionalTime; -import java.util.Random; - public class EuclideanDistanceBasedDrtEstimator implements DrtEstimator { private final Network network; /** @@ -16,26 +22,16 @@ public class EuclideanDistanceBasedDrtEstimator implements DrtEstimator { * Estimated network distance = Euclidean distance * network distance factor */ private final double networkDistanceFactor; - /** - * Slope of the linear regression - */ - private final double slope; - /** - * Intercept of the linear regression - */ - private final double intercept; - - private final double estimatedMeanWaitTime; - - private final double waitTimeStd; + private final RideDurationEstimator rideDurationEstimator; + private final WaitingTimeEstimator waitingTimeEstimator; + private final DistributionGenerator rideDurationDistributionGenerator; + private final DistributionGenerator waitingTimeDistributionGenerator; - private final double mu; - private final double sigma; - private final Random random = new Random(1234); /** * We use log normal distribution to estimate the ride duration of each individual trip. The distribution * is based on the linear regression. + * * @params networkDistanceFactor: Estimated network distance = Euclidean distance * network distance factor * @params slope: slope for the linear regression * @params intercept: intercept for linear regression @@ -47,12 +43,21 @@ public EuclideanDistanceBasedDrtEstimator(Network network, double networkDistanc double mu, double sigma) { this.network = network; this.networkDistanceFactor = networkDistanceFactor; - this.slope = slope; - this.intercept = intercept; - this.estimatedMeanWaitTime = estimatedMeanWaitTime; - this.waitTimeStd = waitTimeStd; - this.mu = mu; - this.sigma = sigma; + this.rideDurationEstimator = new ConstantRideDurationEstimator(slope, intercept); + this.waitingTimeEstimator = new ConstantWaitingTimeEstimator(estimatedMeanWaitTime); + this.rideDurationDistributionGenerator = new LogNormalDistributionGenerator(1, mu, sigma); + this.waitingTimeDistributionGenerator = new NormalDistributionGenerator(2, waitTimeStd); + } + + public EuclideanDistanceBasedDrtEstimator(Network network, double networkDistanceFactor, RideDurationEstimator rideDurationEstimator, + WaitingTimeEstimator waitingTimeEstimator, DistributionGenerator rideDurationDistributionGenerator, + DistributionGenerator waitingTimeDistributionGenerator) { + this.network = network; + this.networkDistanceFactor = networkDistanceFactor; + this.rideDurationEstimator = rideDurationEstimator; + this.waitingTimeEstimator = waitingTimeEstimator; + this.rideDurationDistributionGenerator = rideDurationDistributionGenerator; + this.waitingTimeDistributionGenerator = waitingTimeDistributionGenerator; } @Override @@ -60,19 +65,15 @@ public Estimate estimate(DrtRoute route, OptionalTime departureTime) { Coord fromCoord = network.getLinks().get(route.getStartLinkId()).getToNode().getCoord(); Coord toCoord = network.getLinks().get(route.getEndLinkId()).getToNode().getCoord(); double euclideanDistance = CoordUtils.calcEuclideanDistance(fromCoord, toCoord); - double typicalRideDuration = euclideanDistance * slope + intercept; + + double typicalRideDuration = rideDurationEstimator.getEstimatedRideDuration(route.getStartLinkId(), route.getEndLinkId(), departureTime, euclideanDistance); double typicalRideDistance = networkDistanceFactor * euclideanDistance; - double randomFactor = nextLogNormal(mu, sigma); - double waitTime = Math.max(estimatedMeanWaitTime * (1 + random.nextGaussian() * waitTimeStd), 0); + double typicalWaitingTime = waitingTimeEstimator.estimateWaitTime(route.getStartLinkId(), route.getEndLinkId(), departureTime); + double randomFactor = rideDurationDistributionGenerator.generateRandomValue(); + double waitTime = Math.max(typicalWaitingTime * waitingTimeDistributionGenerator.generateRandomValue(), 0); return new Estimate(typicalRideDistance * randomFactor, typicalRideDuration * randomFactor, waitTime, 0); } - public double nextLogNormal(double mu, double sigma) { - if (sigma == 0) - return Math.exp(mu); - - return Math.exp(sigma * random.nextGaussian() + mu); - } } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ExampleDrtEstimator.java similarity index 82% rename from contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java rename to contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ExampleDrtEstimator.java index 20ea18ee120..b49b3b988f0 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ConstantDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/ExampleDrtEstimator.java @@ -2,13 +2,13 @@ import org.matsim.contrib.drt.estimator.DrtEstimator; import org.matsim.contrib.drt.routing.DrtRoute; -import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.core.utils.misc.OptionalTime; /** * Estimates using a constant detour factor and waiting time. */ -public class ConstantDrtEstimator implements DrtEstimator { +@Deprecated +public class ExampleDrtEstimator implements DrtEstimator { /** * Detour factor for the estimate. 1.0 means no detour, 2.0 means twice the distance. @@ -20,7 +20,7 @@ public class ConstantDrtEstimator implements DrtEstimator { */ private final double waitingTime; - public ConstantDrtEstimator(double detourFactor, double waitingTime) { + public ExampleDrtEstimator(double detourFactor, double waitingTime) { this.detourFactor = detourFactor; this.waitingTime = waitingTime; } diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/OnlineSimulationBasedDrtEstimator.java similarity index 90% rename from contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java rename to contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/OnlineSimulationBasedDrtEstimator.java index f02c4ee59b2..db1f3e83ccd 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/BasicDrtEstimator.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/OnlineSimulationBasedDrtEstimator.java @@ -1,7 +1,6 @@ package org.matsim.contrib.drt.estimator.impl; import org.apache.commons.math3.stat.descriptive.SummaryStatistics; -import org.apache.commons.math3.stat.regression.RegressionResults; import org.apache.commons.math3.stat.regression.SimpleRegression; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -23,12 +22,14 @@ import java.util.SplittableRandom; /** + * When this estimator is used, explicit simulations of DRT will be carried out intermittently. During the iterations where no + * DRT is simulated, estimated DRT will be used. This estimator will replace the original DRT speed-up module * Estimates drt trips based only daily averages. No spatial or temporal differentiation is taken into account for the estimate. * This estimator is suited for small scenarios with few vehicles and trips and consequently few data points. */ -public class BasicDrtEstimator implements DrtOnlineEstimator, IterationEndsListener { +public class OnlineSimulationBasedDrtEstimator implements DrtOnlineEstimator, IterationEndsListener { - private static final Logger log = LogManager.getLogger(BasicDrtEstimator.class); + private static final Logger log = LogManager.getLogger(OnlineSimulationBasedDrtEstimator.class); private final DrtEventSequenceCollector collector; private final DrtEstimatorParams config; @@ -41,8 +42,8 @@ public class BasicDrtEstimator implements DrtOnlineEstimator, IterationEndsListe */ private GlobalEstimate currentEst; - public BasicDrtEstimator(DrtEventSequenceCollector collector, DrtEstimator initial, - DrtEstimatorParams config, DrtConfigGroup drtConfig) { + public OnlineSimulationBasedDrtEstimator(DrtEventSequenceCollector collector, DrtEstimator initial, + DrtEstimatorParams config, DrtConfigGroup drtConfig) { //zones = injector.getModal(DrtZonalSystem.class); this.collector = collector; this.initial = initial; diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/DistributionGenerator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/DistributionGenerator.java new file mode 100644 index 00000000000..d5e6e890729 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/DistributionGenerator.java @@ -0,0 +1,10 @@ +package org.matsim.contrib.drt.estimator.impl.distribution; + +public interface DistributionGenerator { + /** + * @return relative value to the typical ride duration (i.e., generate a distribution around 1.0) + */ + double generateRandomValue(); + + enum DistributionType {NO_DISTRIBUTION, NORMAL, LOG_NORMAL, CUSTOM} +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/LogNormalDistributionGenerator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/LogNormalDistributionGenerator.java new file mode 100644 index 00000000000..1be1250a870 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/LogNormalDistributionGenerator.java @@ -0,0 +1,35 @@ +package org.matsim.contrib.drt.estimator.impl.distribution; + +import java.util.Random; + +public class LogNormalDistributionGenerator implements DistributionGenerator { + private final Random random; + private final double mu; + private final double sigma; + private final double minValue; + + private final double maxValue; + + public LogNormalDistributionGenerator(long seed, double mu, double sigma) { + this.random = new Random(seed); + this.mu = mu; + this.sigma = sigma; + this.minValue = 0.5; + this.maxValue = 3; + } + + public LogNormalDistributionGenerator(long seed, double mu, double sigma, double minValue, double maxValue) { + this.random = new Random(seed); + this.mu = mu; + this.sigma = sigma; + this.minValue = minValue; + this.maxValue = maxValue; + } + + @Override + public double generateRandomValue() { + if (sigma == 0) + return Math.exp(mu); + return Math.max(Math.min(Math.exp(sigma * random.nextGaussian() + mu), maxValue), minValue); + } +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NoDistribution.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NoDistribution.java new file mode 100644 index 00000000000..0643c45ba53 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NoDistribution.java @@ -0,0 +1,8 @@ +package org.matsim.contrib.drt.estimator.impl.distribution; + +public class NoDistribution implements DistributionGenerator{ + @Override + public double generateRandomValue() { + return 1.0; + } +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NormalDistributionGenerator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NormalDistributionGenerator.java new file mode 100644 index 00000000000..5b6a23fc31a --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/distribution/NormalDistributionGenerator.java @@ -0,0 +1,34 @@ +package org.matsim.contrib.drt.estimator.impl.distribution; + +import java.util.Random; + +public class NormalDistributionGenerator implements DistributionGenerator{ + private final Random random; + private final double std; + + private final double minValue; + + private final double maxValue; + + public NormalDistributionGenerator(long seed, double std) { + this.random = new Random(seed); + this.std = std; + this.minValue = 0.5; + this.maxValue = 3.0; + } + + public NormalDistributionGenerator(long seed, double std, double minValue, double maxValue) { + this.random = new Random(seed); + this.std = std; + this.minValue = minValue; + this.maxValue = maxValue; + } + + @Override + public double generateRandomValue() { + double randomValue = 1 + random.nextGaussian() * std; + randomValue = Math.min(maxValue, randomValue); + randomValue = Math.max(minValue, randomValue); + return randomValue; + } +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/ConstantRideDurationEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/ConstantRideDurationEstimator.java new file mode 100644 index 00000000000..7c431fb39ba --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/ConstantRideDurationEstimator.java @@ -0,0 +1,20 @@ +package org.matsim.contrib.drt.estimator.impl.trip_estimation; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.utils.misc.OptionalTime; + +public class ConstantRideDurationEstimator implements RideDurationEstimator { + private final double alpha; + private final double beta; + + public ConstantRideDurationEstimator(double alpha, double beta) { + this.alpha = alpha; + this.beta = beta; + } + + @Override + public double getEstimatedRideDuration(Id fromLinkId, Id toLinkId, OptionalTime departureTime, double directRideDuration) { + return alpha * directRideDuration + beta; + } +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/RideDurationEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/RideDurationEstimator.java new file mode 100644 index 00000000000..d19a4e9fa6c --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/trip_estimation/RideDurationEstimator.java @@ -0,0 +1,11 @@ +package org.matsim.contrib.drt.estimator.impl.trip_estimation; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.utils.collections.Tuple; +import org.matsim.core.utils.misc.OptionalTime; + +public interface RideDurationEstimator { + double getEstimatedRideDuration(Id fromLinkId, Id toLinkId, OptionalTime departureTime, double directTripDuration); + +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ConstantWaitingTimeEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ConstantWaitingTimeEstimator.java new file mode 100644 index 00000000000..1b2d18288d5 --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ConstantWaitingTimeEstimator.java @@ -0,0 +1,18 @@ +package org.matsim.contrib.drt.estimator.impl.waiting_time_estimation; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.utils.misc.OptionalTime; + +public class ConstantWaitingTimeEstimator implements WaitingTimeEstimator { + private final double typicalWaitingTime; + + public ConstantWaitingTimeEstimator(double typicalWaitingTime) { + this.typicalWaitingTime = typicalWaitingTime; + } + + @Override + public double estimateWaitTime(Id fromLinkId, Id toLinkId, OptionalTime departureTime) { + return typicalWaitingTime; + } +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ShapeFileBasedWaitingTimeEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ShapeFileBasedWaitingTimeEstimator.java new file mode 100644 index 00000000000..32bcb03c8cd --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/ShapeFileBasedWaitingTimeEstimator.java @@ -0,0 +1,63 @@ +package org.matsim.contrib.drt.estimator.impl.waiting_time_estimation; + +import org.geotools.api.feature.simple.SimpleFeature; +import org.locationtech.jts.geom.Geometry; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.utils.geometry.geotools.MGC; +import org.matsim.core.utils.misc.OptionalTime; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ShapeFileBasedWaitingTimeEstimator implements WaitingTimeEstimator { + /** + * Typical waiting time. Due to the length limit of the attribute name, we have to use some abbreviate + */ + private final static String TYPICAL_WAITING_TIME_NAME = "typ_wt"; + private final Map, Double> typicalWaitingTimeForEachLink = new HashMap<>(); + /** + * The default typical waiting time. This value will be used for links that are not covered by any + * waiting time zone. The baseTypicalWaitingTime is usually larger than the typical waiting time + * in any waiting time zone. + */ + private final double baseTypicalWaitingTime; + + public ShapeFileBasedWaitingTimeEstimator(Network network, List features) { + baseTypicalWaitingTime = 1800; + initializeWaitingTimeMap(network, features); + } + + public ShapeFileBasedWaitingTimeEstimator(Network network, List features, double baseTypicalWaitingTime) { + this.baseTypicalWaitingTime = baseTypicalWaitingTime; + initializeWaitingTimeMap(network, features); + } + + private void initializeWaitingTimeMap(Network network, List features) { + for (Link link : network.getLinks().values()) { + if (!link.getAllowedModes().contains(TransportMode.car) && !link.getAllowedModes().contains(TransportMode.drt)) { + continue; + } + double minTypicalWaitingTime = baseTypicalWaitingTime; + for (SimpleFeature feature : features) { + Geometry geometry = (Geometry) feature.getDefaultGeometry(); + if (geometry.contains(MGC.coord2Point(link.getToNode().getCoord()))) { + // The link is located within the zone -> reduce typical waiting time if necessary + double typicalWaitingTimeForCurrentZone = (long) feature.getAttribute(TYPICAL_WAITING_TIME_NAME); + if (typicalWaitingTimeForCurrentZone < minTypicalWaitingTime) { + minTypicalWaitingTime = typicalWaitingTimeForCurrentZone; + } + } + } + typicalWaitingTimeForEachLink.put(link.getId(), minTypicalWaitingTime); + } + } + + @Override + public double estimateWaitTime(Id fromLinkId, Id toLinkId, OptionalTime departureTime) { + return typicalWaitingTimeForEachLink.get(fromLinkId); + } +} diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/WaitingTimeEstimator.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/WaitingTimeEstimator.java new file mode 100644 index 00000000000..8649cd88a2c --- /dev/null +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/estimator/impl/waiting_time_estimation/WaitingTimeEstimator.java @@ -0,0 +1,9 @@ +package org.matsim.contrib.drt.estimator.impl.waiting_time_estimation; + +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.core.utils.misc.OptionalTime; + +public interface WaitingTimeEstimator { + double estimateWaitTime(Id fromLinkId, Id toLinkId, OptionalTime departureTime); +} diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/estimator/DrtEstimateAndTeleportTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/estimator/DrtEstimateAndTeleportTest.java new file mode 100644 index 00000000000..cafd39170b3 --- /dev/null +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/estimator/DrtEstimateAndTeleportTest.java @@ -0,0 +1,59 @@ +package org.matsim.contrib.drt.estimator; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.matsim.contrib.common.zones.systems.grid.square.SquareGridZoneSystemParams; +import org.matsim.contrib.drt.estimator.impl.DirectTripBasedDrtEstimator; +import org.matsim.contrib.drt.estimator.impl.distribution.NormalDistributionGenerator; +import org.matsim.contrib.drt.estimator.impl.trip_estimation.ConstantRideDurationEstimator; +import org.matsim.contrib.drt.estimator.impl.waiting_time_estimation.ConstantWaitingTimeEstimator; +import org.matsim.contrib.drt.run.DrtConfigGroup; +import org.matsim.contrib.drt.run.DrtControlerCreator; +import org.matsim.contrib.drt.run.MultiModeDrtConfigGroup; +import org.matsim.contrib.dvrp.run.DvrpConfigGroup; +import org.matsim.contrib.zone.skims.DvrpTravelTimeMatrixParams; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.controler.AbstractModule; +import org.matsim.core.controler.Controler; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; +import org.matsim.testcases.MatsimTestUtils; +import org.matsim.vis.otfvis.OTFVisConfigGroup; + +import java.net.URL; + +public class DrtEstimateAndTeleportTest { + @RegisterExtension + public MatsimTestUtils utils = new MatsimTestUtils(); + + @Test + public void testDrtEstimateAndTeleport() { + URL configUrl = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), "mielec_drt_config.xml"); + + DvrpConfigGroup dvrpConfig = new DvrpConfigGroup(); + DvrpTravelTimeMatrixParams matrixParams = dvrpConfig.getTravelTimeMatrixParams(); + matrixParams.addParameterSet(matrixParams.createParameterSet(SquareGridZoneSystemParams.SET_NAME)); + + Config config = ConfigUtils.loadConfig(configUrl, new MultiModeDrtConfigGroup(), dvrpConfig, + new OTFVisConfigGroup()); + DrtConfigGroup drtConfigGroup = DrtConfigGroup.getSingleModeDrtConfig(config); + drtConfigGroup.simulationType = DrtConfigGroup.SimulationType.estimateAndTeleport; + + Controler controler = DrtControlerCreator.createControler(config, false); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + DrtEstimatorModule.bindEstimator(binder(), drtConfigGroup.mode).toInstance( + new DirectTripBasedDrtEstimator.Builder() + .setWaitingTimeEstimator(new ConstantWaitingTimeEstimator(300)) + .setWaitingTimeDistributionGenerator(new NormalDistributionGenerator(1, 0.4)) + .setRideDurationEstimator(new ConstantRideDurationEstimator(1.25, 300)) + .setRideDurationDistributionGenerator(new NormalDistributionGenerator(2, 0.3)) + .build() + ); + } + }); + controler.run(); + } +} diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java index effd09b64ac..0e035acb518 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/teleportation/DrtTeleportationWithModeChoiceTest.java @@ -6,7 +6,6 @@ import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.network.Network; import org.matsim.contrib.drt.estimator.DrtEstimator; -import org.matsim.contrib.drt.estimator.impl.DetourBasedDrtEstimator; import org.matsim.contrib.drt.estimator.impl.EuclideanDistanceBasedDrtEstimator; import org.matsim.contrib.drt.run.DrtConfigGroup; import org.matsim.contrib.drt.run.DrtControlerCreator; @@ -72,8 +71,6 @@ void testModeChoice() { controler.addOverridingModule(new AbstractDvrpModeModule(drtConfigGroup.mode) { @Override public void install() { -// bindModal(DrtEstimator.class).toInstance(DetourBasedDrtEstimator.normalDistributed(1.2, 32, -// 0.3, 300, 0.4)); bindModal(DrtEstimator.class).toProvider(modalProvider(getter -> new EuclideanDistanceBasedDrtEstimator(getter.getModal(Network.class), 2.0, 0.1577493, 103.0972273, 120, 0.3, -0.1, 0.28))); From 1730ac8213fb52066926563386badd19b3e9e71f Mon Sep 17 00:00:00 2001 From: schlenther Date: Fri, 9 Aug 2024 11:01:06 +0200 Subject: [PATCH 193/213] NoiseAnalysis: merge damages files --- .../analysis/noise/MergeNoiseOutput.java | 76 +++++++++---------- .../analysis/noise/NoiseAnalysis.java | 3 +- .../contrib/noise/MergeNoiseCSVFile.java | 1 + .../org/matsim/contrib/noise/NoiseWriter.java | 14 ++-- 4 files changed, 42 insertions(+), 52 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java b/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java index 88f8f9354e5..e59c4aee75c 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java @@ -13,11 +13,14 @@ import org.apache.avro.file.DataFileWriter; import org.apache.avro.io.DatumWriter; import org.apache.avro.specific.SpecificDatumWriter; +import org.apache.commons.lang.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Coord; import org.matsim.application.avro.XYTData; +import org.matsim.core.config.Config; import org.matsim.core.utils.io.IOUtils; +import org.matsim.core.utils.misc.Time; import tech.tablesaw.api.*; import tech.tablesaw.io.csv.CsvReadOptions; @@ -29,7 +32,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.*; -import java.util.stream.Collectors; + +import static org.geotools.gml3.v3_2.GML.coordinateSystem; /** * Merges noise data from multiple files into one file. @@ -44,17 +48,14 @@ final class MergeNoiseOutput { */ private static final boolean CREATE_CSV_FILES = false; - private final String[] inputPath; private final Path outputDirectory; private final String crs; - private final String[] labels = {"immission", "emission"}; private final int minTime = 3600; private int maxTime = 24 * 3600; - MergeNoiseOutput(String[] inputPath, Path outputDirectory, String crs) { - this.inputPath = inputPath; - this.outputDirectory = outputDirectory; - this.crs = crs; + MergeNoiseOutput(Path path, String coordinateSystem ) { + this.outputDirectory = path; + this.crs = coordinateSystem; } /** @@ -90,25 +91,9 @@ public void setMaxTime(int maxTime) { * Merges noise data from multiple files into one file. */ public void run() { - - // Loop over all paths - for (int i = 0; i < labels.length; i++) { - - // Select the correct method based on the label - switch (labels[i]) { - case "immission" -> { - if (CREATE_CSV_FILES) { - mergeImmissionsCSV(inputPath[i], labels[i]); - } else { - mergeImissions(inputPath[i], labels[i]); - } - - } - case "emission" -> mergeEmissions(inputPath[i], labels[i]); - default -> log.warn("Unknown path: " + inputPath[i]); - } - - } + mergeReceiverPointData(outputDirectory + "/immissions/", "immission"); + mergeReceiverPointData(outputDirectory + "/damages_receiverPoint/", "damages_receiverPoint"); + mergeLinkData(outputDirectory.toString() + "/emissions/", "emission"); } /** @@ -129,7 +114,7 @@ private void writeAvro(XYTData xytData, File output) { } } - private void mergeEmissions(String pathParameter, String label) { + private void mergeLinkData(String pathParameter, String label) { log.info("Merging emissions data for label {}", label); Object2DoubleMap mergedData = new Object2DoubleOpenHashMap<>(); Table csvOutputMerged = Table.create(TextColumn.create("Link Id"), DoubleColumn.create("value")); @@ -165,41 +150,48 @@ private void mergeEmissions(String pathParameter, String label) { } /** - * Merges the immissions data + * Merges receiverPoint data (written by {@link org.matsim.contrib.noise.NoiseWriter} * - * @param pathParameter path to the immissions data - * @param label label for the immissions data + * @param outputDir path to the receiverPoint data + * @param label label for the receiverPoint data (which kind of data) */ - private void mergeImissions(String pathParameter, String label) { + private void mergeReceiverPointData(String outputDir, String label) { // data per time step, maps coord to value Int2ObjectMap> data = new Int2ObjectOpenHashMap<>(); // Loop over all files + //TODO could be adjusted to time bin size from noise config group for (int time = minTime; time <= maxTime; time += 3600) { - String path = pathParameter + label + "_" + round(time, 1) + ".csv"; + String timeDataFile = outputDir + label + "_" + round(time, 1) + ".csv"; + Object2FloatOpenHashMap values = new Object2FloatOpenHashMap<>(); - if (!Files.exists(Path.of(path))) { - log.warn("File {} does not exist", path); + if (!Files.exists(Path.of(timeDataFile))) { + log.warn("File {} does not exist", timeDataFile); continue; } - // Read the file - Table table = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(path)) + //we need "damages_receiverPoint" -> "Damages 01:00:00" and "immission" -> "Immision 01:00:00" + String substrToCapitalize = label.contains("_") ? label.substring(0, label.lastIndexOf("_")) : label; + String valueHeader = StringUtils.capitalize(substrToCapitalize) + " " + Time.writeTime(time, Time.TIMEFORMAT_HHMMSS); + + // Read the data file + Table dataTable = Table.read().csv(CsvReadOptions.builder(IOUtils.getBufferedReader(timeDataFile)) .columnTypesPartial(Map.of("x", ColumnType.FLOAT, "y", ColumnType.FLOAT, "Receiver Point Id", ColumnType.INTEGER, - "t", ColumnType.DOUBLE)) + "t", ColumnType.DOUBLE, + valueHeader, ColumnType.DOUBLE)) .sample(false) .separator(';').build()); - // Loop over all rows in the file - for (Row row : table) { + // Loop over all rows in the data file + for (Row row : dataTable) { float x = row.getFloat("x"); float y = row.getFloat("y"); - float value = (float) row.getDouble(1); // 1 + float value = (float) row.getDouble(valueHeader); FloatFloatPair coord = FloatFloatPair.of(x, y); values.put(coord, value); } @@ -235,7 +227,7 @@ private void mergeImissions(String pathParameter, String label) { } } - xytHourData.setData(Map.of("imissions", raw)); + xytHourData.setData(Map.of(label, raw)); xytHourData.setCrs(crs); File out = outputDirectory.getParent().resolve(label + "_per_hour.avro").toFile(); @@ -257,7 +249,7 @@ private void mergeImissions(String pathParameter, String label) { xytDayData.setTimestamps(List.of(0)); xytDayData.setXCoords(xCoords); xytDayData.setYCoords(yCoords); - xytDayData.setData(Map.of("imissions", raw)); + xytDayData.setData(Map.of(label, raw)); xytDayData.setCrs(crs); File outDay = outputDirectory.getParent().resolve(label + "_per_day.avro").toFile(); diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java index 02d6337de15..deceb84624e 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java @@ -144,8 +144,7 @@ public Integer call() throws Exception { ProcessNoiseImmissions process = new ProcessNoiseImmissions(outputFilePath + "/immissions/", outputFilePath + "/receiverPoints/receiverPoints.csv", noiseParameters.getReceiverPointGap()); process.run(); - final String[] paths = {outputFilePath + "/immissions/", outputFilePath + "/emissions/"}; - MergeNoiseOutput mergeNoiseOutput = new MergeNoiseOutput(paths, Path.of(outputFilePath), config.global().getCoordinateSystem()); + MergeNoiseOutput mergeNoiseOutput = new MergeNoiseOutput(Path.of(outputFilePath), config.global().getCoordinateSystem()); mergeNoiseOutput.run(); return 0; diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/MergeNoiseCSVFile.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/MergeNoiseCSVFile.java index d052f341cfe..7abae434d94 100644 --- a/contribs/noise/src/main/java/org/matsim/contrib/noise/MergeNoiseCSVFile.java +++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/MergeNoiseCSVFile.java @@ -392,6 +392,7 @@ private void readReceiverPoints() { } } + //TODO this should be updated to use CSVReader or something as robust private void readValues() { for (int ll = 0; ll < this.labels.length; ll++) { diff --git a/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseWriter.java b/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseWriter.java index de465940c1a..6187e0b2f06 100644 --- a/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseWriter.java +++ b/contribs/noise/src/main/java/org/matsim/contrib/noise/NoiseWriter.java @@ -78,17 +78,17 @@ public static void writeReceiverPoints(NoiseContext noiseContext, String outputP // .addAttribute("Id", String.class) // .create(); // Collection features = new ArrayList(); -// +// // for (ReceiverPoint rp : noiseContext.getReceiverPoints().values()) { -// +// // SimpleFeature feature = factory.createPoint(MGC.coord2Coordinate(rp.getCoord()), new Object[] {rp.getId().toString()}, null); // features.add(feature); // } -// +// // String filePath = outputPath; // File file = new File(filePath); // file.mkdirs(); -// +// // log.info("Writing receiver points to shapefile... "); // ShapeFileWriter.writeGeometries(features, filePath + "receiverPoints.shp"); // log.info("Writing receiver points to shapefile... Done. "); @@ -318,13 +318,11 @@ public static void writeDamageInfoPerHour(NoiseContext noiseContext, String outp try { BufferedWriter bw = new BufferedWriter(new FileWriter(file)); - - bw.write("Receiver Point Id;Damages " + Time.writeTime(timeInterval, Time.TIMEFORMAT_HHMMSS)); + bw.write("Receiver Point Id;Damages " + Time.writeTime(timeInterval, Time.TIMEFORMAT_HHMMSS) + ";x;y;t"); bw.newLine(); for (NoiseReceiverPoint rp : noiseContext.getReceiverPoints().values()) { - - bw.write(rp.getId() + ";" + rp.getDamageCosts()); + bw.write(rp.getId() + ";" + rp.getDamageCosts() + ";" + rp.getCoord().getX() + ";" + rp.getCoord().getY() + ";" + timeInterval ); bw.newLine(); } From 6ba2578003eaed40f431e3401b88c3a98035aefc Mon Sep 17 00:00:00 2001 From: schlenther Date: Fri, 9 Aug 2024 13:11:10 +0200 Subject: [PATCH 194/213] NoiseDashboard: include stats and damage plots --- .../analysis/noise/MergeNoiseOutput.java | 11 +++- .../analysis/noise/NoiseAnalysis.java | 26 +++++++- .../simwrapper/dashboard/NoiseDashboard.java | 65 ++++++++++++++----- .../dashboard/NoiseDashboardTests.java | 7 +- 4 files changed, 89 insertions(+), 20 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java b/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java index e59c4aee75c..b5b85336c1c 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/noise/MergeNoiseOutput.java @@ -53,6 +53,8 @@ final class MergeNoiseOutput { private final int minTime = 3600; private int maxTime = 24 * 3600; + private final Map totalReceiverPointValues = new HashMap<>(); + MergeNoiseOutput(Path path, String coordinateSystem ) { this.outputDirectory = path; this.crs = coordinateSystem; @@ -162,6 +164,7 @@ private void mergeReceiverPointData(String outputDir, String label) { // Loop over all files //TODO could be adjusted to time bin size from noise config group + String substrToCapitalize = null; for (int time = minTime; time <= maxTime; time += 3600) { String timeDataFile = outputDir + label + "_" + round(time, 1) + ".csv"; @@ -174,7 +177,7 @@ private void mergeReceiverPointData(String outputDir, String label) { } //we need "damages_receiverPoint" -> "Damages 01:00:00" and "immission" -> "Immision 01:00:00" - String substrToCapitalize = label.contains("_") ? label.substring(0, label.lastIndexOf("_")) : label; + substrToCapitalize = label.contains("_") ? label.substring(0, label.lastIndexOf("_")) : label; String valueHeader = StringUtils.capitalize(substrToCapitalize) + " " + Time.writeTime(time, Time.TIMEFORMAT_HHMMSS); // Read the data file @@ -255,9 +258,12 @@ private void mergeReceiverPointData(String outputDir, String label) { File outDay = outputDirectory.getParent().resolve(label + "_per_day.avro").toFile(); writeAvro(xytDayData, outDay); + //cache the overall sum + this.totalReceiverPointValues.put(substrToCapitalize, raw.stream().reduce(0f, Float::sum)); } // Merges the immissions data + @Deprecated private void mergeImmissionsCSV(String pathParameter, String label) { log.info("Merging immissions data for label {}", label); @@ -317,4 +323,7 @@ private void mergeImmissionsCSV(String pathParameter, String label) { log.info("Merged noise data written to {} ", outPerDay); } + public Map getTotalReceiverPointValues() { + return totalReceiverPointValues; + } } diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java b/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java index deceb84624e..1892de7fb74 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/noise/NoiseAnalysis.java @@ -1,5 +1,7 @@ package org.matsim.application.analysis.noise; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.locationtech.jts.geom.Envelope; @@ -19,9 +21,15 @@ import org.matsim.core.config.ConfigUtils; import org.matsim.core.scenario.ScenarioUtils; import org.matsim.core.utils.geometry.CoordinateTransformation; +import org.matsim.core.utils.io.IOUtils; import picocli.CommandLine; +import java.io.IOException; import java.nio.file.Path; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -36,7 +44,10 @@ produces = { "emission_per_day.csv", "immission_per_day.%s", - "immission_per_hour.%s" + "immission_per_hour.%s", + "damages_receiverPoint_per_hour.%s", + "damages_receiverPoint_per_day.%s", + "noise_stats.csv" } ) public class NoiseAnalysis implements MATSimAppCommand { @@ -77,7 +88,7 @@ public Integer call() throws Exception { NoiseConfigGroup noiseParameters = ConfigUtils.addOrGetModule(config, NoiseConfigGroup.class); if(overrideParameters){ - log.warn("no NoiseConfigGroup was configured before. Will set som estandards. You should check the next lines in the log file!"); + log.warn("no NoiseConfigGroup was configured before. Will set some standards. You should check the next lines in the log file!"); noiseParameters.setConsideredActivitiesForReceiverPointGridArray(considerActivities.toArray(String[]::new)); noiseParameters.setConsideredActivitiesForDamageCalculationArray(considerActivities.toArray(String[]::new)); @@ -147,6 +158,17 @@ public Integer call() throws Exception { MergeNoiseOutput mergeNoiseOutput = new MergeNoiseOutput(Path.of(outputFilePath), config.global().getCoordinateSystem()); mergeNoiseOutput.run(); + // Total stats + DecimalFormat df = new DecimalFormat("#.###", DecimalFormatSymbols.getInstance(Locale.US)); + try (CSVPrinter printer = new CSVPrinter(IOUtils.getBufferedWriter(output.getPath("noise_stats.csv").toString()), CSVFormat.DEFAULT)) { + printer.printRecord("Annual cost rate per pop. unit [€]:", df.format(noiseParameters.getAnnualCostRate())); + for (Map.Entry labelValueEntry : mergeNoiseOutput.getTotalReceiverPointValues().entrySet()) { + printer.printRecord("Total " + labelValueEntry.getKey() + " at receiver points", df.format(labelValueEntry.getValue())); + } + } catch (IOException ex) { + log.error(ex); + } + return 0; } diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java index 036b3c5a718..48f173a8adb 100644 --- a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/dashboard/NoiseDashboard.java @@ -1,6 +1,7 @@ package org.matsim.simwrapper.dashboard; import org.matsim.application.analysis.noise.NoiseAnalysis; +import org.matsim.application.analysis.population.StuckAgentAnalysis; import org.matsim.application.prepare.network.CreateAvroNetwork; import org.matsim.simwrapper.Dashboard; import org.matsim.simwrapper.Header; @@ -8,6 +9,7 @@ import org.matsim.simwrapper.viz.ColorScheme; import org.matsim.simwrapper.viz.GridMap; import org.matsim.simwrapper.viz.MapPlot; +import org.matsim.simwrapper.viz.Tile; /** * Shows emission in the scenario. @@ -32,19 +34,12 @@ public void configure(Header header, Layout layout) { header.title = "Noise"; header.description = "Shows the noise footprint and spatial distribution."; - layout.row("aggregate noise") - .el(GridMap.class, (viz, data) -> { - viz.title = "Noise Immissions (Grid)"; - viz.description = "Total Noise Immissions per day"; - viz.height = 12.0; - viz.cellSize = 250; - viz.opacity = 0.2; - viz.maxHeight = 20; - viz.center = data.context().getCenter(); - viz.zoom = data.context().mapZoomLevel; - viz.setColorRamp(new double[]{30, 40, 50, 60, 70}, new String[]{"#1175b3", "#95c7df", "#dfdb95", "#dfb095", "#f4a986", "#cc0c27"}); - viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "immission_per_day.%s", "avro"); - }) + layout.row("stats") + .el(Tile.class, (viz, data) -> { + viz.dataset = data.compute(NoiseAnalysis.class, "noise_stats.csv"); + viz.height = 0.1; + }); + layout.row("emissions") .el(MapPlot.class, (viz, data) -> { viz.title = "Noise Emissions (Link)"; viz.description = "Maximum Noise Level per day [dB]"; @@ -65,18 +60,56 @@ public void configure(Header header, Layout layout) { viz.display.lineWidth.scaleFactor = 8d; viz.display.lineWidth.join = "Link Id"; }); - layout.row("hourly noise") + layout.row("imissions") + .el(GridMap.class, (viz, data) -> { + viz.title = "Noise Immissions (Grid)"; + viz.description = "Total Noise Immissions per day"; + viz.height = 12.0; + viz.cellSize = 250; + viz.opacity = 0.1; + viz.maxHeight = 40; + viz.center = data.context().getCenter(); + viz.zoom = data.context().mapZoomLevel; + viz.setColorRamp(new double[]{30, 40, 50, 60, 70}, new String[]{"#1175b3", "#95c7df", "#dfdb95", "#dfb095", "#f4a986", "#cc0c27"}); + viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "immission_per_day.%s", "avro"); + }) .el(GridMap.class, (viz, data) -> { viz.title = "Hourly Noise Immissions (Grid)"; viz.description = "Noise Immissions per hour"; viz.height = 12.0; viz.cellSize = 250; - viz.opacity = 0.2; - viz.maxHeight = 20; + viz.opacity = 0.1; + viz.maxHeight = 40; viz.center = data.context().getCenter(); viz.zoom = data.context().mapZoomLevel; viz.setColorRamp(new double[]{30, 40, 50, 60, 70}, new String[]{"#1175b3", "#95c7df", "#dfdb95", "#dfb095", "#f4a986", "#cc0c27"}); viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "immission_per_hour.%s", "avro"); }); + layout.row("damages") + .el(GridMap.class, (viz, data) -> { + viz.title = "Daily Noise Damages (Grid)"; + viz.description = "Total Noise Damages per day [€]"; + viz.height = 12.0; + viz.cellSize = 250; + viz.opacity = 0.1; + viz.maxHeight = 40; + viz.center = data.context().getCenter(); + viz.zoom = data.context().mapZoomLevel; + viz.setColorRamp(ColorScheme.Oranges); + viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "damages_receiverPoint_per_day.%s", "avro"); + }) + .el(GridMap.class, (viz, data) -> { + viz.title = "Hourly Noise Damages (Grid)"; + viz.description = "Noise Damages per hour [€]"; + viz.height = 12.0; + viz.cellSize = 250; + viz.opacity = 0.2; + viz.maxHeight = 40; + viz.center = data.context().getCenter(); + viz.zoom = data.context().mapZoomLevel; +// viz.setColorRamp(new double[]{30, 40, 50, 60, 70}, new String[]{"#1175b3", "#95c7df", "#dfdb95", "#dfb095", "#f4a986", "#cc0c27"}); + viz.setColorRamp(ColorScheme.Oranges); + viz.file = data.computeWithPlaceholder(NoiseAnalysis.class, "damages_receiverPoint_per_hour.%s", "avro"); + }); } } diff --git a/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/NoiseDashboardTests.java b/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/NoiseDashboardTests.java index 6ca2a08cee3..fdc846cdff5 100644 --- a/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/NoiseDashboardTests.java +++ b/contribs/simwrapper/src/test/java/org/matsim/simwrapper/dashboard/NoiseDashboardTests.java @@ -46,6 +46,11 @@ void generate() { Assertions.assertThat(out) .isDirectoryContaining("glob:**emission_per_day.csv") .isDirectoryContaining("glob:**immission_per_day.avro") - .isDirectoryContaining("glob:**immission_per_hour.avro"); + .isDirectoryContaining("glob:**immission_per_hour.avro") + .isDirectoryContaining("glob:**damages_receiverPoint_per_hour.avro") + .isDirectoryContaining("glob:**damages_receiverPoint_per_day.avro") + .isDirectoryContaining("glob:**noise_stats.csv"); + + //TODO check content / values of the files } } From cda5767f20627d1e8f8283cb1cb542c6be8c36d8 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Fri, 9 Aug 2024 13:34:12 +0200 Subject: [PATCH 195/213] only perform net consistency check once --- .../org/matsim/core/router/NetworkRoutingProvider.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/matsim/src/main/java/org/matsim/core/router/NetworkRoutingProvider.java b/matsim/src/main/java/org/matsim/core/router/NetworkRoutingProvider.java index a6c00d06942..7b874593fa1 100644 --- a/matsim/src/main/java/org/matsim/core/router/NetworkRoutingProvider.java +++ b/matsim/src/main/java/org/matsim/core/router/NetworkRoutingProvider.java @@ -46,6 +46,7 @@ public class NetworkRoutingProvider implements Provider{ private static final Logger log = LogManager.getLogger( NetworkRoutingProvider.class ) ; private final String routingMode; + private boolean alreadyCheckedConsistency = false; @Inject Map travelTimes; @Inject Map travelDisutilityFactories; @@ -142,6 +143,12 @@ private void checkNetwork(Network filteredNetwork) { return; } + if(alreadyCheckedConsistency){ + return; + } + + log.info("Checking network for mode '{}' for consistency...", mode); + int nLinks = filteredNetwork.getLinks().size(); int nNodes = filteredNetwork.getNodes().size(); new NetworkCleaner().run(filteredNetwork); @@ -153,5 +160,7 @@ private void checkNetwork(Network filteredNetwork) { "\n If this network topology is intended, set the routing config parameter 'networkRouteConsistencyCheck' to 'disable'."); throw new RuntimeException(errorMessage); } + + alreadyCheckedConsistency = true; } } From e2f7c360eda279ed4a0b07ec3298b5bb910413af Mon Sep 17 00:00:00 2001 From: schlenther Date: Fri, 9 Aug 2024 14:18:15 +0200 Subject: [PATCH 196/213] CreateSingleSimWrapperDashboard --- .../CreateSingleSimWrapperDashboard.java | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 contribs/simwrapper/src/main/java/org/matsim/simwrapper/CreateSingleSimWrapperDashboard.java diff --git a/contribs/simwrapper/src/main/java/org/matsim/simwrapper/CreateSingleSimWrapperDashboard.java b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/CreateSingleSimWrapperDashboard.java new file mode 100644 index 00000000000..fce848736a6 --- /dev/null +++ b/contribs/simwrapper/src/main/java/org/matsim/simwrapper/CreateSingleSimWrapperDashboard.java @@ -0,0 +1,148 @@ +/* *********************************************************************** * + * project: org.matsim.* + * Controler.java + * * + * *********************************************************************** * + * * + * copyright : (C) 2007 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** */ + +package org.matsim.simwrapper; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.matsim.application.ApplicationUtils; +import org.matsim.application.MATSimAppCommand; +import org.matsim.application.options.ShpOptions; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.simwrapper.dashboard.*; +import picocli.CommandLine; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +@CommandLine.Command( + name = "dashboard", + description = "Run analysis and create SimWrapper dashboard for existing run output." +) + +/** + * This class creates single SimWrapper dashboards for multiple output directories. It is meant to be run as a post-process, + * e.g. when a specific dashboard was missing after the initial run (for whatever reason). + * It will create the dashboard with all standard settings. + * Depending on the dashboard type, it might be required to provide ShpOptions for data filtering. + * TODO: test whether this works for the non-noise DashboardTypes. + */ +final class CreateSingleSimWrapperDashboard implements MATSimAppCommand { + + private static final Logger log = LogManager.getLogger(CreateSingleSimWrapperDashboard.class); + + @CommandLine.Option(names = "--type", required = true, description = "Provide the dashboard type to be generated. See DashboardType enum within this class.") + private DashboardType dashboardType; + + @CommandLine.Parameters(arity = "1..*", description = "Path to run output directories for which the dashboards is to be generated.") + private List inputPaths; + + @CommandLine.Mixin + private final ShpOptions shp = new ShpOptions(); + + enum DashboardType{ + noise, + emissions, + traffic, + overview, + stuckAgent, + populationAttribute, + ODTrip, + trip, + publicTransit + } + + private CreateSingleSimWrapperDashboard(){ + } + + @Override + public Integer call() throws Exception { + + for (Path runDirectory : inputPaths) { + log.info("Creating " + dashboardType + " for {}", runDirectory); + + Path configPath = ApplicationUtils.matchInput("config.xml", runDirectory); + Config config = ConfigUtils.loadConfig(configPath.toString()); + SimWrapper sw = SimWrapper.create(config); + + SimWrapperConfigGroup simwrapperCfg = ConfigUtils.addOrGetModule(config, SimWrapperConfigGroup.class); + + if (shp.isDefined()){ + //not sure if this is the best way to go, might be that the shape file would be automatically read by providing the --shp command line option + simwrapperCfg.defaultParams().shp = shp.getShapeFile().toString(); + } + + //skip default dashboards + simwrapperCfg.defaultDashboards = SimWrapperConfigGroup.Mode.disabled; + + //add dashboard + switch (dashboardType) { + case noise -> { + sw.addDashboard(new NoiseDashboard()); + } + case emissions -> { + sw.addDashboard(new EmissionsDashboard()); + } + case traffic -> { + sw.addDashboard(new TrafficDashboard()); + } + case overview -> { + sw.addDashboard(new OverviewDashboard()); + } + case stuckAgent -> { + sw.addDashboard(new StuckAgentDashboard()); + } + case populationAttribute -> { + sw.addDashboard(new PopulationAttributeDashboard()); + } + case ODTrip -> { + throw new RuntimeException("ODTripDashboard needs additional information. Single creation is currently not implemented"); +// sw.addDashboard(new ODTripDashboard()); + } + case trip -> { + sw.addDashboard(new TripDashboard()); + } + case publicTransit -> { + sw.addDashboard(new PublicTransitDashboard()); + } + default -> throw new IllegalArgumentException("unkown dashboard type: " + dashboardType); + } + + try { + //append dashboard to existing ones + boolean append = true; + sw.generate(runDirectory, append); + sw.run(runDirectory); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + return 0; + } + + public static void main(String[] args) { + new CreateSingleSimWrapperDashboard().execute(args); + } + +} + From 9175ec805299815d0d8797c57de367e908aa31eb Mon Sep 17 00:00:00 2001 From: schlenther Date: Fri, 9 Aug 2024 14:40:02 +0200 Subject: [PATCH 197/213] fix noise tests: explicitly set activity types for rp grid, when setting act type for damage calculation --- .../org/matsim/contrib/noise/NoiseIT.java | 4 ++ .../noise/NoiseConfigGroupTest/config1.xml | 47 ++++++++++--------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/contribs/noise/src/test/java/org/matsim/contrib/noise/NoiseIT.java b/contribs/noise/src/test/java/org/matsim/contrib/noise/NoiseIT.java index e8aa97a3ab3..542580dcb44 100644 --- a/contribs/noise/src/test/java/org/matsim/contrib/noise/NoiseIT.java +++ b/contribs/noise/src/test/java/org/matsim/contrib/noise/NoiseIT.java @@ -93,6 +93,7 @@ final void test1(){ String[] consideredActivities = {"home", "work"}; noiseParameters.setConsideredActivitiesForDamageCalculationArray(consideredActivities); + noiseParameters.setConsideredActivitiesForReceiverPointGridArray(consideredActivities); com.google.inject.Injector injector = Injector.createInjector( scenario.getConfig() , new AbstractModule(){ @Override public void install(){ @@ -197,6 +198,7 @@ private static void runTest2a( Config runConfig ) { String[] consideredActivities = {"home", "work"}; noiseParameters.setConsideredActivitiesForDamageCalculationArray(consideredActivities); + noiseParameters.setConsideredActivitiesForReceiverPointGridArray(consideredActivities); noiseParameters.setScaleFactor(1.); noiseParameters.setUseActualSpeedLevel(false); @@ -984,6 +986,7 @@ final void test2b(){ String[] consideredActivities = {"home", "work"}; noiseParameters.setConsideredActivitiesForDamageCalculationArray(consideredActivities); + noiseParameters.setConsideredActivitiesForReceiverPointGridArray(consideredActivities); noiseParameters.setScaleFactor(1.); noiseParameters.setNoiseAllocationApproach(NoiseConfigGroup.NoiseAllocationApproach.MarginalCost); @@ -1073,6 +1076,7 @@ final void test2c(){ String[] consideredActivities = {"home", "work"}; noiseParameters.setConsideredActivitiesForDamageCalculationArray(consideredActivities); + noiseParameters.setConsideredActivitiesForReceiverPointGridArray(consideredActivities); noiseParameters.setScaleFactor(1.); noiseParameters.setUseActualSpeedLevel(true); diff --git a/contribs/noise/test/input/org/matsim/contrib/noise/NoiseConfigGroupTest/config1.xml b/contribs/noise/test/input/org/matsim/contrib/noise/NoiseConfigGroupTest/config1.xml index e2d42df47cf..f4830014284 100644 --- a/contribs/noise/test/input/org/matsim/contrib/noise/NoiseConfigGroupTest/config1.xml +++ b/contribs/noise/test/input/org/matsim/contrib/noise/NoiseConfigGroupTest/config1.xml @@ -1,24 +1,25 @@ - + - + + - + - + - + @@ -34,20 +35,20 @@ - - + + - + - + - + - + @@ -66,26 +67,26 @@ - + - + - + - + - + - + @@ -171,20 +172,20 @@ - + - + - + - + - + @@ -199,5 +200,5 @@ - + From 61c65bf0f76f2edd8fab837a47e71d43adf233af Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Fri, 9 Aug 2024 17:43:49 +0200 Subject: [PATCH 198/213] add simple way of rejecting request insertion offers by the customer --- .../DefaultUnplannedRequestInserter.java | 61 +++++++++++-------- .../drt/run/examples/RunDrtExampleIT.java | 54 ++++++++++++++++ 2 files changed, 89 insertions(+), 26 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserter.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserter.java index 0f8443f0141..1854e93ffd1 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserter.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/optimizer/insertion/DefaultUnplannedRequestInserter.java @@ -54,6 +54,7 @@ public class DefaultUnplannedRequestInserter implements UnplannedRequestInserter { private static final Logger log = LogManager.getLogger(DefaultUnplannedRequestInserter.class); public static final String NO_INSERTION_FOUND_CAUSE = "no_insertion_found"; + public static final String OFFER_REJECTED_CAUSE = "offer_rejected"; private final String mode; private final Fleet fleet; @@ -125,17 +126,7 @@ private void scheduleUnplannedRequest(DrtRequest req, Map, Vehic Optional best = insertionSearch.findBestInsertion(req, Collections.unmodifiableCollection(vehicleEntries.values())); if (best.isEmpty()) { - if (!insertionRetryQueue.tryAddFailedRequest(req, now)) { - eventsManager.processEvent( - new PassengerRequestRejectedEvent(now, mode, req.getId(), req.getPassengerIds(), - NO_INSERTION_FOUND_CAUSE)); - log.debug("No insertion found for drt request " - + req - + " with passenger ids=" - + req.getPassengerIds().stream().map(Object::toString).collect(Collectors.joining(",")) - + " fromLinkId=" - + req.getFromLink().getId()); - } + retryOrReject(req, now, NO_INSERTION_FOUND_CAUSE); } else { InsertionWithDetourData insertion = best.get(); @@ -144,26 +135,44 @@ private void scheduleUnplannedRequest(DrtRequest req, Map, Vehic insertion.detourTimeInfo.pickupDetourInfo.departureTime, insertion.detourTimeInfo.dropoffDetourInfo.arrivalTime); - var vehicle = insertion.insertion.vehicleEntry.vehicle; - var pickupDropoffTaskPair = insertionScheduler.scheduleRequest(acceptedRequest.get(), insertion); + if(acceptedRequest.isPresent()) { + var vehicle = insertion.insertion.vehicleEntry.vehicle; + var pickupDropoffTaskPair = insertionScheduler.scheduleRequest(acceptedRequest.get(), insertion); - VehicleEntry newVehicleEntry = vehicleEntryFactory.create(vehicle, now); - if (newVehicleEntry != null) { - vehicleEntries.put(vehicle.getId(), newVehicleEntry); - } else { - vehicleEntries.remove(vehicle.getId()); - } + VehicleEntry newVehicleEntry = vehicleEntryFactory.create(vehicle, now); + if (newVehicleEntry != null) { + vehicleEntries.put(vehicle.getId(), newVehicleEntry); + } else { + vehicleEntries.remove(vehicle.getId()); + } + + double expectedPickupTime = pickupDropoffTaskPair.pickupTask.getBeginTime(); + expectedPickupTime = Math.max(expectedPickupTime, acceptedRequest.get().getEarliestStartTime()); + expectedPickupTime += stopDurationProvider.calcPickupDuration(vehicle, req); - double expectedPickupTime = pickupDropoffTaskPair.pickupTask.getBeginTime(); - expectedPickupTime = Math.max(expectedPickupTime, acceptedRequest.get().getEarliestStartTime()); - expectedPickupTime += stopDurationProvider.calcPickupDuration(vehicle, req); + double expectedDropoffTime = pickupDropoffTaskPair.dropoffTask.getBeginTime(); + expectedDropoffTime += stopDurationProvider.calcDropoffDuration(vehicle, req); - double expectedDropoffTime = pickupDropoffTaskPair.dropoffTask.getBeginTime(); - expectedDropoffTime += stopDurationProvider.calcDropoffDuration(vehicle, req); + eventsManager.processEvent( + new PassengerRequestScheduledEvent(now, mode, req.getId(), req.getPassengerIds(), vehicle.getId(), + expectedPickupTime, expectedDropoffTime)); + } else { + retryOrReject(req, now, OFFER_REJECTED_CAUSE); + } + } + } + private void retryOrReject(DrtRequest req, double now, String cause) { + if (!insertionRetryQueue.tryAddFailedRequest(req, now)) { eventsManager.processEvent( - new PassengerRequestScheduledEvent(now, mode, req.getId(), req.getPassengerIds(), vehicle.getId(), - expectedPickupTime, expectedDropoffTime)); + new PassengerRequestRejectedEvent(now, mode, req.getId(), req.getPassengerIds(), + cause)); + log.debug("No insertion found for drt request " + + req + + " with passenger ids=" + + req.getPassengerIds().stream().map(Object::toString).collect(Collectors.joining(",")) + + " fromLinkId=" + + req.getFromLink().getId()); } } } diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java index 0b2adb16db2..50c7440b957 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java @@ -29,6 +29,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -37,6 +38,10 @@ import org.matsim.contrib.drt.optimizer.DrtRequestInsertionRetryParams; import org.matsim.contrib.drt.optimizer.insertion.repeatedselective.RepeatedSelectiveInsertionSearchParams; import org.matsim.contrib.drt.optimizer.insertion.selective.SelectiveInsertionSearchParams; +import org.matsim.contrib.drt.passenger.AcceptedDrtRequest; +import org.matsim.contrib.drt.passenger.DefaultOfferAcceptor; +import org.matsim.contrib.drt.passenger.DrtOfferAcceptor; +import org.matsim.contrib.drt.passenger.DrtRequest; import org.matsim.contrib.drt.prebooking.PrebookingParams; import org.matsim.contrib.drt.prebooking.logic.ProbabilityBasedPrebookingLogic; import org.matsim.contrib.drt.run.DrtConfigGroup; @@ -53,6 +58,7 @@ import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEvent; import org.matsim.contrib.dvrp.passenger.PassengerRequestScheduledEventHandler; import org.matsim.contrib.dvrp.run.AbstractDvrpModeModule; +import org.matsim.contrib.dvrp.run.AbstractDvrpModeQSimModule; import org.matsim.contrib.dvrp.run.DvrpConfigGroup; import org.matsim.contrib.zone.skims.DvrpTravelTimeMatrixParams; import org.matsim.core.config.Config; @@ -60,6 +66,7 @@ import org.matsim.core.controler.AbstractModule; import org.matsim.core.controler.Controler; import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting; +import org.matsim.core.gbl.MatsimRandom; import org.matsim.core.utils.io.IOUtils; import org.matsim.examples.ExamplesUtils; import org.matsim.testcases.MatsimTestUtils; @@ -392,6 +399,39 @@ void testRunDrtWithPrebooking() { verifyDrtCustomerStatsCloseToExpectedStats(utils.getOutputDirectory(), expectedStats); } + + @Test + void testRunDrtOfferRejectionExample() { + Id.resetCaches(); + URL configUrl = IOUtils.extendUrl(ExamplesUtils.getTestScenarioURL("mielec"), + "mielec_stop_based_drt_config.xml"); + Config config = ConfigUtils.loadConfig(configUrl, new MultiModeDrtConfigGroup(), new DvrpConfigGroup(), + new OTFVisConfigGroup()); + + config.controller().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + + Controler controller = DrtControlerCreator.createControler(config, false); + controller.addOverridingQSimModule(new AbstractDvrpModeQSimModule("drt") { + @Override + protected void configureQSim() { + bindModal(DrtOfferAcceptor.class).toProvider(modalProvider(getter -> new ProbabilisticOfferAcceptor())); + } + }); + controller.run(); + + + var expectedStats = Stats.newBuilder() + .rejectionRate(0.1) + .rejections(190) + .waitAverage(217.01) + .inVehicleTravelTimeMean(362.57) + .totalTravelTimeMean(579.58) + .build(); + + verifyDrtCustomerStatsCloseToExpectedStats(utils.getOutputDirectory(), expectedStats); + } + /** * Early warning system: if customer stats vary more than the defined percentage above or below the expected values * then the following unit tests will fail. This is meant to serve as a red flag. @@ -536,4 +576,18 @@ public void install() { }); } } + + private static class ProbabilisticOfferAcceptor implements DrtOfferAcceptor { + + private final DefaultOfferAcceptor delegate = new DefaultOfferAcceptor(); + + @Override + public Optional acceptDrtOffer(DrtRequest request, double departureTime, double arrivalTime) { + if (MatsimRandom.getLocalInstance().nextBoolean()) { + return Optional.empty(); + } else { + return delegate.acceptDrtOffer(request, departureTime, arrivalTime); + } + } + } } From 954d5528bb04d78a31d6110ab8ab7e64fd6f4da8 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Fri, 9 Aug 2024 17:59:43 +0200 Subject: [PATCH 199/213] update test --- .../drt/run/examples/RunDrtExampleIT.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java b/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java index 50c7440b957..7b62adcace0 100644 --- a/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java +++ b/contribs/drt/src/test/java/org/matsim/contrib/drt/run/examples/RunDrtExampleIT.java @@ -26,10 +26,7 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -422,11 +419,11 @@ protected void configureQSim() { var expectedStats = Stats.newBuilder() - .rejectionRate(0.1) - .rejections(190) - .waitAverage(217.01) - .inVehicleTravelTimeMean(362.57) - .totalTravelTimeMean(579.58) + .rejectionRate(0.46) + .rejections(174.0) + .waitAverage(222.66) + .inVehicleTravelTimeMean(369.74) + .totalTravelTimeMean(592.4) .build(); verifyDrtCustomerStatsCloseToExpectedStats(utils.getOutputDirectory(), expectedStats); @@ -581,9 +578,11 @@ private static class ProbabilisticOfferAcceptor implements DrtOfferAcceptor { private final DefaultOfferAcceptor delegate = new DefaultOfferAcceptor(); + private final Random random = new Random(123); + @Override public Optional acceptDrtOffer(DrtRequest request, double departureTime, double arrivalTime) { - if (MatsimRandom.getLocalInstance().nextBoolean()) { + if (random.nextBoolean()) { return Optional.empty(); } else { return delegate.acceptDrtOffer(request, departureTime, arrivalTime); From c316aa5af2af5dd7eadd77ab3d5e320e8b059eec Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Sun, 11 Aug 2024 22:17:07 +0200 Subject: [PATCH 200/213] fix nasty insertion scheduler bug --- .../drt/scheduler/DefaultRequestInsertionScheduler.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionScheduler.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionScheduler.java index 8b3755ba082..72082906255 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionScheduler.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionScheduler.java @@ -128,8 +128,7 @@ private void verifyConstraints(InsertionWithDetourData insertion) { Schedule schedule = insertion.insertion.vehicleEntry.vehicle.getSchedule(); for (Task task : schedule.getTasks()) { - if (task instanceof DrtStopTask) { - DrtStopTask stopTask = (DrtStopTask) task; + if (task instanceof DrtStopTask stopTask) { for (AcceptedDrtRequest request : stopTask.getPickupRequests().values()) { Verify.verify(stopTask.getEndTime() <= request.getLatestStartTime()); @@ -211,12 +210,16 @@ private DrtStopTask insertPickup(AcceptedDrtRequest request, InsertionWithDetour beforePickupTask = insertWait(vehicleEntry.vehicle, currentTask, dropoffIdx); } } + if(!stops.isEmpty() && stops.size() + 1 > pickupIdx) { + //there is an existing stop which was scheduled earlier and was not the destination of the already diverted drive task + removeBetween(schedule, beforePickupTask, stops.get(pickupIdx).task); + } } else { // insert pickup after an existing stop/stay task StayTask stayTask = null; DrtStopTask stopTask = null; if (pickupIdx == 0) { if (scheduleStatus == ScheduleStatus.PLANNED) {// PLANNED schedule - stayTask = (StayTask)schedule.getTasks().get(0); + stayTask = (StayTask)schedule.getTasks().getFirst(); stayTask.setEndTime(stayTask.getBeginTime());// could get later removed with ScheduleTimingUpdater } else if (STAY.isBaseTypeOf(currentTask)) { stayTask = (StayTask)currentTask; // ongoing stay task From 940cad870b4c150068e35167de39ca3c96611267 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Aug 2024 08:53:07 +0000 Subject: [PATCH 201/213] Bump org.hamcrest:hamcrest from 2.2 to 3.0 Bumps [org.hamcrest:hamcrest](https://github.com/hamcrest/JavaHamcrest) from 2.2 to 3.0. - [Release notes](https://github.com/hamcrest/JavaHamcrest/releases) - [Changelog](https://github.com/hamcrest/JavaHamcrest/blob/master/CHANGES.md) - [Commits](https://github.com/hamcrest/JavaHamcrest/compare/v2.2...v3.0) --- updated-dependencies: - dependency-name: org.hamcrest:hamcrest dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a049d60560f..be4f98f1127 100644 --- a/pom.xml +++ b/pom.xml @@ -333,7 +333,7 @@ org.hamcrest hamcrest - 2.2 + 3.0 test From de00c66b030127d1223bc170a029ec106f408063 Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Tue, 13 Aug 2024 18:36:48 +0200 Subject: [PATCH 202/213] Accept optional OD pairs in route validation (#3409) * add option for existing input od file * Update SampleValidationRoutes.java --------- Co-authored-by: rakow --- .../traveltime/SampleValidationRoutes.java | 73 +++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/contribs/application/src/main/java/org/matsim/application/analysis/traffic/traveltime/SampleValidationRoutes.java b/contribs/application/src/main/java/org/matsim/application/analysis/traffic/traveltime/SampleValidationRoutes.java index 0e6c0f2af59..aa3a1fc4ba0 100644 --- a/contribs/application/src/main/java/org/matsim/application/analysis/traffic/traveltime/SampleValidationRoutes.java +++ b/contribs/application/src/main/java/org/matsim/application/analysis/traffic/traveltime/SampleValidationRoutes.java @@ -19,10 +19,7 @@ import org.matsim.api.core.v01.network.Node; import org.matsim.application.CommandSpec; import org.matsim.application.MATSimAppCommand; -import org.matsim.application.options.CrsOptions; -import org.matsim.application.options.InputOptions; -import org.matsim.application.options.OutputOptions; -import org.matsim.application.options.ShpOptions; +import org.matsim.application.options.*; import org.matsim.application.prepare.network.SampleNetwork; import org.matsim.core.network.NetworkUtils; import org.matsim.core.router.costcalculators.OnlyTimeDependentTravelDisutility; @@ -32,9 +29,11 @@ import org.matsim.core.trafficmonitoring.FreeSpeedTravelTime; import org.matsim.core.utils.geometry.CoordUtils; import org.matsim.core.utils.geometry.transformations.GeotoolsTransformation; +import org.matsim.core.utils.io.IOUtils; import picocli.CommandLine; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -86,6 +85,8 @@ public class SampleValidationRoutes implements MATSimAppCommand { @CommandLine.Option(names = "--mode", description = "Mode to validate", defaultValue = TransportMode.car) private String mode; + @CommandLine.Option(names = "--input-od", description = "Use input fromNode,toNode instead of sampling", required = false) + private String inputOD; public static void main(String[] args) { new SampleValidationRoutes().execute(args); @@ -142,9 +143,15 @@ public Integer call() throws Exception { OnlyTimeDependentTravelDisutility util = new OnlyTimeDependentTravelDisutility(tt); LeastCostPathCalculator router = new SpeedyALTFactory().createPathCalculator(network, util, tt); - List routes = sampleRoutes(network, router, rnd); - log.info("Sampled {} routes in range {}", routes.size(), distRange); + List routes; + if (inputOD != null) { + log.info("Using input OD file {}", inputOD); + routes = queryRoutes(network, router); + } else { + routes = sampleRoutes(network, router, rnd); + log.info("Sampled {} routes in range {}", routes.size(), distRange); + } try (CSVPrinter csv = new CSVPrinter(Files.newBufferedWriter(output.getPath()), CSVFormat.DEFAULT)) { csv.printRecord("from_node", "to_node", "beeline_dist", "dist", "travel_time", "geometry"); @@ -228,6 +235,7 @@ private List sampleRoutes(Network network, LeastCostPathCalculator router ShpOptions.Index index = shp.isDefined() ? shp.createIndex(crs, "_") : null; Predicate exclude = excludeRoads != null && !excludeRoads.isBlank() ? new Predicate<>() { final Pattern p = Pattern.compile(excludeRoads, Pattern.CASE_INSENSITIVE); + @Override public boolean test(Link link) { return p.matcher(NetworkUtils.getHighwayType(link)).find(); @@ -282,6 +290,59 @@ public boolean test(Link link) { return result; } + /** + * Use given od pairs as input for validation. + */ + private List queryRoutes(Network network, LeastCostPathCalculator router) { + + List result = new ArrayList<>(); + String crs = ProjectionUtils.getCRS(network); + + if (this.crs.getInputCRS() != null) + crs = this.crs.getInputCRS(); + + if (crs == null) { + throw new IllegalArgumentException("Input CRS could not be detected. Please specify with --input-crs [EPSG:xxx]"); + } + + GeotoolsTransformation ct = new GeotoolsTransformation(crs, "EPSG:4326"); + + try (CSVParser parser = CSVParser.parse(IOUtils.getBufferedReader(inputOD), CSVFormat.DEFAULT.builder().setHeader().setSkipHeaderRecord(true). + setDelimiter(CsvOptions.detectDelimiter(inputOD)).build())) { + + List header = parser.getHeaderNames(); + if (!header.contains("from_node")) + throw new IllegalArgumentException("Missing 'from_node' column in input file"); + if (!header.contains("to_node")) + throw new IllegalArgumentException("Missing 'to_node' column in input file"); + + for (CSVRecord r : parser) { + Node fromNode = network.getNodes().get(Id.createNodeId(r.get("from_node"))); + Node toNode = network.getNodes().get(Id.createNodeId(r.get("to_node"))); + + if (fromNode == null) + throw new IllegalArgumentException("Node " + r.get("from_node") + " not found"); + if (toNode == null) + throw new IllegalArgumentException("Node " + r.get("to_node") + " not found"); + + LeastCostPathCalculator.Path path = router.calcLeastCostPath(fromNode, toNode, 0, null, null); + result.add(new Route( + fromNode.getId(), + toNode.getId(), + ct.transform(fromNode.getCoord()), + ct.transform(toNode.getCoord()), + path.travelTime, + path.links.stream().mapToDouble(Link::getLength).sum() + )); + } + + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + return result; + } + /** * Key as pair of from and to node. */ From 4dbce8e468fee032e2311fc1ee3245a76bd5a8b7 Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Thu, 15 Aug 2024 18:59:26 +0200 Subject: [PATCH 203/213] add ride scoring parametrization based on car (#3410) --- .../RideScoringParamsFromCarParams.java | 37 +++++++++++++++++++ .../RideScoringParamsFromCarParamsTest.java | 34 +++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 contribs/vsp/src/main/java/org/matsim/contrib/vsp/scoring/RideScoringParamsFromCarParams.java create mode 100644 contribs/vsp/src/test/java/org/matsim/contrib/vsp/scoring/RideScoringParamsFromCarParamsTest.java diff --git a/contribs/vsp/src/main/java/org/matsim/contrib/vsp/scoring/RideScoringParamsFromCarParams.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/scoring/RideScoringParamsFromCarParams.java new file mode 100644 index 00000000000..2286692e4d6 --- /dev/null +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/scoring/RideScoringParamsFromCarParams.java @@ -0,0 +1,37 @@ +package org.matsim.contrib.vsp.scoring; + +import org.matsim.api.core.v01.TransportMode; +import org.matsim.core.config.groups.ScoringConfigGroup; + +public class RideScoringParamsFromCarParams { + + /** + * Sets ride scoring params based on car scoring params (including prices). This assumes that the ride passenger somehow has + * to compensate the driver for the additional driving effort to provide the ride. + * + * @param scoringConfigGroup config.scoring() + * @param alpha represents the share of an average ride trip that the car driver has to drive additionally to the car + * trip to provide the ride. Typical values are between 1 (i.e. driver drives additional 10km to provide a 10 km + * ride) and 2 (i.e. driver drives additional 20km to provide a 10 km ride). Alpha can be calibrated and must + * be alpha >= 0. + */ + public static void setRideScoringParamsBasedOnCarParams (ScoringConfigGroup scoringConfigGroup, double alpha) { + ScoringConfigGroup.ModeParams carParams = scoringConfigGroup.getOrCreateModeParams(TransportMode.car); + ScoringConfigGroup.ModeParams rideParams = scoringConfigGroup.getOrCreateModeParams(TransportMode.ride); + + // constant is a calibration parameter and should not be changed + + // ride has no fixed cost + rideParams.setDailyMonetaryConstant(0.0); + + // account for the driver's monetary distance rate. + rideParams.setMonetaryDistanceRate(alpha * carParams.getMonetaryDistanceRate()); + + // rider and driver have marginalUtilityOfDistance + rideParams.setMarginalUtilityOfDistance((alpha + 1.0) * carParams.getMarginalUtilityOfDistance()); + + // rider and driver have marginalUtilityOfTravelling, the driver additionally loses the opportunity to perform an activity + rideParams.setMarginalUtilityOfTraveling((alpha + 1.0) * carParams.getMarginalUtilityOfTraveling() + + alpha * -scoringConfigGroup.getPerforming_utils_hr()); + } +} diff --git a/contribs/vsp/src/test/java/org/matsim/contrib/vsp/scoring/RideScoringParamsFromCarParamsTest.java b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/scoring/RideScoringParamsFromCarParamsTest.java new file mode 100644 index 00000000000..2703f23443a --- /dev/null +++ b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/scoring/RideScoringParamsFromCarParamsTest.java @@ -0,0 +1,34 @@ +package org.matsim.contrib.vsp.scoring; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; +import org.matsim.core.config.groups.ScoringConfigGroup; + +public class RideScoringParamsFromCarParamsTest { + + @Test + void testSetRideScoringParamsBasedOnCarParams() { + Config config = ConfigUtils.createConfig(); + ScoringConfigGroup scoringConfigGroup = config.scoring(); + + scoringConfigGroup.setPerforming_utils_hr(6.0); + ScoringConfigGroup.ModeParams carParams = scoringConfigGroup.getOrCreateModeParams(TransportMode.car); + carParams.setDailyMonetaryConstant(-10.0); + carParams.setMarginalUtilityOfDistance(-2.0); + carParams.setMarginalUtilityOfTraveling(-1.0); + carParams.setMonetaryDistanceRate(-0.3); + + double alpha = 2.0; + + RideScoringParamsFromCarParams.setRideScoringParamsBasedOnCarParams(scoringConfigGroup, alpha); + + ScoringConfigGroup.ModeParams rideParams = scoringConfigGroup.getOrCreateModeParams(TransportMode.ride); + Assertions.assertEquals(0.0, rideParams.getDailyMonetaryConstant()); + Assertions.assertEquals(-0.6, rideParams.getMonetaryDistanceRate()); + Assertions.assertEquals(-6.0, rideParams.getMarginalUtilityOfDistance()); + Assertions.assertEquals(alpha * -6.0 + (alpha + 1) * -1.0, rideParams.getMarginalUtilityOfTraveling()); + } +} From 091b754394337e771aefd5b43a358b0b9419ec17 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Fri, 16 Aug 2024 11:53:08 +0200 Subject: [PATCH 204/213] add chained pt fare handler --- .../vsp/pt/fare/ChainedPtFareCalculator.java | 23 ++ .../vsp/pt/fare/ChainedPtFareHandler.java | 68 ++++++ .../fare/DistanceBasedPtFareCalculator.java | 71 ++++++ .../pt/fare/DistanceBasedPtFareHandler.java | 81 ------- .../pt/fare/DistanceBasedPtFareParams.java | 213 ++++++++---------- .../fare/FareZoneBasedPtFareCalculator.java | 44 ++++ .../pt/fare/FareZoneBasedPtFareHandler.java | 163 -------------- .../pt/fare/FareZoneBasedPtFareParams.java | 33 +++ .../vsp/pt/fare/PtFareCalculator.java | 12 + .../vsp/pt/fare/PtFareConfigGroup.java | 119 +++++----- .../playground/vsp/pt/fare/PtFareHandler.java | 8 + .../playground/vsp/pt/fare/PtFareModule.java | 63 ++++-- .../playground/vsp/pt/fare/PtFareParams.java | 71 ++++++ .../PtTripWithDistanceBasedFareEstimator.java | 33 ++- .../fare/FareZoneBasedPtFareHandlerTest.java | 27 ++- 15 files changed, 562 insertions(+), 467 deletions(-) create mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareCalculator.java create mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareHandler.java create mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculator.java delete mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareHandler.java create mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculator.java delete mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandler.java create mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareParams.java create mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareCalculator.java create mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareHandler.java create mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareParams.java diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareCalculator.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareCalculator.java new file mode 100644 index 00000000000..a1156d01740 --- /dev/null +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareCalculator.java @@ -0,0 +1,23 @@ +package playground.vsp.pt.fare; + +import com.google.inject.Inject; +import org.matsim.api.core.v01.Coord; + +import java.util.Optional; +import java.util.Set; + +public class ChainedPtFareCalculator implements PtFareCalculator { + @Inject + private Set fareCalculators; + + @Override + public Optional calculateFare(Coord from, Coord to) { + for (PtFareCalculator fareCalculator : fareCalculators) { + Optional fareResult = fareCalculator.calculateFare(from, to); + if (fareResult.isPresent()) { + return fareResult; + } + } + return Optional.empty(); + } +} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareHandler.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareHandler.java new file mode 100644 index 00000000000..cc5963e6345 --- /dev/null +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareHandler.java @@ -0,0 +1,68 @@ +package playground.vsp.pt.fare; + +import com.google.inject.Inject; +import org.matsim.api.core.v01.Coord; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.events.ActivityStartEvent; +import org.matsim.api.core.v01.events.PersonMoneyEvent; +import org.matsim.api.core.v01.population.Person; +import org.matsim.core.api.experimental.events.AgentWaitingForPtEvent; +import org.matsim.core.api.experimental.events.EventsManager; +import org.matsim.core.router.StageActivityTypeIdentifier; +import org.matsim.pt.PtConstants; + +import java.util.HashMap; +import java.util.Map; + +public class ChainedPtFareHandler implements PtFareHandler { + @Inject + private EventsManager events; + + private final Map, Coord> personDepartureCoordMap = new HashMap<>(); + private final Map, Coord> personArrivalCoordMap = new HashMap<>(); + + @Inject + private ChainedPtFareCalculator fareCalculator; + + @Override + public void handleEvent(ActivityStartEvent event) { + if (event.getActType().equals(PtConstants.TRANSIT_ACTIVITY_TYPE)) { + personDepartureCoordMap.computeIfAbsent(event.getPersonId(), c -> event.getCoord()); // The departure place is fixed to the place of + // first pt interaction an agent has in the whole leg + personArrivalCoordMap.put(event.getPersonId(), event.getCoord()); // The arrival stop will keep updating until the agent start a real + // activity (i.e. finish the leg) + } + + if (StageActivityTypeIdentifier.isStageActivity(event.getActType())) { + return; + } + + Id personId = event.getPersonId(); + if (!personDepartureCoordMap.containsKey(personId)) { + return; + } + + Coord from = personDepartureCoordMap.get(personId); + Coord to = personArrivalCoordMap.get(personId); + + PtFareCalculator.FareResult fare = fareCalculator.calculateFare(from, to).orElseThrow(); + + // charge fare to the person + events.processEvent(new PersonMoneyEvent(event.getTime(), event.getPersonId(), -fare.fare(), PtFareConfigGroup.PT_FARE, + fare.transactionPartner(), event.getPersonId().toString())); + + personDepartureCoordMap.remove(personId); + personArrivalCoordMap.remove(personId); + } + + @Override + public void handleEvent(AgentWaitingForPtEvent event) { + //TODO + } + + @Override + public void reset(int iteration) { + personArrivalCoordMap.clear(); + personDepartureCoordMap.clear(); + } +} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculator.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculator.java new file mode 100644 index 00000000000..cc3de24235c --- /dev/null +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculator.java @@ -0,0 +1,71 @@ +package playground.vsp.pt.fare; + +import org.geotools.api.feature.simple.SimpleFeature; +import org.locationtech.jts.geom.Geometry; +import org.matsim.api.core.v01.Coord; +import org.matsim.application.options.ShpOptions; +import org.matsim.core.utils.geometry.CoordUtils; +import org.matsim.core.utils.geometry.geotools.MGC; + +import java.util.List; +import java.util.Optional; + +public class DistanceBasedPtFareCalculator implements PtFareCalculator { + private final double minFare; + private final double shortTripIntercept; + private final double shortTripSlope; + private final double longTripIntercept; + private final double longTripSlope; + private final double longTripThreshold; + private ShpOptions shp = null; + private final String transactionPartner; + + public DistanceBasedPtFareCalculator(DistanceBasedPtFareParams params) { + this.minFare = params.getMinFare(); + this.shortTripIntercept = params.getNormalTripIntercept(); + this.shortTripSlope = params.getNormalTripSlope(); + this.longTripIntercept = params.getLongDistanceTripIntercept(); + this.longTripSlope = params.getLongDistanceTripSlope(); + this.longTripThreshold = params.getLongDistanceTripThreshold(); + this.transactionPartner = params.getTransactionPartner(); + + if (params.getFareZoneShp() != null) { + this.shp = new ShpOptions(params.getFareZoneShp(), null, null); + } + } + + @Override + public Optional calculateFare(Coord from, Coord to) { + if (!shapeCheck(from, to)) { + return Optional.empty(); + } + + double distance = CoordUtils.calcEuclideanDistance(from, to); + + double fare = computeFare(distance, longTripThreshold, minFare, shortTripIntercept, shortTripSlope, longTripIntercept, longTripSlope); + return Optional.of(new FareResult(fare, transactionPartner)); + } + + private boolean shapeCheck(Coord from, Coord to) { + if (shp == null) { + return true; + } + + return inShape(from, shp.readFeatures()) && inShape(to, shp.readFeatures()); + } + + boolean inShape(Coord coord, List features) { + return features.stream().anyMatch(f -> MGC.coord2Point(coord).within((Geometry) f.getDefaultGeometry())); + } + + public static double computeFare(double distance, double longTripThreshold, double minFare, double shortTripIntercept, double shortTripSlope, + double longTripIntercept, double longTripSlope) { + if (distance <= longTripThreshold) { + return Math.max(minFare, shortTripIntercept + shortTripSlope * distance); + } else { + return Math.max(minFare, longTripIntercept + longTripSlope * distance); + } + } + + +} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareHandler.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareHandler.java deleted file mode 100644 index 79741e54919..00000000000 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareHandler.java +++ /dev/null @@ -1,81 +0,0 @@ -package playground.vsp.pt.fare; - -import com.google.inject.Inject; -import org.matsim.api.core.v01.Coord; -import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.events.ActivityStartEvent; -import org.matsim.api.core.v01.events.PersonMoneyEvent; -import org.matsim.api.core.v01.events.handler.ActivityStartEventHandler; -import org.matsim.api.core.v01.population.Person; -import org.matsim.core.api.experimental.events.EventsManager; -import org.matsim.core.router.StageActivityTypeIdentifier; -import org.matsim.core.utils.geometry.CoordUtils; -import org.matsim.pt.PtConstants; - -import java.util.HashMap; -import java.util.Map; - -public class DistanceBasedPtFareHandler implements ActivityStartEventHandler { - @Inject - private EventsManager events; - - private final double minFare; - private final double shortTripIntercept; - private final double shortTripSlope; - private final double longTripIntercept; - private final double longTripSlope; - private final double longTripThreshold; - - private final Map, Coord> personDepartureCoordMap = new HashMap<>(); - private final Map, Coord> personArrivalCoordMap = new HashMap<>(); - - public DistanceBasedPtFareHandler(DistanceBasedPtFareParams params) { - this.minFare = params.getMinFare(); - this.shortTripIntercept = params.getNormalTripIntercept(); - this.shortTripSlope = params.getNormalTripSlope(); - this.longTripIntercept = params.getLongDistanceTripIntercept(); - this.longTripSlope = params.getLongDistanceTripSlope(); - this.longTripThreshold = params.getLongDistanceTripThreshold(); - } - - @Override - public void handleEvent(ActivityStartEvent event) { - if (event.getActType().equals(PtConstants.TRANSIT_ACTIVITY_TYPE)) { - personDepartureCoordMap.computeIfAbsent(event.getPersonId(), c -> event.getCoord()); // The departure place is fixed to the place of first pt interaction an agent has in the whole leg - personArrivalCoordMap.put(event.getPersonId(), event.getCoord()); // The arrival stop will keep updating until the agent start a real activity (i.e. finish the leg) - } - - if (!StageActivityTypeIdentifier.isStageActivity(event.getActType())) { - Id personId = event.getPersonId(); - if (personDepartureCoordMap.containsKey(personId)) { - double distance = CoordUtils.calcEuclideanDistance - (personDepartureCoordMap.get(personId), personArrivalCoordMap.get(personId)); - - double fare = computeFare(distance, longTripThreshold, minFare, shortTripIntercept, shortTripSlope, longTripIntercept, longTripSlope); - // charge fare to the person - events.processEvent( - new PersonMoneyEvent(event.getTime(), event.getPersonId(), -fare, - PtFareConfigGroup.PT_FARE, DistanceBasedPtFareParams.PT_FARE_DISTANCE_BASED, event.getPersonId().toString())); - - personDepartureCoordMap.remove(personId); - personArrivalCoordMap.remove(personId); - } - } - } - - public static double computeFare(double distance, double longTripThreshold, double minFare, - double shortTripIntercept, double shortTripSlope, - double longTripIntercept, double longTripSlope) { - if (distance <= longTripThreshold) { - return Math.max(minFare, shortTripIntercept + shortTripSlope * distance); - } else { - return Math.max(minFare, longTripIntercept + longTripSlope * distance); - } - } - - @Override - public void reset(int iteration) { - personArrivalCoordMap.clear(); - personDepartureCoordMap.clear(); - } -} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java index 442d956bf3c..cc393f92175 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java @@ -1,7 +1,5 @@ package playground.vsp.pt.fare; -import org.matsim.core.config.ReflectiveConfigGroup; - import jakarta.validation.constraints.PositiveOrZero; import java.util.Map; @@ -12,119 +10,106 @@ * The default values are set based on the fitting results of the trip and fare data collected on September 2021 * The values are based on the standard unit of meter (m) and Euro (EUR) */ -public class DistanceBasedPtFareParams extends ReflectiveConfigGroup { - public static final String PT_FARE_DISTANCE_BASED = "distance based pt fare"; - - public static final String SET_NAME = "ptFareCalculationDistanceBased"; - public static final String MIN_FARE = "minFare"; - public static final String NORMAL_TRIP_SLOPE = "normalTripSlope"; - public static final String NORMAL_TRIP_INTERCEPT = "normalTripIntercept"; - public static final String LONG_DISTANCE_TRIP_THRESHOLD = "longDistanceTripThreshold"; - public static final String LONG_DISTANCE_TRIP_SLOPE = "longDistanceTripSlope"; - public static final String LONG_DISTANCE_TRIP_INTERCEPT = "longDistanceTripIntercept"; - public static final String FARE_ZONE_SHP = "fareZoneShp"; - - @PositiveOrZero - private double minFare = 2.0; - @PositiveOrZero - private double normalTripIntercept = 1.6; - @PositiveOrZero - private double normalTripSlope = 0.00017; - @PositiveOrZero - private double longDistanceTripThreshold = 50000.0; - @PositiveOrZero - private double longDistanceTripIntercept = 30.0; - @PositiveOrZero - private double longDistanceTripSlope = 0.00025; - private String fareZoneShp; - - public DistanceBasedPtFareParams() { - super(SET_NAME); - } - - @Override - public Map getComments() { - Map map = super.getComments(); - map.put(MIN_FARE, "Minimum fare for a PT trip " + - "(e.g. Kurzstrecke/short distance ticket in cities, ticket for 1 zone in rural areas)"); - map.put(NORMAL_TRIP_SLOPE, "Linear model y = ax + b: the value of a, for normal trips (e.g. within the city or region)"); - map.put(NORMAL_TRIP_INTERCEPT, "Linear model y = ax + b: the value of b, for normal trips"); - map.put(LONG_DISTANCE_TRIP_SLOPE, "Linear model y = ax + b: the value of a, for long distance trips (e.g. intercity trips)"); - map.put(LONG_DISTANCE_TRIP_INTERCEPT, "Linear model y = ax + b: the value of b, for long trips"); - map.put(LONG_DISTANCE_TRIP_THRESHOLD, "Threshold of the long trips in meters. Below this value, " + - "the trips are considered as normal trips. Above this value, the trips are considered as " + - "inter-city trips"); - map.put(FARE_ZONE_SHP, "Shp file with fare zone(s). This parameter is only used for PtFareCalculationModel 'fareZoneBased'."); - return map; - } - - @StringGetter(MIN_FARE) - public double getMinFare() { - return minFare; - } - - @StringSetter(MIN_FARE) - public void setMinFare(double minFare) { - this.minFare = minFare; - } - - @StringGetter(NORMAL_TRIP_SLOPE) - public double getNormalTripSlope() { - return normalTripSlope; - } - - @StringSetter(NORMAL_TRIP_SLOPE) - public void setNormalTripSlope(double normalTripSlope) { - this.normalTripSlope = normalTripSlope; - } - - @StringGetter(NORMAL_TRIP_INTERCEPT) - public double getNormalTripIntercept() { - return normalTripIntercept; - } - - @StringSetter(NORMAL_TRIP_INTERCEPT) - public void setNormalTripIntercept(double normalTripIntercept) { - this.normalTripIntercept = normalTripIntercept; - } - - @StringGetter(LONG_DISTANCE_TRIP_SLOPE) - public double getLongDistanceTripSlope() { - return longDistanceTripSlope; - } - - @StringSetter(LONG_DISTANCE_TRIP_SLOPE) - public void setLongDistanceTripSlope(double longDistanceTripSlope) { - this.longDistanceTripSlope = longDistanceTripSlope; - } - - @StringGetter(LONG_DISTANCE_TRIP_INTERCEPT) - public double getLongDistanceTripIntercept() { - return longDistanceTripIntercept; - } - - @StringSetter(LONG_DISTANCE_TRIP_INTERCEPT) - public void setLongDistanceTripIntercept(double longDistanceTripIntercept) { - this.longDistanceTripIntercept = longDistanceTripIntercept; - } - - @StringGetter(LONG_DISTANCE_TRIP_THRESHOLD) - public double getLongDistanceTripThreshold() { - return longDistanceTripThreshold; - } - - @StringSetter(LONG_DISTANCE_TRIP_THRESHOLD) - public void setLongDistanceTripThreshold(double longDistanceTripThreshold) { - this.longDistanceTripThreshold = longDistanceTripThreshold; - } - - @StringGetter(FARE_ZONE_SHP) - public String getFareZoneShp() { - return fareZoneShp; +public class DistanceBasedPtFareParams extends PtFareParams { + public static final String SET_NAME = "ptFareCalculationDistanceBased"; + public static final String MIN_FARE = "minFare"; + public static final String NORMAL_TRIP_SLOPE = "normalTripSlope"; + public static final String NORMAL_TRIP_INTERCEPT = "normalTripIntercept"; + public static final String LONG_DISTANCE_TRIP_THRESHOLD = "longDistanceTripThreshold"; + public static final String LONG_DISTANCE_TRIP_SLOPE = "longDistanceTripSlope"; + public static final String LONG_DISTANCE_TRIP_INTERCEPT = "longDistanceTripIntercept"; + + @PositiveOrZero + private double minFare = 2.0; + @PositiveOrZero + private double normalTripIntercept = 1.6; + @PositiveOrZero + private double normalTripSlope = 0.00017; + @PositiveOrZero + private double longDistanceTripThreshold = 50000.0; + @PositiveOrZero + private double longDistanceTripIntercept = 30.0; + @PositiveOrZero + private double longDistanceTripSlope = 0.00025; + + public DistanceBasedPtFareParams() { + super(SET_NAME); + } + + @Override + public Map getComments() { + Map map = super.getComments(); + map.put(MIN_FARE, "Minimum fare for a PT trip (e.g. Kurzstrecke/short distance ticket in cities, ticket for 1 zone in rural areas). Default" + + " " + + "is 2.0EUR."); + map.put(NORMAL_TRIP_SLOPE, "Linear model y = ax + b: the value of a, for normal trips (e.g. within the city or region). Default is 0.00017" + + "EUR."); + map.put(NORMAL_TRIP_INTERCEPT, "Linear model y = ax + b: the value of b, for normal trips. Default is 1.6EUR."); + map.put(LONG_DISTANCE_TRIP_SLOPE, "Linear model y = ax + b: the value of a, for long distance trips (e.g. intercity trips). Default is 0" + + ".00025EUR."); + map.put(LONG_DISTANCE_TRIP_INTERCEPT, "Linear model y = ax + b: the value of b, for long trips. Default is 30.0EUR."); + map.put(LONG_DISTANCE_TRIP_THRESHOLD, "Threshold of the long trips in meters. Below this value, the trips are considered as normal trips. " + + "Above this value, the trips are considered as inter-city trips. Default is 50000.0m."); + return map; + } + + @StringGetter(MIN_FARE) + public double getMinFare() { + return minFare; + } + + @StringSetter(MIN_FARE) + public void setMinFare(double minFare) { + this.minFare = minFare; + } + + @StringGetter(NORMAL_TRIP_SLOPE) + public double getNormalTripSlope() { + return normalTripSlope; + } + + @StringSetter(NORMAL_TRIP_SLOPE) + public void setNormalTripSlope(double normalTripSlope) { + this.normalTripSlope = normalTripSlope; + } + + @StringGetter(NORMAL_TRIP_INTERCEPT) + public double getNormalTripIntercept() { + return normalTripIntercept; + } + + @StringSetter(NORMAL_TRIP_INTERCEPT) + public void setNormalTripIntercept(double normalTripIntercept) { + this.normalTripIntercept = normalTripIntercept; + } + + @StringGetter(LONG_DISTANCE_TRIP_SLOPE) + public double getLongDistanceTripSlope() { + return longDistanceTripSlope; + } + + @StringSetter(LONG_DISTANCE_TRIP_SLOPE) + public void setLongDistanceTripSlope(double longDistanceTripSlope) { + this.longDistanceTripSlope = longDistanceTripSlope; + } + + @StringGetter(LONG_DISTANCE_TRIP_INTERCEPT) + public double getLongDistanceTripIntercept() { + return longDistanceTripIntercept; + } + + @StringSetter(LONG_DISTANCE_TRIP_INTERCEPT) + public void setLongDistanceTripIntercept(double longDistanceTripIntercept) { + this.longDistanceTripIntercept = longDistanceTripIntercept; + } + + @StringGetter(LONG_DISTANCE_TRIP_THRESHOLD) + public double getLongDistanceTripThreshold() { + return longDistanceTripThreshold; } - @StringSetter(FARE_ZONE_SHP) - public void setFareZoneShp(String fareZoneShp) { - this.fareZoneShp = fareZoneShp; + @StringSetter(LONG_DISTANCE_TRIP_THRESHOLD) + public void setLongDistanceTripThreshold(double longDistanceTripThreshold) { + this.longDistanceTripThreshold = longDistanceTripThreshold; } } diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculator.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculator.java new file mode 100644 index 00000000000..feda2b3a950 --- /dev/null +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculator.java @@ -0,0 +1,44 @@ +package playground.vsp.pt.fare; + +import org.geotools.api.feature.simple.SimpleFeature; +import org.locationtech.jts.geom.Geometry; +import org.matsim.api.core.v01.Coord; +import org.matsim.application.options.ShpOptions; +import org.matsim.core.utils.geometry.geotools.MGC; + +import java.util.List; +import java.util.Optional; + +public class FareZoneBasedPtFareCalculator implements PtFareCalculator { + private final ShpOptions shp; + private final String transactionPartner; + + public static final String FARE = "fare"; + + public FareZoneBasedPtFareCalculator(FareZoneBasedPtFareParams params) { + this.shp = new ShpOptions(params.getFareZoneShp(), null, null); + transactionPartner = params.getTransactionPartner(); + } + + @Override + public Optional calculateFare(Coord from, Coord to) { + Optional departureZone = determineFareZone(from, shp.readFeatures()); + Optional arrivalZone = determineFareZone(to, shp.readFeatures()); + + //if one of the zones is empty, it is not included in the shape file, so this calculator cannot compute the fare + if (departureZone.isEmpty() || arrivalZone.isEmpty()) { + return Optional.empty(); + } + + if (!departureZone.get().getID().equals(arrivalZone.get().getID())) { + return Optional.empty(); + } + + Double fare = (Double) departureZone.get().getAttribute(FARE); + return Optional.of(new FareResult(fare, transactionPartner)); + } + + Optional determineFareZone(Coord coord, List features) { + return features.stream().filter(f -> MGC.coord2Point(coord).within((Geometry) f.getDefaultGeometry())).findFirst(); + } +} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandler.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandler.java deleted file mode 100644 index 962a18fac57..00000000000 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandler.java +++ /dev/null @@ -1,163 +0,0 @@ -package playground.vsp.pt.fare; - -import com.google.inject.Inject; -import org.apache.commons.math.stat.regression.SimpleRegression; -import org.geotools.api.feature.simple.SimpleFeature; -import org.locationtech.jts.geom.Geometry; -import org.matsim.api.core.v01.Coord; -import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.events.ActivityStartEvent; -import org.matsim.api.core.v01.events.PersonMoneyEvent; -import org.matsim.api.core.v01.events.handler.ActivityStartEventHandler; -import org.matsim.api.core.v01.population.Person; -import org.matsim.application.options.ShpOptions; -import org.matsim.core.api.experimental.events.EventsManager; -import org.matsim.core.router.StageActivityTypeIdentifier; -import org.matsim.core.utils.geometry.CoordUtils; -import org.matsim.core.utils.geometry.geotools.MGC; -import org.matsim.pt.PtConstants; - -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class FareZoneBasedPtFareHandler implements ActivityStartEventHandler { - @Inject - private EventsManager events; - - public static final String FARE = "fare"; - public static final String PT_FARE_ZONE_BASED = "fare zone based pt fare"; - public static final String PT_GERMANWIDE_FARE_BASED = "german-wide fare based pt fare"; - - private final ShpOptions shp; - - private final Map, Coord> personDepartureCoordMap = new HashMap<>(); - private final Map, Coord> personArrivalCoordMap = new HashMap<>(); - - public FareZoneBasedPtFareHandler(DistanceBasedPtFareParams params) { - this.shp = new ShpOptions(params.getFareZoneShp(), null, null); - } - - @Override - public void handleEvent(ActivityStartEvent event) { - - if (event.getActType().equals(PtConstants.TRANSIT_ACTIVITY_TYPE)) { - personDepartureCoordMap.computeIfAbsent(event.getPersonId(), c -> event.getCoord()); // The departure place is fixed to the place of first pt interaction an agent has in the whole leg - personArrivalCoordMap.put(event.getPersonId(), event.getCoord()); // The arrival stop will keep updating until the agent start a real activity (i.e. finish the leg) - } - - if (!StageActivityTypeIdentifier.isStageActivity(event.getActType())) { - Id personId = event.getPersonId(); - if (personDepartureCoordMap.containsKey(personId)) { - double distance = CoordUtils.calcEuclideanDistance - (personDepartureCoordMap.get(personId), personArrivalCoordMap.get(personId)); - - SimpleFeature departureZone = determineFareZone(personDepartureCoordMap.get(personId), shp.readFeatures()); - SimpleFeature arrivalZone = determineFareZone(personArrivalCoordMap.get(personId), shp.readFeatures()); - - Map.Entry fareEntry = computeFare(distance, departureZone, arrivalZone); - // charge fare to the person - events.processEvent( - new PersonMoneyEvent(event.getTime(), event.getPersonId(), -fareEntry.getValue(), - PtFareConfigGroup.PT_FARE, fareEntry.getKey(), event.getPersonId().toString())); - - personDepartureCoordMap.remove(personId); - personArrivalCoordMap.remove(personId); - } - } - } - - public static Map.Entry computeFare(double distance, SimpleFeature departureZone, SimpleFeature arrivalZone) { - - if (departureZone != null && arrivalZone != null) { -// if both zones are not null -> departure and arrival point are inside of one of the tarifzonen - if (departureZone.getID().equals(arrivalZone.getID())) { - return new AbstractMap.SimpleEntry<>(PT_FARE_ZONE_BASED ,(double) departureZone.getAttribute(FARE)); - } - } -// in every other case return german wide fare / Deutschlandtarif - return getGermanWideFare(distance); - } - - private static Map.Entry getGermanWideFare(double distance) { - - SimpleRegression regression = new SimpleRegression(); - -// in Deutschlandtarif, the linear function for the prices above 100km seem to have a different steepness -// hence the following difference in data points -// prices taken from https://deutschlandtarifverbund.de/wp-content/uploads/2024/07/20231201_TBDT_J_10_Preisliste_V07.pdf - if (distance / 1000 <= 100.) { - regression.addData(1, 1.70); - regression.addData(2,1.90); - regression.addData(3,2.00); - regression.addData(4,2.10); - regression.addData(5,2.20); - regression.addData(6,3.20); - regression.addData(7,3.70); - regression.addData(8,3.80); - regression.addData(9,3.90); - regression.addData(10,4.10); - regression.addData(11,5.00); - regression.addData(12,5.40); - regression.addData(13,5.60); - regression.addData(14,5.80); - regression.addData(15,5.90); - regression.addData(16,6.40); - regression.addData(17,6.50); - regression.addData(18,6.60); - regression.addData(19,6.70); - regression.addData(20,6.90); - regression.addData(30,9.90); - regression.addData(40,13.70); - regression.addData(50,16.30); - regression.addData(60,18.10); - regression.addData(70,20.10); - regression.addData(80,23.20); - regression.addData(90,26.20); - regression.addData(100,28.10); - } else { - regression.addData(100,28.10); - regression.addData(200,47.20); - regression.addData(300,59.70); - regression.addData(400,71.70); - regression.addData(500,83.00); - regression.addData(600,94.60); - regression.addData(700,106.30); - regression.addData(800,118.20); - regression.addData(900,130.10); - regression.addData(1000,141.00); - regression.addData(1100,148.60); - regression.addData(1200,158.10); - regression.addData(1300,169.20); - regression.addData(1400,179.80); - regression.addData(1500,190.10); - regression.addData(1600,201.50); - regression.addData(1700,212.80); - regression.addData(1800,223.30); - regression.addData(1900,233.90); - regression.addData(2000,244.00); - } - return new AbstractMap.SimpleEntry<>(PT_GERMANWIDE_FARE_BASED, regression.getSlope() * distance / 1000 + regression.getIntercept()); - } - - static SimpleFeature determineFareZone(Coord coord, List features) { - SimpleFeature zone = null; - - for (SimpleFeature ft : features) { - Geometry geom = (Geometry) ft.getDefaultGeometry(); - - if (MGC.coord2Point(coord).within(geom)) { - zone = ft; - break; - } - } - return zone; - } - - @Override - public void reset(int iteration) { - personArrivalCoordMap.clear(); - personDepartureCoordMap.clear(); - } -} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareParams.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareParams.java new file mode 100644 index 00000000000..d869f18eaa7 --- /dev/null +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareParams.java @@ -0,0 +1,33 @@ +package playground.vsp.pt.fare; + +import java.util.Map; + +public class FareZoneBasedPtFareParams extends PtFareParams { + public static final String SET_NAME = "ptFareCalculationFareZoneBased"; + + public static final String COST = "cost"; + + private Double cost; + + public FareZoneBasedPtFareParams() { + super(SET_NAME); + } + + @Override + public Map getComments() { + Map map = super.getComments(); + map.put(COST, "Cost of a trip within the fare zone."); + return map; + } + + @StringGetter(COST) + public Double getCost() { + return cost; + } + + @StringSetter(COST) + public void setCost(Double cost) { + this.cost = cost; + } + //TODO check consistency +} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareCalculator.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareCalculator.java new file mode 100644 index 00000000000..06fa0af4ca9 --- /dev/null +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareCalculator.java @@ -0,0 +1,12 @@ +package playground.vsp.pt.fare; + +import org.matsim.api.core.v01.Coord; + +import java.util.Optional; + +public interface PtFareCalculator { + Optional calculateFare(Coord from, Coord to); + + record FareResult(Double fare, String transactionPartner) { + } +} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java index 8abf76dcb37..b629bbf9eb5 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java @@ -1,75 +1,60 @@ package playground.vsp.pt.fare; -import org.matsim.core.config.ReflectiveConfigGroup; - import jakarta.validation.constraints.PositiveOrZero; +import org.matsim.core.config.ReflectiveConfigGroup; import java.util.Map; public class PtFareConfigGroup extends ReflectiveConfigGroup { - public static final String PT_FARE = "pt fare"; - public static final String MODULE_NAME = "ptFare"; - public static final String PT_FARE_CALCULATION = "ptFareCalculation"; - public static final String APPLY_UPPER_BOUND = "applyUpperBound"; - public static final String UPPER_BOUND_FACTOR = "upperBoundFactor"; - - public enum PtFareCalculationModels {distanceBased, fareZoneBased} // More to come (e.g. zone based, hybrid...) - - private static final String PT_FARE_CALCULATION_CMT = "PT fare calculation scheme. Current implementation: distanceBased (more to come...)"; - public static final String UPPER_BOUND_FACTOR_CMT = "When upper bound is applied, upperBound = upperBoundFactor * max Fare of the day. " + - "This value is decided by the ratio between average daily cost of a ticket subscription and the single " + - "trip ticket of the same trip. Usually this value should be somewhere between 1.0 and 2.0"; - public static final String APPLY_UPPER_BOUND_CMT = "Enable the upper bound for daily PT fare to count for ticket subscription. Input value: true or false"; - - private PtFareCalculationModels ptFareCalculation = PtFareCalculationModels.distanceBased; // Use distance based calculation by default - private boolean applyUpperBound = true; - @PositiveOrZero - private double upperBoundFactor = 1.5; - - public PtFareConfigGroup() { - super(MODULE_NAME); - } - - @Override - public Map getComments() { - Map map = super.getComments(); - map.put(PT_FARE_CALCULATION, PT_FARE_CALCULATION_CMT ); - map.put(APPLY_UPPER_BOUND, APPLY_UPPER_BOUND_CMT ); - map.put(UPPER_BOUND_FACTOR, UPPER_BOUND_FACTOR_CMT ); - return map; - } - - @StringGetter(PT_FARE_CALCULATION) - public PtFareCalculationModels getPtFareCalculation() { - return ptFareCalculation; - } - - @StringSetter(PT_FARE_CALCULATION) - public void setPtFareCalculationModel(PtFareCalculationModels ptFareCalculation) { - this.ptFareCalculation = ptFareCalculation; - } - - @StringGetter(APPLY_UPPER_BOUND) - public boolean getApplyUpperBound() { - return applyUpperBound; - } - - @StringSetter(APPLY_UPPER_BOUND) - public void setApplyUpperBound(boolean applyUpperBound) { - this.applyUpperBound = applyUpperBound; - } - - - @StringGetter(UPPER_BOUND_FACTOR) - public double getUpperBoundFactor() { - return upperBoundFactor; - } - - /** - * @param upperBoundFactor -- {@value #UPPER_BOUND_FACTOR_CMT} - */ - @StringSetter(UPPER_BOUND_FACTOR) - public void setUpperBoundFactor(double upperBoundFactor) { - this.upperBoundFactor = upperBoundFactor; - } + public static final String PT_FARE = "pt fare"; + public static final String MODULE_NAME = "ptFare"; + public static final String APPLY_UPPER_BOUND = "applyUpperBound"; + public static final String UPPER_BOUND_FACTOR = "upperBoundFactor"; + + public static final String UPPER_BOUND_FACTOR_CMT = "When upper bound is applied, upperBound = upperBoundFactor * max Fare of the day. " + + "This value is decided by the ratio between average daily cost of a ticket subscription and the single " + + "trip ticket of the same trip. Usually this value should be somewhere between 1.0 and 2.0"; + public static final String APPLY_UPPER_BOUND_CMT = "Enable the upper bound for daily PT fare to count for ticket subscription. Input value: " + + "true" + + " or false"; + + private boolean applyUpperBound = true; + @PositiveOrZero + private double upperBoundFactor = 1.5; + + public PtFareConfigGroup() { + super(MODULE_NAME); + } + + @Override + public Map getComments() { + Map map = super.getComments(); + map.put(APPLY_UPPER_BOUND, APPLY_UPPER_BOUND_CMT); + map.put(UPPER_BOUND_FACTOR, UPPER_BOUND_FACTOR_CMT); + return map; + } + + @StringGetter(APPLY_UPPER_BOUND) + public boolean getApplyUpperBound() { + return applyUpperBound; + } + + @StringSetter(APPLY_UPPER_BOUND) + public void setApplyUpperBound(boolean applyUpperBound) { + this.applyUpperBound = applyUpperBound; + } + + + @StringGetter(UPPER_BOUND_FACTOR) + public double getUpperBoundFactor() { + return upperBoundFactor; + } + + /** + * @param upperBoundFactor -- {@value #UPPER_BOUND_FACTOR_CMT} + */ + @StringSetter(UPPER_BOUND_FACTOR) + public void setUpperBoundFactor(double upperBoundFactor) { + this.upperBoundFactor = upperBoundFactor; + } } diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareHandler.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareHandler.java new file mode 100644 index 00000000000..d911486a0e2 --- /dev/null +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareHandler.java @@ -0,0 +1,8 @@ +package playground.vsp.pt.fare; + +import org.matsim.api.core.v01.events.handler.ActivityStartEventHandler; +import org.matsim.core.api.experimental.events.handler.AgentWaitingForPtEventHandler; + +public interface PtFareHandler extends ActivityStartEventHandler, AgentWaitingForPtEventHandler { + //other methods for informed mode choice +} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java index 4da41c16612..9c0ee97efc2 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java @@ -1,31 +1,50 @@ package playground.vsp.pt.fare; +import com.google.inject.multibindings.Multibinder; import org.matsim.api.core.v01.TransportMode; +import org.matsim.core.config.ConfigGroup; import org.matsim.core.config.ConfigUtils; import org.matsim.core.controler.AbstractModule; +import java.util.Collection; +import java.util.Comparator; +import java.util.stream.Stream; + public class PtFareModule extends AbstractModule { - @Override - public void install() { - getConfig().scoring().getModes().get(TransportMode.pt).setDailyMonetaryConstant(0); - getConfig().scoring().getModes().get(TransportMode.pt).setMarginalUtilityOfDistance(0); - PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(this.getConfig(), PtFareConfigGroup.class); - DistanceBasedPtFareParams distanceBasedPtFareParams = ConfigUtils.addOrGetModule(this.getConfig(), DistanceBasedPtFareParams.class); - - if (ptFareConfigGroup.getPtFareCalculation() == PtFareConfigGroup.PtFareCalculationModels.distanceBased) { - addEventHandlerBinding().toInstance(new DistanceBasedPtFareHandler(distanceBasedPtFareParams)); - } else if (ptFareConfigGroup.getPtFareCalculation() == PtFareConfigGroup.PtFareCalculationModels.fareZoneBased) { - addEventHandlerBinding().toInstance(new FareZoneBasedPtFareHandler(distanceBasedPtFareParams)); - } else { - throw new RuntimeException("Please choose from the following fare Calculation method: [" + - PtFareConfigGroup.PtFareCalculationModels.distanceBased + ", " + PtFareConfigGroup.PtFareCalculationModels.fareZoneBased + "]"); - } - - if (ptFareConfigGroup.getApplyUpperBound()) { - PtFareUpperBoundHandler ptFareUpperBoundHandler = new PtFareUpperBoundHandler(ptFareConfigGroup.getUpperBoundFactor()); - addEventHandlerBinding().toInstance(ptFareUpperBoundHandler); - addControlerListenerBinding().toInstance(ptFareUpperBoundHandler); - } - } + @Override + public void install() { + //TODO check consistency: order unique, cost set + + getConfig().scoring().getModes().get(TransportMode.pt).setDailyMonetaryConstant(0); + getConfig().scoring().getModes().get(TransportMode.pt).setMarginalUtilityOfDistance(0); + Multibinder ptFareCalculator = Multibinder.newSetBinder(binder(), PtFareCalculator.class); + + PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(this.getConfig(), PtFareConfigGroup.class); + Collection fareZoneBased = ptFareConfigGroup.getParameterSets(FareZoneBasedPtFareParams.SET_NAME); + Collection distanceBased = ptFareConfigGroup.getParameterSets(DistanceBasedPtFareParams.SET_NAME); + + Stream.concat(fareZoneBased.stream(), distanceBased.stream()) + .map(c -> (PtFareParams) c) + .sorted(Comparator.comparing(PtFareParams::getPriority).reversed()) + .forEach(p -> { + if (p instanceof FareZoneBasedPtFareParams fareZoneBasedPtFareParams) { + ptFareCalculator.addBinding().toInstance(new FareZoneBasedPtFareCalculator(fareZoneBasedPtFareParams)); + } else if (p instanceof DistanceBasedPtFareParams distanceBasedPtFareParams) { + ptFareCalculator.addBinding().toInstance(new DistanceBasedPtFareCalculator(distanceBasedPtFareParams)); + } else { + throw new RuntimeException("Unknown PtFareParams: " + p.getClass()); + } + }); + + bind(ChainedPtFareCalculator.class); + bind(PtFareHandler.class).to(ChainedPtFareHandler.class); + addEventHandlerBinding().to(PtFareHandler.class); + + if (ptFareConfigGroup.getApplyUpperBound()) { + PtFareUpperBoundHandler ptFareUpperBoundHandler = new PtFareUpperBoundHandler(ptFareConfigGroup.getUpperBoundFactor()); + addEventHandlerBinding().toInstance(ptFareUpperBoundHandler); + addControlerListenerBinding().toInstance(ptFareUpperBoundHandler); + } + } } diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareParams.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareParams.java new file mode 100644 index 00000000000..ece2641d9ad --- /dev/null +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareParams.java @@ -0,0 +1,71 @@ +package playground.vsp.pt.fare; + +import org.matsim.core.config.ReflectiveConfigGroup; + +import java.util.Map; + +public abstract class PtFareParams extends ReflectiveConfigGroup { + public static final String FARE_ZONE_SHP = "fareZoneShp"; + public static final String PRIORITY = "priority"; + public static final String TRANSACTION_PARTNER = "transactionPartner"; + public static final String DESCRIPTION = "description"; + + private int priority; + private String fareZoneShp; + private String transactionPartner; + private String description; + + public PtFareParams(String name) { + super(name); + } + + @Override + public Map getComments() { + var map = super.getComments(); + map.put(FARE_ZONE_SHP, "Shp file with fare zone(s). This parameter is only used for PtFareCalculationModel 'fareZoneBased'."); + map.put(PRIORITY, "Priority of this fare calculation in the list of fare calculations. Higher values mean to be evaluated first."); + map.put(TRANSACTION_PARTNER, "The transaction partner for the fare calculation. This is used in the PersonMoneyEvent."); + map.put(DESCRIPTION, "Description of the fare zone."); + return map; + } + + @StringGetter(FARE_ZONE_SHP) + public String getFareZoneShp() { + return fareZoneShp; + } + + @StringSetter(FARE_ZONE_SHP) + public void setFareZoneShp(String fareZoneShp) { + this.fareZoneShp = fareZoneShp; + } + + @StringGetter(PRIORITY) + public int getPriority() { + return priority; + } + + @StringSetter(PRIORITY) + public void setPriority(int priority) { + this.priority = priority; + } + + @StringGetter(TRANSACTION_PARTNER) + public String getTransactionPartner() { + return transactionPartner; + } + + @StringSetter(TRANSACTION_PARTNER) + public void setTransactionPartner(String transactionPartner) { + this.transactionPartner = transactionPartner; + } + + @StringGetter(DESCRIPTION) + public String getDescription() { + return description; + } + + @StringSetter(DESCRIPTION) + public void setDescription(String description) { + this.description = description; + } +} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java index 5af45c407fe..5795934440e 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java @@ -29,7 +29,8 @@ public class PtTripWithDistanceBasedFareEstimator extends PtTripEstimator { private final Map, TransitStopFacility> facilities; @Inject - public PtTripWithDistanceBasedFareEstimator(TransitSchedule transitSchedule, PtFareConfigGroup config, DistanceBasedPtFareParams ptFare, Scenario scenario) { + public PtTripWithDistanceBasedFareEstimator(TransitSchedule transitSchedule, PtFareConfigGroup config, DistanceBasedPtFareParams ptFare, + Scenario scenario) { super(transitSchedule); this.config = config; this.ptFare = ptFare; @@ -55,8 +56,9 @@ public MinMaxEstimate estimate(EstimatorContext context, String mode, PlanModel maxFareUtility = Math.max(fareUtility, maxFareUtility); max = estimate + maxFareUtility; - } else + } else { max = estimate + fareUtility; + } // Distance fareUtility is the highest possible price, therefore the minimum utility return MinMaxEstimate.of(estimate + fareUtility, max); @@ -78,8 +80,9 @@ public double estimate(EstimatorContext context, String mode, String[] modes, Pl List legs = plan.getLegs(mode, i); // Legs can be null if there is a predefined pt trip - if (legs == null) + if (legs == null) { continue; + } //assert legs != null : "Legs must be not null at this point"; @@ -121,8 +124,9 @@ private DoubleDoublePair estimateTrip(EstimatorContext context, List trip) TransitPassengerRoute route = (TransitPassengerRoute) leg.getRoute(); - if (access == null) + if (access == null) { access = facilities.get(route.getAccessStopId()); + } egress = facilities.get(route.getEgressStopId()); @@ -139,8 +143,9 @@ private DoubleDoublePair estimateTrip(EstimatorContext context, List trip) double dist = CoordUtils.calcEuclideanDistance(access.getCoord(), egress.getCoord()); - double fareUtility = -context.scoring.marginalUtilityOfMoney * DistanceBasedPtFareHandler.computeFare(dist, ptFare.getLongDistanceTripThreshold(), ptFare.getMinFare(), - ptFare.getNormalTripIntercept(), ptFare.getNormalTripSlope(), ptFare.getLongDistanceTripIntercept(), ptFare.getLongDistanceTripSlope()); + double fareUtility = -context.scoring.marginalUtilityOfMoney * DistanceBasedPtFareCalculator.computeFare(dist, + ptFare.getLongDistanceTripThreshold(), ptFare.getMinFare(), ptFare.getNormalTripIntercept(), ptFare.getNormalTripSlope(), + ptFare.getLongDistanceTripIntercept(), ptFare.getLongDistanceTripSlope()); estimate += context.scoring.marginalUtilityOfWaitingPt_s * totalWaitingTime; @@ -165,8 +170,9 @@ private double calcMinimumFare(PlanModel plan) { List legs = plan.getLegs(TransportMode.pt, i); - if (legs == null) + if (legs == null) { continue; + } // first access and last egress TransitStopFacility access = null; @@ -183,8 +189,9 @@ private double calcMinimumFare(PlanModel plan) { TransitPassengerRoute route = (TransitPassengerRoute) leg.getRoute(); hasPT = true; - if (access == null) + if (access == null) { access = facilities.get(route.getAccessStopId()); + } egress = facilities.get(route.getEgressStopId()); } @@ -206,15 +213,17 @@ private double calcMinimumFare(PlanModel plan) { // a single pt trip could never benefit from the upper bound if (n == 1) { - return DistanceBasedPtFareHandler.computeFare(minDist, ptFare.getLongDistanceTripThreshold(), ptFare.getMinFare(), - ptFare.getNormalTripIntercept(), ptFare.getNormalTripSlope(), ptFare.getLongDistanceTripIntercept(), ptFare.getLongDistanceTripSlope()); + return DistanceBasedPtFareCalculator.computeFare(minDist, ptFare.getLongDistanceTripThreshold(), ptFare.getMinFare(), + ptFare.getNormalTripIntercept(), ptFare.getNormalTripSlope(), ptFare.getLongDistanceTripIntercept(), + ptFare.getLongDistanceTripSlope()); } // the upper bound is the maximum single trip times a factor // therefore the minimum upper bound is the fare for the second-longest trip // the max costs are then assumed to be evenly distributed over all pt trips - return 1d / n * config.getUpperBoundFactor() * DistanceBasedPtFareHandler.computeFare(secondMinDist, ptFare.getLongDistanceTripThreshold(), ptFare.getMinFare(), - ptFare.getNormalTripIntercept(), ptFare.getNormalTripSlope(), ptFare.getLongDistanceTripIntercept(), ptFare.getLongDistanceTripSlope()); + return 1d / n * config.getUpperBoundFactor() * DistanceBasedPtFareCalculator.computeFare(secondMinDist, + ptFare.getLongDistanceTripThreshold(), ptFare.getMinFare(), ptFare.getNormalTripIntercept(), ptFare.getNormalTripSlope(), + ptFare.getLongDistanceTripIntercept(), ptFare.getLongDistanceTripSlope()); } @Override diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java b/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java index ec486ec2cee..a894bb44141 100644 --- a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java +++ b/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java @@ -37,6 +37,8 @@ public class FareZoneBasedPtFareHandlerTest { @Test void testFareZoneBasedPtFareHandler() { + final String FARE_ZONE_TRANSACTION_PARTNER = "fare zone transaction partner"; + final String DISTANCE_BASED_TRANSACTION_PARTNER = "distance based transaction partner"; URL context = ExamplesUtils.getTestScenarioURL("kelheim"); Config config = ConfigUtils.loadConfig(IOUtils.extendUrl(context, "config.xml")); @@ -45,11 +47,20 @@ void testFareZoneBasedPtFareHandler() { config.controller().setLastIteration(0); PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(config, PtFareConfigGroup.class); - ptFareConfigGroup.setPtFareCalculationModel(PtFareConfigGroup.PtFareCalculationModels.fareZoneBased); - DistanceBasedPtFareParams fareParams = ConfigUtils.addOrGetModule(config, DistanceBasedPtFareParams.class); - fareParams.setFareZoneShp(IOUtils.extendUrl(context, "ptTestArea/pt-area.shp").toString()); + FareZoneBasedPtFareParams fareZoneBased = new FareZoneBasedPtFareParams(); + fareZoneBased.setCost(2.5); + fareZoneBased.setDescription("simple fare zone based"); + fareZoneBased.setFareZoneShp(IOUtils.extendUrl(context, "ptTestArea/pt-area.shp").toString()); + fareZoneBased.setPriority(10); + fareZoneBased.setTransactionPartner(FARE_ZONE_TRANSACTION_PARTNER); + DistanceBasedPtFareParams distanceBased = new DistanceBasedPtFareParams(); + distanceBased.setPriority(5); + distanceBased.setTransactionPartner(DISTANCE_BASED_TRANSACTION_PARTNER); + + ptFareConfigGroup.addParameterSet(fareZoneBased); + ptFareConfigGroup.addParameterSet(distanceBased); ScoringConfigGroup scoring = ConfigUtils.addOrGetModule(config, ScoringConfigGroup.class); @@ -69,13 +80,13 @@ void testFareZoneBasedPtFareHandler() { Person person = fac.createPerson(Id.createPersonId("fareTestPerson")); Plan plan = fac.createPlan(); - Activity home = fac.createActivityFromCoord("home", new Coord(710300.624,5422165.737)); + Activity home = fac.createActivityFromCoord("home", new Coord(710300.624, 5422165.737)); // bus to Saal (Donau) work location departs at 09:14 home.setEndTime(9 * 3600.); - Activity work = fac.createActivityFromCoord("work", new Coord(714940.65,5420707.78)); + Activity work = fac.createActivityFromCoord("work", new Coord(714940.65, 5420707.78)); // rb17 to regensburg 2nd home location departs at 13:59 work.setEndTime(13 * 3600. + 45 * 60); - Activity home2 = fac.createActivityFromCoord("home", new Coord(726634.40,5433508.07)); + Activity home2 = fac.createActivityFromCoord("home", new Coord(726634.40, 5433508.07)); Leg leg = fac.createLeg(TransportMode.pt); @@ -118,7 +129,7 @@ public void install() { } Assertions.assertEquals(2, events.size()); - Assertions.assertEquals(FareZoneBasedPtFareHandler.PT_FARE_ZONE_BASED, events.get(0)[4]); - Assertions.assertEquals(FareZoneBasedPtFareHandler.PT_GERMANWIDE_FARE_BASED, events.get(1)[4]); + Assertions.assertEquals(FARE_ZONE_TRANSACTION_PARTNER, events.get(0)[4]); + Assertions.assertEquals(DISTANCE_BASED_TRANSACTION_PARTNER, events.get(1)[4]); } } From 6b15b10bf22f966f80f00fdfcc02c3b67ce8d906 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Fri, 16 Aug 2024 13:55:38 +0200 Subject: [PATCH 205/213] implemented tests --- .../vsp/pt/fare/ChainedPtFareCalculator.java | 5 ++ .../fare/DistanceBasedPtFareCalculator.java | 29 +++++-- .../pt/fare/DistanceBasedPtFareParams.java | 78 ++++++++++++++++++- .../fare/FareZoneBasedPtFareCalculator.java | 15 ++-- .../pt/fare/FareZoneBasedPtFareParams.java | 24 ------ .../vsp/pt/fare/PtFareConfigGroup.java | 23 ++++++ .../playground/vsp/pt/fare/PtFareModule.java | 2 - .../PtTripWithDistanceBasedFareEstimator.java | 12 ++- .../DistanceBasedPtFareCalculatorTest.java | 76 ++++++++++++++++++ .../FareZoneBasedPtFareCalculatorTest.java | 57 ++++++++++++++ .../fare/FareZoneBasedPtFareHandlerTest.java | 1 - .../vsp/pt/fare/PtFareConfigGroupTest.java | 45 +++++++++++ .../vsp/pt/fare/PtTripFareEstimatorTest.java | 29 +++---- 13 files changed, 338 insertions(+), 58 deletions(-) create mode 100644 contribs/vsp/src/test/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculatorTest.java create mode 100644 contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculatorTest.java create mode 100644 contribs/vsp/src/test/java/playground/vsp/pt/fare/PtFareConfigGroupTest.java diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareCalculator.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareCalculator.java index a1156d01740..bd38fc3237b 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareCalculator.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareCalculator.java @@ -6,6 +6,11 @@ import java.util.Optional; import java.util.Set; +/** + * This class is a {@link PtFareCalculator} that chains multiple {@link PtFareCalculator}s together. As soon as one of the chained calculators + * returns a fare, this calculator returns that fare. In {@link PtFareModule} all available {@link PtFareCalculator}s are bound to this class. The + * order in which the calculators are bound is determined by the priority of the {@link PtFareParams} they are created from. + */ public class ChainedPtFareCalculator implements PtFareCalculator { @Inject private Set fareCalculators; diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculator.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculator.java index cc3de24235c..3708bf7acce 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculator.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculator.java @@ -1,16 +1,25 @@ package playground.vsp.pt.fare; -import org.geotools.api.feature.simple.SimpleFeature; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.locationtech.jts.geom.Geometry; import org.matsim.api.core.v01.Coord; import org.matsim.application.options.ShpOptions; import org.matsim.core.utils.geometry.CoordUtils; import org.matsim.core.utils.geometry.geotools.MGC; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; +/** + * This class calculates the fare for a public transport trip based on the distance between the origin and destination. If a shape file is + * provided, the + * fare will be calculated only if the trip is within the shape. + */ public class DistanceBasedPtFareCalculator implements PtFareCalculator { + private static final Logger log = LogManager.getLogger(DistanceBasedPtFareCalculator.class); + private final double minFare; private final double shortTripIntercept; private final double shortTripSlope; @@ -20,6 +29,8 @@ public class DistanceBasedPtFareCalculator implements PtFareCalculator { private ShpOptions shp = null; private final String transactionPartner; + private final Map inShapeCache = new HashMap<>(); + public DistanceBasedPtFareCalculator(DistanceBasedPtFareParams params) { this.minFare = params.getMinFare(); this.shortTripIntercept = params.getNormalTripIntercept(); @@ -30,7 +41,12 @@ public DistanceBasedPtFareCalculator(DistanceBasedPtFareParams params) { this.transactionPartner = params.getTransactionPartner(); if (params.getFareZoneShp() != null) { + log.info("For DistanceBasedPtFareCalculator '{}' a fare zone shape file was provided. During the computation, the fare will be " + + "calculated only if the trip is within the shape.", params.getDescription()); this.shp = new ShpOptions(params.getFareZoneShp(), null, null); + } else { + log.info("For DistanceBasedPtFareCalculator '{}' no fare zone shape file was provided. The fare will be calculated for all trips.", + params.getDescription()); } } @@ -50,12 +66,11 @@ private boolean shapeCheck(Coord from, Coord to) { if (shp == null) { return true; } - - return inShape(from, shp.readFeatures()) && inShape(to, shp.readFeatures()); + return inShapeCache.computeIfAbsent(from, this::inShape) && inShapeCache.computeIfAbsent(to, this::inShape); } - boolean inShape(Coord coord, List features) { - return features.stream().anyMatch(f -> MGC.coord2Point(coord).within((Geometry) f.getDefaultGeometry())); + private boolean inShape(Coord coord) { + return shp.readFeatures().stream().anyMatch(f -> MGC.coord2Point(coord).within((Geometry) f.getDefaultGeometry())); } public static double computeFare(double distance, double longTripThreshold, double minFare, double shortTripIntercept, double shortTripSlope, @@ -66,6 +81,4 @@ public static double computeFare(double distance, double longTripThreshold, doub return Math.max(minFare, longTripIntercept + longTripSlope * distance); } } - - } diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java index cc393f92175..605a266e131 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java @@ -1,6 +1,7 @@ package playground.vsp.pt.fare; import jakarta.validation.constraints.PositiveOrZero; +import org.apache.commons.math.stat.regression.SimpleRegression; import java.util.Map; @@ -11,6 +12,8 @@ * The values are based on the standard unit of meter (m) and Euro (EUR) */ public class DistanceBasedPtFareParams extends PtFareParams { + public static final DistanceBasedPtFareParams GERMAN_WIDE_FARE = germanWideFare(); + public static final String SET_NAME = "ptFareCalculationDistanceBased"; public static final String MIN_FARE = "minFare"; public static final String NORMAL_TRIP_SLOPE = "normalTripSlope"; @@ -39,9 +42,8 @@ public DistanceBasedPtFareParams() { @Override public Map getComments() { Map map = super.getComments(); - map.put(MIN_FARE, "Minimum fare for a PT trip (e.g. Kurzstrecke/short distance ticket in cities, ticket for 1 zone in rural areas). Default" + - " " + - "is 2.0EUR."); + map.put(MIN_FARE, "Minimum fare for a PT trip (e.g. Kurzstrecke/short distance ticket in cities, ticket for 1 zone in rural areas). " + + "Default is 2.0EUR."); map.put(NORMAL_TRIP_SLOPE, "Linear model y = ax + b: the value of a, for normal trips (e.g. within the city or region). Default is 0.00017" + "EUR."); map.put(NORMAL_TRIP_INTERCEPT, "Linear model y = ax + b: the value of b, for normal trips. Default is 1.6EUR."); @@ -112,4 +114,74 @@ public double getLongDistanceTripThreshold() { public void setLongDistanceTripThreshold(double longDistanceTripThreshold) { this.longDistanceTripThreshold = longDistanceTripThreshold; } + + // in Deutschlandtarif, the linear function for the prices above 100km seem to have a different steepness + // hence the following difference in data points + // prices taken from https://deutschlandtarifverbund.de/wp-content/uploads/2024/07/20231201_TBDT_J_10_Preisliste_V07.pdf + private static DistanceBasedPtFareParams germanWideFare() { + final double MIN_FARE = 1.70; + + SimpleRegression normalDistanceTrip = new SimpleRegression(); + normalDistanceTrip.addData(1, MIN_FARE); + normalDistanceTrip.addData(2, 1.90); + normalDistanceTrip.addData(3, 2.00); + normalDistanceTrip.addData(4, 2.10); + normalDistanceTrip.addData(5, 2.20); + normalDistanceTrip.addData(6, 3.20); + normalDistanceTrip.addData(7, 3.70); + normalDistanceTrip.addData(8, 3.80); + normalDistanceTrip.addData(9, 3.90); + normalDistanceTrip.addData(10, 4.10); + normalDistanceTrip.addData(11, 5.00); + normalDistanceTrip.addData(12, 5.40); + normalDistanceTrip.addData(13, 5.60); + normalDistanceTrip.addData(14, 5.80); + normalDistanceTrip.addData(15, 5.90); + normalDistanceTrip.addData(16, 6.40); + normalDistanceTrip.addData(17, 6.50); + normalDistanceTrip.addData(18, 6.60); + normalDistanceTrip.addData(19, 6.70); + normalDistanceTrip.addData(20, 6.90); + normalDistanceTrip.addData(30, 9.90); + normalDistanceTrip.addData(40, 13.70); + normalDistanceTrip.addData(50, 16.30); + normalDistanceTrip.addData(60, 18.10); + normalDistanceTrip.addData(70, 20.10); + normalDistanceTrip.addData(80, 23.20); + normalDistanceTrip.addData(90, 26.20); + normalDistanceTrip.addData(100, 28.10); + + SimpleRegression longDistanceTrip = new SimpleRegression(); + longDistanceTrip.addData(100, 28.10); + longDistanceTrip.addData(200, 47.20); + longDistanceTrip.addData(300, 59.70); + longDistanceTrip.addData(400, 71.70); + longDistanceTrip.addData(500, 83.00); + longDistanceTrip.addData(600, 94.60); + longDistanceTrip.addData(700, 106.30); + longDistanceTrip.addData(800, 118.20); + longDistanceTrip.addData(900, 130.10); + longDistanceTrip.addData(1000, 141.00); + longDistanceTrip.addData(1100, 148.60); + longDistanceTrip.addData(1200, 158.10); + longDistanceTrip.addData(1300, 169.20); + longDistanceTrip.addData(1400, 179.80); + longDistanceTrip.addData(1500, 190.10); + longDistanceTrip.addData(1600, 201.50); + longDistanceTrip.addData(1700, 212.80); + longDistanceTrip.addData(1800, 223.30); + longDistanceTrip.addData(1900, 233.90); + longDistanceTrip.addData(2000, 244.00); + + var params = new DistanceBasedPtFareParams(); + params.setNormalTripSlope(normalDistanceTrip.getSlope()); + params.setNormalTripIntercept(normalDistanceTrip.getIntercept()); + params.setLongDistanceTripSlope(longDistanceTrip.getSlope()); + params.setLongDistanceTripIntercept(longDistanceTrip.getIntercept()); + params.setLongDistanceTripThreshold(100_000.); + params.setTransactionPartner("Deutschlandtarif"); + params.setMinFare(MIN_FARE); + + return params; + } } diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculator.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculator.java index feda2b3a950..a676137b487 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculator.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculator.java @@ -6,12 +6,17 @@ import org.matsim.application.options.ShpOptions; import org.matsim.core.utils.geometry.geotools.MGC; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; +/** + * This class calculates the fare for a public transport trip based on the fare zone the origin and destination are in. + */ public class FareZoneBasedPtFareCalculator implements PtFareCalculator { private final ShpOptions shp; private final String transactionPartner; + private final Map> zoneByCoordCache = new HashMap<>(); public static final String FARE = "fare"; @@ -22,8 +27,8 @@ public FareZoneBasedPtFareCalculator(FareZoneBasedPtFareParams params) { @Override public Optional calculateFare(Coord from, Coord to) { - Optional departureZone = determineFareZone(from, shp.readFeatures()); - Optional arrivalZone = determineFareZone(to, shp.readFeatures()); + Optional departureZone = zoneByCoordCache.computeIfAbsent(from, this::determineFareZone); + Optional arrivalZone = zoneByCoordCache.computeIfAbsent(to, this::determineFareZone); //if one of the zones is empty, it is not included in the shape file, so this calculator cannot compute the fare if (departureZone.isEmpty() || arrivalZone.isEmpty()) { @@ -38,7 +43,7 @@ public Optional calculateFare(Coord from, Coord to) { return Optional.of(new FareResult(fare, transactionPartner)); } - Optional determineFareZone(Coord coord, List features) { - return features.stream().filter(f -> MGC.coord2Point(coord).within((Geometry) f.getDefaultGeometry())).findFirst(); + Optional determineFareZone(Coord coord) { + return shp.readFeatures().stream().filter(f -> MGC.coord2Point(coord).within((Geometry) f.getDefaultGeometry())).findFirst(); } } diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareParams.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareParams.java index d869f18eaa7..f213f32dbb0 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareParams.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareParams.java @@ -1,33 +1,9 @@ package playground.vsp.pt.fare; -import java.util.Map; - public class FareZoneBasedPtFareParams extends PtFareParams { public static final String SET_NAME = "ptFareCalculationFareZoneBased"; - public static final String COST = "cost"; - - private Double cost; - public FareZoneBasedPtFareParams() { super(SET_NAME); } - - @Override - public Map getComments() { - Map map = super.getComments(); - map.put(COST, "Cost of a trip within the fare zone."); - return map; - } - - @StringGetter(COST) - public Double getCost() { - return cost; - } - - @StringSetter(COST) - public void setCost(Double cost) { - this.cost = cost; - } - //TODO check consistency } diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java index b629bbf9eb5..1093e607db3 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java @@ -1,9 +1,11 @@ package playground.vsp.pt.fare; import jakarta.validation.constraints.PositiveOrZero; +import org.matsim.core.config.Config; import org.matsim.core.config.ReflectiveConfigGroup; import java.util.Map; +import java.util.stream.Stream; public class PtFareConfigGroup extends ReflectiveConfigGroup { public static final String PT_FARE = "pt fare"; @@ -57,4 +59,25 @@ public double getUpperBoundFactor() { public void setUpperBoundFactor(double upperBoundFactor) { this.upperBoundFactor = upperBoundFactor; } + + @Override + protected void checkConsistency(Config config) { + super.checkConsistency(config); + + var distanceBasedParameterSets = getParameterSets(DistanceBasedPtFareParams.SET_NAME); + var fareZoneBasedParameterSets = getParameterSets(FareZoneBasedPtFareParams.SET_NAME); + + if (distanceBasedParameterSets.isEmpty() && fareZoneBasedParameterSets.isEmpty()) { + throw new IllegalArgumentException("No parameter sets found for pt fare calculation. Please add at least one parameter set."); + } + + long distinctPriorities = Stream.concat(distanceBasedParameterSets.stream(), fareZoneBasedParameterSets.stream()) + .map(PtFareParams.class::cast) + .map(PtFareParams::getPriority) + .distinct().count(); + + if (distinctPriorities != distanceBasedParameterSets.size() + fareZoneBasedParameterSets.size()) { + throw new IllegalArgumentException("Duplicate priorities found in parameter sets. Please make sure that priorities are unique."); + } + } } diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java index 9c0ee97efc2..7974d9b0516 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java @@ -14,8 +14,6 @@ public class PtFareModule extends AbstractModule { @Override public void install() { - //TODO check consistency: order unique, cost set - getConfig().scoring().getModes().get(TransportMode.pt).setDailyMonetaryConstant(0); getConfig().scoring().getModes().get(TransportMode.pt).setMarginalUtilityOfDistance(0); Multibinder ptFareCalculator = Multibinder.newSetBinder(binder(), PtFareCalculator.class); diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java index 5795934440e..90ec2339fa4 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java @@ -29,14 +29,22 @@ public class PtTripWithDistanceBasedFareEstimator extends PtTripEstimator { private final Map, TransitStopFacility> facilities; @Inject - public PtTripWithDistanceBasedFareEstimator(TransitSchedule transitSchedule, PtFareConfigGroup config, DistanceBasedPtFareParams ptFare, + public PtTripWithDistanceBasedFareEstimator(TransitSchedule transitSchedule, PtFareConfigGroup config, Scenario scenario) { super(transitSchedule); this.config = config; - this.ptFare = ptFare; + this.ptFare = extractPtFare(config); this.facilities = scenario.getTransitSchedule().getFacilities(); } + private static DistanceBasedPtFareParams extractPtFare(PtFareConfigGroup config) { + //TODO + return config.getParameterSets(DistanceBasedPtFareParams.SET_NAME).stream() + .map(DistanceBasedPtFareParams.class::cast) + .findFirst() + .orElseThrow(() -> new IllegalStateException("No distance based fare parameters found")); + } + @Override public MinMaxEstimate estimate(EstimatorContext context, String mode, PlanModel plan, List trip, ModeAvailability option) { diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculatorTest.java b/contribs/vsp/src/test/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculatorTest.java new file mode 100644 index 00000000000..005b7f3f80d --- /dev/null +++ b/contribs/vsp/src/test/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculatorTest.java @@ -0,0 +1,76 @@ +package playground.vsp.pt.fare; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Coord; +import org.matsim.core.utils.geometry.CoordUtils; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; + +import java.net.URL; +import java.util.Optional; + +class DistanceBasedPtFareCalculatorTest { + private static final String TRANSACTION_PARTNER = "TP"; + + @Test + void testNormalDistance() { + //100m -> 1.1 EUR + calculateAndCheck(null, new Coord(0, 0), new Coord(0, 100), 1.1); + } + + @Test + void testLongDistance() { + //3000m -> 4.5 EUR + calculateAndCheck(null, new Coord(0, 0), new Coord(0, 3000), 4.5); + } + + @Test + void testThreshold() { + //2000m -> 3.0 EUR + calculateAndCheck(null, new Coord(0, 0), new Coord(0, 2000), 3.0); + } + + @Test + void testNotInShapeFile() { + URL context = ExamplesUtils.getTestScenarioURL("kelheim"); + String shape = IOUtils.extendUrl(context, "ptTestArea/pt-area.shp").toString(); + Coord a = new Coord(726634.40, 5433508.07); + Coord b = new Coord(736634.40, 5533508.07); + DistanceBasedPtFareCalculator calculator = getCalculator(shape); + Assertions.assertEquals(Optional.empty(), calculator.calculateFare(a, b)); + } + + @Test + void testInShapeFile() { + URL context = ExamplesUtils.getTestScenarioURL("kelheim"); + String shape = IOUtils.extendUrl(context, "ptTestArea/pt-area.shp").toString(); + Coord a = new Coord(710300.624, 5422165.737); + Coord b = new Coord(714940.65, 5420707.78); + double distance = CoordUtils.calcEuclideanDistance(a, b); + calculateAndCheck(shape, a, b, distance * 0.0005 + 3.); + } + + private void calculateAndCheck(String shape, Coord a, Coord b, double fare) { + DistanceBasedPtFareCalculator distanceBasedPtFareCalculator = getCalculator(shape); + PtFareCalculator.FareResult fareResult = distanceBasedPtFareCalculator.calculateFare(a, b).orElseThrow(); + Assertions.assertEquals(new PtFareCalculator.FareResult(fare, TRANSACTION_PARTNER), fareResult); + } + + private DistanceBasedPtFareCalculator getCalculator(String shapeFile) { + var params = new DistanceBasedPtFareParams(); + params.setTransactionPartner(TRANSACTION_PARTNER); + //0-2000m: 1EUR + 1EUR/km + params.setNormalTripIntercept(1.0); + params.setNormalTripSlope(0.001); + + //2000m+: 3EUR + 0.5EUR/km + params.setLongDistanceTripThreshold(2000.); + params.setLongDistanceTripIntercept(3.); + params.setLongDistanceTripSlope(0.0005); + + params.setMinFare(1.0); + params.setFareZoneShp(shapeFile); + return new DistanceBasedPtFareCalculator(params); + } +} diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculatorTest.java b/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculatorTest.java new file mode 100644 index 00000000000..ac3eda11b5a --- /dev/null +++ b/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculatorTest.java @@ -0,0 +1,57 @@ +package playground.vsp.pt.fare; + +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Coord; +import org.matsim.core.utils.io.IOUtils; +import org.matsim.examples.ExamplesUtils; + +import java.net.URL; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class FareZoneBasedPtFareCalculatorTest { + private static final double COST_IN_SHP_FILE = 1.5; + private static final String TRANSACTION_PARTNER = "TP"; + + @Test + void testCalculateFareInShape() { + FareZoneBasedPtFareCalculator fareZoneBasedPtFareCalculator = new FareZoneBasedPtFareCalculator(getParams()); + + Coord inShape = new Coord(710300.624, 5422165.737); + Coord inShape2 = new Coord(714940.65, 5420707.78); + + assertEquals(Optional.of(new PtFareCalculator.FareResult(COST_IN_SHP_FILE, TRANSACTION_PARTNER)), + fareZoneBasedPtFareCalculator.calculateFare(inShape, + inShape2)); + assertEquals(Optional.of(new PtFareCalculator.FareResult(COST_IN_SHP_FILE, TRANSACTION_PARTNER)), + fareZoneBasedPtFareCalculator.calculateFare(inShape2, + inShape)); + } + + @Test + void testCalculateFareOutShape() { + FareZoneBasedPtFareCalculator fareZoneBasedPtFareCalculator = new FareZoneBasedPtFareCalculator(getParams()); + + Coord inShape = new Coord(710300.624, 5422165.737); + Coord inShape2 = new Coord(714940.65, 5420707.78); + Coord outShape = new Coord(726634.40, 5433508.07); + Coord outShape2 = new Coord(736634.40, 5533508.07); + + assertEquals(Optional.empty(), fareZoneBasedPtFareCalculator.calculateFare(inShape, outShape)); + assertEquals(Optional.empty(), fareZoneBasedPtFareCalculator.calculateFare(inShape, outShape2)); + assertEquals(Optional.empty(), fareZoneBasedPtFareCalculator.calculateFare(inShape2, outShape)); + assertEquals(Optional.empty(), fareZoneBasedPtFareCalculator.calculateFare(inShape2, outShape)); + assertEquals(Optional.empty(), fareZoneBasedPtFareCalculator.calculateFare(outShape, outShape2)); + } + + private FareZoneBasedPtFareParams getParams() { + URL context = ExamplesUtils.getTestScenarioURL("kelheim"); + + FareZoneBasedPtFareParams fareZoneBasedPtFareParams = new FareZoneBasedPtFareParams(); + fareZoneBasedPtFareParams.setFareZoneShp(IOUtils.extendUrl(context, "ptTestArea/pt-area.shp").toString()); + fareZoneBasedPtFareParams.setTransactionPartner(TRANSACTION_PARTNER); + return fareZoneBasedPtFareParams; + } + +} diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java b/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java index a894bb44141..38cb81e4a11 100644 --- a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java +++ b/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java @@ -49,7 +49,6 @@ void testFareZoneBasedPtFareHandler() { PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(config, PtFareConfigGroup.class); FareZoneBasedPtFareParams fareZoneBased = new FareZoneBasedPtFareParams(); - fareZoneBased.setCost(2.5); fareZoneBased.setDescription("simple fare zone based"); fareZoneBased.setFareZoneShp(IOUtils.extendUrl(context, "ptTestArea/pt-area.shp").toString()); fareZoneBased.setPriority(10); diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtFareConfigGroupTest.java b/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtFareConfigGroupTest.java new file mode 100644 index 00000000000..7af7058648f --- /dev/null +++ b/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtFareConfigGroupTest.java @@ -0,0 +1,45 @@ +package playground.vsp.pt.fare; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.matsim.core.config.Config; +import org.matsim.core.config.ConfigUtils; + +class PtFareConfigGroupTest { + @Test + void testNoFareParams_throws() { + Config config = ConfigUtils.createConfig(); + PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(config, PtFareConfigGroup.class); + Assertions.assertThrows(IllegalArgumentException.class, () -> ptFareConfigGroup.checkConsistency(config)); + } + + @Test + void testSamePriority_throws() { + Config config = ConfigUtils.createConfig(); + PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(config, PtFareConfigGroup.class); + FareZoneBasedPtFareParams fareZoneBased = new FareZoneBasedPtFareParams(); + fareZoneBased.setPriority(5); + ptFareConfigGroup.addParameterSet(fareZoneBased); + + DistanceBasedPtFareParams distanceBased = new DistanceBasedPtFareParams(); + distanceBased.setPriority(5); + ptFareConfigGroup.addParameterSet(distanceBased); + + Assertions.assertThrows(IllegalArgumentException.class, () -> ptFareConfigGroup.checkConsistency(config)); + } + + @Test + void test_ok() { + Config config = ConfigUtils.createConfig(); + PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(config, PtFareConfigGroup.class); + FareZoneBasedPtFareParams fareZoneBased = new FareZoneBasedPtFareParams(); + fareZoneBased.setPriority(5); + ptFareConfigGroup.addParameterSet(fareZoneBased); + + DistanceBasedPtFareParams distanceBased = new DistanceBasedPtFareParams(); + distanceBased.setPriority(10); + ptFareConfigGroup.addParameterSet(distanceBased); + + ptFareConfigGroup.checkConsistency(config); + } +} diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtTripFareEstimatorTest.java b/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtTripFareEstimatorTest.java index 6ddfef69d44..557b8fbdfd6 100644 --- a/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtTripFareEstimatorTest.java +++ b/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtTripFareEstimatorTest.java @@ -60,7 +60,7 @@ public void setUp() throws Exception { group = ConfigUtils.addOrGetModule(config, InformedModeChoiceConfigGroup.class); PtFareConfigGroup fare = ConfigUtils.addOrGetModule(config, PtFareConfigGroup.class); - DistanceBasedPtFareParams distanceFare = ConfigUtils.addOrGetModule(config, DistanceBasedPtFareParams.class); + DistanceBasedPtFareParams distanceFare = new DistanceBasedPtFareParams(); fare.setApplyUpperBound(true); fare.setUpperBoundFactor(1.5); @@ -73,6 +73,8 @@ public void setUp() throws Exception { distanceFare.setLongDistanceTripIntercept(1); distanceFare.setLongDistanceTripSlope(0.01); + fare.addParameterSet(distanceFare); + controler = MATSimApplication.prepare(TestScenario.class, config); injector = controler.getInjector(); @@ -98,8 +100,9 @@ private List estimateAgent(Id personId) { List trip = model.getLegs(TransportMode.pt, i); - if (trip == null) + if (trip == null) { continue; + } MinMaxEstimate est = estimator.estimate(context, TransportMode.pt, model, trip, ModeAvailability.YES); @@ -116,9 +119,9 @@ void fare() { System.out.println(est); assertThat(est) - .allMatch(e -> e.getMin() < e.getMax(), "Min smaller max") - .first().extracting(MinMaxEstimate::getMin, InstanceOfAssertFactories.DOUBLE) - .isCloseTo(-379.4, Offset.offset(0.1)); + .allMatch(e -> e.getMin() < e.getMax(), "Min smaller max") + .first().extracting(MinMaxEstimate::getMin, InstanceOfAssertFactories.DOUBLE) + .isCloseTo(-379.4, Offset.offset(0.1)); } @@ -129,7 +132,7 @@ void all() { List est = estimateAgent(agent); assertThat(est) - .allMatch(e -> e.getMin() <= e.getMax(), "Min smaller max"); + .allMatch(e -> e.getMin() <= e.getMax(), "Min smaller max"); } } @@ -157,22 +160,22 @@ void planEstimate() { double estimate = estimator.estimate(context, TransportMode.pt, new String[]{"pt", "car", "pt", "pt", "pt"}, model, ModeAvailability.YES); assertThat(estimate) - .isLessThanOrEqualTo(maxSum) - .isGreaterThanOrEqualTo(minSum) - .isCloseTo(-2738.72, Offset.offset(0.1)); + .isLessThanOrEqualTo(maxSum) + .isGreaterThanOrEqualTo(minSum) + .isCloseTo(-2738.72, Offset.offset(0.1)); estimate = estimator.estimate(context, TransportMode.pt, new String[]{"pt", "car", "car", "car", "pt"}, model, ModeAvailability.YES); assertThat(estimate) - .isLessThanOrEqualTo(maxSum) - .isGreaterThanOrEqualTo(minSum) - .isCloseTo(-1222.91, Offset.offset(0.1)); + .isLessThanOrEqualTo(maxSum) + .isGreaterThanOrEqualTo(minSum) + .isCloseTo(-1222.91, Offset.offset(0.1)); // Essentially single trip estimate = estimator.estimate(context, TransportMode.pt, new String[]{"pt", "car", "car", "car", "car"}, model, ModeAvailability.YES); assertThat(estimate) - .isCloseTo(singleTrips.get(0).getMin(), Offset.offset(0.1)); + .isCloseTo(singleTrips.get(0).getMin(), Offset.offset(0.1)); } } From 417a83bf42d3d21ac6cf1fb8714f00f59bf8f670 Mon Sep 17 00:00:00 2001 From: Paul Heinrich Date: Fri, 16 Aug 2024 14:11:11 +0200 Subject: [PATCH 206/213] implemented integration test --- .../vsp/pt/fare/PtFareConfigGroup.java | 15 +-- .../playground/vsp/pt/fare/PtFareModule.java | 2 +- .../playground/vsp/pt/fare/PtFareParams.java | 18 +-- .../fare/FareZoneBasedPtFareHandlerTest.java | 115 ++++++++++-------- .../vsp/pt/fare/PtFareConfigGroupTest.java | 8 +- 5 files changed, 85 insertions(+), 73 deletions(-) diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java index 1093e607db3..e4a72423fb2 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java @@ -52,9 +52,6 @@ public double getUpperBoundFactor() { return upperBoundFactor; } - /** - * @param upperBoundFactor -- {@value #UPPER_BOUND_FACTOR_CMT} - */ @StringSetter(UPPER_BOUND_FACTOR) public void setUpperBoundFactor(double upperBoundFactor) { this.upperBoundFactor = upperBoundFactor; @@ -71,13 +68,13 @@ protected void checkConsistency(Config config) { throw new IllegalArgumentException("No parameter sets found for pt fare calculation. Please add at least one parameter set."); } - long distinctPriorities = Stream.concat(distanceBasedParameterSets.stream(), fareZoneBasedParameterSets.stream()) - .map(PtFareParams.class::cast) - .map(PtFareParams::getPriority) - .distinct().count(); + long distinctOrders = Stream.concat(distanceBasedParameterSets.stream(), fareZoneBasedParameterSets.stream()) + .map(PtFareParams.class::cast) + .map(PtFareParams::getOrder) + .distinct().count(); - if (distinctPriorities != distanceBasedParameterSets.size() + fareZoneBasedParameterSets.size()) { - throw new IllegalArgumentException("Duplicate priorities found in parameter sets. Please make sure that priorities are unique."); + if (distinctOrders != distanceBasedParameterSets.size() + fareZoneBasedParameterSets.size()) { + throw new IllegalArgumentException("Duplicate order values found in parameter sets. Please make sure that order values are unique."); } } } diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java index 7974d9b0516..c9f327a6cec 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java @@ -24,7 +24,7 @@ public void install() { Stream.concat(fareZoneBased.stream(), distanceBased.stream()) .map(c -> (PtFareParams) c) - .sorted(Comparator.comparing(PtFareParams::getPriority).reversed()) + .sorted(Comparator.comparing(PtFareParams::getOrder)) .forEach(p -> { if (p instanceof FareZoneBasedPtFareParams fareZoneBasedPtFareParams) { ptFareCalculator.addBinding().toInstance(new FareZoneBasedPtFareCalculator(fareZoneBasedPtFareParams)); diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareParams.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareParams.java index ece2641d9ad..56e96fb49c2 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareParams.java +++ b/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareParams.java @@ -6,11 +6,11 @@ public abstract class PtFareParams extends ReflectiveConfigGroup { public static final String FARE_ZONE_SHP = "fareZoneShp"; - public static final String PRIORITY = "priority"; + public static final String ORDER = "order"; public static final String TRANSACTION_PARTNER = "transactionPartner"; public static final String DESCRIPTION = "description"; - private int priority; + private int order; private String fareZoneShp; private String transactionPartner; private String description; @@ -23,7 +23,7 @@ public PtFareParams(String name) { public Map getComments() { var map = super.getComments(); map.put(FARE_ZONE_SHP, "Shp file with fare zone(s). This parameter is only used for PtFareCalculationModel 'fareZoneBased'."); - map.put(PRIORITY, "Priority of this fare calculation in the list of fare calculations. Higher values mean to be evaluated first."); + map.put(ORDER, "Order of this fare calculation in the list of fare calculations. Lower values mean to be evaluated first."); map.put(TRANSACTION_PARTNER, "The transaction partner for the fare calculation. This is used in the PersonMoneyEvent."); map.put(DESCRIPTION, "Description of the fare zone."); return map; @@ -39,14 +39,14 @@ public void setFareZoneShp(String fareZoneShp) { this.fareZoneShp = fareZoneShp; } - @StringGetter(PRIORITY) - public int getPriority() { - return priority; + @StringGetter(ORDER) + public int getOrder() { + return order; } - @StringSetter(PRIORITY) - public void setPriority(int priority) { - this.priority = priority; + @StringSetter(ORDER) + public void setOrder(int order) { + this.order = order; } @StringGetter(TRANSACTION_PARTNER) diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java b/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java index 38cb81e4a11..9d76e3ea13b 100644 --- a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java +++ b/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java @@ -1,12 +1,14 @@ package playground.vsp.pt.fare; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import org.matsim.analysis.personMoney.PersonMoneyEventsAnalysisModule; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.events.PersonMoneyEvent; +import org.matsim.api.core.v01.events.handler.PersonMoneyEventHandler; import org.matsim.api.core.v01.population.*; import org.matsim.core.config.Config; import org.matsim.core.config.ConfigUtils; @@ -20,57 +22,70 @@ import org.matsim.examples.ExamplesUtils; import org.matsim.testcases.MatsimTestUtils; -import java.io.BufferedReader; -import java.io.IOException; import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import static org.matsim.application.ApplicationUtils.globFile; - public class FareZoneBasedPtFareHandlerTest { + private final static String FARE_ZONE_TRANSACTION_PARTNER = "fare zone transaction partner"; + private final static String DISTANCE_BASED_TRANSACTION_PARTNER = "distance based transaction partner"; + @RegisterExtension private MatsimTestUtils utils = new MatsimTestUtils(); @Test void testFareZoneBasedPtFareHandler() { - final String FARE_ZONE_TRANSACTION_PARTNER = "fare zone transaction partner"; - final String DISTANCE_BASED_TRANSACTION_PARTNER = "distance based transaction partner"; - - URL context = ExamplesUtils.getTestScenarioURL("kelheim"); - Config config = ConfigUtils.loadConfig(IOUtils.extendUrl(context, "config.xml")); - config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); - config.controller().setOutputDirectory(utils.getOutputDirectory()); - config.controller().setLastIteration(0); + //Prepare + Config config = getConfig(); + //adapt pt fare PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(config, PtFareConfigGroup.class); FareZoneBasedPtFareParams fareZoneBased = new FareZoneBasedPtFareParams(); fareZoneBased.setDescription("simple fare zone based"); - fareZoneBased.setFareZoneShp(IOUtils.extendUrl(context, "ptTestArea/pt-area.shp").toString()); - fareZoneBased.setPriority(10); + fareZoneBased.setFareZoneShp(IOUtils.extendUrl(config.getContext(), "ptTestArea/pt-area.shp").toString()); + fareZoneBased.setOrder(1); fareZoneBased.setTransactionPartner(FARE_ZONE_TRANSACTION_PARTNER); DistanceBasedPtFareParams distanceBased = new DistanceBasedPtFareParams(); - distanceBased.setPriority(5); + distanceBased.setOrder(2); distanceBased.setTransactionPartner(DISTANCE_BASED_TRANSACTION_PARTNER); ptFareConfigGroup.addParameterSet(fareZoneBased); ptFareConfigGroup.addParameterSet(distanceBased); - ScoringConfigGroup scoring = ConfigUtils.addOrGetModule(config, ScoringConfigGroup.class); + MutableScenario scenario = setUpScenario(config); - ScoringConfigGroup.ActivityParams homeParams = new ScoringConfigGroup.ActivityParams("home"); - ScoringConfigGroup.ActivityParams workParams = new ScoringConfigGroup.ActivityParams("work"); - homeParams.setTypicalDuration(8 * 3600.); - workParams.setTypicalDuration(8 * 3600.); - scoring.addActivityParams(homeParams); - scoring.addActivityParams(workParams); + //Run + var fareAnalysis = new FareAnalysis(); + + Controler controler = new Controler(scenario); + controler.addOverridingModule(new AbstractModule() { + @Override + public void install() { + install(new PtFareModule()); + addEventHandlerBinding().toInstance(fareAnalysis); + } + }); + controler.run(); + + //Check + List events = fareAnalysis.getEvents(); + Assertions.assertEquals(2, events.size()); + + final String FARE_TEST_PERSON = "fareTestPerson"; + //first event is the fare zone based event + Assertions.assertEquals(new PersonMoneyEvent(33264, Id.createPersonId(FARE_TEST_PERSON), -1.5, "pt fare", FARE_ZONE_TRANSACTION_PARTNER, + FARE_TEST_PERSON), events.get(0)); + //second event is the distance based event + Assertions.assertEquals(new PersonMoneyEvent(52056, Id.createPersonId(FARE_TEST_PERSON), -4.526183060514956, "pt fare", + DISTANCE_BASED_TRANSACTION_PARTNER, FARE_TEST_PERSON), events.get(1)); + } + + private @NotNull MutableScenario setUpScenario(Config config) { MutableScenario scenario = (MutableScenario) ScenarioUtils.loadScenario(config); Population population = ScenarioUtils.createScenario(ConfigUtils.createConfig()).getPopulation(); @@ -98,37 +113,37 @@ void testFareZoneBasedPtFareHandler() { person.addPlan(plan); population.addPerson(person); scenario.setPopulation(population); + return scenario; + } - Controler controler = new Controler(scenario); - controler.addOverridingModule(new AbstractModule() { - @Override - public void install() { - install(new PtFareModule()); - install(new PersonMoneyEventsAnalysisModule()); - } - }); - controler.run(); + private @NotNull Config getConfig() { + URL context = ExamplesUtils.getTestScenarioURL("kelheim"); + Config config = ConfigUtils.loadConfig(IOUtils.extendUrl(context, "config.xml")); + config.controller().setOverwriteFileSetting(OutputDirectoryHierarchy.OverwriteFileSetting.deleteDirectoryIfExists); + config.controller().setOutputDirectory(utils.getOutputDirectory()); + config.controller().setLastIteration(0); - Assertions.assertTrue(Files.exists(Path.of(utils.getOutputDirectory()))); + ScoringConfigGroup scoring = ConfigUtils.addOrGetModule(config, ScoringConfigGroup.class); -// read personMoneyEvents.tsv and check if both fare entries do have the correct fare type - String filePath = globFile(Path.of(utils.getOutputDirectory()), "*output_personMoneyEvents.tsv*").toString(); - String line; - List events = new ArrayList<>(); + ScoringConfigGroup.ActivityParams homeParams = new ScoringConfigGroup.ActivityParams("home"); + ScoringConfigGroup.ActivityParams workParams = new ScoringConfigGroup.ActivityParams("work"); + homeParams.setTypicalDuration(8 * 3600.); + workParams.setTypicalDuration(8 * 3600.); + scoring.addActivityParams(homeParams); + scoring.addActivityParams(workParams); + return config; + } - try (BufferedReader br = IOUtils.getBufferedReader(filePath)) { -// skip header - br.readLine(); + private static class FareAnalysis implements PersonMoneyEventHandler { + private final List events = new ArrayList<>(); - while ((line = br.readLine()) != null) { - events.add(line.split(";")); - } - } catch (IOException e) { - e.printStackTrace(); + @Override + public void handleEvent(PersonMoneyEvent event) { + events.add(event); } - Assertions.assertEquals(2, events.size()); - Assertions.assertEquals(FARE_ZONE_TRANSACTION_PARTNER, events.get(0)[4]); - Assertions.assertEquals(DISTANCE_BASED_TRANSACTION_PARTNER, events.get(1)[4]); + public List getEvents() { + return events; + } } } diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtFareConfigGroupTest.java b/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtFareConfigGroupTest.java index 7af7058648f..adec9b3aa6b 100644 --- a/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtFareConfigGroupTest.java +++ b/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtFareConfigGroupTest.java @@ -18,11 +18,11 @@ void testSamePriority_throws() { Config config = ConfigUtils.createConfig(); PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(config, PtFareConfigGroup.class); FareZoneBasedPtFareParams fareZoneBased = new FareZoneBasedPtFareParams(); - fareZoneBased.setPriority(5); + fareZoneBased.setOrder(5); ptFareConfigGroup.addParameterSet(fareZoneBased); DistanceBasedPtFareParams distanceBased = new DistanceBasedPtFareParams(); - distanceBased.setPriority(5); + distanceBased.setOrder(5); ptFareConfigGroup.addParameterSet(distanceBased); Assertions.assertThrows(IllegalArgumentException.class, () -> ptFareConfigGroup.checkConsistency(config)); @@ -33,11 +33,11 @@ void test_ok() { Config config = ConfigUtils.createConfig(); PtFareConfigGroup ptFareConfigGroup = ConfigUtils.addOrGetModule(config, PtFareConfigGroup.class); FareZoneBasedPtFareParams fareZoneBased = new FareZoneBasedPtFareParams(); - fareZoneBased.setPriority(5); + fareZoneBased.setOrder(5); ptFareConfigGroup.addParameterSet(fareZoneBased); DistanceBasedPtFareParams distanceBased = new DistanceBasedPtFareParams(); - distanceBased.setPriority(10); + distanceBased.setOrder(10); ptFareConfigGroup.addParameterSet(distanceBased); ptFareConfigGroup.checkConsistency(config); From 4c66b9072f33a34e60fd2fb5b544671e2e6f3d46 Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Fri, 16 Aug 2024 19:43:37 +0200 Subject: [PATCH 207/213] Pt distance class fares (#3413) * allow for distance based pt fares by distance class * move to contrib.vsp --- .../vsp/pt/fare/ChainedPtFareCalculator.java | 2 +- .../vsp/pt/fare/ChainedPtFareHandler.java | 2 +- .../fare/DistanceBasedPtFareCalculator.java | 31 ++- .../pt/fare/DistanceBasedPtFareParams.java | 210 ++++++++++++++++++ .../fare/FareZoneBasedPtFareCalculator.java | 2 +- .../pt/fare/FareZoneBasedPtFareParams.java | 2 +- .../vsp/pt/fare/PtFareCalculator.java | 2 +- .../vsp/pt/fare/PtFareConfigGroup.java | 2 +- .../contrib}/vsp/pt/fare/PtFareHandler.java | 2 +- .../contrib}/vsp/pt/fare/PtFareModule.java | 2 +- .../contrib}/vsp/pt/fare/PtFareParams.java | 2 +- .../vsp/pt/fare/PtFareUpperBoundHandler.java | 3 +- .../PtTripWithDistanceBasedFareEstimator.java | 13 +- .../pt/fare/DistanceBasedPtFareParams.java | 187 ---------------- .../DistanceBasedPtFareCalculatorTest.java | 15 +- .../FareZoneBasedPtFareCalculatorTest.java | 2 +- .../fare/FareZoneBasedPtFareHandlerTest.java | 7 +- .../vsp/pt/fare/PtFareConfigGroupTest.java | 2 +- .../vsp/pt/fare/PtTripFareEstimatorTest.java | 17 +- .../java/playground/vsp/TestScenario.java | 2 +- 20 files changed, 265 insertions(+), 242 deletions(-) rename contribs/vsp/src/main/java/{playground => org/matsim/contrib}/vsp/pt/fare/ChainedPtFareCalculator.java (96%) rename contribs/vsp/src/main/java/{playground => org/matsim/contrib}/vsp/pt/fare/ChainedPtFareHandler.java (98%) rename contribs/vsp/src/main/java/{playground => org/matsim/contrib}/vsp/pt/fare/DistanceBasedPtFareCalculator.java (68%) create mode 100644 contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareParams.java rename contribs/vsp/src/main/java/{playground => org/matsim/contrib}/vsp/pt/fare/FareZoneBasedPtFareCalculator.java (97%) rename contribs/vsp/src/main/java/{playground => org/matsim/contrib}/vsp/pt/fare/FareZoneBasedPtFareParams.java (83%) rename contribs/vsp/src/main/java/{playground => org/matsim/contrib}/vsp/pt/fare/PtFareCalculator.java (85%) rename contribs/vsp/src/main/java/{playground => org/matsim/contrib}/vsp/pt/fare/PtFareConfigGroup.java (98%) rename contribs/vsp/src/main/java/{playground => org/matsim/contrib}/vsp/pt/fare/PtFareHandler.java (88%) rename contribs/vsp/src/main/java/{playground => org/matsim/contrib}/vsp/pt/fare/PtFareModule.java (98%) rename contribs/vsp/src/main/java/{playground => org/matsim/contrib}/vsp/pt/fare/PtFareParams.java (97%) rename contribs/vsp/src/main/java/{playground => org/matsim/contrib}/vsp/pt/fare/PtFareUpperBoundHandler.java (98%) rename contribs/vsp/src/main/java/{playground => org/matsim/contrib}/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java (91%) delete mode 100644 contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java rename contribs/vsp/src/test/java/{playground => org/matsim/contrib}/vsp/pt/fare/DistanceBasedPtFareCalculatorTest.java (80%) rename contribs/vsp/src/test/java/{playground => org/matsim/contrib}/vsp/pt/fare/FareZoneBasedPtFareCalculatorTest.java (98%) rename contribs/vsp/src/test/java/{playground => org/matsim/contrib}/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java (94%) rename contribs/vsp/src/test/java/{playground => org/matsim/contrib}/vsp/pt/fare/PtFareConfigGroupTest.java (97%) rename contribs/vsp/src/test/java/{playground => org/matsim/contrib}/vsp/pt/fare/PtTripFareEstimatorTest.java (90%) diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareCalculator.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/ChainedPtFareCalculator.java similarity index 96% rename from contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareCalculator.java rename to contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/ChainedPtFareCalculator.java index bd38fc3237b..1e95a8b909f 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareCalculator.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/ChainedPtFareCalculator.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import com.google.inject.Inject; import org.matsim.api.core.v01.Coord; diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareHandler.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/ChainedPtFareHandler.java similarity index 98% rename from contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareHandler.java rename to contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/ChainedPtFareHandler.java index cc5963e6345..fef87f65ba3 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/ChainedPtFareHandler.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/ChainedPtFareHandler.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import com.google.inject.Inject; import org.matsim.api.core.v01.Coord; diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculator.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareCalculator.java similarity index 68% rename from contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculator.java rename to contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareCalculator.java index 3708bf7acce..74c1d13b9b5 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculator.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareCalculator.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -11,6 +11,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.SortedMap; /** * This class calculates the fare for a public transport trip based on the distance between the origin and destination. If a shape file is @@ -21,11 +22,7 @@ public class DistanceBasedPtFareCalculator implements PtFareCalculator { private static final Logger log = LogManager.getLogger(DistanceBasedPtFareCalculator.class); private final double minFare; - private final double shortTripIntercept; - private final double shortTripSlope; - private final double longTripIntercept; - private final double longTripSlope; - private final double longTripThreshold; + private final SortedMap distanceClassFareParams; private ShpOptions shp = null; private final String transactionPartner; @@ -33,11 +30,7 @@ public class DistanceBasedPtFareCalculator implements PtFareCalculator { public DistanceBasedPtFareCalculator(DistanceBasedPtFareParams params) { this.minFare = params.getMinFare(); - this.shortTripIntercept = params.getNormalTripIntercept(); - this.shortTripSlope = params.getNormalTripSlope(); - this.longTripIntercept = params.getLongDistanceTripIntercept(); - this.longTripSlope = params.getLongDistanceTripSlope(); - this.longTripThreshold = params.getLongDistanceTripThreshold(); + this.distanceClassFareParams = params.getDistanceClassFareParams(); this.transactionPartner = params.getTransactionPartner(); if (params.getFareZoneShp() != null) { @@ -58,7 +51,7 @@ public Optional calculateFare(Coord from, Coord to) { double distance = CoordUtils.calcEuclideanDistance(from, to); - double fare = computeFare(distance, longTripThreshold, minFare, shortTripIntercept, shortTripSlope, longTripIntercept, longTripSlope); + double fare = computeFare(distance, minFare, distanceClassFareParams); return Optional.of(new FareResult(fare, transactionPartner)); } @@ -73,12 +66,14 @@ private boolean inShape(Coord coord) { return shp.readFeatures().stream().anyMatch(f -> MGC.coord2Point(coord).within((Geometry) f.getDefaultGeometry())); } - public static double computeFare(double distance, double longTripThreshold, double minFare, double shortTripIntercept, double shortTripSlope, - double longTripIntercept, double longTripSlope) { - if (distance <= longTripThreshold) { - return Math.max(minFare, shortTripIntercept + shortTripSlope * distance); - } else { - return Math.max(minFare, longTripIntercept + longTripSlope * distance); + public static double computeFare(double distance, double minFare, + SortedMap distanceClassFareParams) { + for (DistanceBasedPtFareParams.DistanceClassLinearFareFunctionParams distanceClassFareParam : distanceClassFareParams.values()) { + if (distance <= distanceClassFareParam.getMaxDistance()) { + return Math.max(minFare, distance * distanceClassFareParam.getFareSlope() + distanceClassFareParam.getFareIntercept()); + } } + log.error("No fare found for distance of " + distance + " meters."); + throw new RuntimeException("No fare found for distance of " + distance + " meters."); } } diff --git a/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareParams.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareParams.java new file mode 100644 index 00000000000..e84a9e88abb --- /dev/null +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareParams.java @@ -0,0 +1,210 @@ +package org.matsim.contrib.vsp.pt.fare; + +import jakarta.validation.constraints.PositiveOrZero; +import org.apache.commons.math.stat.regression.SimpleRegression; +import org.matsim.core.config.ReflectiveConfigGroup; + +import java.util.*; + +/** + * @author Chengqi Lu (luchengqi7) + * The parameters for the distance-based PT trip fare calculation. + * The default values are set based on the fitting results of the trip and fare data collected on September 2021 + * The values are based on the standard unit of meter (m) and Euro (EUR) + */ +public class DistanceBasedPtFareParams extends PtFareParams { + public static final DistanceBasedPtFareParams GERMAN_WIDE_FARE = germanWideFare(); + + public static final String SET_NAME = "ptFareCalculationDistanceBased"; + public static final String MIN_FARE = "minFare"; + + @PositiveOrZero + private double minFare = 2.0; + + public DistanceBasedPtFareParams() { + super(SET_NAME); + } + + @Override + public Map getComments() { + Map map = super.getComments(); + map.put(MIN_FARE, "Minimum fare for a PT trip (e.g. Kurzstrecke/short distance ticket in cities, ticket for 1 zone in rural areas). " + + "Default is 2.0EUR."); + return map; + } + + @StringGetter(MIN_FARE) + public double getMinFare() { + return minFare; + } + + @StringSetter(MIN_FARE) + public void setMinFare(double minFare) { + this.minFare = minFare; + } + + // in Deutschlandtarif, the linear function for the prices above 100km seem to have a different steepness + // hence the following difference in data points + // prices taken from https://deutschlandtarifverbund.de/wp-content/uploads/2024/07/20231201_TBDT_J_10_Preisliste_V07.pdf + private static DistanceBasedPtFareParams germanWideFare() { + final double MIN_FARE = 1.70; + + SimpleRegression under100kmTrip = new SimpleRegression(); + under100kmTrip.addData(1, MIN_FARE); + under100kmTrip.addData(2, 1.90); + under100kmTrip.addData(3, 2.00); + under100kmTrip.addData(4, 2.10); + under100kmTrip.addData(5, 2.20); + under100kmTrip.addData(6, 3.20); + under100kmTrip.addData(7, 3.70); + under100kmTrip.addData(8, 3.80); + under100kmTrip.addData(9, 3.90); + under100kmTrip.addData(10, 4.10); + under100kmTrip.addData(11, 5.00); + under100kmTrip.addData(12, 5.40); + under100kmTrip.addData(13, 5.60); + under100kmTrip.addData(14, 5.80); + under100kmTrip.addData(15, 5.90); + under100kmTrip.addData(16, 6.40); + under100kmTrip.addData(17, 6.50); + under100kmTrip.addData(18, 6.60); + under100kmTrip.addData(19, 6.70); + under100kmTrip.addData(20, 6.90); + under100kmTrip.addData(30, 9.90); + under100kmTrip.addData(40, 13.70); + under100kmTrip.addData(50, 16.30); + under100kmTrip.addData(60, 18.10); + under100kmTrip.addData(70, 20.10); + under100kmTrip.addData(80, 23.20); + under100kmTrip.addData(90, 26.20); + under100kmTrip.addData(100, 28.10); + + SimpleRegression longDistanceTrip = new SimpleRegression(); + longDistanceTrip.addData(100, 28.10); + longDistanceTrip.addData(200, 47.20); + longDistanceTrip.addData(300, 59.70); + longDistanceTrip.addData(400, 71.70); + longDistanceTrip.addData(500, 83.00); + longDistanceTrip.addData(600, 94.60); + longDistanceTrip.addData(700, 106.30); + longDistanceTrip.addData(800, 118.20); + longDistanceTrip.addData(900, 130.10); + longDistanceTrip.addData(1000, 141.00); + longDistanceTrip.addData(1100, 148.60); + longDistanceTrip.addData(1200, 158.10); + longDistanceTrip.addData(1300, 169.20); + longDistanceTrip.addData(1400, 179.80); + longDistanceTrip.addData(1500, 190.10); + longDistanceTrip.addData(1600, 201.50); + longDistanceTrip.addData(1700, 212.80); + longDistanceTrip.addData(1800, 223.30); + longDistanceTrip.addData(1900, 233.90); + longDistanceTrip.addData(2000, 244.00); + + var params = new DistanceBasedPtFareParams(); + + DistanceClassLinearFareFunctionParams distanceClass100kmFareParams = params.getOrCreateDistanceClassFareParams(100_000.); + distanceClass100kmFareParams.setFareSlope(under100kmTrip.getSlope()); + distanceClass100kmFareParams.setFareIntercept(under100kmTrip.getIntercept()); + + DistanceClassLinearFareFunctionParams distanceClassLongFareParams = params.getOrCreateDistanceClassFareParams(Double.POSITIVE_INFINITY); + distanceClassLongFareParams.setFareSlope(longDistanceTrip.getSlope()); + distanceClassLongFareParams.setFareIntercept(longDistanceTrip.getIntercept()); + + params.setTransactionPartner("Deutschlandtarif"); + params.setMinFare(MIN_FARE); + + return params; + } + + public SortedMap getDistanceClassFareParams() { + @SuppressWarnings("unchecked") + final Collection distanceClassFareParams = + (Collection) getParameterSets(DistanceClassLinearFareFunctionParams.SET_NAME); + final SortedMap map = new TreeMap<>(); + + for (DistanceClassLinearFareFunctionParams pars : distanceClassFareParams) { + if (this.isLocked()) { + pars.setLocked(); + } + map.put(pars.getMaxDistance(), pars); + } + if (this.isLocked()) { + return Collections.unmodifiableSortedMap(map); + } else { + return map; + } + } + + public DistanceClassLinearFareFunctionParams getOrCreateDistanceClassFareParams(double maxDistance) { + DistanceClassLinearFareFunctionParams distanceClassFareParams = this.getDistanceClassFareParams().get(maxDistance); + if (distanceClassFareParams == null) { + distanceClassFareParams = new DistanceClassLinearFareFunctionParams(maxDistance); + addParameterSet(distanceClassFareParams); + } + return distanceClassFareParams; + } + + public static class DistanceClassLinearFareFunctionParams extends ReflectiveConfigGroup { + + public static final String SET_NAME = "distanceClassLinearFareFunctionParams"; + public static final String FARE_SLOPE = "fareSlope"; + public static final String FARE_INTERCEPT = "fareIntercept"; + public static final String MAX_DISTANCE = "maxDistance"; + + @PositiveOrZero + private double fareSlope; + @PositiveOrZero + private double fareIntercept; + @PositiveOrZero + private double maxDistance; + + public DistanceClassLinearFareFunctionParams(double maxDistance) { + super(SET_NAME); + this.maxDistance = maxDistance; + } + + @StringGetter(FARE_SLOPE) + public double getFareSlope() { + return fareSlope; + } + + @StringSetter(FARE_SLOPE) + public void setFareSlope(double fareSlope) { + this.fareSlope = fareSlope; + } + + @StringGetter(FARE_INTERCEPT) + public double getFareIntercept() { + return fareIntercept; + } + + + @StringSetter(FARE_INTERCEPT) + public void setFareIntercept(double fareIntercept) { + this.fareIntercept = fareIntercept; + } + + @StringGetter(MAX_DISTANCE) + public double getMaxDistance() { + return maxDistance; + } + + @StringSetter(MAX_DISTANCE) + public void setMaxDistance(double maxDistance) { + this.maxDistance = maxDistance; + } + + @Override + public Map getComments() { + Map map = super.getComments(); + map.put(FARE_SLOPE, "Linear function fare = slope * distance + intercept: the value of the slope factor in currency units / m" + + "(not km!)."); + map.put(FARE_INTERCEPT, "Linear function fare = slope * distance + intercept: the value of the intercept in currency units."); + map.put(MAX_DISTANCE, "The given linear function is applied to trips up to this distance threshold in meters. If set to a finite value" + + ", the linear function for the next distance class will be tried out. If no fare is defined with " + MAX_DISTANCE + " greater than" + + "pt trip length, an error is thrown."); + return map; + } + } +} diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculator.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareCalculator.java similarity index 97% rename from contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculator.java rename to contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareCalculator.java index a676137b487..1066bb4b014 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculator.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareCalculator.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import org.geotools.api.feature.simple.SimpleFeature; import org.locationtech.jts.geom.Geometry; diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareParams.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareParams.java similarity index 83% rename from contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareParams.java rename to contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareParams.java index f213f32dbb0..391c609684e 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/FareZoneBasedPtFareParams.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareParams.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; public class FareZoneBasedPtFareParams extends PtFareParams { public static final String SET_NAME = "ptFareCalculationFareZoneBased"; diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareCalculator.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareCalculator.java similarity index 85% rename from contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareCalculator.java rename to contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareCalculator.java index 06fa0af4ca9..597f105c0dc 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareCalculator.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareCalculator.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import org.matsim.api.core.v01.Coord; diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareConfigGroup.java similarity index 98% rename from contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java rename to contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareConfigGroup.java index e4a72423fb2..9001b2ce2e9 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareConfigGroup.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareConfigGroup.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import jakarta.validation.constraints.PositiveOrZero; import org.matsim.core.config.Config; diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareHandler.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareHandler.java similarity index 88% rename from contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareHandler.java rename to contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareHandler.java index d911486a0e2..0bd169e0b60 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareHandler.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareHandler.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import org.matsim.api.core.v01.events.handler.ActivityStartEventHandler; import org.matsim.core.api.experimental.events.handler.AgentWaitingForPtEventHandler; diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareModule.java similarity index 98% rename from contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java rename to contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareModule.java index c9f327a6cec..d3b2f39d02a 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareModule.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareModule.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import com.google.inject.multibindings.Multibinder; import org.matsim.api.core.v01.TransportMode; diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareParams.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareParams.java similarity index 97% rename from contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareParams.java rename to contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareParams.java index 56e96fb49c2..2ab1c501d4f 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareParams.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareParams.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import org.matsim.core.config.ReflectiveConfigGroup; diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareUpperBoundHandler.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareUpperBoundHandler.java similarity index 98% rename from contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareUpperBoundHandler.java rename to contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareUpperBoundHandler.java index 6638c12e7f3..5d05602df2d 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtFareUpperBoundHandler.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtFareUpperBoundHandler.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import com.google.inject.Inject; import org.matsim.api.core.v01.Id; @@ -10,7 +10,6 @@ import org.matsim.core.config.groups.QSimConfigGroup; import org.matsim.core.controler.events.AfterMobsimEvent; import org.matsim.core.controler.listener.AfterMobsimListener; -import org.matsim.pt.PtConstants; import java.util.ArrayList; import java.util.HashMap; diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java similarity index 91% rename from contribs/vsp/src/main/java/playground/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java rename to contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java index 90ec2339fa4..11bbaae184d 100644 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/PtTripWithDistanceBasedFareEstimator.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import com.google.inject.Inject; import it.unimi.dsi.fastutil.doubles.DoubleArrayList; @@ -152,9 +152,7 @@ private DoubleDoublePair estimateTrip(EstimatorContext context, List trip) double dist = CoordUtils.calcEuclideanDistance(access.getCoord(), egress.getCoord()); double fareUtility = -context.scoring.marginalUtilityOfMoney * DistanceBasedPtFareCalculator.computeFare(dist, - ptFare.getLongDistanceTripThreshold(), ptFare.getMinFare(), ptFare.getNormalTripIntercept(), ptFare.getNormalTripSlope(), - ptFare.getLongDistanceTripIntercept(), ptFare.getLongDistanceTripSlope()); - + ptFare.getMinFare(), ptFare.getDistanceClassFareParams()); estimate += context.scoring.marginalUtilityOfWaitingPt_s * totalWaitingTime; @@ -221,17 +219,14 @@ private double calcMinimumFare(PlanModel plan) { // a single pt trip could never benefit from the upper bound if (n == 1) { - return DistanceBasedPtFareCalculator.computeFare(minDist, ptFare.getLongDistanceTripThreshold(), ptFare.getMinFare(), - ptFare.getNormalTripIntercept(), ptFare.getNormalTripSlope(), ptFare.getLongDistanceTripIntercept(), - ptFare.getLongDistanceTripSlope()); + return DistanceBasedPtFareCalculator.computeFare(minDist, ptFare.getMinFare(), ptFare.getDistanceClassFareParams()); } // the upper bound is the maximum single trip times a factor // therefore the minimum upper bound is the fare for the second-longest trip // the max costs are then assumed to be evenly distributed over all pt trips return 1d / n * config.getUpperBoundFactor() * DistanceBasedPtFareCalculator.computeFare(secondMinDist, - ptFare.getLongDistanceTripThreshold(), ptFare.getMinFare(), ptFare.getNormalTripIntercept(), ptFare.getNormalTripSlope(), - ptFare.getLongDistanceTripIntercept(), ptFare.getLongDistanceTripSlope()); + ptFare.getMinFare(), ptFare.getDistanceClassFareParams()); } @Override diff --git a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java b/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java deleted file mode 100644 index 605a266e131..00000000000 --- a/contribs/vsp/src/main/java/playground/vsp/pt/fare/DistanceBasedPtFareParams.java +++ /dev/null @@ -1,187 +0,0 @@ -package playground.vsp.pt.fare; - -import jakarta.validation.constraints.PositiveOrZero; -import org.apache.commons.math.stat.regression.SimpleRegression; - -import java.util.Map; - -/** - * @author Chengqi Lu (luchengqi7) - * The parameters for the distance-based PT trip fare calculation. - * The default values are set based on the fitting results of the trip and fare data collected on September 2021 - * The values are based on the standard unit of meter (m) and Euro (EUR) - */ -public class DistanceBasedPtFareParams extends PtFareParams { - public static final DistanceBasedPtFareParams GERMAN_WIDE_FARE = germanWideFare(); - - public static final String SET_NAME = "ptFareCalculationDistanceBased"; - public static final String MIN_FARE = "minFare"; - public static final String NORMAL_TRIP_SLOPE = "normalTripSlope"; - public static final String NORMAL_TRIP_INTERCEPT = "normalTripIntercept"; - public static final String LONG_DISTANCE_TRIP_THRESHOLD = "longDistanceTripThreshold"; - public static final String LONG_DISTANCE_TRIP_SLOPE = "longDistanceTripSlope"; - public static final String LONG_DISTANCE_TRIP_INTERCEPT = "longDistanceTripIntercept"; - - @PositiveOrZero - private double minFare = 2.0; - @PositiveOrZero - private double normalTripIntercept = 1.6; - @PositiveOrZero - private double normalTripSlope = 0.00017; - @PositiveOrZero - private double longDistanceTripThreshold = 50000.0; - @PositiveOrZero - private double longDistanceTripIntercept = 30.0; - @PositiveOrZero - private double longDistanceTripSlope = 0.00025; - - public DistanceBasedPtFareParams() { - super(SET_NAME); - } - - @Override - public Map getComments() { - Map map = super.getComments(); - map.put(MIN_FARE, "Minimum fare for a PT trip (e.g. Kurzstrecke/short distance ticket in cities, ticket for 1 zone in rural areas). " + - "Default is 2.0EUR."); - map.put(NORMAL_TRIP_SLOPE, "Linear model y = ax + b: the value of a, for normal trips (e.g. within the city or region). Default is 0.00017" + - "EUR."); - map.put(NORMAL_TRIP_INTERCEPT, "Linear model y = ax + b: the value of b, for normal trips. Default is 1.6EUR."); - map.put(LONG_DISTANCE_TRIP_SLOPE, "Linear model y = ax + b: the value of a, for long distance trips (e.g. intercity trips). Default is 0" + - ".00025EUR."); - map.put(LONG_DISTANCE_TRIP_INTERCEPT, "Linear model y = ax + b: the value of b, for long trips. Default is 30.0EUR."); - map.put(LONG_DISTANCE_TRIP_THRESHOLD, "Threshold of the long trips in meters. Below this value, the trips are considered as normal trips. " + - "Above this value, the trips are considered as inter-city trips. Default is 50000.0m."); - return map; - } - - @StringGetter(MIN_FARE) - public double getMinFare() { - return minFare; - } - - @StringSetter(MIN_FARE) - public void setMinFare(double minFare) { - this.minFare = minFare; - } - - @StringGetter(NORMAL_TRIP_SLOPE) - public double getNormalTripSlope() { - return normalTripSlope; - } - - @StringSetter(NORMAL_TRIP_SLOPE) - public void setNormalTripSlope(double normalTripSlope) { - this.normalTripSlope = normalTripSlope; - } - - @StringGetter(NORMAL_TRIP_INTERCEPT) - public double getNormalTripIntercept() { - return normalTripIntercept; - } - - @StringSetter(NORMAL_TRIP_INTERCEPT) - public void setNormalTripIntercept(double normalTripIntercept) { - this.normalTripIntercept = normalTripIntercept; - } - - @StringGetter(LONG_DISTANCE_TRIP_SLOPE) - public double getLongDistanceTripSlope() { - return longDistanceTripSlope; - } - - @StringSetter(LONG_DISTANCE_TRIP_SLOPE) - public void setLongDistanceTripSlope(double longDistanceTripSlope) { - this.longDistanceTripSlope = longDistanceTripSlope; - } - - @StringGetter(LONG_DISTANCE_TRIP_INTERCEPT) - public double getLongDistanceTripIntercept() { - return longDistanceTripIntercept; - } - - @StringSetter(LONG_DISTANCE_TRIP_INTERCEPT) - public void setLongDistanceTripIntercept(double longDistanceTripIntercept) { - this.longDistanceTripIntercept = longDistanceTripIntercept; - } - - @StringGetter(LONG_DISTANCE_TRIP_THRESHOLD) - public double getLongDistanceTripThreshold() { - return longDistanceTripThreshold; - } - - @StringSetter(LONG_DISTANCE_TRIP_THRESHOLD) - public void setLongDistanceTripThreshold(double longDistanceTripThreshold) { - this.longDistanceTripThreshold = longDistanceTripThreshold; - } - - // in Deutschlandtarif, the linear function for the prices above 100km seem to have a different steepness - // hence the following difference in data points - // prices taken from https://deutschlandtarifverbund.de/wp-content/uploads/2024/07/20231201_TBDT_J_10_Preisliste_V07.pdf - private static DistanceBasedPtFareParams germanWideFare() { - final double MIN_FARE = 1.70; - - SimpleRegression normalDistanceTrip = new SimpleRegression(); - normalDistanceTrip.addData(1, MIN_FARE); - normalDistanceTrip.addData(2, 1.90); - normalDistanceTrip.addData(3, 2.00); - normalDistanceTrip.addData(4, 2.10); - normalDistanceTrip.addData(5, 2.20); - normalDistanceTrip.addData(6, 3.20); - normalDistanceTrip.addData(7, 3.70); - normalDistanceTrip.addData(8, 3.80); - normalDistanceTrip.addData(9, 3.90); - normalDistanceTrip.addData(10, 4.10); - normalDistanceTrip.addData(11, 5.00); - normalDistanceTrip.addData(12, 5.40); - normalDistanceTrip.addData(13, 5.60); - normalDistanceTrip.addData(14, 5.80); - normalDistanceTrip.addData(15, 5.90); - normalDistanceTrip.addData(16, 6.40); - normalDistanceTrip.addData(17, 6.50); - normalDistanceTrip.addData(18, 6.60); - normalDistanceTrip.addData(19, 6.70); - normalDistanceTrip.addData(20, 6.90); - normalDistanceTrip.addData(30, 9.90); - normalDistanceTrip.addData(40, 13.70); - normalDistanceTrip.addData(50, 16.30); - normalDistanceTrip.addData(60, 18.10); - normalDistanceTrip.addData(70, 20.10); - normalDistanceTrip.addData(80, 23.20); - normalDistanceTrip.addData(90, 26.20); - normalDistanceTrip.addData(100, 28.10); - - SimpleRegression longDistanceTrip = new SimpleRegression(); - longDistanceTrip.addData(100, 28.10); - longDistanceTrip.addData(200, 47.20); - longDistanceTrip.addData(300, 59.70); - longDistanceTrip.addData(400, 71.70); - longDistanceTrip.addData(500, 83.00); - longDistanceTrip.addData(600, 94.60); - longDistanceTrip.addData(700, 106.30); - longDistanceTrip.addData(800, 118.20); - longDistanceTrip.addData(900, 130.10); - longDistanceTrip.addData(1000, 141.00); - longDistanceTrip.addData(1100, 148.60); - longDistanceTrip.addData(1200, 158.10); - longDistanceTrip.addData(1300, 169.20); - longDistanceTrip.addData(1400, 179.80); - longDistanceTrip.addData(1500, 190.10); - longDistanceTrip.addData(1600, 201.50); - longDistanceTrip.addData(1700, 212.80); - longDistanceTrip.addData(1800, 223.30); - longDistanceTrip.addData(1900, 233.90); - longDistanceTrip.addData(2000, 244.00); - - var params = new DistanceBasedPtFareParams(); - params.setNormalTripSlope(normalDistanceTrip.getSlope()); - params.setNormalTripIntercept(normalDistanceTrip.getIntercept()); - params.setLongDistanceTripSlope(longDistanceTrip.getSlope()); - params.setLongDistanceTripIntercept(longDistanceTrip.getIntercept()); - params.setLongDistanceTripThreshold(100_000.); - params.setTransactionPartner("Deutschlandtarif"); - params.setMinFare(MIN_FARE); - - return params; - } -} diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculatorTest.java b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareCalculatorTest.java similarity index 80% rename from contribs/vsp/src/test/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculatorTest.java rename to contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareCalculatorTest.java index 005b7f3f80d..5a62cff6375 100644 --- a/contribs/vsp/src/test/java/playground/vsp/pt/fare/DistanceBasedPtFareCalculatorTest.java +++ b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareCalculatorTest.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -61,13 +61,16 @@ private DistanceBasedPtFareCalculator getCalculator(String shapeFile) { var params = new DistanceBasedPtFareParams(); params.setTransactionPartner(TRANSACTION_PARTNER); //0-2000m: 1EUR + 1EUR/km - params.setNormalTripIntercept(1.0); - params.setNormalTripSlope(0.001); + DistanceBasedPtFareParams.DistanceClassLinearFareFunctionParams distanceClass2kmFareParams = + params.getOrCreateDistanceClassFareParams(2000.0); + distanceClass2kmFareParams.setFareIntercept(1.0); + distanceClass2kmFareParams.setFareSlope(0.001); //2000m+: 3EUR + 0.5EUR/km - params.setLongDistanceTripThreshold(2000.); - params.setLongDistanceTripIntercept(3.); - params.setLongDistanceTripSlope(0.0005); + DistanceBasedPtFareParams.DistanceClassLinearFareFunctionParams distanceClassLongFareParams = + params.getOrCreateDistanceClassFareParams(Double.POSITIVE_INFINITY); + distanceClassLongFareParams.setFareIntercept(3.0); + distanceClassLongFareParams.setFareSlope(0.0005); params.setMinFare(1.0); params.setFareZoneShp(shapeFile); diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculatorTest.java b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareCalculatorTest.java similarity index 98% rename from contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculatorTest.java rename to contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareCalculatorTest.java index ac3eda11b5a..a23019c86f3 100644 --- a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareCalculatorTest.java +++ b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareCalculatorTest.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Coord; diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java similarity index 94% rename from contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java rename to contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java index 9d76e3ea13b..f55e7bf7026 100644 --- a/contribs/vsp/src/test/java/playground/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java +++ b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Assertions; @@ -49,6 +49,11 @@ void testFareZoneBasedPtFareHandler() { fareZoneBased.setTransactionPartner(FARE_ZONE_TRANSACTION_PARTNER); DistanceBasedPtFareParams distanceBased = new DistanceBasedPtFareParams(); + DistanceBasedPtFareParams.DistanceClassLinearFareFunctionParams distanceClassFareParams = + distanceBased.getOrCreateDistanceClassFareParams(999_999_999.); + distanceClassFareParams.setFareSlope(0.00017); + distanceClassFareParams.setFareIntercept(1.6); + distanceBased.addParameterSet(distanceClassFareParams); distanceBased.setOrder(2); distanceBased.setTransactionPartner(DISTANCE_BASED_TRANSACTION_PARTNER); diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtFareConfigGroupTest.java b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/PtFareConfigGroupTest.java similarity index 97% rename from contribs/vsp/src/test/java/playground/vsp/pt/fare/PtFareConfigGroupTest.java rename to contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/PtFareConfigGroupTest.java index adec9b3aa6b..ed32e9ac859 100644 --- a/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtFareConfigGroupTest.java +++ b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/PtFareConfigGroupTest.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtTripFareEstimatorTest.java b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/PtTripFareEstimatorTest.java similarity index 90% rename from contribs/vsp/src/test/java/playground/vsp/pt/fare/PtTripFareEstimatorTest.java rename to contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/PtTripFareEstimatorTest.java index 557b8fbdfd6..791931b89a2 100644 --- a/contribs/vsp/src/test/java/playground/vsp/pt/fare/PtTripFareEstimatorTest.java +++ b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/PtTripFareEstimatorTest.java @@ -1,4 +1,4 @@ -package playground.vsp.pt.fare; +package org.matsim.contrib.vsp.pt.fare; import com.google.inject.Inject; import com.google.inject.Injector; @@ -66,12 +66,15 @@ public void setUp() throws Exception { fare.setUpperBoundFactor(1.5); distanceFare.setMinFare(0.1); - distanceFare.setNormalTripIntercept(0.5); - distanceFare.setNormalTripSlope(0.1); - - distanceFare.setLongDistanceTripThreshold(20000); - distanceFare.setLongDistanceTripIntercept(1); - distanceFare.setLongDistanceTripSlope(0.01); + DistanceBasedPtFareParams.DistanceClassLinearFareFunctionParams distanceClass20kmFareParams = + distanceFare.getOrCreateDistanceClassFareParams(20000.0); + distanceClass20kmFareParams.setFareIntercept(0.5); + distanceClass20kmFareParams.setFareSlope(0.1); + + DistanceBasedPtFareParams.DistanceClassLinearFareFunctionParams distanceClassLongFareParams = + distanceFare.getOrCreateDistanceClassFareParams(Double.POSITIVE_INFINITY); + distanceClassLongFareParams.setFareIntercept(1.0); + distanceClassLongFareParams.setFareSlope(0.01); fare.addParameterSet(distanceFare); diff --git a/contribs/vsp/src/test/java/playground/vsp/TestScenario.java b/contribs/vsp/src/test/java/playground/vsp/TestScenario.java index 24fde8c688a..973c9362786 100644 --- a/contribs/vsp/src/test/java/playground/vsp/TestScenario.java +++ b/contribs/vsp/src/test/java/playground/vsp/TestScenario.java @@ -14,7 +14,7 @@ import org.matsim.modechoice.estimators.DefaultLegScoreEstimator; import org.matsim.modechoice.estimators.FixedCostsEstimator; import org.matsim.testcases.MatsimTestUtils; -import playground.vsp.pt.fare.PtTripWithDistanceBasedFareEstimator; +import org.matsim.contrib.vsp.pt.fare.PtTripWithDistanceBasedFareEstimator; import javax.annotation.Nullable; import java.net.URL; From 8d209f69fa166f92c110322d3f9db488a477dd84 Mon Sep 17 00:00:00 2001 From: vsp-gleich Date: Fri, 16 Aug 2024 20:17:38 +0200 Subject: [PATCH 208/213] Pt fares minor cleanup (#3414) * shorten parameter set name, remove duplicate parameter set in test, comment --- .../matsim/contrib/vsp/pt/fare/DistanceBasedPtFareParams.java | 3 ++- .../contrib/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareParams.java b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareParams.java index e84a9e88abb..6a968d80dda 100644 --- a/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareParams.java +++ b/contribs/vsp/src/main/java/org/matsim/contrib/vsp/pt/fare/DistanceBasedPtFareParams.java @@ -46,6 +46,7 @@ public void setMinFare(double minFare) { // in Deutschlandtarif, the linear function for the prices above 100km seem to have a different steepness // hence the following difference in data points // prices taken from https://deutschlandtarifverbund.de/wp-content/uploads/2024/07/20231201_TBDT_J_10_Preisliste_V07.pdf + // TODO: This fare will change. We might need a way to select the fare of a specific year private static DistanceBasedPtFareParams germanWideFare() { final double MIN_FARE = 1.70; @@ -147,7 +148,7 @@ public DistanceClassLinearFareFunctionParams getOrCreateDistanceClassFareParams( public static class DistanceClassLinearFareFunctionParams extends ReflectiveConfigGroup { - public static final String SET_NAME = "distanceClassLinearFareFunctionParams"; + public static final String SET_NAME = "distanceClassLinearFare"; public static final String FARE_SLOPE = "fareSlope"; public static final String FARE_INTERCEPT = "fareIntercept"; public static final String MAX_DISTANCE = "maxDistance"; diff --git a/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java index f55e7bf7026..687a2c4f522 100644 --- a/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java +++ b/contribs/vsp/src/test/java/org/matsim/contrib/vsp/pt/fare/FareZoneBasedPtFareHandlerTest.java @@ -53,7 +53,6 @@ void testFareZoneBasedPtFareHandler() { distanceBased.getOrCreateDistanceClassFareParams(999_999_999.); distanceClassFareParams.setFareSlope(0.00017); distanceClassFareParams.setFareIntercept(1.6); - distanceBased.addParameterSet(distanceClassFareParams); distanceBased.setOrder(2); distanceBased.setTransactionPartner(DISTANCE_BASED_TRANSACTION_PARTNER); From 3f7824c63ff074ad75fe271cd7c106ecd38f0eaf Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Mon, 19 Aug 2024 13:57:33 +0200 Subject: [PATCH 209/213] add designated vehicle for shifts --- .../shifts/dispatcher/DrtShiftDispatcherImpl.java | 12 ++++++++++++ .../operations/shifts/io/DrtShiftsReader.java | 10 ++++++++-- .../operations/shifts/io/DrtShiftsWriter.java | 3 +++ .../shifts/run/ShiftDrtModeOptimizerQSimModule.java | 4 +++- .../extension/operations/shifts/shift/DrtShift.java | 7 +++++-- .../operations/shifts/shift/DrtShiftImpl.java | 12 ++++++++++-- .../shifts/shift/DrtShiftSpecification.java | 3 +++ .../shifts/shift/DrtShiftSpecificationImpl.java | 13 +++++++++++++ .../extension/operations/shifts/ShiftsIOTest.java | 7 +++++++ .../drt/extension/operations/shifts/testShifts.xml | 4 ++-- 10 files changed, 66 insertions(+), 9 deletions(-) diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java index 6e082f6f7d5..2e962edfa46 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java @@ -218,6 +218,18 @@ private void assignShifts(double timeStep) { for (DrtShift shift : assignableShifts) { ShiftDvrpVehicle vehicle = null; + if(shift.getDesignatedVehicleId().isPresent()) { + DvrpVehicle designatedVehicle = fleet.getVehicles().get(shift.getDesignatedVehicleId().get()); + Verify.verify(designatedVehicle.getSchedule().getStatus() == Schedule.ScheduleStatus.STARTED); + Verify.verify(designatedVehicle instanceof ShiftDvrpVehicle); + if(!vehicle.getShifts().isEmpty()) { + continue; + } + if(shift.getOperationFacilityId().isPresent()) { + Verify.verify(idleVehiclesQueues.get(shift.getOperationFacilityId().get()).contains(designatedVehicle)); + } + } + for (ShiftEntry active : activeShifts) { if (active.shift().getEndTime() > shift.getStartTime()) { break; diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/io/DrtShiftsReader.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/io/DrtShiftsReader.java index f707a8c8108..928fd2360cd 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/io/DrtShiftsReader.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/io/DrtShiftsReader.java @@ -8,6 +8,7 @@ import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftBreakSpecificationImpl; import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftSpecificationImpl; import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftsSpecification; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.core.utils.io.MatsimXmlParser; import org.xml.sax.Attributes; @@ -27,6 +28,7 @@ public class DrtShiftsReader extends MatsimXmlParser { public static final String START_TIME = "start"; public static final String END_TIME = "end"; public static final String OPERATION_FACILITY_ID = "operationFacilityId"; + public static final String DESIGNATED_VEHICLE_ID = "designatedVehicleId"; public static final String EARLIEST_BREAK_START_TIME = "earliestStart"; public static final String LATEST_BREAK_END_TIME = "latestEnd"; @@ -55,8 +57,12 @@ public void startTag(final String name, final Attributes atts, final Stack, DrtShiftSpecification> shifts) throws atts.add(createTuple(END_TIME, shift.getEndTime())); shift.getOperationFacilityId().ifPresent(operationFacilityId -> atts.add(createTuple(OPERATION_FACILITY_ID, operationFacilityId.toString()))); + shift.getDesignatedVehicleId().ifPresent(designatedVehicleId -> + atts.add(createTuple(DESIGNATED_VEHICLE_ID, designatedVehicleId.toString()))); this.writeStartTag(SHIFT_NAME, atts); //Write break, if present diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java index a65de06b2c4..64180f24491 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/run/ShiftDrtModeOptimizerQSimModule.java @@ -92,7 +92,9 @@ public DrtShifts get() { breakSpec.getLatestBreakEndTime(), breakSpec.getDuration()); } - return new DrtShiftImpl(spec.getId(), spec.getStartTime(), spec.getEndTime(), spec.getOperationFacilityId().orElse(null), shiftBreak); + return new DrtShiftImpl(spec.getId(), spec.getStartTime(), spec.getEndTime(), + spec.getOperationFacilityId().orElse(null), spec.getDesignatedVehicleId().orElse(null), + shiftBreak); }) .collect(ImmutableMap.toImmutableMap(DrtShift::getId, s -> s)); return () -> shifts; diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShift.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShift.java index d641677cd38..24442914ba3 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShift.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShift.java @@ -3,6 +3,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Identifiable; import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacility; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import java.util.Optional; @@ -15,8 +16,6 @@ public interface DrtShift extends Identifiable { double getEndTime(); - Optional getBreak(); - boolean isStarted(); boolean isEnded(); @@ -26,4 +25,8 @@ public interface DrtShift extends Identifiable { void end(); Optional> getOperationFacilityId(); + + Optional getBreak(); + + Optional> getDesignatedVehicleId(); } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftImpl.java index 79373816104..1f929cdd574 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftImpl.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftImpl.java @@ -2,6 +2,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacility; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import java.util.Optional; @@ -15,6 +16,7 @@ public class DrtShiftImpl implements DrtShift { private final double start; private final double end; private final Id operationFacilityId; + private final Id designatedVehicleId; private final DrtShiftBreak shiftBreak; @@ -22,12 +24,13 @@ public class DrtShiftImpl implements DrtShift { private boolean ended = false; public DrtShiftImpl(Id id, double start, double end, Id operationFacilityId, - DrtShiftBreak shiftBreak) { + Id designatedVehicleId, DrtShiftBreak shiftBreak) { this.id = id; this.start = start; this.end = end; this.operationFacilityId = operationFacilityId; - this.shiftBreak = shiftBreak; + this.designatedVehicleId = designatedVehicleId; + this.shiftBreak = shiftBreak; } @Override @@ -45,6 +48,11 @@ public Optional getBreak() { return Optional.ofNullable(shiftBreak); } + @Override + public Optional> getDesignatedVehicleId() { + return Optional.ofNullable(designatedVehicleId); + } + @Override public boolean isStarted() { return started; diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecification.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecification.java index 18f877c45e3..e32ad8a8416 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecification.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecification.java @@ -3,6 +3,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Identifiable; import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacility; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import java.util.Optional; @@ -18,4 +19,6 @@ public interface DrtShiftSpecification extends Identifiable { Optional getBreak(); Optional> getOperationFacilityId(); + + Optional> getDesignatedVehicleId(); } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecificationImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecificationImpl.java index fd5a36f2501..6e0bc88b0dc 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecificationImpl.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/shift/DrtShiftSpecificationImpl.java @@ -2,6 +2,7 @@ import org.matsim.api.core.v01.Id; import org.matsim.contrib.drt.extension.operations.operationFacilities.OperationFacility; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import java.util.Optional; @@ -15,6 +16,7 @@ public class DrtShiftSpecificationImpl implements DrtShiftSpecification { private final double end; private final DrtShiftBreakSpecification shiftBreak; private final Id operationFacilityId; + private final Id designatedVehicleId; private DrtShiftSpecificationImpl(Builder builder) { this.id = builder.id; @@ -22,6 +24,7 @@ private DrtShiftSpecificationImpl(Builder builder) { this.end = builder.end; this.shiftBreak = builder.shiftBreak; this.operationFacilityId = builder.operationFacilityId; + this.designatedVehicleId = builder.designatedVehicleId; } @Override @@ -44,6 +47,11 @@ public Optional> getOperationFacilityId() { return Optional.ofNullable(operationFacilityId); } + @Override + public Optional> getDesignatedVehicleId() { + return Optional.ofNullable(designatedVehicleId); + } + @Override public Id getId() { return id; @@ -69,6 +77,7 @@ public static final class Builder { private double end; private DrtShiftBreakSpecification shiftBreak; private Id operationFacilityId; + public Id designatedVehicleId; private Builder() { } @@ -97,6 +106,10 @@ public Builder operationFacility(Id operationFacilityId) { this.operationFacilityId = operationFacilityId; return this; } + public Builder designatedVehicle(Id designatedVehicleId) { + this.designatedVehicleId = designatedVehicleId; + return this; + } public DrtShiftSpecificationImpl build() { return new DrtShiftSpecificationImpl(this); diff --git a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/ShiftsIOTest.java b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/ShiftsIOTest.java index ff5eb57ecdc..ae00d55bd16 100644 --- a/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/ShiftsIOTest.java +++ b/contribs/drt-extensions/src/test/java/org/matsim/contrib/drt/extension/operations/shifts/ShiftsIOTest.java @@ -15,6 +15,7 @@ import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftSpecification; import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftsSpecification; import org.matsim.contrib.drt.extension.operations.shifts.shift.DrtShiftsSpecificationImpl; +import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.testcases.MatsimTestUtils; /** @@ -35,6 +36,9 @@ public class ShiftsIOTest { private final Id oid1 = Id.create("op1", OperationFacility.class); private final Id oid2 = Id.create("op2", OperationFacility.class); + private final Id vehId1 = Id.create("drt1", DvrpVehicle.class); + private final Id vehId2 = Id.create("drt2", DvrpVehicle.class); + @Test void testBasicReaderWriter() { @@ -69,6 +73,7 @@ private void checkContent(DrtShiftsSpecification shiftsSpecification) { assertEquals(45000., shiftSpecification1.getEndTime(), 0); assertTrue(shiftSpecification1.getOperationFacilityId().isPresent()); assertEquals(oid1, shiftSpecification1.getOperationFacilityId().get()); + assertEquals(vehId1, shiftSpecification1.getDesignatedVehicleId().get()); assertEquals(1800., shiftSpecification1.getBreak().orElseThrow().getDuration(), 0); assertEquals(28800., shiftSpecification1.getBreak().orElseThrow().getEarliestBreakStartTime(), 0); assertEquals(32400., shiftSpecification1.getBreak().orElseThrow().getLatestBreakEndTime(), 0); @@ -80,6 +85,7 @@ private void checkContent(DrtShiftsSpecification shiftsSpecification) { assertEquals(49000., shiftSpecification2.getEndTime(), 0); assertTrue(shiftSpecification2.getOperationFacilityId().isPresent()); assertEquals(oid2, shiftSpecification2.getOperationFacilityId().get()); + assertEquals(vehId2, shiftSpecification2.getDesignatedVehicleId().get()); assertEquals(3600., shiftSpecification2.getBreak().orElseThrow().getDuration(), 0); assertEquals(29200., shiftSpecification2.getBreak().orElseThrow().getEarliestBreakStartTime(), 0); assertEquals(32800., shiftSpecification2.getBreak().orElseThrow().getLatestBreakEndTime(), 0); @@ -91,6 +97,7 @@ private void checkContent(DrtShiftsSpecification shiftsSpecification) { assertEquals(53000., shiftSpecification3.getEndTime(), 0); assertFalse(shiftSpecification3.getOperationFacilityId().isPresent()); assertEquals(Optional.empty(), shiftSpecification3.getOperationFacilityId()); + assertEquals(Optional.empty(), shiftSpecification3.getDesignatedVehicleId()); assertTrue(shiftSpecification3.getBreak().isEmpty()); } } diff --git a/contribs/drt-extensions/test/input/org/matsim/contrib/drt/extension/operations/shifts/testShifts.xml b/contribs/drt-extensions/test/input/org/matsim/contrib/drt/extension/operations/shifts/testShifts.xml index 2cb87bd3c9f..972a28788af 100644 --- a/contribs/drt-extensions/test/input/org/matsim/contrib/drt/extension/operations/shifts/testShifts.xml +++ b/contribs/drt-extensions/test/input/org/matsim/contrib/drt/extension/operations/shifts/testShifts.xml @@ -1,8 +1,8 @@ - + - + From 56e1e328320c5625e02442e5fdc3da5e677b63f4 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Mon, 19 Aug 2024 14:00:56 +0200 Subject: [PATCH 210/213] actually use designated vehicle in assignment --- .../dispatcher/DrtShiftDispatcherImpl.java | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java index 2e962edfa46..2bcebb2e8e5 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java @@ -228,33 +228,36 @@ private void assignShifts(double timeStep) { if(shift.getOperationFacilityId().isPresent()) { Verify.verify(idleVehiclesQueues.get(shift.getOperationFacilityId().get()).contains(designatedVehicle)); } + vehicle = (ShiftDvrpVehicle) designatedVehicle; } - for (ShiftEntry active : activeShifts) { - if (active.shift().getEndTime() > shift.getStartTime()) { - break; - } - if(shift.getOperationFacilityId().isPresent()) { - //we have to check that the vehicle ends the previous shift at the same facility where - //the new shift is to start. - if(active.shift().getOperationFacilityId().isPresent()) { - if(!active.shift().getOperationFacilityId().get().equals(shift.getOperationFacilityId().get())) { - continue; - } - } else { - Optional nextShiftChangeover = ShiftSchedules.getNextShiftChangeover(active.vehicle().getSchedule()); - if(nextShiftChangeover.isPresent()) { - Verify.verify(nextShiftChangeover.get().getShift().equals(active.shift())); - if(!nextShiftChangeover.get().getFacility().getId().equals(shift.getOperationFacilityId().get())) { - // there is already a shift changeover scheduled elsewhere + if(vehicle == null) { + for (ShiftEntry active : activeShifts) { + if (active.shift().getEndTime() > shift.getStartTime()) { + break; + } + if (shift.getOperationFacilityId().isPresent()) { + //we have to check that the vehicle ends the previous shift at the same facility where + //the new shift is to start. + if (active.shift().getOperationFacilityId().isPresent()) { + if (!active.shift().getOperationFacilityId().get().equals(shift.getOperationFacilityId().get())) { continue; } + } else { + Optional nextShiftChangeover = ShiftSchedules.getNextShiftChangeover(active.vehicle().getSchedule()); + if (nextShiftChangeover.isPresent()) { + Verify.verify(nextShiftChangeover.get().getShift().equals(active.shift())); + if (!nextShiftChangeover.get().getFacility().getId().equals(shift.getOperationFacilityId().get())) { + // there is already a shift changeover scheduled elsewhere + continue; + } + } } } - } - if (assignShiftToVehicleLogic.canAssignVehicleToShift(active.vehicle(), shift)) { - vehicle = active.vehicle(); - break; + if (assignShiftToVehicleLogic.canAssignVehicleToShift(active.vehicle(), shift)) { + vehicle = active.vehicle(); + break; + } } } From 9dcb7a707b30b2cc81437b9ce364b34165c536e8 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Mon, 19 Aug 2024 23:02:10 +0200 Subject: [PATCH 211/213] drt shift designated vehicle fix --- .../operations/shifts/dispatcher/DrtShiftDispatcherImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java index 2bcebb2e8e5..b021d811b3b 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/dispatcher/DrtShiftDispatcherImpl.java @@ -222,7 +222,7 @@ private void assignShifts(double timeStep) { DvrpVehicle designatedVehicle = fleet.getVehicles().get(shift.getDesignatedVehicleId().get()); Verify.verify(designatedVehicle.getSchedule().getStatus() == Schedule.ScheduleStatus.STARTED); Verify.verify(designatedVehicle instanceof ShiftDvrpVehicle); - if(!vehicle.getShifts().isEmpty()) { + if(!((ShiftDvrpVehicle) designatedVehicle).getShifts().isEmpty()) { continue; } if(shift.getOperationFacilityId().isPresent()) { From 0dfee66a495ace7ad8e185bdfa7e5455335c8a20 Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Tue, 20 Aug 2024 17:00:13 +0200 Subject: [PATCH 212/213] update (e)shift task schedulers --- .../scheduler/EShiftTaskScheduler.java | 195 +++++++++--------- .../scheduler/ShiftTaskSchedulerImpl.java | 5 +- 2 files changed, 102 insertions(+), 98 deletions(-) diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java index a87c54a1be8..9c5a7172282 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/eshifts/scheduler/EShiftTaskScheduler.java @@ -62,17 +62,17 @@ public class EShiftTaskScheduler implements ShiftTaskScheduler { private final Network network; private final ChargingInfrastructure chargingInfrastructure; - public EShiftTaskScheduler(Network network, TravelTime travelTime, TravelDisutility travelDisutility, - MobsimTimer timer, ShiftDrtTaskFactory taskFactory, ShiftsParams shiftsParams, - ChargingInfrastructure chargingInfrastructure, OperationFacilities operationFacilities, Fleet fleet) { - this.travelTime = travelTime; - this.timer = timer; - this.taskFactory = taskFactory; - this.network = network; - this.shiftsParams = shiftsParams; - this.router = new SpeedyALTFactory().createPathCalculator(network, travelDisutility, travelTime); - this.chargingInfrastructure = chargingInfrastructure; - } + public EShiftTaskScheduler(Network network, TravelTime travelTime, TravelDisutility travelDisutility, + MobsimTimer timer, ShiftDrtTaskFactory taskFactory, ShiftsParams shiftsParams, + ChargingInfrastructure chargingInfrastructure, OperationFacilities operationFacilities, Fleet fleet) { + this.travelTime = travelTime; + this.timer = timer; + this.taskFactory = taskFactory; + this.network = network; + this.shiftsParams = shiftsParams; + this.router = new SpeedyALTFactory().createPathCalculator(network, travelDisutility, travelTime); + this.chargingInfrastructure = chargingInfrastructure; + } public void relocateForBreak(ShiftDvrpVehicle vehicle, OperationFacility breakFacility, DrtShift shift) { final Schedule schedule = vehicle.getSchedule(); @@ -81,7 +81,7 @@ public void relocateForBreak(ShiftDvrpVehicle vehicle, OperationFacility breakFa final Link toLink = network.getLinks().get(breakFacility.getLinkId()); if (currentTask instanceof DriveTask && currentTask.getTaskType().equals(EmptyVehicleRelocator.RELOCATE_VEHICLE_TASK_TYPE) - && currentTask.equals(schedule.getTasks().get(schedule.getTaskCount()-2))) { + && currentTask.equals(schedule.getTasks().get(schedule.getTaskCount() - 2))) { //try to divert/cancel relocation LinkTimePair start = ((OnlineDriveTaskTracker) currentTask.getTaskTracker()).getDiversionPoint(); VrpPathWithTravelData path; @@ -112,13 +112,13 @@ public void relocateForBreak(ShiftDvrpVehicle vehicle, OperationFacility breakFa } else { final Task task = schedule.getTasks().get(schedule.getTaskCount() - 1); final Link lastLink = ((StayTask) task).getLink(); - double departureTime = task.getBeginTime(); + double departureTime = task.getBeginTime(); - // @Nico Did I change something here? - if (schedule.getCurrentTask() == task) { - departureTime = Math.max(task.getBeginTime(), timer.getTimeOfDay()); - } - if (lastLink.getId() != breakFacility.getLinkId()) { + // @Nico Did I change something here? + if (schedule.getCurrentTask() == task) { + departureTime = Math.max(task.getBeginTime(), timer.getTimeOfDay()); + } + if (lastLink.getId() != breakFacility.getLinkId()) { VrpPathWithTravelData path = VrpPaths.calcAndCreatePath(lastLink, toLink, departureTime, router, @@ -154,7 +154,7 @@ public void relocateForBreak(ShiftDvrpVehicle vehicle, OperationFacility breakFa double endTime = startTime + shift.getBreak().orElseThrow().getDuration(); double latestDetourArrival = timer.getTimeOfDay(); - relocateForBreakImpl(vehicle, startTime, endTime, latestDetourArrival, toLink, shift, breakFacility); + relocateForBreakImpl(vehicle, startTime, endTime, latestDetourArrival, toLink, shift, breakFacility); } } } @@ -165,24 +165,24 @@ private void relocateForBreakImpl(ShiftDvrpVehicle vehicle, double startTime, do Schedule schedule = vehicle.getSchedule(); // append SHIFT_BREAK task - DrtShiftBreak shiftBreak = shift.getBreak().orElseThrow(); + DrtShiftBreak shiftBreak = shift.getBreak().orElseThrow(); - ShiftBreakTask dropoffStopTask; - ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle(); - Optional charger = charge(breakFacility, ev); - if (charger.isPresent()) { + ShiftBreakTask dropoffStopTask; + ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle(); + Optional charger = charge(breakFacility, ev); + if (charger.isPresent()) { final Charger chargerImpl = charger.get(); - final double waitTime = ChargingEstimations - .estimateMaxWaitTimeForNextVehicle(chargerImpl); + final double waitTime = ChargingEstimations + .estimateMaxWaitTimeForNextVehicle(chargerImpl); - if (ev.getBattery().getCharge() / ev.getBattery().getCapacity() > shiftsParams.chargeDuringBreakThreshold || - waitTime > 0) { + if (ev.getBattery().getCharge() / ev.getBattery().getCapacity() > shiftsParams.chargeDuringBreakThreshold || + waitTime > 0) { dropoffStopTask = taskFactory.createShiftBreakTask(vehicle, startTime, endTime, link, shiftBreak, breakFacility); } else { - double energyCharge = ((BatteryCharging) ev.getChargingPower()).calcEnergyCharged(chargerImpl.getSpecification(), endTime - startTime); - double totalEnergy = -energyCharge; + double energyCharge = ((BatteryCharging) ev.getChargingPower()).calcEnergyCharged(chargerImpl.getSpecification(), endTime - startTime); + double totalEnergy = -energyCharge; ((ChargingWithAssignmentLogic) chargerImpl.getLogic()).assignVehicle(ev); dropoffStopTask = ((ShiftEDrtTaskFactoryImpl) taskFactory).createChargingShiftBreakTask(vehicle, startTime, endTime, link, shiftBreak, chargerImpl, totalEnergy, breakFacility); @@ -199,32 +199,32 @@ private void relocateForBreakImpl(ShiftDvrpVehicle vehicle, double startTime, do final double latestTimeConstraintArrival = shiftBreak.getLatestBreakEndTime() - shiftBreak.getDuration(); - shiftBreak.schedule(Math.min(latestDetourArrival, latestTimeConstraintArrival)); + shiftBreak.schedule(Math.min(latestDetourArrival, latestTimeConstraintArrival)); } private Optional charge(OperationFacility breakFacility, ElectricVehicle electricVehicle) { if (chargingInfrastructure != null) { - List> chargerIds = breakFacility.getChargers(); - if(!chargerIds.isEmpty()) { - Optional selectedCharger = chargerIds - .stream() - .map(id -> chargingInfrastructure.getChargers().get(id)) - .filter(charger -> shiftsParams.breakChargerType.equals(charger.getChargerType())) - .min((c1, c2) -> { - final double waitTime = ChargingEstimations - .estimateMaxWaitTimeForNextVehicle(c1); - final double waitTime2 = ChargingEstimations - .estimateMaxWaitTimeForNextVehicle(c2); - return Double.compare(waitTime, waitTime2); - }); - if(selectedCharger.isPresent()) { - if (selectedCharger.get().getLogic().getChargingStrategy().isChargingCompleted(electricVehicle)) { - return Optional.empty(); - } - } - return selectedCharger; - } - } + List> chargerIds = breakFacility.getChargers(); + if (!chargerIds.isEmpty()) { + Optional selectedCharger = chargerIds + .stream() + .map(id -> chargingInfrastructure.getChargers().get(id)) + .filter(charger -> shiftsParams.breakChargerType.equals(charger.getChargerType())) + .min((c1, c2) -> { + final double waitTime = ChargingEstimations + .estimateMaxWaitTimeForNextVehicle(c1); + final double waitTime2 = ChargingEstimations + .estimateMaxWaitTimeForNextVehicle(c2); + return Double.compare(waitTime, waitTime2); + }); + if (selectedCharger.isPresent()) { + if (selectedCharger.get().getLogic().getChargingStrategy().isChargingCompleted(electricVehicle)) { + return Optional.empty(); + } + } + return selectedCharger; + } + } return Optional.empty(); } @@ -234,7 +234,7 @@ public void relocateForShiftChange(DvrpVehicle vehicle, Link link, DrtShift shif final Task currentTask = schedule.getCurrentTask(); if (currentTask instanceof DriveTask && currentTask.getTaskType().equals(EmptyVehicleRelocator.RELOCATE_VEHICLE_TASK_TYPE) - && currentTask.equals(schedule.getTasks().get(schedule.getTaskCount()-2))) { + && currentTask.equals(schedule.getTasks().get(schedule.getTaskCount() - 2))) { //try to divert/cancel relocation LinkTimePair start = ((OnlineDriveTaskTracker) currentTask.getTaskTracker()).getDiversionPoint(); VrpPathWithTravelData path; @@ -317,22 +317,22 @@ private void appendShiftChange(DvrpVehicle vehicle, DrtShift shift, OperationFac // append SHIFT_CHANGEOVER task - ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle(); - Optional charger = charge(breakFacility, ev); - if (charger.isPresent()) { - Charger chargingImpl = charger.get(); + ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle(); + Optional charger = charge(breakFacility, ev); + if (charger.isPresent()) { + Charger chargingImpl = charger.get(); - final double waitTime = ChargingEstimations - .estimateMaxWaitTimeForNextVehicle(chargingImpl); + final double waitTime = ChargingEstimations + .estimateMaxWaitTimeForNextVehicle(chargingImpl); - if (ev.getBattery().getCharge() / ev.getBattery().getCapacity() < shiftsParams.chargeDuringBreakThreshold + if (ev.getBattery().getCharge() / ev.getBattery().getCapacity() < shiftsParams.chargeDuringBreakThreshold || ((ChargingWithAssignmentLogic) chargingImpl.getLogic()).getAssignedVehicles().contains(ev) - || waitTime >0) { + || waitTime > 0) { dropoffStopTask = taskFactory.createShiftChangeoverTask(vehicle, startTime, endTime, link, shift, breakFacility); } else { - double energyCharge = ((BatteryCharging) ev.getChargingPower()).calcEnergyCharged(chargingImpl.getSpecification(), endTime - startTime); - double totalEnergy = -energyCharge; + double energyCharge = ((BatteryCharging) ev.getChargingPower()).calcEnergyCharged(chargingImpl.getSpecification(), endTime - startTime); + double totalEnergy = -energyCharge; ((ChargingWithAssignmentLogic) chargingImpl.getLogic()).assignVehicle(ev); dropoffStopTask = ((ShiftEDrtTaskFactoryImpl) taskFactory).createChargingShiftChangeoverTask(vehicle, startTime, endTime, link, chargingImpl, totalEnergy, shift, breakFacility); @@ -353,9 +353,11 @@ public void startShift(ShiftDvrpVehicle vehicle, double now, DrtShift shift) { if (stayTask instanceof WaitForShiftTask) { ((WaitForShiftTask) stayTask).getFacility().deregisterVehicle(vehicle.getId()); stayTask.setEndTime(now); - if(Schedules.getLastTask(schedule).equals(stayTask)) { + if (Schedules.getLastTask(schedule).equals(stayTask)) { //nothing planned yet. schedule.addTask(taskFactory.createStayTask(vehicle, now, shift.getEndTime(), stayTask.getLink())); + } else { + Schedules.getNextTask(schedule).setBeginTime(now); } } else { throw new IllegalStateException("Vehicle cannot start shift during task:" + stayTask.getTaskType().name()); @@ -370,9 +372,9 @@ public boolean updateShiftChange(ShiftDvrpVehicle vehicle, Link link, DrtShift s VrpPathWithTravelData path = VrpPaths.calcAndCreatePath(start.link, link, Math.max(start.time, timer.getTimeOfDay()), router, travelTime); //if (path.getArrivalTime() <= shift.getEndTime()) { - updateShiftChangeImpl(vehicle, path, shift, facility, lastTask); - return true; - // } + updateShiftChangeImpl(vehicle, path, shift, facility, lastTask); + return true; + // } } return false; } @@ -381,29 +383,28 @@ public boolean updateShiftChange(ShiftDvrpVehicle vehicle, Link link, DrtShift s public void planAssignedShift(ShiftDvrpVehicle vehicle, double timeStep, DrtShift shift) { Schedule schedule = vehicle.getSchedule(); StayTask stayTask = (StayTask) schedule.getCurrentTask(); - if (stayTask instanceof WaitForShiftTask waitForShiftTask) { - if(waitForShiftTask instanceof EDrtWaitForShiftTask eDrtWaitForShiftTask) { - if(eDrtWaitForShiftTask.getChargingTask() != null) { - Task nextTask = Schedules.getNextTask(vehicle.getSchedule()); - if(nextTask instanceof WaitForShiftTask) { - // set +1 to ensure this update happens after next shift start check - nextTask.setEndTime(Math.max(timeStep + 1, shift.getStartTime())); - //append stay task if required - if(Schedules.getLastTask(schedule).equals(nextTask)) { - schedule.addTask(taskFactory.createStayTask(vehicle, nextTask.getEndTime(), shift.getEndTime(), ((WaitForShiftTask) nextTask).getLink())); - } - } else { - throw new RuntimeException(); - } - } else { - stayTask.setEndTime(Math.max(timeStep +1 , shift.getStartTime())); + if (stayTask instanceof EDrtWaitForShiftTask eDrtWaitForShiftTask) { + if (eDrtWaitForShiftTask.getChargingTask() != null) { + Task nextTask = Schedules.getNextTask(vehicle.getSchedule()); + if (nextTask instanceof WaitForShiftTask) { + // set +1 to ensure this update happens after next shift start check + nextTask.setEndTime(Math.max(timeStep + 1, shift.getStartTime())); //append stay task if required - if(Schedules.getLastTask(schedule).equals(stayTask)) { - schedule.addTask(taskFactory.createStayTask(vehicle, stayTask.getEndTime(), shift.getEndTime(), stayTask.getLink())); + if (Schedules.getLastTask(schedule).equals(nextTask)) { + schedule.addTask(taskFactory.createStayTask(vehicle, nextTask.getEndTime(), shift.getEndTime(), ((WaitForShiftTask) nextTask).getLink())); } + } else { + throw new RuntimeException(); + } + } else { + stayTask.setEndTime(Math.max(timeStep + 1, shift.getStartTime())); + //append stay task if required + if (Schedules.getLastTask(schedule).equals(stayTask)) { + schedule.addTask(taskFactory.createStayTask(vehicle, stayTask.getEndTime(), shift.getEndTime(), stayTask.getLink())); } } } + } @@ -412,10 +413,10 @@ public void cancelAssignedShift(ShiftDvrpVehicle vehicle, double timeStep, DrtSh Schedule schedule = vehicle.getSchedule(); StayTask stayTask = (StayTask) schedule.getCurrentTask(); if (stayTask instanceof WaitForShiftTask waitForShiftTask) { - if(waitForShiftTask instanceof EDrtWaitForShiftTask eDrtWaitForShiftTask) { - if(eDrtWaitForShiftTask.getChargingTask() != null) { + if (waitForShiftTask instanceof EDrtWaitForShiftTask eDrtWaitForShiftTask) { + if (eDrtWaitForShiftTask.getChargingTask() != null) { Task nextTask = Schedules.getNextTask(vehicle.getSchedule()); - if(nextTask instanceof WaitForShiftTask) { + if (nextTask instanceof WaitForShiftTask) { nextTask.setEndTime(vehicle.getServiceEndTime()); } else { throw new RuntimeException(); @@ -433,15 +434,15 @@ private void updateShiftChangeImpl(DvrpVehicle vehicle, VrpPathWithTravelData vr DrtShift shift, OperationFacility facility, Task lastTask) { Schedule schedule = vehicle.getSchedule(); - Optional oldChangeOver = ShiftSchedules.getNextShiftChangeover(schedule); - if(oldChangeOver.isPresent() && oldChangeOver.get() instanceof EDrtShiftChangeoverTaskImpl) { - if(((EDrtShiftChangeoverTaskImpl) oldChangeOver.get()).getChargingTask() != null) { - ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle(); - ((EDrtShiftChangeoverTaskImpl) oldChangeOver.get()).getChargingTask().getChargingLogic().unassignVehicle(ev); - } - } + Optional oldChangeOver = ShiftSchedules.getNextShiftChangeover(schedule); + if (oldChangeOver.isPresent() && oldChangeOver.get() instanceof EDrtShiftChangeoverTaskImpl) { + if (((EDrtShiftChangeoverTaskImpl) oldChangeOver.get()).getChargingTask() != null) { + ElectricVehicle ev = ((EvDvrpVehicle) vehicle).getElectricVehicle(); + ((EDrtShiftChangeoverTaskImpl) oldChangeOver.get()).getChargingTask().getChargingLogic().unassignVehicle(ev); + } + } - List copy = new ArrayList<>(schedule.getTasks().subList(lastTask.getTaskIdx() + 1, schedule.getTasks().size())); + List copy = new ArrayList<>(schedule.getTasks().subList(lastTask.getTaskIdx() + 1, schedule.getTasks().size())); for (Task task : copy) { schedule.removeTask(task); } @@ -449,7 +450,7 @@ private void updateShiftChangeImpl(DvrpVehicle vehicle, VrpPathWithTravelData vr ((OnlineDriveTaskTracker) lastTask.getTaskTracker()).divertPath(vrpPath); } else { //add drive to break location - lastTask.setEndTime(vrpPath.getDepartureTime()); + lastTask.setEndTime(vrpPath.getDepartureTime()); schedule.addTask(taskFactory.createDriveTask(vehicle, vrpPath, RELOCATE_VEHICLE_SHIFT_CHANGEOVER_TASK_TYPE)); // add RELOCATE } diff --git a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/scheduler/ShiftTaskSchedulerImpl.java b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/scheduler/ShiftTaskSchedulerImpl.java index 94b5c3d0fed..c2fcc1ac4ee 100644 --- a/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/scheduler/ShiftTaskSchedulerImpl.java +++ b/contribs/drt-extensions/src/main/java/org/matsim/contrib/drt/extension/operations/shifts/scheduler/ShiftTaskSchedulerImpl.java @@ -269,6 +269,8 @@ public void startShift(ShiftDvrpVehicle vehicle, double now, DrtShift shift) { if(Schedules.getLastTask(schedule).equals(stayTask)) { //nothing planned yet. schedule.addTask(taskFactory.createStayTask(vehicle, now, shift.getEndTime(), stayTask.getLink())); + } else { + Schedules.getNextTask(schedule).setBeginTime(now); } } else { throw new IllegalStateException("Vehicle cannot start shift during task:" + stayTask.getTaskType().name()); @@ -296,7 +298,8 @@ public void planAssignedShift(ShiftDvrpVehicle vehicle, double timeStep, DrtShif Schedule schedule = vehicle.getSchedule(); StayTask stayTask = (StayTask) schedule.getCurrentTask(); if (stayTask instanceof WaitForShiftTask) { - stayTask.setEndTime(Math.max(timeStep, shift.getStartTime())); + // set +1 to ensure this update happens after next shift start check + stayTask.setEndTime(Math.max(timeStep + 1, shift.getStartTime())); } } From b2f35162bf97f5eec2b5755c16f59f96fb8b2f5b Mon Sep 17 00:00:00 2001 From: nkuehnel Date: Tue, 20 Aug 2024 17:05:51 +0200 Subject: [PATCH 213/213] update (e)shift task schedulers --- .../DefaultRequestInsertionScheduler.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/contribs/drt/src/main/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionScheduler.java b/contribs/drt/src/main/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionScheduler.java index 72082906255..bab43ffc742 100644 --- a/contribs/drt/src/main/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionScheduler.java +++ b/contribs/drt/src/main/java/org/matsim/contrib/drt/scheduler/DefaultRequestInsertionScheduler.java @@ -24,6 +24,7 @@ import java.util.List; +import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.contrib.drt.optimizer.VehicleEntry; import org.matsim.contrib.drt.optimizer.Waypoint; @@ -37,6 +38,7 @@ import org.matsim.contrib.drt.stops.StopTimeCalculator; import org.matsim.contrib.dvrp.fleet.DvrpVehicle; import org.matsim.contrib.dvrp.fleet.Fleet; +import org.matsim.contrib.dvrp.path.DivertedVrpPath; import org.matsim.contrib.dvrp.path.VrpPathWithTravelData; import org.matsim.contrib.dvrp.path.VrpPaths; import org.matsim.contrib.dvrp.schedule.DriveTask; @@ -65,9 +67,9 @@ public class DefaultRequestInsertionScheduler implements RequestInsertionSchedul private final StopTimeCalculator stopTimeCalculator; private final boolean scheduleWaitBeforeDrive; - public DefaultRequestInsertionScheduler(Fleet fleet, MobsimTimer timer, - TravelTime travelTime, ScheduleTimingUpdater scheduleTimingUpdater, DrtTaskFactory taskFactory, - StopTimeCalculator stopTimeCalculator, boolean scheduleWaitBeforeDrive) { + public DefaultRequestInsertionScheduler(Fleet fleet, MobsimTimer timer, TravelTime travelTime, + ScheduleTimingUpdater scheduleTimingUpdater, DrtTaskFactory taskFactory, + StopTimeCalculator stopTimeCalculator, boolean scheduleWaitBeforeDrive) { this.timer = timer; this.travelTime = travelTime; this.scheduleTimingUpdater = scheduleTimingUpdater; @@ -143,7 +145,7 @@ private void verifyConstraints(InsertionWithDetourData insertion) { } private void verifyStructure(Schedule schedule) { - boolean previousDrive = false; + DriveTask previousDrive = null; int startIndex = schedule.getStatus().equals(ScheduleStatus.STARTED) ? schedule.getCurrentTask().getTaskIdx() : 0; @@ -151,11 +153,18 @@ private void verifyStructure(Schedule schedule) { for (int index = startIndex; index < schedule.getTaskCount(); index++) { Task task = schedule.getTasks().get(index); - if (task instanceof DriveTask) { - Verify.verify(!previousDrive); - previousDrive = true; + if (task instanceof DriveTask driveTask) { + if(previousDrive != null) { + Verify.verify(previousDrive.getPath() instanceof DivertedVrpPath, + "The first of two subsequent drive tasks has to be a diverted path."); + Id firstEnd = previousDrive.getPath().getToLink().getId(); + Id secondStart = driveTask.getPath().getFromLink().getId(); + Verify.verify(firstEnd.equals(secondStart), + String.format("Subsequent drive tasks are not connected link %s !=> %s", firstEnd.toString(), secondStart.toString())); + } + previousDrive = driveTask; } else { - previousDrive = false; + previousDrive = null; } } } @@ -343,7 +352,7 @@ private DrtStopTask insertPickup(AcceptedDrtRequest request, InsertionWithDetour } private DrtStopTask insertDropoff(AcceptedDrtRequest request, InsertionWithDetourData insertionWithDetourData, - DrtStopTask pickupTask) { + DrtStopTask pickupTask) { final double now = timer.getTimeOfDay(); var insertion = insertionWithDetourData.insertion; VehicleEntry vehicleEntry = insertion.vehicleEntry;