diff --git a/GAMS/IntExtOpt.gms b/GAMS/IntExtOpt.gms index 5b1afba8e6e4934fdf665400f145627b629e0dce..ec4b52772d7201aa8ae46d395d4a1d04af5c8526 100644 --- a/GAMS/IntExtOpt.gms +++ b/GAMS/IntExtOpt.gms @@ -36,7 +36,7 @@ PARAMETER importPrices(import_crop) prices for imports; PARAMETER maxNetImport(import_crop) maximum net import for each crop based on world market; PARAMETER minNetImport(import_crop) minimum net import for each crop based on world market; - PARAMETER irrigCost(location) irrigation cost in cost per 1000 Mlitre or Mha for each litre per m2; + PARAMETER irrigCost(location) irrigation cost in cost per 1000 Mlitre or Mha for each litre per m2; PARAMETER irrigMaxRate(crop, location) max water application rate irrigation in litre per m2; PARAMETER irrigConstraint(location) max water available for irrigation in litre per m2; PARAMETER minDemandPerCereal(cereal_crop) min demand for each cereal crop as factor of all cereals; @@ -44,11 +44,11 @@ PARAMETER seedAndWasteRate(all_types) rate of use for seed and waste combined; PARAMETER subsidyRate(crop) 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; - SCALAR cropIncCost price for increasing crop; - SCALAR cropDecCost price for decreasing crop; - SCALAR pastureDecCost price for decreasing pasture; + PARAMETER agriExpansionCost(location) price for increase agricultural area varies based on amount of managed or unmanaged forest - 1000$ per ha; + SCALAR pastureIncCost price for increasing pasture area - 1000$ per ha; + SCALAR cropIncCost price for increasing crop - 1000$ per ha; + SCALAR cropDecCost price for decreasing crop - 1000$ per ha; + SCALAR pastureDecCost price for decreasing pasture - 1000$ per ha; SCALAR meatEfficency efficiency of converting feed and pasture into animal products; SCALAR fertiliserUnitCost fert cost at max fert rate; @@ -61,10 +61,10 @@ PARAMETER previousLandCoverArea(land_cover, location) land cover area in Mha; * PARAMETER minimumLandCoverArea(land_cover, location) minimum land cover area to constrain conversion; - PARAMETER carbonFluxRate(land_cover_before, land_cover_after, location) carbon flux; - PARAMETER woodYield(land_cover_before, land_cover_after, location) wood yield; - SCALAR carbonPrice price of carbon; - SCALAR woodPrice price of wood and timber; + PARAMETER carbonFluxRate(land_cover_before, land_cover_after, location) carbon flux - MtC-eq per Mha; + PARAMETER woodYield(land_cover_before, land_cover_after, location) wood yield - MtC-eq per Mha; + SCALAR carbonPrice price of carbon - $ per tonne or million$ per Mt; + SCALAR woodPrice price of wood and timber - $ per tonne or million$ per Mt; *$gdxin "C:\Users\Bart\Documents\PhD\GAMS testing area\_gams_java_gdb1.gdx" $gdxin %gdxincname% @@ -77,9 +77,22 @@ $load previousLandCoverArea, carbonFluxRate, woodYield, carbonPrice, woodPrice *$load minimumLandCoverArea $gdxin -* need to convert from $/kg to $/Mt - carbonPrice = carbonPrice * 0.01; - woodPrice = woodPrice * 0.01; +* convert units from $/t to billion$/Mt + carbonPrice = carbonPrice * 0.001; + woodPrice = woodPrice * 0.001; + +* convert units from 1000$/ha to million$/Mha +* agriExpansionCost(location) = agriExpansionCost(location) * 1000; +* pastureIncCost = pastureIncCost * 1000; +* cropIncCost = cropIncCost * 1000; +* cropDecCost = cropDecCost * 1000; +* pastureDecCost = pastureDecCost * 1000; + +* covert units from 1000$/t to million$/Mt +* exportPrices(import_crop) = exportPrices(import_crop) * 1000; +* importPrices(import_crop) = importPrices(import_crop) * 1000; + + SCALAR delta use to smooth power function see 7.5 www.gams.com dd docs solversconopt.pdf / 0.00000000001 /; @@ -149,8 +162,8 @@ $gdxin landCoverArea, landCoverChange, woodHarvest; EQUATIONS - UNIT_COST_EQ(crop, location) cost per area - YIELD_EQ(crop, location) yield given chosen intensity + UNIT_COST_EQ(crop, location) cost per area - million$ per Mha + YIELD_EQ(crop, location) yield given chosen intensity - tonnes per hectare CROP_DEMAND_CONSTRAINT(crop) satisfy demand for individual crops TOTAL_CEREAL_DEMAND_CONSTRAINT satisfy demand for combined cereals TOTAL_OIL_PULSE_DEMAND_CONSTRAINT satisfy demand for combined oilcrops and pulses @@ -178,7 +191,6 @@ $gdxin CROPLAND_LAND_COVER_CALC(location) cropland area equals sum of all crop areas PASTURE_LAND_COVER_CALC(location) pasture area (land cover) equals pasture area (land use) * MINIMUM_LAND_COVER_CONSTRAINT(location) constraint on land cover conversion -* TOTAL_LAND_COVER_CONSTRAINT(location) total land cover equals suitable area LAND_COVER_CHANGE_CALC(land_cover, location) LAND_COVER_CHANGE_CONSTRAINT(land_cover, location) LAND_COVER_SELF_CHANGE_CONSTRAINT(land_cover, location) @@ -190,7 +202,7 @@ $gdxin fertiliserUnitCost * fertI(crop, location) + irrigCost(location) * irrigMaxRate(crop, location) * irrigI(crop, location) + otherIntCost(crop) * otherIntensity(crop, location) - ) ; + ); YIELD_EQ(crop, location) .. yield(crop, location) =E= ( yieldNone(crop, location) + @@ -251,8 +263,6 @@ $gdxin LAND_COVER_SELF_CHANGE_CONSTRAINT(land_cover, location) .. landCoverChange(land_cover, land_cover, location) =E= 0; -* TOTAL_LAND_COVER_CONSTRAINT(location) .. sum(land_cover, landCoverArea(land_cover, location)) =E= suitableLandArea(location); - WOOD_HARVEST_CALC(location) .. woodHarvest(location) =E= sum((land_cover_before, land_cover_after), landCoverChange(land_cover_before, land_cover_after, location) * woodYield(land_cover_before, land_cover_after, location)); CARBON_FLUX_CALC(location) .. carbonFlux(location) =E= sum((land_cover_before, land_cover_after), landCoverChange(land_cover_before, land_cover_after, location) * carbonFluxRate(land_cover_before, land_cover_after, location)); diff --git a/debug_config.properties b/debug_config.properties index a59915593399115739bbf169389cc39e26bfb4eb..c161ff3a4daf04abe5e0566aa3d4a3d142b82c6b 100644 --- a/debug_config.properties +++ b/debug_config.properties @@ -1,24 +1,22 @@ -BASE_DIR=.. +BASE_DIR=C:/Users/Bart/git/plumv2 -YIELD_DIR=/Users/palexand/Documents/LURG/LPJ/LPJGPLUM_remap6p7_20190225/rcp26 +YIELD_DIR=C:/Users/Bart/Documents/PhD/LURG/rcp60 -END_TIMESTEP=0 +OUTPUT_DIR = C:/Users/Bart/git/plumv2/output + +END_TIMESTEP=10 END_FIRST_STAGE_CALIBRATION=10 TIMESTEP_SIZE=1 IS_CALIBRATION_RUN=true -DEBUG_JUST_DEMAND_OUTPUT=true -GENERATE_NEW_YIELD_CLUSTERS=false +GENERATE_NEW_YIELD_CLUSTERS=true -DEMAND_PRICE_IMPORT_AND_PROD_COST=true +DEMAND_PRICE_IMPORT_AND_PROD_COST=false -EXTRAPOLATE_YIELD_FERT_RESPONSE=false +YIELD_FILENAME=yield.out DEBUG_LIMIT_COUNTRIES=false -DEBUG_COUNTRY_NAME=Italy - -ADJUST_DIET_PREFS=true - -TARGET_DIET_FILE=/Users/palexand/Downloads/Tau_diet.csv \ No newline at end of file +DEBUG_COUNTRY_NAME=Peru & Ecuador +GAMS_COUNTRY_TO_SAVE=Peru & Ecuador \ No newline at end of file diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java index d8f42418536952d2ca5aa3093940e213cb134257..c33525081df0405ab433b74521c38ecda6201833 100755 --- a/src/ac/ed/lurg/ModelConfig.java +++ b/src/ac/ed/lurg/ModelConfig.java @@ -423,7 +423,7 @@ public class ModelConfig { public static final String TARGET_DIET_FILE = getProperty("TARGET_DIET_FILE", DATA_DIR + File.separator + "TargetDiet.txt"); // Forestry parameters - public static final double CARBON_PRICE = getDoubleProperty("CARBON_PRICE", 20.0); // $/tC - public static final double WOOD_PRICE = getDoubleProperty("WOOD_PRICE", 0.175); // $/tC + public static final double CARBON_PRICE = getDoubleProperty("CARBON_PRICE", 10.0); // $/tC-eq + public static final double WOOD_PRICE = getDoubleProperty("WOOD_PRICE", 50.0); // $/tC-eq } diff --git a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java index 9f1d7b93f060c0ddef00a0288a924e1a1d5f27f6..26eaa91fa082a1d09e1c95647206adbd35cbd0fa 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java @@ -38,6 +38,7 @@ import ac.ed.lurg.types.Parameter; import ac.ed.lurg.types.YieldType; import ac.ed.lurg.utils.LazyHashMap; import ac.ed.lurg.utils.LogWriter; +import ac.ed.lurg.utils.TripleMap; import ac.ed.lurg.yield.YieldResponsesItem; public class GamsLocationOptimiser { @@ -74,6 +75,9 @@ public class GamsLocationOptimiser { long startTime = System.currentTimeMillis(); gamsJob.run(opt, inDB); + if (inputData.getCountryInput().getCountry().getName().equals("Peru & Ecuador")) + LogWriter.println("" + inputData.getPreviousLandUse().get(2).getUnprotectedLandCoverArea(LandCoverType.CROPLAND)); + if (ModelConfig.CLEANUP_GAMS_DIR) cleanup(ws.workingDirectory()); @@ -560,7 +564,7 @@ public class GamsLocationOptimiser { // Land cover change GAMSVariable varLandCoverChange = outDB.getVariable("landCoverChange"); - LandCoverChangeItem landCoverChange = new LandCoverChangeItem(); + TripleMap<Integer, LandCoverType, LandCoverType, Double> landCoverChanges = new TripleMap<Integer, LandCoverType, LandCoverType, Double>(); for (GAMSVariableRecord rec : varLandCoverChange) { @@ -577,19 +581,20 @@ public class GamsLocationOptimiser { if (fromLC.equals("natural")) { double prevUnmanagedForestProp = getPrevUnmanagedForestProp(locId); - landCoverChange.setLandCoverChange(LandCoverType.UNMANAGED_FOREST, LandCoverType.getForName(toLC), locId, change * prevUnmanagedForestProp); - landCoverChange.setLandCoverChange(LandCoverType.OTHER_NATURAL, LandCoverType.getForName(toLC), locId, change * (1 - prevUnmanagedForestProp)); + landCoverChanges.put(locId, LandCoverType.UNMANAGED_FOREST, LandCoverType.getForName(toLC), change * prevUnmanagedForestProp); + landCoverChanges.put(locId, LandCoverType.OTHER_NATURAL, LandCoverType.getForName(toLC), change * (1 - prevUnmanagedForestProp)); } else if (toLC.equals("natural")) { double prevUnmanagedForestProp = getPrevUnmanagedForestProp(locId); - landCoverChange.setLandCoverChange(LandCoverType.getForName(fromLC), LandCoverType.UNMANAGED_FOREST, locId, change * prevUnmanagedForestProp); - landCoverChange.setLandCoverChange(LandCoverType.getForName(fromLC), LandCoverType.OTHER_NATURAL, locId, change * (1 - prevUnmanagedForestProp)); + landCoverChanges.put(locId, LandCoverType.getForName(fromLC), LandCoverType.UNMANAGED_FOREST, change * prevUnmanagedForestProp); + landCoverChanges.put(locId, LandCoverType.getForName(fromLC), LandCoverType.OTHER_NATURAL, change * (1 - prevUnmanagedForestProp)); } else { - landCoverChange.setLandCoverChange(LandCoverType.getForName(fromLC), LandCoverType.getForName(toLC), locId, change); + landCoverChanges.put(locId, LandCoverType.getForName(fromLC), LandCoverType.getForName(toLC), change); } + // Potential case where fromLC = natural and toLC = natural unaccounted for but should never happen due to GAMS constraint (LAND_COVER_SELF_CHANGE_CONTRAINT). } - GamsLocationOutput results = new GamsLocationOutput(modelStatus, landUses, cropUsageData, landCoverChange); + GamsLocationOutput results = new GamsLocationOutput(modelStatus, landUses, cropUsageData, landCoverChanges); return results; } diff --git a/src/ac/ed/lurg/country/gams/GamsLocationOutput.java b/src/ac/ed/lurg/country/gams/GamsLocationOutput.java index b64a6d6ddb97826f6f64313cd44e042fe22a8f8b..258064949b97f96c58357e0115a45fdea64f659d 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationOutput.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationOutput.java @@ -5,26 +5,29 @@ import java.util.Map; import com.gams.api.GAMSGlobals.ModelStat; import ac.ed.lurg.landuse.CropUsageData; -import ac.ed.lurg.landuse.LandCoverChangeItem; import ac.ed.lurg.landuse.LandUseItem; import ac.ed.lurg.types.CropType; +import ac.ed.lurg.utils.TripleMap; +import ac.ed.lurg.types.LandCoverType; public class GamsLocationOutput { ModelStat status; Map<Integer, LandUseItem> landUses; // data mapped from id (not raster) private Map<CropType, CropUsageData> cropUsageData; - LandCoverChangeItem landCoverChange = new LandCoverChangeItem(); + //Map<Integer, DoubleMap<LandCoverType, LandCoverType, Double>> landCoverChange; + //LandCoverChangeItem landCoverChange; + TripleMap<Integer, LandCoverType, LandCoverType, Double> landCoverChanges; public GamsLocationOutput(ModelStat status, Map<Integer, LandUseItem> landUses, Map<CropType, CropUsageData> cropUsageData, - LandCoverChangeItem landCoverChange) { + TripleMap<Integer, LandCoverType, LandCoverType, Double> landCoverChange) { super(); this.status = status; this.landUses = landUses; this.cropUsageData = cropUsageData; - this.landCoverChange = landCoverChange; + this.landCoverChanges = landCoverChange; } public ModelStat getStatus() { @@ -38,7 +41,7 @@ public class GamsLocationOutput { return cropUsageData; } - public LandCoverChangeItem getLandCoverChange() { - return landCoverChange; + public TripleMap<Integer, LandCoverType, LandCoverType, Double> getLandCoverChanges() { + return landCoverChanges; } } diff --git a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java index d4b6b9394d6222385dbc8c83945017bfb9454968..a520bf68552b8a25b8078899ab796e4d94964a49 100644 --- a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java @@ -5,6 +5,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import ac.ed.lurg.ModelConfig; import ac.ed.lurg.landuse.CarbonFluxItem; import ac.ed.lurg.landuse.Intensity; import ac.ed.lurg.landuse.IrrigationItem; @@ -15,8 +16,10 @@ import ac.ed.lurg.types.CropType; import ac.ed.lurg.types.GamsLandCoverType; import ac.ed.lurg.types.LandCoverType; import ac.ed.lurg.types.YieldType; +import ac.ed.lurg.utils.DoubleMap; import ac.ed.lurg.utils.LazyTreeMap; import ac.ed.lurg.utils.LogWriter; +import ac.ed.lurg.utils.TripleMap; import ac.ed.lurg.yield.YieldRaster; import ac.ed.lurg.yield.YieldResponsesItem; import ac.sac.raster.IntegerRasterItem; @@ -101,7 +104,7 @@ public class GamsRasterOptimiser { //checkedTotalAreas(rasterInputData.getPreviousAreas(), "old"); //checkedTotalAreas(newAreaRaster, "new"); - LandCoverChangeItem landCoverChangeSet = gamsOutput.getLandCoverChange(); + //TripleMap<Integer, LandCoverType, LandCoverType, Double> landCoverChanges = gamsOutput.getLandCoverChanges(); for (Map.Entry<Integer, LandUseItem> entry : gamsOutput.getLandUses().entrySet()) { Integer locId = entry.getKey(); @@ -116,54 +119,39 @@ public class GamsRasterOptimiser { keys.add(mapEntry.getKey()); } - // Allocate land cover change to grid cells + + RasterSet<LandUseItem> landUseItemsForLocation = newLandUseRaster.createSubsetForKeys(keys); - Map<LandCoverType, Map<LandCoverType, Double>> landCoverChange = landCoverChangeSet.getLandCoverChangeForLocation(locId); + DoubleMap<LandCoverType, LandCoverType, Double> landCoverChange = gamsOutput.getLandCoverChanges().getInnerMap(locId); /* - for (LandCoverType fromLC : LandCoverType.getConvertibleTypes()) { - for (LandCoverType toLC : LandCoverType.getConvertibleTypes()) { - double change = landCoverChange.getLandCoverChange(fromLC, toLC, locId); - allocAllLandCropsTop(newLandUseRaster, keys, toLC, fromLC, change, locId); - } + if (landCoverChange == null) { + landCoverChange = new DoubleMap<LandCoverType, LandCoverType, Double>(); } */ - for (Entry<LandCoverType, Map<LandCoverType, Double>> fromMap: landCoverChange.entrySet()) { - LandCoverType fromLC = fromMap.getKey(); - for (Entry<LandCoverType, Double> toMap: fromMap.getValue().entrySet()) { - LandCoverType toLC = toMap.getKey(); - double change = toMap.getValue(); - allocAllLandCropsTop(newLandUseRaster, keys, toLC, fromLC, change, locId); - } - } - - -/* - double gamsPastureChange = newLandUseAggItem.getLandCoverArea(LandCoverType.PASTURE) - prevLandUseAggItem.getLandCoverArea(LandCoverType.PASTURE); - double gamsCroplandChange = newLandUseAggItem.getLandCoverArea(LandCoverType.CROPLAND) - prevLandUseAggItem.getLandCoverArea(LandCoverType.CROPLAND); - RasterSet<LandUseItem> landUseItemsForLocation = newLandUseRaster.createSubsetForKeys(keys); - - if (DEBUG) { - checkedTotalAreas(landUseItemsForLocation, locId + " before"); - LogWriter.println("pastureChange " + gamsPastureChange); - LogWriter.println("croplandChange " + gamsCroplandChange); - } - - double prevManagedForest = 0, prevUnmanagedForest = 0, prevNatural = 0, protectedAreasPastureChange = 0, protectedAreasCroplandChange = 0; + double prevTimberForest = 0, prevCarbonForest = 0, prevUnmanagedForest = 0, prevNatural = 0; + double protectedAreasPastureChange = 0, protectedAreasCroplandChange = 0; for (LandUseItem luItem: landUseItemsForLocation.values()) { - prevManagedForest += luItem.getUnprotectedLandCoverArea(LandCoverType.MANAGED_FOREST); + prevTimberForest += luItem.getUnprotectedLandCoverArea(LandCoverType.TIMBER_FOREST); + prevCarbonForest += luItem.getUnprotectedLandCoverArea(LandCoverType.CARBON_FOREST); prevUnmanagedForest += luItem.getUnprotectedLandCoverArea(LandCoverType.UNMANAGED_FOREST); prevNatural += luItem.getTotalUnprotectedNatural(); } - double prevForestTotal = prevManagedForest + prevUnmanagedForest; + double prevForestTotal = prevTimberForest + + prevCarbonForest + prevUnmanagedForest; double prevForestToNaturalFraction = (prevNatural > 0) ? prevForestTotal / prevNatural : 0; - double prevForestManagedFraction = (prevForestTotal > 0) ? prevManagedForest / prevForestTotal : 0; + double prevForestTimberFraction = (prevForestTotal > 0) ? prevTimberForest / prevForestTotal : 0; + double prevForestCarbonFraction = (prevForestTotal > 0) ? prevCarbonForest / prevForestTotal : 0; + double prevForestUnmanagedFraction = (prevForestTotal > 0) ? prevUnmanagedForest / prevForestTotal : 0; + // Floating point errors if(prevForestToNaturalFraction > 1.0) prevForestToNaturalFraction = 1.0; - if(prevForestManagedFraction > 1.0) prevForestManagedFraction = 1.0; + if(prevForestTimberFraction > 1.0) prevForestTimberFraction = 1.0; + if(prevForestCarbonFraction > 1.0) prevForestCarbonFraction = 1.0; + if(prevForestUnmanagedFraction > 1.0) prevForestUnmanagedFraction = 1.0; + //this tries to honour spatial distribution of protected areas, force removal of pasture and cropland from protected areas if (ModelConfig.FORCE_PROTECTED_AREAS && year >= ModelConfig.FORCE_PROTECTED_AREAS_START_YEAR) { @@ -183,16 +171,20 @@ public class GamsRasterOptimiser { double pastureShortfall = excessAgriculture * prevPastureFract; double croplandShortfall = excessAgriculture * (1 - prevPastureFract); - protectedLandShortfall += luItem.moveAreas(LandCoverType.MANAGED_FOREST, LandCoverType.PASTURE, - pastureShortfall * prevForestToNaturalFraction * prevForestManagedFraction); + protectedLandShortfall += luItem.moveAreas(LandCoverType.TIMBER_FOREST, LandCoverType.PASTURE, + pastureShortfall * prevForestToNaturalFraction * prevForestTimberFraction); + protectedLandShortfall += luItem.moveAreas(LandCoverType.TIMBER_FOREST, LandCoverType.PASTURE, + pastureShortfall * prevForestToNaturalFraction * prevForestCarbonFraction); protectedLandShortfall += luItem.moveAreas(LandCoverType.UNMANAGED_FOREST, LandCoverType.PASTURE, - pastureShortfall * prevForestToNaturalFraction * (1 - prevForestManagedFraction)); + pastureShortfall * prevForestToNaturalFraction * prevForestUnmanagedFraction); protectedLandShortfall += luItem.moveAreas(LandCoverType.OTHER_NATURAL, LandCoverType.PASTURE, pastureShortfall * (1 - prevForestToNaturalFraction)); - protectedLandShortfall += luItem.moveAreas(LandCoverType.MANAGED_FOREST, LandCoverType.CROPLAND, - croplandShortfall * prevForestToNaturalFraction * prevForestManagedFraction); + protectedLandShortfall += luItem.moveAreas(LandCoverType.TIMBER_FOREST, LandCoverType.CROPLAND, + croplandShortfall * prevForestToNaturalFraction * prevForestTimberFraction); + protectedLandShortfall += luItem.moveAreas(LandCoverType.CARBON_FOREST, LandCoverType.CROPLAND, + croplandShortfall * prevForestToNaturalFraction * prevForestCarbonFraction); protectedLandShortfall += luItem.moveAreas(LandCoverType.UNMANAGED_FOREST, LandCoverType.CROPLAND, - croplandShortfall * prevForestToNaturalFraction * (1 - prevForestManagedFraction)); + croplandShortfall * prevForestToNaturalFraction * prevForestUnmanagedFraction); protectedLandShortfall += luItem.moveAreas(LandCoverType.OTHER_NATURAL, LandCoverType.CROPLAND, croplandShortfall * (1 - prevForestToNaturalFraction)); @@ -209,58 +201,28 @@ public class GamsRasterOptimiser { if (DEBUG) { LogWriter.println("protectedAreasPastureChange " + protectedAreasPastureChange + " protectedAreasCroplandChange " + protectedAreasCroplandChange); } - - - } - - double totalPastureChange = protectedAreasPastureChange + gamsPastureChange; - double totalCroplandChange = protectedAreasCroplandChange + gamsCroplandChange; - - double pastureFromCrop = 0; - double pastureFromNatural = 0; - double cropFromNatural = 0; - - // Gained pasture and lost cropland - if (totalPastureChange > 0 && totalCroplandChange < 0) { - pastureFromCrop = Math.min(totalPastureChange, -totalCroplandChange); - // Gain in pasture greater than loss in cropland - if (totalPastureChange > -totalCroplandChange) - pastureFromNatural = totalPastureChange+totalCroplandChange; // take pasture gain not met by cropland loss from natural - // Gain in pasture less than loss in cropland - else - cropFromNatural = totalPastureChange+totalCroplandChange; // (-ve) add cropland loss not met by pasture gain to natural - } - // Gained cropland and lost pasture - else if (totalPastureChange < 0 && totalCroplandChange > 0) { - pastureFromCrop = -Math.min(-totalPastureChange, totalCroplandChange); - - if (totalCroplandChange > -totalPastureChange) - cropFromNatural = totalPastureChange+totalCroplandChange; - else - pastureFromNatural = totalPastureChange+totalCroplandChange; - } - else { - pastureFromNatural = totalPastureChange; - cropFromNatural = totalCroplandChange; - } + double totalNaturalArea = newLandUseAggItem.getTotalNatural(); + + + for (LandCoverType lc : LandCoverType.getProtectibleTypes()) { + double fraction = newLandUseAggItem.getLandCoverArea(lc) / totalNaturalArea; + landCoverChange.addTo(lc, LandCoverType.CROPLAND, protectedAreasCroplandChange * fraction); + landCoverChange.addTo(lc, LandCoverType.PASTURE, protectedAreasPastureChange * fraction); + } - if (DEBUG) { - LogWriter.println("pastureFromCrop " + pastureFromCrop); - LogWriter.println("pastureFromNatural " + pastureFromNatural); - LogWriter.println("cropFromNatural " + cropFromNatural); + } + + // Allocate land cover change to grid cells + for (Entry<LandCoverType, Map<LandCoverType, Double>> fromMap: landCoverChange.getMap().entrySet()) { + LandCoverType fromLC = fromMap.getKey(); + for (Entry<LandCoverType, Double> toMap: fromMap.getValue().entrySet()) { + LandCoverType toLC = toMap.getKey(); + double change = toMap.getValue(); + allocAllLandCropsTop(newLandUseRaster, keys, toLC, fromLC, change, locId); + } } - allocAllLandCropsTop(newLandUseRaster, keys, LandCoverType.PASTURE, LandCoverType.MANAGED_FOREST, pastureFromNatural * prevForestToNaturalFraction * prevForestManagedFraction, locId); - allocAllLandCropsTop(newLandUseRaster, keys, LandCoverType.PASTURE, LandCoverType.UNMANAGED_FOREST, pastureFromNatural * prevForestToNaturalFraction * (1-prevForestManagedFraction), locId); - allocAllLandCropsTop(newLandUseRaster, keys, LandCoverType.PASTURE, LandCoverType.OTHER_NATURAL, pastureFromNatural * (1-prevForestToNaturalFraction), locId); - allocAllLandCropsTop(newLandUseRaster, keys, LandCoverType.PASTURE, LandCoverType.CROPLAND, pastureFromCrop, locId); - allocAllLandCropsTop(newLandUseRaster, keys, LandCoverType.CROPLAND, LandCoverType.MANAGED_FOREST, cropFromNatural * prevForestToNaturalFraction * prevForestManagedFraction, locId); - allocAllLandCropsTop(newLandUseRaster, keys, LandCoverType.CROPLAND, LandCoverType.UNMANAGED_FOREST, cropFromNatural * prevForestToNaturalFraction * (1-prevForestManagedFraction), locId); - allocAllLandCropsTop(newLandUseRaster, keys, LandCoverType.CROPLAND, LandCoverType.OTHER_NATURAL, cropFromNatural * (1-prevForestToNaturalFraction), locId); - - if (DEBUG) checkedTotalAreas(landUseItemsForLocation, locId + " after"); -*/ for (RasterKey key : keys) { LandUseItem newLandUseItem = newLandUseRaster.get(key); if (newLandUseItem != null) { @@ -272,10 +234,9 @@ public class GamsRasterOptimiser { } } - + if (DEBUG) checkedTotalAreas(landUseItemsForLocation, locId + " after"); } - return newLandUseRaster; } @@ -459,8 +420,6 @@ public class GamsRasterOptimiser { // Carbon flux if (!aggCFlux.checkForKeys(prevLC, newLC)) { // if not seen yet - //LogWriter.println("prevLC: " + prevLC + ", newLC: " + newLC); - //LogWriter.println("Data: " + carbonFluxItem.getCarbonFluxes()); aggCFlux.setCarbonFlux(prevLC, newLC, carbonFluxItem.getCarbonFlux(prevLC, newLC)); } else { aggCFlux.setCarbonFlux(prevLC, newLC, aggregateMean(aggCFlux.getCarbonFlux(prevLC, newLC), suitableAreaSoFar, diff --git a/src/ac/ed/lurg/landuse/LandUseItem.java b/src/ac/ed/lurg/landuse/LandUseItem.java index f6774523f6f5c2082b5512e23dae52df8e5fab92..dff462d47d8a7cabf0baa1baf370673572bb9940 100644 --- a/src/ac/ed/lurg/landuse/LandUseItem.java +++ b/src/ac/ed/lurg/landuse/LandUseItem.java @@ -1,9 +1,11 @@ package ac.ed.lurg.landuse; import java.io.Serializable; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import ac.ed.lurg.ModelConfig; import ac.ed.lurg.types.CropToDouble; @@ -19,7 +21,7 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial private Map<CropType, Double> cropFractions = new HashMap<CropType, Double>(); private Map<LandCoverType, Double> landCoverAreas = new HashMap<LandCoverType, Double>(); private Map<LandCoverType, Double> unprotectedAreas = new HashMap<LandCoverType, Double>(); - //private Map<GamsLandCoverType, Double> gamsLandCoverAreas = new HashMap<GamsLandCoverType, Double>(); + private Map<LandCoverType, Map<Integer, Double>> minimumLandCover = new HashMap<LandCoverType, Map<Integer, Double>>(); // Minimum land cover by year of expiry private double protectedArea; //protected area in Mha private double unavailableArea; //area unavailable due to altitude etc private double suitableArea; @@ -433,37 +435,17 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial return total; } - /* - public boolean checkForUnprotected(LandCoverType landCover) { - return unprotectedAreas.containsKey(landCover); - } - */ - /* - public double getGamsLandCoverArea(GamsLandCoverType landCoverType) { - return gamsLandCoverAreas.get(landCoverType); - } - - public void setGamsLandCoverArea(GamsLandCoverType c, double d) { - if (Double.isNaN(d) || Double.isInfinite(d)) - throw new RuntimeException("AreasItem for " + c + " is " + d); - - double landCover = (d < 0.0) ? 0.0 : d; - - gamsLandCoverAreas.put(c, landCover); + public double getMinimumLandCover(LandCoverType lcType, Integer year) { + double area = 0; + Map<Integer, Double> yearMap = minimumLandCover.get(lcType); + for (Entry<Integer, Double> entry : yearMap.entrySet()) { + if (entry.getKey() > year) { + area += entry.getValue(); + } + } + return area; } - - // move areas from one land cover to another, return any residual not possible - public void moveGamsAreas(GamsLandCoverType toType, GamsLandCoverType fromType, double changeReq) { - - double prevTo = getGamsLandCoverArea(toType); - double prevFrom = getGamsLandCoverArea(fromType); - - setGamsLandCoverArea(toType, prevTo + changeReq); - setGamsLandCoverArea(fromType, prevFrom - changeReq); - - } - */ @Override public String toString() { return "LandUseItem: [landCoverAreas=" + landCoverAreas + ", protectedArea=" + protectedArea + ", unavailableArea=" + unavailableArea + "]"; diff --git a/src/ac/ed/lurg/output/LpjgOutputer.java b/src/ac/ed/lurg/output/LpjgOutputer.java index 5ba5f785f1d232c49ebfad835ff38d3565f6bfeb..2562d1e2826644ebe319c99500e8283b8702a2cd 100644 --- a/src/ac/ed/lurg/output/LpjgOutputer.java +++ b/src/ac/ed/lurg/output/LpjgOutputer.java @@ -172,7 +172,7 @@ public class LpjgOutputer extends AbstractLandUseOutputer { try { String landCoverFileName = outputDir.getPath() + File.separator + "GamsLandCoverFract.txt"; landCoverWriter = new BufferedWriter(new FileWriter(landCoverFileName, false)); - landCoverWriter.write("Lon Lat Year CROPLAND PASTURE TIMBER CARBON NATURAL BARREN URBAN"); + landCoverWriter.write("Lon Lat Year CROPLAND PASTURE TIMBER CARBON UNMANAGED NATURAL BARREN URBAN"); landCoverWriter.newLine(); for (Entry<RasterKey, LandUseItem> entry : landUseRaster.entrySet()) { diff --git a/src/ac/ed/lurg/types/LandCoverType.java b/src/ac/ed/lurg/types/LandCoverType.java index 47c1563360ac3c5321c0bccbc8f9f70169da7a81..84277884348507591164cb63df228a39c471e8b3 100644 --- a/src/ac/ed/lurg/types/LandCoverType.java +++ b/src/ac/ed/lurg/types/LandCoverType.java @@ -65,5 +65,17 @@ public enum LandCoverType { return convertibleTypes; } + + public static Collection<LandCoverType> getProtectibleTypes() { + + Collection<LandCoverType> protectibleTypes = new HashSet<LandCoverType>(); + + for (LandCoverType c : values()) + if (c.isProtectable) + protectibleTypes.add(c); + + return protectibleTypes; + + } } diff --git a/src/ac/ed/lurg/utils/DoubleMap.java b/src/ac/ed/lurg/utils/DoubleMap.java new file mode 100644 index 0000000000000000000000000000000000000000..9c2762b3a7ea918cd876a173527655af034d5e2c --- /dev/null +++ b/src/ac/ed/lurg/utils/DoubleMap.java @@ -0,0 +1,51 @@ +package ac.ed.lurg.utils; + +import java.util.HashMap; +import java.util.Map; + +public class DoubleMap<K, L, V extends Double> { + + Map<K, Map<L, Double>> theMap = new HashMap<K, Map<L, Double>>(); + + public DoubleMap() { + + } + + 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)) { + double current = get(key1, key2); + put(key1, key2, current + value); + } else { + put(key1, key2, value); + } + + + } +} diff --git a/src/ac/ed/lurg/utils/NestedMap.java b/src/ac/ed/lurg/utils/NestedMap.java new file mode 100644 index 0000000000000000000000000000000000000000..54f72c9b9a326241846770277ffe9878286debe8 --- /dev/null +++ b/src/ac/ed/lurg/utils/NestedMap.java @@ -0,0 +1,51 @@ +package ac.ed.lurg.utils; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.List; + +public class NestedMap { + + Map<Object, Object> theMap; + Integer depth; + + NestedMap() { + theMap = new HashMap<Object, Object>(); + } + + public void put(List<Object> keys, Object value) { + + + + Collections.reverse(keys); + theMap.put(keys.get(keys.size() - 1), createNestedMap(keys.subList(0, keys.size() - 1), value)); + } + + private Map<Object, Object> createNestedMap(List<Object> keys, Object value) { + Map<Object, Object> valueMap = new HashMap<Object, Object>(); + valueMap.put(keys.get(0), value); + Map<Object, Object> higherMap; + if (keys.size() > 1) { + higherMap = createNestedMap(keys.subList(1, keys.size()), valueMap); + return higherMap; + } else { + return valueMap; + } + } + /* + private Map<Object, Object> getLowestLevel(List<Object> keys) { + if (theMap.containsKey(keys.get(0))) { + getLowestLevel(keys.subList(1, keys.size())); + } else { + return theMap.get(key); + } + } + */ + /* + private Map<Object, Object> getMapForKeys(List<Object> keys) { + Map<Object, Object> map = new HashMap<Object, Object>(); + + } + */ +} diff --git a/src/ac/ed/lurg/utils/TripleMap.java b/src/ac/ed/lurg/utils/TripleMap.java new file mode 100644 index 0000000000000000000000000000000000000000..78a0dbb9136a1ec786771786055c6f024e4d85b7 --- /dev/null +++ b/src/ac/ed/lurg/utils/TripleMap.java @@ -0,0 +1,37 @@ +package ac.ed.lurg.utils; + +import java.util.HashMap; +import java.util.Map; + +public class TripleMap<K, L, M, V extends Double> { + + 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); + + } +}