MATSIM
RandomizingTimeDistanceTravelDisutilityFactory.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * RandomizingTimeDistanceTravelDisutilityFactory.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2007 by the members listed in the COPYING, *
8  * LICENSE and WARRANTY file. *
9  * email : info at matsim dot org *
10  * *
11  * *********************************************************************** *
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * See also COPYING, LICENSE and WARRANTY file *
18  * *
19  * *********************************************************************** */
20 
21 package org.matsim.core.router.costcalculators;
22 
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
25 import org.matsim.core.config.Config;
29 
30 import java.util.Collections;
31 import java.util.Set;
32 import java.util.concurrent.atomic.AtomicInteger;
33 
46  private static final Logger log = LogManager.getLogger( RandomizingTimeDistanceTravelDisutilityFactory.class ) ;
47 
48  private static final AtomicInteger wrnCnt = new AtomicInteger(0);
49  private static final AtomicInteger normalisationWrnCnt = new AtomicInteger(0);
50 
51  private final String mode;
52  private final double sigma;
54 
55  public RandomizingTimeDistanceTravelDisutilityFactory( final String mode, Config config ) {
56  // NOTE: It is difficult to get rid of this constructor completely, since "mode" needs to be passed in. One could still get all other
57  // material from injection, but there are many uses of this class outside injection.
58 
59  this.mode = mode;
60  this.cnScoringGroup = config.scoring();
61  this.sigma = config.routing().getRoutingRandomness();
62  }
63 
64  @Override
66  // yyyy This here should honor subpopulations. It is really not so difficult; something like cnScoringGroup.getScoringParameters( "subpop"
67  // ).getMarginalUtilityOfMoney(); That line, or some variant of it, would need to be in the TravelDisutility directly. And I am quite unsure what is the status of
68  // the "default" subpopulation anyways ... I seem to recall that Thibaut wanted to get rid of that. The following method at least outputs
69  // a warning. However, we know by now that few people think about such warnings. kai, mar'20
70  logWarningsIfNecessary( cnScoringGroup );
71 
72  final ScoringConfigGroup.ModeParams params = cnScoringGroup.getModes().get( mode ) ;
73  if ( params == null ) {
74  throw new NullPointerException( mode+" is not part of the valid mode parameters "+cnScoringGroup.getModes().keySet() );
75  }
76 
77  /* Usually, the travel-utility should be negative (it's a disutility) but the cost should be positive. Thus negate the utility.*/
78  final double marginalCostOfTime_s = (-params.getMarginalUtilityOfTraveling() / 3600.0) + (cnScoringGroup.getPerforming_utils_hr() / 3600.0);
79  final double marginalCostOfDistance_m = - params.getMonetaryDistanceRate() * cnScoringGroup.getMarginalUtilityOfMoney()
80  - params.getMarginalUtilityOfDistance() ;
81 
82  double normalization = 1;
83  if ( sigma != 0. ) {
84  normalization = 1. / Math.exp(this.sigma * this.sigma / 2);
85  if (normalisationWrnCnt.getAndIncrement() < 10) {
86  log.info(" sigma: " + this.sigma + "; resulting normalization: " + normalization);
87  }
88  }
89 
90  return new RandomizingTimeDistanceTravelDisutility(
91  travelTime,
92  marginalCostOfTime_s,
93  marginalCostOfDistance_m,
94  normalization,
95  sigma);
96  }
97 
98  private void logWarningsIfNecessary(final ScoringConfigGroup cnScoringGroup) {
99  if ( wrnCnt.getAndIncrement() < 1 ) {
100  if ( cnScoringGroup.getModes().get( mode ).getMonetaryDistanceRate() > 0. ) {
101  log.warn("Monetary distance cost rate needs to be NEGATIVE to produce the normal " +
102  "behavior; just found positive. Continuing anyway.") ;
103  }
104 
105  final Set<String> monoSubpopKeyset = Collections.singleton( null );
106  if ( !cnScoringGroup.getScoringParametersPerSubpopulation().keySet().equals( monoSubpopKeyset ) ) {
107  log.warn( "Scoring parameters are defined for different subpopulations." +
108  " The routing disutility will only consider the ones of the default subpopulation.");
109  log.warn( "This warning can safely be ignored if disutility of traveling only depends on travel time.");
110  }
111 
112  if ( cnScoringGroup.getModes().get( mode ).getMonetaryDistanceRate() == 0. && this.sigma != 0. ) {
113  log.warn("There will be no routing randomness. The randomization of the travel disutility requires the monetary distance rate "
114  + "to be different than zero. Continuing anyway.") ;
115  }
116 
117  if ( (cnScoringGroup.getModes().get( mode ).getMarginalUtilityOfTraveling() + cnScoringGroup.getPerforming_utils_hr()) == 0. && this.sigma != 0. ) {
118  log.warn("There will be no routing randomness. The randomization of the travel disutility requires the travel time cost rate "
119  + "to be different than zero. Continuing anyway.") ;
120  }
121  }
122  }
123 
124 }
final ScoringConfigGroup scoring()
Definition: Config.java:407
RoutingConfigGroup routing()
Definition: Config.java:439
Map< String, ScoringParameterSet > getScoringParametersPerSubpopulation()