From 6a9cc12a7d772155a24ad8e7bcdbeb778b74e523 Mon Sep 17 00:00:00 2001 From: Bart Arendarczyk <s1924442@ed.ac.uk> Date: Tue, 23 Aug 2022 14:55:46 +0100 Subject: [PATCH] Added animal production cost to improve imports/exports. --- GAMS/IntExtOpt.gms | 26 +- src/ac/ed/lurg/ModelConfig.java | 854 +++++++-------- .../country/gams/GamsLocationOptimiser.java | 976 +++++++++--------- 3 files changed, 932 insertions(+), 924 deletions(-) diff --git a/GAMS/IntExtOpt.gms b/GAMS/IntExtOpt.gms index f69d1de3..2dacfcaf 100644 --- a/GAMS/IntExtOpt.gms +++ b/GAMS/IntExtOpt.gms @@ -7,6 +7,7 @@ SET feed_crop(crop) / wheat, maize, rice, oilcrops, pulses, starchyRoots, fruitveg, pasture/; SET feed_crop_less_pasture(feed_crop) / wheat, maize, rice, oilcrops, pulses, starchyRoots, fruitveg /; SET import_crop(all_types) / monogastrics, ruminants, wheat, maize, rice, oilcrops, pulses, starchyRoots, fruitveg, sugar, energycrops /; + SET animal(all_types) / monogastrics, ruminants /; SET location; PARAMETER suitableLandArea(location) areas of land in Mha; @@ -36,7 +37,7 @@ PARAMETER minDemandPerCereal(cereal_crop) min demand for each cereal crop as factor of all cereals; PARAMETER minDemandPerOilcrop(oilpulse_crop) min demand for oilcrop pulses as factor of total; PARAMETER seedAndWasteRate(all_types) rate of use for seed and waste combined; - PARAMETER subsidyRate(crop) rates of subsidy compared to costs; + PARAMETER subsidyRate(all_types) rates of subsidy compared to costs; PARAMETER agriExpansionCost(location) price for increase agricultural area varies based on amount of managed or unmanaged forest; SCALAR pastureIncCost price for increasing pasture area; @@ -93,9 +94,13 @@ $gdxin PARAMETER baseCost(crop); PARAMETER otherIntCost(crop); baseCost(crop) = prodCost(crop)*0.3; - otherIntCost(crop) = baseCost(crop)*0.7 + otherICost; + otherIntCost(crop) = prodCost(crop)*0.7 + otherICost; baseCost('pasture') = 0.04; otherIntCost('pasture') = 0.8 + otherICost; + + PARAMETER animalProdCost(animal); + animalProdCost('ruminants') = 0.35; + animalProdCost('monogastrics') = 0.25; VARIABLES area(crop, location) total area for each crop - Mha @@ -109,6 +114,7 @@ $gdxin yield(crop, location) yield per area for each crop - t per ha unitCost(crop, location) cost per area for each crop - cost net_supply(crop) supply after exports and feed + animalProd(animal) animal production agriLandExpansion(location) addition agricultural land needed as it must be positive it deliberately does not account for abandonment cropIncrease(location) cropDecrease(location) @@ -146,7 +152,9 @@ $gdxin CROP_DECREASE_CALC(location) PASTURE_INCREASE_CONV_CALC(location) PASTURE_DECREASE_CONV_CALC(location) - PASTURE_TOTAL_CHANGE_CONSTRAINT(location) + PASTURE_TOTAL_CHANGE_CONSTRAINT(location) + RUM_PROD_CALC ruminants production + MON_PROD_CALC monogastrics production COST_EQ total cost objective function; UNIT_COST_EQ(crop, location) .. unitCost(crop, location) =E= ( baseCost(crop) + @@ -171,6 +179,9 @@ $gdxin TOTAL_OIL_PULSE_DEMAND_CONSTRAINT .. sum(oilpulse_crop, net_supply(oilpulse_crop)) =G= demand('oilcropspulses'); + RUM_PROD_CALC .. animalProd('ruminants') =E= meatEfficency * sum(feed_crop, ruminantFeed(feed_crop) * cropDM(feed_crop)) * (1 - seedAndWasteRate('ruminants')); + MON_PROD_CALC .. animalProd('monogastrics') =E= meatEfficency * sum(feed_crop_less_pasture, monogastricFeed(feed_crop_less_pasture) * cropDM(feed_crop_less_pasture)) * (1 - seedAndWasteRate('monogastrics')); + RUMINANT_DEMAND_CONSTRAINT .. meatEfficency * sum(feed_crop, ruminantFeed(feed_crop) * cropDM(feed_crop)) * (1 - seedAndWasteRate('ruminants')) =G= (demand('ruminants') - importAmount('ruminants') + exportAmount('ruminants')); MONOGASTRICS_DEMAND_CONSTRAINT .. meatEfficency * sum(feed_crop_less_pasture, monogastricFeed(feed_crop_less_pasture) * cropDM(feed_crop_less_pasture)) * (1 - seedAndWasteRate('monogastrics')) =G= (demand('monogastrics') - importAmount('monogastrics') + exportAmount('monogastrics')); @@ -217,7 +228,8 @@ $gdxin ) ) * domesticPriceMarkup + - SUM(import_crop, importAmount(import_crop) * importPrices(import_crop) - exportAmount(import_crop) * exportPrices(import_crop)) + SUM(import_crop, importAmount(import_crop) * importPrices(import_crop) - exportAmount(import_crop) * exportPrices(import_crop)) + + SUM(animal, animalProd(animal) * animalProdCost(animal) * (1 - subsidyRate(animal))) ); MODEL LAND_USE /ALL/ ; @@ -261,15 +273,15 @@ $gdxin totalArea(crop) = sum(location, area.l(crop, location)); feedCostRate(feed_crop)$[totalProd(feed_crop) <> 0] = totalProdCost(feed_crop) / totalProd(feed_crop); - totalProdCost('ruminants') = sum(feed_crop, ruminantFeed.l(feed_crop) * feedCostRate(feed_crop)); - totalProdCost('monogastrics') = sum(feed_crop, monogastricFeed.l(feed_crop) * feedCostRate(feed_crop)); + totalProdCost('ruminants') = sum(feed_crop, ruminantFeed.l(feed_crop) * feedCostRate(feed_crop)) + animalProd.l('ruminants') * animalProdCost('ruminants'); + totalProdCost('monogastrics') = sum(feed_crop, monogastricFeed.l(feed_crop) * feedCostRate(feed_crop)) + animalProd.l('monogastrics') * animalProdCost('monogastrics'); netImportCost(import_crop) = importAmount.l(import_crop) * importPrices(import_crop) - exportAmount.l(import_crop) * exportPrices(import_crop); netImportAmount(import_crop) = importAmount.l(import_crop) - exportAmount.l(import_crop); Scalar totalCostsLessLU; - totalCostsLessLU = sum(crop,totalProdCost(crop))+ sum(import_crop,netImportCost(import_crop)); + totalCostsLessLU = sum(crop,totalProdCost(crop)) + sum(animal,totalProdCost(animal)) + sum(import_crop,netImportCost(import_crop)); Scalar ms 'model status', ss 'solve status'; diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java index 86a8a329..10b59b45 100755 --- a/src/ac/ed/lurg/ModelConfig.java +++ b/src/ac/ed/lurg/ModelConfig.java @@ -1,427 +1,427 @@ -package ac.ed.lurg; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Enumeration; -import java.util.Properties; - -import ac.ed.lurg.shock.parameterShocksReader; -import ac.ed.lurg.types.ModelFitType; -import ac.ed.lurg.types.PriceType; -import ac.ed.lurg.utils.LogWriter; - -public class ModelConfig { - - private Properties configFile; - private static ModelConfig modelConfig; - public static final String CONFIG_FILE = System.getProperty("CONFIG_FILE"); - - private static parameterShocksReader shocksReader; - - private ModelConfig() { - configFile = new Properties(); - try { - System.out.println("Config. file is " + CONFIG_FILE); - if (CONFIG_FILE != null) - configFile.load(new FileInputStream(CONFIG_FILE)); - } - catch (IOException e) { - System.err.println("Problems reading config file"); - System.err.println(e.getMessage()); - } - } - - public static String getSetupDetails() { - String buildVerion = System.getProperty("BUILDVER"); - StringBuffer sb = new StringBuffer("Build version: " + buildVerion + "\n"); - - Properties props = getModelConfig().configFile; - Enumeration<?> em = props.keys(); - while(em.hasMoreElements()) { - String str = (String) em.nextElement(); - sb.append(str + ": " + props.get(str) + "\n"); - } - - return sb.toString(); - } - - private static ModelConfig getModelConfig() { - if (modelConfig == null) - modelConfig = new ModelConfig(); - - return modelConfig; - } - - private static String getProperty(String prop) { - return getModelConfig().getProp(prop); - } - private static String getProperty(String prop, String defaultString) { - String propValue = getProperty(prop); - return propValue == null ? defaultString : propValue; - } - private String getProp(String prop) { - return configFile.getProperty(prop); - } - - private static Integer getIntProperty(String prop, Integer defaultInt) { - Integer propValue = getModelConfig().getIntProp(prop); - return propValue == null ? defaultInt : propValue; - } - private Integer getIntProp(String prop) { - String v = configFile.getProperty(prop); - return v==null ? null : Integer.valueOf(v); - } - - @SuppressWarnings("unused") - private static Long getLongProperty(String prop, Long defaultLong) { - Long propValue = getModelConfig().getLongProp(prop); - return propValue == null ? defaultLong : propValue; - } - private Long getLongProp(String prop) { - String v = configFile.getProperty(prop); - return v==null ? null : Long.valueOf(v); - } - - private static Double getDoubleProperty(String prop, Double defaultDouble) { - Double propValue = getModelConfig().getDoubleProp(prop); - return propValue == null ? defaultDouble : propValue; - } - private Double getDoubleProp(String prop) { - String v = configFile.getProperty(prop); - return v==null ? null : Double.valueOf(v); - } - - private static Boolean getBooleanProperty(String prop, Boolean defaultBoolean) { - return getModelConfig().getBooleanProp(prop, defaultBoolean); - } - private boolean getBooleanProp(String prop, Boolean defaultBoolean) { - String v = configFile.getProperty(prop); - return v==null ? defaultBoolean : Boolean.valueOf(v); - } - - public static double updateParameterForShocks(int year, String parameter) { - - Double value = null; - try { - value = getModelConfig().getClass().getField(parameter).getDouble(parameter); - - if(SHOCKS_POSSIBLE) { - - if (shocksReader == null) { - shocksReader = new parameterShocksReader(","); - shocksReader.read(SHOCKS_PARAMETER_FILE); - } - Double updatedValue = shocksReader.queryForParameter(year, parameter); - - if(updatedValue !=null) - value = updatedValue; - } - - } - catch (IllegalAccessException | NoSuchFieldException e) { - LogWriter.printlnError("cannot find parameter in model config to shock: " + parameter); - LogWriter.print(e); - } - return value; - } - - public static final boolean SUPPRESS_STD_OUTPUT = getBooleanProperty("SUPPRESS_STD_OUTPUT", Boolean.FALSE); - - // Directory information - public static final String BASE_DIR = getProperty("BASE_DIR"); // this must to be set in config file - public static final String OUTPUT_DIR = getProperty("OUTPUT_DIR", "."); - public static final String TEMP_DIR = getProperty("TEMP_DIR", OUTPUT_DIR + File.separator + "GamsTmp"); - public static final String DATA_DIR = getProperty("DATA_DIR", BASE_DIR + File.separator + "data"); - public static final String GAMS_DIR = getProperty("GAMS_DIR", BASE_DIR + File.separator + "GAMS"); - public static final boolean CLEANUP_GAMS_DIR = getBooleanProperty("CLEANUP_GAMS_DIR", false); - - public static final boolean ORIG_LEAST_COST_MIN = getBooleanProperty("ORIG_LEAST_COST_MIN", true); - public static final String GAMS_MODEL_NAME = getProperty("GAMS_MODEL_NAME", ORIG_LEAST_COST_MIN==true ? "IntExtOpt.gms" : "LUOpt.gms"); - public static final String GAMS_MODEL = getProperty("GAMS_MODEL", GAMS_DIR + File.separator + GAMS_MODEL_NAME); - public static final String DEMAND_GAMS_MODEL = getProperty("DEMAND_GAMS_MODEL", GAMS_DIR + File.separator + "elasticDemand.gms"); - public static final String DEMAND_PARAM_FILE = getProperty("DEMAND_PARAM_FILE", DATA_DIR + File.separator + "DemandParamConv.gdx"); - - // Country (non-gridded) data - public static final boolean DEMAND_FROM_FILE = getBooleanProperty("DEMAND_FROM_FILE", false); // used in hindcasting - public static final boolean PRICE_ELASTIC_DEMAND = getBooleanProperty("PRICE_ELASTIC_DEMAND", true); - public static final boolean DONT_REBASE_DEMAND = getBooleanProperty("DONT_REBASE_DEMAND", false);; - public static final String DEMAND_CURVES_FILE = getProperty("DEMAND_CURVES_FILE", DATA_DIR + File.separator + "com_curves.csv"); // either DEMAND_CURVES_FILE or DEMAND_CONSUMPTION_FILE is used, but not both - public static final String DEMAND_CONSUMPTION_FILE = getProperty("DEMAND_CONSUMPTION_FILE", DATA_DIR + File.separator + "hist_comsump.csv"); - public static final PriceType PRICE_CALCULATION = PriceType.findByName(getProperty("PRICE_CALCULATION", "weightedImportsExports")); - public static final String SSP_FILENAME = getProperty("SSP_FILENAME", "ssp.csv"); - public static final String SSP_FILE = getProperty("SSP_FILE", DATA_DIR + File.separator + SSP_FILENAME); - public static final String BASELINE_CONSUMP_FILE = DATA_DIR + File.separator + "base_consump.csv"; - public static final String CALORIE_PER_T_FILE = DATA_DIR + File.separator + "calories_per_t.csv"; - public static final String COUNTRY_CODES_FILE = DATA_DIR + File.separator + "country_codes4.csv"; - public static final String COUNTRY_DATA_FILE = DATA_DIR + File.separator + "country_data.csv"; - public static final String NET_IMPORTS_FILE = DATA_DIR + File.separator + "net_imports.csv"; - public static final String BIOENERGY_1GEN_BASE_DEMAND_FILE = DATA_DIR + File.separator + "bio_demand.csv"; - public static final String BIOENERGY_2GEN_DEMAND_FILENAME = getProperty("BIOENERGY_2GEN_DEMAND_FILENAME", "bioenergy_gen2_iiasa.csv"); - public static final String BIOENERGY_2GEN_DEMAND_FILE = getProperty("BIOENERGY_2GEN_DEMAND_FILE", DATA_DIR + File.separator + BIOENERGY_2GEN_DEMAND_FILENAME); - public static final String BIOENERGY_1GEN_FUTURE_DEMAND_FILENAME = getProperty("BIOENERGY_1GEN_FUTURE_DEMAND_FILENAME", "bioenergy_gen1.csv"); - public static final String BIOENERGY_1GEN_FUTURE_DEMAND_FILE = getProperty("BIOENERGY_1GEN_FUTURE_DEMAND_FILE", DATA_DIR + File.separator + BIOENERGY_1GEN_FUTURE_DEMAND_FILENAME); - public static final String TRADE_BARRIERS_FILENAME = getProperty("TRADE_BARRIERS_FILENAME", "tradeBarriers.csv"); - public static final String TRADE_BARRIERS_FILE = getProperty("TRADE_BARRIERS_FILE", DATA_DIR + File.separator + TRADE_BARRIERS_FILENAME); - public static final String TRADE_DISTORTIONS_FILE = DATA_DIR + File.separator + "tradeDistortions.csv"; - public static final String STOCKS_FILE = DATA_DIR + File.separator + "global_stocks.csv"; - public static final String COUNTRY_GROUPING_FILE = DATA_DIR + File.separator + "country_groups.csv"; - public static final String OTHER_WATER_USES_FILE = DATA_DIR + File.separator + "other_water_uses.csv"; - public static final String BASE_DEMAND_FRACT_FILE = DATA_DIR + File.separator + "base_demand_fracts.csv"; - public static final String SHOCKS_PARAMETER_FILE = OUTPUT_DIR + File.separator+ "shocks.csv"; - public static final String SUBSIDY_RATE_FILENAME = getProperty("SUBSIDY_RATE_FILENAME", "subsidyrates.csv"); - public static final String SUBSIDY_RATE_FILE = getProperty("SUBSIDY_RATE_FILE", DATA_DIR + File.separator + SUBSIDY_RATE_FILENAME); - public static final String ANIMAL_RATES_FILE = DATA_DIR + File.separator + "animal_numbers.csv";; - public static final String INITIAL_CONSUMER_PRICE_FILE = DATA_DIR + File.separator + "consumerprices.csv";; - public static final String GDP_FRACTIONS_FILE = DATA_DIR + File.separator + "agriculturalGdpFraction.csv"; - - // yield data - public static final String YIELD_DIR_BASE = getProperty("YIELD_DIR_BASE"); - public static final String YIELD_DIR_TOP = getProperty("YIELD_DIR_TOP"); - public static final String YIELD_DIR = getProperty("YIELD_DIR", YIELD_DIR_BASE + File.separator + YIELD_DIR_TOP); - public static final int LPJG_MONITOR_TIMEOUT_SEC = getIntProperty("LPJG_MONITOR_TIMEOUT", 60*60*2); - public static final String ANPP_FILENAME = getProperty("ANPP_FILENAME", "anpp.out"); - public static final String YIELD_FILENAME = getProperty("YIELD_FILENAME", "yield.out"); - public static final boolean PASTURE_FERT_RESPONSE_FROM_LPJ = getBooleanProperty("PASTURE_FERT_RESPONSE_FROM_LPJ", false);; - - public static final double CALIB_FACTOR_CEREAL_C3 = getDoubleProperty("CALIB_FACTOR_CEREAL_C3", 1.046); - public static final double CALIB_FACTOR_CEREAL_C4 = getDoubleProperty("CALIB_FACTOR_CEREAL_C4", 0.654); - public static final double CALIB_FACTOR_MISCANTHUS = getDoubleProperty("CALIB_FACTOR_MISCANTHUS", 2.148); - public static final double CALIB_FACTOR_RICE = getDoubleProperty("CALIB_FACTOR_RICE", 0.972); - public static final double CALIB_FACTOR_OILCROPS = getDoubleProperty("CALIB_FACTOR_OILCROPS", 0.578); - public static final double CALIB_FACTOR_PULSES = getDoubleProperty("CALIB_FACTOR_PULSES", 0.686); - public static final double CALIB_FACTOR_STARCHY_ROOTS = getDoubleProperty("CALIB_FACTOR_STARCHY_ROOTS",4.560); - public static final double CALIB_FACTOR_FRUITVEG = getDoubleProperty("CALIB_FACTOR_FRUITVEG",3.526); - public static final double CALIB_FACTOR_SUGAR = getDoubleProperty("CALIB_FACTOR_SUGAR", 11.909); - - // These are production prices in PLUM style feed equivalent terms - public static final double INITIAL_PRICE_SHIFT = getDoubleProperty("INITIAL_PRICE_SHIFT", 1.0); - public static final double INITAL_PRICE_WHEAT = getDoubleProperty("INITAL_PRICE_WHEAT", 0.157 * ModelConfig.INITIAL_PRICE_SHIFT); - public static final double INITAL_PRICE_MAIZE = getDoubleProperty("INITAL_PRICE_MAIZE", 0.152 * ModelConfig.INITIAL_PRICE_SHIFT); - public static final double INITAL_PRICE_RICE = getDoubleProperty("INITAL_PRICE_RICE", 0.182 * ModelConfig.INITIAL_PRICE_SHIFT); - public static final double INITAL_PRICE_OILCROPS = getDoubleProperty("INITAL_PRICE_OILCROPS", (0.820 * .4 + 0.314 * .6) * 0.3 * ModelConfig.INITIAL_PRICE_SHIFT); - public static final double INITAL_PRICE_PULSES = getDoubleProperty("INITAL_PRICE_PULSES", 0.2 * ModelConfig.INITIAL_PRICE_SHIFT); - public static final double INITAL_PRICE_STARCHYROOTS = getDoubleProperty("INITAL_PRICE_STARCHYROOTS", 0.1 * ModelConfig.INITIAL_PRICE_SHIFT); - 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.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 - public static final double INITAL_DEMAND_PRICE_CEREALS = getDoubleProperty("INITAL_DEMAND_PRICE_CEREALS", 120.2365); - public static final double INITAL_DEMAND_PRICE_OILCROPS_PULSES = getDoubleProperty("INITAL_DEMAND_PRICE_OILCROPS_PULSES", 147.4032); - public static final double INITAL_DEMAND_PRICE_STARCHYROOTS = getDoubleProperty("INITAL_DEMAND_PRICE_STARCHYROOTS", 543.5512); - public static final double INITAL_DEMAND_PRICE_MONOGASTRICS = getDoubleProperty("INITAL_DEMAND_PRICE_MONOGASTRICS", 1243.899); - public static final double INITAL_DEMAND_PRICE_RUMINANTS = getDoubleProperty("INITAL_DEMAND_PRICE_RUMINANTS", 1043.901); - public static final double INITAL_DEMAND_PRICE_FRUITVEG = getDoubleProperty("INITAL_DEMAND_PRICE_FRUITVEG", 3381.178); - public static final double INITAL_DEMAND_PRICE_SUGAR = getDoubleProperty("INITAL_DEMAND_PRICE_SUGAR", 168.9247); - - // Spatial (gridded) data - public static final double CELL_SIZE_X = getDoubleProperty("CELL_SIZE_X", 0.5); - public static final double CELL_SIZE_Y = getDoubleProperty("CELL_SIZE_Y", CELL_SIZE_X); - public static final String SPATIAL_DIR_NAME = getProperty("SPATIAL_DIR_NAME", "halfdeg"); - public static final String SPATIAL_DATA_DIR = getProperty("SPATIAL_DATA_DIR", DATA_DIR + File.separator + SPATIAL_DIR_NAME); - public static final String INITAL_LAND_COVER_FILENAME = getProperty("INITAL_LAND_COVER_FILENAME", "hurtt_2010.txt"); - public static final String INITAL_LAND_COVER_FILE = SPATIAL_DATA_DIR + File.separator + INITAL_LAND_COVER_FILENAME; - public static final String COUNTRY_BOUNDARY_FILE = SPATIAL_DATA_DIR + File.separator + "country_boundaries.asc"; - public static final String IRRIGATION_COST_FILE = SPATIAL_DATA_DIR + File.separator + "irrigation_cost.asc"; - public static final String IRRIGATION_CONSTRAINT_FILE = SPATIAL_DATA_DIR + File.separator + "blue_water_available_pseudoCRU_rcp8p5_2004_2013_grid_allhdyro_mm.txt"; - public static final String FPU_BOUNDARIES_FILE = SPATIAL_DATA_DIR + File.separator + "FPU.asc"; - public static final String FPU_GROUPING_FILE = SPATIAL_DATA_DIR + File.separator + "fpuGrouping.txt"; - public static final String IRRIG_MAX_WATER_FILENAME = getProperty("IRRIG_MAX_WATER_FILENAME", "gsirrigation.out"); - public static final String IRRIG_RUNOFF_FILE = getProperty("IRRIG_RUNOFF_FILE", "tot_runoff.out"); - public static final String PROTECTED_AREAS_FILE = getProperty("PROTECTED_AREAS_FILE",SPATIAL_DATA_DIR + File.separator + "protectedAreas2019.asc"); - public static final String HALF_EARTH_FILE = getProperty("HALF_EARTH_FILE",SPATIAL_DATA_DIR + File.separator + "global_biodiversity_priorities50perc.asc"); - public static final String HIGH_SLOPE_AREAS_FILE = SPATIAL_DATA_DIR + File.separator + "maxcropfrac2.txt"; - public static final String YIELDSHOCK_MAP_DIR = SPATIAL_DATA_DIR + File.separator + "yieldshockmaps"; - public static final String YIELDSHOCKS_PARAMETER_FILE = getProperty("YIELDSHOCKS_PARAMETER_FILE", OUTPUT_DIR + File.separator+ "yieldshocks.csv"); - public static final String PRICESHOCKS_PARAMETER_FILE = getProperty("PRICESHOCKS_PARAMETER_FILE", OUTPUT_DIR + File.separator+ "priceshocks.csv"); - public static final String EXPORT_RESTRICTIONS_FILE = getProperty("EXPORT_RESTRICTIONS_FILE", OUTPUT_DIR + File.separator+ "exportrestictions.csv");; - - // Output - public static final String LAND_COVER_OUTPUT_FILE = OUTPUT_DIR + File.separator + "lc.txt"; - public static final String PRICES_OUTPUT_FILE = OUTPUT_DIR + File.separator + "prices.txt"; - public static final String DEMAND_OUTPUT_FILE = OUTPUT_DIR + File.separator + "demand.txt"; - public static final String DOMESTIC_OUTPUT_FILE = OUTPUT_DIR + File.separator + "domestic.txt"; - public static final String COUNTRY_DEMAND_FILE = OUTPUT_DIR + File.separator + "countryDemand.txt"; - public static final String DEMAND_OPTIMISATION_OUTPUT_FILE = OUTPUT_DIR + File.separator + "countryDemandOpt.txt"; - public static final String FOOD_BALANCE_SHEET_FILE = OUTPUT_DIR + File.separator + "fbs.txt"; - public static final String ANIMAL_NUMBERS_OUTPUT_FILE = OUTPUT_DIR + File.separator + "animals.txt";; - - public static final boolean OUTPUT_FOR_LPJG = getBooleanProperty("OUTPUT_FOR_LPJG", true); - public static final boolean INTERPOLATE_OUTPUT_YEARS = getBooleanProperty("INTERPOLATE_OUTPUT_YEARS", true); - - // Calibration related stuff - public static final boolean IS_CALIBRATION_RUN = getBooleanProperty("IS_CALIBRATION_RUN", false); - public static final String CALIB_DIR = IS_CALIBRATION_RUN ? OUTPUT_DIR : getProperty("CALIB_DIR", OUTPUT_DIR); - public static final int END_FIRST_STAGE_CALIBRATION = getIntProperty("END_FIRST_STAGE_CALIBRATION", 10); - public static final String SERIALIZED_LAND_USE_FILENAME = "landUseRaster.ser"; - public static final String SERIALIZED_CROP_USAGE_FILENAME = "countryCropUsages.ser"; - public static final String SERIALIZED_INTERNATIONAL_MARKET_FILENAME = "internationalMarket.ser"; - public static final String SERIALIZED_LAND_USE_FILE = CALIB_DIR + File.separator + SERIALIZED_LAND_USE_FILENAME; - public static final String SERIALIZED_CROP_USAGE_FILE = CALIB_DIR + File.separator + SERIALIZED_CROP_USAGE_FILENAME; - public static final String SERIALIZED_INTERNATIONAL_MARKET_FILE = CALIB_DIR + File.separator + SERIALIZED_INTERNATIONAL_MARKET_FILENAME; - public static final String SERIALIZED_DEMAND_MANAGER_FILENAME = "demandManager.ser"; - public static final String SERIALIZED_DEMAND_MANAGER_FILE = CALIB_DIR + File.separator + SERIALIZED_DEMAND_MANAGER_FILENAME; - public static final String CHECKPOINT_LAND_USE_FILE = getProperty("CHECKPOINT_LAND_USE_FILE", OUTPUT_DIR + File.separator + SERIALIZED_LAND_USE_FILENAME); - public static final String CHECKPOINT_DEMAND_MANAGER_FILE = getProperty("CHECKPOINT_DEMAND_MANAGER_FILE", OUTPUT_DIR + File.separator + SERIALIZED_DEMAND_MANAGER_FILENAME); - public static final String CHECKPOINT_CROP_USAGE_FILE = getProperty("CHECKPOINT_CROP_USAGE_FILE", OUTPUT_DIR + File.separator + SERIALIZED_CROP_USAGE_FILENAME); - public static final String CHECKPOINT_INTERNATIONAL_MARKET_FILE = getProperty("CHECKPOINT_INTERNATIONAL_MARKET_FILE", OUTPUT_DIR + File.separator + SERIALIZED_INTERNATIONAL_MARKET_FILENAME); - - 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); - public static final String CLUSTERED_YIELD_FILE = getProperty("CLUSTERED_YIELD_FILE", CALIB_DIR + File.separator + "cluster.asc"); - public static final boolean GENERATE_NEW_YIELD_CLUSTERS = getBooleanProperty("GENERATE_NEW_YIELD_CLUSTERS", IS_CALIBRATION_RUN); - - // Temporal configuration - public static final int START_TIMESTEP = getIntProperty("START_TIMESTEP", 0); - public static final int END_TIMESTEP = getIntProperty("END_TIMESTEP", 90); - public static final int TIMESTEP_SIZE = getIntProperty("TIMESTEP_SIZE", 1); - public static final int BASE_YEAR = getIntProperty("BASE_YEAR", 2010); - - // Import export limits - public static final double ANNUAL_MAX_IMPORT_CHANGE = getDoubleProperty("ANNUAL_MAX_IMPORT_CHANGE", 0.05); - public static final double MAX_IMPORT_CHANGE = getDoubleProperty("MAX_IMPORT_CHANGE", ANNUAL_MAX_IMPORT_CHANGE*TIMESTEP_SIZE); - - // Fertiliser application rates in kg/ha - public static final double MIN_FERT_AMOUNT = getDoubleProperty("MIN_FERT_AMOUNT", 0.0); - public static final double MID_FERT_AMOUNT = getDoubleProperty("MID_FERT_AMOUNT", 200.0); - public static final double MAX_FERT_AMOUNT = getDoubleProperty("MAX_FERT_AMOUNT", 1000.0); - public static final int FERT_AMOUNT_PADDING = getIntProperty("FERT_AMOUNT_PADDING", 4);; - - // SSP shift parameters - public static final double SSP_POPULATION_FACTOR = getDoubleProperty("SSP_POPULATION_FACTOR", 1.0); - public static final double SSP_GDP_PC_FACTOR = getDoubleProperty("SSP_GDP_PC_FACTOR", 1.0); - - // Other model parameters - public static final boolean CHANGE_DEMAND_YEAR = IS_CALIBRATION_RUN ? false : getBooleanProperty("CHANGE_DEMAND_YEAR", true); - public static final double DIETARY_CLOSURE = getDoubleProperty("DIETARY_CLOSURE", 0.25); // Amount diet converges in DIETARY_CLOSURE_GDP_CHANGE rate of GDP shift - public static final double DIETARY_CLOSURE_GDP_CHANGE = getDoubleProperty("DIETARY_CLOSURE_GDP_CHANGE", 2.0); // 2 is double of GDP - public static final double DIETARY_CLOSURE_PARAM = getDoubleProperty("DIETARY_CLOSURE_PARAM", Math.log((1-DIETARY_CLOSURE))/DIETARY_CLOSURE_GDP_CHANGE); // Zero is no dietary closure, number specifies closure rate for changes in GDP per capita, e.g. Math.log(0.5)/2 - public static final String SSP_SCENARIO = getProperty("SSP_SCENARIO", "SSP1_v9_130325"); - public static final ModelFitType DEMAND_ANIMAL_PROD_FIT = ModelFitType.findByName(getProperty("DEMAND_ANIMAL_PROD_FIT", "loglinear")); - public static final ModelFitType DEMAND_NON_ANIMAL_PROD_FIT = ModelFitType.findByName(getProperty("DEMAND_NON_ANIMAL_PROD_FIT", "loglinear")); - public static final boolean LIMIT_DEMAND_FRACTION = getBooleanProperty("LIMIT_DEMAND_FRACTION", true); - public static final boolean DEMAND_FRACT_BY_COST = getBooleanProperty("DEMAND_FRACT_BY_COST", false);; - public static final double MAX_INCOME_PROPORTION_FOOD_SPEND = getDoubleProperty("MAX_INCOME_PROPORTION_FOOD_SPEND", 0.7); - - public static final double PASTURE_HARVEST_FRACTION = getDoubleProperty("PASTURE_HARVEST_FRACTION", 0.5); - public static final double MEAT_EFFICIENCY = getDoubleProperty("MEAT_EFFICIENCY", 1.0); // 'meat' is includes feed conversion ratio already, this is tech. change or similar - public static final double IRRIGIATION_EFFICIENCY = getDoubleProperty("IRRIGIATION_EFFICIENCY", 0.5); - public static final int ELLIOTT_BASEYEAR = 2010; - public static final double ENVIRONMENTAL_WATER_CONSTRAINT = getDoubleProperty("ENVIRONMENTAL_WATER_CONSTRAINT", 0.5); // change with care, as due to normalisation it might not have the impact you first imagine - public static final double OTHER_WATER_USE_FACTOR = getDoubleProperty("OTHER_WATER_USE_FACTOR", 1.0); - public static final boolean USE_BLUE_WATER_FILE_IRRIG_CONSTRAINT = getBooleanProperty("USE_BLUE_WATER_FILE_IRRIG_CONSTRAINT", false);; - - public static final double LAND_CHANGE_COST = getDoubleProperty("LAND_CHANGE_COST", 0.2); - public static final double CROP_TO_PASTURE_COST_FACTOR = getDoubleProperty("CROP_TO_PASTURE_COST_FACTOR", 1.0); - public static final double AGRI_LAND_EXPANSION_COST_FACTOR = getDoubleProperty("AGRI_LAND_EXPANSION_COST_FACTOR", 1.0); - - public static final double CROP_INCREASE_COST = getDoubleProperty("CROP_INCREASE_COST", 0.05 * LAND_CHANGE_COST * AGRI_LAND_EXPANSION_COST_FACTOR); - public static final double PASTURE_DECREASE_COST = getDoubleProperty("PASTURE_DECREASE_COST", LAND_CHANGE_COST); - public static final double CROP_DECREASE_COST = getDoubleProperty("CROP_DECREASE_COST", 1.65 * LAND_CHANGE_COST); - public static final double PASTURE_INCREASE_COST = getDoubleProperty("PASTURE_INCREASE_COST", 0.35 * LAND_CHANGE_COST * CROP_TO_PASTURE_COST_FACTOR * AGRI_LAND_EXPANSION_COST_FACTOR); - public static final double AGRI_EXPANSION_COST_BASE = getDoubleProperty("AGRI_EXPANSION_COST_BASE", 0.03 * LAND_CHANGE_COST * AGRI_LAND_EXPANSION_COST_FACTOR); - public static final double AGRI_EXPANSION_COST_BASE_MANAGED_FOREST = getDoubleProperty("AGRI_EXPANSION_COST_BASE_MANAGED_FOREST", 0.5 * LAND_CHANGE_COST * AGRI_LAND_EXPANSION_COST_FACTOR); - - public static final double TECHNOLOGY_CHANGE_ANNUAL_RATE = getDoubleProperty("TECHNOLOGY_CHANGE_ANNUAL_RATE", 0.002); - public static final int TECHNOLOGY_CHANGE_START_STEP = getIntProperty("TECHNOLOGY_CHANGE_START_STEP", 0); - - public static final boolean USE_BIOENERGY_TRAJECTORY = getBooleanProperty("USE_BIOENERGY_TRAJECTORY", true); // false is the old style, i.e. BIOENERGY_CHANGE_ANNUAL_RATE, BIOENERGY_CHANGE_START_YEAR and BIOENERGY_CHANGE_END_YEAR - // original way to specify changes in bioenergy - public static final double BIOENERGY_CHANGE_ANNUAL_RATE = IS_CALIBRATION_RUN ? 0.0 : getDoubleProperty("BIOENERGY_CHANGE_ANNUAL_RATE", 0.10); // 6.2/2.31/20 - public static final int BIOENERGY_CHANGE_START_YEAR = getIntProperty("BIOENERGY_CHANGE_START_YEAR", 2010); - public static final int BIOENERGY_CHANGE_END_YEAR = getIntProperty("BIOENERGY_CHANGE_END_YEAR", 2060); - // newer way - public static final boolean ENABLE_GEN2_BIOENERGY = getBooleanProperty("ENABLE_GEN2_BIOENERGY", true); - public static final String BIOENERGY_DEMAND_SCENARIO = getProperty("BIOENERGY_DEMAND_SCENARIO", "SSP2_RCP45"); - public static final String GEN2_BIOENERGY_MODEL = getProperty("GEN2_BIOENERGY_MODEL", "ENSEMBLE-MEAN"); - public static final double BIOENERGY_DEMAND_SHIFT = IS_CALIBRATION_RUN ? 1.0 : getDoubleProperty("BIOENERGY_DEMAND_SHIFT", 1.0); - // 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_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 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 = IS_CALIBRATION_RUN ? 0 : getIntProperty("DEMAND_RECALC_MAX_ITERATIONS", 1); // 0 is original behaviour - public static final boolean DEMAND_RECALC_ON_NEGATIVE_STOCK = IS_CALIBRATION_RUN ? false : getBooleanProperty("DEMAND_RECALC_ON_NEGATIVE_STOCK", false); - - public static final double POPULATION_AGGREG_LIMIT = getDoubleProperty("POPULATION_AGGREG_LIMIT", 30.0); // in millions, smaller countries are aggregated on a regional basis - public static final boolean PREDEFINED_COUNTRY_GROUPING = getBooleanProperty("PREDEFINED_COUNTRY_GROUPING", true); - - // 1536.7 Mha is all cropland in LUH2, or 1555.6 Mha from FAO. country_data[Country =="World" & Year == 2011, list(arable+ perm_crops)] - // 1377.6 Mha is area of crops in FAO crop production. con_prod_unadj[Country =="World" & Item %in% itemDetails[produced==TRUE]$Item & Year == 2011, sum(prod_area, na.rm=TRUE)] - // 1105.6 Mha is harvested in crops we represent. crop_prod[Country =="World" & Item %in% itemGroupMapping$cropProdItem & Year == 2011, sum(area)] - // extract values by running AltLURead.R and common.R - // So we do not represent crops covering (1341.911-1239.03)/1547.464=6.65% of cropland. Additionally 10.3% of cropland is set aside, fallow or failed crops, - public static final double UNHANDLED_CROP_RATE = getDoubleProperty("UNHANDLED_CROP_RATE", 0.0665); // mostly forage crops - public static final double SETASIDE_RATE = getDoubleProperty("SETASIDE_RATE", 0.103); // includes aside, fallow and failed cropland areas - - public static final double OTHER_INTENSITY_COST = getDoubleProperty("OTHER_INTENSITY_COST", 0.8); - public static final double OTHER_INTENSITY_PARAM = getDoubleProperty("OTHER_INTENSITY_PARAM", 3.22); - - public static final double IRRIG_COST_SCALE_FACTOR = getDoubleProperty("IRRIG_COST_SCALE_FACTOR", 0.0003); - public static final double IRRIG_COST_MULTIPLIER = getDoubleProperty("IRRIG_COST_MULTIPLIER", 1.0); - public static final double FERTILISER_COST_PER_T = getDoubleProperty("FERTILISER_COST_PER_T", 1.4); // $500/t, 18% N/t - public static final double FERTILISER_MAX_COST = FERTILISER_COST_PER_T * MAX_FERT_AMOUNT/1000; - - public static final double DOMESTIC_PRICE_MARKUP = getDoubleProperty("DOMESTIC_PRICE_MARKUP", 1.0); - public static final double TRANSPORT_LOSSES = getDoubleProperty("TRANSPORT_LOSSES", 0.05); // in international trade - public static final double TRANSPORT_COST = getDoubleProperty("TRANSPORT_COST", 0.1); // 10% transport cost - public static final double TRADE_BARRIER_FACTOR_DEFAULT = getDoubleProperty("TRADE_BARRIER_FACTOR_DEFAULT", 0.2); // price factor in international trade, transport cost and real trade barriers - public static final double TRADE_BARRIER_MULTIPLIER = getDoubleProperty("TRADE_BARRIER_MULTIPLIER", 1.0); - public static final boolean ACTIVE_TRADE_BARRIERS = getBooleanProperty("ACTIVE_TRADE_BARRIERS", true); // if set to true read in barrier information from file, otherwise use default as above - public static final double TRADE_BARRIER_ENERGY_CROPS = getDoubleProperty("TRADE_BARRIER_ENERGY_CROPS", 0.01); // price factor in international trade, transport cost and real trade barriers - public static final boolean SHOCKS_POSSIBLE = getBooleanProperty("SHOCKS_POSSIBLE", false); - public static final double YIELD_SHOCK_MAGNIFIER = getDoubleProperty("YIELD_SHOCK_MAGNIFIER", 1.0); - - public static final boolean PROTECTED_AREAS_ENABLED = getBooleanProperty("PROTECTED_AREAS_ENABLED", true); - public static final double MIN_NATURAL_RATE = getDoubleProperty("MIN_NATURAL_RATE", 0.05); - - public static final boolean DEBUG_JUST_DEMAND_OUTPUT = getBooleanProperty("DEBUG_JUST_DEMAND_OUTPUT", false); - public static final boolean DEBUG_LIMIT_COUNTRIES = getBooleanProperty("DEBUG_LIMIT_COUNTRIES", false); - public static final String DEBUG_COUNTRY_NAME = getProperty("DEBUG_COUNTRY_NAME", "United States of America"); - public static final String GAMS_COUNTRY_TO_SAVE = getProperty("GAMS_COUNTRY_TO_SAVE", "China"); - public static final boolean SAVE_GAMS_DEBUG_OUTPUTS = getBooleanProperty("SAVE_GAMS_DEBUG_OUTPUTS", false); - public static final boolean EXCLUDE_COUNTRIES_IN_LIST = getBooleanProperty("EXCLUDE_COUNTRIES_IN_LIST", false); - public static final String EXCLUDED_COUNTRIES_FILE = DATA_DIR + File.separator + "countries_excluded.csv"; - - - public static final double PASTURE_MAX_IRRIGATION_RATE = getDoubleProperty("DEFAULT_MAX_IRRIGATION_RATE", 50.0); // shouldn't need this but some areas crops don't have a value, but was causing them to be selected - public static final int LPJG_TIMESTEP_SIZE = getIntProperty("LPJG_TIMESTEP_SIZE", 5); - public static final int LPJ_YEAR_OFFSET = getIntProperty("LPJ_YEAR_OFFSET", 0);; - - public static final int NUM_YIELD_CLUSTERS = getIntProperty("NUM_YIELD_CLUSTERS", 8000); - public static final long RANDOM_SEED = getIntProperty("RANDOM_SEED", 1974329); // any number will do - - public static final String CHECKPOINT_YEARS = getProperty("CHECKPOINT_YEARS", null); // 2020,2050 - - // Protected areas forcing parameters - public static final boolean FORCE_PROTECTED_AREAS = IS_CALIBRATION_RUN ? false : getBooleanProperty("FORCE_PROTECTED_AREAS", false); - public static final int FORCE_PROTECTED_AREAS_START_YEAR = getIntProperty("FORCE_PROTECTED_AREAS_START_YEAR", 2020); - public static final int FORCE_PROTECTED_AREAS_END_YEAR = getIntProperty("FORCE_PROTECTED_AREAS_END_YEAR", 2040); - public static final double CONSTANT_PROTECTED_AREA_RATE = getDoubleProperty("CONSTANT_PROTECTED_AREA_RATE", Double.NaN); - public static final boolean HALFEARTH = getBooleanProperty("HALFEARTH", false); - - // CRAFTY - public static final boolean USE_CRAFTY_COUNTRIES = getBooleanProperty("USE_CRAFTY_COUNTRIES", false); - public static final String CRAFTY_COUNTRIES_FILE= getProperty("CRAFTY_COUNTRIES_FILE", DATA_DIR + File.separator + "craftyCountries.csv"); - public static final String CRAFTY_PRODUCTION_DIR = getProperty("CRAFTY_PRODUCTION_DIR", OUTPUT_DIR + File.separator + "crafty"); - - public static final boolean EXTRAPOLATE_YIELD_FERT_RESPONSE = getBooleanProperty("EXTRAPOLATE_YIELD_FERT_RESPONSE", false); - - public static final boolean ADJUST_DIET_PREFS = getBooleanProperty("ADJUST_DIET_PREFS", false); - public static final int DIET_CHANGE_START_YEAR = getIntProperty("DIET_CHANGE_START_YEAR", 2020); - public static final int DIET_CHANGE_END_YEAR = getIntProperty("DIET_CHANGE_END_YEAR", 2040); - public static final String TARGET_DIET_FILE = getProperty("TARGET_DIET_FILE", DATA_DIR + File.separator + "TargetDiet.txt"); - public static final boolean APPLY_EXPORT_TAXES = getBooleanProperty("APPLY_EXPORT_TAXES", false); - public static final double EXPORT_TAX_RATE = getDoubleProperty("EXPORT_TAX_RATE", 1.0); - public static final double EXPORT_TAX_THRESHOLD = getDoubleProperty("EXPORT_TAX_THRESHOLD", 0.1); - public static final int RESET_STOCK_YEAR = IS_CALIBRATION_RUN ? 0 : getIntProperty("RESET_STOCK_YEAR", 2010); - public static final String MIN_MAX_TRADE_FILE = getProperty("MIN_MAX_TRADE_FILE", OUTPUT_DIR + File.separator + "minMaxNetImport.csv"); - - public static final boolean APPLY_TARGET_STOCK_RATE = getBooleanProperty("APPLY_TARGET_STOCK_RATE", false); - public static final double TARGET_STOCK_RATE = getDoubleProperty("TARGET_STOCK_RATE", 0.3); - public static final double TARGET_STOCK_RATE_LAMBA = getDoubleProperty("TARGET_STOCK_RATE_LAMBA", 0.1); -} +package ac.ed.lurg; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Properties; + +import ac.ed.lurg.shock.parameterShocksReader; +import ac.ed.lurg.types.ModelFitType; +import ac.ed.lurg.types.PriceType; +import ac.ed.lurg.utils.LogWriter; + +public class ModelConfig { + + private Properties configFile; + private static ModelConfig modelConfig; + public static final String CONFIG_FILE = System.getProperty("CONFIG_FILE"); + + private static parameterShocksReader shocksReader; + + private ModelConfig() { + configFile = new Properties(); + try { + System.out.println("Config. file is " + CONFIG_FILE); + if (CONFIG_FILE != null) + configFile.load(new FileInputStream(CONFIG_FILE)); + } + catch (IOException e) { + System.err.println("Problems reading config file"); + System.err.println(e.getMessage()); + } + } + + public static String getSetupDetails() { + String buildVerion = System.getProperty("BUILDVER"); + StringBuffer sb = new StringBuffer("Build version: " + buildVerion + "\n"); + + Properties props = getModelConfig().configFile; + Enumeration<?> em = props.keys(); + while(em.hasMoreElements()) { + String str = (String) em.nextElement(); + sb.append(str + ": " + props.get(str) + "\n"); + } + + return sb.toString(); + } + + private static ModelConfig getModelConfig() { + if (modelConfig == null) + modelConfig = new ModelConfig(); + + return modelConfig; + } + + private static String getProperty(String prop) { + return getModelConfig().getProp(prop); + } + private static String getProperty(String prop, String defaultString) { + String propValue = getProperty(prop); + return propValue == null ? defaultString : propValue; + } + private String getProp(String prop) { + return configFile.getProperty(prop); + } + + private static Integer getIntProperty(String prop, Integer defaultInt) { + Integer propValue = getModelConfig().getIntProp(prop); + return propValue == null ? defaultInt : propValue; + } + private Integer getIntProp(String prop) { + String v = configFile.getProperty(prop); + return v==null ? null : Integer.valueOf(v); + } + + @SuppressWarnings("unused") + private static Long getLongProperty(String prop, Long defaultLong) { + Long propValue = getModelConfig().getLongProp(prop); + return propValue == null ? defaultLong : propValue; + } + private Long getLongProp(String prop) { + String v = configFile.getProperty(prop); + return v==null ? null : Long.valueOf(v); + } + + private static Double getDoubleProperty(String prop, Double defaultDouble) { + Double propValue = getModelConfig().getDoubleProp(prop); + return propValue == null ? defaultDouble : propValue; + } + private Double getDoubleProp(String prop) { + String v = configFile.getProperty(prop); + return v==null ? null : Double.valueOf(v); + } + + private static Boolean getBooleanProperty(String prop, Boolean defaultBoolean) { + return getModelConfig().getBooleanProp(prop, defaultBoolean); + } + private boolean getBooleanProp(String prop, Boolean defaultBoolean) { + String v = configFile.getProperty(prop); + return v==null ? defaultBoolean : Boolean.valueOf(v); + } + + public static double updateParameterForShocks(int year, String parameter) { + + Double value = null; + try { + value = getModelConfig().getClass().getField(parameter).getDouble(parameter); + + if(SHOCKS_POSSIBLE) { + + if (shocksReader == null) { + shocksReader = new parameterShocksReader(","); + shocksReader.read(SHOCKS_PARAMETER_FILE); + } + Double updatedValue = shocksReader.queryForParameter(year, parameter); + + if(updatedValue !=null) + value = updatedValue; + } + + } + catch (IllegalAccessException | NoSuchFieldException e) { + LogWriter.printlnError("cannot find parameter in model config to shock: " + parameter); + LogWriter.print(e); + } + return value; + } + + public static final boolean SUPPRESS_STD_OUTPUT = getBooleanProperty("SUPPRESS_STD_OUTPUT", Boolean.FALSE); + + // Directory information + public static final String BASE_DIR = getProperty("BASE_DIR"); // this must to be set in config file + public static final String OUTPUT_DIR = getProperty("OUTPUT_DIR", "."); + public static final String TEMP_DIR = getProperty("TEMP_DIR", OUTPUT_DIR + File.separator + "GamsTmp"); + public static final String DATA_DIR = getProperty("DATA_DIR", BASE_DIR + File.separator + "data"); + public static final String GAMS_DIR = getProperty("GAMS_DIR", BASE_DIR + File.separator + "GAMS"); + public static final boolean CLEANUP_GAMS_DIR = getBooleanProperty("CLEANUP_GAMS_DIR", false); + + public static final boolean ORIG_LEAST_COST_MIN = getBooleanProperty("ORIG_LEAST_COST_MIN", true); + public static final String GAMS_MODEL_NAME = getProperty("GAMS_MODEL_NAME", ORIG_LEAST_COST_MIN==true ? "IntExtOpt.gms" : "LUOpt.gms"); + public static final String GAMS_MODEL = getProperty("GAMS_MODEL", GAMS_DIR + File.separator + GAMS_MODEL_NAME); + public static final String DEMAND_GAMS_MODEL = getProperty("DEMAND_GAMS_MODEL", GAMS_DIR + File.separator + "elasticDemand.gms"); + public static final String DEMAND_PARAM_FILE = getProperty("DEMAND_PARAM_FILE", DATA_DIR + File.separator + "DemandParamConv.gdx"); + + // Country (non-gridded) data + public static final boolean DEMAND_FROM_FILE = getBooleanProperty("DEMAND_FROM_FILE", false); // used in hindcasting + public static final boolean PRICE_ELASTIC_DEMAND = getBooleanProperty("PRICE_ELASTIC_DEMAND", true); + public static final boolean DONT_REBASE_DEMAND = getBooleanProperty("DONT_REBASE_DEMAND", false);; + public static final String DEMAND_CURVES_FILE = getProperty("DEMAND_CURVES_FILE", DATA_DIR + File.separator + "com_curves.csv"); // either DEMAND_CURVES_FILE or DEMAND_CONSUMPTION_FILE is used, but not both + public static final String DEMAND_CONSUMPTION_FILE = getProperty("DEMAND_CONSUMPTION_FILE", DATA_DIR + File.separator + "hist_comsump.csv"); + public static final PriceType PRICE_CALCULATION = PriceType.findByName(getProperty("PRICE_CALCULATION", "weightedImportsExports")); + public static final String SSP_FILENAME = getProperty("SSP_FILENAME", "ssp.csv"); + public static final String SSP_FILE = getProperty("SSP_FILE", DATA_DIR + File.separator + SSP_FILENAME); + public static final String BASELINE_CONSUMP_FILE = DATA_DIR + File.separator + "base_consump.csv"; + public static final String CALORIE_PER_T_FILE = DATA_DIR + File.separator + "calories_per_t.csv"; + public static final String COUNTRY_CODES_FILE = DATA_DIR + File.separator + "country_codes4.csv"; + public static final String COUNTRY_DATA_FILE = DATA_DIR + File.separator + "country_data.csv"; + public static final String NET_IMPORTS_FILE = DATA_DIR + File.separator + "net_imports.csv"; + public static final String BIOENERGY_1GEN_BASE_DEMAND_FILE = DATA_DIR + File.separator + "bio_demand.csv"; + public static final String BIOENERGY_2GEN_DEMAND_FILENAME = getProperty("BIOENERGY_2GEN_DEMAND_FILENAME", "bioenergy_gen2_iiasa.csv"); + public static final String BIOENERGY_2GEN_DEMAND_FILE = getProperty("BIOENERGY_2GEN_DEMAND_FILE", DATA_DIR + File.separator + BIOENERGY_2GEN_DEMAND_FILENAME); + public static final String BIOENERGY_1GEN_FUTURE_DEMAND_FILENAME = getProperty("BIOENERGY_1GEN_FUTURE_DEMAND_FILENAME", "bioenergy_gen1.csv"); + public static final String BIOENERGY_1GEN_FUTURE_DEMAND_FILE = getProperty("BIOENERGY_1GEN_FUTURE_DEMAND_FILE", DATA_DIR + File.separator + BIOENERGY_1GEN_FUTURE_DEMAND_FILENAME); + public static final String TRADE_BARRIERS_FILENAME = getProperty("TRADE_BARRIERS_FILENAME", "tradeBarriers.csv"); + public static final String TRADE_BARRIERS_FILE = getProperty("TRADE_BARRIERS_FILE", DATA_DIR + File.separator + TRADE_BARRIERS_FILENAME); + public static final String TRADE_DISTORTIONS_FILE = DATA_DIR + File.separator + "tradeDistortions.csv"; + public static final String STOCKS_FILE = DATA_DIR + File.separator + "global_stocks.csv"; + public static final String COUNTRY_GROUPING_FILE = DATA_DIR + File.separator + "country_groups.csv"; + public static final String OTHER_WATER_USES_FILE = DATA_DIR + File.separator + "other_water_uses.csv"; + public static final String BASE_DEMAND_FRACT_FILE = DATA_DIR + File.separator + "base_demand_fracts.csv"; + public static final String SHOCKS_PARAMETER_FILE = OUTPUT_DIR + File.separator+ "shocks.csv"; + public static final String SUBSIDY_RATE_FILENAME = getProperty("SUBSIDY_RATE_FILENAME", "subsidyrates.csv"); + public static final String SUBSIDY_RATE_FILE = getProperty("SUBSIDY_RATE_FILE", DATA_DIR + File.separator + SUBSIDY_RATE_FILENAME); + public static final String ANIMAL_RATES_FILE = DATA_DIR + File.separator + "animal_numbers.csv";; + public static final String INITIAL_CONSUMER_PRICE_FILE = DATA_DIR + File.separator + "consumerprices.csv";; + public static final String GDP_FRACTIONS_FILE = DATA_DIR + File.separator + "agriculturalGdpFraction.csv"; + + // yield data + public static final String YIELD_DIR_BASE = getProperty("YIELD_DIR_BASE"); + public static final String YIELD_DIR_TOP = getProperty("YIELD_DIR_TOP"); + public static final String YIELD_DIR = getProperty("YIELD_DIR", YIELD_DIR_BASE + File.separator + YIELD_DIR_TOP); + public static final int LPJG_MONITOR_TIMEOUT_SEC = getIntProperty("LPJG_MONITOR_TIMEOUT", 60*60*2); + public static final String ANPP_FILENAME = getProperty("ANPP_FILENAME", "anpp.out"); + public static final String YIELD_FILENAME = getProperty("YIELD_FILENAME", "yield.out"); + public static final boolean PASTURE_FERT_RESPONSE_FROM_LPJ = getBooleanProperty("PASTURE_FERT_RESPONSE_FROM_LPJ", false);; + + public static final double CALIB_FACTOR_CEREAL_C3 = getDoubleProperty("CALIB_FACTOR_CEREAL_C3", 1.046); + public static final double CALIB_FACTOR_CEREAL_C4 = getDoubleProperty("CALIB_FACTOR_CEREAL_C4", 0.654); + public static final double CALIB_FACTOR_MISCANTHUS = getDoubleProperty("CALIB_FACTOR_MISCANTHUS", 2.148); + public static final double CALIB_FACTOR_RICE = getDoubleProperty("CALIB_FACTOR_RICE", 0.972); + public static final double CALIB_FACTOR_OILCROPS = getDoubleProperty("CALIB_FACTOR_OILCROPS", 0.578); + public static final double CALIB_FACTOR_PULSES = getDoubleProperty("CALIB_FACTOR_PULSES", 0.686); + public static final double CALIB_FACTOR_STARCHY_ROOTS = getDoubleProperty("CALIB_FACTOR_STARCHY_ROOTS",4.560); + public static final double CALIB_FACTOR_FRUITVEG = getDoubleProperty("CALIB_FACTOR_FRUITVEG",3.526); + public static final double CALIB_FACTOR_SUGAR = getDoubleProperty("CALIB_FACTOR_SUGAR", 11.909); + + // These are production prices in PLUM style feed equivalent terms + public static final double INITIAL_PRICE_SHIFT = getDoubleProperty("INITIAL_PRICE_SHIFT", 1.0); + public static final double INITAL_PRICE_WHEAT = getDoubleProperty("INITAL_PRICE_WHEAT", 0.157 * ModelConfig.INITIAL_PRICE_SHIFT); + public static final double INITAL_PRICE_MAIZE = getDoubleProperty("INITAL_PRICE_MAIZE", 0.152 * ModelConfig.INITIAL_PRICE_SHIFT); + public static final double INITAL_PRICE_RICE = getDoubleProperty("INITAL_PRICE_RICE", 0.182 * ModelConfig.INITIAL_PRICE_SHIFT); + public static final double INITAL_PRICE_OILCROPS = getDoubleProperty("INITAL_PRICE_OILCROPS", (0.820 * .4 + 0.314 * .6) * 0.3 * ModelConfig.INITIAL_PRICE_SHIFT); + public static final double INITAL_PRICE_PULSES = getDoubleProperty("INITAL_PRICE_PULSES", 0.2 * ModelConfig.INITIAL_PRICE_SHIFT); + public static final double INITAL_PRICE_STARCHYROOTS = getDoubleProperty("INITAL_PRICE_STARCHYROOTS", 0.1 * ModelConfig.INITIAL_PRICE_SHIFT); + public static final double INITAL_PRICE_MONOGASTRICS = getDoubleProperty("INITAL_PRICE_MONOGASTRICS", 0.3 * ModelConfig.INITIAL_PRICE_SHIFT); // approx. feed equivalent cost + animal production cost - subsidies + public static final double INITAL_PRICE_RUMINANTS = getDoubleProperty("INITAL_PRICE_RUMINANTS", 0.35 * ModelConfig.INITIAL_PRICE_SHIFT); // approx. pasture equivalent cost + animal production cost - subsidies + 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.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 + public static final double INITAL_DEMAND_PRICE_CEREALS = getDoubleProperty("INITAL_DEMAND_PRICE_CEREALS", 120.2365); + public static final double INITAL_DEMAND_PRICE_OILCROPS_PULSES = getDoubleProperty("INITAL_DEMAND_PRICE_OILCROPS_PULSES", 147.4032); + public static final double INITAL_DEMAND_PRICE_STARCHYROOTS = getDoubleProperty("INITAL_DEMAND_PRICE_STARCHYROOTS", 543.5512); + public static final double INITAL_DEMAND_PRICE_MONOGASTRICS = getDoubleProperty("INITAL_DEMAND_PRICE_MONOGASTRICS", 1243.899); + public static final double INITAL_DEMAND_PRICE_RUMINANTS = getDoubleProperty("INITAL_DEMAND_PRICE_RUMINANTS", 1043.901); + public static final double INITAL_DEMAND_PRICE_FRUITVEG = getDoubleProperty("INITAL_DEMAND_PRICE_FRUITVEG", 3381.178); + public static final double INITAL_DEMAND_PRICE_SUGAR = getDoubleProperty("INITAL_DEMAND_PRICE_SUGAR", 168.9247); + + // Spatial (gridded) data + public static final double CELL_SIZE_X = getDoubleProperty("CELL_SIZE_X", 0.5); + public static final double CELL_SIZE_Y = getDoubleProperty("CELL_SIZE_Y", CELL_SIZE_X); + public static final String SPATIAL_DIR_NAME = getProperty("SPATIAL_DIR_NAME", "halfdeg"); + public static final String SPATIAL_DATA_DIR = getProperty("SPATIAL_DATA_DIR", DATA_DIR + File.separator + SPATIAL_DIR_NAME); + public static final String INITAL_LAND_COVER_FILENAME = getProperty("INITAL_LAND_COVER_FILENAME", "hurtt_2010.txt"); + public static final String INITAL_LAND_COVER_FILE = SPATIAL_DATA_DIR + File.separator + INITAL_LAND_COVER_FILENAME; + public static final String COUNTRY_BOUNDARY_FILE = SPATIAL_DATA_DIR + File.separator + "country_boundaries.asc"; + public static final String IRRIGATION_COST_FILE = SPATIAL_DATA_DIR + File.separator + "irrigation_cost.asc"; + public static final String IRRIGATION_CONSTRAINT_FILE = SPATIAL_DATA_DIR + File.separator + "blue_water_available_pseudoCRU_rcp8p5_2004_2013_grid_allhdyro_mm.txt"; + public static final String FPU_BOUNDARIES_FILE = SPATIAL_DATA_DIR + File.separator + "FPU.asc"; + public static final String FPU_GROUPING_FILE = SPATIAL_DATA_DIR + File.separator + "fpuGrouping.txt"; + public static final String IRRIG_MAX_WATER_FILENAME = getProperty("IRRIG_MAX_WATER_FILENAME", "gsirrigation.out"); + public static final String IRRIG_RUNOFF_FILE = getProperty("IRRIG_RUNOFF_FILE", "tot_runoff.out"); + public static final String PROTECTED_AREAS_FILE = getProperty("PROTECTED_AREAS_FILE",SPATIAL_DATA_DIR + File.separator + "protectedAreas2019.asc"); + public static final String HALF_EARTH_FILE = getProperty("HALF_EARTH_FILE",SPATIAL_DATA_DIR + File.separator + "global_biodiversity_priorities50perc.asc"); + public static final String HIGH_SLOPE_AREAS_FILE = SPATIAL_DATA_DIR + File.separator + "maxcropfrac2.txt"; + public static final String YIELDSHOCK_MAP_DIR = SPATIAL_DATA_DIR + File.separator + "yieldshockmaps"; + public static final String YIELDSHOCKS_PARAMETER_FILE = getProperty("YIELDSHOCKS_PARAMETER_FILE", OUTPUT_DIR + File.separator+ "yieldshocks.csv"); + public static final String PRICESHOCKS_PARAMETER_FILE = getProperty("PRICESHOCKS_PARAMETER_FILE", OUTPUT_DIR + File.separator+ "priceshocks.csv"); + public static final String EXPORT_RESTRICTIONS_FILE = getProperty("EXPORT_RESTRICTIONS_FILE", OUTPUT_DIR + File.separator+ "exportrestictions.csv");; + + // Output + public static final String LAND_COVER_OUTPUT_FILE = OUTPUT_DIR + File.separator + "lc.txt"; + public static final String PRICES_OUTPUT_FILE = OUTPUT_DIR + File.separator + "prices.txt"; + public static final String DEMAND_OUTPUT_FILE = OUTPUT_DIR + File.separator + "demand.txt"; + public static final String DOMESTIC_OUTPUT_FILE = OUTPUT_DIR + File.separator + "domestic.txt"; + public static final String COUNTRY_DEMAND_FILE = OUTPUT_DIR + File.separator + "countryDemand.txt"; + public static final String DEMAND_OPTIMISATION_OUTPUT_FILE = OUTPUT_DIR + File.separator + "countryDemandOpt.txt"; + public static final String FOOD_BALANCE_SHEET_FILE = OUTPUT_DIR + File.separator + "fbs.txt"; + public static final String ANIMAL_NUMBERS_OUTPUT_FILE = OUTPUT_DIR + File.separator + "animals.txt";; + + public static final boolean OUTPUT_FOR_LPJG = getBooleanProperty("OUTPUT_FOR_LPJG", true); + public static final boolean INTERPOLATE_OUTPUT_YEARS = getBooleanProperty("INTERPOLATE_OUTPUT_YEARS", true); + + // Calibration related stuff + public static final boolean IS_CALIBRATION_RUN = getBooleanProperty("IS_CALIBRATION_RUN", false); + public static final String CALIB_DIR = IS_CALIBRATION_RUN ? OUTPUT_DIR : getProperty("CALIB_DIR", OUTPUT_DIR); + public static final int END_FIRST_STAGE_CALIBRATION = getIntProperty("END_FIRST_STAGE_CALIBRATION", 10); + public static final String SERIALIZED_LAND_USE_FILENAME = "landUseRaster.ser"; + public static final String SERIALIZED_CROP_USAGE_FILENAME = "countryCropUsages.ser"; + public static final String SERIALIZED_INTERNATIONAL_MARKET_FILENAME = "internationalMarket.ser"; + public static final String SERIALIZED_LAND_USE_FILE = CALIB_DIR + File.separator + SERIALIZED_LAND_USE_FILENAME; + public static final String SERIALIZED_CROP_USAGE_FILE = CALIB_DIR + File.separator + SERIALIZED_CROP_USAGE_FILENAME; + public static final String SERIALIZED_INTERNATIONAL_MARKET_FILE = CALIB_DIR + File.separator + SERIALIZED_INTERNATIONAL_MARKET_FILENAME; + public static final String SERIALIZED_DEMAND_MANAGER_FILENAME = "demandManager.ser"; + public static final String SERIALIZED_DEMAND_MANAGER_FILE = CALIB_DIR + File.separator + SERIALIZED_DEMAND_MANAGER_FILENAME; + public static final String CHECKPOINT_LAND_USE_FILE = getProperty("CHECKPOINT_LAND_USE_FILE", OUTPUT_DIR + File.separator + SERIALIZED_LAND_USE_FILENAME); + public static final String CHECKPOINT_DEMAND_MANAGER_FILE = getProperty("CHECKPOINT_DEMAND_MANAGER_FILE", OUTPUT_DIR + File.separator + SERIALIZED_DEMAND_MANAGER_FILENAME); + public static final String CHECKPOINT_CROP_USAGE_FILE = getProperty("CHECKPOINT_CROP_USAGE_FILE", OUTPUT_DIR + File.separator + SERIALIZED_CROP_USAGE_FILENAME); + public static final String CHECKPOINT_INTERNATIONAL_MARKET_FILE = getProperty("CHECKPOINT_INTERNATIONAL_MARKET_FILE", OUTPUT_DIR + File.separator + SERIALIZED_INTERNATIONAL_MARKET_FILENAME); + + 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); + public static final String CLUSTERED_YIELD_FILE = getProperty("CLUSTERED_YIELD_FILE", CALIB_DIR + File.separator + "cluster.asc"); + public static final boolean GENERATE_NEW_YIELD_CLUSTERS = getBooleanProperty("GENERATE_NEW_YIELD_CLUSTERS", IS_CALIBRATION_RUN); + + // Temporal configuration + public static final int START_TIMESTEP = getIntProperty("START_TIMESTEP", 0); + public static final int END_TIMESTEP = getIntProperty("END_TIMESTEP", 90); + public static final int TIMESTEP_SIZE = getIntProperty("TIMESTEP_SIZE", 1); + public static final int BASE_YEAR = getIntProperty("BASE_YEAR", 2010); + + // Import export limits + public static final double ANNUAL_MAX_IMPORT_CHANGE = getDoubleProperty("ANNUAL_MAX_IMPORT_CHANGE", 0.05); + public static final double MAX_IMPORT_CHANGE = getDoubleProperty("MAX_IMPORT_CHANGE", ANNUAL_MAX_IMPORT_CHANGE*TIMESTEP_SIZE); + + // Fertiliser application rates in kg/ha + public static final double MIN_FERT_AMOUNT = getDoubleProperty("MIN_FERT_AMOUNT", 0.0); + public static final double MID_FERT_AMOUNT = getDoubleProperty("MID_FERT_AMOUNT", 200.0); + public static final double MAX_FERT_AMOUNT = getDoubleProperty("MAX_FERT_AMOUNT", 1000.0); + public static final int FERT_AMOUNT_PADDING = getIntProperty("FERT_AMOUNT_PADDING", 4);; + + // SSP shift parameters + public static final double SSP_POPULATION_FACTOR = getDoubleProperty("SSP_POPULATION_FACTOR", 1.0); + public static final double SSP_GDP_PC_FACTOR = getDoubleProperty("SSP_GDP_PC_FACTOR", 1.0); + + // Other model parameters + public static final boolean CHANGE_DEMAND_YEAR = IS_CALIBRATION_RUN ? false : getBooleanProperty("CHANGE_DEMAND_YEAR", true); + public static final double DIETARY_CLOSURE = getDoubleProperty("DIETARY_CLOSURE", 0.25); // Amount diet converges in DIETARY_CLOSURE_GDP_CHANGE rate of GDP shift + public static final double DIETARY_CLOSURE_GDP_CHANGE = getDoubleProperty("DIETARY_CLOSURE_GDP_CHANGE", 2.0); // 2 is double of GDP + public static final double DIETARY_CLOSURE_PARAM = getDoubleProperty("DIETARY_CLOSURE_PARAM", Math.log((1-DIETARY_CLOSURE))/DIETARY_CLOSURE_GDP_CHANGE); // Zero is no dietary closure, number specifies closure rate for changes in GDP per capita, e.g. Math.log(0.5)/2 + public static final String SSP_SCENARIO = getProperty("SSP_SCENARIO", "SSP1_v9_130325"); + public static final ModelFitType DEMAND_ANIMAL_PROD_FIT = ModelFitType.findByName(getProperty("DEMAND_ANIMAL_PROD_FIT", "loglinear")); + public static final ModelFitType DEMAND_NON_ANIMAL_PROD_FIT = ModelFitType.findByName(getProperty("DEMAND_NON_ANIMAL_PROD_FIT", "loglinear")); + public static final boolean LIMIT_DEMAND_FRACTION = getBooleanProperty("LIMIT_DEMAND_FRACTION", true); + public static final boolean DEMAND_FRACT_BY_COST = getBooleanProperty("DEMAND_FRACT_BY_COST", false);; + public static final double MAX_INCOME_PROPORTION_FOOD_SPEND = getDoubleProperty("MAX_INCOME_PROPORTION_FOOD_SPEND", 0.7); + + public static final double PASTURE_HARVEST_FRACTION = getDoubleProperty("PASTURE_HARVEST_FRACTION", 0.5); + public static final double MEAT_EFFICIENCY = getDoubleProperty("MEAT_EFFICIENCY", 1.0); // 'meat' is includes feed conversion ratio already, this is tech. change or similar + public static final double IRRIGIATION_EFFICIENCY = getDoubleProperty("IRRIGIATION_EFFICIENCY", 0.5); + public static final int ELLIOTT_BASEYEAR = 2010; + public static final double ENVIRONMENTAL_WATER_CONSTRAINT = getDoubleProperty("ENVIRONMENTAL_WATER_CONSTRAINT", 0.5); // change with care, as due to normalisation it might not have the impact you first imagine + public static final double OTHER_WATER_USE_FACTOR = getDoubleProperty("OTHER_WATER_USE_FACTOR", 1.0); + public static final boolean USE_BLUE_WATER_FILE_IRRIG_CONSTRAINT = getBooleanProperty("USE_BLUE_WATER_FILE_IRRIG_CONSTRAINT", false);; + + public static final double LAND_CHANGE_COST = getDoubleProperty("LAND_CHANGE_COST", 0.2); + public static final double CROP_TO_PASTURE_COST_FACTOR = getDoubleProperty("CROP_TO_PASTURE_COST_FACTOR", 1.0); + public static final double AGRI_LAND_EXPANSION_COST_FACTOR = getDoubleProperty("AGRI_LAND_EXPANSION_COST_FACTOR", 1.0); + + public static final double CROP_INCREASE_COST = getDoubleProperty("CROP_INCREASE_COST", 0.05 * LAND_CHANGE_COST * AGRI_LAND_EXPANSION_COST_FACTOR); + public static final double PASTURE_DECREASE_COST = getDoubleProperty("PASTURE_DECREASE_COST", LAND_CHANGE_COST); + public static final double CROP_DECREASE_COST = getDoubleProperty("CROP_DECREASE_COST", 1.65 * LAND_CHANGE_COST); + public static final double PASTURE_INCREASE_COST = getDoubleProperty("PASTURE_INCREASE_COST", 0.35 * LAND_CHANGE_COST * CROP_TO_PASTURE_COST_FACTOR * AGRI_LAND_EXPANSION_COST_FACTOR); + public static final double AGRI_EXPANSION_COST_BASE = getDoubleProperty("AGRI_EXPANSION_COST_BASE", 0.03 * LAND_CHANGE_COST * AGRI_LAND_EXPANSION_COST_FACTOR); + public static final double AGRI_EXPANSION_COST_BASE_MANAGED_FOREST = getDoubleProperty("AGRI_EXPANSION_COST_BASE_MANAGED_FOREST", 0.5 * LAND_CHANGE_COST * AGRI_LAND_EXPANSION_COST_FACTOR); + + public static final double TECHNOLOGY_CHANGE_ANNUAL_RATE = getDoubleProperty("TECHNOLOGY_CHANGE_ANNUAL_RATE", 0.002); + public static final int TECHNOLOGY_CHANGE_START_STEP = getIntProperty("TECHNOLOGY_CHANGE_START_STEP", 0); + + public static final boolean USE_BIOENERGY_TRAJECTORY = getBooleanProperty("USE_BIOENERGY_TRAJECTORY", true); // false is the old style, i.e. BIOENERGY_CHANGE_ANNUAL_RATE, BIOENERGY_CHANGE_START_YEAR and BIOENERGY_CHANGE_END_YEAR + // original way to specify changes in bioenergy + public static final double BIOENERGY_CHANGE_ANNUAL_RATE = IS_CALIBRATION_RUN ? 0.0 : getDoubleProperty("BIOENERGY_CHANGE_ANNUAL_RATE", 0.10); // 6.2/2.31/20 + public static final int BIOENERGY_CHANGE_START_YEAR = getIntProperty("BIOENERGY_CHANGE_START_YEAR", 2010); + public static final int BIOENERGY_CHANGE_END_YEAR = getIntProperty("BIOENERGY_CHANGE_END_YEAR", 2060); + // newer way + public static final boolean ENABLE_GEN2_BIOENERGY = getBooleanProperty("ENABLE_GEN2_BIOENERGY", true); + public static final String BIOENERGY_DEMAND_SCENARIO = getProperty("BIOENERGY_DEMAND_SCENARIO", "SSP2_RCP45"); + public static final String GEN2_BIOENERGY_MODEL = getProperty("GEN2_BIOENERGY_MODEL", "ENSEMBLE-MEAN"); + public static final double BIOENERGY_DEMAND_SHIFT = IS_CALIBRATION_RUN ? 1.0 : getDoubleProperty("BIOENERGY_DEMAND_SHIFT", 1.0); + // 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_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 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 = IS_CALIBRATION_RUN ? 0 : getIntProperty("DEMAND_RECALC_MAX_ITERATIONS", 1); // 0 is original behaviour + public static final boolean DEMAND_RECALC_ON_NEGATIVE_STOCK = IS_CALIBRATION_RUN ? false : getBooleanProperty("DEMAND_RECALC_ON_NEGATIVE_STOCK", false); + + public static final double POPULATION_AGGREG_LIMIT = getDoubleProperty("POPULATION_AGGREG_LIMIT", 30.0); // in millions, smaller countries are aggregated on a regional basis + public static final boolean PREDEFINED_COUNTRY_GROUPING = getBooleanProperty("PREDEFINED_COUNTRY_GROUPING", true); + + // 1536.7 Mha is all cropland in LUH2, or 1555.6 Mha from FAO. country_data[Country =="World" & Year == 2011, list(arable+ perm_crops)] + // 1377.6 Mha is area of crops in FAO crop production. con_prod_unadj[Country =="World" & Item %in% itemDetails[produced==TRUE]$Item & Year == 2011, sum(prod_area, na.rm=TRUE)] + // 1105.6 Mha is harvested in crops we represent. crop_prod[Country =="World" & Item %in% itemGroupMapping$cropProdItem & Year == 2011, sum(area)] + // extract values by running AltLURead.R and common.R + // So we do not represent crops covering (1341.911-1239.03)/1547.464=6.65% of cropland. Additionally 10.3% of cropland is set aside, fallow or failed crops, + public static final double UNHANDLED_CROP_RATE = getDoubleProperty("UNHANDLED_CROP_RATE", 0.0665); // mostly forage crops + public static final double SETASIDE_RATE = getDoubleProperty("SETASIDE_RATE", 0.103); // includes aside, fallow and failed cropland areas + + public static final double OTHER_INTENSITY_COST = getDoubleProperty("OTHER_INTENSITY_COST", 0.8); + public static final double OTHER_INTENSITY_PARAM = getDoubleProperty("OTHER_INTENSITY_PARAM", 3.22); + + public static final double IRRIG_COST_SCALE_FACTOR = getDoubleProperty("IRRIG_COST_SCALE_FACTOR", 0.0003); + public static final double IRRIG_COST_MULTIPLIER = getDoubleProperty("IRRIG_COST_MULTIPLIER", 1.0); + public static final double FERTILISER_COST_PER_T = getDoubleProperty("FERTILISER_COST_PER_T", 1.4); // $500/t, 18% N/t + public static final double FERTILISER_MAX_COST = FERTILISER_COST_PER_T * MAX_FERT_AMOUNT/1000; + + public static final double DOMESTIC_PRICE_MARKUP = getDoubleProperty("DOMESTIC_PRICE_MARKUP", 1.0); + public static final double TRANSPORT_LOSSES = getDoubleProperty("TRANSPORT_LOSSES", 0.05); // in international trade + public static final double TRANSPORT_COST = getDoubleProperty("TRANSPORT_COST", 0.1); // 10% transport cost + public static final double TRADE_BARRIER_FACTOR_DEFAULT = getDoubleProperty("TRADE_BARRIER_FACTOR_DEFAULT", 0.2); // price factor in international trade, transport cost and real trade barriers + public static final double TRADE_BARRIER_MULTIPLIER = getDoubleProperty("TRADE_BARRIER_MULTIPLIER", 1.0); + public static final boolean ACTIVE_TRADE_BARRIERS = getBooleanProperty("ACTIVE_TRADE_BARRIERS", true); // if set to true read in barrier information from file, otherwise use default as above + public static final double TRADE_BARRIER_ENERGY_CROPS = getDoubleProperty("TRADE_BARRIER_ENERGY_CROPS", 0.01); // price factor in international trade, transport cost and real trade barriers + public static final boolean SHOCKS_POSSIBLE = getBooleanProperty("SHOCKS_POSSIBLE", false); + public static final double YIELD_SHOCK_MAGNIFIER = getDoubleProperty("YIELD_SHOCK_MAGNIFIER", 1.0); + + public static final boolean PROTECTED_AREAS_ENABLED = getBooleanProperty("PROTECTED_AREAS_ENABLED", true); + public static final double MIN_NATURAL_RATE = getDoubleProperty("MIN_NATURAL_RATE", 0.05); + + public static final boolean DEBUG_JUST_DEMAND_OUTPUT = getBooleanProperty("DEBUG_JUST_DEMAND_OUTPUT", false); + public static final boolean DEBUG_LIMIT_COUNTRIES = getBooleanProperty("DEBUG_LIMIT_COUNTRIES", false); + public static final String DEBUG_COUNTRY_NAME = getProperty("DEBUG_COUNTRY_NAME", "United States of America"); + public static final String GAMS_COUNTRY_TO_SAVE = getProperty("GAMS_COUNTRY_TO_SAVE", "China"); + public static final boolean SAVE_GAMS_DEBUG_OUTPUTS = getBooleanProperty("SAVE_GAMS_DEBUG_OUTPUTS", false); + public static final boolean EXCLUDE_COUNTRIES_IN_LIST = getBooleanProperty("EXCLUDE_COUNTRIES_IN_LIST", false); + public static final String EXCLUDED_COUNTRIES_FILE = DATA_DIR + File.separator + "countries_excluded.csv"; + + + public static final double PASTURE_MAX_IRRIGATION_RATE = getDoubleProperty("DEFAULT_MAX_IRRIGATION_RATE", 50.0); // shouldn't need this but some areas crops don't have a value, but was causing them to be selected + public static final int LPJG_TIMESTEP_SIZE = getIntProperty("LPJG_TIMESTEP_SIZE", 5); + public static final int LPJ_YEAR_OFFSET = getIntProperty("LPJ_YEAR_OFFSET", 0);; + + public static final int NUM_YIELD_CLUSTERS = getIntProperty("NUM_YIELD_CLUSTERS", 8000); + public static final long RANDOM_SEED = getIntProperty("RANDOM_SEED", 1974329); // any number will do + + public static final String CHECKPOINT_YEARS = getProperty("CHECKPOINT_YEARS", null); // 2020,2050 + + // Protected areas forcing parameters + public static final boolean FORCE_PROTECTED_AREAS = IS_CALIBRATION_RUN ? false : getBooleanProperty("FORCE_PROTECTED_AREAS", false); + public static final int FORCE_PROTECTED_AREAS_START_YEAR = getIntProperty("FORCE_PROTECTED_AREAS_START_YEAR", 2020); + public static final int FORCE_PROTECTED_AREAS_END_YEAR = getIntProperty("FORCE_PROTECTED_AREAS_END_YEAR", 2040); + public static final double CONSTANT_PROTECTED_AREA_RATE = getDoubleProperty("CONSTANT_PROTECTED_AREA_RATE", Double.NaN); + public static final boolean HALFEARTH = getBooleanProperty("HALFEARTH", false); + + // CRAFTY + public static final boolean USE_CRAFTY_COUNTRIES = getBooleanProperty("USE_CRAFTY_COUNTRIES", false); + public static final String CRAFTY_COUNTRIES_FILE= getProperty("CRAFTY_COUNTRIES_FILE", DATA_DIR + File.separator + "craftyCountries.csv"); + public static final String CRAFTY_PRODUCTION_DIR = getProperty("CRAFTY_PRODUCTION_DIR", OUTPUT_DIR + File.separator + "crafty"); + + public static final boolean EXTRAPOLATE_YIELD_FERT_RESPONSE = getBooleanProperty("EXTRAPOLATE_YIELD_FERT_RESPONSE", false); + + public static final boolean ADJUST_DIET_PREFS = getBooleanProperty("ADJUST_DIET_PREFS", false); + public static final int DIET_CHANGE_START_YEAR = getIntProperty("DIET_CHANGE_START_YEAR", 2020); + public static final int DIET_CHANGE_END_YEAR = getIntProperty("DIET_CHANGE_END_YEAR", 2040); + public static final String TARGET_DIET_FILE = getProperty("TARGET_DIET_FILE", DATA_DIR + File.separator + "TargetDiet.txt"); + public static final boolean APPLY_EXPORT_TAXES = getBooleanProperty("APPLY_EXPORT_TAXES", false); + public static final double EXPORT_TAX_RATE = getDoubleProperty("EXPORT_TAX_RATE", 1.0); + public static final double EXPORT_TAX_THRESHOLD = getDoubleProperty("EXPORT_TAX_THRESHOLD", 0.1); + public static final int RESET_STOCK_YEAR = IS_CALIBRATION_RUN ? 0 : getIntProperty("RESET_STOCK_YEAR", 2010); + public static final String MIN_MAX_TRADE_FILE = getProperty("MIN_MAX_TRADE_FILE", OUTPUT_DIR + File.separator + "minMaxNetImport.csv"); + + public static final boolean APPLY_TARGET_STOCK_RATE = getBooleanProperty("APPLY_TARGET_STOCK_RATE", false); + public static final double TARGET_STOCK_RATE = getDoubleProperty("TARGET_STOCK_RATE", 0.3); + public static final double TARGET_STOCK_RATE_LAMBA = getDoubleProperty("TARGET_STOCK_RATE_LAMBA", 0.1); +} diff --git a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java index 960f67ae..a72ac56a 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java @@ -1,490 +1,486 @@ -package ac.ed.lurg.country.gams; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Vector; - -import com.gams.api.GAMSDatabase; -import com.gams.api.GAMSException; -import com.gams.api.GAMSGlobals; -import com.gams.api.GAMSGlobals.ModelStat; -import com.gams.api.GAMSJob; -import com.gams.api.GAMSOptions; -import com.gams.api.GAMSParameter; -import com.gams.api.GAMSParameterRecord; -import com.gams.api.GAMSSet; -import com.gams.api.GAMSVariable; -import com.gams.api.GAMSVariableRecord; -import com.gams.api.GAMSWorkspace; -import com.gams.api.GAMSWorkspaceInfo; - -import ac.ed.lurg.ModelConfig; -import ac.ed.lurg.country.CountryPrice; -import ac.ed.lurg.country.TradeConstraint; -import ac.ed.lurg.landuse.CropUsageData; -import ac.ed.lurg.landuse.Intensity; -import ac.ed.lurg.landuse.IrrigationItem; -import ac.ed.lurg.landuse.LandUseItem; -import ac.ed.lurg.types.CommodityType; -import ac.ed.lurg.types.CropType; -import ac.ed.lurg.types.LandCoverType; -import ac.ed.lurg.types.YieldType; -import ac.ed.lurg.utils.LazyHashMap; -import ac.ed.lurg.utils.LogWriter; -import ac.ed.lurg.yield.YieldResponsesItem; - -public class GamsLocationOptimiser { - - private static final boolean DEBUG = true; - - private GamsLocationInput inputData; - - public GamsLocationOptimiser(GamsLocationInput inputData) { - this.inputData = inputData; - } - - public GamsLocationOutput run() { - - File workingDirectory = new File(ModelConfig.TEMP_DIR); - workingDirectory.mkdir(); - - GAMSWorkspaceInfo wsInfo = new GAMSWorkspaceInfo(); - wsInfo.setWorkingDirectory(workingDirectory.getAbsolutePath()); - // wsInfo.setDebugLevel(DebugLevel.VERBOSE); - - GAMSWorkspace ws = new GAMSWorkspace(wsInfo); - GAMSDatabase inDB = ws.addDatabase(); - - setupInDB(inDB); - - GAMSJob gamsJob = ws.addJobFromFile(ModelConfig.GAMS_MODEL); - GAMSOptions opt = ws.addOptions(); - - opt.setAllModelTypes("conopt"); - - opt.defines("gdxincname", inDB.getName()); - - long startTime = System.currentTimeMillis(); - gamsJob.run(opt, inDB); - - if (ModelConfig.CLEANUP_GAMS_DIR) - cleanup(ws.workingDirectory()); - - LogWriter.println("Took " + (System.currentTimeMillis() - startTime) + " ms to run"); - - return handleResults(gamsJob.OutDB()); - } - - private void setupInDB(GAMSDatabase inDB) { - //if (DEBUG) LogWriter.println("\nLocation set"); - GAMSSet locationSet = inDB.addSet("location", 1); - for (Integer locId : inputData.getPreviousLandUse().keySet()) { - //if (DEBUG) LogWriter.println(" " + locId); - locationSet.addRecord(locId.toString()); - } - - if (DEBUG) LogWriter.println("\nPrevious crop and land areas"); - GAMSParameter prevCropP = inDB.addParameter("previousArea", 2); - GAMSParameter prevFertIP = inDB.addParameter("previousFertIntensity", 2); - GAMSParameter prevIrrigIP = inDB.addParameter("previousIrrigIntensity", 2); - GAMSParameter prevOtherIP = inDB.addParameter("previousOtherIntensity", 2); - - GAMSParameter previousRuminantFeedP = inDB.addParameter("previousRuminantFeed", 1); - GAMSParameter previousMonogastricFeedP = inDB.addParameter("previousMonogastricFeed", 1); - GAMSParameter previousImportAmountP = inDB.addParameter("previousImportAmount", 1); - GAMSParameter previousExportAmountP = inDB.addParameter("previousExportAmount", 1); - - GAMSParameter landP = inDB.addParameter("suitableLandArea", 1); - GAMSParameter agriExpansionCostP = inDB.addParameter("agriExpansionCost", 1); - GAMSParameter seedAndWasteRateP = inDB.addParameter("seedAndWasteRate", 1); - - double totalAgriLand = 0; - double totalSuitable = 0; - - for (Map.Entry<Integer, ? extends LandUseItem> entry : inputData.getPreviousLandUse().entrySet()) { - Integer locationId = entry.getKey(); - String locString = Integer.toString(locationId); - LandUseItem landUseItem = entry.getValue(); - - double suitableLand = landUseItem.getSuitableArea(); - totalSuitable += suitableLand; - if (DEBUG) LogWriter.println(String.format(" %d %15s,\t %.3f", locationId, "suitableLand", suitableLand)); - setGamsParamValueTruncate(landP.addRecord(locString), suitableLand, 3); - - double agriExpansionCost = ModelConfig.AGRI_EXPANSION_COST_BASE + landUseItem.getForestManagedFraction() * ModelConfig.AGRI_EXPANSION_COST_BASE_MANAGED_FOREST; - if (DEBUG) LogWriter.println(String.format(" %d %15s,\t %.3f", locationId, "agriExpansionCost", agriExpansionCost)); - setGamsParamValue(agriExpansionCostP.addRecord(Integer.toString(locationId)), agriExpansionCost, 3); - - - for (CropType cropType : CropType.getNonMeatTypes()) { - Vector<String> v = new Vector<String>(); - v.add(cropType.getGamsName()); - v.add(locString); - - double area; - if (CropType.PASTURE == cropType) - area = landUseItem.getLandCoverArea(LandCoverType.PASTURE); - else - area = landUseItem.getCropArea(cropType); - - double prevFertI, prevIrrigI, prevOtherI; - Intensity intensity = landUseItem.getIntensity(cropType); - - if (intensity==null) { // could be first time through or this crop not previously grown in this location, so give it some default values - prevFertI = CropType.PASTURE.equals(cropType) ? 0.0 : 0.5; - prevIrrigI = CropType.PASTURE.equals(cropType) ? 0.0 : 0.5; - prevOtherI = CropType.PASTURE.equals(cropType) ? 0.1 : 0.5; - } - else { - prevOtherI = intensity.getOtherIntensity(); - if (prevOtherI == 0 & !CropType.PASTURE.equals(cropType)) { // this is needed or optimizer gets a bit confused if some areas are kept as cropland but are not productive, due to zero other intensity (i.e. set aside) - prevFertI = 0.5; - prevIrrigI = 0.5; - } - else { - prevFertI = intensity.getFertiliserIntensity(); - prevIrrigI = intensity.getIrrigationIntensity(); - } - } - - if (DEBUG) LogWriter.println(String.format(" %d %15s,\t %.2f,\t %.3f,\t %.3f,\t %.3f", locationId, cropType.getGamsName(), area, prevFertI, prevIrrigI, prevOtherI)); - - setGamsParamValue(prevCropP.addRecord(v), area, 3); - setGamsParamValue(prevFertIP.addRecord(v), prevFertI, 4); - setGamsParamValue(prevIrrigIP.addRecord(v), prevIrrigI, 4); - setGamsParamValue(prevOtherIP.addRecord(v), prevOtherI, 4); - - totalAgriLand += area; - - } - } - if (DEBUG) LogWriter.println(String.format(" Total agricultural %.1f,\t suitable %.1f", totalAgriLand, totalSuitable)); - - if (DEBUG) LogWriter.println("\nIrrigation data (cost, constraint)"); - GAMSParameter irrigCostP = inDB.addParameter("irrigCost", 1); - GAMSParameter irrigConstraintP = inDB.addParameter("irrigConstraint", 1); - Map<Integer, ? extends IrrigationItem> irrigationData = inputData.getIrrigationCosts(); - - double irrigCostMultiplier = ModelConfig.updateParameterForShocks(inputData.getTimestep().getYear(),"IRRIG_COST_MULTIPLIER"); - - for (Entry<Integer, ? extends IrrigationItem> entry : irrigationData.entrySet()) { - Integer locationId = entry.getKey(); - IrrigationItem irrigCostItem = entry.getValue(); - double irrigCost = irrigCostItem.getIrrigCost()*irrigCostMultiplier; - double irrigConstraint = irrigCostItem.getIrrigConstraint(); - if (DEBUG) LogWriter.println(String.format(" %d \t %.5f,\t %.1f", locationId, irrigCost, irrigConstraint)); - setGamsParamValue(irrigCostP.addRecord(Integer.toString(locationId)), irrigCost, 5); - setGamsParamValue(irrigConstraintP.addRecord(Integer.toString(locationId)), irrigConstraint, 3); - } - - if (DEBUG) LogWriter.println("\nDemand: " + inputData.getCountryInput().getCountry() + " " + inputData.getTimestep().getYear()); - GamsCountryInput countryInput = inputData.getCountryInput(); - GAMSParameter demandP = inDB.addParameter("demand", 1); - addCommodityMapParm(demandP, countryInput.getProjectedDemand(), -1); - setGamsParamValue(demandP.addRecord(CropType.ENERGY_CROPS.getGamsName()), countryInput.getSecondGenBioenergyDemand(), -1); - - GAMSParameter minCerealFracP = inDB.addParameter("minDemandPerCereal", 1); - GAMSParameter minOilcropsFracP = inDB.addParameter("minDemandPerOilcrop", 1); - if (DEBUG) LogWriter.println("\nMinDemandFractions"); - - for (Entry<CommodityType, Map<CropType, Double>> entry : countryInput.getMinDemandFractions().entrySet()) { - CommodityType comm = entry.getKey(); - for (Map.Entry<CropType, Double> entry2 : entry.getValue().entrySet()) { - CropType crop = entry2.getKey(); - double minCommFract = ModelConfig.LIMIT_DEMAND_FRACTION ? entry2.getValue() : 0.0; - GAMSParameter minCropsFracP = (comm == CommodityType.CEREALS ? minCerealFracP : minOilcropsFracP); - setGamsParamValueTruncate(minCropsFracP.addRecord(crop.getGamsName()), minCommFract, 4); - if (DEBUG) LogWriter.println(String.format(" %15s, %10s, %.4f", comm.getGamsName(), crop.getGamsName(), minCommFract)); - } - } - - if (DEBUG) LogWriter.println("\nYield (fert/irrig) None/None, Max/None, None/Max, Max/Max, Shock,\t [fert p],\t [irrig p],\t {max irrig}"); - GAMSParameter yNoneP = inDB.addParameter("yieldNone", 2); - GAMSParameter y_fert = inDB.addParameter("yieldFertOnly", 2); - GAMSParameter y_irrig = inDB.addParameter("yieldIrrigOnly", 2); - GAMSParameter y_both = inDB.addParameter("yieldBoth", 2); - GAMSParameter y_shock = inDB.addParameter("yieldShock", 2); - GAMSParameter fert_p = inDB.addParameter("fertParam", 2); - GAMSParameter irrig_p = inDB.addParameter("irrigParam", 2); - GAMSParameter irrigMaxP = inDB.addParameter("irrigMaxRate", 2); - - for (Entry<Integer, ? extends YieldResponsesItem> entry : inputData.getYields().entrySet()) { - Integer locationId = entry.getKey(); - String locString = Integer.toString(locationId); - YieldResponsesItem yresp = entry.getValue(); - IrrigationItem irrigationItem = irrigationData.get(locationId); - - for (CropType crop : CropType.getNonMeatTypes()) { - Vector<String> v = new Vector<String>(); - v.add(crop.getGamsName()); - v.add(locString); - - if (crop.equals(CropType.SETASIDE)) { - setGamsParamValue(irrigMaxP.addRecord(v), 1000, 3); // need to set this to any positive value to give an incentive not to irrigate setaside - continue; - } - - double maxIrrig = irrigationItem.getMaxIrrigAmount(crop); - - if (DEBUG) LogWriter.println(String.format("%d %15s,\t %.1f,\t %.1f, \t %.1f,\t %.1f,\t %.2f,\t\t [%.2f],\t [%.2f],\t {%.2f}", - locationId, crop.getGamsName(), - yresp.getExtrapolatedYield(YieldType.NO_FERT_NO_IRRIG, crop), - yresp.getExtrapolatedYield(YieldType.FERT_MAX_NO_IRRIG, crop), - yresp.getExtrapolatedYield(YieldType.NO_FERT_IRRIG_MAX, crop), - yresp.getExtrapolatedYield(YieldType.FERT_MAX_IRRIG_MAX, crop), - yresp.getShockRate(crop), yresp.getFertParam(crop), yresp.getIrrigParam(crop), maxIrrig)); - - setGamsParamValue(yNoneP.addRecord(v), yresp.getExtrapolatedYield(YieldType.NO_FERT_NO_IRRIG, crop), 4); - setGamsParamValue(y_fert.addRecord(v), yresp.getExtrapolatedYield(YieldType.FERT_MAX_NO_IRRIG, crop), 4); - setGamsParamValue(y_irrig.addRecord(v), yresp.getExtrapolatedYield(YieldType.NO_FERT_IRRIG_MAX, crop), 4); - setGamsParamValue(y_both.addRecord(v), yresp.getExtrapolatedYield(YieldType.FERT_MAX_IRRIG_MAX, crop), 4); - setGamsParamValue(y_shock.addRecord(v), yresp.getShockRate(crop), 4); - setGamsParamValue(fert_p.addRecord(v), yresp.getFertParam(crop), 4); - setGamsParamValue(irrig_p.addRecord(v), yresp.getIrrigParam(crop), 4); - setGamsParamValue(irrigMaxP.addRecord(v), maxIrrig, 3); - } - } - - if (DEBUG) LogWriter.println("\nCrop, subsidy rate"); - GAMSParameter subsideRateP = inDB.addParameter("subsidyRate", 1); - for (CropType crop : CropType.getNonMeatTypes()) { - if (crop.equals(CropType.PASTURE)) { // subsidise pasture using value for ruminants - setGamsParamValue(subsideRateP.addRecord(crop.getGamsName()), countryInput.getSubsidyRates().get(CropType.RUMINANTS), 4); - } else { - double subsidyRate = countryInput.getSubsidyRates().get(crop); - if (DEBUG) LogWriter.println(String.format("%15s,\t %.4f", crop.getGamsName(), subsidyRate)); - setGamsParamValue(subsideRateP.addRecord(crop.getGamsName()), subsidyRate, 4); - } - } - - if (DEBUG) LogWriter.println("\nImport-export, min trade/prod, max trade/prod, global import price, global export price, imports, exports, ruminantFeed, monogastricFeed, seedAndWasteRate"); - - GAMSParameter minTradeP = null; - GAMSParameter maxTradeP = null; - minTradeP = inDB.addParameter("minNetImport", 1); - maxTradeP = inDB.addParameter("maxNetImport", 1); - - GAMSParameter importPriceP = inDB.addParameter("importPrices", 1); - GAMSParameter exportPriceP = inDB.addParameter("exportPrices", 1); - - for (CropType crop : CropType.getImportedTypes()) { - - TradeConstraint iec = countryInput.getTradeConstraints().get(crop); - CountryPrice gp = countryInput.getCountryPrices().get(crop); - double minTrade = iec.getMinConstraint(); - double maxTrade = iec.getMaxConstraint(); - double importPrice = gp.getImportPrice(); - double exportPrice = gp.getProducerNetExportPrice(); - - CropUsageData cu = countryInput.getPreviousCropUsageData().get(crop); - double netImports = cu.getNetImportsExpected(); - double imports = netImports>0 ? netImports : 0; - double exports = netImports<0 ? -netImports : 0; - - double ruminantFeed = cu.getRuminantFeed(); - double monogastricFeed = cu.getMonogastricFeed(); - double seedAndWasteRate = crop.getSeedAndWasteRate(); - - if (DEBUG) LogWriter.println(String.format(" %15s, \t %5.1f, \t %5.1f, \t %5.3f, \t %5.3f, \t %5.1f, \t %5.1f, \t %5.1f, \t %5.1f, \t %5.3f", - crop.getGamsName(), minTrade, maxTrade, importPrice, exportPrice, imports, exports, ruminantFeed, monogastricFeed, seedAndWasteRate)); - - setGamsParamValue(minTradeP.addRecord(crop.getGamsName()), minTrade, 3); - setGamsParamValue(maxTradeP.addRecord(crop.getGamsName()), maxTrade, 3); - setGamsParamValue(importPriceP.addRecord(crop.getGamsName()), importPrice, 3); - setGamsParamValue(exportPriceP.addRecord(crop.getGamsName()), exportPrice, 3); - setGamsParamValue(previousImportAmountP.addRecord(crop.getGamsName()), imports, 3); - setGamsParamValue(previousExportAmountP.addRecord(crop.getGamsName()), exports, 3); - setGamsParamValue(previousRuminantFeedP.addRecord(crop.getGamsName()), ruminantFeed, 3); - setGamsParamValue(previousMonogastricFeedP.addRecord(crop.getGamsName()), monogastricFeed, 3); - setGamsParamValue(seedAndWasteRateP.addRecord(crop.getGamsName()), seedAndWasteRate, 3); - } - - //below in case running without shocks to use original values in model config - - double meatEff = ModelConfig.updateParameterForShocks(inputData.getTimestep().getYear(), "MEAT_EFFICIENCY"); - double fertCost = ModelConfig.updateParameterForShocks(inputData.getTimestep().getYear(), "FERTILISER_COST_PER_T"); - double otherIntCost = ModelConfig.updateParameterForShocks(inputData.getTimestep().getYear(), "OTHER_INTENSITY_COST"); - - LogWriter.print("\n"); - addScalar(inDB, "cropIncCost", ModelConfig.CROP_INCREASE_COST, 3); - addScalar(inDB, "cropDecCost", ModelConfig.CROP_DECREASE_COST, 3); - addScalar(inDB, "pastureDecCost", ModelConfig.PASTURE_DECREASE_COST, 3); - addScalar(inDB, "pastureIncCost", ModelConfig.PASTURE_INCREASE_COST, 3); - addScalar(inDB, "meatEfficency", meatEff, 3); - addScalar(inDB, "fertiliserUnitCost", fertCost, 3); - addScalar(inDB, "otherICost",otherIntCost, 3); - addScalar(inDB, "otherIParam", ModelConfig.OTHER_INTENSITY_PARAM, 3); - addScalar(inDB, "unhandledCropRate", ModelConfig.UNHANDLED_CROP_RATE, 3); - addScalar(inDB, "setAsideRate", ModelConfig.SETASIDE_RATE, 5); - addScalar(inDB, "domesticPriceMarkup", ModelConfig.DOMESTIC_PRICE_MARKUP, 3); - } - - private void addScalar(GAMSDatabase gamsDb, String recordName, double val, int places) { - GAMSParameter param = gamsDb.addParameter(recordName, 0); - double dOut = setGamsParamValue(param.addRecord(), val, places); - if (DEBUG) LogWriter.println(recordName + ": " + dOut); - } - - private double setGamsParamValue(GAMSParameterRecord param, double val, int places) { - double dOut = places >= 0 ? Math.round(val * Math.pow(10,places)) / Math.pow(10,places) : val; - param.setValue(dOut); - return dOut; - } - - private double setGamsParamValueTruncate(GAMSParameterRecord param, double val, int places) { - double dOut = ((int)(val * Math.pow(10,places))) / Math.pow(10,places); - param.setValue(dOut); - return dOut; - } - - @SuppressWarnings("serial") - private GamsLocationOutput handleResults(GAMSDatabase outDB) { - int modelStatusInt = (int) outDB.getParameter("ms").findRecord().getValue(); - ModelStat modelStatus = GAMSGlobals.ModelStat.lookup(modelStatusInt); - String contextString = String.format("%s %s: Modelstatus %s, Solvestatus %s", - inputData.getCountryInput().getCountry(), - inputData.getTimestep().getYear(), - modelStatus.toString(), - GAMSGlobals.SolveStat.lookup((int) outDB.getParameter("ss").findRecord().getValue())); - LogWriter.println("\n" + contextString); - - if (modelStatus != ModelStat.OPTIMAL_LOCAL) - LogWriter.printlnError("Critical!!! Land use incorrectly solved. " + contextString); - - GAMSVariable varAreas = outDB.getVariable("area"); - GAMSVariable varFertIntensities = outDB.getVariable("fertI"); - GAMSVariable varIrrigIntensities = outDB.getVariable("irrigI"); - GAMSVariable varOtherIntensities = outDB.getVariable("otherIntensity"); - GAMSVariable varRuminantFeed = outDB.getVariable("ruminantFeed"); - GAMSVariable varMonogastricFeed = outDB.getVariable("monogastricFeed"); - GAMSParameter parmNetImports = outDB.getParameter("netImportAmount"); - GAMSParameter parmNetImportCost = outDB.getParameter("netImportCost"); - GAMSVariable varYields = outDB.getVariable("yield"); - GAMSVariable varUnitEnergies = outDB.getVariable("unitCost"); - GAMSParameter parmProd = outDB.getParameter("totalProd"); - GAMSParameter parmProdCost = outDB.getParameter("totalProdCost"); - GAMSParameter parmCroplandArea = outDB.getParameter("totalCropland"); - GAMSParameter parmTotalArea = outDB.getParameter("totalArea"); - GAMSParameter parmProdShock = outDB.getParameter("productionShock"); - - double totalCropArea = 0; - double totalPastureArea = 0; - double area, fertIntensity, irrigIntensity, otherIntensity = Double.NaN, ruminantFeed, monogastricFeed, netImport, netImportCost, yield, unitCost, prod, prodCost; - - final LazyHashMap<Integer, LandUseItem> landUses = new LazyHashMap<Integer, LandUseItem>() { - protected LandUseItem createValue() { return new LandUseItem(); } - }; - - Map<Integer, ? extends IrrigationItem> allIrrigationRefData = inputData.getIrrigationCosts(); - - Map<CropType, CropUsageData> cropUsageData = new HashMap<CropType, CropUsageData>(); - - for (GAMSVariableRecord rec : varAreas) { - String itemName = rec.getKeys()[0]; - String locationName = rec.getKeys()[1]; - area = rec.getLevel(); - fertIntensity = varFertIntensities.findRecord(itemName, locationName).getLevel(); - irrigIntensity = varIrrigIntensities.findRecord(itemName, locationName).getLevel(); - otherIntensity = varOtherIntensities.findRecord(itemName, locationName).getLevel(); - yield = varYields.findRecord(itemName, locationName).getLevel(); - unitCost = varUnitEnergies.findRecord(itemName, locationName).getLevel(); - - int locId = Integer.parseInt(locationName); - CropType cropType = CropType.getForGamsName(itemName); - - if (!cropUsageData.containsKey(cropType)) { // then we must not have seen this crop type before, so need to do all non location specific stuff - ruminantFeed = varRuminantFeed.findRecord(itemName).getLevel(); - monogastricFeed = varMonogastricFeed.findRecord(itemName).getLevel(); - netImport = cropType.isImportedCrop() ? getParmValue(parmNetImports, itemName) : 0; - netImportCost = cropType.isImportedCrop() ? getParmValue(parmNetImportCost, itemName) : 0; - prod = getParmValue(parmProd, itemName); - prodCost = getParmValue(parmProdCost, itemName); - double totalArea = getParmValue(parmTotalArea, itemName); - double prodShock = getParmValue(parmProdShock, itemName); - - cropUsageData.put(cropType, new CropUsageData(ruminantFeed, monogastricFeed, netImport, netImportCost, prod, prodCost, totalArea, prodShock)); - if (DEBUG) LogWriter.println(String.format("\n%s:\tarea= %.1f,\tmonogastricFeed= %.1f,\truminantFeed= %.1f,\tnetImports= %.3f,\tnetImportCost= %.3f,\tprod= %.3f, \tprodCost= %.3f,\tprodCostRate= %.3f,\tprodShock= %.3f", itemName, totalArea, monogastricFeed, ruminantFeed, netImport, netImportCost, prod, prodCost, prodCost/prod, prodShock)); - - } - - LandUseItem landUseItem = landUses.lazyGet(locId); - - if (area > 0) { - - if (DEBUG) LogWriter.println(String.format("\t location %s, %s:\tarea= %.1f,\tfert= %.3f,\tirrg= %.3f,\tintensity= %.3f", locationName, itemName, area, fertIntensity, irrigIntensity, otherIntensity)); - IrrigationItem irrigRefData = allIrrigationRefData.get(locId); - landUseItem.setIntensity(cropType, new Intensity(fertIntensity, irrigIntensity, otherIntensity, yield, unitCost, irrigRefData.getMaxIrrigAmount(cropType))); - } - - double croplandArea = getParmValue(parmCroplandArea, locationName); - if (cropType.equals(CropType.PASTURE)) { - landUseItem.setLandCoverArea(LandCoverType.PASTURE, area); - totalPastureArea += area; - } - else { - landUseItem.setLandCoverArea(LandCoverType.CROPLAND, croplandArea); // will set this multiple times, once for each arable crop, but doesn't really matter - totalCropArea += area; - } - - landUseItem.setCropFraction(cropType, croplandArea > 0 ? area/croplandArea : 0); - } - - for (CropType meatTypes : CropType.getMeatTypes()) { - netImport = getParmValue(parmNetImports, meatTypes.getGamsName()); - netImportCost= getParmValue(parmNetImportCost, meatTypes.getGamsName()); - prod = getParmValue(parmProd, meatTypes.getGamsName()); - prodCost = getParmValue(parmProdCost, meatTypes.getGamsName()); - - cropUsageData.put(meatTypes, new CropUsageData(0.0, 0.0, netImport, netImportCost, prod, prodCost, Double.NaN, 0)); - if (DEBUG) LogWriter.println(String.format("\n%s:\t\t\t\t\tnetImports= %.3f,\tnetImportCost= %.3f,\tprod= %.3f,\tprodCost= %.3f", meatTypes.getGamsName(), netImport, netImportCost, prod, prodCost)); - } - LogWriter.println(String.format("\n%s %s: Total area= %.1f (crop=%.1f, pasture %.1f)", - inputData.getCountryInput().getCountry(), inputData.getTimestep().getYear(), - totalCropArea+totalPastureArea, totalCropArea, totalPastureArea)); - - GamsLocationOutput results = new GamsLocationOutput(modelStatus, landUses, cropUsageData); - return results; - } - - private double getParmValue(GAMSParameter aParm, String itemName) { - try { - GAMSParameterRecord record = aParm.findRecord(itemName); - double d = record.getValue(); - return d; - } - catch (GAMSException gamsEx) { - //LogWriter.println("GAMSException thrown for " + itemName); - return 0; - } - } - - private void addCommodityMapParm(GAMSParameter parm, Map<CommodityType, Double> itemMap, int places) { - for (Map.Entry<CommodityType, Double> entry : itemMap.entrySet()) { - double d = entry.getValue(); - if (DEBUG) LogWriter.println(String.format(" %15s,\t %.1f", entry.getKey().getGamsName(), d)); - if (!Double.isNaN(d)) - setGamsParamValue(parm.addRecord(entry.getKey().getGamsName()), d, places); - } - } - - - private void cleanup(String directory) { - File directoryToDelete = new File(directory); - String files[] = directoryToDelete.list(); - for (String file : files) { - File fileToDelete = new File(directoryToDelete, file); - try { - fileToDelete.delete(); - } catch(Exception e){ - LogWriter.print(e); - } - } - try { - directoryToDelete.delete(); - } catch(Exception e) { - LogWriter.print(e); - } - } -} +package ac.ed.lurg.country.gams; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Vector; + +import com.gams.api.GAMSDatabase; +import com.gams.api.GAMSException; +import com.gams.api.GAMSGlobals; +import com.gams.api.GAMSGlobals.ModelStat; +import com.gams.api.GAMSJob; +import com.gams.api.GAMSOptions; +import com.gams.api.GAMSParameter; +import com.gams.api.GAMSParameterRecord; +import com.gams.api.GAMSSet; +import com.gams.api.GAMSVariable; +import com.gams.api.GAMSVariableRecord; +import com.gams.api.GAMSWorkspace; +import com.gams.api.GAMSWorkspaceInfo; + +import ac.ed.lurg.ModelConfig; +import ac.ed.lurg.country.CountryPrice; +import ac.ed.lurg.country.TradeConstraint; +import ac.ed.lurg.landuse.CropUsageData; +import ac.ed.lurg.landuse.Intensity; +import ac.ed.lurg.landuse.IrrigationItem; +import ac.ed.lurg.landuse.LandUseItem; +import ac.ed.lurg.types.CommodityType; +import ac.ed.lurg.types.CropType; +import ac.ed.lurg.types.LandCoverType; +import ac.ed.lurg.types.YieldType; +import ac.ed.lurg.utils.LazyHashMap; +import ac.ed.lurg.utils.LogWriter; +import ac.ed.lurg.yield.YieldResponsesItem; + +public class GamsLocationOptimiser { + + private static final boolean DEBUG = true; + + private GamsLocationInput inputData; + + public GamsLocationOptimiser(GamsLocationInput inputData) { + this.inputData = inputData; + } + + public GamsLocationOutput run() { + + File workingDirectory = new File(ModelConfig.TEMP_DIR); + workingDirectory.mkdir(); + + GAMSWorkspaceInfo wsInfo = new GAMSWorkspaceInfo(); + wsInfo.setWorkingDirectory(workingDirectory.getAbsolutePath()); + // wsInfo.setDebugLevel(DebugLevel.VERBOSE); + + GAMSWorkspace ws = new GAMSWorkspace(wsInfo); + GAMSDatabase inDB = ws.addDatabase(); + + setupInDB(inDB); + + GAMSJob gamsJob = ws.addJobFromFile(ModelConfig.GAMS_MODEL); + GAMSOptions opt = ws.addOptions(); + + opt.setAllModelTypes("conopt"); + + opt.defines("gdxincname", inDB.getName()); + + long startTime = System.currentTimeMillis(); + gamsJob.run(opt, inDB); + + if (ModelConfig.CLEANUP_GAMS_DIR) + cleanup(ws.workingDirectory()); + + LogWriter.println("Took " + (System.currentTimeMillis() - startTime) + " ms to run"); + + return handleResults(gamsJob.OutDB()); + } + + private void setupInDB(GAMSDatabase inDB) { + //if (DEBUG) LogWriter.println("\nLocation set"); + GAMSSet locationSet = inDB.addSet("location", 1); + for (Integer locId : inputData.getPreviousLandUse().keySet()) { + //if (DEBUG) LogWriter.println(" " + locId); + locationSet.addRecord(locId.toString()); + } + + if (DEBUG) LogWriter.println("\nPrevious crop and land areas"); + GAMSParameter prevCropP = inDB.addParameter("previousArea", 2); + GAMSParameter prevFertIP = inDB.addParameter("previousFertIntensity", 2); + GAMSParameter prevIrrigIP = inDB.addParameter("previousIrrigIntensity", 2); + GAMSParameter prevOtherIP = inDB.addParameter("previousOtherIntensity", 2); + + GAMSParameter previousRuminantFeedP = inDB.addParameter("previousRuminantFeed", 1); + GAMSParameter previousMonogastricFeedP = inDB.addParameter("previousMonogastricFeed", 1); + GAMSParameter previousImportAmountP = inDB.addParameter("previousImportAmount", 1); + GAMSParameter previousExportAmountP = inDB.addParameter("previousExportAmount", 1); + + GAMSParameter landP = inDB.addParameter("suitableLandArea", 1); + GAMSParameter agriExpansionCostP = inDB.addParameter("agriExpansionCost", 1); + GAMSParameter seedAndWasteRateP = inDB.addParameter("seedAndWasteRate", 1); + + double totalAgriLand = 0; + double totalSuitable = 0; + + for (Map.Entry<Integer, ? extends LandUseItem> entry : inputData.getPreviousLandUse().entrySet()) { + Integer locationId = entry.getKey(); + String locString = Integer.toString(locationId); + LandUseItem landUseItem = entry.getValue(); + + double suitableLand = landUseItem.getSuitableArea(); + totalSuitable += suitableLand; + if (DEBUG) LogWriter.println(String.format(" %d %15s,\t %.3f", locationId, "suitableLand", suitableLand)); + setGamsParamValueTruncate(landP.addRecord(locString), suitableLand, 3); + + double agriExpansionCost = ModelConfig.AGRI_EXPANSION_COST_BASE + landUseItem.getForestManagedFraction() * ModelConfig.AGRI_EXPANSION_COST_BASE_MANAGED_FOREST; + if (DEBUG) LogWriter.println(String.format(" %d %15s,\t %.3f", locationId, "agriExpansionCost", agriExpansionCost)); + setGamsParamValue(agriExpansionCostP.addRecord(Integer.toString(locationId)), agriExpansionCost, 3); + + + for (CropType cropType : CropType.getNonMeatTypes()) { + Vector<String> v = new Vector<String>(); + v.add(cropType.getGamsName()); + v.add(locString); + + double area; + if (CropType.PASTURE == cropType) + area = landUseItem.getLandCoverArea(LandCoverType.PASTURE); + else + area = landUseItem.getCropArea(cropType); + + double prevFertI, prevIrrigI, prevOtherI; + Intensity intensity = landUseItem.getIntensity(cropType); + + if (intensity==null) { // could be first time through or this crop not previously grown in this location, so give it some default values + prevFertI = CropType.PASTURE.equals(cropType) ? 0.0 : 0.5; + prevIrrigI = CropType.PASTURE.equals(cropType) ? 0.0 : 0.5; + prevOtherI = CropType.PASTURE.equals(cropType) ? 0.1 : 0.5; + } + else { + prevOtherI = intensity.getOtherIntensity(); + if (prevOtherI == 0 & !CropType.PASTURE.equals(cropType)) { // this is needed or optimizer gets a bit confused if some areas are kept as cropland but are not productive, due to zero other intensity (i.e. set aside) + prevFertI = 0.5; + prevIrrigI = 0.5; + } + else { + prevFertI = intensity.getFertiliserIntensity(); + prevIrrigI = intensity.getIrrigationIntensity(); + } + } + + if (DEBUG) LogWriter.println(String.format(" %d %15s,\t %.2f,\t %.3f,\t %.3f,\t %.3f", locationId, cropType.getGamsName(), area, prevFertI, prevIrrigI, prevOtherI)); + + setGamsParamValue(prevCropP.addRecord(v), area, 3); + setGamsParamValue(prevFertIP.addRecord(v), prevFertI, 4); + setGamsParamValue(prevIrrigIP.addRecord(v), prevIrrigI, 4); + setGamsParamValue(prevOtherIP.addRecord(v), prevOtherI, 4); + + totalAgriLand += area; + + } + } + if (DEBUG) LogWriter.println(String.format(" Total agricultural %.1f,\t suitable %.1f", totalAgriLand, totalSuitable)); + + if (DEBUG) LogWriter.println("\nIrrigation data (cost, constraint)"); + GAMSParameter irrigCostP = inDB.addParameter("irrigCost", 1); + GAMSParameter irrigConstraintP = inDB.addParameter("irrigConstraint", 1); + Map<Integer, ? extends IrrigationItem> irrigationData = inputData.getIrrigationCosts(); + + double irrigCostMultiplier = ModelConfig.updateParameterForShocks(inputData.getTimestep().getYear(),"IRRIG_COST_MULTIPLIER"); + + for (Entry<Integer, ? extends IrrigationItem> entry : irrigationData.entrySet()) { + Integer locationId = entry.getKey(); + IrrigationItem irrigCostItem = entry.getValue(); + double irrigCost = irrigCostItem.getIrrigCost()*irrigCostMultiplier; + double irrigConstraint = irrigCostItem.getIrrigConstraint(); + if (DEBUG) LogWriter.println(String.format(" %d \t %.5f,\t %.1f", locationId, irrigCost, irrigConstraint)); + setGamsParamValue(irrigCostP.addRecord(Integer.toString(locationId)), irrigCost, 5); + setGamsParamValue(irrigConstraintP.addRecord(Integer.toString(locationId)), irrigConstraint, 3); + } + + if (DEBUG) LogWriter.println("\nDemand: " + inputData.getCountryInput().getCountry() + " " + inputData.getTimestep().getYear()); + GamsCountryInput countryInput = inputData.getCountryInput(); + GAMSParameter demandP = inDB.addParameter("demand", 1); + addCommodityMapParm(demandP, countryInput.getProjectedDemand(), -1); + setGamsParamValue(demandP.addRecord(CropType.ENERGY_CROPS.getGamsName()), countryInput.getSecondGenBioenergyDemand(), -1); + + GAMSParameter minCerealFracP = inDB.addParameter("minDemandPerCereal", 1); + GAMSParameter minOilcropsFracP = inDB.addParameter("minDemandPerOilcrop", 1); + if (DEBUG) LogWriter.println("\nMinDemandFractions"); + + for (Entry<CommodityType, Map<CropType, Double>> entry : countryInput.getMinDemandFractions().entrySet()) { + CommodityType comm = entry.getKey(); + for (Map.Entry<CropType, Double> entry2 : entry.getValue().entrySet()) { + CropType crop = entry2.getKey(); + double minCommFract = ModelConfig.LIMIT_DEMAND_FRACTION ? entry2.getValue() : 0.0; + GAMSParameter minCropsFracP = (comm == CommodityType.CEREALS ? minCerealFracP : minOilcropsFracP); + setGamsParamValueTruncate(minCropsFracP.addRecord(crop.getGamsName()), minCommFract, 4); + if (DEBUG) LogWriter.println(String.format(" %15s, %10s, %.4f", comm.getGamsName(), crop.getGamsName(), minCommFract)); + } + } + + if (DEBUG) LogWriter.println("\nYield (fert/irrig) None/None, Max/None, None/Max, Max/Max, Shock,\t [fert p],\t [irrig p],\t {max irrig}"); + GAMSParameter yNoneP = inDB.addParameter("yieldNone", 2); + GAMSParameter y_fert = inDB.addParameter("yieldFertOnly", 2); + GAMSParameter y_irrig = inDB.addParameter("yieldIrrigOnly", 2); + GAMSParameter y_both = inDB.addParameter("yieldBoth", 2); + GAMSParameter y_shock = inDB.addParameter("yieldShock", 2); + GAMSParameter fert_p = inDB.addParameter("fertParam", 2); + GAMSParameter irrig_p = inDB.addParameter("irrigParam", 2); + GAMSParameter irrigMaxP = inDB.addParameter("irrigMaxRate", 2); + + for (Entry<Integer, ? extends YieldResponsesItem> entry : inputData.getYields().entrySet()) { + Integer locationId = entry.getKey(); + String locString = Integer.toString(locationId); + YieldResponsesItem yresp = entry.getValue(); + IrrigationItem irrigationItem = irrigationData.get(locationId); + + for (CropType crop : CropType.getNonMeatTypes()) { + Vector<String> v = new Vector<String>(); + v.add(crop.getGamsName()); + v.add(locString); + + if (crop.equals(CropType.SETASIDE)) { + setGamsParamValue(irrigMaxP.addRecord(v), 1000, 3); // need to set this to any positive value to give an incentive not to irrigate setaside + continue; + } + + double maxIrrig = irrigationItem.getMaxIrrigAmount(crop); + + if (DEBUG) LogWriter.println(String.format("%d %15s,\t %.1f,\t %.1f, \t %.1f,\t %.1f,\t %.2f,\t\t [%.2f],\t [%.2f],\t {%.2f}", + locationId, crop.getGamsName(), + yresp.getExtrapolatedYield(YieldType.NO_FERT_NO_IRRIG, crop), + yresp.getExtrapolatedYield(YieldType.FERT_MAX_NO_IRRIG, crop), + yresp.getExtrapolatedYield(YieldType.NO_FERT_IRRIG_MAX, crop), + yresp.getExtrapolatedYield(YieldType.FERT_MAX_IRRIG_MAX, crop), + yresp.getShockRate(crop), yresp.getFertParam(crop), yresp.getIrrigParam(crop), maxIrrig)); + + setGamsParamValue(yNoneP.addRecord(v), yresp.getExtrapolatedYield(YieldType.NO_FERT_NO_IRRIG, crop), 4); + setGamsParamValue(y_fert.addRecord(v), yresp.getExtrapolatedYield(YieldType.FERT_MAX_NO_IRRIG, crop), 4); + setGamsParamValue(y_irrig.addRecord(v), yresp.getExtrapolatedYield(YieldType.NO_FERT_IRRIG_MAX, crop), 4); + setGamsParamValue(y_both.addRecord(v), yresp.getExtrapolatedYield(YieldType.FERT_MAX_IRRIG_MAX, crop), 4); + setGamsParamValue(y_shock.addRecord(v), yresp.getShockRate(crop), 4); + setGamsParamValue(fert_p.addRecord(v), yresp.getFertParam(crop), 4); + setGamsParamValue(irrig_p.addRecord(v), yresp.getIrrigParam(crop), 4); + setGamsParamValue(irrigMaxP.addRecord(v), maxIrrig, 3); + } + } + + if (DEBUG) LogWriter.println("\nCrop, subsidy rate"); + GAMSParameter subsideRateP = inDB.addParameter("subsidyRate", 1); + for (CropType crop : CropType.getImportedTypes()) { + double subsidyRate = countryInput.getSubsidyRates().get(crop); + if (DEBUG) LogWriter.println(String.format("%15s,\t %.4f", crop.getGamsName(), subsidyRate)); + setGamsParamValue(subsideRateP.addRecord(crop.getGamsName()), subsidyRate, 4); + } + + if (DEBUG) LogWriter.println("\nImport-export, min trade/prod, max trade/prod, global import price, global export price, imports, exports, ruminantFeed, monogastricFeed, seedAndWasteRate"); + + GAMSParameter minTradeP = null; + GAMSParameter maxTradeP = null; + minTradeP = inDB.addParameter("minNetImport", 1); + maxTradeP = inDB.addParameter("maxNetImport", 1); + + GAMSParameter importPriceP = inDB.addParameter("importPrices", 1); + GAMSParameter exportPriceP = inDB.addParameter("exportPrices", 1); + + for (CropType crop : CropType.getImportedTypes()) { + + TradeConstraint iec = countryInput.getTradeConstraints().get(crop); + CountryPrice gp = countryInput.getCountryPrices().get(crop); + double minTrade = iec.getMinConstraint(); + double maxTrade = iec.getMaxConstraint(); + double importPrice = gp.getImportPrice(); + double exportPrice = gp.getProducerNetExportPrice(); + + CropUsageData cu = countryInput.getPreviousCropUsageData().get(crop); + double netImports = cu.getNetImportsExpected(); + double imports = netImports>0 ? netImports : 0; + double exports = netImports<0 ? -netImports : 0; + + double ruminantFeed = cu.getRuminantFeed(); + double monogastricFeed = cu.getMonogastricFeed(); + double seedAndWasteRate = crop.getSeedAndWasteRate(); + + if (DEBUG) LogWriter.println(String.format(" %15s, \t %5.1f, \t %5.1f, \t %5.3f, \t %5.3f, \t %5.1f, \t %5.1f, \t %5.1f, \t %5.1f, \t %5.3f", + crop.getGamsName(), minTrade, maxTrade, importPrice, exportPrice, imports, exports, ruminantFeed, monogastricFeed, seedAndWasteRate)); + + setGamsParamValue(minTradeP.addRecord(crop.getGamsName()), minTrade, 3); + setGamsParamValue(maxTradeP.addRecord(crop.getGamsName()), maxTrade, 3); + setGamsParamValue(importPriceP.addRecord(crop.getGamsName()), importPrice, 3); + setGamsParamValue(exportPriceP.addRecord(crop.getGamsName()), exportPrice, 3); + setGamsParamValue(previousImportAmountP.addRecord(crop.getGamsName()), imports, 3); + setGamsParamValue(previousExportAmountP.addRecord(crop.getGamsName()), exports, 3); + setGamsParamValue(previousRuminantFeedP.addRecord(crop.getGamsName()), ruminantFeed, 3); + setGamsParamValue(previousMonogastricFeedP.addRecord(crop.getGamsName()), monogastricFeed, 3); + setGamsParamValue(seedAndWasteRateP.addRecord(crop.getGamsName()), seedAndWasteRate, 3); + } + + //below in case running without shocks to use original values in model config + + double meatEff = ModelConfig.updateParameterForShocks(inputData.getTimestep().getYear(), "MEAT_EFFICIENCY"); + double fertCost = ModelConfig.updateParameterForShocks(inputData.getTimestep().getYear(), "FERTILISER_COST_PER_T"); + double otherIntCost = ModelConfig.updateParameterForShocks(inputData.getTimestep().getYear(), "OTHER_INTENSITY_COST"); + + LogWriter.print("\n"); + addScalar(inDB, "cropIncCost", ModelConfig.CROP_INCREASE_COST, 3); + addScalar(inDB, "cropDecCost", ModelConfig.CROP_DECREASE_COST, 3); + addScalar(inDB, "pastureDecCost", ModelConfig.PASTURE_DECREASE_COST, 3); + addScalar(inDB, "pastureIncCost", ModelConfig.PASTURE_INCREASE_COST, 3); + addScalar(inDB, "meatEfficency", meatEff, 3); + addScalar(inDB, "fertiliserUnitCost", fertCost, 3); + addScalar(inDB, "otherICost",otherIntCost, 3); + addScalar(inDB, "otherIParam", ModelConfig.OTHER_INTENSITY_PARAM, 3); + addScalar(inDB, "unhandledCropRate", ModelConfig.UNHANDLED_CROP_RATE, 3); + addScalar(inDB, "setAsideRate", ModelConfig.SETASIDE_RATE, 5); + addScalar(inDB, "domesticPriceMarkup", ModelConfig.DOMESTIC_PRICE_MARKUP, 3); + } + + private void addScalar(GAMSDatabase gamsDb, String recordName, double val, int places) { + GAMSParameter param = gamsDb.addParameter(recordName, 0); + double dOut = setGamsParamValue(param.addRecord(), val, places); + if (DEBUG) LogWriter.println(recordName + ": " + dOut); + } + + private double setGamsParamValue(GAMSParameterRecord param, double val, int places) { + double dOut = places >= 0 ? Math.round(val * Math.pow(10,places)) / Math.pow(10,places) : val; + param.setValue(dOut); + return dOut; + } + + private double setGamsParamValueTruncate(GAMSParameterRecord param, double val, int places) { + double dOut = ((int)(val * Math.pow(10,places))) / Math.pow(10,places); + param.setValue(dOut); + return dOut; + } + + @SuppressWarnings("serial") + private GamsLocationOutput handleResults(GAMSDatabase outDB) { + int modelStatusInt = (int) outDB.getParameter("ms").findRecord().getValue(); + ModelStat modelStatus = GAMSGlobals.ModelStat.lookup(modelStatusInt); + String contextString = String.format("%s %s: Modelstatus %s, Solvestatus %s", + inputData.getCountryInput().getCountry(), + inputData.getTimestep().getYear(), + modelStatus.toString(), + GAMSGlobals.SolveStat.lookup((int) outDB.getParameter("ss").findRecord().getValue())); + LogWriter.println("\n" + contextString); + + if (modelStatus != ModelStat.OPTIMAL_LOCAL) + LogWriter.printlnError("Critical!!! Land use incorrectly solved. " + contextString); + + GAMSVariable varAreas = outDB.getVariable("area"); + GAMSVariable varFertIntensities = outDB.getVariable("fertI"); + GAMSVariable varIrrigIntensities = outDB.getVariable("irrigI"); + GAMSVariable varOtherIntensities = outDB.getVariable("otherIntensity"); + GAMSVariable varRuminantFeed = outDB.getVariable("ruminantFeed"); + GAMSVariable varMonogastricFeed = outDB.getVariable("monogastricFeed"); + GAMSParameter parmNetImports = outDB.getParameter("netImportAmount"); + GAMSParameter parmNetImportCost = outDB.getParameter("netImportCost"); + GAMSVariable varYields = outDB.getVariable("yield"); + GAMSVariable varUnitEnergies = outDB.getVariable("unitCost"); + GAMSParameter parmProd = outDB.getParameter("totalProd"); + GAMSParameter parmProdCost = outDB.getParameter("totalProdCost"); + GAMSParameter parmCroplandArea = outDB.getParameter("totalCropland"); + GAMSParameter parmTotalArea = outDB.getParameter("totalArea"); + GAMSParameter parmProdShock = outDB.getParameter("productionShock"); + + double totalCropArea = 0; + double totalPastureArea = 0; + double area, fertIntensity, irrigIntensity, otherIntensity = Double.NaN, ruminantFeed, monogastricFeed, netImport, netImportCost, yield, unitCost, prod, prodCost; + + final LazyHashMap<Integer, LandUseItem> landUses = new LazyHashMap<Integer, LandUseItem>() { + protected LandUseItem createValue() { return new LandUseItem(); } + }; + + Map<Integer, ? extends IrrigationItem> allIrrigationRefData = inputData.getIrrigationCosts(); + + Map<CropType, CropUsageData> cropUsageData = new HashMap<CropType, CropUsageData>(); + + for (GAMSVariableRecord rec : varAreas) { + String itemName = rec.getKeys()[0]; + String locationName = rec.getKeys()[1]; + area = rec.getLevel(); + fertIntensity = varFertIntensities.findRecord(itemName, locationName).getLevel(); + irrigIntensity = varIrrigIntensities.findRecord(itemName, locationName).getLevel(); + otherIntensity = varOtherIntensities.findRecord(itemName, locationName).getLevel(); + yield = varYields.findRecord(itemName, locationName).getLevel(); + unitCost = varUnitEnergies.findRecord(itemName, locationName).getLevel(); + + int locId = Integer.parseInt(locationName); + CropType cropType = CropType.getForGamsName(itemName); + + if (!cropUsageData.containsKey(cropType)) { // then we must not have seen this crop type before, so need to do all non location specific stuff + ruminantFeed = varRuminantFeed.findRecord(itemName).getLevel(); + monogastricFeed = varMonogastricFeed.findRecord(itemName).getLevel(); + netImport = cropType.isImportedCrop() ? getParmValue(parmNetImports, itemName) : 0; + netImportCost = cropType.isImportedCrop() ? getParmValue(parmNetImportCost, itemName) : 0; + prod = getParmValue(parmProd, itemName); + prodCost = getParmValue(parmProdCost, itemName); + double totalArea = getParmValue(parmTotalArea, itemName); + double prodShock = getParmValue(parmProdShock, itemName); + + cropUsageData.put(cropType, new CropUsageData(ruminantFeed, monogastricFeed, netImport, netImportCost, prod, prodCost, totalArea, prodShock)); + if (DEBUG) LogWriter.println(String.format("\n%s:\tarea= %.1f,\tmonogastricFeed= %.1f,\truminantFeed= %.1f,\tnetImports= %.3f,\tnetImportCost= %.3f,\tprod= %.3f, \tprodCost= %.3f,\tprodCostRate= %.3f,\tprodShock= %.3f", itemName, totalArea, monogastricFeed, ruminantFeed, netImport, netImportCost, prod, prodCost, prodCost/prod, prodShock)); + + } + + LandUseItem landUseItem = landUses.lazyGet(locId); + + if (area > 0) { + + if (DEBUG) LogWriter.println(String.format("\t location %s, %s:\tarea= %.1f,\tfert= %.3f,\tirrg= %.3f,\tintensity= %.3f", locationName, itemName, area, fertIntensity, irrigIntensity, otherIntensity)); + IrrigationItem irrigRefData = allIrrigationRefData.get(locId); + landUseItem.setIntensity(cropType, new Intensity(fertIntensity, irrigIntensity, otherIntensity, yield, unitCost, irrigRefData.getMaxIrrigAmount(cropType))); + } + + double croplandArea = getParmValue(parmCroplandArea, locationName); + if (cropType.equals(CropType.PASTURE)) { + landUseItem.setLandCoverArea(LandCoverType.PASTURE, area); + totalPastureArea += area; + } + else { + landUseItem.setLandCoverArea(LandCoverType.CROPLAND, croplandArea); // will set this multiple times, once for each arable crop, but doesn't really matter + totalCropArea += area; + } + + landUseItem.setCropFraction(cropType, croplandArea > 0 ? area/croplandArea : 0); + } + + for (CropType meatTypes : CropType.getMeatTypes()) { + netImport = getParmValue(parmNetImports, meatTypes.getGamsName()); + netImportCost= getParmValue(parmNetImportCost, meatTypes.getGamsName()); + prod = getParmValue(parmProd, meatTypes.getGamsName()); + prodCost = getParmValue(parmProdCost, meatTypes.getGamsName()); + + cropUsageData.put(meatTypes, new CropUsageData(0.0, 0.0, netImport, netImportCost, prod, prodCost, Double.NaN, 0)); + if (DEBUG) LogWriter.println(String.format("\n%s:\t\t\t\t\tnetImports= %.3f,\tnetImportCost= %.3f,\tprod= %.3f,\tprodCost= %.3f", meatTypes.getGamsName(), netImport, netImportCost, prod, prodCost)); + } + LogWriter.println(String.format("\n%s %s: Total area= %.1f (crop=%.1f, pasture %.1f)", + inputData.getCountryInput().getCountry(), inputData.getTimestep().getYear(), + totalCropArea+totalPastureArea, totalCropArea, totalPastureArea)); + + GamsLocationOutput results = new GamsLocationOutput(modelStatus, landUses, cropUsageData); + return results; + } + + private double getParmValue(GAMSParameter aParm, String itemName) { + try { + GAMSParameterRecord record = aParm.findRecord(itemName); + double d = record.getValue(); + return d; + } + catch (GAMSException gamsEx) { + //LogWriter.println("GAMSException thrown for " + itemName); + return 0; + } + } + + private void addCommodityMapParm(GAMSParameter parm, Map<CommodityType, Double> itemMap, int places) { + for (Map.Entry<CommodityType, Double> entry : itemMap.entrySet()) { + double d = entry.getValue(); + if (DEBUG) LogWriter.println(String.format(" %15s,\t %.1f", entry.getKey().getGamsName(), d)); + if (!Double.isNaN(d)) + setGamsParamValue(parm.addRecord(entry.getKey().getGamsName()), d, places); + } + } + + + private void cleanup(String directory) { + File directoryToDelete = new File(directory); + String files[] = directoryToDelete.list(); + for (String file : files) { + File fileToDelete = new File(directoryToDelete, file); + try { + fileToDelete.delete(); + } catch(Exception e){ + LogWriter.print(e); + } + } + try { + directoryToDelete.delete(); + } catch(Exception e) { + LogWriter.print(e); + } + } +} -- GitLab