001package org.matsim.contrib.carsharing.manager; 002 003import java.util.ArrayList; 004import java.util.List; 005 006import org.matsim.api.core.v01.Id; 007import org.matsim.api.core.v01.network.Link; 008import org.matsim.api.core.v01.network.Network; 009import org.matsim.api.core.v01.population.Activity; 010import org.matsim.api.core.v01.population.Leg; 011import org.matsim.api.core.v01.population.Person; 012import org.matsim.api.core.v01.population.Plan; 013import org.matsim.api.core.v01.population.PlanElement; 014import org.matsim.contrib.carsharing.events.NoVehicleCarSharingEvent; 015import org.matsim.contrib.carsharing.events.StartRentalEvent; 016import org.matsim.contrib.carsharing.manager.demand.CurrentTotalDemand; 017import org.matsim.contrib.carsharing.manager.demand.VehicleChoiceAgent; 018import org.matsim.contrib.carsharing.manager.routers.RouterProvider; 019import org.matsim.contrib.carsharing.manager.supply.CarsharingSupplyInterface; 020import org.matsim.contrib.carsharing.manager.supply.CompanyAgent; 021import org.matsim.contrib.carsharing.manager.supply.CompanyContainer; 022import org.matsim.contrib.carsharing.manager.supply.OneWayContainer; 023import org.matsim.contrib.carsharing.manager.supply.TwoWayContainer; 024import org.matsim.contrib.carsharing.manager.supply.VehiclesContainer; 025import org.matsim.contrib.carsharing.models.ChooseTheCompany; 026import org.matsim.contrib.carsharing.models.ChooseVehicleType; 027import org.matsim.contrib.carsharing.models.KeepingTheCarModel; 028import org.matsim.contrib.carsharing.router.CarsharingRoute; 029import org.matsim.contrib.carsharing.stations.CarsharingStation; 030import org.matsim.contrib.carsharing.vehicles.CSVehicle; 031import org.matsim.contrib.carsharing.vehicles.StationBasedVehicle; 032import org.matsim.core.api.experimental.events.EventsManager; 033import org.matsim.core.controler.events.IterationStartsEvent; 034import org.matsim.core.controler.listener.IterationStartsListener; 035 036import com.google.inject.Inject; 037import com.google.inject.name.Named; 038 039/** 040 * Class containing all the information about carsharing supply and demand. 041 * 042 * @author balac 043 */ 044public class CarsharingManagerNew implements CarsharingManagerInterface, IterationStartsListener { 045 046 @Inject 047 @Named("carnetwork") 048 private Network network; 049 @Inject 050 private CurrentTotalDemand currentDemand; 051 @Inject 052 private KeepingTheCarModel keepTheCarModel; 053 @Inject 054 private ChooseTheCompany chooseCompany; 055 @Inject 056 private ChooseVehicleType chooseVehicleType; 057 @Inject 058 private CarsharingSupplyInterface carsharingSupplyContainer; 059 @Inject 060 private EventsManager eventsManager; 061 @Inject 062 private RouterProvider routerProvider; 063 @Inject 064 private VehicleChoiceAgent vehicleChoiceAgent; 065 066 @Override 067 public List<PlanElement> reserveAndrouteCarsharingTrip(final Plan plan, String carsharingType, Leg legToBeRouted, Double time) { 068 Person person = plan.getPerson(); 069 Link startLink = network.getLinks().get(legToBeRouted.getRoute().getStartLinkId()); 070 Link destinationLink = network.getLinks().get(legToBeRouted.getRoute().getEndLinkId()); 071 072 // === get the vehicle for the trip if the agent has it already === 073 CSVehicle vehicle = getVehicleAtLocation(startLink, plan.getPerson(), carsharingType); 074 075 boolean willHaveATripFromLocation = willUseTheVehicleLaterFromLocation(destinationLink.getId(), plan, 076 legToBeRouted); 077 double durationOfNextActivity = getDurationOfNextActivity(plan, legToBeRouted, time); 078 boolean keepTheCar; 079 if (((CarsharingRoute) legToBeRouted.getRoute()).isOldRoute()) 080 keepTheCar = ((CarsharingRoute) legToBeRouted.getRoute()).isKeepthecar(); 081 else 082 keepTheCar = keepTheCarModel.keepTheCarDuringNextActivity(durationOfNextActivity, plan.getPerson(), 083 carsharingType); 084 // TODO: create a method for getting the search distance 085 double searchDistance = 1000.0; 086 if (vehicle != null) { 087 088 if ((willHaveATripFromLocation && keepTheCar) 089 || (willHaveATripFromLocation && carsharingType.equals("twoway"))) { 090 ((CarsharingRoute) legToBeRouted.getRoute()).setKeepthecar(true); 091 return this.routerProvider.routeCarsharingTrip(plan, time, legToBeRouted, carsharingType, vehicle, 092 startLink, destinationLink, true, true); 093 } else { 094 095 if (carsharingType.equals("oneway")) { 096 097 CompanyContainer companyContainer = this.carsharingSupplyContainer 098 .getCompany(vehicle.getCompanyId()); 099 VehiclesContainer vehiclesContainer = companyContainer.getVehicleContainer(carsharingType); 100 Link parkingLocation = vehiclesContainer.findClosestAvailableParkingLocation(destinationLink, 101 searchDistance); 102 103 if (parkingLocation == null) 104 return null; 105 destinationLink = parkingLocation; 106 vehiclesContainer.reserveParking(destinationLink); 107 108 } else if (carsharingType.equals("twoway")) { 109 CarsharingStation parkingStation = ((TwoWayContainer) this.carsharingSupplyContainer 110 .getCompany(vehicle.getCompanyId()).getVehicleContainer(carsharingType)) 111 .getTwowaycarsharingstationsMap() 112 .get(((StationBasedVehicle) vehicle).getStationId()); 113 destinationLink = parkingStation.getLink(); 114 } 115 116 return this.routerProvider.routeCarsharingTrip(plan, time, legToBeRouted, carsharingType, vehicle, 117 startLink, destinationLink, false, true); 118 } 119 } else { 120 121 // === agent does not hold the vehicle, therefore must find a one 122 // from the supply side=== 123 // === here he chooses the company, type of vehicle and in the end 124 // vehicle === 125 // === possibly this could be moved to one method which decides 126 // based on the supply which vehicle to take 127 String typeOfVehicle = chooseVehicleType.getPreferredVehicleType(plan, legToBeRouted); 128 // CompanyAgent companyAgent = 129 // this.carsharingSupplyContainer.getCompanyAgents(). 130 // get(((CarsharingRoute)legToBeRouted.getRoute()).getCompany()); 131 List<CSVehicle> offeredVehicles = new ArrayList<>(); 132 for (CompanyAgent companyAgent : this.carsharingSupplyContainer.getCompanyAgents().values()) { 133 134 CSVehicle offeredVehicle = companyAgent.vehicleRequest(person.getId(), startLink, destinationLink, 135 carsharingType, typeOfVehicle); 136 137 if (offeredVehicle != null) 138 offeredVehicles.add(offeredVehicle); 139 } 140 141 if (offeredVehicles.size() == 0) { 142 eventsManager.processEvent( 143 new NoVehicleCarSharingEvent(time, carsharingType, "", startLink, destinationLink)); 144 145 return null; 146 } 147 148 // TODO: offer the possible cars to the agent, from which the agent 149 // can choose 150 CSVehicle chosenVehicle = vehicleChoiceAgent.chooseVehicle(offeredVehicles, startLink, legToBeRouted, time, 151 plan.getPerson()); 152 153 if (chosenVehicle == null) { 154 eventsManager.processEvent( 155 new NoVehicleCarSharingEvent(time, carsharingType, "", startLink, destinationLink)); 156 157 return null; 158 } else { 159 160 CompanyContainer companyContainer = this.carsharingSupplyContainer 161 .getCompany(chosenVehicle.getCompanyId()); 162 VehiclesContainer vehiclesContainer = companyContainer.getVehicleContainer(carsharingType); 163 Link stationLink = vehiclesContainer.getVehicleLocation(chosenVehicle); 164 165 if (false == companyContainer.reserveVehicle(chosenVehicle)) { 166 eventsManager.processEvent(new NoVehicleCarSharingEvent(time, carsharingType, 167 chosenVehicle.getCompanyId(), startLink, destinationLink)); 168 169 return null; 170 } 171 172 eventsManager.processEvent(new StartRentalEvent(time, carsharingType, chosenVehicle.getCompanyId(), 173 startLink, stationLink, destinationLink, person.getId(), chosenVehicle.getVehicleId())); 174 175 if ((willHaveATripFromLocation && keepTheCar) 176 || (willHaveATripFromLocation && carsharingType.equals("twoway"))) { 177 ((CarsharingRoute) legToBeRouted.getRoute()).setKeepthecar(true); 178 179 return this.routerProvider.routeCarsharingTrip(plan, time, legToBeRouted, carsharingType, 180 chosenVehicle, stationLink, destinationLink, true, false); 181 } else { 182 if ((carsharingType.equals("oneway")) || (carsharingType.equals("freefloating"))) { 183 Link parkingStationLink = this.carsharingSupplyContainer.findClosestAvailableParkingSpace( 184 destinationLink, carsharingType, chosenVehicle.getCompanyId(), searchDistance); 185 if (parkingStationLink == null) 186 return null; 187 188 vehiclesContainer.reserveParking(parkingStationLink); 189 190 destinationLink = parkingStationLink; 191 } 192 193 return this.routerProvider.routeCarsharingTrip(plan, time, legToBeRouted, carsharingType, 194 chosenVehicle, stationLink, destinationLink, false, false); 195 } 196 197 } 198 199 } 200 } 201 202 private double getDurationOfNextActivity(Plan plan, Leg legToBeRouted, double time) { 203 204 int index = plan.getPlanElements().indexOf(legToBeRouted); 205 206 Activity a = (Activity) plan.getPlanElements().get(index + 1); 207 208 //return a.getEndTime() - time > 0.0 ? a.getEndTime() - time : 0.0; 209 return a.getEndTime().isUndefined() ? 0 : a.getEndTime().seconds() - time; 210 } 211 212 private boolean willUseTheVehicleLaterFromLocation(Id<Link> linkId, Plan plan, Leg currentLeg) { 213 boolean willUseVehicle = false; 214 215 String mode = currentLeg.getMode(); 216 List<PlanElement> planElements = plan.getPlanElements(); 217 218 int index = planElements.indexOf(currentLeg) + 1; 219 220 for (int i = index; i < planElements.size(); i++) { 221 222 if (planElements.get(i) instanceof Leg) { 223 224 if (((Leg) planElements.get(i)).getMode().equals(mode)) { 225 226 if (((Leg) planElements.get(i)).getRoute().getStartLinkId().toString().equals(linkId.toString())) { 227 228 willUseVehicle = true; 229 } 230 } 231 } 232 } 233 return willUseVehicle; 234 } 235 236 private CSVehicle getVehicleAtLocation(Link currentLink, Person person, String carsharingType) { 237 238 return this.currentDemand.getVehicleOnLink(person.getId(), currentLink, carsharingType); 239 240 } 241 242 @Override 243 public void freeParkingSpot(String vehicleId, Id<Link> linkId) { 244 245 CSVehicle vehicle = this.carsharingSupplyContainer.getVehicleWithId(vehicleId); 246 CompanyContainer companyContainer = this.carsharingSupplyContainer.getCompany(vehicle.getCompanyId()); 247 VehiclesContainer vehiclesContainer = companyContainer.getVehicleContainer(vehicle.getCsType()); 248 249 ((OneWayContainer) vehiclesContainer).freeParkingSpot(vehicle); 250 } 251 252 @Override 253 public boolean parkVehicle(String vehicleId, Id<Link> linkId) { 254 CSVehicle vehicle = this.carsharingSupplyContainer.getVehicleWithId(vehicleId); 255 Link link = network.getLinks().get(linkId); 256 this.carsharingSupplyContainer.getCompany(vehicle.getCompanyId()).parkVehicle(vehicle, link); 257 return false; 258 } 259 260 @Override 261 public void notifyIterationStarts(IterationStartsEvent event) { 262 this.carsharingSupplyContainer.populateSupply(); 263 this.currentDemand.reset(); 264 } 265}