From b1a6b46091c2ba6465141970e477dd3788901b64 Mon Sep 17 00:00:00 2001
From: Peter Alexander <peter@blackhillock.co.uk>
Date: Mon, 14 Sep 2015 10:30:32 +0100
Subject: [PATCH] Change to exponential fertiliser response

---
 GAMS/IntExtOpt.gms                            | 12 +++++++---
 src/ac/ed/lurg/ModelConfig.java               |  2 +-
 src/ac/ed/lurg/ModelMain.java                 |  7 +++---
 .../country/gams/GamsRasterOptimiser.java     |  6 ++++-
 .../lurg/yield/LPJYieldResponseMapReader.java |  8 ++++---
 src/ac/ed/lurg/yield/YieldResponse.java       | 22 +++++++++++++------
 src/ac/ed/lurg/yield/YieldResponsesItem.java  |  4 ----
 .../raster/AbstractTabularRasterReader.java   |  2 +-
 8 files changed, 40 insertions(+), 23 deletions(-)

diff --git a/GAMS/IntExtOpt.gms b/GAMS/IntExtOpt.gms
index 0ac433f0..de122d72 100644
--- a/GAMS/IntExtOpt.gms
+++ b/GAMS/IntExtOpt.gms
@@ -119,10 +119,16 @@ $gdxin
  
  YIELD_EQ(crop, location) .. yield(crop, location) =E= (
                yieldNone(crop, location) + 
-               (yieldFertOnly(crop, location) - yieldNone(crop, location)) * ((fertI(crop, location) + delta) ** fertParam(crop, location)) +
-               (yieldIrrigOnly(crop, location) - yieldNone(crop, location)) * ((irrigI(crop, location) + delta) ** irrigParam(crop, location)) +
+*               (yieldFertOnly(crop, location) - yieldNone(crop, location)) * ((fertI(crop, location) + delta) ** fertParam(crop, location)) +
+*               (yieldIrrigOnly(crop, location) - yieldNone(crop, location)) * ((irrigI(crop, location) + delta) ** irrigParam(crop, location)) +
+*               (yieldBoth(crop, location) + yieldNone(crop, location) - yieldFertOnly(crop, location) - yieldIrrigOnly(crop, location)) *
+*                                       ((fertI(crop, location) + delta) ** fertParam(crop, location)) * ((irrigI(crop, location) + delta) ** irrigParam(crop, location)) 
+
+               (yieldFertOnly(crop, location) - yieldNone(crop, location)) * (1 - exp(-fertParam(crop, location)*fertI(crop, location))) +
+               (yieldIrrigOnly(crop, location) - yieldNone(crop, location)) * (1 - exp(-irrigParam(crop, location)*irrigI(crop, location))) +
                (yieldBoth(crop, location) + yieldNone(crop, location) - yieldFertOnly(crop, location) - yieldIrrigOnly(crop, location)) *
-                                       ((fertI(crop, location) + delta) ** fertParam(crop, location)) * ((irrigI(crop, location) + delta) ** irrigParam(crop, location)) 
+                                      (1 - exp(-fertParam(crop, location)*fertI(crop, location))) * (1 - exp(-irrigParam(crop, location)*irrigI(crop, location)))
+
             ) * cropAdj(crop) * otherIntensity(crop, location);
    
  NET_SUPPLY_EQ(crop) .. net_supply(crop) =E= sum(location, area(crop, location) * yield(crop, location)) - feedAmount(crop) + netImportAmount(crop);
diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java
index 2e1a43b0..1e4673a8 100644
--- a/src/ac/ed/lurg/ModelConfig.java
+++ b/src/ac/ed/lurg/ModelConfig.java
@@ -128,7 +128,7 @@ public class ModelConfig {
 	// Fertiliser application rates in kg/ha
 	public static final double MIN_FERT_AMOUNT = 5;
 	public static final double MID_FERT_AMOUNT = 50;
-	public static final double MAX_FERT_AMOUNT = 200;
+	public static final double MAX_FERT_AMOUNT = 500;
 
 	// Other model parameters
 	public static final boolean KEEP_DEMAND_FIXED = getBooleanProperty("KEEP_DEMAND_FIXED", false);
diff --git a/src/ac/ed/lurg/ModelMain.java b/src/ac/ed/lurg/ModelMain.java
index a6827925..b683a6dd 100644
--- a/src/ac/ed/lurg/ModelMain.java
+++ b/src/ac/ed/lurg/ModelMain.java
@@ -20,13 +20,13 @@ import ac.ed.lurg.demand.BaseConsumpManager;
 import ac.ed.lurg.demand.DemandManager;
 import ac.ed.lurg.landuse.CropUsageData;
 import ac.ed.lurg.landuse.CropUsageReader;
-import ac.ed.lurg.landuse.LandUseItem;
 import ac.ed.lurg.landuse.IrrigationConstraintReader;
 import ac.ed.lurg.landuse.IrrigationItem;
 import ac.ed.lurg.landuse.IrrigationMaxAmountReader;
 import ac.ed.lurg.landuse.IrrigiationCostReader;
 import ac.ed.lurg.landuse.LandCoverItem;
 import ac.ed.lurg.landuse.LandCoverReader;
+import ac.ed.lurg.landuse.LandUseItem;
 import ac.ed.lurg.output.LpjgOutputer;
 import ac.ed.lurg.types.CropToDoubleMap;
 import ac.ed.lurg.types.CropType;
@@ -35,6 +35,7 @@ import ac.ed.lurg.types.ModelFitType;
 import ac.ed.lurg.utils.LogWriter;
 import ac.ed.lurg.yield.LPJYieldResponseMapReader;
 import ac.ed.lurg.yield.YieldRaster;
+import ac.ed.lurg.yield.YieldResponsesItem;
 import ac.sac.raster.IntegerRasterItem;
 import ac.sac.raster.InterpolatingRasterSet;
 import ac.sac.raster.RasterHeaderDetails;
@@ -97,8 +98,8 @@ public class ModelMain {
 
 		YieldRaster yieldSurfaces = getYieldSurfaces(timestep);  // this will wait for the marker file from LPJ if configured to do so
 
-		//		YieldResponsesItem yresp = yieldSurfaces.getFromCoordinates(-50.0, -4.0);
-		//		LogWriter.printlnError("Test key: " + yresp.getYieldMax(CropType.CEREALS)  + ", " + yresp.getYieldFertOnly(CropType.CEREALS) + ", " + yresp.getYieldIrrigOnly(CropType.CEREALS));
+		YieldResponsesItem yresp = yieldSurfaces.getFromCoordinates(-90.5, 45.5);
+		LogWriter.printlnError("Test key: " + yresp.getYieldMax(CropType.MAIZE)  + ", " + yresp.getYieldFertOnly(CropType.MAIZE) + ", " + yresp.getYieldIrrigOnly(CropType.MAIZE) + ", " + yresp.getYieldNone(CropType.MAIZE));
 
 		CropToDoubleMap totalImportCommodities = new CropToDoubleMap();
 		CropToDoubleMap totalExportCommodities = new CropToDoubleMap();
diff --git a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java
index 6df3f1b8..05d9d376 100644
--- a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java
+++ b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java
@@ -357,7 +357,11 @@ public class GamsRasterOptimiser {
 				// Crops yields and area fractions
 				for (CropType crop : CropType.getNonMeatTypes()) {
 					for (YieldType yieldType : YieldType.values()) {
-						avgYResp.setYield(yieldType, crop, yresp.getYield(yieldType, crop));
+						double y = yresp.getYield(yieldType, crop);
+						if (Double.isNaN(y))
+							LogWriter.printlnError("Problem getting yield at, col:" + key.getCol() + ", row:"  + key.getRow() + ", x:" + yieldRaster.getXCoordin(key) + ", y:" + yieldRaster.getYCoordin(key) + ", type:" + yieldType + ", crop:" + crop);
+						else
+							avgYResp.setYield(yieldType, crop, y);
 					}
 
 					double areaSoFar = aggLandUse.getCropArea(crop);
diff --git a/src/ac/ed/lurg/yield/LPJYieldResponseMapReader.java b/src/ac/ed/lurg/yield/LPJYieldResponseMapReader.java
index 74231fca..3eb218e7 100644
--- a/src/ac/ed/lurg/yield/LPJYieldResponseMapReader.java
+++ b/src/ac/ed/lurg/yield/LPJYieldResponseMapReader.java
@@ -81,10 +81,12 @@ public class LPJYieldResponseMapReader extends AbstractTabularRasterReader<Yield
 				for (IrrigationRate irrig : IrrigationRate.values()) {
 					YieldType yieldType = YieldType.getYieldType(fert, irrig);
 					
-					if (!fert.equals(FertiliserRate.NO_FERT))
-						adjFactor = 10;  // 10 for kg/m2 to t/ha
+					if (fert.equals(FertiliserRate.NO_FERT))
+						adjFactor = 10 * 0.4; // adjust no fert yield to 40% of figure
+					else if (fert.equals(FertiliserRate.MID_FERT))
+						adjFactor = 10 * 0.9;  // adjust mid fert yield to 90% of figure
 					else
-						adjFactor = 5;  
+						adjFactor = 10;  // 10 for kg/m2 to t/ha
 
 					String fertIrrigString = irrig.getId() + fert.getId();
 					double ww = getValueForCol(rowValues, "TeWW" + fertIrrigString) * adjFactor;
diff --git a/src/ac/ed/lurg/yield/YieldResponse.java b/src/ac/ed/lurg/yield/YieldResponse.java
index d71b2d7d..590031f7 100644
--- a/src/ac/ed/lurg/yield/YieldResponse.java
+++ b/src/ac/ed/lurg/yield/YieldResponse.java
@@ -5,13 +5,19 @@ import java.util.Map;
 
 import ac.ed.lurg.ModelConfig;
 import ac.ed.lurg.types.YieldType;
-import ac.ed.lurg.utils.LogWriter;
 
 public class YieldResponse {
 	Map<YieldType, Double> yields = new HashMap<YieldType, Double>();
 	private double fertParm;
 	private double irrigParm;
 
+	private static double defaultParam;
+	
+	static {
+		defaultParam =  calcParam(0, 0.8, 1, 0, 0.5, 1.0);  // default assumes 80% at mid point
+	}
+
+	
 	public void setYield(YieldType type, double yield) {
 		yields.put(type, yield);
 		fertParm = 0;
@@ -35,23 +41,25 @@ public class YieldResponse {
 			fertParm = calcParam(getYield(YieldType.NO_FERT_NO_IRRIG), getYield(YieldType.FERT_MID_NO_IRRIG), getYield(YieldType.FERT_MAX_NO_IRRIG), 
 					ModelConfig.MIN_FERT_AMOUNT/ModelConfig.MAX_FERT_AMOUNT, ModelConfig.MID_FERT_AMOUNT/ModelConfig.MAX_FERT_AMOUNT, ModelConfig.MAX_FERT_AMOUNT/ModelConfig.MAX_FERT_AMOUNT);
 			
-			if (fertParm > 1)
-				LogWriter.println(String.format("%s %s %s", getYield(YieldType.NO_FERT_NO_IRRIG), getYield(YieldType.FERT_MID_NO_IRRIG), getYield(YieldType.FERT_MAX_NO_IRRIG)));
+			//LogWriter.println(String.format("%s %s %s", getYield(YieldType.NO_FERT_NO_IRRIG), getYield(YieldType.FERT_MID_NO_IRRIG), getYield(YieldType.FERT_MAX_NO_IRRIG)));
 		}
 		return fertParm;
 	}
 	
 	public double getIrrigParam() {
 		if (irrigParm == 0) {
-			irrigParm = calcParam (0, 0.7, 1, 0, 0.5, 1.0);  // we don't have a mid irrigation figure, so lets assume 60% at mid point
+			irrigParm = defaultParam; 
 		}
+
 		return irrigParm;
 	}
 	
-	private double calcParam(double yMin, double yMid, double yMax, double xMin, double xMid, double xMax) {
+	private static double calcParam(double yMin, double yMid, double yMax, double xMin, double xMid, double xMax) {
 		if (yMid <= yMin || yMax <= yMid)
-			return 1;  // default to linear
+			return defaultParam;
 
-		return Math.log((yMid - yMin)/(yMax - yMin)) / Math.log((xMid - xMin)/(xMax - xMin)) / xMax;
+		return -Math.log(1 - ((yMid-yMin)/(yMax-yMin))) * (xMax-xMin) / (xMid-xMin); 					// 1-exp(-x) function
+	//	return Math.log((yMid - yMin)/(yMax - yMin)) / Math.log((xMid - xMin)/(xMax - xMin)) / xMax;  	// Cobb-Douglas
 	}
+	
 }
\ No newline at end of file
diff --git a/src/ac/ed/lurg/yield/YieldResponsesItem.java b/src/ac/ed/lurg/yield/YieldResponsesItem.java
index 159d5554..d90f6ade 100644
--- a/src/ac/ed/lurg/yield/YieldResponsesItem.java
+++ b/src/ac/ed/lurg/yield/YieldResponsesItem.java
@@ -5,7 +5,6 @@ import java.util.Map;
 
 import ac.ed.lurg.types.CropType;
 import ac.ed.lurg.types.YieldType;
-import ac.ed.lurg.utils.LogWriter;
 import ac.sac.raster.RasterItem;
 
 public class YieldResponsesItem implements RasterItem {
@@ -28,9 +27,6 @@ public class YieldResponsesItem implements RasterItem {
 	public double getYield(YieldType yieldType, CropType crop) {
 		YieldResponse yr = getYieldResponseForCrop(crop);
 		double d = yr.getYield(yieldType);
-		if (Double.isNaN(d)) {
-			LogWriter.printlnError("YieldResponses: No yield found for type " + yieldType + ", crop " + crop);
-		}
 		return d;
 	}	
 
diff --git a/src/ac/sac/raster/AbstractTabularRasterReader.java b/src/ac/sac/raster/AbstractTabularRasterReader.java
index dd3fdb47..1cabc85d 100644
--- a/src/ac/sac/raster/AbstractTabularRasterReader.java
+++ b/src/ac/sac/raster/AbstractTabularRasterReader.java
@@ -40,7 +40,7 @@ public abstract class AbstractTabularRasterReader<D extends RasterItem> {
 		//	List<String> colNames = new ArrayList<String>(Arrays.asList(headertokens));
 
 		for (int i=0; i<headertokens.length; i++) {
-			headertokens[i] = headertokens[i].toLowerCase();
+			headertokens[i] = headertokens[i].toLowerCase().replace("\"", "");
 		}
 		
 		return headertokens;
-- 
GitLab