From d8a84e8cb6ea226695a9087e7a59b2c86ea55bd7 Mon Sep 17 00:00:00 2001
From: Bart Arendarczyk <s1924442@ed.ac.uk>
Date: Fri, 29 Oct 2021 16:19:58 +0100
Subject: [PATCH] Changes to allow reading in CRAFTY production data (UK-SSP).

---
 data/craftyCountries.csv                      |   2 +
 .../country/crafty/CraftyCountryAgent.java    |  98 +++++------
 .../country/crafty/CraftyProdManager.java     | 159 +++++++++--------
 src/ac/ed/lurg/landuse/CropUsageData.java     | 163 +++++++++---------
 4 files changed, 217 insertions(+), 205 deletions(-)
 create mode 100644 data/craftyCountries.csv

diff --git a/data/craftyCountries.csv b/data/craftyCountries.csv
new file mode 100644
index 00000000..c8a2d122
--- /dev/null
+++ b/data/craftyCountries.csv
@@ -0,0 +1,2 @@
+Country
+United Kingdom
diff --git a/src/ac/ed/lurg/country/crafty/CraftyCountryAgent.java b/src/ac/ed/lurg/country/crafty/CraftyCountryAgent.java
index af0145d6..864fbea7 100644
--- a/src/ac/ed/lurg/country/crafty/CraftyCountryAgent.java
+++ b/src/ac/ed/lurg/country/crafty/CraftyCountryAgent.java
@@ -1,53 +1,47 @@
-package ac.ed.lurg.country.crafty;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import ac.ed.lurg.country.AbstractCountryAgent;
-import ac.ed.lurg.country.CompositeCountry;
-import ac.ed.lurg.country.GlobalPrice;
-import ac.ed.lurg.demand.AbstractDemandManager;
-import ac.ed.lurg.landuse.CropUsageData;
-import ac.ed.lurg.types.CommodityType;
-import ac.ed.lurg.types.CropType;
-
-/**
- * Country agent that is interface over data transferred to and from CRAFTY.
- * Need to configure country mapping to that there is
- * */
-public class CraftyCountryAgent extends AbstractCountryAgent {
-
-	private Map<CropType, CropUsageData> cropUsageData;
-
-	public CraftyCountryAgent(AbstractDemandManager demandManager,CompositeCountry country, Map<CropType, Double> tradeBarriers) {
-		super(demandManager, country, tradeBarriers);
-	}
-
-	public Map<CropType, CropUsageData> getCropUsageData() {
-		return cropUsageData;
-	}
-
-	public void updateProduction(Map<CropType, Double> cropProduction, Map<CropType, GlobalPrice> worldPrices) {
-		calculateCountryPricesAndDemand(worldPrices, false);
-
-		cropUsageData = new HashMap<CropType, CropUsageData>();
-		for (Entry<CropType, Double> entry : cropProduction.entrySet()) {
-			CropUsageData cropusage = new CropUsageData(entry.getValue());
-			cropUsageData.put(entry.getKey(), cropusage);
-		}
-
-		updateNetImportsFromProdAndDemand(currentProjectedDemand, currentMinDemandFract, cropUsageData);
-	}
-
-	@Override
- 	protected double getCommPriceFromCropPrice(CommodityType commodity) {
- 		double commPricePlum = 0;
- 		Map<CropType, Double> demandFract = baseDemandFact.get(commodity);
- 
- 		for (CropType crop : commodity.getCropTypes()) {
- 			commPricePlum += currentCountryPrices.get(crop).getImportPrice() * demandFract.get(crop);  // weight price by base demand of each cereal crop
- 		}
- 		return commPricePlum;
- 	}
+package ac.ed.lurg.country.crafty;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import ac.ed.lurg.country.AbstractCountryAgent;
+import ac.ed.lurg.country.CompositeCountry;
+import ac.ed.lurg.country.GlobalPrice;
+import ac.ed.lurg.demand.AbstractDemandManager;
+import ac.ed.lurg.landuse.CropUsageData;
+import ac.ed.lurg.types.CommodityType;
+import ac.ed.lurg.types.CropType;
+
+/**
+ * Country agent that is interface over data transferred to and from CRAFTY.
+ * Need to configure country mapping to that there is
+ * */
+public class CraftyCountryAgent extends AbstractCountryAgent {
+
+	private Map<CropType, CropUsageData> cropUsageData;
+
+	public CraftyCountryAgent(AbstractDemandManager demandManager,CompositeCountry country, Map<CropType, Double> tradeBarriers) {
+		super(demandManager, country, tradeBarriers);
+	}
+
+	public Map<CropType, CropUsageData> getCropUsageData() {
+		return cropUsageData;
+	}
+
+	public void updateProduction(Map<CropType, CropUsageData> cropUsageMap, Map<CropType, GlobalPrice> worldPrices) {
+		this.cropUsageData = cropUsageMap;
+		calculateCountryPricesAndDemand(worldPrices, false);
+		updateNetImportsFromProdAndDemand(currentProjectedDemand, currentMinDemandFract, cropUsageMap);
+	}
+
+	@Override
+ 	protected double getCommPriceFromCropPrice(CommodityType commodity) {
+ 		double commPricePlum = 0;
+ 		Map<CropType, Double> demandFract = baseDemandFact.get(commodity);
+ 
+ 		for (CropType crop : commodity.getCropTypes()) {
+ 			commPricePlum += currentCountryPrices.get(crop).getImportPrice() * demandFract.get(crop);  // weight price by base demand of each cereal crop
+ 		}
+ 		return commPricePlum;
+ 	}
 }
\ 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..59329faa 100644
--- a/src/ac/ed/lurg/country/crafty/CraftyProdManager.java
+++ b/src/ac/ed/lurg/country/crafty/CraftyProdManager.java
@@ -1,76 +1,85 @@
-package ac.ed.lurg.country.crafty;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import ac.ed.lurg.ModelConfig;
-import ac.ed.lurg.Timestep;
-import ac.ed.lurg.country.CompositeCountry;
-import ac.ed.lurg.country.GlobalPrice;
-import ac.ed.lurg.types.CropType;
-import ac.ed.lurg.utils.LogWriter;
-import ac.ed.lurg.utils.StringTabularReader;
-import ac.ed.lurg.utils.WatchForFile;
-
-public class CraftyProdManager {
-
-	private Collection<CompositeCountry> craftyCountries;
-	
-	public synchronized Collection<CompositeCountry> getCraftyCountries() {
-		if (craftyCountries == null) {
-			craftyCountries = new ArrayList<CompositeCountry>();
-			StringTabularReader 	tabularReader = new StringTabularReader(",", new String[]{"Country"});
-			List<Map<String, String>> rows = tabularReader.read(ModelConfig.CRAFTY_PRODUCTION_DIR + File.separator + "craftyCountries.csv");
-			for (Map<String, String> row : rows) {
-				craftyCountries.add(new CompositeCountry(row.get("Country"), "craftycountry"));
-			}
-		}
-		return craftyCountries;
-	}
-
-	public void updateWithCraftyData(Collection<CraftyCountryAgent> craftyCountryAgents, Timestep timestep, Map<CropType, GlobalPrice> worldPrices) {
-		String rootDir = ModelConfig.CRAFTY_PRODUCTION_DIR + File.separator + timestep.getYear();
-		long startTime = System.currentTimeMillis();
-		
-		WatchForFile fileWatcher = new WatchForFile(new File(rootDir + File.separator + "done"));
-		boolean foundFile = fileWatcher.await(ModelConfig.LPJG_MONITOR_TIMEOUT_SEC);
-		if (!foundFile) {
-			LogWriter.printlnError("Not able to find marker file.  May have timed out.");
-			throw new RuntimeException("Not able to find marker file.  May have timed out.");
-		}
-		LogWriter.println("Found marker file in " + (System.currentTimeMillis() - startTime) + " ms");
-		
-		StringTabularReader 	tabularReader = new StringTabularReader(",", new String[]{"Country","Crop","Production"});
-		tabularReader.read(rootDir + File.separator + "production.csv");
-
-		
-		for (CraftyCountryAgent cca : craftyCountryAgents) {
-			Map<CropType, Double> cropProduction = new HashMap<CropType, Double>();
-	
-			Map<String, String> queryMap = new HashMap<String, String>();
-			queryMap.put("Country", cca.getCountry().getName());
-
-			try {
-				List<Map<String, String>> rows = tabularReader.query(queryMap);
-				for (Map<String, String> row : rows) {
-					String cropS = row.get("Crop");
-					CropType crop = CropType.getForGamsName(cropS);
-					String prodS = row.get("Production");
-					Double prod = Double.valueOf(prodS);
-					cropProduction.put(crop, prod);
-				}
-				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);
-			}
-			catch (Exception e) {
-				LogWriter.println("Problem getting Crafty data for: " + cca.getCountry());
-			}
-		}
-	}
+package ac.ed.lurg.country.crafty;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import ac.ed.lurg.ModelConfig;
+import ac.ed.lurg.Timestep;
+import ac.ed.lurg.country.CompositeCountry;
+import ac.ed.lurg.country.GlobalPrice;
+import ac.ed.lurg.landuse.CropUsageData;
+import ac.ed.lurg.types.CropType;
+import ac.ed.lurg.utils.LogWriter;
+import ac.ed.lurg.utils.StringTabularReader;
+import ac.ed.lurg.utils.WatchForFile;
+
+public class CraftyProdManager {
+
+	private Collection<CompositeCountry> craftyCountries;
+	
+	public synchronized Collection<CompositeCountry> getCraftyCountries() {
+		if (craftyCountries == null) {
+			craftyCountries = new ArrayList<CompositeCountry>();
+			StringTabularReader 	tabularReader = new StringTabularReader(",", new String[]{"Country"});
+			List<Map<String, String>> rows = tabularReader.read(ModelConfig.DATA_DIR + File.separator + "craftyCountries.csv");
+			for (Map<String, String> row : rows) {
+				craftyCountries.add(new CompositeCountry(row.get("Country"), "craftycountry"));
+			}
+		}
+		return craftyCountries;
+	}
+
+	public void updateWithCraftyData(Collection<CraftyCountryAgent> craftyCountryAgents, Timestep timestep, Map<CropType, GlobalPrice> worldPrices) {
+		String rootDir = ModelConfig.CRAFTY_PRODUCTION_DIR + File.separator + timestep.getYear();
+		long startTime = System.currentTimeMillis();
+		
+		WatchForFile fileWatcher = new WatchForFile(new File(rootDir + File.separator + "done"));
+		boolean foundFile = fileWatcher.await(ModelConfig.LPJG_MONITOR_TIMEOUT_SEC);
+		if (!foundFile) {
+			LogWriter.printlnError("Not able to find marker file.  May have timed out.");
+			throw new RuntimeException("Not able to find marker file.  May have timed out.");
+		}
+		LogWriter.println("Found marker file in " + (System.currentTimeMillis() - startTime) + " ms");
+		
+		StringTabularReader 	tabularReader = new StringTabularReader(",", new String[]{"Country","Crop","Production","MonogastricFeed","RuminantFeed","NetImportsExpected"});
+		tabularReader.read(rootDir + File.separator + "production.csv");
+
+		
+		for (CraftyCountryAgent cca : craftyCountryAgents) {
+			Map<CropType, CropUsageData> cropUsageMap = new HashMap<CropType, CropUsageData>();
+	
+			Map<String, String> queryMap = new HashMap<String, String>();
+			queryMap.put("Country", cca.getCountry().getName());
+
+			try {
+				List<Map<String, String>> rows = tabularReader.query(queryMap);
+				for (Map<String, String> row : rows) {
+					String cropS = row.get("Crop");
+					CropType crop = CropType.getForGamsName(cropS);
+					String prodS = row.get("Production");
+					Double prod = Double.valueOf(prodS);
+					String monoFeedS = row.get("MonogastricFeed");
+					Double monoFeed = Double.valueOf(monoFeedS);
+					String rumFeedS = row.get("MonogastricFeed");
+					Double rumFeed = Double.valueOf(rumFeedS);
+					String netImpS = row.get("NetImportsExpected");
+					Double netImp = Double.valueOf(netImpS);
+					
+					CropUsageData cropUsageItem = new CropUsageData(rumFeed, monoFeed, netImp, prod);
+					cropUsageMap.put(crop, cropUsageItem);
+				}
+				if (cropUsageMap.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 " + cropUsageMap.size());
+				}
+				cca.updateProduction(cropUsageMap, worldPrices);
+			}
+			catch (Exception e) {
+				LogWriter.println("Problem getting Crafty data for: " + cca.getCountry());
+			}
+		}
+	}
 }
\ No newline at end of file
diff --git a/src/ac/ed/lurg/landuse/CropUsageData.java b/src/ac/ed/lurg/landuse/CropUsageData.java
index ea261ea8..fb7e396b 100644
--- a/src/ac/ed/lurg/landuse/CropUsageData.java
+++ b/src/ac/ed/lurg/landuse/CropUsageData.java
@@ -1,79 +1,86 @@
-package ac.ed.lurg.landuse;
-
-import java.io.Serializable;
-
-public class CropUsageData implements Serializable  {
-
-	private static final long serialVersionUID = 1200684888140690926L;
-	
-	private double ruminantFeed;
-	private double monogastricFeed;
-	private double netImportsExpected;
-	private double prodShock;
-	private double netImportCostExpected;
-	private double prod;
-	private double prodCost;
-	private double area;
-
-	public CropUsageData(double prod) {
-		this.prod = prod;
-	}
-	
-	public CropUsageData(double ruminantFeed, double monogastricFeed, double netImportsExpected, double netImportCost, double prod, double prodCost, double area, double prodShock) {
-		this.ruminantFeed = ruminantFeed;
-		this.monogastricFeed = monogastricFeed;
-		this.netImportsExpected = netImportsExpected;
-		this.netImportCostExpected = netImportCost;
-		this.prod = prod;
-		this.prodCost = prodCost;
-		this.area= area;
-		this.prodShock = prodShock;
-	}
-		
-	public double getRuminantFeed() {
-		return ruminantFeed;
-	}
-	
-	public double getMonogastricFeed() {
-		return monogastricFeed;
-	}
-
-	public double getNetImportCostExpected() {
-		return netImportCostExpected;
-	}
-	
-	public double getNetImportsExpected() {
-		return netImportsExpected;
-	}
-	
-	public double getProductionExpected() {
-		return prod;
-	}
-	
-	public double getShockedNetImports() {
-		return netImportsExpected + prodShock;
-	}
-	
-	public double getProductionShock() {
-		return prodShock;
-	}
-	
-	public double getTotalProdCost() {
-		return prodCost;
-	}
-	
-	public double getProdCostRate() {
-		if (prod - prodShock <= 0.0)
-			return Double.NaN;
-		else
-			return prodCost / (prod - prodShock);
-	}
-
-	public void updateNetImports(double netImports) {
-		this.netImportsExpected = netImports;
-	}
-	
-	public double getArea(){
-		return area;
-	}
+package ac.ed.lurg.landuse;
+
+import java.io.Serializable;
+
+public class CropUsageData implements Serializable  {
+
+	private static final long serialVersionUID = 1200684888140690926L;
+	
+	private double ruminantFeed;
+	private double monogastricFeed;
+	private double netImportsExpected;
+	private double prodShock;
+	private double netImportCostExpected;
+	private double prod;
+	private double prodCost;
+	private double area;
+
+	public CropUsageData(double prod) {
+		this.prod = prod;
+	}
+	
+	public CropUsageData(double ruminantFeed, double monogastricFeed, double netImportsExpected, double netImportCost, double prod, double prodCost, double area, double prodShock) {
+		this.ruminantFeed = ruminantFeed;
+		this.monogastricFeed = monogastricFeed;
+		this.netImportsExpected = netImportsExpected;
+		this.netImportCostExpected = netImportCost;
+		this.prod = prod;
+		this.prodCost = prodCost;
+		this.area= area;
+		this.prodShock = prodShock;
+	}
+	
+	public CropUsageData(double ruminantFeed, double monogastricFeed, double netImportsExpected, double prod) {
+		this.ruminantFeed = ruminantFeed;
+		this.monogastricFeed = monogastricFeed;
+		this.netImportsExpected = netImportsExpected;
+		this.prod = prod;
+	}
+		
+	public double getRuminantFeed() {
+		return ruminantFeed;
+	}
+	
+	public double getMonogastricFeed() {
+		return monogastricFeed;
+	}
+
+	public double getNetImportCostExpected() {
+		return netImportCostExpected;
+	}
+	
+	public double getNetImportsExpected() {
+		return netImportsExpected;
+	}
+	
+	public double getProductionExpected() {
+		return prod;
+	}
+	
+	public double getShockedNetImports() {
+		return netImportsExpected + prodShock;
+	}
+	
+	public double getProductionShock() {
+		return prodShock;
+	}
+	
+	public double getTotalProdCost() {
+		return prodCost;
+	}
+	
+	public double getProdCostRate() {
+		if (prod - prodShock <= 0.0)
+			return Double.NaN;
+		else
+			return prodCost / (prod - prodShock);
+	}
+
+	public void updateNetImports(double netImports) {
+		this.netImportsExpected = netImports;
+	}
+	
+	public double getArea(){
+		return area;
+	}
 }
\ No newline at end of file
-- 
GitLab