From 2d43a3332ea41768268964d4a43d0ab77dc7f36b Mon Sep 17 00:00:00 2001 From: Bart Arendarczyk <s1924442@ed.ac.uk> Date: Fri, 26 May 2023 14:17:35 +0100 Subject: [PATCH] Added feature to force land cover change specified in external file. --- src/ac/ed/lurg/ModelConfig.java | 3 ++ src/ac/ed/lurg/ModelMain.java | 21 +++++++++++++- src/ac/ed/lurg/country/CountryAgent.java | 27 +++++++++++++---- .../ed/lurg/country/CountryAgentManager.java | 24 ++++++++++----- .../country/gams/GamsLocationOptimiser.java | 2 +- .../lurg/country/gams/GamsLocationOutput.java | 3 +- .../country/gams/GamsRasterOptimiser.java | 2 +- src/ac/ed/lurg/landuse/ForcedLccItem.java | 24 +++++++++++++++ .../LandCoverChangeItem.java | 17 ++--------- .../lurg/landuse/LandCoverChangeReader.java | 29 +++++++++++++++++++ 10 files changed, 120 insertions(+), 32 deletions(-) create mode 100644 src/ac/ed/lurg/landuse/ForcedLccItem.java rename src/ac/ed/lurg/{country => landuse}/LandCoverChangeItem.java (61%) create mode 100644 src/ac/ed/lurg/landuse/LandCoverChangeReader.java diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java index 6fc46c13..cf5ced4c 100755 --- a/src/ac/ed/lurg/ModelConfig.java +++ b/src/ac/ed/lurg/ModelConfig.java @@ -554,6 +554,9 @@ public class ModelConfig { public static final double CONSTANT_PROTECTED_AREA_RATE = getDoubleProperty("CONSTANT_PROTECTED_AREA_RATE", Double.NaN); public static final boolean HALFEARTH = getBooleanProperty("HALFEARTH", false); + public static final boolean FORCE_LCC = getBooleanProperty("FORCE_LCC", false); + public static final String FORCED_LCC_FILES_DIR = getProperty("FORCED_LCC_FILES_DIR", OUTPUT_DIR); + public static final boolean USE_CRAFTY_COUNTRIES = getBooleanProperty("USE_CRAFTY_COUNTRIES", false); public static final String CRAFTY_COUNTRIES_FILE= getProperty("CRAFTY_COUNTRIES_FILE", DATA_DIR + File.separator + "craftyCountries.csv"); public static final String CRAFTY_PRODUCTION_DIR = getProperty("CRAFTY_PRODUCTION_DIR", OUTPUT_DIR + File.separator + "crafty"); diff --git a/src/ac/ed/lurg/ModelMain.java b/src/ac/ed/lurg/ModelMain.java index 21154b03..5ceb915f 100644 --- a/src/ac/ed/lurg/ModelMain.java +++ b/src/ac/ed/lurg/ModelMain.java @@ -112,10 +112,14 @@ public class ModelMain { getUpdateIrrigationData(timestep); // updating currentIrrigationData // When running half earth we can to alter protected areas data at a point in time - if(ModelConfig.HALFEARTH && ModelConfig.FORCE_PROTECTED_AREAS_START_YEAR == timestep.getYear() && !ModelConfig.IS_CALIBRATION_RUN) { + if (ModelConfig.HALFEARTH && ModelConfig.FORCE_PROTECTED_AREAS_START_YEAR == timestep.getYear() && !ModelConfig.IS_CALIBRATION_RUN) { new ProtectedAreasReader(globalLandUseRaster).getRasterDataFromFile(ModelConfig.HALF_EARTH_FILE); countryAgents.updateProtectedAreasForAll(globalLandUseRaster); } + + if (ModelConfig.FORCE_LCC) { + forceLandCoverChanges(timestep); + } getWoodYieldData(timestep); getCarbonFluxData(timestep); @@ -875,6 +879,21 @@ public class ModelMain { currentIrrigationData.updateIrrigConstraints(timestep); } } + + private void forceLandCoverChanges(Timestep timestep) { + String filePath = ModelConfig.FORCED_LCC_FILES_DIR + File.separator + "forcedLcc" + timestep.getYear() + ".txt"; + File file = new File(filePath); + if (file.exists()) { + RasterSet<ForcedLccItem> forcedLccRaster = new RasterSet<ForcedLccItem>(desiredProjection) { + protected ForcedLccItem createRasterData() { + return new ForcedLccItem(); + } + }; + LandCoverChangeReader lccReader = new LandCoverChangeReader(forcedLccRaster); + lccReader.getRasterDataFromFile(filePath); + countryAgents.forceLandCoverChangesForAll(forcedLccRaster); + } + } private void serializeCheckpoint() { serializeLandUse(globalLandUseRaster); diff --git a/src/ac/ed/lurg/country/CountryAgent.java b/src/ac/ed/lurg/country/CountryAgent.java index 92c68420..2b6b2e86 100644 --- a/src/ac/ed/lurg/country/CountryAgent.java +++ b/src/ac/ed/lurg/country/CountryAgent.java @@ -13,14 +13,9 @@ import ac.ed.lurg.country.gams.GamsRasterOptimiser; import ac.ed.lurg.country.gams.GamsRasterOutput; import ac.ed.lurg.demand.AbstractDemandManager; import ac.ed.lurg.forestry.WoodYieldItem; -import ac.ed.lurg.landuse.CarbonUsageData; -import ac.ed.lurg.landuse.CropUsageData; -import ac.ed.lurg.landuse.IrrigationItem; -import ac.ed.lurg.landuse.LandUseItem; +import ac.ed.lurg.landuse.*; 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; import ac.ed.lurg.types.CropType; import ac.ed.lurg.types.LandCoverType; @@ -347,6 +342,26 @@ public class CountryAgent extends AbstractCountryAgent { } } + + public void forceLandCoverChanges(RasterSet<ForcedLccItem> lccRaster) { + for (Map.Entry<RasterKey, ForcedLccItem> entry : lccRaster.entrySet()) { + RasterKey key = entry.getKey(); + ForcedLccItem lccItem = entry.getValue(); + if (previousGamsRasterOutput.getLandUses().containsKey(key)) { + LandUseItem landUseItem = previousGamsRasterOutput.getLandUses().get(key); + Map<LandCoverType, Map<LandCoverType, Double>> lccMap = lccItem.getFractions(); + for (LandCoverType fromLc : lccMap.keySet()) { + Map<LandCoverType, Double> toMap = lccMap.get(fromLc); + for (LandCoverType toLc : toMap.keySet()) { + double fraction = toMap.get(toLc); + double previousArea = landUseItem.getLandCoverArea(fromLc, LandProtectionType.CONVERTIBLE); + double areaToMove = previousArea * fraction; + landUseItem.moveAreas(toLc, fromLc, areaToMove); + } + } + } + } + } public CarbonUsageData getCarbonUsageData() { return previousGamsRasterOutput.getCarbonUsageData(); diff --git a/src/ac/ed/lurg/country/CountryAgentManager.java b/src/ac/ed/lurg/country/CountryAgentManager.java index 771ec230..5e4eb032 100644 --- a/src/ac/ed/lurg/country/CountryAgentManager.java +++ b/src/ac/ed/lurg/country/CountryAgentManager.java @@ -22,16 +22,10 @@ import ac.ed.lurg.country.crafty.CraftyProdManager; import ac.ed.lurg.demand.AbstractDemandManager; import ac.ed.lurg.forestry.WoodYieldItem; import ac.ed.lurg.forestry.WoodYieldRasterSet; -import ac.ed.lurg.landuse.CarbonUsageData; -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.landuse.*; 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; import ac.ed.lurg.types.WoodType; import ac.ed.lurg.utils.LogWriter; @@ -190,6 +184,22 @@ public class CountryAgentManager { ca.updateProtectedAreas(newPA); } } + + public void forceLandCoverChangesForAll(RasterSet<ForcedLccItem> lccRaster) { + for (CountryAgent ca : gamsCountryAgents) { + Collection<RasterKey> countryKeys = countryBoundaryRaster.getKeysFor(ca.getCountry()); + RasterSet<ForcedLccItem> lccRasterForCountry = new RasterSet<ForcedLccItem>(lccRaster.getHeaderDetails()); + for (RasterKey key : countryKeys) { + if (lccRaster.containsKey(key)) { + lccRasterForCountry.put(key, lccRaster.get(key)); + } + } + if (!lccRasterForCountry.isEmpty()) { + ca.forceLandCoverChanges(lccRasterForCountry); + } + + } + } public void serializeCropUsageForAll() { Map<CompositeCountry, Map<CropType, CropUsageData>> cropUsageDataMap = new HashMap<CompositeCountry, Map<CropType, CropUsageData>>(); diff --git a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java index 74ac942d..b56b4591 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java @@ -27,7 +27,7 @@ import com.gams.api.GAMSWorkspaceInfo; import ac.ed.lurg.ModelConfig; import ac.ed.lurg.carbon.CarbonFluxItem; import ac.ed.lurg.country.CountryPrice; -import ac.ed.lurg.country.LandCoverChangeItem; +import ac.ed.lurg.landuse.LandCoverChangeItem; import ac.ed.lurg.country.TradeConstraint; import ac.ed.lurg.forestry.WoodYieldData; import ac.ed.lurg.landuse.CarbonUsageData; diff --git a/src/ac/ed/lurg/country/gams/GamsLocationOutput.java b/src/ac/ed/lurg/country/gams/GamsLocationOutput.java index a6d8b4b8..ebbc2e2e 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationOutput.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationOutput.java @@ -1,6 +1,5 @@ package ac.ed.lurg.country.gams; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -12,7 +11,7 @@ import ac.ed.lurg.landuse.LandUseItem; import ac.ed.lurg.landuse.WoodUsageData; import ac.ed.lurg.types.CropType; import ac.ed.lurg.types.WoodType; -import ac.ed.lurg.country.LandCoverChangeItem; +import ac.ed.lurg.landuse.LandCoverChangeItem; public class GamsLocationOutput { ModelStat status; diff --git a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java index 019d50d9..4427ecb8 100644 --- a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java @@ -5,7 +5,7 @@ import java.util.Map.Entry; import ac.ed.lurg.ModelConfig; import ac.ed.lurg.carbon.CarbonFluxItem; -import ac.ed.lurg.country.LandCoverChangeItem; +import ac.ed.lurg.landuse.LandCoverChangeItem; import ac.ed.lurg.forestry.WoodYieldData; import ac.ed.lurg.forestry.WoodYieldItem; import ac.ed.lurg.landuse.*; diff --git a/src/ac/ed/lurg/landuse/ForcedLccItem.java b/src/ac/ed/lurg/landuse/ForcedLccItem.java new file mode 100644 index 00000000..b2d795ed --- /dev/null +++ b/src/ac/ed/lurg/landuse/ForcedLccItem.java @@ -0,0 +1,24 @@ +package ac.ed.lurg.landuse; + +import ac.ed.lurg.types.LandCoverType; +import ac.sac.raster.RasterItem; + +import java.util.HashMap; +import java.util.Map; + +public class ForcedLccItem implements RasterItem { + private final Map<LandCoverType, Map<LandCoverType, Double>> fractions; + + public ForcedLccItem() { + fractions = new HashMap<>(); + } + + public void setFraction(LandCoverType fromLc, LandCoverType toLc, double fract) { + Map<LandCoverType, Double> toMap = fractions.computeIfAbsent(fromLc, k -> new HashMap<>()); + toMap.put(toLc, fract); + } + + public Map<LandCoverType, Map<LandCoverType, Double>> getFractions() { + return fractions; + } +} diff --git a/src/ac/ed/lurg/country/LandCoverChangeItem.java b/src/ac/ed/lurg/landuse/LandCoverChangeItem.java similarity index 61% rename from src/ac/ed/lurg/country/LandCoverChangeItem.java rename to src/ac/ed/lurg/landuse/LandCoverChangeItem.java index e464e439..dbc9a800 100644 --- a/src/ac/ed/lurg/country/LandCoverChangeItem.java +++ b/src/ac/ed/lurg/landuse/LandCoverChangeItem.java @@ -1,11 +1,11 @@ -package ac.ed.lurg.country; +package ac.ed.lurg.landuse; import ac.ed.lurg.types.LandCoverType; +import ac.sac.raster.RasterItem; -public class LandCoverChangeItem { +public class LandCoverChangeItem implements RasterItem { private LandCoverType fromLandCover; private LandCoverType toLandCover; - private int age; private double area; public LandCoverChangeItem() {} @@ -16,13 +16,6 @@ public class LandCoverChangeItem { this.area = area; } - public LandCoverChangeItem(LandCoverType fromLandCover, LandCoverType toLandCover, int age, double area) { - this.fromLandCover = fromLandCover; - this.toLandCover = toLandCover; - this.age = age; - this.area = area; - } - public LandCoverType getFromLandCover() { return fromLandCover; } @@ -31,10 +24,6 @@ public class LandCoverChangeItem { return toLandCover; } - public int getAge() { - return age; - } - public double getArea() { return area; } diff --git a/src/ac/ed/lurg/landuse/LandCoverChangeReader.java b/src/ac/ed/lurg/landuse/LandCoverChangeReader.java new file mode 100644 index 00000000..76a7f4b4 --- /dev/null +++ b/src/ac/ed/lurg/landuse/LandCoverChangeReader.java @@ -0,0 +1,29 @@ +package ac.ed.lurg.landuse; + +import ac.ed.lurg.types.LandCoverType; +import ac.sac.raster.AbstractTabularRasterReader; +import ac.sac.raster.RasterKey; +import ac.sac.raster.RasterSet; + +import java.util.Map; + +public class LandCoverChangeReader extends AbstractTabularRasterReader<ForcedLccItem> { + private static final int MIN_COLS = 3; + + public LandCoverChangeReader(RasterSet<ForcedLccItem> lccRaster) { + super(" +", MIN_COLS, lccRaster); + } + + @Override + protected void setData(RasterKey key, ForcedLccItem item, Map<String, Double> rowValues) { + for (LandCoverType fromLc : LandCoverType.values()) { + for (LandCoverType toLc : LandCoverType.values()) { + String colName = fromLc.getName() + "->" + toLc.getName(); + if (rowValues.containsKey(colName)) { + double fract = getValueForCol(rowValues, colName); + item.setFraction(fromLc, toLc, fract); + } + } + } + } +} -- GitLab