Skip to content

Commit

Permalink
Merge pull request matsim-org#860 from matsim-org/discreteModeChoiceM…
Browse files Browse the repository at this point in the history
…aintenance

DMC contrib maintenance
  • Loading branch information
kainagel authored Apr 14, 2023
2 parents 8836dfa + 61d0714 commit 008006a
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 38 deletions.
13 changes: 12 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,22 @@
<name>MATSim code examples</name>
<description>MATSim code examples</description>

<properties>
<!--stable build based on weekly (e.g. 15.0-PR2344), PR-based (e.g. 15.0-2023w01) or official (e.g. 14.0) releases -->
<matsim.version>15.0-2023w03</matsim.version>

<!-- <matsim.version>15.0-PR2369</matsim.version>-->
<!-- <matsim.version>15.0-SNAPSHOT</matsim.version>-->
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

<repositories>
<!--Note that in general repositories are not transitive, so they need to be repeated at every level where needed.-->
<!-- for accessing the parent POM -->
<repository>
<id>matsim</id>
<id>matsim </id>
<url>https://repo.matsim.org/repository/matsim</url>
</repository>
<!-- for dependencies of osm-network-reader -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

import org.matsim.api.core.v01.Scenario;
import org.matsim.api.core.v01.TransportMode;
import org.matsim.contrib.otfvis.OTFVisLiveModule;
import org.matsim.contribs.discrete_mode_choice.model.mode_availability.DefaultModeAvailability;
import org.matsim.contribs.discrete_mode_choice.modules.*;
import org.matsim.contribs.discrete_mode_choice.modules.config.DiscreteModeChoiceConfigGroup;
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.config.groups.PlanCalcScoreConfigGroup;
import org.matsim.core.config.groups.PlansCalcRouteConfigGroup;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Controler;
import org.matsim.core.controler.OutputDirectoryHierarchy.OverwriteFileSetting;
import org.matsim.core.replanning.strategies.DefaultPlanStrategiesModule;
import org.matsim.core.scenario.ScenarioUtils;
import org.matsim.core.utils.collections.CollectionUtils;

Expand All @@ -19,8 +23,9 @@ public final class RunDiscreteModeChoiceExample{
// The code below works with v14 since approx jun'21. kai

public static void main ( String [] args ) {

args = new String [] {"scenarios/equil/config.xml"};
if ( args==null || args.length==0 ){
args = new String[]{"scenarios/equil/config.xml"};
}

Config config = ConfigUtils.loadConfig( args );

Expand All @@ -29,52 +34,59 @@ public static void main ( String [] args ) {
config.controler().setLastIteration( 2 );

String modeB = "modeB";
final String[] modes = {TransportMode.car, modeB};
String modeC = "modeC";
final String[] modes = {TransportMode.car, modeB, modeC};

// we have to do this ugly cast because TeleportedModeParams extends ModeParams and the setter methods are part
// of ModeParams and the return signature is ModeParams :-/ . This has to be changed in the Config Group itself
var paramB = (PlansCalcRouteConfigGroup.TeleportedModeParams) new PlansCalcRouteConfigGroup.TeleportedModeParams(modeB).setTeleportedModeSpeed(10.);
var paramWalk = (PlansCalcRouteConfigGroup.TeleportedModeParams) new PlansCalcRouteConfigGroup.TeleportedModeParams(TransportMode.walk)
.setTeleportedModeSpeed(4./3.6);
config.plansCalcRoute().addTeleportedModeParams( new PlansCalcRouteConfigGroup.TeleportedModeParams(modeB).setTeleportedModeSpeed(10. ) );
config.plansCalcRoute().addTeleportedModeParams( new PlansCalcRouteConfigGroup.TeleportedModeParams(modeC).setTeleportedModeSpeed(10. ) );
config.plansCalcRoute().addTeleportedModeParams( new PlansCalcRouteConfigGroup.TeleportedModeParams(TransportMode.walk).setTeleportedModeSpeed(4./3.6 ) );

config.plansCalcRoute().addTeleportedModeParams(paramB);
config.plansCalcRoute().addTeleportedModeParams(paramWalk);
config.planCalcScore().addModeParams( new PlanCalcScoreConfigGroup.ModeParams( modeB ).setConstant( 13. ) );
config.planCalcScore().addModeParams( new PlanCalcScoreConfigGroup.ModeParams( modeC ).setConstant( 12. ) );

// the following is first inlined and then adapted from DiscreteModeChoiceConfigurator.configureAsSubtourModeChoiceReplacement( config );
config.strategy().addStrategySettings( new StrategySettings().setStrategyName( DiscreteModeChoiceModule.STRATEGY_NAME ).setWeight( 0.1 ) );
config.strategy().addStrategySettings( new StrategySettings().setStrategyName( DiscreteModeChoiceModule.STRATEGY_NAME ).setWeight( 1. ) );
{
DiscreteModeChoiceConfigGroup dmcConfig = ConfigUtils.addOrGetModule( config, DiscreteModeChoiceConfigGroup.class );

dmcConfig.setCachedModes( CollectionUtils.stringArrayToSet( modes ) );
// (I think that this is only a hint to the computation, influencing performance, but not behavior. kai, jun'21)

dmcConfig.getSubtourConstraintConfig().setConstrainedModes( CollectionUtils.stringArrayToSet( modes ) );
// (These are, I think, the chain-based modes. kai, jun'21)

dmcConfig.getVehicleTourConstraintConfig().setRestrictedModes( CollectionUtils.stringArrayToSet( modes ) );
// (yy I don't know the difference to the subtour constraint. kai, jun'21)

dmcConfig.setModelType( ModelModule.ModelType.Tour );
// (yy I assume that this means that the algorithm is working at the tour level. As opposed to trip level. kai, jun'21)

dmcConfig.setSelector( SelectorModule.RANDOM );
// (yyyy I don't know what this does. kai, jun'21)

dmcConfig.setTourConstraints( CollectionUtils.stringArrayToSet( new String[]{ConstraintModule.VEHICLE_CONTINUITY, ConstraintModule.SUBTOUR_MODE} ) );
// (yyyy I don't know what this does. kai, jun'21)
{ // material that is only relevant if ModelType=Tour:
// (Means that the algo makes choices for each tour, configured below. As opposed to making choices for each trip.)
dmcConfig.setTourFinder( TourFinderModule.PLAN_BASED );
// (A tour is something that returns to its starting point, but this still leaves several options. "PLAN_BASED" means the
// whole plan is considered as the tour ((what happens if it does not return to its starting location?)); there is also
// "HOME_BASED" and "ACTIVITY_BASED" (trips starting from a certain activity type).)
// dmcConfig.setTourConstraints( CollectionUtils.stringArrayToSet( new String[]{ConstraintModule.VEHICLE_CONTINUITY, ConstraintModule.SUBTOUR_MODE} ) );
dmcConfig.setTourConstraints( CollectionUtils.stringArrayToSet( new String[]{ConstraintModule.VEHICLE_CONTINUITY} ) );
// (This sets the constraints explicitly. Can be configured with the next two options. Since backwards compatibility
// with the old subtour mode choice behavior is not important for us, we remove the related constraint.)
{
dmcConfig.getVehicleTourConstraintConfig().setRestrictedModes( CollectionUtils.stringArrayToSet( new String[]{TransportMode.car } ) );
// (config group for VehicleTourConstraint. Vehicles in these modes need to be conserved.)

// dmcConfig.getSubtourConstraintConfig().setConstrainedModes( CollectionUtils.stringArrayToSet( modes ) );
// (config group for SubtourModeConstraint, which needs to be activated above for this here to have effect.
// For modes listed here, the whole subtour has to use the same mode. This is mostly for backwards
// compatibility, since this is the behavior of the old subtour mode choice.)
}
}
dmcConfig.setSelector( SelectorModule.MULTINOMIAL_LOGIT );
// (This selects between the alternatives. Only "MULTINOMIAL_LOGIT" will actually use a logic model; "RANDOM" selects randomly
// between the candidates, and "MAXIMUM" returns the best alternative. "RANDOM" is what subtour mode choice does.)

dmcConfig.setTourEstimator( EstimatorModule.MATSIM_DAY_SCORING );
// (yyyy I don't know what this does. kai, jun'21)

dmcConfig.setTourFinder( TourFinderModule.PLAN_BASED );
// (yyyy I don't know what this does. kai, jun'21)

dmcConfig.setModeAvailability( ModeAvailabilityModule.DEFAULT );
// (do not consider car availability. If one looks into the code, this is in fact cleverly programmed as a replacable guice binding.)

dmcConfig.getDefaultModeAvailabilityConfig().setAvailableModes( CollectionUtils.stringArrayToSet( modes ) );
// (to configure the "detault" mode availability. Don't know what it does. Presumably configures the modes between which can be switched. kai, jun'21)
// (The estimator that is used to come up with utilities for the mode choice.)
{
dmcConfig.setModeAvailability( ModeAvailabilityModule.DEFAULT );
// (do not consider car availability. If one looks into the code, this is in fact cleverly programmed as a user-replaceable guice binding.)

dmcConfig.getDefaultModeAvailabilityConfig().setAvailableModes( CollectionUtils.stringArrayToSet( new String[]{TransportMode.car, modeB, modeC } ) );
// (_If_ default mode availability is configured above, this configures which modes this will include. Other modes will not
// be considered. So if one removes modeC above, it will no longer be considered.)
}
}

Scenario scenario = ScenarioUtils.loadScenario( config );
Expand All @@ -83,6 +95,15 @@ public static void main ( String [] args ) {

controler.addOverridingModule( new DiscreteModeChoiceModule() );

// controler.addOverridingModule( new AbstractModule(){
// @Override public void install(){
// bindModeAvailability(DEFAULT).to( DefaultModeAvailability.class );
//;
// }
// } )

// controler.addOverridingModule( new OTFVisLiveModule() );

controler.run() ;

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,58 @@

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.population.Person;
import org.matsim.api.core.v01.population.Population;
import org.matsim.codeexamples.RunAbcSimpleExample;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.events.EventsUtils;
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.utils.io.IOUtils;
import org.matsim.examples.ExamplesUtils;
import org.matsim.testcases.MatsimTestUtils;

import static org.junit.Assert.fail;

public class RunDiscreteModeChoiceExampleTest{
private static final Logger log = LogManager.getLogger( RunDiscreteModeChoiceExampleTest.class );
@Rule public MatsimTestUtils utils = new MatsimTestUtils();

@Test
// @Ignore // this works with with 14.x since approx jun. kai, jun'21
public void main(){
RunDiscreteModeChoiceExample.main(null);
public void testMain(){

try{
RunDiscreteModeChoiceExample.main( new String []{ IOUtils.extendUrl( ExamplesUtils.getTestScenarioURL( "equil" ), "config.xml" ).toString()
, "--config:controler.outputDirectory=" + utils.getOutputDirectory()
, "--config:controler.lastIteration=2"
} );
{
String expected = utils.getInputDirectory() + "/output_events.xml.gz" ;
String actual = utils.getOutputDirectory() + "/output_events.xml.gz" ;
EventsUtils.compareEventsFiles( expected, actual );
}
{
final Population expected = PopulationUtils.createPopulation( ConfigUtils.createConfig() );
PopulationUtils.readPopulation( expected, utils.getInputDirectory() + "/output_plans.xml.gz" );
final Population actual = PopulationUtils.createPopulation( ConfigUtils.createConfig() );
PopulationUtils.readPopulation( actual, utils.getOutputDirectory() + "/output_plans.xml.gz" );
PopulationUtils.comparePopulations( expected, actual ) ;

for( Person expectedPerson : expected.getPersons().values() ){
Person actualPerson = actual.getPersons().get( Id.createPersonId( expectedPerson.getId() ) );
Assert.assertEquals( expectedPerson.getSelectedPlan().getScore(), actualPerson.getSelectedPlan().getScore() );
}
}


} catch ( Exception ee ) {
log.fatal(ee) ;
fail() ;
}

}
}
Binary file not shown.
Binary file not shown.

0 comments on commit 008006a

Please sign in to comment.