From 425084a8647b54b66afb467acad7aaf7d8d0c217 Mon Sep 17 00:00:00 2001
From: Bart Arendarczyk <s1924442@ed.ac.uk>
Date: Fri, 26 May 2023 11:38:11 +0100
Subject: [PATCH]  Added constraint to limit global increases in exports.

---
 src/ac/ed/lurg/InternationalMarket.java  |  6 ++---
 src/ac/ed/lurg/ModelConfig.java          | 34 ++++++++++++------------
 src/ac/ed/lurg/country/CountryAgent.java |  6 ++---
 src/ac/ed/lurg/country/GlobalPrice.java  | 12 +++++++--
 4 files changed, 33 insertions(+), 25 deletions(-)

diff --git a/src/ac/ed/lurg/InternationalMarket.java b/src/ac/ed/lurg/InternationalMarket.java
index 098483d3..11b67d68 100644
--- a/src/ac/ed/lurg/InternationalMarket.java
+++ b/src/ac/ed/lurg/InternationalMarket.java
@@ -102,15 +102,15 @@ public class InternationalMarket {
 		for (Entry<CropType, GlobalPrice> entry : worldPrices.entrySet()) {
 			Double initialStock = initialStockLevels.get(entry.getKey());
 			if (initialStock != null) {
-				entry.getValue().setStockToTargetLevel();
+				entry.getValue().setStockToTargetLevel(entry.getKey().getStockToUseRatio());
 			}
 		}
 
 		for (Map.Entry<WoodType, GlobalPrice> entry : woodPrices.entrySet()) {
-			entry.getValue().setStockToTargetLevel();
+			entry.getValue().setStockToTargetLevel(ModelConfig.DEFAULT_STOCK_USE_RATIO);
 		}
 
-		carbonPrice.resetStock(0.0);
+		carbonPrice.setStockToTargetLevel(ModelConfig.DEFAULT_STOCK_USE_RATIO);
 	}
 
 	void determineInternationalTrade(Collection<AbstractCountryAgent> countryAgents, Timestep timestep) {
diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java
index 5f1c05e1..6fc46c13 100755
--- a/src/ac/ed/lurg/ModelConfig.java
+++ b/src/ac/ed/lurg/ModelConfig.java
@@ -283,18 +283,18 @@ public class ModelConfig {
 	public static final String PASTURE_C4_COLUMN  = getProperty("PASTURE_C4_COLUMN", "C4G_pas");
 
 	// These are production prices in PLUM style feed equivalent terms
-	public static final double INITAL_PRICE_WHEAT = getDoubleProperty("INITAL_PRICE_WHEAT", 0.0556);
-	public static final double INITAL_PRICE_MAIZE = getDoubleProperty("INITAL_PRICE_MAIZE", 0.0361);
-	public static final double INITAL_PRICE_RICE = getDoubleProperty("INITAL_PRICE_RICE", 0.0704);
-	public static final double INITAL_PRICE_OILCROPS_NFIX = getDoubleProperty("INITAL_PRICE_OILCROPS_NFIX", 0.0901);
-	public static final double INITAL_PRICE_OILCROPS_OTHER = getDoubleProperty("INITAL_PRICE_OILCROPS_OTHER", 0.0899);
-	public static final double INITAL_PRICE_PULSES = getDoubleProperty("INITAL_PRICE_PULSES", 0.0948);
-	public static final double INITAL_PRICE_STARCHYROOTS = getDoubleProperty("INITAL_PRICE_STARCHYROOTS", 0.0302);
-	public static final double INITAL_PRICE_MONOGASTRICS = getDoubleProperty("INITAL_PRICE_MONOGASTRICS", 0.0984); // value from calibration
-	public static final double INITAL_PRICE_RUMINANTS = getDoubleProperty("INITAL_PRICE_RUMINANTS", 0.115); // value from calibration
-	public static final double INITAL_PRICE_ENERGYCROPS = getDoubleProperty("INITAL_PRICE_ENERGYCROPS", 0.014);
-	public static final double INITAL_PRICE_FRUITVEG = getDoubleProperty("INITAL_PRICE_FRUITVEG", 0.0459);
-	public static final double INITAL_PRICE_SUGAR = getDoubleProperty("INITAL_PRICE_SUGAR", 0.0096);
+	public static final double INITAL_PRICE_WHEAT = getDoubleProperty("INITAL_PRICE_WHEAT", 0.0521);
+	public static final double INITAL_PRICE_MAIZE = getDoubleProperty("INITAL_PRICE_MAIZE", 0.0331);
+	public static final double INITAL_PRICE_RICE = getDoubleProperty("INITAL_PRICE_RICE", 0.0635);
+	public static final double INITAL_PRICE_OILCROPS_NFIX = getDoubleProperty("INITAL_PRICE_OILCROPS_NFIX", 0.0894);
+	public static final double INITAL_PRICE_OILCROPS_OTHER = getDoubleProperty("INITAL_PRICE_OILCROPS_OTHER", 0.0851);
+	public static final double INITAL_PRICE_PULSES = getDoubleProperty("INITAL_PRICE_PULSES", 0.0961);
+	public static final double INITAL_PRICE_STARCHYROOTS = getDoubleProperty("INITAL_PRICE_STARCHYROOTS", 0.0273);
+	public static final double INITAL_PRICE_MONOGASTRICS = getDoubleProperty("INITAL_PRICE_MONOGASTRICS", 0.0959); // value from calibration
+	public static final double INITAL_PRICE_RUMINANTS = getDoubleProperty("INITAL_PRICE_RUMINANTS", 0.111); // value from calibration
+	public static final double INITAL_PRICE_ENERGYCROPS = getDoubleProperty("INITAL_PRICE_ENERGYCROPS", 0.0127);
+	public static final double INITAL_PRICE_FRUITVEG = getDoubleProperty("INITAL_PRICE_FRUITVEG", 0.0400);
+	public static final double INITAL_PRICE_SUGAR = getDoubleProperty("INITAL_PRICE_SUGAR", 0.00948);
 
 	// These are initial demand system prices in 2000 kcal terms
 	public static final double INITAL_DEMAND_PRICE_CEREALS_STARCHY_ROOTS = getDoubleProperty("INITAL_DEMAND_PRICE_CEREALS_STARCHY_ROOTS", 110.23);
@@ -410,7 +410,7 @@ public class ModelConfig {
 	public static final String CHECKPOINT_WOOD_USAGE_FILE = getProperty("CHECKPOINT_WOOD_USAGE_FILE", OUTPUT_DIR + File.separator +  SERIALIZED_WOOD_USAGE_FILENAME);
 	public static final String CHECKPOINT_CARBON_USAGE_FILE = getProperty("CHECKPOINT_CARBON_USAGE_FILE", OUTPUT_DIR + File.separator +  SERIALIZED_CARBON_USAGE_FILENAME);
 	public static final boolean USE_INITIAL_CROP_USAGE_DATA = getBooleanProperty("USE_INITIAL_CROP_USAGE_DATA", false); // Read crop usage from file rather than serialized
-	public static final int CALIB_TRANSITION_TIME = getIntProperty("CALIB_TRANSITION_TIME", 10); // transition from calibration to current values over this time
+	public static final int CALIB_TRANSITION_TIME = getIntProperty("CALIB_TRANSITION_TIME", 20); // transition from calibration to current values over this time
 
 	public static final boolean MARKET_ADJ_PRICE = getBooleanProperty("MARKET_ADJ_PRICE", true);
 	public static final boolean CHANGE_YIELD_DATA_YEAR = IS_CALIBRATION_RUN ? false : getBooleanProperty("CHANGE_YIELD_DATA_YEAR", true);
@@ -427,7 +427,7 @@ public class ModelConfig {
 	// Import export limits
 	public static final double ANNUAL_MAX_IMPORT_CHANGE = getDoubleProperty("ANNUAL_MAX_IMPORT_CHANGE", 0.5); // Loose constraint as we have TRADE_ADJUSTMENT_COST_RATE
 	public static final double MAX_IMPORT_CHANGE = getDoubleProperty("MAX_IMPORT_CHANGE", ANNUAL_MAX_IMPORT_CHANGE*TIMESTEP_SIZE);
-	public static final double TRADE_ADJUSTMENT_COST_RATE = getDoubleProperty("TRADE_ADJUSTMENT_COST_RATE", 0.004); // Cost of changing imports/exports
+	public static final double TRADE_ADJUSTMENT_COST_RATE = getDoubleProperty("TRADE_ADJUSTMENT_COST_RATE", 0.006); // Cost of changing imports/exports
 	
 	// Price caps
 	public static final String PRICE_CAP_FILE = DATA_DIR + File.separator + "price_caps.csv";
@@ -487,7 +487,7 @@ public class ModelConfig {
 	public static final boolean RESET_ENERGYCROP_PRICE = getBooleanProperty("RESET_ENERGYCROP_PRICE", false); // Resets price after calibration to avoid problems due to low initial demand
 	//	public static final double BIOENERGY_HEATING_VALUE_GJ_PER_T = getDoubleProperty("BIOENERGY_HEATING_VALUE_GJ_PER_T", 17.5); // GJ per t DM
 
-	public static final double MARKET_LAMBDA = getDoubleProperty("MARKET_LAMBDA", 1.6); // controls international market price adjustment rate
+	public static final double MARKET_LAMBDA = getDoubleProperty("MARKET_LAMBDA", 1.0); // controls international market price adjustment rate
 	public static final double MARKET_DELTA = getDoubleProperty("MARKET_DELTA", 0.01); // price adjustment sensitivity to stock use ratio imbalance
 	public static final double DEFAULT_STOCK_USE_RATIO = getDoubleProperty("DEFAULT_STOCK_USE_RATIO", 0.3);
 
@@ -581,8 +581,8 @@ public class ModelConfig {
 	public static final double FOREST_MANAGEMENT_COST = IS_FORESTRY_ON ? getDoubleProperty("FOREST_MANAGEMENT_COST", 2.0) : 0.0; // establishment, management etc. $1000/ha
 	public static final double FOREST_BASE_COST = getDoubleProperty("FOREST_BASE_COST", 0.12); // $1000/ha
 	public static final double WOOD_TRADE_BARRIER = getDoubleProperty("WOOD_TRADE_BARRIER", 0.1); //$1000/m3
-	public static final double INIT_ROUNDWOOD_PRICE = IS_FORESTRY_ON ? getDoubleProperty("INIT_ROUNDWOOD_PRICE", 0.06) : 0.0; // $1000/m3
-	public static final double INIT_FUELWOOD_PRICE = IS_FORESTRY_ON ? getDoubleProperty("INIT_FUELWOOD_PRICE", 0.04) : 0.0; // $1000/m3
+	public static final double INIT_ROUNDWOOD_PRICE = IS_FORESTRY_ON ? getDoubleProperty("INIT_ROUNDWOOD_PRICE", 0.0655) : 0.0; // $1000/m3
+	public static final double INIT_FUELWOOD_PRICE = IS_FORESTRY_ON ? getDoubleProperty("INIT_FUELWOOD_PRICE", 0.0461) : 0.0; // $1000/m3
 	public static final int CARBON_WOOD_MAX_TIME = getIntProperty("CARBON_WOOD_MAX_TIME", 160); // upper data limit, years
 	
 	// Carbon
diff --git a/src/ac/ed/lurg/country/CountryAgent.java b/src/ac/ed/lurg/country/CountryAgent.java
index bbb49d9e..92c68420 100644
--- a/src/ac/ed/lurg/country/CountryAgent.java
+++ b/src/ac/ed/lurg/country/CountryAgent.java
@@ -178,7 +178,7 @@ public class CountryAgent extends AbstractCountryAgent {
 
 				if (crop.isImportedCrop()) {
 					changeUp = cropPrice.getTradeChangeUp(maxOfProdOrSupply);
-					//changeDown = cropPrice.getTradeChangeDown(maxOfProdOrSupply, crop.getStockToUseRatio());
+					changeDown = cropPrice.getTradeChangeDown(maxOfProdOrSupply, crop.getStockToUseRatio());
 
 					if (changeUp < 0) { // need to reduce imports to avoid negative stocks
 						baseTrade += changeUp;
@@ -225,7 +225,7 @@ public class CountryAgent extends AbstractCountryAgent {
 			} else {
 				double maxOfProdOrSupply = carbonUsageData.getCarbonCredits() + Math.max(baseTrade, 0);
 				changeUp = globalCarbonPrice.getTradeChangeUp(maxOfProdOrSupply);
-				changeDown = maxOfProdOrSupply * ModelConfig.MAX_IMPORT_CHANGE;
+				changeDown = globalCarbonPrice.getTradeChangeDown(maxOfProdOrSupply, ModelConfig.DEFAULT_STOCK_USE_RATIO);
 
 				if (changeUp < 0) { // need to reduce imports to avoid negative stocks
 					baseTrade += changeUp;
@@ -260,7 +260,7 @@ public class CountryAgent extends AbstractCountryAgent {
 				changeUp = changeDown = 0.0;
 			} else {
 				changeUp = woodPrice.getTradeChangeUp(maxOfProdOrSupply);
-				changeDown = maxOfProdOrSupply * ModelConfig.MAX_IMPORT_CHANGE;
+				changeDown = woodPrice.getTradeChangeDown(maxOfProdOrSupply, ModelConfig.DEFAULT_STOCK_USE_RATIO);
 
 				if (changeUp < 0) { // need to reduce imports to avoid negative stocks
 					baseTrade += changeUp;
diff --git a/src/ac/ed/lurg/country/GlobalPrice.java b/src/ac/ed/lurg/country/GlobalPrice.java
index 614ba705..f250f571 100644
--- a/src/ac/ed/lurg/country/GlobalPrice.java
+++ b/src/ac/ed/lurg/country/GlobalPrice.java
@@ -190,8 +190,8 @@ public class GlobalPrice implements Serializable {
 		this.stockLevel = stock;
 	}
 
-	public void setStockToTargetLevel() {
-		stockLevel = production * stockUseRatio;
+	public void setStockToTargetLevel(double targetStockUseRatio) {
+		stockLevel = production * targetStockUseRatio;
 	}
 
 	public double getTradeChangeUp(double maxOfProdOrSupply) {
@@ -205,4 +205,12 @@ public class GlobalPrice implements Serializable {
 		return (0.9 * stockLevel - (importAmount - getExportsAfterTransportLosses())) * supplyFraction;
 	}
 
+	public double getTradeChangeDown(double maxOfProdOrSupply, double targetStockUseRatio) {
+		maxOfProdOrSupply += 0.05 * production / CountryManager.getInstance().getCountryCount();
+		double supplyFraction = maxOfProdOrSupply / (production * 1.05);
+		double stockShortfall = Math.max(0, production * targetStockUseRatio - stockLevel); // allow additional exports to replenish stocks
+		double exportShortfall = Math.max(0, 1.1 * importAmount - getExportsAfterTransportLosses()); // allow 10% excess exports
+		return supplyFraction * (exportShortfall + stockShortfall);
+	}
+
 }
\ No newline at end of file
-- 
GitLab