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