From 50906f96647d03f656ea037942fad1f1963b45e2 Mon Sep 17 00:00:00 2001
From: s1924442 <b.arendarczyk@sms.ed.ac.uk>
Date: Wed, 31 Mar 2021 14:49:38 +0100
Subject: [PATCH] Added carbon demand from external file.

---
 src/ac/ed/lurg/ModelConfig.java               |  4 +-
 src/ac/ed/lurg/ModelMain.java                 |  7 +-
 src/ac/ed/lurg/country/CountryAgent.java      |  2 +-
 .../ed/lurg/country/CountryAgentManager.java  |  2 +-
 .../country/crafty/CraftyCountryAgent.java    |  8 ++-
 .../country/crafty/CraftyProdManager.java     |  4 +-
 .../ed/lurg/demand/AbstractDemandManager.java |  6 ++
 .../ed/lurg/demand/CarbonDemandManager.java   | 64 +++++++++++++++++++
 8 files changed, 86 insertions(+), 11 deletions(-)
 create mode 100644 src/ac/ed/lurg/demand/CarbonDemandManager.java

diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java
index 77dddcf6..583b7be0 100755
--- a/src/ac/ed/lurg/ModelConfig.java
+++ b/src/ac/ed/lurg/ModelConfig.java
@@ -424,8 +424,10 @@ public class ModelConfig {
 	public static final String TARGET_DIET_FILE = getProperty("TARGET_DIET_FILE", DATA_DIR + File.separator + "TargetDiet.txt");
 	
 	// Forestry parameters
-	public static final String CONVERSION_COST_FILE = DATA_DIR + File.separator + "conversion_costs.csv";
+	public static final String CONVERSION_COST_FILE = DATA_DIR + File.separator + "conversion_costs.csv"; // cost of converting from one land cover to another, $1000/ha
 	public static final String SERIALIZED_CARBON_MARKET_FILE = CALIB_DIR + File.separator +  "CarbonMarket.ser";
+	public static final String CARBON_DEMAND_FILENAME = getProperty("CARBON_DEMAND_FILENAME", "carbon_demand.csv");
+	public static final String CARBON_DEMAND_FILE = getProperty("CARBON_DEMAND_FILE", DATA_DIR + File.separator + CARBON_DEMAND_FILENAME);
 	public static final double CARBON_PRICE = getDoubleProperty("CARBON_PRICE", 0.02); // $1000/tC-eq
 	public static final double WOOD_PRICE = getDoubleProperty("WOOD_PRICE", 0.05); // $1000/tC-eq
 	public static final int FOREST_LOCKIN_PERIOD = getIntProperty("FOREST_LOCKIN_PERIOD", 30); // cannot convert forest after planting for this many years
diff --git a/src/ac/ed/lurg/ModelMain.java b/src/ac/ed/lurg/ModelMain.java
index 6d8d436f..91402619 100644
--- a/src/ac/ed/lurg/ModelMain.java
+++ b/src/ac/ed/lurg/ModelMain.java
@@ -143,13 +143,12 @@ public class ModelMain {
 		double previousGen2EcDDemand = (timestep.isInitialTimestep() || ModelConfig.IS_CALIBRATION_RUN ) ? 0: demandManager.getSecondGenBioenergyDemand(timestep.getPreviousTimestep());
 		double gen2EcDDemand = demandManager.getSecondGenBioenergyDemand(ModelConfig.IS_CALIBRATION_RUN ? new Timestep(1) : timestep);
 		double gen2Increase = (gen2EcDDemand>previousGen2EcDDemand) ? gen2EcDDemand - previousGen2EcDDemand : 0.0;
-		double previousCarbonDemand = (timestep.isInitialTimestep() || ModelConfig.IS_CALIBRATION_RUN ) ? 0: 0.0;
-		double carbonDemand = 1000; //TODO read from file
-		double carbonDemandIncrease = (carbonDemand > previousCarbonDemand) ? carbonDemand - previousCarbonDemand: 0;
 		
+		double previousCarbonDemand = (timestep.isInitialTimestep() || ModelConfig.IS_CALIBRATION_RUN ) ? 0: demandManager.getCarbonDemand(timestep.getPreviousTimestep());
+		double carbonDemand = demandManager.getCarbonDemand(ModelConfig.IS_CALIBRATION_RUN ? new Timestep(1) : timestep);
+		double carbonDemandIncrease = (carbonDemand > previousCarbonDemand) ? carbonDemand - previousCarbonDemand: 0;
 		
 		CarbonFluxRasterSet currentCarbonFluxData = getCarbonFluxData(timestep);
-		
 		WoodYieldRasterSet currentWoodYieldData = getWoodYieldData(timestep);
 		
 		DoubleMap<LandCoverType, LandCoverType, Double> conversionCosts = new ConversionCostReader().read();
diff --git a/src/ac/ed/lurg/country/CountryAgent.java b/src/ac/ed/lurg/country/CountryAgent.java
index 8478526c..d1308e99 100644
--- a/src/ac/ed/lurg/country/CountryAgent.java
+++ b/src/ac/ed/lurg/country/CountryAgent.java
@@ -219,7 +219,7 @@ public class CountryAgent extends AbstractCountryAgent {
 			importConstraints.put(crop, new TradeConstraint(baseTrade - changeDown, baseTrade + changeUp));
 		}
 		
-		// Carbon import/export constraints
+		// Carbon import/export constraints TODO not used
 		double baseTrade = getNetCarbonFlux();
 		double countryArea = LandUseItem.getTotalLandArea(previousGamsRasterOutput.getLandUses().values());
 		double changeUp = 0.0;
diff --git a/src/ac/ed/lurg/country/CountryAgentManager.java b/src/ac/ed/lurg/country/CountryAgentManager.java
index 1012723d..3ca85261 100644
--- a/src/ac/ed/lurg/country/CountryAgentManager.java
+++ b/src/ac/ed/lurg/country/CountryAgentManager.java
@@ -137,7 +137,7 @@ public class CountryAgentManager {
 		}
 		
 		if (craftyCountryAgents.size() > 0) {
-			craftyManager.updateWithCraftyData(craftyCountryAgents, timestep, internationalMarket.getWorldPrices());  // this will wait for the marker file from CRAFTY
+			craftyManager.updateWithCraftyData(craftyCountryAgents, timestep, internationalMarket.getWorldPrices(), internationalMarket.getCarbonPrice());  // this will wait for the marker file from CRAFTY
 		}
 	}
 	
diff --git a/src/ac/ed/lurg/country/crafty/CraftyCountryAgent.java b/src/ac/ed/lurg/country/crafty/CraftyCountryAgent.java
index af0145d6..8879fd0d 100644
--- a/src/ac/ed/lurg/country/crafty/CraftyCountryAgent.java
+++ b/src/ac/ed/lurg/country/crafty/CraftyCountryAgent.java
@@ -28,8 +28,8 @@ public class CraftyCountryAgent extends AbstractCountryAgent {
 		return cropUsageData;
 	}
 
-	public void updateProduction(Map<CropType, Double> cropProduction, Map<CropType, GlobalPrice> worldPrices) {
-		calculateCountryPricesAndDemand(worldPrices, false);
+	public void updateProduction(Map<CropType, Double> cropProduction, Map<CropType, GlobalPrice> worldPrices, GlobalPrice carbonPrice) {
+		calculateCountryPricesAndDemand(worldPrices, carbonPrice, false);
 
 		cropUsageData = new HashMap<CropType, CropUsageData>();
 		for (Entry<CropType, Double> entry : cropProduction.entrySet()) {
@@ -50,4 +50,8 @@ public class CraftyCountryAgent extends AbstractCountryAgent {
  		}
  		return commPricePlum;
  	}
+	
+	public double getNetCarbonFlux() {
+		return 0;
+	}
 }
\ No newline at end of file
diff --git a/src/ac/ed/lurg/country/crafty/CraftyProdManager.java b/src/ac/ed/lurg/country/crafty/CraftyProdManager.java
index 1a4414bc..7b67dccf 100644
--- a/src/ac/ed/lurg/country/crafty/CraftyProdManager.java
+++ b/src/ac/ed/lurg/country/crafty/CraftyProdManager.java
@@ -32,7 +32,7 @@ public class CraftyProdManager {
 		return craftyCountries;
 	}
 
-	public void updateWithCraftyData(Collection<CraftyCountryAgent> craftyCountryAgents, Timestep timestep, Map<CropType, GlobalPrice> worldPrices) {
+	public void updateWithCraftyData(Collection<CraftyCountryAgent> craftyCountryAgents, Timestep timestep, Map<CropType, GlobalPrice> worldPrices, GlobalPrice carbonPrice) {
 		String rootDir = ModelConfig.CRAFTY_PRODUCTION_DIR + File.separator + timestep.getYear();
 		long startTime = System.currentTimeMillis();
 		
@@ -66,7 +66,7 @@ public class CraftyProdManager {
 				if (cropProduction.size() < CropType.getImportedTypes().size()) {  // Don't need setaside or pasture, which aren't imported either
 					LogWriter.printlnError("Not all crops present in Crafty production for country: " + cca.getCountry() + " only " + cropProduction.size());
 				}
-				cca.updateProduction(cropProduction, worldPrices);
+				cca.updateProduction(cropProduction, worldPrices, carbonPrice);
 			}
 			catch (Exception e) {
 				LogWriter.println("Problem getting Crafty data for: " + cca.getCountry());
diff --git a/src/ac/ed/lurg/demand/AbstractDemandManager.java b/src/ac/ed/lurg/demand/AbstractDemandManager.java
index 81808f06..f97074d4 100644
--- a/src/ac/ed/lurg/demand/AbstractDemandManager.java
+++ b/src/ac/ed/lurg/demand/AbstractDemandManager.java
@@ -19,12 +19,14 @@ public abstract class AbstractDemandManager {
 	protected CalorieManager calorieManager;
 	protected BioenergyDemandManager bioenergyDemandManager;
 	protected CerealFractionsManager cerealFractionsManager;
+	protected CarbonDemandManager carbonDemandManager;
 
 	public AbstractDemandManager(CompositeCountryManager compositeCountryManager, CalorieManager calorieManager) {
 		this.compositeCountryManager = compositeCountryManager;
 		this.calorieManager = calorieManager; 
 		bioenergyDemandManager = new BioenergyDemandManager();
 		cerealFractionsManager = new CerealFractionsManager(compositeCountryManager);
+		carbonDemandManager = new CarbonDemandManager();
 	}
 
 	public Map<CommodityType, Double> getDemand(CompositeCountry cc, int year, Map<CommodityType, Double> prices, boolean outputGamsDemand) {
@@ -130,5 +132,9 @@ public abstract class AbstractDemandManager {
 //		LogWriter.println("updated map " + updatedFoodDemandMap);
 		return updatedFoodDemandMap;
 	}
+	
+	public double getCarbonDemand(Timestep timestep) {
+		return carbonDemandManager.getGlobalCarbonDemand(timestep.getYear());
+	}
 
 }
diff --git a/src/ac/ed/lurg/demand/CarbonDemandManager.java b/src/ac/ed/lurg/demand/CarbonDemandManager.java
new file mode 100644
index 00000000..dc9bf1a0
--- /dev/null
+++ b/src/ac/ed/lurg/demand/CarbonDemandManager.java
@@ -0,0 +1,64 @@
+package ac.ed.lurg.demand;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import ac.ed.lurg.ModelConfig;
+import ac.ed.lurg.utils.Interpolator;
+import ac.ed.lurg.utils.LogWriter;
+
+public class CarbonDemandManager {
+	private Map<Integer, Double> globalCarbonDemand; // global demand for carbon sequestration
+	private static final int YEAR_COL = 0;
+	private static final int DEMAND_COL = 1; 
+	
+	public CarbonDemandManager() {
+		readCarbonDemandData();
+	}
+	
+	public void readCarbonDemandData() {
+		
+		Map<Integer, Double> data = new HashMap<Integer, Double>();
+		
+		String filename = ModelConfig.CARBON_DEMAND_FILE;
+		try {
+			BufferedReader reader = new BufferedReader(new FileReader(filename)); 
+			String line;
+			Integer year;
+			Double demand;
+			reader.readLine(); // read header
+
+			while ((line=reader.readLine()) != null) {
+				String[] tokens = line.split(",");
+				
+				if (tokens.length < 2)
+					LogWriter.printlnError("Too few columns in " + filename + ", " + line);
+				
+				year = Integer.valueOf(tokens[YEAR_COL]);
+				demand = Double.valueOf(tokens[DEMAND_COL]);
+				
+				data.put(year,  demand);
+			} 
+			reader.close(); 
+		
+		} catch (IOException e) {
+			LogWriter.printlnError("Failed in reading carbon demand data");
+			LogWriter.print(e);
+		}
+		globalCarbonDemand = data;
+		LogWriter.println("Processed " + filename);
+	}
+	
+	public double getGlobalCarbonDemand(int year) {
+		int downYear = (year/5) * 5;
+		int upYear = downYear + 5;
+		Double lowerD = globalCarbonDemand.get(downYear);
+		Double upperD = globalCarbonDemand.get(upYear);
+		double factor = ((double)(year - downYear)) / (upYear - downYear);
+		Double d = Interpolator.interpolate(lowerD, upperD, factor);
+		return d;
+	}
+}
-- 
GitLab