diff --git a/data/global_stocks.csv b/data/global_stocks.csv index 69c06771186276afb2943d05d27c67aede01dff5..439a5d4764adc1a68131ed95de3bf2a2afb550cf 100644 --- a/data/global_stocks.csv +++ b/data/global_stocks.csv @@ -1,11 +1,12 @@ -plumCropItem,V1 -FruitVeg,182.092751337307 -WheatBarleyOats,879.537641313273 -Pulses,46.532195 -Starchy Roots,410.796684630225 -Oilcrops,378.961539547602 -MaizeMilletSorghum,810.753713560517 -Sugar,1484.01363920056 -Rice (Paddy Equivalent),439.184612481259 -Ruminants,412.1217514 -Monogastrics,45.6726812 +plumCropItem,V1 +FruitVeg,182.092751337307 +WheatBarleyOats,879.537641313273 +Pulses,46.532195 +Starchy Roots,410.796684630225 +Oilcrops,378.961539547602 +MaizeMilletSorghum,810.753713560517 +Sugar,1484.01363920056 +Rice (Paddy Equivalent),439.184612481259 +Ruminants,412.1217514 +Monogastrics,45.6726812 +Energy crops,20 \ No newline at end of file diff --git a/scripts/runPlum.sh b/scripts/runPlum.sh index c2983c97ccb93882a752ccd6ad8704fa28ad48ea..2fcb597ed6245b3d8dc557bb10db939d2ee2e6a1 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 a34e824cbf79fdd142999e43cba2e2deb50a5846..e2c4d25933363c8013050af2168cb0599b02b3ea 100644 --- a/src/ac/ed/lurg/InternationalMarket.java +++ b/src/ac/ed/lurg/InternationalMarket.java @@ -9,6 +9,7 @@ import java.util.Map.Entry; import ac.ed.lurg.country.AbstractCountryAgent; import ac.ed.lurg.country.GlobalPrice; +import ac.ed.lurg.country.StockReader; import ac.ed.lurg.landuse.CropUsageData; import ac.ed.lurg.types.CropToDoubleMap; import ac.ed.lurg.types.CropType; @@ -19,11 +20,11 @@ public class InternationalMarket { private Map<CropType, GlobalPrice> worldPrices = new HashMap<CropType, GlobalPrice>(); public InternationalMarket() { - //Map<CropType, Double> stockLevel = getInitialStockLevels(); + Map<CropType, Double> stockLevel = getInitialStockLevels(); for (CropType crop : CropType.getImportedTypes()) { - //Double stock = stockLevel.get(crop); - worldPrices.put(crop, GlobalPrice.createInitial(crop.getInitialPrice())); + Double initialStock = stockLevel.get(crop); + worldPrices.put(crop, GlobalPrice.createInitial(crop.getInitialPrice(), initialStock)); } } @@ -31,11 +32,11 @@ public class InternationalMarket { return worldPrices; } -/* private Map<CropType, Double> getInitialStockLevels() { + private Map<CropType, Double> getInitialStockLevels() { Map<CropType, Double> initialStockLevels = new StockReader().read(); initialStockLevels.put(CropType.ENERGY_CROPS, 0.0); return initialStockLevels; - } */ + } void determineInternationalTrade(Collection<AbstractCountryAgent> countryAgents, double gen2EcDDemand, Timestep timestep) { CropToDoubleMap totalImportCommodities = new CropToDoubleMap(); @@ -68,9 +69,12 @@ 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.println(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)); + if (adjustedPrice.getStockLevel() < 0) + LogWriter.println("Global stocks are below zero" + crop.getGamsName() + ", " + timestep.getYear()); + worldPrices.put(crop, adjustedPrice); } } diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java index 010dab2061e2a6a997c8afdbb57db3050f003adf..28ac95a6469e1fd87b15e46466b184db05204cbe 100755 --- a/src/ac/ed/lurg/ModelConfig.java +++ b/src/ac/ed/lurg/ModelConfig.java @@ -209,7 +209,7 @@ public class ModelConfig { public static final double INITAL_PRICE_MONOGASTRICS = getDoubleProperty("INITAL_PRICE_MONOGASTRICS", 0.4 * 0.5 * ModelConfig.INITIAL_PRICE_SHIFT); // quantities is in feed equivalent term (0.4 is weighted average price per feed, and 0.5 accounts for mark-up for additional processing) public static final double INITAL_PRICE_RUMINANTS = getDoubleProperty("INITAL_PRICE_RUMINANTS", 0.1 * 0.6 * ModelConfig.INITIAL_PRICE_SHIFT); // quantities is in feed equivalent term public static final double INITAL_PRICE_ENERGYCROPS = getDoubleProperty("INITAL_PRICE_ENERGYCROPS", 0.04 * ModelConfig.INITIAL_PRICE_SHIFT); - public static final double INITAL_PRICE_FRUITVEG = getDoubleProperty("INITAL_PRICE_FRUITVEG", 0.3 * ModelConfig.INITIAL_PRICE_SHIFT); + public static final double INITAL_PRICE_FRUITVEG = getDoubleProperty("INITAL_PRICE_FRUITVEG", 0.1 * ModelConfig.INITIAL_PRICE_SHIFT); public static final double INITAL_PRICE_SUGAR = getDoubleProperty("INITAL_PRICE_SUGAR", 0.02 * ModelConfig.INITIAL_PRICE_SHIFT); // These are initial demand system prices in 2000 kcal terms @@ -269,7 +269,7 @@ public class ModelConfig { public static final int BASE_YEAR = getIntProperty("BASE_YEAR", 2010); // Import export limits - public static final double ANNUAL_MAX_IMPORT_CHANGE = IS_CALIBRATION_RUN ? 0.0 : getDoubleProperty("ANNUAL_MAX_IMPORT_CHANGE", 0.02); + public static final double ANNUAL_MAX_IMPORT_CHANGE = IS_CALIBRATION_RUN ? 0.0 : getDoubleProperty("ANNUAL_MAX_IMPORT_CHANGE", 0.05); public static final double MAX_IMPORT_CHANGE = IS_CALIBRATION_RUN ? 0.0 : getDoubleProperty("MAX_IMPORT_CHANGE", ANNUAL_MAX_IMPORT_CHANGE*TIMESTEP_SIZE); // Fertiliser application rates in kg/ha @@ -344,7 +344,8 @@ public class ModelConfig { public static final double MARKET_LAMBA = getDoubleProperty("MARKET_LAMBA", 0.4); // controls international market price adjustment rate public static final boolean PRICE_UPDATE_BY_MARKET_IMBALANCE = getBooleanProperty("PRICE_UPDATE_BY_MARKET_IMBALANCE", false);; - public static final double STOCK_TARGET_RATE = getDoubleProperty("STOCK_TARGET_RATE", 0.05); + public static final double MAX_PRICE_INCREASE = getDoubleProperty("MAX_PRICE_INCREASE", 1.5); + public static final double MAX_PRICE_DECREASE = getDoubleProperty("MAX_PRICE_DECREASE", .75); public static final int DEMAND_RECALC_MAX_ITERATIONS = getIntProperty("DEMAND_RECALC_MAX_ITERATIONS", 0); // 0 is original behaviour public static final double POPULATION_AGGREG_LIMIT = getDoubleProperty("POPULATION_AGGREG_LIMIT", 30.0); // in millions, smaller countries are aggregated on a regional basis diff --git a/src/ac/ed/lurg/country/GlobalPrice.java b/src/ac/ed/lurg/country/GlobalPrice.java index b4b30601ee138bd2df1739fc527ab322b41aead8..181320b5c295a15ceb9ff95a39651e45e296c69c 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; @@ -20,8 +22,8 @@ public class GlobalPrice { this.transportLosses = transportLosses; } - public static GlobalPrice createInitial(double exportPrice) { - return new GlobalPrice(exportPrice, Double.NaN, Double.NaN, Double.NaN, Double.NaN); + public static GlobalPrice createInitial(double exportPrice, double intitalStock) { + return new GlobalPrice(ModelConfig.START_TIMESTEP-1, exportPrice, intitalStock, Double.NaN, Double.NaN, Double.NaN); } public double getExportPrice(){ @@ -35,13 +37,11 @@ public class GlobalPrice { public double getCountryImportPrice(double countryTradeBarrier, Timestep timestep) { int currentYear = timestep.getYear(); - double tradeBarrierMultiplier = (!ModelConfig.SHOCKS_POSSIBLE)? ModelConfig.TRADE_BARRIER_MULTIPLIER: ModelConfig.getParameter(Parameter.TRADE_BARRIER_MULTIPLIER, currentYear); double transportLossesRate =(!ModelConfig.SHOCKS_POSSIBLE) ? ModelConfig.TRANSPORT_LOSSES : ModelConfig.getParameter(Parameter.TRANSPORT_LOSSES, currentYear); double transportCosts = (!ModelConfig.SHOCKS_POSSIBLE) ? ModelConfig.TRANSPORT_COST : ModelConfig.getParameter(Parameter.TRANSPORT_COST, currentYear); - double importPrice = exportPrice * (1 + transportCosts) * (1.0 + countryTradeBarrier*tradeBarrierMultiplier) - / (1.0 - transportLossesRate); + double importPrice = exportPrice * (1 + transportCosts) * (1.0 + countryTradeBarrier*tradeBarrierMultiplier) / (1.0 - transportLossesRate); return importPrice; } @@ -61,46 +61,48 @@ public class GlobalPrice { return transportLosses; } - public GlobalPrice createWithUpdatedMarketPrices(double imports, double exportsBeforeTransportLosses, 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 + public GlobalPrice createWithUpdatedMarketPrices(double newImports, double newExportAmountBeforeLoss, Timestep timestep, double production) { - double transportLossRate = (!ModelConfig.SHOCKS_POSSIBLE) ? ModelConfig.TRANSPORT_LOSSES : ModelConfig.getParameter(Parameter.TRANSPORT_LOSSES, timestep.getYear()); - double transportLosses = exportsBeforeTransportLosses * transportLossRate; - double exportsAfterTransportLosses = exportsBeforeTransportLosses - transportLosses; - - if (imports > 0 || exportsAfterTransportLosses > 0) { - double updatedStock = stockLevel + exportsBeforeTransportLosses - transportLosses - imports; - LogWriter.println(String.format(" global stocks from %.2f to %.2f", stockLevel, updatedStock)); - if (updatedStock < 0) - LogWriter.println(String.format("Global stocks are below zero")); + if (newImports > 0 || newExportAmountBeforeLoss > 0) { + double oldDiff = timestep.getTimestep() != timestepId ? 0.0 : exportAmountBeforeLoss - transportLosses - importAmount; // if recomputing for same year need to back our previous adjustment + double transportLossRate = (!ModelConfig.SHOCKS_POSSIBLE) ? ModelConfig.TRANSPORT_LOSSES : ModelConfig.getParameter(Parameter.TRANSPORT_LOSSES, timestep.getYear()); + double newTransportLosses = newExportAmountBeforeLoss * transportLossRate; + double stockChange = newExportAmountBeforeLoss - newTransportLosses - newImports - oldDiff; + double updatedStock = stockLevel + stockChange; + + LogWriter.println(String.format(" imports %.2f, exports %.2f", newImports, newExportAmountBeforeLoss - newTransportLosses)); + LogWriter.println(String.format(" updatedStock %.2f, previous %.2f (last timestep %.2f), stockChange %.2f, oldDiff %.2f", updatedStock, stockLevel, stockLevel-oldDiff, stockChange, oldDiff)); - double newPrice, adjustment; + double adjustment; double financialSpeculationMultiplier = (!ModelConfig.SHOCKS_POSSIBLE)? 1.0 : ModelConfig.getParameter(Parameter.FINANCIAL_SPECULATION_MULTIPLIER,timestep.getYear()); if (!ModelConfig.MARKET_ADJ_PRICE) { adjustment = 1; } else if (ModelConfig.PRICE_UPDATE_BY_MARKET_IMBALANCE) { - double ratio = (imports-exportsAfterTransportLosses)/(imports-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())); + double ratio = stockChange/(production-stockChange); + adjustment = Math.exp(-ratio * ModelConfig.MARKET_LAMBA); + LogWriter.println(String.format(" initally imbalance ratio= %.4f", ratio)); } else { - double stockTarget = ModelConfig.STOCK_TARGET_RATE * production; - double ratio = (stockTarget - updatedStock) / stockTarget; + if (stockChange >= 0) // stock increasing, so decrease price. stockChange is positive so adjustment < 1 + adjustment = 1 - ModelConfig.MARKET_LAMBA * stockChange/production; + else // stock decreasing, so increase price. stockChange is negative so adjustment > 1 + adjustment = 1 - ModelConfig.MARKET_LAMBA * stockChange/Math.max(0, stockLevel); - if (Math.abs(ratio) >= 1) - adjustment = 10; // default to max change - else - adjustment = 1 + ModelConfig.MARKET_LAMBA * ratio/(1 - ratio*ratio); - - LogWriter.println(String.format("Price update from stock target: adjustment= %s, ratio= %s", adjustment, ratio)); + LogWriter.print(String.format(" initally adjustment= %.4f", adjustment)); } - newPrice = exportPrice * adjustment * financialSpeculationMultiplier; - return new GlobalPrice(newPrice, updatedStock, imports, exportsBeforeTransportLosses, transportLosses); + if (adjustment < ModelConfig.MAX_PRICE_DECREASE) + adjustment = ModelConfig.MAX_PRICE_DECREASE; // default to max down change + + if (adjustment > ModelConfig.MAX_PRICE_INCREASE) + adjustment = ModelConfig.MAX_PRICE_INCREASE; // default to max up change + + LogWriter.println(String.format(", after limit %.4f", adjustment)); + + double newPrice = exportPrice * adjustment * financialSpeculationMultiplier; + 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)); @@ -116,4 +118,4 @@ public class GlobalPrice { public double getStockChange() { return exportAmountBeforeLoss - transportLosses - importAmount; } -} +} \ No newline at end of file