001/* *********************************************************************** * 002 * project: org.matsim.* 003 * PlanToPlanStepBasedOnEvents.java 004 * * 005 * *********************************************************************** * 006 * * 007 * copyright : (C) 2012 by the members listed in the COPYING, * 008 * LICENSE and WARRANTY file. * 009 * email : info at matsim dot org * 010 * * 011 * *********************************************************************** * 012 * * 013 * This program is free software; you can redistribute it and/or modify * 014 * it under the terms of the GNU General Public License as published by * 015 * the Free Software Foundation; either version 2 of the License, or * 016 * (at your option) any later version. * 017 * See also COPYING, LICENSE and WARRANTY file * 018 * * 019 * *********************************************************************** */ 020 021package org.matsim.contrib.cadyts.car; 022 023import java.util.HashSet; 024import java.util.Set; 025 026import javax.inject.Inject; 027 028import org.apache.log4j.Logger; 029import org.matsim.api.core.v01.Id; 030import org.matsim.api.core.v01.Scenario; 031import org.matsim.api.core.v01.TransportMode; 032import org.matsim.api.core.v01.events.LinkLeaveEvent; 033import org.matsim.api.core.v01.events.VehicleLeavesTrafficEvent; 034import org.matsim.api.core.v01.events.VehicleEntersTrafficEvent; 035import org.matsim.api.core.v01.events.handler.LinkLeaveEventHandler; 036import org.matsim.api.core.v01.events.handler.VehicleLeavesTrafficEventHandler; 037import org.matsim.api.core.v01.network.Link; 038import org.matsim.api.core.v01.events.handler.VehicleEntersTrafficEventHandler; 039import org.matsim.api.core.v01.population.Person; 040import org.matsim.api.core.v01.population.Plan; 041import org.matsim.contrib.cadyts.general.CadytsConfigGroup; 042import org.matsim.contrib.cadyts.general.PlansTranslator; 043import org.matsim.core.config.ConfigUtils; 044import org.matsim.core.events.algorithms.Vehicle2DriverEventHandler; 045 046import cadyts.demand.PlanBuilder; 047 048public final class PlansTranslatorBasedOnEvents implements PlansTranslator<Link>, LinkLeaveEventHandler, 049VehicleEntersTrafficEventHandler, VehicleLeavesTrafficEventHandler { 050 // could be/remain public as long as constructor is package-private. kai, feb'20 051 // used from outside, e.g. vsp-playgrounds 052 053 private static final Logger log = Logger.getLogger(PlansTranslatorBasedOnEvents.class); 054 055 private final Scenario scenario; 056 057 private Vehicle2DriverEventHandler delegate = new Vehicle2DriverEventHandler(); 058 059 private int iteration = -1; 060 061 // this is _only_ there for output: 062 Set<Plan> plansEverSeen = new HashSet<>(); 063 064 private static final String STR_PLANSTEPFACTORY = "planStepFactory"; 065 private static final String STR_ITERATION = "iteration"; 066 067 private final Set<Id<Link>> calibratedLinks = new HashSet<>() ; 068 069 @Inject 070 PlansTranslatorBasedOnEvents(final Scenario scenario) { 071 this.scenario = scenario; 072 Set<String> abc = ConfigUtils.addOrGetModule(scenario.getConfig(), CadytsConfigGroup.GROUP_NAME, CadytsConfigGroup.class).getCalibratedLinks(); 073 for ( String str : abc ) { 074 this.calibratedLinks.add( Id.createLinkId(str) ) ; 075 } 076 } 077 078 private long plansFound = 0; 079 private long plansNotFound = 0; 080 081 @Override 082 public final cadyts.demand.Plan<Link> getCadytsPlan(final Plan plan) { 083 @SuppressWarnings("unchecked") 084 PlanBuilder<Link> planStepFactory = (PlanBuilder<Link>) plan.getCustomAttributes().get(STR_PLANSTEPFACTORY); 085 if (planStepFactory == null) { 086 this.plansNotFound++; 087 return null; 088 } 089 this.plansFound++; 090 final cadyts.demand.Plan<Link> planSteps = planStepFactory.getResult(); 091 return planSteps; 092 } 093 094 @Override 095 public void reset(final int iteration) { 096 this.iteration = iteration; 097 098 log.warn("found " + this.plansFound + " out of " + (this.plansFound + this.plansNotFound) + " (" 099 + (100. * this.plansFound / (this.plansFound + this.plansNotFound)) + "%)"); 100 log.warn("(above values may both be at zero for a couple of iterations if multiple plans per agent all have no score)"); 101 102 delegate.reset(iteration); 103 } 104 105 @Override 106 public void handleEvent(VehicleEntersTrafficEvent event) { 107 if (event.getNetworkMode().equals(TransportMode.car)) 108 delegate.handleEvent(event); 109 } 110 111 @Override 112 public void handleEvent(VehicleLeavesTrafficEvent event) { 113 delegate.handleEvent(event); 114 } 115 116 @Override 117 public void handleEvent(LinkLeaveEvent event) { 118 119 Id<Person> driverId = delegate.getDriverOfVehicle(event.getVehicleId()); 120 121 // if it is not a car, ignore the event 122 if (driverId == null) 123 return; 124 125 // if only a subset of links is calibrated but the link is not contained, ignore the event 126 if (!calibratedLinks.contains(event.getLinkId())) 127 return; 128 129 // get the "Person" behind the id: 130 Person person = this.scenario.getPopulation().getPersons().get(driverId); 131 132 // return if the driver is not in the standard population: 133 if ( person==null ) { 134 return ; 135 } 136 // (I think that this will be ok: they will be counted, as they will be in reality. But we cannot influence them in the normal way because they are not part of normal replanning. Cadyts 137 // should still work, since it operates on all the others. kai, based on https://matsim.atlassian.net/browse/MATSIM-648, nov'18 138 139 // get the selected plan: 140 Plan selectedPlan = person.getSelectedPlan(); 141 142 // get the planStepFactory for the plan (or create one): 143 PlanBuilder<Link> tmpPlanStepFactory = getPlanStepFactoryForPlan(selectedPlan); 144 145 if (tmpPlanStepFactory != null) { 146 147 Link link = this.scenario.getNetwork().getLinks().get(event.getLinkId()); 148 149 // add the "turn" to the planStepfactory 150 tmpPlanStepFactory.addTurn(link, (int) event.getTime()); 151 } 152 } 153 154 // ################################################################################### 155 // only private functions below here (low level functionality) 156 157 private PlanBuilder<Link> getPlanStepFactoryForPlan(final Plan selectedPlan) { 158 PlanBuilder<Link> planStepFactory = null; 159 160 planStepFactory = (PlanBuilder<Link>) selectedPlan.getCustomAttributes().get(STR_PLANSTEPFACTORY); 161 Integer factoryIteration = (Integer) selectedPlan.getCustomAttributes().get(STR_ITERATION); 162 if (planStepFactory == null || factoryIteration == null || factoryIteration != this.iteration) { 163 // attach the iteration number to the plan: 164 selectedPlan.getCustomAttributes().put(STR_ITERATION, this.iteration); 165 166 // construct a new PlanBulder and attach it to the plan: 167 planStepFactory = new PlanBuilder<Link>(); 168 selectedPlan.getCustomAttributes().put(STR_PLANSTEPFACTORY, planStepFactory); 169 170 // memorize the plan as being seen: 171 this.plansEverSeen.add(selectedPlan); 172 } 173 174 return planStepFactory; 175 } 176 177}