diff --git a/GAMS/IntExtOpt.gms b/GAMS/IntExtOpt.gms index ec4b52772d7201aa8ae46d395d4a1d04af5c8526..c915b7dee1440e64c07afdc8a7d574f22948995e 100644 --- a/GAMS/IntExtOpt.gms +++ b/GAMS/IntExtOpt.gms @@ -60,7 +60,7 @@ SCALAR maxLandExpansionRate max rate of country land expansion; PARAMETER previousLandCoverArea(land_cover, location) land cover area in Mha; -* PARAMETER minimumLandCoverArea(land_cover, location) minimum land cover area to constrain conversion; + PARAMETER minimumLandCoverArea(land_cover, location) minimum land cover area to constrain conversion; 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; @@ -74,7 +74,7 @@ $load yieldNone, yieldFertOnly, yieldIrrigOnly, yieldBoth, yieldShock $load fertParam, irrigParam, otherIParam, exportPrices, importPrices, maxNetImport, minNetImport, unhandledCropRate, setAsideRate, maxLandExpansionRate, subsidyRate $load meatEfficency, otherICost, irrigCost, irrigMaxRate, irrigConstraint, fertiliserUnitCost, domesticPriceMarkup, minDemandPerCereal, minDemandPerOilcrop, seedAndWasteRate $load previousLandCoverArea, carbonFluxRate, woodYield, carbonPrice, woodPrice -*$load minimumLandCoverArea +$load minimumLandCoverArea $gdxin * convert units from $/t to billion$/Mt @@ -190,7 +190,7 @@ $gdxin PASTURE_TOTAL_CHANGE_CONSTRAINT(location) 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 + MINIMUM_LAND_COVER_CONSTRAINT(location) constraint on land cover conversion LAND_COVER_CHANGE_CALC(land_cover, location) LAND_COVER_CHANGE_CONSTRAINT(land_cover, location) LAND_COVER_SELF_CHANGE_CONSTRAINT(land_cover, location) @@ -254,7 +254,7 @@ $gdxin PASTURE_LAND_COVER_CALC(location) .. landCoverArea('pasture', location) =E= cropArea('pasture', location); -* MINIMUM_LAND_COVER_CONSTRAINT(location, land_cover) .. landCoverArea(land_cover, location)) =G= minimumLandCover(land_cover_after, location); + MINIMUM_LAND_COVER_CONSTRAINT(location, land_cover) .. landCoverArea(land_cover, location)) =G= minimumLandCover(land_cover_after, location); LAND_COVER_CHANGE_CALC(land_cover, location) .. landCoverArea(land_cover, location) =E= previousLandCoverArea(land_cover, location) + sum(land_cover_before, landCoverChange(land_cover_before, land_cover, location)) - sum(land_cover_after, landCoverChange(land_cover, land_cover_after, location)); diff --git a/src/ac/ed/lurg/country/CountryAgent.java b/src/ac/ed/lurg/country/CountryAgent.java index a723454c430cae6b289d5997ea2920ce30a92610..bb23039660c15bc996c58ba1bbaada2bb5625aec 100644 --- a/src/ac/ed/lurg/country/CountryAgent.java +++ b/src/ac/ed/lurg/country/CountryAgent.java @@ -25,7 +25,9 @@ import ac.ed.lurg.landuse.WoodYieldItem; import ac.ed.lurg.types.CommodityType; import ac.ed.lurg.types.CropType; import ac.ed.lurg.types.LandCoverType; +import ac.ed.lurg.utils.DoubleMap; import ac.ed.lurg.utils.LogWriter; +import ac.ed.lurg.utils.TripleMap; import ac.ed.lurg.utils.cluster.Cluster; import ac.ed.lurg.utils.cluster.KMeans; import ac.ed.lurg.yield.YieldClusterPoint; @@ -41,6 +43,7 @@ public class CountryAgent extends AbstractCountryAgent { private RasterSet<IntegerRasterItem> yieldClusters; private Map<CropType, Double> subsidyRates; private boolean saveGamsGdxFiles; + private TripleMap<Integer, Integer, LandCoverType, Double> minimumLandCover; //<Year, Location, LandCoverType, Area> public CountryAgent(AbstractDemandManager demandManager,CompositeCountry country, RasterSet<LandUseItem> cropAreaRaster, Map<CropType, CropUsageData> cropUsageData, Map<CropType, Double> tradeBarriers, RasterSet<IntegerRasterItem> yieldClusters, @@ -49,6 +52,8 @@ public class CountryAgent extends AbstractCountryAgent { super(demandManager, country, tradeBarriers); this.yieldClusters = yieldClusters; this.subsidyRates = subsidyRates; + + minimumLandCover = new TripleMap<Integer, Integer, LandCoverType, Double>(); // TODO how to intialise? GamsRasterOutput initialData = new GamsRasterOutput(cropAreaRaster, cropUsageData); previousGamsRasterOutput = initialData; @@ -104,7 +109,8 @@ public class CountryAgent extends AbstractCountryAgent { } public GamsRasterOutput determineProduction(YieldRaster countryYieldSurfaces, RasterSet<IrrigationItem> irrigData, - Map<CropType, GlobalPrice> worldPrices, double globalGen2EcIncrease, RasterSet<CarbonFluxItem> carbonFluxData, RasterSet<WoodYieldItem> woodYieldData) { + Map<CropType, GlobalPrice> worldPrices, double globalGen2EcIncrease, RasterSet<CarbonFluxItem> carbonFluxData, + RasterSet<WoodYieldItem> woodYieldData) { // project demand calculateCountryPricesAndDemand(worldPrices, false); @@ -123,9 +129,11 @@ public class CountryAgent extends AbstractCountryAgent { else { if (yieldClusters==null) yieldClusters = calcYieldClusters(irrigData, countryYieldSurfaces); // this should only be on the first timestep + + // optimize areas and intensity - GamsRasterInput input = getGamsRasterInput(irrigData, countryYieldSurfaces, globalGen2EcIncrease, carbonFluxData, woodYieldData); + GamsRasterInput input = getGamsRasterInput(irrigData, countryYieldSurfaces, globalGen2EcIncrease, carbonFluxData, woodYieldData, minimumLandCover); GamsRasterOptimiser opti = new GamsRasterOptimiser(input, yieldClusters); LogWriter.println("Running " + country.getName() + ", currentTimestep " + currentTimestep); @@ -135,6 +143,7 @@ public class CountryAgent extends AbstractCountryAgent { saveGDXFile("landuse"); previousGamsRasterOutput = result; + updateMinimumLandCover(); return result; } @@ -158,7 +167,8 @@ public class CountryAgent extends AbstractCountryAgent { } private GamsRasterInput getGamsRasterInput(RasterSet<IrrigationItem> irrigData, YieldRaster countryYieldSurfaces, double gen2EcIncrease, - RasterSet<CarbonFluxItem> carbonFluxData, RasterSet<WoodYieldItem> woodYieldData) { + RasterSet<CarbonFluxItem> carbonFluxData, RasterSet<WoodYieldItem> woodYieldData, + TripleMap<Integer, Integer, LandCoverType, Double> minimumLandCover) { double allowedImportChange; if (currentTimestep.isInitialTimestep() || (ModelConfig.IS_CALIBRATION_RUN && currentTimestep.getTimestep() <= ModelConfig.END_FIRST_STAGE_CALIBRATION)) { // initialisation time-step @@ -200,11 +210,24 @@ public class CountryAgent extends AbstractCountryAgent { importConstraints.put(crop, new TradeConstraint(baseTrade - changeDown, baseTrade + changeUp)); } + + // Aggregate minimum land cover for current timestep + DoubleMap<Integer, LandCoverType, Double> minimumLandCoverForTimestep = new DoubleMap<Integer, LandCoverType, Double>(); + + for (Entry<Integer, DoubleMap<Integer, LandCoverType, Double>> yearMap : minimumLandCover.getMap().entrySet()) { + if (yearMap.getKey() < currentTimestep.getYear()) { + for (Entry<Integer, Map<LandCoverType, Double>> locMap : yearMap.getValue().getMap().entrySet()) { + for (Entry<LandCoverType, Double> coverMap : locMap.getValue().entrySet()) { + minimumLandCoverForTimestep.addTo(locMap.getKey(), coverMap.getKey(), coverMap.getValue()); + } + } + } + } GamsCountryInput countryLevelInputs = new GamsCountryInput(country, currentProjectedDemand, currentCountryPrices, importConstraints, previousGamsRasterOutput.getCropUsageData(), currentMinDemandFract, subsidyRates); GamsRasterInput input = new GamsRasterInput(currentTimestep, countryYieldSurfaces, previousGamsRasterOutput.getLandUses(), irrigData, - carbonFluxData, woodYieldData, countryLevelInputs); + carbonFluxData, woodYieldData, minimumLandCoverForTimestep, countryLevelInputs); return input; } @@ -291,4 +314,8 @@ public class CountryAgent extends AbstractCountryAgent { } } + + private void updateMinimumLandCover() { + //TODO + } } \ No newline at end of file diff --git a/src/ac/ed/lurg/country/gams/GamsLocationInput.java b/src/ac/ed/lurg/country/gams/GamsLocationInput.java index d00a90bf138a6dcba29b47d22609e582b5ec0c61..899e6e3324e1c3e3f95c6f913ba45e2354bdf532 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationInput.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationInput.java @@ -7,6 +7,8 @@ import ac.ed.lurg.landuse.CarbonFluxItem; import ac.ed.lurg.landuse.IrrigationItem; import ac.ed.lurg.landuse.LandUseItem; import ac.ed.lurg.landuse.WoodYieldItem; +import ac.ed.lurg.types.LandCoverType; +import ac.ed.lurg.utils.DoubleMap; import ac.ed.lurg.yield.YieldResponsesItem; public class GamsLocationInput { @@ -17,11 +19,12 @@ public class GamsLocationInput { private Map<Integer, ? extends IrrigationItem> irrigationCosts; private Map<Integer, ? extends CarbonFluxItem> carbonFluxes; private Map<Integer, ? extends WoodYieldItem> woodYields; + private DoubleMap<Integer, LandCoverType, Double> minimumLandCover; private GamsCountryInput countryInput; public GamsLocationInput(Timestep timestep, Map<Integer, ? extends YieldResponsesItem> yields, Map<Integer, ? extends LandUseItem> previousLandUse, Map<Integer, ? extends IrrigationItem> irrigationCosts, Map<Integer, ? extends CarbonFluxItem> carbonFluxes, - Map<Integer, ? extends WoodYieldItem> woodYields, GamsCountryInput countryInput) { + Map<Integer, ? extends WoodYieldItem> woodYields, DoubleMap<Integer, LandCoverType, Double> minimumLandCover, GamsCountryInput countryInput) { super(); this.timestep = timestep; this.yields = yields; @@ -30,6 +33,7 @@ public class GamsLocationInput { this.carbonFluxes = carbonFluxes; this.woodYields = woodYields; this.countryInput = countryInput; + this.minimumLandCover = minimumLandCover; } public Map<Integer, ? extends YieldResponsesItem> getYields() { @@ -52,6 +56,10 @@ public class GamsLocationInput { return woodYields; } + public DoubleMap<Integer, LandCoverType, Double> getMinimumLandCover() { + return minimumLandCover; + } + public GamsCountryInput getCountryInput() { return countryInput; } diff --git a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java index 26eaa91fa082a1d09e1c95647206adbd35cbd0fa..2786437bb0ef3b756a59a4e666513c1bcda8439f 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java @@ -27,7 +27,6 @@ import ac.ed.lurg.landuse.CarbonFluxItem; import ac.ed.lurg.landuse.CropUsageData; import ac.ed.lurg.landuse.Intensity; import ac.ed.lurg.landuse.IrrigationItem; -import ac.ed.lurg.landuse.LandCoverChangeItem; import ac.ed.lurg.landuse.LandUseItem; import ac.ed.lurg.landuse.WoodYieldItem; import ac.ed.lurg.types.CommodityType; @@ -36,6 +35,7 @@ import ac.ed.lurg.types.GamsLandCoverType; import ac.ed.lurg.types.LandCoverType; import ac.ed.lurg.types.Parameter; import ac.ed.lurg.types.YieldType; +import ac.ed.lurg.utils.DoubleMap; import ac.ed.lurg.utils.LazyHashMap; import ac.ed.lurg.utils.LogWriter; import ac.ed.lurg.utils.TripleMap; @@ -399,6 +399,21 @@ public class GamsLocationOptimiser { } + // Minimum land covers + GAMSParameter minimumLandCover = inDB.addParameter("minimumLandCover", 2); + + for (Entry<Integer, Map<LandCoverType, Double>> locMap : inputData.getMinimumLandCover().getMap().entrySet()) { + Integer locationId = locMap.getKey(); + String locString = Integer.toString(locationId); + + for (Entry<LandCoverType, Double> coverMap : locMap.getValue().entrySet()) { + Vector<String> v = new Vector<String>(); + v.add(coverMap.getKey().getName()); + v.add(locString); + setGamsParamValue(minimumLandCover.addRecord(v), coverMap.getValue(), 3); + } + } + } private void addScalar(GAMSDatabase gamsDb, String recordName, double val, int places) { @@ -430,8 +445,9 @@ public class GamsLocationOptimiser { GAMSGlobals.SolveStat.lookup((int) outDB.getParameter("ss").findRecord().getValue())); LogWriter.println("\n" + contextString); - if (modelStatus != ModelStat.OPTIMAL_LOCAL) + if (modelStatus != ModelStat.OPTIMAL_LOCAL) { LogWriter.printlnError("Critical!!! Land use incorrectly solved. " + contextString); + } GAMSVariable varAreas = outDB.getVariable("cropArea"); GAMSVariable varFertIntensities = outDB.getVariable("fertI"); @@ -566,6 +582,11 @@ public class GamsLocationOptimiser { TripleMap<Integer, LandCoverType, LandCoverType, Double> landCoverChanges = new TripleMap<Integer, LandCoverType, LandCoverType, Double>(); + /* + if (inputData.getCountryInput().getCountry().getName().equals("Peru & Ecuador")) { + LogWriter.println("foo"); + } + */ for (GAMSVariableRecord rec : varLandCoverChange) { String fromLC = rec.getKeys()[0]; @@ -575,11 +596,15 @@ public class GamsLocationOptimiser { double change = rec.getLevel(); + /* if (change == 0.0) { continue; } + */ - if (fromLC.equals("natural")) { + if (fromLC.equals("natural") && toLC.equals("natural")) { + continue; + } else if (fromLC.equals("natural")) { double prevUnmanagedForestProp = getPrevUnmanagedForestProp(locId); landCoverChanges.put(locId, LandCoverType.UNMANAGED_FOREST, LandCoverType.getForName(toLC), change * prevUnmanagedForestProp); landCoverChanges.put(locId, LandCoverType.OTHER_NATURAL, LandCoverType.getForName(toLC), change * (1 - prevUnmanagedForestProp)); @@ -590,11 +615,25 @@ public class GamsLocationOptimiser { } else { 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). + } + + // Minimum land cover additions. Need to keep track of new forest areas to restrict conversion + DoubleMap<Integer, LandCoverType, Double> minimumLandCoverAdditions = new DoubleMap<Integer, LandCoverType, Double>(); + + for (Entry<Integer, DoubleMap<LandCoverType, LandCoverType, Double>> locMap : landCoverChanges.getMap().entrySet()) { + Integer locId = locMap.getKey(); + DoubleMap<LandCoverType, LandCoverType, Double> changeMap = locMap.getValue(); + for (LandCoverType fromLC : LandCoverType.getConvertibleTypes()) { + minimumLandCoverAdditions.addTo(locId, LandCoverType.TIMBER_FOREST, changeMap.get(fromLC, LandCoverType.TIMBER_FOREST)); + minimumLandCoverAdditions.addTo(locId, LandCoverType.CARBON_FOREST, changeMap.get(fromLC, LandCoverType.CARBON_FOREST)); + } + + } + - GamsLocationOutput results = new GamsLocationOutput(modelStatus, landUses, cropUsageData, landCoverChanges); + GamsLocationOutput results = new GamsLocationOutput(modelStatus, landUses, cropUsageData, landCoverChanges, minimumLandCoverAdditions); return results; } diff --git a/src/ac/ed/lurg/country/gams/GamsLocationOutput.java b/src/ac/ed/lurg/country/gams/GamsLocationOutput.java index 258064949b97f96c58357e0115a45fdea64f659d..a30c9d2deb5988673fabe9e7191318d7fec4f7e7 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationOutput.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationOutput.java @@ -7,6 +7,7 @@ import com.gams.api.GAMSGlobals.ModelStat; import ac.ed.lurg.landuse.CropUsageData; import ac.ed.lurg.landuse.LandUseItem; import ac.ed.lurg.types.CropType; +import ac.ed.lurg.utils.DoubleMap; import ac.ed.lurg.utils.TripleMap; import ac.ed.lurg.types.LandCoverType; @@ -15,19 +16,20 @@ public class GamsLocationOutput { Map<Integer, LandUseItem> landUses; // data mapped from id (not raster) private Map<CropType, CropUsageData> cropUsageData; - //Map<Integer, DoubleMap<LandCoverType, LandCoverType, Double>> landCoverChange; - //LandCoverChangeItem landCoverChange; TripleMap<Integer, LandCoverType, LandCoverType, Double> landCoverChanges; + DoubleMap<Integer, LandCoverType, Double> minimumLandCover; public GamsLocationOutput(ModelStat status, Map<Integer, LandUseItem> landUses, Map<CropType, CropUsageData> cropUsageData, - TripleMap<Integer, LandCoverType, LandCoverType, Double> landCoverChange) { + TripleMap<Integer, LandCoverType, LandCoverType, Double> landCoverChange, + DoubleMap<Integer, LandCoverType, Double> minimumLandCover) { super(); this.status = status; this.landUses = landUses; this.cropUsageData = cropUsageData; this.landCoverChanges = landCoverChange; + this.minimumLandCover = minimumLandCover; } public ModelStat getStatus() { @@ -44,4 +46,8 @@ public class GamsLocationOutput { public TripleMap<Integer, LandCoverType, LandCoverType, Double> getLandCoverChanges() { return landCoverChanges; } + + public DoubleMap<Integer, LandCoverType, Double> getMinimumLandCover() { + return minimumLandCover; + } } diff --git a/src/ac/ed/lurg/country/gams/GamsRasterInput.java b/src/ac/ed/lurg/country/gams/GamsRasterInput.java index f6ef7f850b2255c10d3ad162a66dc8d5cfd9e117..1f6557762e44cbf3413ee3acd58d230590194181 100644 --- a/src/ac/ed/lurg/country/gams/GamsRasterInput.java +++ b/src/ac/ed/lurg/country/gams/GamsRasterInput.java @@ -3,6 +3,9 @@ package ac.ed.lurg.country.gams; import ac.ed.lurg.Timestep; import ac.ed.lurg.landuse.LandUseItem; import ac.ed.lurg.landuse.WoodYieldItem; +import ac.ed.lurg.types.LandCoverType; +import ac.ed.lurg.utils.DoubleMap; +import ac.ed.lurg.utils.TripleMap; import ac.ed.lurg.landuse.CarbonFluxItem; import ac.ed.lurg.landuse.IrrigationItem; import ac.ed.lurg.yield.YieldRaster; @@ -16,10 +19,12 @@ public class GamsRasterInput { private RasterSet<IrrigationItem> irrigationCost; private RasterSet<CarbonFluxItem> carbonFluxes; private RasterSet<WoodYieldItem> woodYields; + private DoubleMap<Integer, LandCoverType, Double> minimumLandCover; private GamsCountryInput countryInput; public GamsRasterInput(Timestep timestep, YieldRaster yields, RasterSet<LandUseItem> previousLandsUses, RasterSet<IrrigationItem> irrigationCost, - RasterSet<CarbonFluxItem> carbonFluxes, RasterSet<WoodYieldItem> woodYields, GamsCountryInput countryInput) { + RasterSet<CarbonFluxItem> carbonFluxes, RasterSet<WoodYieldItem> woodYields, DoubleMap<Integer, LandCoverType, Double> minimumLandCover, + GamsCountryInput countryInput) { super(); this.timestep = timestep; this.yields = yields; @@ -27,6 +32,7 @@ public class GamsRasterInput { this.irrigationCost = irrigationCost; this.carbonFluxes = carbonFluxes; this.woodYields = woodYields; + this.minimumLandCover = minimumLandCover; this.countryInput = countryInput; } @@ -50,6 +56,10 @@ public class GamsRasterInput { return woodYields; } + public DoubleMap<Integer, LandCoverType, Double> getMinimumLandCover() { + return minimumLandCover; + } + public GamsCountryInput getCountryInput() { return countryInput; } diff --git a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java index a520bf68552b8a25b8078899ab796e4d94964a49..60b4cb5d4f8694e608904b3775f5252fde5b3a36 100644 --- a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java @@ -9,7 +9,6 @@ import ac.ed.lurg.ModelConfig; import ac.ed.lurg.landuse.CarbonFluxItem; import ac.ed.lurg.landuse.Intensity; import ac.ed.lurg.landuse.IrrigationItem; -import ac.ed.lurg.landuse.LandCoverChangeItem; import ac.ed.lurg.landuse.LandUseItem; import ac.ed.lurg.landuse.WoodYieldItem; import ac.ed.lurg.types.CropType; @@ -19,7 +18,6 @@ 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; @@ -56,7 +54,7 @@ public class GamsRasterOptimiser { private GamsRasterOutput convertToRaster(GamsLocationInput gamsInput, GamsLocationOutput gamsOutput) { RasterSet<LandUseItem> newIntensityRaster = allocAreas(gamsInput.getPreviousLandUse(), gamsOutput, gamsInput.getTimestep().getYear()); - return new GamsRasterOutput(gamsOutput.getStatus(), newIntensityRaster, gamsOutput.getCommoditiesData()); + return new GamsRasterOutput(gamsOutput.getStatus(), newIntensityRaster, gamsOutput.getCommoditiesData(), gamsOutput.getMinimumLandCover()); } private RasterSet<LandUseItem> createWithSameLandCovers(RasterSet<LandUseItem> toCopy) { @@ -103,8 +101,6 @@ public class GamsRasterOptimiser { //checkedTotalAreas(rasterInputData.getPreviousAreas(), "old"); //checkedTotalAreas(newAreaRaster, "new"); - - //TripleMap<Integer, LandCoverType, LandCoverType, Double> landCoverChanges = gamsOutput.getLandCoverChanges(); for (Map.Entry<Integer, LandUseItem> entry : gamsOutput.getLandUses().entrySet()) { Integer locId = entry.getKey(); @@ -119,9 +115,13 @@ public class GamsRasterOptimiser { keys.add(mapEntry.getKey()); } - + RasterSet<LandUseItem> landUseItemsForLocation = newLandUseRaster.createSubsetForKeys(keys); + if (rasterInputData.getCountryInput().getCountry().getName().equals("Peru & Ecuador")) { + LogWriter.println("foo"); + } + DoubleMap<LandCoverType, LandCoverType, Double> landCoverChange = gamsOutput.getLandCoverChanges().getInnerMap(locId); /* @@ -204,7 +204,7 @@ public class GamsRasterOptimiser { double totalNaturalArea = newLandUseAggItem.getTotalNatural(); - + // Add protected area changes to GAMS changes for (LandCoverType lc : LandCoverType.getProtectibleTypes()) { double fraction = newLandUseAggItem.getLandCoverArea(lc) / totalNaturalArea; landCoverChange.addTo(lc, LandCoverType.CROPLAND, protectedAreasCroplandChange * fraction); @@ -549,7 +549,7 @@ public class GamsRasterOptimiser { checkedTotalAreas(landUseRaster, "before"); checkedTotalAreas(aggregatedAreas, "after"); return new GamsLocationInput(rasterInputData.getTimestep(), aggregatedYields, aggregatedAreas, aggregatedIrrigCosts, - aggregatedCarbonFluxes, aggregatedWoodYields, rasterInputData.getCountryInput()); + aggregatedCarbonFluxes, aggregatedWoodYields, rasterInputData.getMinimumLandCover(), rasterInputData.getCountryInput()); } private void logWarningWithCoord(String message, RasterKey key, YieldRaster yieldRaster, CropType crop) { diff --git a/src/ac/ed/lurg/country/gams/GamsRasterOutput.java b/src/ac/ed/lurg/country/gams/GamsRasterOutput.java index 33e021825cda6bb6983f9df3c5954fa199260fa6..78bbbfefd903a86d6dee4ce44e3c4f69d496166e 100644 --- a/src/ac/ed/lurg/country/gams/GamsRasterOutput.java +++ b/src/ac/ed/lurg/country/gams/GamsRasterOutput.java @@ -7,6 +7,8 @@ import com.gams.api.GAMSGlobals.ModelStat; import ac.ed.lurg.landuse.CropUsageData; import ac.ed.lurg.landuse.LandUseItem; import ac.ed.lurg.types.CropType; +import ac.ed.lurg.types.LandCoverType; +import ac.ed.lurg.utils.DoubleMap; import ac.sac.raster.RasterSet; public class GamsRasterOutput { @@ -14,16 +16,19 @@ public class GamsRasterOutput { private ModelStat status; private RasterSet<LandUseItem> landUses; private Map<CropType, CropUsageData> cropUsageData; + private DoubleMap<Integer, LandCoverType, Double> minimumLandCoverAdditions; public GamsRasterOutput(RasterSet<LandUseItem> landUses, Map<CropType, CropUsageData> cropUsageData) { super(); this.landUses = landUses; - this.cropUsageData = cropUsageData; + this.cropUsageData = cropUsageData; } - public GamsRasterOutput(ModelStat status, RasterSet<LandUseItem> intensityRaster, Map<CropType, CropUsageData> cropUsageData) { + public GamsRasterOutput(ModelStat status, RasterSet<LandUseItem> intensityRaster, Map<CropType, CropUsageData> cropUsageData, + DoubleMap<Integer, LandCoverType, Double> minimumLandCoverAdditions) { this(intensityRaster, cropUsageData); this.status = status; + this.minimumLandCoverAdditions = minimumLandCoverAdditions; } public ModelStat getStatus() { @@ -37,4 +42,8 @@ public class GamsRasterOutput { public Map<CropType, CropUsageData> getCropUsageData() { return cropUsageData; } + + public DoubleMap<Integer, LandCoverType, Double> getMinimumLandCoverAdditions() { + return minimumLandCoverAdditions; + } } diff --git a/src/ac/ed/lurg/landuse/LandUseItem.java b/src/ac/ed/lurg/landuse/LandUseItem.java index dff462d47d8a7cabf0baa1baf370673572bb9940..b6e60f8233ff54bae7fc8e1d37037b1b8dcc9cff 100644 --- a/src/ac/ed/lurg/landuse/LandUseItem.java +++ b/src/ac/ed/lurg/landuse/LandUseItem.java @@ -11,6 +11,7 @@ import ac.ed.lurg.ModelConfig; import ac.ed.lurg.types.CropToDouble; import ac.ed.lurg.types.CropType; import ac.ed.lurg.types.LandCoverType; +import ac.ed.lurg.utils.DoubleMap; import ac.ed.lurg.utils.Interpolator; import ac.sac.raster.InterpolatingRasterItem; @@ -19,12 +20,12 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial private Map<CropType, Intensity> intensityMap = new HashMap<CropType, Intensity>(); 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<LandCoverType, Map<Integer, Double>> minimumLandCover = new HashMap<LandCoverType, Map<Integer, Double>>(); // Minimum land cover by year of expiry + private Map<LandCoverType, Double> landCoverAreas = new HashMap<LandCoverType, Double>(); //Mha + private Map<LandCoverType, Double> unprotectedAreas = new HashMap<LandCoverType, Double>(); //Mha + //private DoubleMap<LandCoverType, Integer, Double> minimumLandCover = new DoubleMap<LandCoverType, Integer, Double>(); //Minimum land cover by year of expiry (Mha) private double protectedArea; //protected area in Mha private double unavailableArea; //area unavailable due to altitude etc - private double suitableArea; + private double suitableArea; //Mha public LandUseItem() {} @@ -435,9 +436,10 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial return total; } + /* public double getMinimumLandCover(LandCoverType lcType, Integer year) { double area = 0; - Map<Integer, Double> yearMap = minimumLandCover.get(lcType); + Map<Integer, Double> yearMap = minimumLandCover.getInnerMap(lcType); for (Entry<Integer, Double> entry : yearMap.entrySet()) { if (entry.getKey() > year) { area += entry.getValue(); @@ -445,6 +447,7 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial } return area; } + */ @Override public String toString() { diff --git a/src/ac/ed/lurg/utils/DoubleMap.java b/src/ac/ed/lurg/utils/DoubleMap.java index 9c2762b3a7ea918cd876a173527655af034d5e2c..c94b232b25ccf0c1cd25a3a9355484dfb68b7f78 100644 --- a/src/ac/ed/lurg/utils/DoubleMap.java +++ b/src/ac/ed/lurg/utils/DoubleMap.java @@ -3,12 +3,13 @@ package ac.ed.lurg.utils; import java.util.HashMap; import java.util.Map; -public class DoubleMap<K, L, V extends Double> { +public class DoubleMap<K, L, V> { - Map<K, Map<L, Double>> theMap = new HashMap<K, Map<L, Double>>(); + // Stores a double mapped by two consecutive keys + 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) { diff --git a/src/ac/ed/lurg/utils/NestedMap.java b/src/ac/ed/lurg/utils/NestedMap.java index 54f72c9b9a326241846770277ffe9878286debe8..397f686f9c72616d2ad5d7016933090b9a016a9b 100644 --- a/src/ac/ed/lurg/utils/NestedMap.java +++ b/src/ac/ed/lurg/utils/NestedMap.java @@ -5,47 +5,35 @@ import java.util.HashMap; import java.util.Map; import java.util.List; -public class NestedMap { +public class NestedMap<K, V> { - Map<Object, Object> theMap; - Integer depth; + private final HashMap<K, NestedMap> node; + private V value; - NestedMap() { - theMap = new HashMap<Object, Object>(); + public NestedMap() { + node = new HashMap<>(); + value = null; } - 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)); + public void makeNode(K key) { + this.node.put(key, new NestedMap()); } - - 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; - } + + public NestedMap<K, V> getNode(K key) { + return this.node.get(key); } - /* - 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); - } + + public boolean hasNode(K key) { + return this.node.containsKey(key); } - */ - /* - private Map<Object, Object> getMapForKeys(List<Object> keys) { - Map<Object, Object> map = new HashMap<Object, Object>(); - + + public void setValue(V value) { + this.value = value; } - */ + + public V getValue() { + return value; + } + + } diff --git a/src/ac/ed/lurg/utils/TripleMap.java b/src/ac/ed/lurg/utils/TripleMap.java index 78a0dbb9136a1ec786771786055c6f024e4d85b7..11c6cf37136d7f1119c7a11490b29e14bef21d1a 100644 --- a/src/ac/ed/lurg/utils/TripleMap.java +++ b/src/ac/ed/lurg/utils/TripleMap.java @@ -3,7 +3,7 @@ package ac.ed.lurg.utils; import java.util.HashMap; import java.util.Map; -public class TripleMap<K, L, M, V extends Double> { +public class TripleMap<K, L, M, V> { Map<K, DoubleMap<L, M, V >> theMap = new HashMap<K, DoubleMap<L, M, V>>(); @@ -34,4 +34,8 @@ public class TripleMap<K, L, M, V extends Double> { return theMap.get(key); } + + public Map<K, DoubleMap<L, M, V >> getMap() { + return theMap; + } }