diff --git a/src/ac/ed/lurg/InternationalMarket.java b/src/ac/ed/lurg/InternationalMarket.java index 86350e1f3732cd35df42a619771cbfeccfb6e1df..606f6b8e2936261c8f60bca0e12ab013c25fece2 100644 --- a/src/ac/ed/lurg/InternationalMarket.java +++ b/src/ac/ed/lurg/InternationalMarket.java @@ -45,8 +45,7 @@ public class InternationalMarket { } carbonPrice = GlobalPrice.createInitial(ModelConfig.INIT_CARBON_PRICE, 0); - woodPrice = GlobalPrice.createInitial(ModelConfig.INIT_WOOD_PRICE, ModelConfig.INIT_WOOD_STOCK); - + woodPrice = GlobalPrice.createInitial(ModelConfig.INIT_WOOD_PRICE, ModelConfig.INIT_WOOD_STOCK); } else { List<Object> deserializedPrices = deserializeGlobalPrice(); @@ -54,8 +53,14 @@ public class InternationalMarket { //carbonPrice = (GlobalPrice) deserializedPrices.get(1); carbonPrice = GlobalPrice.createInitial(ModelConfig.INIT_CARBON_PRICE, 0); woodPrice = (GlobalPrice) deserializedPrices.get(2); - + + if (ModelConfig.RESET_ENERGYCROP_PRICE) { + double previousExportPrice = worldPrices.get(CropType.ENERGY_CROPS).getExportPrice(); + GlobalPrice newPrice = worldPrices.get(CropType.ENERGY_CROPS).createPriceAdjustedByFactor(ModelConfig.INITAL_PRICE_ENERGYCROPS / previousExportPrice); + worldPrices.put(CropType.ENERGY_CROPS, newPrice); + } } + priceShockManager = new PriceShockManager(); } @@ -83,6 +88,17 @@ public class InternationalMarket { Map<CropType, Double> initialStockLevels = new StockReader().read(); return initialStockLevels; } + + void resetStocks() { + Map<CropType, Double> initialStockLevels = getInitialStockLevels(); + for (Entry<CropType, GlobalPrice> entry : worldPrices.entrySet()) { + Double initialStock = initialStockLevels.get(entry.getKey()); + if (initialStock != null) + entry.getValue().resetStock(initialStock); + } + woodPrice.resetStock(ModelConfig.INIT_WOOD_STOCK); + carbonPrice.resetStock(0.0); + } void determineInternationalTrade(Collection<AbstractCountryAgent> countryAgents, double carbonDemand, Timestep timestep) { CropToDoubleMap totalImportCommodities = new CropToDoubleMap(); @@ -123,6 +139,7 @@ public class InternationalMarket { // Update carbon price double totalCarbonSequestered = 0; + @SuppressWarnings("unused") double totalCarbonEmitted = 0; for (AbstractCountryAgent ca : countryAgents) { double netCarbonFlux = ca.getNetCarbonFlux(); diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java index 8e274af0c6d41b3876a2f90a98af6e79e0585a75..8cb8be40f6dead5bf35ed696064351c5d126d7d4 100755 --- a/src/ac/ed/lurg/ModelConfig.java +++ b/src/ac/ed/lurg/ModelConfig.java @@ -13,13 +13,13 @@ 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 { @@ -46,14 +46,14 @@ public class ModelConfig { 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); } @@ -64,7 +64,7 @@ public class ModelConfig { 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; @@ -73,7 +73,7 @@ public class ModelConfig { 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); @@ -83,7 +83,7 @@ public class ModelConfig { 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; @@ -92,15 +92,15 @@ public class ModelConfig { 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; @@ -127,7 +127,6 @@ public class ModelConfig { return value; } - public static final boolean SUPPRESS_STD_OUTPUT = getBooleanProperty("SUPPRESS_STD_OUTPUT", Boolean.FALSE); // Directory information @@ -364,19 +363,7 @@ public class ModelConfig { 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 - - //Dietary stuff - public static final double RUMINANT_CHANGE_ANNUAL_RATE = getDoubleProperty("RUMINANT_CHANGE_ANNUAL_RATE", 0.0); - public static final double MONOGASTRIC_CHANGE_ANNUAL_RATE = getDoubleProperty("MONOGASTRIC_CHANGE_ANNUAL_RATE", 0.00); - public static final boolean CONSTANT_DIET_LOW_INCOME = getBooleanProperty("CONSTANT_DIET_LOW_INCOME", false); - public static final boolean CONSTANT_DIET_HIGH_INCOME = getBooleanProperty("CONSTANT_DIET_HIGH_INCOME", false); - //below should all sum to zero - public static final double CEREALS_SUB_PROPORTION = getDoubleProperty("CEREALS_SUB_PROPORTION", 0.3); - public static final double OILCROPSPULSES_SUB_PROPORTION = getDoubleProperty("OILCROPSPULSES_SUB_PROPORTION", 0.25); - public static final double STARCHY_ROOTS_SUB_PROPORTION = getDoubleProperty("STARCHY_ROOTS_SUB_PROPORTION", 0.25); - public static final double FRUITVEG_SUB_PROPORTION = getDoubleProperty("FRUITVEG_SUB_PROPORTION", 0.1); - public static final double SUGAR_SUB_PROPORTION = getDoubleProperty("SUGAR_SUB_PROPORTION", 0.1); + // 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);; @@ -395,7 +382,7 @@ public class ModelConfig { // 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); @@ -403,7 +390,7 @@ public class ModelConfig { 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 @@ -413,14 +400,14 @@ public class ModelConfig { 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 double MAX_CHINA_LAND_EXPANSION_RATE = getDoubleProperty("MAX_CHINA_LAND_EXPANSION_RATE", 0.011*0.4); // 1.1% max forest change 40% of natural land is forest 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 DEBUG_COUNTRY_NAME = getProperty("DEBUG_COUNTRY_NAME", "China"); public static final String GAMS_COUNTRY_TO_SAVE = getProperty("GAMS_COUNTRY_TO_SAVE", "China");; 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"; @@ -453,6 +440,8 @@ public class ModelConfig { 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"); // Forestry and carbon market parameters public static final String CONVERSION_COST_FILE = DATA_DIR + File.separator + "conversion_costs.csv"; // cost of converting from one land cover to another, $1000/ha @@ -461,7 +450,7 @@ public class ModelConfig { public static final String TIMBER_DEMAND_FILENAME = getProperty("TIMBER_DEMAND_FILENAME", "timber_demand.csv"); public static final String TIMBER_DEMAND_FILE = getProperty("TIMBER_DEMAND_FILE", DATA_DIR + File.separator + TIMBER_DEMAND_FILENAME); - public static final double INIT_WOOD_STOCK = getDoubleProperty("INIT_WOOD_STOCK", 1000.0); // tC-eq + public static final double INIT_WOOD_STOCK = getDoubleProperty("INIT_WOOD_STOCK", 500.0); // tC-eq public static final double IND_ROUNDWOOD_DEMAND_ELASTICITY = getDoubleProperty("IND_ROUNDWOOD_DEMAND_ELASTICITY", 0.3123881); public static final double FUELWOOD_DEMAND_ELASTICITY = getDoubleProperty("FUELDWOOD_DEMAND_ELASTICITY", -0.3598551); public static final String WOOD_NET_IMPORTS_FILENAME = getProperty("WOOD_NET_IMPORTS_FILENAME", "wood_net_imports.csv"); @@ -476,5 +465,7 @@ public class ModelConfig { public static final int CARBON_HORIZON = getIntProperty("CARBON_HORIZON", 30); public static final double WOOD_TRADE_BARRIER = getDoubleProperty("WOOD_TRADE_BARRIER", 0.05); //$1000/tC public static final double INIT_CARBON_PRICE = IS_CARBON_ON ? getDoubleProperty("INIT_CARBON_PRICE", 0.02) : 0.0; // $1000/tC-eq - public static final double INIT_WOOD_PRICE = IS_FORESTRY_ON ? getDoubleProperty("INIT_WOOD_PRICE", 0.3) : 0.0; // $1000/tC-eq + public static final double INIT_WOOD_PRICE = IS_FORESTRY_ON ? getDoubleProperty("INIT_WOOD_PRICE", 0.4) : 0.0; // $1000/tC-eq + public static final boolean RESET_ENERGYCROP_PRICE = getBooleanProperty("RESET_ENERGYCROP_PRICE", true); + public static final boolean ENABLE_VEGETATION_CLEARANCE_COST = getBooleanProperty("ENABLE_VEGETATION_CLEARANCE_COST", true); } diff --git a/src/ac/ed/lurg/ModelMain.java b/src/ac/ed/lurg/ModelMain.java index 3a2f4a15a1de2b052a207d53b6f3e04f253017ea..3ff119d4bf124eb5cfd0a80b2b8b293c58bbd31d 100644 --- a/src/ac/ed/lurg/ModelMain.java +++ b/src/ac/ed/lurg/ModelMain.java @@ -138,7 +138,6 @@ public class ModelMain { } private void doTimestep(Timestep timestep) { - System.gc(); LogWriter.println("Timestep: " + timestep.toString()); LogWriter.println("Memory usage 1: " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024.0*1024.0*1024.0)); @@ -171,6 +170,10 @@ public class ModelMain { countryAgents.determineProductionForAll(timestep, yieldSurfaces, currentIrrigationData, carbonFluxData, woodYieldData, conversionCosts, carbonDemandIncrease); + + if (ModelConfig.RESET_STOCK_YEAR == timestep.getYear()) + internationalMarket.resetStocks(); + internationalMarket.determineInternationalTrade(countryAgents.getAll(), carbonDemand, timestep); int i = 0; @@ -437,17 +440,18 @@ public class ModelMain { private void writeCountryDemandFile(Timestep timestep){ try { - StringBuffer sbHeadings = new StringBuffer("Year, Country, Commodity, Demand, BioenergyDemand"); + StringBuffer sbHeadings = new StringBuffer("Year, Country, Commodity, Demand, BioenergyDemand, ConsumerPrice"); BufferedWriter outputFile = FileWriterHelper.getFileWriter(timestep, ModelConfig.COUNTRY_DEMAND_FILE, sbHeadings.toString()); for (AbstractCountryAgent country : countryAgents.getAll()) { for (CommodityType commodity : CommodityType.getAllFoodItems()) { double bioenergyDemand = demandManager.getFirstGenBioenergyDemand(country.getCountry(), timestep.getYear(), commodity); double demand = country.getCurrentProjectedDemand().get(commodity); + double consumerPrice = country.getCurrentConsumerPrice(commodity); StringBuffer sbData = new StringBuffer(); sbData.append(String.format("%d,%s,%s", timestep.getYear(), country.getCountry(), commodity.getGamsName())); - sbData.append(String.format(",%.3f,%.3f", demand, bioenergyDemand)); + sbData.append(String.format(",%.4f,%.4f,%.4f", demand, bioenergyDemand, consumerPrice)); outputFile.write(sbData.toString()); outputFile.newLine(); @@ -664,8 +668,9 @@ public class ModelMain { rasterToSerialise.put(entry.getKey(), newLuItem); } try { - LogWriter.println("Starting serializing LandUse to " + ModelConfig.SERIALIZED_LAND_USE_FILE); - FileOutputStream fileOut = new FileOutputStream(ModelConfig.SERIALIZED_LAND_USE_FILE); + String fileStr = ModelConfig.IS_CALIBRATION_RUN ? ModelConfig.SERIALIZED_LAND_USE_FILE : ModelConfig.CHECKPOINT_LAND_USE_FILE; + LogWriter.println("Starting serializing LandUse to " + fileStr); + FileOutputStream fileOut = new FileOutputStream(fileStr); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(rasterToSerialise); out.close(); @@ -781,7 +786,7 @@ public class ModelMain { /** Get wood yield data */ private WoodYieldRasterSet getWoodYieldData(Timestep timestep) { - if (ModelConfig.IS_FORESTRY_ON) { + if (ModelConfig.IS_FORESTRY_ON || ModelConfig.ENABLE_VEGETATION_CLEARANCE_COST) { return woodYieldReader.getWoodYields(globalLandUseRaster, timestep, internationalMarket.getWoodPrice().getExportPrice()); } else { return new WoodYieldRasterSet(desiredProjection); diff --git a/src/ac/ed/lurg/carbon/AgeFunction.java b/src/ac/ed/lurg/carbon/AgeFunction.java deleted file mode 100644 index 461cab6e9dfc449e4e1f38c3b0000ea283c3df24..0000000000000000000000000000000000000000 --- a/src/ac/ed/lurg/carbon/AgeFunction.java +++ /dev/null @@ -1,47 +0,0 @@ -package ac.ed.lurg.carbon; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -import ac.ed.lurg.utils.BilinearInterpolator; - -public class AgeFunction implements Serializable { - private static final long serialVersionUID = -6068915999792275002L; - public static final int MAX_AGE = 150; - public static final int YEAR_INTERVAL = 20; - private static final int YEAR_OFFSET = 10; - public static final int AGE_INTERVAL = 10; - - private Map<Integer, Map<Integer, Double>> data = new HashMap<Integer, Map<Integer, Double>>(); - - public void setData(int year, int age, double yield) { - Map<Integer, Double> yieldMap = data.computeIfAbsent(year, o -> new HashMap<Integer, Double>()); - yieldMap.put(age, yield); - } - - public double getValue(int year, int age) { - int yearLower = Math.floorDiv(year, YEAR_INTERVAL) * YEAR_INTERVAL + YEAR_OFFSET; - int yearUpper = yearLower + YEAR_INTERVAL; - int ageLower = Math.floorDiv(age, AGE_INTERVAL) * AGE_INTERVAL; - ageLower = Math.min(ageLower, MAX_AGE); - int ageUpper = ageLower + AGE_INTERVAL; - ageUpper = Math.min(ageUpper, MAX_AGE); - double q11 = data.get(yearLower).get(ageLower); - double q12 = data.get(yearLower).get(ageUpper); - double q21 = data.get(yearUpper).get(ageLower); - double q22 = data.get(yearUpper).get(ageUpper); - // Edge case when age > MAX_AGE. Use linear interpolation. - if (ageLower == ageUpper) { - return q11 + (year - yearLower) * ((q21 - q11) / (yearUpper - yearLower)); - } - double d = BilinearInterpolator.interpolate(year, age, yearLower, yearUpper, ageLower, ageUpper, q11, q12, q21, q22); - return d; - - } - - public int getMaxAge() { - return MAX_AGE; - } - -} diff --git a/src/ac/ed/lurg/country/AbstractCountryAgent.java b/src/ac/ed/lurg/country/AbstractCountryAgent.java index f6cc92d43ab593df641048471cb86791e8809970..16680218da0235a8b26e14c1d762501c4fa0b31c 100644 --- a/src/ac/ed/lurg/country/AbstractCountryAgent.java +++ b/src/ac/ed/lurg/country/AbstractCountryAgent.java @@ -22,6 +22,7 @@ public abstract class AbstractCountryAgent { private Map<CropType, GlobalPrice> currentWorldPrices; protected Map<CropType, CountryPrice> currentCountryPrices; private Map<CropType, CountryPrice> previousCountryPrices; + private Map<CommodityType, Double> currentConsumerCommodityPrices; protected CountryPrice currentCarbonPrice; protected CountryPrice currentTimberPrice; protected Timestep currentTimestep; @@ -102,18 +103,27 @@ public abstract class AbstractCountryAgent { if (!ModelConfig.PRICE_ELASTIC_DEMAND) return null; - Map<CommodityType, Double> prices = new HashMap<CommodityType, Double>(); + currentConsumerCommodityPrices = new HashMap<CommodityType, Double>(); for (CommodityType commodity : CommodityType.getAllFoodItems()) { - double commPricePlum = getCommPriceFromCropPrice(commodity); - prices.put(commodity, commPricePlum); + double commPricePlum = 0; + Map<CropType, Double> demandFract = currentDemandFract.get(commodity); + + for (CropType crop : commodity.getCropTypes()) { + double consumerCropPrice = currentCountryPrices.get(crop).getConsumerPrice(); + commPricePlum += consumerCropPrice * demandFract.get(crop); // weight price by base demand of each cereal crop + } + + currentConsumerCommodityPrices.put(commodity, commPricePlum); LogWriter.println("Producer price for " + commodity.getGamsName() + " is " + commPricePlum); } - return prices; + return currentConsumerCommodityPrices; } - protected abstract double getCommPriceFromCropPrice(CommodityType commodity); + public double getCurrentConsumerPrice(CommodityType commodity) { + return currentConsumerCommodityPrices.get(commodity); + } public Map<CommodityType, Double> getCurrentProjectedDemand() { return currentProjectedDemand; diff --git a/src/ac/ed/lurg/country/CountryAgent.java b/src/ac/ed/lurg/country/CountryAgent.java index 0f17e1b2ea84499374772535758457001a3e79cd..7a1b60aa56cc44aa9cb81c55a82b4bfa469b923b 100644 --- a/src/ac/ed/lurg/country/CountryAgent.java +++ b/src/ac/ed/lurg/country/CountryAgent.java @@ -21,6 +21,8 @@ import ac.ed.lurg.forestry.WoodYieldItem; import ac.ed.lurg.landuse.CropUsageData; import ac.ed.lurg.landuse.IrrigationItem; import ac.ed.lurg.landuse.LandUseItem; +import ac.ed.lurg.shock.MinMaxNetImportManager; +import ac.ed.lurg.shock.MinMaxNetImportManager.LimitType; import ac.ed.lurg.landuse.LccKey; import ac.ed.lurg.landuse.WoodUsageData; import ac.ed.lurg.types.CommodityType; @@ -43,15 +45,20 @@ public class CountryAgent extends AbstractCountryAgent { private GamsRasterOutput previousGamsRasterOutput; private RasterSet<IntegerRasterItem> yieldClusters; private Map<CropType, Double> subsidyRates; + private Map<Integer, Map<CropType, Double>> exportRestrictions; + private Map<Integer, Map<LimitType, Map<CropType, Double>>> minMaxTradeLimits; private boolean saveGamsGdxFiles; public CountryAgent(AbstractDemandManager demandManager,CompositeCountry country, RasterSet<LandUseItem> cropAreaRaster, Map<CropType, CropUsageData> cropUsageData, Map<CropType, Double> tradeBarriers, RasterSet<IntegerRasterItem> yieldClusters, - Map<CropType, Double> subsidyRates, Map<WoodType, WoodUsageData> countryWoodData) { + Map<CropType, Double> subsidyRates, Map<WoodType, WoodUsageData> countryWoodData, + Map<Integer, Map<CropType, Double>> exportRestrictions, Map<Integer, Map<LimitType, Map<CropType, Double>>> minMaxTradeLimits) { super(demandManager, country, tradeBarriers); this.yieldClusters = yieldClusters; this.subsidyRates = subsidyRates; + this.exportRestrictions = exportRestrictions; + this.minMaxTradeLimits = minMaxTradeLimits; GamsRasterOutput initialData = new GamsRasterOutput(cropAreaRaster, cropUsageData, countryWoodData); previousGamsRasterOutput = initialData; @@ -184,7 +191,7 @@ public class CountryAgent extends AbstractCountryAgent { double carbonDemandIncrease) { double allowedImportChange; - if (currentTimestep.isInitialTimestep() || (ModelConfig.IS_CALIBRATION_RUN && currentTimestep.getTimestep() <= ModelConfig.END_FIRST_STAGE_CALIBRATION)) { // initialisation time-step + if (ModelConfig.IS_CALIBRATION_RUN && currentTimestep.getTimestep() <= ModelConfig.END_FIRST_STAGE_CALIBRATION) { // initialisation time-step allowedImportChange = 0.0; } else { // normal (not the initial) time-step @@ -192,6 +199,7 @@ public class CountryAgent extends AbstractCountryAgent { } Map<CropType, TradeConstraint> importConstraints = new HashMap<CropType, TradeConstraint>(); + Map<CropType, Double> currentExportRestictions = (exportRestrictions == null) ? null : exportRestrictions.get(currentTimestep.getYear()); for (Map.Entry<CropType, CropUsageData> entry : previousGamsRasterOutput.getCropUsageData().entrySet()) { CropUsageData cropUsage = entry.getValue(); @@ -212,8 +220,22 @@ public class CountryAgent extends AbstractCountryAgent { if (CropType.ENERGY_CROPS.equals(crop) && baseTrade == 0) { // could apply this logic for all crops? changeDown = changeUp = allowedImportChange * currentGen2EcDemand; } - - importConstraints.put(crop, new TradeConstraint(baseTrade - changeDown, baseTrade + changeUp)); + + double restiction = 0; + if (currentExportRestictions != null) { + Double r = currentExportRestictions.get(crop); + if (r != null) + restiction = r; + } + + Double minLimit=null, maxLimit=null; + if (minMaxTradeLimits != null) { + Map<LimitType, Map<CropType, Double>> minMaxLimits = minMaxTradeLimits.get(currentTimestep.getYear()); + minLimit = minMaxLimits.get(MinMaxNetImportManager.LimitType.MIN_LIMIT_TYPE).get(crop); + maxLimit = minMaxLimits.get(MinMaxNetImportManager.LimitType.MAX_LIMIT_TYPE).get(crop); + } + LogWriter.print(crop.toString()); + importConstraints.put(crop, new TradeConstraint(baseTrade - changeDown, baseTrade + changeUp, restiction, minLimit, maxLimit)); } // Carbon import/export constraints TODO not used, might want in future @@ -245,8 +267,9 @@ public class CountryAgent extends AbstractCountryAgent { // assume 1tC/ha/year double potentialYield = LandUseItem.getTotalLandCover(previousGamsRasterOutput.getLandUses().values(), LandCoverType.TIMBER_FOREST); double currentDemand = currentWoodDemand.get(woodType); - double importsNeeded = Math.max(0, currentDemand - potentialYield * 0.5); - baseTrade = importsNeeded > 0 ? importsNeeded : baseTrade * 2; + double importsNeeded = Math.max(0, currentDemand - potentialYield * 3); + baseTrade = importsNeeded > 0 ? importsNeeded : baseTrade; + baseTrade = baseTrade < 0 ? baseTrade * 20 : baseTrade; } double changeUp = 0.0; @@ -267,20 +290,7 @@ public class CountryAgent extends AbstractCountryAgent { return input; } - - @Override - protected double getCommPriceFromCropPrice(CommodityType commodity) { - double commPricePlum = 0; - Map<CropType, Double> demandFract = currentDemandFract.get(commodity); - - for (CropType crop : commodity.getCropTypes()) { - double consumerCropPrice = currentCountryPrices.get(crop).getConsumerPrice(); - commPricePlum += consumerCropPrice * demandFract.get(crop); // weight price by base demand of each cereal crop - } - - return commPricePlum; - } - + @Override protected CountryPrice createCountryPrices(CropType crop, GlobalPrice worldPrice) { Map<CropType, CropUsageData> cropUsageMap = previousGamsRasterOutput.getCropUsageData(); diff --git a/src/ac/ed/lurg/country/CountryAgentManager.java b/src/ac/ed/lurg/country/CountryAgentManager.java index 09fe057e7c0902394b8dfe912def28ccca1f55dc..257b80ee544c6d4c7a0353d7128070f5898d14d0 100644 --- a/src/ac/ed/lurg/country/CountryAgentManager.java +++ b/src/ac/ed/lurg/country/CountryAgentManager.java @@ -23,6 +23,9 @@ import ac.ed.lurg.landuse.CropUsageData; import ac.ed.lurg.landuse.IrrigationItem; import ac.ed.lurg.landuse.IrrigationRasterSet; import ac.ed.lurg.landuse.LandUseItem; +import ac.ed.lurg.shock.ExportRestrictionManager; +import ac.ed.lurg.shock.MinMaxNetImportManager; +import ac.ed.lurg.shock.MinMaxNetImportManager.LimitType; import ac.ed.lurg.landuse.LccKey; import ac.ed.lurg.landuse.WoodUsageData; import ac.ed.lurg.types.CropType; @@ -38,6 +41,8 @@ public class CountryAgentManager { private TradeManager tradeBarrierManager; private SubsidyRateManager subsidyRateManager; private InternationalMarket internationalMarket; + private ExportRestrictionManager exportRestrictionManager; + private MinMaxNetImportManager minMaxNetImportManager; private CountryBoundaryRaster countryBoundaryRaster; private RasterSet<IntegerRasterItem> clusterIdRaster; private RasterSet<LandUseItem> globalLandUseRaster; @@ -57,6 +62,8 @@ public class CountryAgentManager { this.globalLandUseRaster = globalLandUseRaster; tradeBarrierManager = new TradeManager(compositeCountryManager); subsidyRateManager = new SubsidyRateManager(compositeCountryManager); + exportRestrictionManager = new ExportRestrictionManager(); + minMaxNetImportManager = new MinMaxNetImportManager(); craftyManager = new CraftyProdManager(); } @@ -92,8 +99,10 @@ public class CountryAgentManager { } else { Map<CropType, Double> subsidyRates = subsidyRateManager.getSubsidyRates(cc); + Map<Integer, Map<CropType, Double>> exportRestrictions = exportRestrictionManager.getShocksForCountry(cc); + Map<Integer, Map<LimitType, Map<CropType, Double>>> minMaxTradeLimits = minMaxNetImportManager.getMinMaxNetImportForCountry(cc); - CountryAgent ca = new CountryAgent(demandManager, cc, initCountryLandUse, countryCommodityData, tradeBarriers, yieldClusters, subsidyRates, countryWoodData); + CountryAgent ca = new CountryAgent(demandManager, cc, initCountryLandUse, countryCommodityData, tradeBarriers, yieldClusters, subsidyRates, countryWoodData, exportRestrictions, minMaxTradeLimits); gamsCountryAgents.add(ca); countryAgents.add(ca); } diff --git a/src/ac/ed/lurg/country/CountryPrice.java b/src/ac/ed/lurg/country/CountryPrice.java index 22c4587f279a44ce4ce4c2f7cd1913d5d681d84f..aac3fbc0e36c5177cc7d3276976d44618873d1f4 100644 --- a/src/ac/ed/lurg/country/CountryPrice.java +++ b/src/ac/ed/lurg/country/CountryPrice.java @@ -52,10 +52,10 @@ public class CountryPrice { consumerPrice = importPrice; break; case WEIGHTEDIMPEXP: - consumerPrice = importPrice*importWeighting + getExportPrice()*(1-importWeighting); + consumerPrice = weightPrice(importWeighting, importPrice, getExportPrice()); break; case WEIGHTEDINCLPRODCOSTS: - consumerPrice = importPrice*importWeighting + exportOrProdCost*(1-importWeighting); + consumerPrice = weightPrice(importWeighting, importPrice, exportOrProdCost); break; default: consumerPrice = importPrice; @@ -67,6 +67,13 @@ public class CountryPrice { crop, importPrice, getExportPrice(), prodCost, importWeighting, consumerPrice)); return consumerPrice; } + + private double weightPrice(double weight, double iPrice, double ePrice) { + if (ePrice > iPrice) + return iPrice; // consumer price is not be allowed to rise above import price, you could just import rather than buying domestically produced products + else + return iPrice*weight + ePrice*(1-weight); + } private double calcProducerNetExportPrice(double exportTaxRate) { if (ModelConfig.APPLY_EXPORT_TAXES) diff --git a/src/ac/ed/lurg/country/GlobalPrice.java b/src/ac/ed/lurg/country/GlobalPrice.java index f62455041703515ac5fdfb17e5f113ac7d6a5d48..552ba9df53bd246e2c20fe91db650ca2a567aabb 100644 --- a/src/ac/ed/lurg/country/GlobalPrice.java +++ b/src/ac/ed/lurg/country/GlobalPrice.java @@ -142,4 +142,8 @@ public class GlobalPrice implements Serializable { public GlobalPrice createPriceAdjustedByFactor(double factor) { return new GlobalPrice(timestep, exportPrice * factor, stockLevel, importAmount, exportAmountBeforeLoss, transportLosses, referencePrice); } + + public void resetStock(Double stock) { + this.stockLevel = stock; + } } \ No newline at end of file diff --git a/src/ac/ed/lurg/country/TradeConstraint.java b/src/ac/ed/lurg/country/TradeConstraint.java index c314ab0c9ac00978ac4ae456caa38c9aa7c5ba6a..085065b6ce27e22607fcee4e2c9223df6a88d5a0 100644 --- a/src/ac/ed/lurg/country/TradeConstraint.java +++ b/src/ac/ed/lurg/country/TradeConstraint.java @@ -1,12 +1,42 @@ package ac.ed.lurg.country; +import ac.ed.lurg.utils.LogWriter; + public class TradeConstraint { private double minValue; private double maxValue; - public TradeConstraint(double minValue, double maxValue) { - this.minValue = minValue; - this.maxValue = maxValue; + public TradeConstraint(double min, double max) { + minValue = min; + maxValue = max; + } + + public TradeConstraint(double min, double max, double exportRetriction, Double minLimit, Double maxLimit) { + LogWriter.print(" TradeConstraint: min=" + min + ", max=" + max + ", exportRetriction=" + exportRetriction + ", minLimit=" + minLimit + ", maxLimit=" + maxLimit); + + if (minLimit != null && min < minLimit) { + min = minLimit.doubleValue(); + if (min > max) + max = min; + } + + if (maxLimit != null && max > maxLimit) { + max = maxLimit.doubleValue(); + if (min > max) + min = max; + } + + minValue = applyExportRestriction(min, exportRetriction); + maxValue = applyExportRestriction(max, exportRetriction); + + LogWriter.println(" - resulted in minValue=" + minValue + ", maxValue=" + maxValue); + } + + private double applyExportRestriction(double amountBefore, double restrictionRate) { + if (amountBefore < 0 & restrictionRate > 0) // exporting and an export restriction is in place + return amountBefore * (1 - restrictionRate); + else + return amountBefore; } public double getMinConstraint() { @@ -16,4 +46,9 @@ public class TradeConstraint { public double getMaxConstraint() { return maxValue; } + + @Override + public String toString() { + return "TradeConstraint [minValue=" + minValue + ", maxValue=" + maxValue + "]"; + } } diff --git a/src/ac/ed/lurg/country/crafty/CraftyCountryAgent.java b/src/ac/ed/lurg/country/crafty/CraftyCountryAgent.java index 83faccc1589b99da4c420e16a9d90cd139ac2ced..3494f1559d73ccc99a91cdfbb0c832d9d164a678 100644 --- a/src/ac/ed/lurg/country/crafty/CraftyCountryAgent.java +++ b/src/ac/ed/lurg/country/crafty/CraftyCountryAgent.java @@ -34,21 +34,17 @@ public class CraftyCountryAgent extends AbstractCountryAgent { updateNetImportsFromProdAndDemand(currentProjectedDemand, currentDemandFract, cropUsageMap); } - @Override - protected double getCommPriceFromCropPrice(CommodityType commodity) { - double commPricePlum = 0; - Map<CropType, Double> demandFract = currentDemandFract.get(commodity); - - for (CropType crop : commodity.getCropTypes()) { - commPricePlum += currentCountryPrices.get(crop).getImportPrice() * demandFract.get(crop); // weight price by base demand of each cereal crop - } - return commPricePlum; - } - @Override protected CountryPrice createCountryPrices(CropType crop, GlobalPrice worldPrice) { - // TODO Auto-generated method stub - return null; + CropUsageData cropUsage = cropUsageData.get(crop); + + double weighting = Math.max(0, cropUsage.getShockedNetImports()/(cropUsage.getProductionExpected()+cropUsage.getShockedNetImports())); + double prodCost = cropUsage.getProdCostRate(); + Double tb = tradeBarriers.get(crop); + double tradeBarrier = tb==null ? 0 : tb; + double exportTaxRateForCrop = CommodityType.CEREALS.getCropTypes().contains(crop) ? exportTaxRate : 0.0; + CountryPrice cp = new CountryPrice(crop, worldPrice, tradeBarrier, prodCost, weighting, exportTaxRateForCrop); + return cp; } public double getNetCarbonFlux() { diff --git a/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java b/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java index 814347b235f4ef041655d9c1b5900a6c237df9f1..c107b32939c5402e91b8e1c380d0f003e560ede7 100755 --- a/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java @@ -1,181 +1,180 @@ -package ac.ed.lurg.country.gams; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Vector; - -import com.gams.api.GAMSDatabase; -import com.gams.api.GAMSGlobals; -import com.gams.api.GAMSGlobals.DebugLevel; -import com.gams.api.GAMSJob; -import com.gams.api.GAMSOptions; -import com.gams.api.GAMSParameter; -import com.gams.api.GAMSParameterRecord; -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.types.CommodityType; -import ac.ed.lurg.utils.LogWriter; - -public class GamsDemandOptimiser { - - private GamsDemandInput inputData; - - public GamsDemandOptimiser(GamsDemandInput inputData) { - this.inputData = inputData; - } - - public GamsDemandOutput getDemandPc() { - File workingDirectory = new File(ModelConfig.TEMP_DIR); - workingDirectory.mkdir(); - GAMSWorkspaceInfo wsInfo = new GAMSWorkspaceInfo(); - wsInfo.setWorkingDirectory(workingDirectory.getAbsolutePath()); - LogWriter.println("debug5"); - System.gc(); - GAMSWorkspace ws = new GAMSWorkspace(wsInfo); - GAMSOptions opt = ws.addOptions(); - GAMSJob gamsJob = ws.addJobFromFile(ModelConfig.DEMAND_GAMS_MODEL); - - GAMSDatabase inDB = ws.addDatabase(); - setupPriceGdpDB(inDB); - ArrayList<GAMSDatabase> dbs = new ArrayList<GAMSDatabase>(); - dbs.add(inDB); - opt.defines("gdx_prices_and_gdp", inDB.getName()); - - if (ModelConfig.ADJUST_DIET_PREFS) { - LogWriter.println("Adusting diet params"); - GAMSDatabase originalParamDb = ws.addDatabaseFromGDX(new File(ModelConfig.DEMAND_PARAM_FILE).getAbsolutePath()); - GAMSDatabase adjustedParamDb = ws.addDatabase(originalParamDb); - adjustDietParams(adjustedParamDb); - dbs.add(adjustedParamDb); - opt.defines("gdx_parameters", adjustedParamDb.getName()); - } - else - opt.defines("gdx_parameters", new File(ModelConfig.DEMAND_PARAM_FILE).getAbsolutePath()); - - long startTime = System.currentTimeMillis(); - LogWriter.println("Memory usage: GAMS Demand " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024.0*1024.0*1024.0)); - gamsJob.run(opt, dbs.toArray(new GAMSDatabase[dbs.size()])); - LogWriter.println("Took " + (System.currentTimeMillis() - startTime) + " ms to run"); - return handleResults(gamsJob.OutDB()); - } - - private void adjustDietParams(GAMSDatabase adjustedParamDb) { - // get original parameters - GAMSParameter tauParam = adjustedParamDb.getParameter("tau"); - TauCalculationManager tauManager = TauCalculationManager.getInstance(); - - for (GAMSParameterRecord rec : tauParam) { - String key = rec.getKeys()[0]; - double initialTau = rec.getValue(); - - CommodityType commodity = CommodityType.getForGamsName(key); - double adjusted = tauManager.getFinalTau(inputData.getYear(), initialTau, commodity); - LogWriter.println(String.format("%14s: initialTau=%.6f, adjusted=%.6f", key, initialTau, adjusted)); - rec.setValue(adjusted); - } - } - - private void setupPriceGdpDB(GAMSDatabase inDB) { - GAMSParameter gdpPcP = inDB.addParameter("gdp_pc", 0); - double gdpPc = inputData.getGdpPc(); - LogWriter.println(String.format("gdp_pc = %.5f", gdpPc)); - setGamsParamValue(gdpPcP.addRecord(), gdpPc, 5); - GamsDemandOutput previousGamsDemands = inputData.getPreviousDemands(); - - GAMSParameter prevUP = inDB.addParameter("previousU", 0); - double previousUtility = previousGamsDemands == null ? 0 : previousGamsDemands.getUtility();//-16.3829624069452 + 4.3659621833299 * Math.log10(gdpPc); - LogWriter.println(String.format("previousU = %.5f, estimated = %.5f", previousUtility, -16.3829624069452 + 4.3659621833299 * Math.log10(gdpPc))); - setGamsParamValue(prevUP.addRecord(), previousUtility, 5); - - GAMSParameter maxIncomePropFoodSpendP = inDB.addParameter("maxIncomePropFoodSpend", 0); - setGamsParamValue(maxIncomePropFoodSpendP.addRecord(), ModelConfig.MAX_INCOME_PROPORTION_FOOD_SPEND, 4); - - LogWriter.println("\nPrice"); - GAMSParameter priceP = inDB.addParameter("price", 1); - GAMSParameter prevSubsP = inDB.addParameter("previousSubs", 1); - GAMSParameter prevDiscP = inDB.addParameter("previousDisc", 1); - - for (Map.Entry<CommodityType, Double> entry : inputData.getPrices().entrySet()) { - CommodityType comm = entry.getKey(); - double priceComm = entry.getValue(); - doCommodity(inDB, priceP, prevSubsP, prevDiscP, gdpPc, previousGamsDemands, comm, priceComm, - comm==CommodityType.NONFOOD ? 5 : 0.05, comm==CommodityType.NONFOOD ? 0.5 : 0.05); - } - } - - private void doCommodity(GAMSDatabase inDB, GAMSParameter priceP, GAMSParameter prevSubsP, GAMSParameter prevDiscP, double gdpPc, - GamsDemandOutput previousGamsDemands, CommodityType comm, double price, double defaultSubs, double defaultDisc) { - - Vector<String> v = new Vector<String>(); - v.add(comm.getGamsName()); - double prevSubs = defaultSubs, prevDisc = defaultDisc; - - if (previousGamsDemands != null) { - GamsCommodityDemand demand = previousGamsDemands.getGamsDemands(comm); - prevSubs = demand.getSubsistence(); - prevDisc = demand.getDiscretionary(); - } - - LogWriter.println(String.format("%14s: price=%.4f, previousSubs=%.4f, previousDisc=%.4f", comm.getGamsName(), price, prevSubs, prevDisc)); - setGamsParamValue(priceP.addRecord(v), price, 4); - setGamsParamValue(prevSubsP.addRecord(v), prevSubs, 4); - setGamsParamValue(prevDiscP.addRecord(v), prevDisc, 4); - } - - private double setGamsParamValue(GAMSParameterRecord param, double val, int places) { - double dOut = Math.round(val * Math.pow(10,places)) / Math.pow(10,places); - param.setValue(dOut); - return dOut; - } - - private GamsDemandOutput handleResults(GAMSDatabase outDB) { - int modelStatus = (int) outDB.getParameter("ms").findRecord().getValue(); - String status = GAMSGlobals.ModelStat.lookup(modelStatus).toString(); - LogWriter.println(String.format("\nDemand %s: Modelstatus (%d) %s, Solvestatus %s", inputData.getCountry(), - modelStatus, status, GAMSGlobals.SolveStat.lookup((int) outDB.getParameter("ss").findRecord().getValue()) )); - - GAMSVariable varU = outDB.getVariable("u"); - double utility = varU.getFirstRecord().getLevel(); - LogWriter.println(String.format("u = %.4f", utility)); - - GAMSVariable varSubs = outDB.getVariable("SubsistenceC"); - GAMSVariable varDisc = outDB.getVariable("DiscretionaryC"); - - HashSet<GamsCommodityDemand> demandMap = new HashSet<GamsCommodityDemand>(); - Collection<CommodityType> unhandledComms = new ArrayList<CommodityType>(CommodityType.getAllFoodItems()); - - for (GAMSVariableRecord rec : varSubs) { - String commodityName = rec.getKeys()[0]; - CommodityType commodity = CommodityType.getForGamsName(commodityName, true); - - if (commodity == null) - LogWriter.println(String.format("Can't find commodity from Gams demand, so ignoring: " + commodityName)); - else { - double subsGams = rec.getLevel(); - double discGams = modelStatus==0 ? 0 : varDisc.findRecord(commodityName).getLevel(); //modelStatus==0 is optimiser not run, i.e. too low GDP - GamsCommodityDemand demand = new GamsCommodityDemand(commodity, subsGams, discGams,inputData.getKcalPerT(commodity)); - LogWriter.println(demand.toString()); - demandMap.add(demand); - unhandledComms.remove(commodity); - } - } - - for (CommodityType commodity : unhandledComms) { - LogWriter.println(commodity + " not found in Gams output so adding with zero demand"); - demandMap.add(new GamsCommodityDemand(commodity, 0, 0, 0)); - } - - GAMSParameter parConsumpFact = outDB.getParameter("desiredConsumpFactor"); - double desiredConsumpFactor = parConsumpFact.getFirstRecord().getValue(); - LogWriter.println(String.format("desiredConsumpFactor=%.4f", desiredConsumpFactor)); - - return new GamsDemandOutput(status, demandMap, utility, desiredConsumpFactor); - } -} +package ac.ed.lurg.country.gams; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Vector; + +import com.gams.api.GAMSDatabase; +import com.gams.api.GAMSGlobals; +import com.gams.api.GAMSJob; +import com.gams.api.GAMSOptions; +import com.gams.api.GAMSParameter; +import com.gams.api.GAMSParameterRecord; +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.types.CommodityType; +import ac.ed.lurg.utils.LogWriter; + +public class GamsDemandOptimiser { + + private GamsDemandInput inputData; + + public GamsDemandOptimiser(GamsDemandInput inputData) { + this.inputData = inputData; + } + + public GamsDemandOutput getDemandPc() { + File workingDirectory = new File(ModelConfig.TEMP_DIR); + workingDirectory.mkdir(); + GAMSWorkspaceInfo wsInfo = new GAMSWorkspaceInfo(); + wsInfo.setWorkingDirectory(workingDirectory.getAbsolutePath()); + + GAMSWorkspace ws = new GAMSWorkspace(wsInfo); + GAMSOptions opt = ws.addOptions(); + GAMSJob gamsJob = ws.addJobFromFile(ModelConfig.DEMAND_GAMS_MODEL); + + GAMSDatabase inDB = ws.addDatabase(); + setupPriceGdpDB(inDB); + ArrayList<GAMSDatabase> dbs = new ArrayList<GAMSDatabase>(); + dbs.add(inDB); + opt.defines("gdx_prices_and_gdp", inDB.getName()); + + if (ModelConfig.ADJUST_DIET_PREFS) { + LogWriter.println("Adusting diet params"); + GAMSDatabase originalParamDb = ws.addDatabaseFromGDX(new File(ModelConfig.DEMAND_PARAM_FILE).getAbsolutePath()); + GAMSDatabase adjustedParamDb = ws.addDatabase(originalParamDb); + adjustDietParams(adjustedParamDb); + dbs.add(adjustedParamDb); + opt.defines("gdx_parameters", adjustedParamDb.getName()); + } + else + opt.defines("gdx_parameters", new File(ModelConfig.DEMAND_PARAM_FILE).getAbsolutePath()); + + long startTime = System.currentTimeMillis(); + LogWriter.println("Memory usage: GAMS Demand " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024.0*1024.0*1024.0)); + gamsJob.run(opt, dbs.toArray(new GAMSDatabase[dbs.size()])); + + LogWriter.println("Took " + (System.currentTimeMillis() - startTime) + " ms to run"); + return handleResults(gamsJob.OutDB()); + } + + private void adjustDietParams(GAMSDatabase adjustedParamDb) { + // get original parameters + GAMSParameter tauParam = adjustedParamDb.getParameter("tau"); + TauCalculationManager tauManager = TauCalculationManager.getInstance(); + + for (GAMSParameterRecord rec : tauParam) { + String key = rec.getKeys()[0]; + double initialTau = rec.getValue(); + + CommodityType commodity = CommodityType.getForGamsName(key); + double adjusted = tauManager.getFinalTau(inputData.getYear(), initialTau, commodity); + LogWriter.println(String.format("%14s: initialTau=%.6f, adjusted=%.6f", key, initialTau, adjusted)); + rec.setValue(adjusted); + } + } + + private void setupPriceGdpDB(GAMSDatabase inDB) { + GAMSParameter gdpPcP = inDB.addParameter("gdp_pc", 0); + double gdpPc = inputData.getGdpPc(); + LogWriter.println(String.format("gdp_pc = %.5f", gdpPc)); + setGamsParamValue(gdpPcP.addRecord(), gdpPc, 5); + GamsDemandOutput previousGamsDemands = inputData.getPreviousDemands(); + + GAMSParameter prevUP = inDB.addParameter("previousU", 0); + double previousUtility = previousGamsDemands == null ? 0 : previousGamsDemands.getUtility();//-16.3829624069452 + 4.3659621833299 * Math.log10(gdpPc); + LogWriter.println(String.format("previousU = %.5f, estimated = %.5f", previousUtility, -16.3829624069452 + 4.3659621833299 * Math.log10(gdpPc))); + setGamsParamValue(prevUP.addRecord(), previousUtility, 5); + + GAMSParameter maxIncomePropFoodSpendP = inDB.addParameter("maxIncomePropFoodSpend", 0); + setGamsParamValue(maxIncomePropFoodSpendP.addRecord(), ModelConfig.MAX_INCOME_PROPORTION_FOOD_SPEND, 4); + + LogWriter.println("\nPrice"); + GAMSParameter priceP = inDB.addParameter("price", 1); + GAMSParameter prevSubsP = inDB.addParameter("previousSubs", 1); + GAMSParameter prevDiscP = inDB.addParameter("previousDisc", 1); + + for (Map.Entry<CommodityType, Double> entry : inputData.getPrices().entrySet()) { + CommodityType comm = entry.getKey(); + double priceComm = entry.getValue(); + doCommodity(inDB, priceP, prevSubsP, prevDiscP, gdpPc, previousGamsDemands, comm, priceComm, + comm==CommodityType.NONFOOD ? 5 : 0.05, comm==CommodityType.NONFOOD ? 0.5 : 0.05); + } + } + + private void doCommodity(GAMSDatabase inDB, GAMSParameter priceP, GAMSParameter prevSubsP, GAMSParameter prevDiscP, double gdpPc, + GamsDemandOutput previousGamsDemands, CommodityType comm, double price, double defaultSubs, double defaultDisc) { + + Vector<String> v = new Vector<String>(); + v.add(comm.getGamsName()); + double prevSubs = defaultSubs, prevDisc = defaultDisc; + + if (previousGamsDemands != null) { + GamsCommodityDemand demand = previousGamsDemands.getGamsDemands(comm); + prevSubs = demand.getSubsistence(); + prevDisc = demand.getDiscretionary(); + } + + LogWriter.println(String.format("%14s: price=%.4f, previousSubs=%.4f, previousDisc=%.4f", comm.getGamsName(), price, prevSubs, prevDisc)); + setGamsParamValue(priceP.addRecord(v), price, 4); + setGamsParamValue(prevSubsP.addRecord(v), prevSubs, 4); + setGamsParamValue(prevDiscP.addRecord(v), prevDisc, 4); + } + + private double setGamsParamValue(GAMSParameterRecord param, double val, int places) { + double dOut = Math.round(val * Math.pow(10,places)) / Math.pow(10,places); + param.setValue(dOut); + return dOut; + } + + private GamsDemandOutput handleResults(GAMSDatabase outDB) { + int modelStatus = (int) outDB.getParameter("ms").findRecord().getValue(); + String status = GAMSGlobals.ModelStat.lookup(modelStatus).toString(); + LogWriter.println(String.format("\nDemand %s: Modelstatus (%d) %s, Solvestatus %s", inputData.getCountry(), + modelStatus, status, GAMSGlobals.SolveStat.lookup((int) outDB.getParameter("ss").findRecord().getValue()) )); + + GAMSVariable varU = outDB.getVariable("u"); + double utility = varU.getFirstRecord().getLevel(); + LogWriter.println(String.format("u = %.4f", utility)); + + GAMSVariable varSubs = outDB.getVariable("SubsistenceC"); + GAMSVariable varDisc = outDB.getVariable("DiscretionaryC"); + + HashSet<GamsCommodityDemand> demandMap = new HashSet<GamsCommodityDemand>(); + Collection<CommodityType> unhandledComms = new ArrayList<CommodityType>(CommodityType.getAllFoodItems()); + + for (GAMSVariableRecord rec : varSubs) { + String commodityName = rec.getKeys()[0]; + CommodityType commodity = CommodityType.getForGamsName(commodityName, true); + + if (commodity == null) + LogWriter.println(String.format("Can't find commodity from Gams demand, so ignoring: " + commodityName)); + else { + double subsGams = rec.getLevel(); + double discGams = modelStatus==0 ? 0 : varDisc.findRecord(commodityName).getLevel(); //modelStatus==0 is optimiser not run, i.e. too low GDP + GamsCommodityDemand demand = new GamsCommodityDemand(commodity, subsGams, discGams,inputData.getKcalPerT(commodity)); + LogWriter.println(demand.toString()); + demandMap.add(demand); + unhandledComms.remove(commodity); + } + } + + for (CommodityType commodity : unhandledComms) { + LogWriter.println(commodity + " not found in Gams output so adding with zero demand"); + demandMap.add(new GamsCommodityDemand(commodity, 0, 0, 0)); + } + + GAMSParameter parConsumpFact = outDB.getParameter("desiredConsumpFactor"); + double desiredConsumpFactor = parConsumpFact.getFirstRecord().getValue(); + LogWriter.println(String.format("desiredConsumpFactor=%.4f", desiredConsumpFactor)); + + return new GamsDemandOutput(status, demandMap, utility, desiredConsumpFactor); + } +} diff --git a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java index 791d0744b2dda21b703aff8733b6ada845ecbc75..85208f09f0da4061d5115ab9fa24402ae0c761b5 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java @@ -10,7 +10,6 @@ import java.util.Vector; import com.gams.api.GAMSDatabase; import com.gams.api.GAMSException; import com.gams.api.GAMSGlobals; -import com.gams.api.GAMSGlobals.DebugLevel; import com.gams.api.GAMSGlobals.ModelStat; import com.gams.api.GAMSJob; import com.gams.api.GAMSOptions; @@ -46,7 +45,7 @@ import ac.ed.lurg.yield.YieldResponsesItem; public class GamsLocationOptimiser { - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; private GamsLocationInput inputData; @@ -55,16 +54,19 @@ public class GamsLocationOptimiser { } public GamsLocationOutput run() { + File workingDirectory = new File(ModelConfig.TEMP_DIR); workingDirectory.mkdir(); + GAMSWorkspaceInfo wsInfo = new GAMSWorkspaceInfo(); wsInfo.setWorkingDirectory(workingDirectory.getAbsolutePath()); - LogWriter.println("debugb6"); - System.gc(); + // 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(); @@ -73,16 +75,14 @@ public class GamsLocationOptimiser { opt.defines("gdxincname", inDB.getName()); long startTime = System.currentTimeMillis(); - gamsJob.run(opt, inDB); + 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) { @@ -195,11 +195,11 @@ public class GamsLocationOptimiser { 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"); @@ -287,7 +287,7 @@ public class GamsLocationOptimiser { double minTrade = iec.getMinConstraint(); double maxTrade = iec.getMaxConstraint(); double importPrice = gp.getImportPrice(); - double exportPrice = gp.getExportPrice(); + double exportPrice = gp.getProducerNetExportPrice(); CropUsageData cu = countryInput.getPreviousCropUsageData().get(crop); double netImports = cu.getNetImportsExpected(); @@ -311,7 +311,6 @@ public class GamsLocationOptimiser { 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 @@ -479,7 +478,7 @@ public class GamsLocationOptimiser { GAMSParameter parmProdCost = outDB.getParameter("totalProdCost"); GAMSParameter parmCroplandArea = outDB.getParameter("totalCropland"); GAMSParameter parmTotalArea = outDB.getParameter("totalArea"); - GAMSParameter parmProdShock = outDB.getParameter("productionShock"); + GAMSParameter parmProdShock = outDB.getParameter("productionShock"); double totalCropArea = 0; double totalPastureArea = 0; diff --git a/src/ac/ed/lurg/forestry/WoodYieldItem.java b/src/ac/ed/lurg/forestry/WoodYieldItem.java index 9027b28f303c6d95c629f4481c8490e7d737e0c5..f9f0459579df3cfd35c6869417b21b132070ff83 100644 --- a/src/ac/ed/lurg/forestry/WoodYieldItem.java +++ b/src/ac/ed/lurg/forestry/WoodYieldItem.java @@ -45,6 +45,13 @@ public class WoodYieldItem implements RasterItem { } public void calcRotationData(Map<LccKey, Double[]> woodYields, Map<LandCoverType, LandCoverTile> landUseTiles, Timestep timestep, double woodPrice) { + + if (!ModelConfig.IS_FORESTRY_ON) { + optimalRotation = 0; + yieldAtRotation = 0; + return; + } + // Optimal rotation List<Double> levArr = new ArrayList<Double>(); diff --git a/src/ac/ed/lurg/landuse/LandCoverTile.java b/src/ac/ed/lurg/landuse/LandCoverTile.java index 776add086d3443d9de4ec61c5b3cc2f54cb2d249..250e37f0d59584995c2d30fc3ac8b9209cb760e0 100644 --- a/src/ac/ed/lurg/landuse/LandCoverTile.java +++ b/src/ac/ed/lurg/landuse/LandCoverTile.java @@ -42,15 +42,14 @@ public class LandCoverTile implements Serializable, InterpolatingRasterItem<Land areas.put(key, prevArea + a); } + // This is used during calibration to preserve Land cover age distribution public void addArea(LandProtectionType lpType, double a) { double totalArea = getTotalArea(lpType); if (totalArea == 0) { - for (int age = 0; age <= 150; age+=10) { - addArea(lpType, age, a/16); // assuming even distribution - } + addArea(lpType, 0, a); // assuming all age=0 if no previous land cover } else { - double factor = (a + totalArea) / totalArea; + double factor = (a + totalArea) / totalArea; // proportional allocation for (LandKey key : areas.keySet()) { if (key.getLpType().equals(lpType)) { double prevArea = getArea(key); @@ -81,7 +80,7 @@ public class LandCoverTile implements Serializable, InterpolatingRasterItem<Land setArea(key, prevArea - a); } - public void removeArea(LandProtectionType lpType, double a) { // Subtracts area uniformly + public void removeArea(LandProtectionType lpType, double a) { // Subtracts area proportionally if (a == 0) return; double totalArea = getTotalArea(lpType); @@ -106,19 +105,6 @@ public class LandCoverTile implements Serializable, InterpolatingRasterItem<Land return area; } - public void resetAreaForAge(LandProtectionType lpType, int age) { - LandKey key = new LandKey(lpType, age); - double a = getArea(key); - areas.remove(key); - setArea(lpType, 0, a); - } - - public void resetAreaForAge(LandProtectionType lpType, int age, double a) { - a = Math.min(getArea(lpType, age), a); - removeArea(lpType, age, a); - addArea(lpType, 0, a); - } - public void removeAllArea(LandProtectionType lpType) { Map<LandKey, Double> newAreas = new HashMap<LandKey, Double>(); for (LandKey key : areas.keySet()) { diff --git a/src/ac/ed/lurg/landuse/WoodUsageData.java b/src/ac/ed/lurg/landuse/WoodUsageData.java index d650ef5d85de31830f3d017d73e287c89a9e4d91..cddab4878b87b12ff86f674346c2ee4bd8599c3f 100644 --- a/src/ac/ed/lurg/landuse/WoodUsageData.java +++ b/src/ac/ed/lurg/landuse/WoodUsageData.java @@ -6,18 +6,18 @@ public class WoodUsageData implements Serializable { private static final long serialVersionUID = -3329080279189782763L; - private double harvest; + private double rotaHarvest; private double netImport; private double lucHarvest; public WoodUsageData(double harvest, double netImport, double lucHarvest) { - this.harvest = harvest; + this.rotaHarvest = harvest; this.netImport = netImport; this.lucHarvest = lucHarvest; } public double getHarvest() { - return harvest; + return rotaHarvest; } public double getNetImport() { diff --git a/src/ac/ed/lurg/output/LpjgOutputer.java b/src/ac/ed/lurg/output/LpjgOutputer.java index 4d45187bd48669f533f449fb18614e314e3c5231..725f2976b10b465e23a8c308aff64b3173ac635f 100644 --- a/src/ac/ed/lurg/output/LpjgOutputer.java +++ b/src/ac/ed/lurg/output/LpjgOutputer.java @@ -125,7 +125,7 @@ public class LpjgOutputer extends AbstractLandUseOutputer { try { String landCoverFileName = outputDir.getPath() + File.separator + "LandCoverFract.txt"; landCoverWriter = new BufferedWriter(new FileWriter(landCoverFileName, false)); - landCoverWriter.write("Lon Lat Year CROPLAND PASTURE NATURAL BARREN URBAN"); + landCoverWriter.write("Lon Lat Year CROPLAND PASTURE TIMBER CARBON NATURAL BARREN URBAN"); landCoverWriter.newLine(); for (Entry<RasterKey, LandUseItem> entry : landUseRaster.entrySet()) { @@ -143,11 +143,12 @@ public class LpjgOutputer extends AbstractLandUseOutputer { double crop = item.getLandCoverFract(LandCoverType.CROPLAND); double pasture = item.getLandCoverFract(LandCoverType.PASTURE); - double forest = item.getLandCoverFract(LandCoverType.TIMBER_FOREST) + item.getLandCoverFract(LandCoverType.CARBON_FOREST); + double timberForest = item.getLandCoverFract(LandCoverType.TIMBER_FOREST); + double carbonForest = item.getLandCoverFract(LandCoverType.CARBON_FOREST); double otherNatural = item.getLandCoverFract(LandCoverType.NATURAL); double barren = item.getLandCoverFract(LandCoverType.BARREN); double urban = item.getLandCoverFract(LandCoverType.URBAN); - landCoverWriter.write(String.format("%.2f %.2f %d %.14f %.14f %.14f %.14f %.14f", lat, lon, year, crop, pasture, (forest+otherNatural), barren, urban)); + landCoverWriter.write(String.format("%.2f %.2f %d %.14f %.14f %.14f %.14f %.14f", lat, lon, year, crop, pasture, timberForest, carbonForest, otherNatural, barren, urban)); landCoverWriter.newLine(); } } diff --git a/src/ac/ed/lurg/shock/ExportRestrictionManager.java b/src/ac/ed/lurg/shock/ExportRestrictionManager.java index e9b808b7ff207f0604f27fa55b7d7bf28c6288b3..de7d3d56f5a22152eaf30096e9a36a2c61c71714 100644 --- a/src/ac/ed/lurg/shock/ExportRestrictionManager.java +++ b/src/ac/ed/lurg/shock/ExportRestrictionManager.java @@ -6,9 +6,9 @@ import java.util.List; import java.util.Map; import ac.ed.lurg.ModelConfig; -import ac.ed.lurg.Timestep; import ac.ed.lurg.country.CompositeCountry; import ac.ed.lurg.types.CropType; +import ac.ed.lurg.utils.LazyHashMap; import ac.ed.lurg.utils.LogWriter; import ac.ed.lurg.utils.StringTabularReader; @@ -18,7 +18,7 @@ public class ExportRestrictionManager { public ExportRestrictionManager() { String shockFile = ModelConfig.EXPORT_RESTRICTIONS_FILE; - exportShockReader = new StringTabularReader(",", new String[]{"year", "country", "crop", "shockFactor"}); + exportShockReader = new StringTabularReader(",", new String[]{"year", "compositeCountry", "crop", "shockFactor"}); if (new File(shockFile).isFile()) exportShockReader.read(shockFile); @@ -26,24 +26,33 @@ public class ExportRestrictionManager { LogWriter.println("Can't find a export shock file (" +shockFile + "), so will not apply export restriction"); } - public Map<CropType, Double> getShocksForCountry(Timestep timestep, CompositeCountry cc) { - Map<CropType, Double> shocks = new HashMap<CropType, Double>(); - + @SuppressWarnings("serial") + public Map<Integer, Map<CropType, Double>> getShocksForCountry(CompositeCountry cc) { Map<String, String> queryMap = new HashMap<String, String>(); - queryMap.put("year", Integer.toString(timestep.getYear())); - queryMap.put("country", cc.getName()); - + queryMap.put("compositeCountry", cc.getName()); List<Map<String, String>> rows = exportShockReader.query(queryMap); - for (Map<String, String> row : rows) { - String cropTypeS = row.get("crop"); - String shockFactorS = row.get("shockFactor"); - CropType crop = CropType.getForFaoName(cropTypeS); - Double shockFactor = Double.valueOf(shockFactorS); - - LogWriter.println("Got export shock at " + timestep + ": " + cc.getName() + " " + cropTypeS + " " + shockFactorS); - - shocks.put(crop, shockFactor); + LazyHashMap<Integer, Map<CropType, Double>> shocks = null; + + if (rows.size() > 0) { + shocks = new LazyHashMap<Integer, Map<CropType, Double>>() { + protected Map<CropType, Double> createValue() { return new HashMap<CropType, Double>(); } + }; + + for (Map<String, String> row : rows) { + String cropTypeS = row.get("crop"); + String shockFactorS = row.get("shockFactor"); + String yearS = row.get("year"); + LogWriter.println("Got export shock " + cc.getName() + " : " + yearS + " " + cropTypeS + " " + shockFactorS); + + CropType crop = CropType.getForGamsName(cropTypeS); + Double shockFactor = Double.valueOf(shockFactorS); + Integer year = Integer.valueOf(yearS); + + Map<CropType, Double> shocksCC = shocks.lazyGet(year); + shocksCC.put(crop, shockFactor); + } } + return shocks; } } \ No newline at end of file diff --git a/src/ac/ed/lurg/shock/MinMaxNetImportManager.java b/src/ac/ed/lurg/shock/MinMaxNetImportManager.java new file mode 100644 index 0000000000000000000000000000000000000000..0c4fda65de6ba143d3ae56687a34bcb42f4fecfb --- /dev/null +++ b/src/ac/ed/lurg/shock/MinMaxNetImportManager.java @@ -0,0 +1,89 @@ +package ac.ed.lurg.shock; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import ac.ed.lurg.ModelConfig; +import ac.ed.lurg.country.CompositeCountry; +import ac.ed.lurg.types.CropType; +import ac.ed.lurg.utils.LazyHashMap; +import ac.ed.lurg.utils.LogWriter; +import ac.ed.lurg.utils.StringTabularReader; + +public class MinMaxNetImportManager { + private StringTabularReader minMaxTradeReader; + + public enum LimitType { + MIN_LIMIT_TYPE("min"), + MAX_LIMIT_TYPE("max"); + + private String limitType; + + LimitType(String limitType) { + this.limitType = limitType; + } + + public static LimitType findByName(String str){ + for(LimitType p : values()){ + if( p.limitType.equals(str)){ + return p; + } + } + + LogWriter.printlnError("No LimitType found for " + str); + return null; + } + } + + public MinMaxNetImportManager() { + + String fileName = ModelConfig.MIN_MAX_TRADE_FILE; + minMaxTradeReader = new StringTabularReader(",", new String[]{"year", "compositeCountry", "crop", "limitType", "netImportValue"}); + + if (new File(fileName).isFile()) + minMaxTradeReader.read(fileName); + else + LogWriter.println("Can't find a min_max_trade file (" +fileName + "), so will not apply trade limits."); + } + + @SuppressWarnings("serial") + public Map<Integer, Map<LimitType, Map<CropType, Double>>> getMinMaxNetImportForCountry(CompositeCountry cc) { + Map<String, String> queryMap = new HashMap<String, String>(); + queryMap.put("compositeCountry", cc.getName()); + + List<Map<String, String>> rows = minMaxTradeReader.query(queryMap); + LazyHashMap<Integer, Map<LimitType, Map<CropType, Double>>> tradeLimits = null; + + if (rows.size() > 0) { + tradeLimits = new LazyHashMap<Integer, Map<LimitType, Map<CropType, Double>>>() { + protected Map<LimitType, Map<CropType, Double>> createValue() { + Map<LimitType, Map<CropType, Double>> theMap = new HashMap<LimitType, Map<CropType, Double>>(); + theMap.put(LimitType.MIN_LIMIT_TYPE, new HashMap<CropType, Double>()); + theMap.put(LimitType.MAX_LIMIT_TYPE, new HashMap<CropType, Double>()); + return theMap; + } + }; + + for (Map<String, String> row : rows) { + String cropTypeS = row.get("crop"); + String netImportValueS = row.get("netImportValue"); + String yearS = row.get("year"); + String limitTypeS = row.get("limitType"); + LogWriter.println("Got export " + limitTypeS + " trade limit " + cc.getName() + " : " + yearS + " " + cropTypeS + " " + netImportValueS); + + CropType crop = CropType.getForGamsName(cropTypeS); + Double netImportValue = Double.valueOf(netImportValueS); + Integer year = Integer.valueOf(yearS); + LimitType limitType = LimitType.findByName(limitTypeS); + + Map<LimitType, Map<CropType, Double>> minMaxlimits = tradeLimits.lazyGet(year); + Map<CropType, Double> limits = minMaxlimits.get(limitType); + limits.put(crop, netImportValue); + } + } + + return tradeLimits; + } +} \ No newline at end of file diff --git a/src/ac/ed/lurg/types/CommodityType.java b/src/ac/ed/lurg/types/CommodityType.java index 5c3b8e5e282866cd2c1bd8561498dc9f74ce824d..15dd1da8eced826397aec6c7b596319e73bd5481 100644 --- a/src/ac/ed/lurg/types/CommodityType.java +++ b/src/ac/ed/lurg/types/CommodityType.java @@ -12,34 +12,32 @@ public enum CommodityType { //processedFull$cb_fs[is.na(fcr) & Country=="World" & Year == 2010, list(energy=sum(energy_kcal_pc*365/1000000*country_data[Country=="World" & Year == 2010]$population, na.rm=TRUE), food=sum(food)), by="plumDemandItem"][, list(plumDemandItem, energy/food)] //processedFull$cb_fs[!is.na(fcr) & Country=="World" & Year == 2010, list(energy=sum(energy_kcal_pc*365/1000000*country_data[Country=="World" & Year == 2010]$population, na.rm=TRUE), food=sum(food*fcr)), by="plumDemandItem"][, list(plumDemandItem, energy/food)] - CEREALS("Cereals", "cereals", false, new CropType[]{CropType.WHEAT, CropType.MAIZE, CropType.RICE}, new Double[]{0.385, 0.171, 0.444}, ModelConfig.CEREALS_SUB_PROPORTION, ModelConfig.INITAL_DEMAND_PRICE_CEREALS, 409.0), - OILCROPSPULSES("OilcropsPulses", "oilcropspulses", false, new CropType[]{CropType.OILCROPS, CropType.PULSES}, new Double[]{0.815, 0.185}, ModelConfig.OILCROPSPULSES_SUB_PROPORTION, ModelConfig.INITAL_DEMAND_PRICE_OILCROPS_PULSES, 23.0), - STARCHY_ROOTS("Starchy Roots", "starchyRoots", false, new CropType[]{CropType.STARCHY_ROOTS}, new Double[]{1.0}, ModelConfig.STARCHY_ROOTS_SUB_PROPORTION, ModelConfig.INITAL_DEMAND_PRICE_STARCHYROOTS, 14.0), - MONOGASTRICS("Monogastrics", "monogastrics", true, new CropType[]{CropType.MONOGASTRICS}, new Double[]{1.0}, Double.NaN, ModelConfig.INITAL_DEMAND_PRICE_MONOGASTRICS, 3.0), - RUMINANTS("Ruminants", "ruminants", true, new CropType[]{CropType.RUMINANTS}, new Double[]{1.0}, Double.NaN, ModelConfig.INITAL_DEMAND_PRICE_RUMINANTS, 20.0), - FRUITVEG("FruitVeg", "fruitveg", false, new CropType[]{CropType.FRUITVEG}, new Double[]{1.0}, ModelConfig.FRUITVEG_SUB_PROPORTION, ModelConfig.INITAL_DEMAND_PRICE_FRUITVEG, 21.0), - SUGAR("Sugar", "sugar", false, new CropType[]{CropType.SUGAR}, new Double[]{1.0}, ModelConfig.SUGAR_SUB_PROPORTION, ModelConfig.INITAL_DEMAND_PRICE_SUGAR, 35.0), - NONFOOD("Nonfood", "nonfood", false, new CropType[]{}, new Double[]{}, Double.NaN, Double.NaN, 0.0); + CEREALS("Cereals", "cereals", false, new CropType[]{CropType.WHEAT, CropType.MAIZE, CropType.RICE}, new Double[]{0.385, 0.171, 0.444}, ModelConfig.INITAL_DEMAND_PRICE_CEREALS, 409.0), + OILCROPSPULSES("OilcropsPulses", "oilcropspulses", false, new CropType[]{CropType.OILCROPS, CropType.PULSES}, new Double[]{0.815, 0.185}, ModelConfig.INITAL_DEMAND_PRICE_OILCROPS_PULSES, 23.0), + STARCHY_ROOTS("Starchy Roots", "starchyRoots", false, new CropType[]{CropType.STARCHY_ROOTS}, new Double[]{1.0}, ModelConfig.INITAL_DEMAND_PRICE_STARCHYROOTS, 14.0), + MONOGASTRICS("Monogastrics", "monogastrics", true, new CropType[]{CropType.MONOGASTRICS}, new Double[]{1.0}, ModelConfig.INITAL_DEMAND_PRICE_MONOGASTRICS, 3.0), + RUMINANTS("Ruminants", "ruminants", true, new CropType[]{CropType.RUMINANTS}, new Double[]{1.0}, ModelConfig.INITAL_DEMAND_PRICE_RUMINANTS, 20.0), + FRUITVEG("FruitVeg", "fruitveg", false, new CropType[]{CropType.FRUITVEG}, new Double[]{1.0}, ModelConfig.INITAL_DEMAND_PRICE_FRUITVEG, 21.0), + SUGAR("Sugar", "sugar", false, new CropType[]{CropType.SUGAR}, new Double[]{1.0}, ModelConfig.INITAL_DEMAND_PRICE_SUGAR, 35.0), + NONFOOD("Nonfood", "nonfood", false, new CropType[]{}, new Double[]{}, Double.NaN, 0.0); private String faoName; private String gamsName; private boolean isAnimalProduct; private Collection<CropType> cropTypes; - private double meatSubstitutionProportion; private double initialPrice; private double minFAOCalorieIntake; - + CommodityType (String faoName, String gamsName, boolean isAnimalProduct, CropType[] cropTypeMapping, Double[] defaultDemandFract, - double meatSubstitutionProportion, double initialPrice, double minFAOCalorieIntake) { + double initialPrice, double minFAOCalorieIntake) { this.faoName = faoName; this.gamsName = gamsName; this.isAnimalProduct = isAnimalProduct; this.cropTypes = Arrays.asList(cropTypeMapping); - this.meatSubstitutionProportion = meatSubstitutionProportion; this.initialPrice = initialPrice; this.minFAOCalorieIntake = minFAOCalorieIntake; } - + private static final Map<String, CommodityType> faoNameCache = new HashMap<String, CommodityType>(); private static final Map<String, CommodityType> gamsNameCache = new HashMap<String, CommodityType>(); private static final Collection<CommodityType> foodsToConsider = new HashSet<CommodityType>(); @@ -47,7 +45,7 @@ public enum CommodityType { for (CommodityType c : values()) { faoNameCache.put(c.getFaoName(), c); gamsNameCache.put(c.getGamsName(), c); - + if (!c.equals(NONFOOD)) foodsToConsider.add(c); } @@ -58,23 +56,23 @@ public enum CommodityType { if (commodity == null) throw new RuntimeException("Can't find CommodityType for faoName: " + faoName); - + return commodity; } - + public static CommodityType getForGamsName(String gamsName) { return getForGamsName(gamsName, false); } - + public static CommodityType getForGamsName(String gamsName, boolean allowNulls) { CommodityType commodity = gamsNameCache.get(gamsName); if (commodity == null & !allowNulls) throw new RuntimeException("Can't find CommodityType for gamsName: " + gamsName); - + return commodity; } - + public static Collection<CommodityType> getAllFoodItems() { return foodsToConsider; } @@ -82,7 +80,7 @@ public enum CommodityType { public String getFaoName() { return faoName; } - + public String getGamsName() { return gamsName; } @@ -90,19 +88,15 @@ public enum CommodityType { public boolean isAnimalProduct() { return isAnimalProduct; } - - public double getMeatSubstitutionProportion(){ - return meatSubstitutionProportion; - } - + public Collection<CropType> getCropTypes(){ return cropTypes; } - + public double getDefaultInitialPrice() { return initialPrice; } - + public double getMinFAOCalorieIntake() { return minFAOCalorieIntake; } diff --git a/src/ac/ed/lurg/types/ForestType.java b/src/ac/ed/lurg/types/ForestType.java deleted file mode 100644 index e591ca244a403ede79d387676668e9ad4373ba75..0000000000000000000000000000000000000000 --- a/src/ac/ed/lurg/types/ForestType.java +++ /dev/null @@ -1,16 +0,0 @@ -package ac.ed.lurg.types; - -public enum ForestType { - TIMBER_FOREST("timberForest"), - CARBON_FOREST("carbonForest"); - - private String name; - - ForestType(String name) { - this.name = name; - } - - public String getName() { - return name; - } -} diff --git a/src/ac/ed/lurg/types/GamsLandCoverType.java b/src/ac/ed/lurg/types/GamsLandCoverType.java deleted file mode 100644 index d656e10b2d8087b137e1ecf2063c29afaf46c8b2..0000000000000000000000000000000000000000 --- a/src/ac/ed/lurg/types/GamsLandCoverType.java +++ /dev/null @@ -1,45 +0,0 @@ -package ac.ed.lurg.types; - -import java.util.HashMap; -import java.util.Map; - -import ac.ed.lurg.utils.LogWriter; - -public enum GamsLandCoverType { - TIMBER_FOREST("timberForest"), - CARBON_FOREST("carbonForest"), - NATURAL("natural"), - PASTURE("pasture"), - CROPLAND("cropland"); - - private String name; - - GamsLandCoverType(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - private static final Map<String, GamsLandCoverType> nameCache = new HashMap<String, GamsLandCoverType>(); - static { - for (GamsLandCoverType c : values()) { - nameCache.put(c.getName(), c); - } - } - - private static GamsLandCoverType getFromCache(Map<String, GamsLandCoverType> cache, String name) { - GamsLandCoverType type = cache.get(name); - - if (type == null) - LogWriter.printlnError("Can't find Item for " + name); - - return type; - } - - public static GamsLandCoverType getForName(String name) { - return getFromCache(nameCache, name); - } -} - diff --git a/src/ac/ed/lurg/types/NonCropType.java b/src/ac/ed/lurg/types/NonCropType.java deleted file mode 100644 index ad5f9a6dc209daea30c1f75ce516b28a0e0140b7..0000000000000000000000000000000000000000 --- a/src/ac/ed/lurg/types/NonCropType.java +++ /dev/null @@ -1,53 +0,0 @@ -package ac.ed.lurg.types; - -import java.util.Collection; -import java.util.HashSet; - -public enum NonCropType { - TIMBER_FOREST("timberForest", true, true), - CARBON_FOREST("carbonForest", true, true), - NATURAL("natural", true, false); - - private String gamsName; - private boolean isWoodProducing; - private boolean isManagedForest; - - private NonCropType (String gamsName, boolean isWoodProducing, boolean isManagedForest) { - this.gamsName = gamsName; - this.isWoodProducing = isWoodProducing; - this.isManagedForest = isManagedForest; - } - - public String getGamsName() { - return gamsName; - } - - public boolean isWoodProducing() { - return isWoodProducing; - } - - public boolean isManagedForest() { - return isManagedForest; - } - - public static Collection<NonCropType> getWoodProducingTypes() { - Collection<NonCropType> lu = new HashSet<NonCropType>(); - - for (NonCropType c : values()) - if (c.isWoodProducing) - lu.add(c); - - return lu; - } - - public static Collection<NonCropType> getManagedForestTypes() { - Collection<NonCropType> lu = new HashSet<NonCropType>(); - - for (NonCropType c : values()) - if (c.isManagedForest) - lu.add(c); - - return lu; - } - -} diff --git a/src/ac/ed/lurg/types/WoodType.java b/src/ac/ed/lurg/types/WoodType.java index a840707636a1e31694ead55eeb82b6978e348293..e32c8dee2db391488ecf26208588cffe77f90899 100644 --- a/src/ac/ed/lurg/types/WoodType.java +++ b/src/ac/ed/lurg/types/WoodType.java @@ -5,7 +5,7 @@ import java.util.Map; import ac.ed.lurg.ModelConfig; public enum WoodType { - ROUNDWOOD("roundwood", ModelConfig.IND_ROUNDWOOD_DEMAND_ELASTICITY), + IND_ROUNDWOOD("roundwood", ModelConfig.IND_ROUNDWOOD_DEMAND_ELASTICITY), FUELWOOD("fuelwood", ModelConfig.FUELWOOD_DEMAND_ELASTICITY); private String name; diff --git a/src/ac/ed/lurg/utils/BilinearInterpolator.java b/src/ac/ed/lurg/utils/BilinearInterpolator.java deleted file mode 100644 index bbe4b68144133845e7064e58e540e5030f52818a..0000000000000000000000000000000000000000 --- a/src/ac/ed/lurg/utils/BilinearInterpolator.java +++ /dev/null @@ -1,22 +0,0 @@ -package ac.ed.lurg.utils; - -public final class BilinearInterpolator { - /* - * coordinates to interpolate (x, y) - * known values q11 = f(x1, y1), q12 = f(x1, y2), q21 = f(x2, y1), q22 = f(x2, y2) - */ - public static double interpolate(double x, double y, double x1, double x2, double y1, double y2, double q11, double q12, double q21, double q22) { - double fxy1 = ((x2 - x) / (x2 - x1)) * q11 + ((x - x1) / (x2 - x1)) * q21; - double fxy2 = ((x2 - x) / (x2 - x1)) * q12 + ((x - x1) / (x2 - x1)) * q22; - double fxy = ((y2 - y) / (y2 - y1)) * fxy1 + ((y - y1) / (y2 - y1)) * fxy2; - return fxy; - } - - // Version with integer coordinates - public static double interpolate(int x, int y, int x1, int x2, int y1, int y2, double q11, double q12, double q21, double q22) { - double fxy1 = ((x2 - x) / (x2 - x1)) * q11 + ((x - x1) / (x2 - x1)) * q21; - double fxy2 = ((x2 - x) / (x2 - x1)) * q12 + ((x - x1) / (x2 - x1)) * q22; - double fxy = ((y2 - y) / (y2 - y1)) * fxy1 + ((y - y1) / (y2 - y1)) * fxy2; - return fxy; - } -} diff --git a/src/ac/ed/lurg/utils/DoubleMap.java b/src/ac/ed/lurg/utils/DoubleMap.java deleted file mode 100644 index ed3a2d10be74dfa30eaa26671bd942d8c1a905a8..0000000000000000000000000000000000000000 --- a/src/ac/ed/lurg/utils/DoubleMap.java +++ /dev/null @@ -1,56 +0,0 @@ -package ac.ed.lurg.utils; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -public class DoubleMap<K, L, V> implements Serializable { - private static final long serialVersionUID = 309214428660247740L; - - // Stores a double mapped by two consecutive keys - private Map<K, Map<L, Double>> theMap; - - public DoubleMap() { - this.theMap = new HashMap<K, Map<L, Double>>(); - } - - public void put(K key1, L key2, double value) { - if (theMap.containsKey(key1)) { // check if inner map already exists - theMap.get(key1).put(key2, value); // adds new entry or overwrites existing if exists - } else { // add new complete entry - Map<L, Double> innerMap = new HashMap<L, Double>(); - innerMap.put(key2, value); - theMap.put(key1, innerMap); - } - } - - public Double get(K key1, L key2) { - if (theMap.containsKey(key1)) { // check if first key exits - return theMap.get(key1).get(key2); // will return null if second key doesn't exist - } else { - return null; // will return null if first key doesn't exist - } - } - - public Map<L, Double> getInnerMap(K key) { - return theMap.get(key); - - } - - public Map<K, Map<L, Double>> getMap() { - return theMap; - } - - public void addTo(K key1, L key2, double value) { - if (theMap.containsKey(key1)) { - if (theMap.get(key1).containsKey(key2)) { - double current = get(key1, key2); - put(key1, key2, current + value); - } else { - theMap.get(key1).put(key2, value); - } - } else { - put(key1, key2, value); - } - } -} diff --git a/src/ac/ed/lurg/utils/DualKey.java b/src/ac/ed/lurg/utils/DualKey.java deleted file mode 100644 index 0841eaedc6dfedaf090e18b673c16f2100e5849a..0000000000000000000000000000000000000000 --- a/src/ac/ed/lurg/utils/DualKey.java +++ /dev/null @@ -1,43 +0,0 @@ -package ac.ed.lurg.utils; - -public class DualKey<K, Q> { - private K key1; - private Q key2; - - public DualKey(K key1, Q key2) { - this.key1 = key1; - this.key2 = key2; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((key1 == null) ? 0 : key1.hashCode()); - result = prime * result + ((key2 == null) ? 0 : key2.hashCode()); - return result; - } - - @SuppressWarnings("unchecked") - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - DualKey<K, Q> other = (DualKey<K, Q>) obj; - if (key1 == null) { - if (other.key1 != null) - return false; - } else if (!key1.equals(other.key1)) - return false; - if (key2 == null) { - if (other.key2 != null) - return false; - } else if (!key2.equals(other.key2)) - return false; - return true; - } -} diff --git a/src/ac/ed/lurg/utils/TripleMap.java b/src/ac/ed/lurg/utils/TripleMap.java deleted file mode 100644 index aa9e32dd959b704fe0451ffd039390b1641aecce..0000000000000000000000000000000000000000 --- a/src/ac/ed/lurg/utils/TripleMap.java +++ /dev/null @@ -1,40 +0,0 @@ -package ac.ed.lurg.utils; - -import java.util.HashMap; -import java.util.Map; - -public class TripleMap<K, L, M, V> { - - private Map<K, DoubleMap<L, M, V >> theMap = new HashMap<K, DoubleMap<L, M, V>>(); - - public TripleMap() { - - } - - public void put(K key1, L key2, M key3, double value) { - if (theMap.containsKey(key1)) { - theMap.get(key1).put(key2, key3, value); - } else { - DoubleMap<L, M, V> innerMap = new DoubleMap<L, M, V>(); - innerMap.put(key2, key3, value); - theMap.put(key1, innerMap); - } - } - - public Double get(K key1, L key2, M key3) { - if (theMap.containsKey(key1)) { - return theMap.get(key1).get(key2, key3); - } else { - return null; - } - } - - public DoubleMap<L, M, V> getInnerMap(K key) { - return theMap.get(key); - - } - - public Map<K, DoubleMap<L, M, V >> getMap() { - return theMap; - } -} diff --git a/src/ac/ed/lurg/yield/YieldClusterPoint.java b/src/ac/ed/lurg/yield/YieldClusterPoint.java index 75943f0479f3bd33d36da3413b562fb459addc10..710e9ce7fcea4eb9690944ebf5b4d2abd44467a9 100644 --- a/src/ac/ed/lurg/yield/YieldClusterPoint.java +++ b/src/ac/ed/lurg/yield/YieldClusterPoint.java @@ -40,7 +40,7 @@ public class YieldClusterPoint implements ClusteringPoint<String> { this.pasture = yields.getYield(YieldType.NO_FERT_NO_IRRIG, CropType.PASTURE); this.wheatMax = yields.getYield(YieldType.FERT_MAX_IRRIG_MAX, CropType.WHEAT); this.maizeMax = yields.getYield(YieldType.FERT_MAX_IRRIG_MAX, CropType.MAIZE); - this.irrigWaterAval = irrigItem.getIrrigConstraint(); + this.irrigWaterAval = (irrigItem==null) ? 0.0 :irrigItem.getIrrigConstraint(); this.protectedArea = protectedArea; }