Skip to content

Commit

Permalink
feat: define which EV to charge during activities
Browse files Browse the repository at this point in the history
  • Loading branch information
tschlenther committed Feb 19, 2024
1 parent 45dd481 commit 65bbbe7
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 81 deletions.
34 changes: 3 additions & 31 deletions contribs/vsp/src/main/java/playground/vsp/ev/UrbanEVModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

package playground.vsp.ev;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.matsim.contrib.ev.EvModule;
import org.matsim.contrib.ev.charging.ChargingModule;
import org.matsim.contrib.ev.discharging.DischargingModule;
Expand All @@ -31,9 +33,6 @@
import org.matsim.core.config.groups.ScoringConfigGroup;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.mobsim.qsim.AbstractQSimModule;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.matsim.core.mobsim.qsim.components.QSimComponentsConfigGroup;

public class UrbanEVModule extends AbstractModule {
Expand All @@ -47,13 +46,6 @@ public class UrbanEVModule extends AbstractModule {
QSimComponentsConfigGroup qsimComponentsConfig = ConfigUtils.addOrGetModule( config, QSimComponentsConfigGroup.class );
qsimComponentsConfig.addActiveComponent( EvModule.EV_COMPONENT );

// UrbanEVConfigGroup urbanEVConfig = ConfigUtils.addOrGetModule( config, UrbanEVConfigGroup.class );

// if (urbanEVConfig == null)
// throw new IllegalArgumentException(
// "no config group of type " + UrbanEVConfigGroup.GROUP_NAME + " was specified in the config");
// was this meaningful? I.e. do we want the code to fail if there is no such config group? kai, apr'23

//standard EV stuff
install(new ChargingInfrastructureModule());
install(new ChargingModule());
Expand All @@ -62,7 +54,6 @@ public class UrbanEVModule extends AbstractModule {
install(new ElectricFleetModule());

//bind custom EVFleet stuff
// bind(ElectricFleetUpdater.class).in(Singleton.class);
addControlerListenerBinding().to(ElectricFleetUpdater.class).in( Singleton.class );
// (this takes the matsim modal vehicles for each leg and gives them to the ElectricFleetSpecification. Don't know why it has to be in
// this ad-hoc way. kai, apr'23)
Expand All @@ -74,21 +65,14 @@ protected void configureQSim() {
// bind(UrbanVehicleChargingHandler.class);
addMobsimScopeEventHandlerBinding().to(UrbanVehicleChargingHandler.class);
// (I think that this takes the plugin/plugout activities, and actually initiates the charging. kai, apr'23)
// yes it does, just like the regular VehicleChargingHandler in the ev contrib. schlenther, feb'24.
}
});

//bind urban ev planning stuff
addMobsimListenerBinding().to(UrbanEVTripsPlanner.class);
// (I think that this inserts the charging activities just before the mobsim starts (i.e. it is not in the plans). kai, apr'23)

//TODO find a better solution for this yyyy yes. We do not want automagic. kai, apr'23 done. kai, apr'23
// Collection<String> whileChargingActTypes = urbanEVConfig.getWhileChargingActivityTypes().isEmpty() ?
// config.planCalcScore().getActivityTypes() :
// urbanEVConfig.getWhileChargingActivityTypes();

// bind(ActivityWhileChargingFinder.class).toInstance(new ActivityWhileChargingFinder(whileChargingActTypes,
// urbanEVConfig.getMinWhileChargingActivityDuration_s()));

bind( ActivityWhileChargingFinder.class ).in( Singleton.class );

//bind custom analysis:
Expand All @@ -98,16 +82,4 @@ protected void configureQSim() {
addControlerListenerBinding().to(ActsWhileChargingAnalyzer.class);
}

// private Set<String> getOpenBerlinActivityTypes() {
// Set<String> activityTypes = new HashSet<>();
// for (long ii = 600; ii <= 97200; ii += 600) {
// activityTypes.add("home_" + ii + ".0");
// activityTypes.add("work_" + ii + ".0");
// activityTypes.add("leisure_" + ii + ".0");
// activityTypes.add("shopping_" + ii + ".0");
// activityTypes.add("other_" + ii + ".0");
// }
// return activityTypes;
// }

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,12 @@

package playground.vsp.ev;

import static java.util.stream.Collectors.*;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
import com.sun.istack.Nullable;
import jakarta.inject.Provider;

import one.util.streamex.StreamEx;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.logging.log4j.LogManager;
Expand All @@ -43,18 +35,16 @@
import org.matsim.api.core.v01.TransportMode;
import org.matsim.api.core.v01.network.Link;
import org.matsim.api.core.v01.network.Network;
import org.matsim.api.core.v01.population.Activity;
import org.matsim.api.core.v01.population.Leg;
import org.matsim.api.core.v01.population.Person;
import org.matsim.api.core.v01.population.Plan;
import org.matsim.api.core.v01.population.PlanElement;
import org.matsim.api.core.v01.population.PopulationFactory;
import org.matsim.api.core.v01.population.*;
import org.matsim.contrib.common.util.StraightLineKnnFinder;
import org.matsim.contrib.ev.charging.ChargingLogic;
import org.matsim.contrib.ev.charging.ChargingPower;
import org.matsim.contrib.ev.discharging.AuxEnergyConsumption;
import org.matsim.contrib.ev.discharging.DriveEnergyConsumption;
import org.matsim.contrib.ev.fleet.*;
import org.matsim.contrib.ev.fleet.ElectricFleetSpecification;
import org.matsim.contrib.ev.fleet.ElectricFleetUtils;
import org.matsim.contrib.ev.fleet.ElectricVehicle;
import org.matsim.contrib.ev.fleet.ElectricVehicleSpecification;
import org.matsim.contrib.ev.infrastructure.ChargerSpecification;
import org.matsim.contrib.ev.infrastructure.ChargingInfrastructureSpecification;
import org.matsim.core.config.Config;
Expand All @@ -69,11 +59,7 @@
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.population.PopulationUtils;
import org.matsim.core.population.routes.NetworkRoute;
import org.matsim.core.router.LinkWrapperFacility;
import org.matsim.core.router.SingleModeNetworksCache;
import org.matsim.core.router.StageActivityTypeIdentifier;
import org.matsim.core.router.TripRouter;
import org.matsim.core.router.TripStructureUtils;
import org.matsim.core.router.*;
import org.matsim.core.router.util.TravelTime;
import org.matsim.core.utils.misc.OptionalTime;
import org.matsim.core.utils.timing.TimeInterpretation;
Expand All @@ -82,15 +68,15 @@
import org.matsim.utils.objectattributes.attributable.AttributesImpl;
import org.matsim.vehicles.Vehicle;
import org.matsim.vehicles.VehicleUtils;
import org.matsim.vehicles.Vehicles;
import org.matsim.withinday.utils.EditPlans;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
import com.sun.istack.Nullable;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

import one.util.streamex.StreamEx;
import static java.util.stream.Collectors.*;

class UrbanEVTripsPlanner implements MobsimInitializedListener {

Expand All @@ -100,9 +86,6 @@ class UrbanEVTripsPlanner implements MobsimInitializedListener {
@Inject
Scenario scenario;

@Inject
Vehicles vehicles;

@Inject
private SingleModeNetworksCache singleModeNetworksCache;

Expand Down Expand Up @@ -151,9 +134,10 @@ public void notifyMobsimInitialized(MobsimInitializedEvent e) {
if (!(e.getQueueSimulation() instanceof QSim)) {
throw new IllegalStateException(UrbanEVTripsPlanner.class + " only works with a mobsim of type " + QSim.class);
}
UrbanEVConfigGroup configGroup = (UrbanEVConfigGroup)config.getModules().get(UrbanEVConfigGroup.GROUP_NAME);
//collect all selected plans that contain ev legs and map them to the set of ev used
Map<Plan, Set<Id<Vehicle>>> selectedEVPlans = StreamEx.of(scenario.getPopulation().getPersons().values())
.mapToEntry(p -> p.getSelectedPlan(), p -> getUsedEV(p.getSelectedPlan()))
.mapToEntry(p -> p.getSelectedPlan(), p -> getUsedEVToPreplan(p.getSelectedPlan()))
.filterValues(evSet -> !evSet.isEmpty())
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));

Expand All @@ -169,16 +153,17 @@ public void notifyMobsimInitialized(MobsimInitializedEvent e) {
* @param plan
* @return
*/
private Set<Id<Vehicle>> getUsedEV(Plan plan) {
private Set<Id<Vehicle>> getUsedEVToPreplan(Plan plan) {
return TripStructureUtils.getLegs(plan)
.stream()
.map(leg -> VehicleUtils.getVehicleId(plan.getPerson(), leg.getMode()))
.filter(vehicleId -> isEV(vehicleId))
.filter(vehicleId -> isEVAndToBeChargedWhileActivities(vehicleId))
.collect(toSet());
}

private boolean isEV(Id<Vehicle> vehicleId) {
return this.electricFleetSpecification.getVehicleSpecifications().containsKey(Id.create(vehicleId, Vehicle.class));
private boolean isEVAndToBeChargedWhileActivities(Id<Vehicle> vehicleId) {
ElectricVehicleSpecification ev = this.electricFleetSpecification.getVehicleSpecifications().getOrDefault(Id.create(vehicleId, Vehicle.class), null);
return (ev != null && UrbanEVUtils.isChargingDuringActivities(ev));
}

private void processPlans(Map<Plan, Set<Id<Vehicle>>> selectedEVPlans) {
Expand Down
67 changes: 67 additions & 0 deletions contribs/vsp/src/main/java/playground/vsp/ev/UrbanEVUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* *********************************************************************** *
* project: org.matsim.*
* Controler.java
* *
* *********************************************************************** *
* *
* copyright : (C) 2007 by the members listed in the COPYING, *
* LICENSE and WARRANTY file. *
* email : info at matsim dot org *
* *
* *********************************************************************** *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* See also COPYING, LICENSE and WARRANTY file *
* *
* *********************************************************************** */

package playground.vsp.ev;

import org.matsim.contrib.ev.fleet.ElectricVehicleSpecification;
import org.matsim.vehicles.Vehicle;

public final class UrbanEVUtils {

public static final String PLAN_CHARGING_DURING_ACTS_ATTRIBUTE_NAME = "planChargingDuringActivities";

/**
* Checks whether {@code electricVehicleSpecification} should be charged during the drivers' activities. <br>
* If this is the case, [@code {@link UrbanEVTripsPlanner} will pre-plan charging according to the driver's selected plan. <br>
* <p>
* Checks for the corresponding attribute with key={@code PLAN_CHARGING_DURING_ACTS_ATTRIBUTE_NAME} in the MATSim input vehicle.
* <b>If the attribute was not provided, true is returned!</b>
* This means that by default, <i>all</i> electricVehicleSpecifications are planned to get charged during activities and not during trips
* (planning for the latter is done by {@code org.matsim.contrib.ev.routing.EVNetworkRoutingModule}.
* </p>
* @param electricVehicleSpecification
* @return
*/
public static boolean isChargingDuringActivities(ElectricVehicleSpecification electricVehicleSpecification) {
Object attribute = electricVehicleSpecification.getMatsimVehicle().getAttributes().getAttribute(PLAN_CHARGING_DURING_ACTS_ATTRIBUTE_NAME);
return attribute == null ? true : (Boolean) attribute;
}

/**
* see description for {@code setChargingDuringActivities(Vehicle vehicle, boolean value)}
* @param electricVehicleSpecification
* @param value
*/
public static void setChargingDuringActivities(ElectricVehicleSpecification electricVehicleSpecification, boolean value) {
setChargingDuringActivities(electricVehicleSpecification.getMatsimVehicle(), value);
}

/**
* defines whether the vehicle shall be included for planning recharging during the driver's activities (with {@code UrbanEVTripsPlanner}, or not. <br>
* In the latter case, recharging may be planned to take place during a trip, if the vehicle is taken for a trip with a mode that is
* routed by {@code org.matsim.contrib.ev.routing.EVNetworkRoutingModule}.
* @param vehicle
* @param value
*/
public static void setChargingDuringActivities(Vehicle vehicle, boolean value) {
vehicle.getAttributes().putAttribute(PLAN_CHARGING_DURING_ACTS_ATTRIBUTE_NAME, value);
}

}
Loading

0 comments on commit 65bbbe7

Please sign in to comment.