Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Towards grades in emissions #2547

Closed
wants to merge 9 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ private enum EmissionSpecificationMarker {BEGIN_EMISSIONS, END_EMISSIONS}

public static final String HBEFA_ROAD_TYPE = "hbefa_road_type";

public static final String HBEFA_ROAD_GRADIENT = "hbefa_road_gradient";

public static void setHbefaRoadType(Link link, String type) {
link.getAttributes().putAttribute(HBEFA_ROAD_TYPE, type);
}
Expand All @@ -57,6 +59,10 @@ public static String getHbefaRoadType(Link link) {
return (String) link.getAttributes().getAttribute(HBEFA_ROAD_TYPE);
}

public static void setHbefaRoadGradient(Link link, String gradient) { link.getAttributes().putAttribute(String.valueOf(HBEFA_ROAD_GRADIENT), gradient); } // implement the setHbefaRoadGradient-Method here but it is not callable in the exmaple project then...

public static String getHbefaRoadGradient(Link link) { return (String) link.getAttributes().getAttribute(String.valueOf(HBEFA_ROAD_GRADIENT)); }

public static Map<Pollutant, Double> sumUpEmissions(Map<Pollutant, Double> warmEmissions, Map<Pollutant, Double> coldEmissions) {

return Stream.concat(warmEmissions.entrySet().stream(), coldEmissions.entrySet().stream())
Expand Down Expand Up @@ -97,7 +103,7 @@ public static Map<Id<Person>, SortedMap<Pollutant, Double>> setNonCalculatedEmis
for (Pollutant pollutant : pollutants) {
emissionType2Value.put(pollutant, 0.0);
}
} else { // person in map, but some emissions are not set; setting these to 0.0
} else { // person in map, but some emissions are not set; setting these to 0.0
emissionType2Value = totalEmissions.get(personId);
for (Pollutant pollutant : emissionType2Value.keySet()) {
// else do nothing
Expand Down Expand Up @@ -181,18 +187,19 @@ static Tuple<HbefaVehicleCategory, HbefaVehicleAttributes> convertVehicleDescrip
Tuple<HbefaVehicleCategory, HbefaVehicleAttributes> vehicleInformationTuple;

Gbl.assertNotNull(vehicleType);
Gbl.assertNotNull(vehicleType.getEngineInformation());
Gbl.assertNotNull(VehicleUtils.getHbefaVehicleCategory(vehicleType.getEngineInformation()));
final EngineInformation engineInformation = vehicleType.getEngineInformation();
Gbl.assertNotNull( engineInformation );
Gbl.assertNotNull(VehicleUtils.getHbefaVehicleCategory( engineInformation ) );

HbefaVehicleCategory hbefaVehicleCategory = mapString2HbefaVehicleCategory( VehicleUtils.getHbefaVehicleCategory( vehicleType.getEngineInformation() ) ) ;
HbefaVehicleCategory hbefaVehicleCategory = mapString2HbefaVehicleCategory( VehicleUtils.getHbefaVehicleCategory( engineInformation ) ) ;

HbefaVehicleAttributes hbefaVehicleAttributes = new HbefaVehicleAttributes();

final String hbefaTechnology = VehicleUtils.getHbefaTechnology( vehicleType.getEngineInformation() );
final String hbefaTechnology = VehicleUtils.getHbefaTechnology( engineInformation );
if ( hbefaTechnology!=null ){
hbefaVehicleAttributes.setHbefaTechnology( hbefaTechnology );
hbefaVehicleAttributes.setHbefaSizeClass( VehicleUtils.getHbefaSizeClass( vehicleType.getEngineInformation() ) );
hbefaVehicleAttributes.setHbefaEmConcept( VehicleUtils.getHbefaEmissionsConcept( vehicleType.getEngineInformation() ) );
hbefaVehicleAttributes.setHbefaSizeClass( VehicleUtils.getHbefaSizeClass( engineInformation ) );
hbefaVehicleAttributes.setHbefaEmConcept( VehicleUtils.getHbefaEmissionsConcept( engineInformation ) );
}
// yyyy we are as of now not catching the case where the information is not there. kai/kai, sep'19

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,16 @@ abstract class HbefaEmissionFactorKey {
private HbefaVehicleAttributes vehicleAttributes = new HbefaVehicleAttributes();
private Pollutant component;



// private String roadGradient;
// this is, in the end, added in the WARMEmissionFactorKey, where it probably belongs. kai, apr'23

HbefaEmissionFactorKey(HbefaEmissionFactorKey copyFrom) {
this.vehicleCategory = copyFrom.getVehicleCategory();
this.vehicleAttributes = copyFrom.getVehicleAttributes();
this.component = copyFrom.getComponent();
// this.roadGradient = copyFrom.getRoadGradient();
}

HbefaEmissionFactorKey() {
Expand Down Expand Up @@ -63,6 +69,12 @@ public void setComponent(Pollutant component) {
this.component = component;
}

// public String getRoadGradient() {
// return roadGradient;
// }

// public void setRoadGradient(String roadGradient) { this.roadGradient = roadGradient; }

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.matsim.contrib.emissions;

/**
* @author Tim Kirschbaum
* */
public enum HbefaRoadGradient {
ZERO,
PLUS_2,
PLUS_4,
PLUS_6,
MINUS_2,
MINUS_4,
MINUS_6,
PLUS_MINUS_2,
PLUS_MINUS_4,
PLUS_MINUS_6;

HbefaRoadGradient() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ static Map<HbefaWarmEmissionFactorKey, HbefaWarmEmissionFactor> loadAverageWarm(
return load(file, HbefaTables::createWarmKey, record -> {
var factor = Double.parseDouble(record.get("EFA_weighted"));
var speed = Double.parseDouble(record.get("V_weighted"));
return new HbefaWarmEmissionFactor(factor, speed);
// var roadGradient = record.get("Gradient");
// return new HbefaWarmEmissionFactor(factor, speed, roadGradient);
return new HbefaWarmEmissionFactor(factor, speed );
});
}

Expand All @@ -53,7 +55,10 @@ static Map<HbefaWarmEmissionFactorKey, HbefaWarmEmissionFactor> loadDetailedWarm
var key = createWarmKey(record);
setCommonDetailedParametersOnKey(key, record);
return key;
}, record -> new HbefaWarmEmissionFactor(Double.parseDouble(record.get("EFA")), Double.parseDouble(record.get("V"))));
}, record -> new HbefaWarmEmissionFactor(Double.parseDouble(record.get("EFA"))
, Double.parseDouble(record.get("V"))
// , record.get("Gradient")
));
}

static Map<HbefaColdEmissionFactorKey, HbefaColdEmissionFactor> loadAverageCold(URL file) {
Expand Down Expand Up @@ -90,8 +95,10 @@ private static HbefaWarmEmissionFactorKey createWarmKey(CSVRecord record) {
var key = new HbefaWarmEmissionFactorKey();
setCommonParametersOnKey(key, record);
var trafficSit = record.get("TrafficSit");
var roadGradient = record.get("Gradient");
key.setRoadCategory(trafficSit.substring(0, trafficSit.lastIndexOf('/')));
key.setTrafficSituation(mapString2HbefaTrafficSituation(trafficSit));
key.setRoadGradient(roadGradient);
key.setVehicleAttributes(new HbefaVehicleAttributes());
return key;
}
Expand Down Expand Up @@ -129,6 +136,26 @@ private static HbefaTrafficSituation mapString2HbefaTrafficSituation(String stri
throw new RuntimeException();
}
}
//TODO to use when enum functionality is implemented. also use it furtherup
private static HbefaRoadGradient mapString2HbefaRoadGradient(String string) {
// I cannot say if and how this is needed. Currently, it is never called. kai, apr'23

if (string.equals("0%")) return HbefaRoadGradient.ZERO;
else if (string.equals("+2%")) return HbefaRoadGradient.PLUS_2;
else if (string.equals("+4%")) return HbefaRoadGradient.PLUS_4;
else if (string.equals("+6%")) return HbefaRoadGradient.PLUS_6;
else if (string.equals("-2%")) return HbefaRoadGradient.MINUS_2;
else if (string.equals("-4%")) return HbefaRoadGradient.MINUS_4;
else if (string.equals("-6%")) return HbefaRoadGradient.MINUS_6;
else if (string.equals("+/-2%")) return HbefaRoadGradient.PLUS_MINUS_2;
else if (string.equals("+/-4%")) return HbefaRoadGradient.PLUS_MINUS_4;
else if (string.equals("+/-6%")) return HbefaRoadGradient.PLUS_MINUS_6;

else {
logger.warn("Could not map String " + string + " to any HbefaRoadGradient; please check syntax in hbefa input file.");
throw new RuntimeException();
}
}

private static int mapAmbientCondPattern2Distance(String string) {
String distanceString = string.split(",")[2];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,22 @@ class HbefaWarmEmissionFactor extends HbefaEmissionFactor {

private final double speed;

/*package-private*/ HbefaWarmEmissionFactor(double factor, double speed) {
// public String getRoadGradient() {
// return roadGradient;
// }
//
// private final String roadGradient;

// /*package-private*/ HbefaWarmEmissionFactor(double factor, double speed, @Deprecated String roadGradient) {

// My strong intuition is that roadGradient does <i>not</i> belong into the emission factor. Since the emissions factor is output,
// not input. For this, one has to note that for HBEFA speed is output, for a certain traffic state on a certain road category. This is
// nonwithstanding the fact that for some versions of the emission calculation it is then used as input. kai, apr'23

/*package-private*/ HbefaWarmEmissionFactor(double factor, double speed ) {
super(factor);
this.speed = speed;
// this.roadGradient = roadGradient;
}

public double getSpeed() {
Expand All @@ -40,6 +53,7 @@ public double getSpeed() {
public String toString() {
return "HbefaWarmEmissionFactor{" +
"speed=" + speed +
// ", roadGradient=" + roadGradient +
", warmEmissionFactor=" + getFactor() +
'}';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ class HbefaWarmEmissionFactorKey extends HbefaEmissionFactorKey {

private String roadCategory;
private HbefaTrafficSituation trafficSituation;
private String roadGradient; // added var roadGradient
// It is most probably correct to add roadGradient here. However, the way it is done right now it is far from complete. Including that it is
// not used in equals and in HashCode. kai, apr'23

// What is also missing in general is some wildcard syntax. This now comes in as a problem here since it makes retrofitting the non-grade
// code more difficult. So far an easy solution for wildcards did not come to mind, and for a complicated solution we
// did not have the patience. Maybe there is a library? In the meantime, we have operated with the fallbacks in the config. So one could
// now include something there either fall back to zero grade if grade is not available in the link. Or abort. (I find the latter more
// plausible; one can add a grade to each individual link in the pre-processing.) kai, apr'23


/*package-private*/ HbefaWarmEmissionFactorKey() {
}
Expand All @@ -34,12 +44,15 @@ public HbefaWarmEmissionFactorKey(HbefaWarmEmissionFactorKey key) {
super(key);
this.roadCategory = key.roadCategory;
this.trafficSituation = key.trafficSituation;
this.roadGradient = key.roadGradient;
}

String getRoadCategory() {
return this.roadCategory;
}



/*package-private*/ void setRoadCategory(String roadCategory) {
this.roadCategory = roadCategory;
}
Expand All @@ -52,6 +65,10 @@ String getRoadCategory() {
this.trafficSituation = trafficSituation;
}

/*package-private*/ void setRoadGradient(String roadGradient) {
this.roadGradient = roadGradient;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand All @@ -69,6 +86,7 @@ public int hashCode() {
int result = super.hashCode();
result = 31 * result + trafficSituation.hashCode();
result = 31 * result + roadCategory.hashCode();
result = 31 * result + roadGradient.hashCode();
return result;
}

Expand All @@ -80,6 +98,7 @@ public String toString(){
+ getComponent() + "; "
+ roadCategory + "; "
+ trafficSituation + "; "
+ roadGradient + "; "
+ getVehicleAttributes();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,13 @@ static class EmissionCalculator {
private EmissionModule emissionModule;

Map<Pollutant, Double> calculateWarmEmissions(Vehicle vehicle, Link link, double distance, double time) {

var vehicleAttributes = getVehicleAttributes(vehicle);
var roadType = EmissionUtils.getHbefaRoadType(link);
return emissionModule.getWarmEmissionAnalysisModule().calculateWarmEmissions(time, roadType, link.getFreespeed(), distance, vehicleAttributes);
var roadGradient = EmissionUtils.getHbefaRoadGradient(link);
return emissionModule.getWarmEmissionAnalysisModule().calculateWarmEmissions(time, roadType, roadGradient,link.getFreespeed(), distance, vehicleAttributes);
// The above is plausible as the adapter method which takes matsim objects (vehicle, link), and converts them into plain
// lookup tables. HOWEVER, then one should either resolve vehicleAttributes into individual entries. Or combine the link attributes into
// linkAttributes. (This may not be so much a problem as long as (all the) calculateWarmEmissions are not public.) kai, apr'23
}

Map<Pollutant, Double> calculateColdEmissions(Vehicle vehicle, double parkingDuration, int distance) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public WarmEmissionAnalysisModule(
key.setTrafficSituation(trafficSituation);
key.setVehicleCategory(vehicleCategory);
key.setVehicleAttributes(vehicleAttribute);
key.setComponent(pollutant);
key.setComponent(pollutant); //TODO add key.setroadGradient here later kerseboom,jan'23
HbefaWarmEmissionFactor result = detailedHbefaWarmTable.get(key);
if (result == null) {
throw new RuntimeException("emissions factor for key=" + key + " is missing." +
Expand Down Expand Up @@ -228,10 +228,10 @@ public Map<Pollutant, Double> checkVehicleInfoAndCalculateWarmEmissions(Vehicle

double freeVelocity = link.getFreespeed(); //TODO: what about time dependence

return calculateWarmEmissions(travelTime, EmissionUtils.getHbefaRoadType(link), freeVelocity, link.getLength(), vehicleInformationTuple);
return calculateWarmEmissions(travelTime, EmissionUtils.getHbefaRoadType(link),EmissionUtils.getHbefaRoadGradient(link),freeVelocity, link.getLength(), vehicleInformationTuple);
}

Map<Pollutant, Double> calculateWarmEmissions(double travelTime_sec, String roadType, double freeVelocity_ms,
Map<Pollutant, Double> calculateWarmEmissions(double travelTime_sec, String roadType, String roadGradient, double freeVelocity_ms,
double linkLength_m, Tuple<HbefaVehicleCategory, HbefaVehicleAttributes> vehicleInformationTuple) {

Map<Pollutant, Double> warmEmissionsOfEvent = new EnumMap<>(Pollutant.class);
Expand All @@ -257,6 +257,7 @@ Map<Pollutant, Double> calculateWarmEmissions(double travelTime_sec, String road
HbefaWarmEmissionFactorKey efkey = new HbefaWarmEmissionFactorKey();
efkey.setVehicleCategory(vehicleInformationTuple.getFirst());
efkey.setRoadCategory(roadType);
efkey.setRoadGradient(roadGradient); //TODO make it work and then change and use the enum kerseboom, jan'23
if (this.detailedHbefaWarmTable != null) {
HbefaVehicleAttributes hbefaVehicleAttributes = new HbefaVehicleAttributes();
hbefaVehicleAttributes.setHbefaTechnology(vehicleInformationTuple.getSecond().getHbefaTechnology());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ class WarmEmissionHandler implements LinkEnterEventHandler, LinkLeaveEventHandle
private final Map<Id<Vehicle>, Tuple<Id<Link>, Double>> vehicleEntersTrafficMap = new HashMap<>();

/*package-private*/ WarmEmissionHandler( Scenario scenario, Map<HbefaWarmEmissionFactorKey, HbefaWarmEmissionFactor> avgHbefaWarmTable,
Map<HbefaWarmEmissionFactorKey, HbefaWarmEmissionFactor> detailedHbefaWarmTable,
Map<HbefaRoadVehicleCategoryKey, Map<HbefaTrafficSituation, Double>> hbefaRoadTrafficSpeeds, Set<Pollutant> warmPollutants,
EventsManager eventsManager ){
Map<HbefaWarmEmissionFactorKey, HbefaWarmEmissionFactor> detailedHbefaWarmTable,
Map<HbefaRoadVehicleCategoryKey, Map<HbefaTrafficSituation, Double>> hbefaRoadTrafficSpeeds, Set<Pollutant> warmPollutants,
EventsManager eventsManager ){

this.scenario = scenario;
this.emissionsConfigGroup = ConfigUtils.addOrGetModule( scenario.getConfig(), EmissionsConfigGroup.class );
Expand Down Expand Up @@ -107,15 +107,15 @@ public void handleEvent(VehicleLeavesTrafficEvent event) {
Link link = this.scenario.getNetwork().getLinks().get(event.getLinkId());
if ( linkLengthIsZero( link.getId(), link.getLength() ) ) { trafficLeaveCnt++; }

final double leaveTime = event.getTime();
final double now = event.getTime();
final Id<Vehicle> vehicleId = event.getVehicleId();
if ( this.linkEnterMap.containsKey( vehicleId ) ) {
double travelTime = leaveTime - this.linkEnterMap.get(vehicleId).getSecond() + 1.0;
double travelTime = now - this.linkEnterMap.get(vehicleId).getSecond() + 1.0;
// this extra second added to travelTime is needed because the vehicleLeavesTrafficEvent
// is thrown one second earlier (by design) ~kn,kmt,rjg 08.22
Vehicle vehicle = VehicleUtils.findVehicle(vehicleId, scenario);
if (vehicle != null) {
emissionsCalculation( vehicleId, vehicle, link, leaveTime, travelTime );
emissionsCalculation( vehicleId, vehicle, link, now, travelTime );
this.vehicleEntersTrafficMap.remove( vehicleId );
this.linkEnterMap.remove( vehicleId );
// clearing these maps so that no second emission event is computed for travel from parking to link leave
Expand Down Expand Up @@ -182,10 +182,10 @@ public void handleEvent(LinkLeaveEvent event) {

}

private void emissionsCalculation(Id<Vehicle> vehicleId, Vehicle vehicle, Link link, double leaveTime, double travelTime) {
private void emissionsCalculation(Id<Vehicle> vehicleId, Vehicle vehicle, Link link, double now, double travelTime) {
VehicleType vehicleType = vehicle.getType();
Map<Pollutant, Double> warmEmissions = warmEmissionAnalysisModule.checkVehicleInfoAndCalculateWarmEmissions(vehicleType, vehicleId, link, travelTime);
warmEmissionAnalysisModule.throwWarmEmissionEvent(leaveTime, link.getId(), vehicleId, warmEmissions);
warmEmissionAnalysisModule.throwWarmEmissionEvent(now, link.getId(), vehicleId, warmEmissions);
}

private boolean linkLengthIsZero( Id<Link> linkId, double linkLength) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@
import org.matsim.core.config.Config;
import org.matsim.core.config.ConfigUtils;
import org.matsim.core.controler.AbstractModule;
import org.matsim.core.controler.Controler;
import org.matsim.core.controler.Injector;
import org.matsim.core.controler.OutputDirectoryHierarchy;
import org.matsim.core.events.EventsUtils;
import org.matsim.core.events.MatsimEventsReader;
import org.matsim.core.events.algorithms.EventWriterXML;
Expand All @@ -47,29 +45,16 @@
*/
public final class RunAverageEmissionToolOfflineExample{

// private static final String configFile = "./scenarios/sampleScenario/testv2_Vehv1/config_average.xml";

public static final String emissionEventsFilename = "emission.events.offline.xml.gz";

// (remove dependency of one test/execution path from other. kai/ihab, nov'18)

private Config config;

// =======================================================================================================

public static void main (String[] args){
RunAverageEmissionToolOfflineExample emissionToolOfflineExampleV2 = new RunAverageEmissionToolOfflineExample();
emissionToolOfflineExampleV2.run();
// yyyy I think that this will fail (since config is null, see under run). kai, apr'23
}

// public Config prepareConfig() {
// config = ConfigUtils.loadConfig(configFile, new EmissionsConfigGroup());
// return config;
// }

public Config prepareConfig(String args){
throw new RuntimeException("execution path no longer exists");
}
public Config prepareConfig(String [] args) {
config = ConfigUtils.loadConfig(args, new EmissionsConfigGroup());
EmissionsConfigGroup ecg = ConfigUtils.addOrGetModule( config, EmissionsConfigGroup.class );
Expand Down Expand Up @@ -106,7 +91,7 @@ public void install(){
// OutputDirectoryHierarchy outputDirectoryHierarchy = injector.getInstance( OutputDirectoryHierarchy.class );

final String outputDirectory = scenario.getConfig().controler().getOutputDirectory();
EventWriterXML emissionEventWriter = new EventWriterXML( outputDirectory + emissionEventsFilename );
EventWriterXML emissionEventWriter = new EventWriterXML( outputDirectory + "emission.events.offline.xml.gz" );
emissionModule.getEmissionEventsManager().addHandler(emissionEventWriter);

eventsManager.initProcessing();
Expand Down
Loading