diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java index 8f4c6f1d31fadb0149a6471d0635047370941363..2a0aeba990e25a447f90fc84e29f62c8a12a1f46 100644 --- a/src/ac/ed/lurg/ModelConfig.java +++ b/src/ac/ed/lurg/ModelConfig.java @@ -318,5 +318,8 @@ public class ModelConfig { public static final int NUM_YIELD_CLUSTERS = getIntProperty("NUM_YIELD_CLUSTERS", 8000); public static final long RANDOM_SEED = getIntProperty("RANDOM_SEED", 1974329); // any number will do - + // Protected areas forcing parameters + public static final boolean FORCE_PROTECTED_AREAS = IS_CALIBRATION_RUN ? false : getBooleanProperty("FORCE_PROTECTED_AREAS", false); + public static final int FORCE_PROTECTED_AREAS_START_YEAR = getIntProperty("FORCE_PROTECTED_AREAS_START_YEAR", 2020); + public static final int FORCE_PROTECTED_AREAS_END_YEAR = getIntProperty("FORCE_PROTECTED_AREAS_END_YEAR", 2050); } diff --git a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java index 3df7848829c0673de98cb47706e282cf89d74b31..ce2992fe81651c47cb86a3ab0053a986254f511d 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java @@ -106,7 +106,7 @@ public class GamsLocationOptimiser { String locString = Integer.toString(locationId); LandUseItem landUseItem = entry.getValue(); - double suitableLand = landUseItem.getSuitableLand(); + double suitableLand = landUseItem.getSuitableLand(inputData.getTimestep().getYear()); totalSuitable += suitableLand; if (DEBUG) LogWriter.println(String.format(" %d %15s,\t %.3f", locationId, "suitableLand", suitableLand)); setGamsParamValueTruncate(landP.addRecord(locString), suitableLand, 3); diff --git a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java index 8e1d8764812dc7fe8045ac8e77da8ad00afac775..ca9f71d8b8246cb700b79cdb358f22eb539efc00 100644 --- a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java @@ -76,17 +76,15 @@ public class GamsRasterOptimiser { LogWriter.printlnError("Total Area " + comment + ": " + l.getName() + ": " + total); } - double unprotectedNatural=0, suitableArea=0, protectedArea=0, unprotectedArea=0; + double unprotectedNatural=0, suitableArea=0, protectedArea=0; for (LandUseItem a : areaRaster.values()) { if (a != null) { protectedArea += a.getProtectedArea(); - unprotectedArea += a.getUnprotectedArea(); unprotectedNatural += a.getUnprotectedNatural(); - suitableArea += a.getSuitableLand(); + suitableArea += a.getSuitableLand(rasterInputData.getTimestep().getYear()); } } LogWriter.println("Total protectedArea " + comment + ": " + protectedArea); - LogWriter.println("Total unprotectedArea " + comment + ": " + unprotectedArea); LogWriter.println("Total unprotectedNatural " + comment + ": " + unprotectedNatural); LogWriter.println("Total suitableArea " + comment + ": " + suitableArea); } @@ -120,17 +118,17 @@ public class GamsRasterOptimiser { LogWriter.println("croplandChange" + croplandChange); } - double prevUnprotectedManagedForest = 0, prevUnprotectedUnmanagedForest = 0, prevUnprotectedNatural = 0; + double prevManagedForest = 0, prevUnmanagedForest = 0, prevNatural = 0; for (LandUseItem luItem: landUseItemsForLocation.values()) { - prevUnprotectedManagedForest += luItem.getUnprotectedLandCoverArea(LandCoverType.MANAGED_FOREST); - prevUnprotectedUnmanagedForest += luItem.getUnprotectedLandCoverArea(LandCoverType.UNMANAGED_FOREST); - prevUnprotectedNatural += luItem.getUnprotectedNatural(); + prevManagedForest += luItem.getLandCoverArea(LandCoverType.MANAGED_FOREST); + prevUnmanagedForest += luItem.getLandCoverArea(LandCoverType.UNMANAGED_FOREST); + prevNatural += luItem.getTotalNatural(); } - double prevForestTotal = prevUnprotectedManagedForest + prevUnprotectedUnmanagedForest; - double prevForestToNaturalFraction = (prevUnprotectedNatural > 0) ? prevForestTotal / prevUnprotectedNatural : 0; - double prevForestManagedFraction = (prevForestTotal > 0) ? prevUnprotectedManagedForest / prevForestTotal : 0; + double prevForestTotal = prevManagedForest + prevUnmanagedForest; + double prevForestToNaturalFraction = (prevNatural > 0) ? prevForestTotal / prevNatural : 0; + double prevForestManagedFraction = (prevForestTotal > 0) ? prevManagedForest / prevForestTotal : 0; double pastureFromCrop = 0; double pastureFromNatural = 0; @@ -335,8 +333,8 @@ public class GamsRasterOptimiser { IrrigationItem aggIrig = aggregatedIrrigCosts.lazyGet(clusterId); // Irrigation cost - double suitableAreaThisTime = landUseItem.getSuitableLand(); - double suitableAreaSoFar = aggLandUse.getSuitableLand(); + double suitableAreaThisTime = landUseItem.getSuitableLand(rasterInputData.getTimestep().getYear()); + double suitableAreaSoFar = aggLandUse.getSuitableLand(rasterInputData.getTimestep().getYear()); if (irrigItem!= null) { aggIrig.setIrrigCost( aggregateMean(aggIrig.getIrrigCost(), suitableAreaSoFar, irrigItem.getIrrigCost(), suitableAreaThisTime)); @@ -379,12 +377,12 @@ public class GamsRasterOptimiser { aggLandUse.setIntensity(crop, intensityThisTime); // intensity currently is always the same within a location, so can just that any. If this changes need to average here. } - // Unavailable Fraction - confusingly, this must be done before protected areas and land covers are set due to getUnprotectedArea() call - double unprotectedAreaSoFar = aggLandUse.getUnprotectedArea(); - double unprotectedAreaThisTime = landUseItem.getUnprotectedArea(); + // Unavailable Fraction + double totalAreaSoFar = aggLandUse.getTotalLandCoverArea(); + double totalAreaThisTime = landUseItem.getTotalLandCoverArea(); double unavailFractThisTime = landUseItem.getUnavailableFract(); double unavailFractSoFar = aggLandUse.getUnavailableFract(); - double averagedUnavailFract = aggregateMean(unavailFractSoFar, unprotectedAreaSoFar, unavailFractThisTime, unprotectedAreaThisTime); + double averagedUnavailFract = aggregateMean(unavailFractSoFar, totalAreaSoFar, unavailFractThisTime, totalAreaThisTime); aggLandUse.setUnavailableFract(averagedUnavailFract); // Protected areas diff --git a/src/ac/ed/lurg/landuse/LandUseItem.java b/src/ac/ed/lurg/landuse/LandUseItem.java index 7c40083be3df0d1dd5150d21e2ac2947bf5289b1..b933746bbcedcc12bf0c9640087a60168538d5ff 100644 --- a/src/ac/ed/lurg/landuse/LandUseItem.java +++ b/src/ac/ed/lurg/landuse/LandUseItem.java @@ -50,10 +50,6 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial return unavailableFract; } - public double getUnprotectedArea() { - return getTotalLandCoverArea()-getProtectedArea(); - } - public Intensity getIntensity(CropType crop) { return intensityMap.get(crop); } @@ -241,43 +237,60 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial return total; } + public double getTotalNatural() { + double totalNatural = getLandCoverArea(LandCoverType.OTHER_NATURAL) + getLandCoverArea(LandCoverType.MANAGED_FOREST) + getLandCoverArea(LandCoverType.UNMANAGED_FOREST); + return totalNatural; + } + /** averages protected areas across land cover types */ public double getUnprotectedLandCoverArea(LandCoverType c) { double lcTypeArea = getLandCoverArea(c); if (c.isProtectable()) { - double unprotectedNaturalFract = getUnprotectedNaturalFract(); - return lcTypeArea * unprotectedNaturalFract; + double unprotectedNat = getUnprotectedNatural(); + double totalNatural = getTotalNatural(); + double unprotectedFract = (totalNatural > 0) ? unprotectedNat/totalNatural : 0; + return lcTypeArea * unprotectedFract; } else { return lcTypeArea; } } - private double getUnprotectedNaturalFract() { - double unprotectedNat = getUnprotectedNatural(); - double totalNatural = getLandCoverArea(LandCoverType.OTHER_NATURAL) + getLandCoverArea(LandCoverType.MANAGED_FOREST) + getLandCoverArea(LandCoverType.UNMANAGED_FOREST); - double unprotectedFract = (totalNatural > 0) ? unprotectedNat/totalNatural : 0; - return unprotectedFract; - } - - public double getUnprotectedNatural() { + private double getDesiredProtected() { double totalLand = getTotalLandCoverArea(); if (totalLand <=0) return 0; - double totalNatural = getLandCoverArea(LandCoverType.OTHER_NATURAL) + getLandCoverArea(LandCoverType.MANAGED_FOREST) + getLandCoverArea(LandCoverType.UNMANAGED_FOREST); - double protectedFract = getProtectedArea() / totalLand; double minAndProtectedA = totalLand * (1 - (1-protectedFract) * (1-unavailableFract) * (1-ModelConfig.MIN_NATURAL_RATE)); - - double unprotectedNat = Math.max(0, totalNatural - minAndProtectedA); // if we are already using more than is protected then the unprotectedArea is 0 + return minAndProtectedA; + } + + public double getUnprotectedNatural() { + double desiredProtected = getDesiredProtected(); + double totalNatural = getTotalNatural(); + double unprotectedNat = Math.max(0, totalNatural - desiredProtected); // if we are already using more than is protected then the unprotectedArea is 0 return unprotectedNat; } - public double getSuitableLand() { - double totalUnprotectedNatural = getUnprotectedNatural(); + public double getSuitableLand(int year) { + double suitable; double currentAgri = getLandCoverArea(LandCoverType.PASTURE) + getLandCoverArea(LandCoverType.CROPLAND); - double suitable = currentAgri + totalUnprotectedNatural; + double desiredProtected = getDesiredProtected(); + double totalNatural = getTotalNatural(); + double natAvailForAgri = totalNatural - desiredProtected; // could be negative, i.e. excess agricultural area already used + + if (ModelConfig.FORCE_PROTECTED_AREAS && natAvailForAgri < 0 && year >= ModelConfig.FORCE_PROTECTED_AREAS_START_YEAR) { + double proportion = 1; + + if (year < ModelConfig.FORCE_PROTECTED_AREAS_END_YEAR) + proportion = 1.0 / (ModelConfig.FORCE_PROTECTED_AREAS_END_YEAR - year); + + suitable = Math.max(0, currentAgri + natAvailForAgri * proportion); // netNatAvailForAgri is negative, but suitable area < 0 is not sensible (seems to happen with high barren areas) + } + else + suitable = currentAgri + Math.max(0, natAvailForAgri); // should be identical to currentAgri + getUnprotectedNatural() in this case + return suitable; } @@ -369,6 +382,6 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial @Override public String toString() { - return "LandUseItem: [landCoverAreas=" + landCoverAreas + ", protectedArea=" + protectedArea + "], suitableLand " + getSuitableLand(); + return "LandUseItem: [landCoverAreas=" + landCoverAreas + ", protectedArea=" + protectedArea + ", unavailableFract=" + unavailableFract + "]"; } } \ No newline at end of file diff --git a/src/ac/ed/lurg/output/LandUseOutputer.java b/src/ac/ed/lurg/output/LandUseOutputer.java index a6b99151dd697b915d0d202adeb2eec78a36bd4a..2e181271f883c0dca5694d030dbbc6d6dcddd8e6 100644 --- a/src/ac/ed/lurg/output/LandUseOutputer.java +++ b/src/ac/ed/lurg/output/LandUseOutputer.java @@ -57,7 +57,7 @@ public class LandUseOutputer extends AbstractLandUseOutputer { StringBuffer sbData = new StringBuffer(String.format("%.2f %.2f", lat, lon)); sbData.append(String.format(" %.8f", item.getTotalLandCoverArea())); - sbData.append(String.format(" %.8f", item.getSuitableLand())); + sbData.append(String.format(" %.8f", item.getSuitableLand(year))); for (LandCoverType cover : LandCoverType.values()) { sbData.append(String.format(" %.8f", item.getLandCoverArea(cover)));