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.measurement;
022
023import java.util.HashSet;
024import java.util.Map;
025import java.util.Set;
026import java.util.TreeMap;
027
028import org.apache.log4j.Logger;
029import org.junit.Assert;
030import org.matsim.api.core.v01.Id;
031import org.matsim.api.core.v01.Scenario;
032import org.matsim.api.core.v01.events.PersonArrivalEvent;
033import org.matsim.api.core.v01.events.PersonDepartureEvent;
034import org.matsim.api.core.v01.events.handler.PersonArrivalEventHandler;
035import org.matsim.api.core.v01.events.handler.PersonDepartureEventHandler;
036import org.matsim.api.core.v01.population.Person;
037import org.matsim.api.core.v01.population.Plan;
038import org.matsim.contrib.analysis.kai.DataMap;
039import org.matsim.contrib.analysis.kai.Databins;
040import org.matsim.contrib.cadyts.general.PlansTranslator;
041
042import cadyts.demand.PlanBuilder;
043import cadyts.measurements.SingleLinkMeasurement.TYPE;
044import cadyts.supply.SimResults;
045
046public class MeasurementListener implements PlansTranslator<Measurement>,  
047                PersonDepartureEventHandler, PersonArrivalEventHandler, SimResults<Measurement> {
048        
049        private static final long serialVersionUID = 1L;
050
051        private static final Logger log = Logger.getLogger(MeasurementListener.class);
052
053        private final Scenario scenario;
054
055        private final Map<Id<Person>,PersonDepartureEvent> driverAgents = new TreeMap<>() ;
056        
057        private int iteration = -1;
058
059        // this is _only_ there for output:
060        Set<Plan> plansEverSeen = new HashSet<>();
061
062        private static final String STR_PLANSTEPFACTORY = "planStepFactory";
063        private static final String STR_ITERATION = "iteration";
064
065        private final Measurements  measurements ;
066
067        private final Databins<Measurement> databins ;
068
069        MeasurementListener(final Scenario scenario, Measurements measurements) {
070                this.measurements = measurements ;
071                this.scenario = scenario;
072                
073                double[] dataBoundaries = new double[24] ;
074                for ( int ii=0 ; ii<dataBoundaries.length; ii++ ) {
075                        dataBoundaries[ii] = ii * 3600. ;
076                        // hourly bins, not connected to anything; this might be improved ...
077                }
078                this.databins = new Databins<Measurement>( "travel times for measurement facility at each hour" , dataBoundaries ) ;
079        }
080
081        private long plansFound = 0;
082        private long plansNotFound = 0;
083
084        @Override
085        public final cadyts.demand.Plan<Measurement> getCadytsPlan(final Plan plan) {
086                @SuppressWarnings("unchecked")
087                PlanBuilder<Measurement> planStepFactory = (PlanBuilder<Measurement>) plan.getCustomAttributes().get(STR_PLANSTEPFACTORY);
088                if (planStepFactory == null) {
089                        this.plansNotFound++;
090                        return null;
091                }
092                this.plansFound++;
093                final cadyts.demand.Plan<Measurement> planSteps = planStepFactory.getResult();
094                return planSteps;
095        }
096
097        @Override
098        public void reset(final int iteration1) {
099                this.iteration = iteration1;
100
101                log.warn("found " + this.plansFound + " out of " + (this.plansFound + this.plansNotFound) + " ("
102                                + (100. * this.plansFound / (this.plansFound + this.plansNotFound)) + "%)");
103                log.warn("(above values may both be at zero for a couple of iterations if multiple plans per agent all have no score)");
104
105                this.driverAgents.clear();
106        }
107
108        @Override
109        public void handleEvent(PersonDepartureEvent event) {
110                this.driverAgents.put(event.getPersonId(), event ) ;
111        }
112        
113        @Override
114        public void handleEvent(PersonArrivalEvent event) {
115                PersonDepartureEvent dpEvent = this.driverAgents.remove( event.getPersonId() ) ;
116                double ttime = event.getTime() - dpEvent.getTime() ;
117                
118                // the travel time determines the measurement "facility":
119                Measurement measurement = measurements.getMeasurementFromTTimeInSeconds(ttime) ;
120                
121                // the following will fill the cadyts plan:
122                // get the planStepFactory for the plan (or create one):
123                Person person = this.scenario.getPopulation().getPersons().get(event.getPersonId());
124                PlanBuilder<Measurement> tmpPlanStepFactory = getPlanStepFactoryForPlan(person.getSelectedPlan());
125                // add the measurement:
126                if (tmpPlanStepFactory != null) {
127                        // can this happen?? Maybe in early time steps???
128                                                
129                        tmpPlanStepFactory.addTurn( measurement, (int) event.getTime());
130                }
131                
132                // the following will lead to getSimValue:
133                int idx = this.databins.getIndex( dpEvent.getTime() ) ;
134                this.databins.inc( measurement, idx);
135
136        }
137
138        // ###################################################################################
139        // only private functions below here (low level functionality)
140
141        private PlanBuilder<Measurement> getPlanStepFactoryForPlan(final Plan selectedPlan) {
142
143                @SuppressWarnings("unchecked")
144                PlanBuilder<Measurement> planStepFactory = (PlanBuilder<Measurement>) selectedPlan.getCustomAttributes().get(STR_PLANSTEPFACTORY);
145
146                Integer factoryIteration = (Integer) selectedPlan.getCustomAttributes().get(STR_ITERATION);
147                if (planStepFactory == null || factoryIteration == null || factoryIteration != this.iteration) {
148                        // attach the iteration number to the plan:
149                        selectedPlan.getCustomAttributes().put(STR_ITERATION, this.iteration);
150
151                        // construct a new PlanBulder and attach it to the plan:
152                        planStepFactory = new PlanBuilder<Measurement>();
153                        selectedPlan.getCustomAttributes().put(STR_PLANSTEPFACTORY, planStepFactory);
154
155                        // memorize the plan as being seen:
156                        this.plansEverSeen.add(selectedPlan);
157                }
158
159                return planStepFactory;
160        }
161
162        @Override
163        public double getSimValue(Measurement mea, int startTime_s, int endTime_s, TYPE type) {
164                Assert.assertNotNull( mea ); 
165                return this.databins.getValue( mea, this.databins.getIndex( startTime_s ) ) ;
166        }
167
168        
169
170}