From 986f5b74409b126daed87851731be6c47703746c Mon Sep 17 00:00:00 2001
From: Peter Alexander <p.m.w.alexander@gmail.com>
Date: Wed, 17 Jul 2019 23:21:30 +0100
Subject: [PATCH] Bug fixes to stock level based price adjustment

---
 scripts/runPlum.sh                      |  2 +-
 src/ac/ed/lurg/InternationalMarket.java |  2 +-
 src/ac/ed/lurg/country/GlobalPrice.java | 44 ++++++++++++++++---------
 3 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/scripts/runPlum.sh b/scripts/runPlum.sh
index c2983c97..2fcb597e 100755
--- a/scripts/runPlum.sh
+++ b/scripts/runPlum.sh
@@ -76,7 +76,7 @@ fi
 cd $scenariodir
 
 echo "starting"
-runcmd="java -Xmx1G -XX:+PrintGC -classpath $GAMSPATH/apifiles/Java/api/GAMSJavaAPI.jar:$classesdir -DBUILDVER=$buildver -DCONFIG_FILE=$scenariodir/config.properties ac.ed.lurg.ModelMain"
+runcmd="java -Xmx2G -XX:+PrintGC -classpath $GAMSPATH/apifiles/Java/api/GAMSJavaAPI.jar:$classesdir -DBUILDVER=$buildver -DCONFIG_FILE=$scenariodir/config.properties ac.ed.lurg.ModelMain"
 echo $runcmd
 $runcmd
 echo "finished"
diff --git a/src/ac/ed/lurg/InternationalMarket.java b/src/ac/ed/lurg/InternationalMarket.java
index a34e824c..262531cd 100644
--- a/src/ac/ed/lurg/InternationalMarket.java
+++ b/src/ac/ed/lurg/InternationalMarket.java
@@ -68,7 +68,7 @@ public class InternationalMarket {
 			GlobalPrice prevPrice = worldPrices.get(crop);
 			double imports = totalImportCommodities.containsKey(crop) ? totalImportCommodities.get(crop) : 0.0;
 			double exportsBeforeTransportLosses = totalExportCommodities.containsKey(crop) ? totalExportCommodities.get(crop) : 0.0;
-			LogWriter.print("Updating " + crop.getGamsName() + " prices : ");
+			LogWriter.print(timestep.getYear() + " Updating " + crop.getGamsName() + " prices : ");
 			GlobalPrice adjustedPrice = prevPrice.createWithUpdatedMarketPrices(imports, exportsBeforeTransportLosses, timestep, totalProduction.get(crop));
 			LogWriter.println( String.format("Price for %s updated from %s to %s \n", crop.getGamsName(), prevPrice, adjustedPrice));
 			worldPrices.put(crop, adjustedPrice);
diff --git a/src/ac/ed/lurg/country/GlobalPrice.java b/src/ac/ed/lurg/country/GlobalPrice.java
index b4b30601..aee2d8f8 100644
--- a/src/ac/ed/lurg/country/GlobalPrice.java
+++ b/src/ac/ed/lurg/country/GlobalPrice.java
@@ -6,13 +6,15 @@ import ac.ed.lurg.types.Parameter;
 import ac.ed.lurg.utils.LogWriter;
 
 public class GlobalPrice {
+	private int timestepId;
 	private double exportPrice;
 	private double importAmount;
 	private double exportAmountBeforeLoss;
 	private double transportLosses;
 	private double stockLevel;
 
-	private GlobalPrice(double exportPrice, double stockLevel, double importAmount, double exportAmountBeforeLoss, double transportLosses) {
+	private GlobalPrice(int timestepId, double exportPrice, double stockLevel, double importAmount, double exportAmountBeforeLoss, double transportLosses) {
+		this.timestepId = timestepId;
 		this.exportPrice = exportPrice;
 		this.stockLevel = stockLevel;
 		this.importAmount = importAmount;
@@ -21,7 +23,7 @@ public class GlobalPrice {
 	}
 	
 	public static GlobalPrice createInitial(double exportPrice) {
-		return new GlobalPrice(exportPrice, Double.NaN, Double.NaN, Double.NaN, Double.NaN);
+		return new GlobalPrice(ModelConfig.START_TIMESTEP-1, exportPrice, Double.NaN, Double.NaN, Double.NaN, Double.NaN);
 	}
 	
 	public double getExportPrice(){
@@ -61,18 +63,23 @@ public class GlobalPrice {
 		return transportLosses;
 	}
 
-	public GlobalPrice createWithUpdatedMarketPrices(double imports, double exportsBeforeTransportLosses, Timestep timestep, double production) {
+	public GlobalPrice createWithUpdatedMarketPrices(double newImports, double newExportAmountBeforeLoss, Timestep timestep, double production) {
 
 		if (Double.isNaN(stockLevel))
 			stockLevel = ModelConfig.STOCK_TARGET_RATE * production;  // set stock initially to target level, this is pretty horrible and should really be done on construction but don't easily have production value at that point
 
 		double transportLossRate = (!ModelConfig.SHOCKS_POSSIBLE) ? ModelConfig.TRANSPORT_LOSSES : ModelConfig.getParameter(Parameter.TRANSPORT_LOSSES, timestep.getYear());
-		double transportLosses = exportsBeforeTransportLosses * transportLossRate;
-		double exportsAfterTransportLosses = exportsBeforeTransportLosses - transportLosses;
+		double newTransportLosses = newExportAmountBeforeLoss * transportLossRate;
+		double exportsAfterTransportLosses = newExportAmountBeforeLoss - newTransportLosses;
 		
-		if (imports > 0 || exportsAfterTransportLosses > 0) {
-			double updatedStock = stockLevel + exportsBeforeTransportLosses - transportLosses - imports;
-			LogWriter.println(String.format(" global stocks from %.2f to %.2f", stockLevel, updatedStock));
+		if (newImports > 0 || exportsAfterTransportLosses > 0) {
+			double oldDiff = 0;
+			if (timestep.getTimestep() == timestepId)  // if recomputing for same year need to back our previous adjustment
+				oldDiff = exportAmountBeforeLoss - transportLosses - importAmount;
+			double newDiff = newExportAmountBeforeLoss - newTransportLosses - newImports;
+			double updatedStock = stockLevel + newDiff - oldDiff;
+			
+			LogWriter.println(String.format(" global stocks from %.2f to %.2f due to newDiff %.2f oldDiff %.2f", stockLevel, updatedStock, newDiff, oldDiff));
 			if (updatedStock < 0)
 				LogWriter.println(String.format("Global stocks are below zero"));
 			
@@ -83,24 +90,30 @@ public class GlobalPrice {
 				adjustment = 1;
 			}
 			else if (ModelConfig.PRICE_UPDATE_BY_MARKET_IMBALANCE) {
-				double ratio = (imports-exportsAfterTransportLosses)/(imports-exportsAfterTransportLosses+production);
+				double ratio = (newImports-exportsAfterTransportLosses)/(newImports-exportsAfterTransportLosses+production);
 				adjustment =  Math.exp(ratio * ModelConfig.MARKET_LAMBA);
-				LogWriter.println(String.format("Price update market imbalance: adjustment= %s, imports %.1f, exports %.1f", adjustment, imports, getExportsAfterTransportLosses()));
+				LogWriter.println(String.format("Price update market imbalance: adjustment= %.4f, imports %.1f, exports %.1f", adjustment, newImports, getExportsAfterTransportLosses()));
 			}
 			else {
 				double stockTarget = ModelConfig.STOCK_TARGET_RATE * production;
 				double ratio = (stockTarget - updatedStock) / stockTarget;
 				
-				if (Math.abs(ratio) >= 1)
-					adjustment = 10;  // default to max change
-				else
+				if (ratio >= 0) {
 					adjustment = 1 + ModelConfig.MARKET_LAMBA * ratio/(1 - ratio*ratio);
+					if (adjustment > 3 || ratio > 1)
+						adjustment = 3;  // default to max up change
+				}
+				else {
+					adjustment = 1 / ( 1 - ModelConfig.MARKET_LAMBA * ratio/(1 - ratio*ratio));
+					if (adjustment < 0.1  || ratio < -1)
+						adjustment = 0.1;  // default to max down change
+				}
 				
-				LogWriter.println(String.format("Price update from stock target: adjustment= %s, ratio= %s", adjustment, ratio));
+				LogWriter.println(String.format("Price update from stock target: adjustment= %.4f, ratio= %.4f", adjustment, ratio));
 			}
 			
 			newPrice = exportPrice * adjustment * financialSpeculationMultiplier;
-			return new GlobalPrice(newPrice, updatedStock, imports, exportsBeforeTransportLosses, transportLosses);			
+			return new GlobalPrice(timestep.getTimestep(), newPrice, updatedStock, newImports, newExportAmountBeforeLoss, newTransportLosses);			
 		}
 		else {
 			LogWriter.printlnError(String.format("Price for not updated (still %s), as no imports and no exports for it", exportPrice));
@@ -117,3 +130,4 @@ public class GlobalPrice {
 		return exportAmountBeforeLoss - transportLosses - importAmount;
 	}
 }
+
-- 
GitLab