diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java index 6fc46c13b22a13b5d79d95e4edc4537af318c7bd..cf5ced4ca1ed4169c32f935b15075ddcd78534af 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 21154b03f31888fe9baa8f81d82f08e021733e84..5ceb915ffa39cb20eaf504c94ebf146824b12beb 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 92c684207d1e8850d0db24310808f2ecdc4d2f80..2b6b2e86c95aa98a1c7adc1bfd15f4aa4711e85c 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 771ec23089087bea10d7b4a4063abbb34780f6e8..5e4eb03220cba6fcc785cfcfcbd8e40f0349bc61 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 74ac942d4ef83baf780d35b8a3e3ec6d4eb249e7..b56b459127479426ea4b0a90256f26a18c26e8cc 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 a6d8b4b83d06c8fec04c73d42f3641013b0f3cd2..ebbc2e2e1ea6b7c8e18db80c24baf8a8b17968fa 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 019d50d9803c061f69949fa3f214b908ef4d85ab..4427ecb8d1918ce2d3bdba05331684086eb66a27 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 0000000000000000000000000000000000000000..b2d795edb0c6c74072838e95d282fd10e74e0ca9 --- /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 e464e43946f215be0f2a56b76923bac7e11af1a3..dbc9a8007326156b2ebb10bc58043e1bc969bf17 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 0000000000000000000000000000000000000000..76a7f4b4211c702d2e6cd961e19ba98658bc3560 --- /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); + } + } + } + } +}