diff --git a/config.properties b/config.properties index 8ac5a792d734f459a81d0ff8d0f4455672110a2f..604560a832717535b2aa0417bb47086df60cb8eb 100644 --- a/config.properties +++ b/config.properties @@ -3,27 +3,28 @@ BASE_DIR=C:/Users/s1924442/git/plumv2 YIELD_DIR=C:/Users/s1924442/Documents/PhD/LURG/rcp60 YIELD_DIR_TOP=rcp60 -OUTPUT_DIR = C:/Users/s1924442/Documents/PhD/PLUM outputs/forest_calib +CALIB_DIR=C:/Users/s1924442/Documents/PhD/PLUM outputs/forest_calib +OUTPUT_DIR = C:/Users/s1924442/Documents/PhD/PLUM outputs/forest_test WOOD_AND_CARBON_DIR = C:/Users/s1924442/Documents/PhD/Carbon and wood yields/forestry_dummy_4 BASE_YEAR=2010 START_TIMESTEP=0 TIMESTEP_SIZE=1 -END_TIMESTEP=10 +END_TIMESTEP=0 -IS_CALIBRATION_RUN=true -END_FIRST_STAGE_CALIBRATION=0 +IS_CALIBRATION_RUN=false +END_FIRST_STAGE_CALIBRATION=1 GENERATE_NEW_YIELD_CLUSTERS=false YIELD_FILENAME=yield.out DEBUG_LIMIT_COUNTRIES=true -DEBUG_COUNTRY_NAME=Central America -GAMS_COUNTRY_TO_SAVE=Central America +DEBUG_COUNTRY_NAME=United Kingdom +GAMS_COUNTRY_TO_SAVE=United Kingdom -INIT_WOOD_PRICE=0.4 +INIT_WOOD_PRICE=0.04 INIT_WOOD_STOCK=1000 INIT_CARBON_PRICE=0.0 INFRASTRUCTURE_EXPANSION_COST=0.0 @@ -33,6 +34,6 @@ FOREST_MANAGEMENT_COST=0.25 FOREST_MAX_CHANGE=0.02 LAND_CHANGE_COST=0.5 NATURAL_AREA_VALUE=0.0 -VEGETATION_CLEARING_COST=0.05 +VEGETATION_CLEARING_COST=0.02 IS_FORESTRY_ON=true -IS_CARBON_ON=true +IS_CARBON_ON=false diff --git a/src/ac/ed/lurg/carbon/CarbonFluxItem.java b/src/ac/ed/lurg/carbon/CarbonFluxItem.java index 3514e65a58ae7394b6bb85f03fab280c28358ad5..9dd7c6dbece4fc3651e592f849988179bca474c5 100644 --- a/src/ac/ed/lurg/carbon/CarbonFluxItem.java +++ b/src/ac/ed/lurg/carbon/CarbonFluxItem.java @@ -10,6 +10,7 @@ import ac.ed.lurg.Timestep; import ac.ed.lurg.landuse.LandCoverTile; import ac.ed.lurg.landuse.LccKey; import ac.ed.lurg.types.LandCoverType; +import ac.ed.lurg.types.LandProtectionType; public class CarbonFluxItem implements RasterItem, Serializable { private static final long serialVersionUID = 440720456140537815L; @@ -24,13 +25,13 @@ public class CarbonFluxItem implements RasterItem, Serializable { public void calcConversionCarbonFlux(LccKey key, Double[] cFluxes, Map<LandCoverType, LandCoverTile> landUseTiles, Timestep timestep) { LandCoverTile tiles = landUseTiles.get(key.getFromLc()); - double totalArea = tiles.getTotalConvertibleArea(); + double totalArea = tiles.getTotalArea(LandProtectionType.CONVERTIBLE); if (totalArea == 0) { this.conversionCarbonFlux.put(key, 0.0); } else { double totalFlux = 0; - for (int age=0; age<=tiles.getMaxAgeBin(); age++) { - totalFlux += cFluxes[age] * tiles.getConvertibleArea(age); + for (int age=0; age<=LandCoverTile.getMaxAgeBin(); age++) { + totalFlux += cFluxes[age] * tiles.getArea(LandProtectionType.CONVERTIBLE, age); } double meanFlux = totalFlux / totalArea; this.conversionCarbonFlux.put(key, meanFlux); @@ -45,13 +46,13 @@ public class CarbonFluxItem implements RasterItem, Serializable { LandCoverTile tiles = landUseTiles.get(lcType); - double totalArea = tiles.getTotalConvertibleArea(); + double totalArea = tiles.getTotalArea(LandProtectionType.CONVERTIBLE); if (totalArea == 0) { this.ecosystemCarbonFlux.put(lcType, 0.0); } else { double totalFlux = 0; - for (int age=0; age<=tiles.getMaxAgeBin(); age++) { - totalFlux += cFluxes[age] * tiles.getConvertibleArea(age); + for (int age=0; age<=LandCoverTile.getMaxAgeBin(); age++) { + totalFlux += cFluxes[age] * tiles.getArea(LandProtectionType.CONVERTIBLE, age); } double meanFlux = totalFlux / totalArea; this.ecosystemCarbonFlux.put(lcType, meanFlux); diff --git a/src/ac/ed/lurg/forestry/WoodYieldItem.java b/src/ac/ed/lurg/forestry/WoodYieldItem.java index e3da5d72aba0015993bb2bd7fe061fc6f9dc56f7..049715c779633fc187cd07e738178d45775cf080 100644 --- a/src/ac/ed/lurg/forestry/WoodYieldItem.java +++ b/src/ac/ed/lurg/forestry/WoodYieldItem.java @@ -10,6 +10,7 @@ import ac.ed.lurg.Timestep; import ac.ed.lurg.landuse.LandCoverTile; import ac.ed.lurg.landuse.LccKey; import ac.ed.lurg.types.LandCoverType; +import ac.ed.lurg.types.LandProtectionType; import ac.sac.raster.RasterItem; public class WoodYieldItem implements RasterItem { @@ -31,13 +32,13 @@ public class WoodYieldItem implements RasterItem { LandCoverTile tiles = landUseTiles.get(key.getFromLc()); - double totalArea = tiles.getTotalConvertibleArea(); // Assuming no harvest from protected areas + double totalArea = tiles.getTotalArea(LandProtectionType.CONVERTIBLE); // Assuming no harvest from protected areas if (totalArea == 0) { this.yield.put(key, 0.0) ; } else { double totalYield = 0; for (int age=0; age<=LandCoverTile.getMaxAgeBin(); age++) { - totalYield += yields[age] * tiles.getConvertibleArea(age); + totalYield += yields[age] * tiles.getArea(LandProtectionType.CONVERTIBLE, age); } double meanYield = totalYield / totalArea; @@ -70,11 +71,11 @@ public class WoodYieldItem implements RasterItem { final double OVER_ROTA_AGE_HARVEST_PROP = 0.05; LandCoverTile timberTiles = landUseTiles.get(LandCoverType.TIMBER_FOREST); - double timberForestArea = timberTiles.getTotalConvertibleArea(); + double timberForestArea = timberTiles.getTotalArea(LandProtectionType.CONVERTIBLE); if (timberForestArea == 0) { currentRotationHarvest = 0.0; } else { - currentRotationHarvest += timberTiles.getConvertibleArea(optimalRotation) * yieldAtRotation; + currentRotationHarvest += timberTiles.getArea(LandProtectionType.CONVERTIBLE, optimalRotation) * yieldAtRotation; /* timberTiles.resetAreaForAge(optimalRotation); // WARNING: side effect diff --git a/src/ac/ed/lurg/landuse/LandCoverTile.java b/src/ac/ed/lurg/landuse/LandCoverTile.java index 73c2b0f5e9969370218efbe32f3a66547457e776..b79af9b860b097f3d2cff7cce1338c5df4170e25 100644 --- a/src/ac/ed/lurg/landuse/LandCoverTile.java +++ b/src/ac/ed/lurg/landuse/LandCoverTile.java @@ -2,161 +2,102 @@ package ac.ed.lurg.landuse; import java.io.Serializable; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import ac.ed.lurg.ModelConfig; import ac.ed.lurg.utils.LogWriter; import ac.sac.raster.InterpolatingRasterItem; +import ac.ed.lurg.types.LandProtectionType; public class LandCoverTile implements Serializable, InterpolatingRasterItem<LandCoverTile> { private static final long serialVersionUID = 3208516181615267472L; private static final int MAX_AGE = 250; - private Double[] convertibleAreas; // area Mha; index = age - private Double[] protectedAreas; // area Mha; index = age - private double unavailableArea; // unavailable for conversion due to slope, altitude TODO age? + private Map<LandProtectionType, LandParcel> areas; public LandCoverTile() { - this.convertibleAreas = new Double[MAX_AGE+1]; - this.protectedAreas = new Double[MAX_AGE+1]; - Arrays.fill(convertibleAreas, 0.0); - Arrays.fill(protectedAreas, 0.0); - unavailableArea = 0.0; + this.areas = new HashMap<LandProtectionType, LandParcel>(); + for (LandProtectionType lpType : LandProtectionType.values()) { + areas.put(lpType, new LandParcel()); + } } - public double getConvertibleArea(int age) { - return convertibleAreas[age]; - } - - public void setConvertibleArea(int age, double area) { - convertibleAreas[age] = area; + public double getArea(LandProtectionType lpType, int age) { + return areas.get(lpType).get(age); } - public void addConvertibleArea(double a) { - convertibleAreas[0] += a; + public void addArea(LandProtectionType lpType, double a) { + areas.get(lpType).add(0, a); // new area is always age=0 } - public double getTotalConvertibleArea() { - double total = 0; - for (double d : convertibleAreas) { - total += d; - } - return total; + public void addArea(LandProtectionType lpType, int age, double a) { + areas.get(lpType).add(age, a); } - public void removeConvertibleArea(double a) { // Subtracts area uniformly - if (a <= 0) - return; - double totalArea = getTotalConvertibleArea(); - double areaToRemove = Math.min(totalArea, a); - if (Math.abs(a - areaToRemove) > 1e-10) { - LogWriter.printlnError("LandCoverTile.removeConvertibleArea: attempting to remove too much area: " + a + ", available: " + totalArea); - } - double factor = (totalArea - areaToRemove) / totalArea; - for (int i=0; i<convertibleAreas.length; i++) { - convertibleAreas[i] *= factor; - } + public void setArea(LandProtectionType lpType, int age, double a) { + areas.get(lpType).set(age, a); } - public double getProtectedArea(int age) { - return protectedAreas[age]; + public double getTotalArea(LandProtectionType lpType) { + return areas.get(lpType).getTotal(); } - public void setProtectedArea(int age, double area) { - protectedAreas[age] = area; + public void removeArea(LandProtectionType lpType, double a) { // Subtracts area uniformly + areas.get(lpType).subtractUniform(a); } - public void addProtectedArea(double d) { - protectedAreas[0] += d; - + public void removeArea(LandProtectionType lpType, int age, double a) { + areas.get(lpType).subtract(age, a); } - public double getTotalProtectedArea() { - double total = 0; - for (double d : protectedAreas) { - total += d; - } - return total; - } - - public void removeProtectedArea(double a) { // Subtracts area uniformly - if (a <= 0) - return; - double totalArea = getTotalProtectedArea(); - double areaToRemove = a; - if (a > totalArea) { - LogWriter.printlnError("LandCoverTile.removeProtectedArea: attempting to remove too much area: " + a + ", available: " + totalArea); - areaToRemove = totalArea; - } - double factor = (totalArea - areaToRemove) / totalArea; - for (int i=0; i<protectedAreas.length; i++) { - protectedAreas[i] *= factor; - } - } - - public double getUnavailableArea() { - return unavailableArea; - } - - public void addUnavailableArea(double d) { - unavailableArea += d; - } - public double getTotalArea() { - return getTotalConvertibleArea() + getTotalProtectedArea() + unavailableArea; + double area = 0; + for (LandProtectionType lpType : LandProtectionType.values()) { + area += getTotalArea(lpType); + } + return area; } - public void resetAreaForAge(int age) { - convertibleAreas[0] += convertibleAreas[age]; - convertibleAreas[age] = 0.0; + public void resetAreaForAge(LandProtectionType lpType, int age) { + areas.get(lpType).resetAge(age); } - public void resetAreaForAge(int age, double area) { - if (area > getConvertibleArea(age)) { + public void resetAreaForAge(LandProtectionType lpType, int age, double area) { + if (area > getArea(lpType, age)) { LogWriter.printlnError("LandCoverTile.resetAreaForAge: not enough area"); return; } - convertibleAreas[0] += area; - convertibleAreas[age] -= area; + addArea(lpType, area); + removeArea(lpType, age, area); } public void removeAllArea() { - Arrays.fill(convertibleAreas, 0.0); - Arrays.fill(protectedAreas, 0.0); - unavailableArea = 0.0; + for (LandProtectionType lpType : LandProtectionType.values()) { + areas.get(lpType).clearAll(); + } } public void incrementAge() { for (int t = 0; t < ModelConfig.TIMESTEP_SIZE; t++) { - int n = convertibleAreas.length; - convertibleAreas[n-1] += convertibleAreas[n-2]; // final age bin is all absorbing - // shift values - for (int i=(n-2); i>0; i--) { - convertibleAreas[i] = convertibleAreas[i-1]; - } - convertibleAreas[0]= 0.0; - - int m = protectedAreas.length; - protectedAreas[m-1] += protectedAreas[m-2]; // final age bin is all absorbing - // shift values - for (int i=(m-2); i>0; i--) { - protectedAreas[i] = protectedAreas[i-1]; + for (LandProtectionType lpType : LandProtectionType.values()) { + areas.get(lpType).incrementAge(); } - protectedAreas[0]= 0.0; } } // Moves area from convertible to protected, maintaining age classes public void moveAreaToProtected(double area) { - double convertibleA = getTotalConvertibleArea(); + double convertibleA = getTotalArea(LandProtectionType.CONVERTIBLE); if (area > convertibleA) { LogWriter.printlnWarning("LandCoverTile.moveAreaToProtected cannot protect all required area"); area = Math.min(convertibleA, area); } double fractToMove = area / convertibleA; for (int i = 0; i <= MAX_AGE; i ++) { - double areaToMove = convertibleAreas[i] * fractToMove; - protectedAreas[i] += areaToMove; - convertibleAreas[i] -= areaToMove; + double areaToMove = getArea(LandProtectionType.CONVERTIBLE, i) * fractToMove; + addArea(LandProtectionType.PROTECTED, i, areaToMove); + removeArea(LandProtectionType.CONVERTIBLE, i, areaToMove); } } diff --git a/src/ac/ed/lurg/landuse/LandParcel.java b/src/ac/ed/lurg/landuse/LandParcel.java new file mode 100644 index 0000000000000000000000000000000000000000..7dc3aa643328e5ddd8808f64ab2b495c5c7851c2 --- /dev/null +++ b/src/ac/ed/lurg/landuse/LandParcel.java @@ -0,0 +1,89 @@ +package ac.ed.lurg.landuse; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import ac.ed.lurg.utils.LogWriter; + +public class LandParcel implements Serializable { + private static final long serialVersionUID = -114360206977984739L; + Map<Integer, Double> parcels; + + public LandParcel() { + this.parcels = new TreeMap<Integer, Double>(); + } + + public void set(int age, double area) { + parcels.put(age, area); + } + + public double get(int age) { + return parcels.getOrDefault(age, 0.0); + } + + public void add(int age, double area) { + double newArea = get(age) + area; + set(age, newArea); + } + + public void subtract(int age, double area) { + double prevArea = get(age); + double newArea; + if (prevArea < area) { + LogWriter.printlnError("LandParcel: Attempting to subtract too much area"); + newArea = 0.0; + } else { + newArea = prevArea - area; + } + set(age, newArea); + } + + public void subtractUniform(double area) { + if (area <= 0) + return; + double totalArea = getTotal(); + double areaToRemove = Math.min(totalArea, area); + if (Math.abs(area - areaToRemove) > 1e-10) { + LogWriter.printlnError("LandParcel.subtractUniform: attempting to remove too much area: " + area + ", available: " + totalArea); + } + double factor = (totalArea - areaToRemove) / totalArea; + for (int i : parcels.keySet()) { + double newArea = get(i) * factor; + set(i, newArea); + } + } + + public double getTotal() { + return parcels.values().stream().reduce(0.0, Double::sum); + } + + public void resetAge(int age) { + double area = get(age); + set(age, 0.0); + set(0, area); + } + + public void incrementAge() { + if (parcels.size() == 0) + return; + + Set<Integer> keys = parcels.keySet(); + List<Integer> orderedKeys = new ArrayList<Integer>(keys); + Collections.sort(orderedKeys); + Collections.reverse(orderedKeys); + for (int age : orderedKeys) { + double area = get(age); + set(age + 1, area); + parcels.remove(age); + } + } + + public void clearAll() { + parcels.clear(); + } +} diff --git a/src/ac/ed/lurg/landuse/LandUseBinarySerializer.java b/src/ac/ed/lurg/landuse/LandUseBinarySerializer.java index c31e480981a0b3cbdc0a0bc64d224771b7477bb2..96b62f83e1e50366106a654080316dfef6e6bc89 100644 --- a/src/ac/ed/lurg/landuse/LandUseBinarySerializer.java +++ b/src/ac/ed/lurg/landuse/LandUseBinarySerializer.java @@ -14,6 +14,7 @@ import java.util.Map; import ac.ed.lurg.ModelConfig; import ac.ed.lurg.types.LandCoverType; +import ac.ed.lurg.types.LandProtectionType; import ac.ed.lurg.utils.LogWriter; import ac.sac.raster.RasterKey; import ac.sac.raster.RasterSet; @@ -56,7 +57,7 @@ public class LandUseBinarySerializer { for (LandCoverType lcType : LandCoverType.values()) { LandCoverTile tile = tiles.get(lcType); for (int a = 0; a < NUM_AGE_CLASSES; a++) { - writer.writeDouble(tile.getConvertibleArea(a)); + writer.writeDouble(tile.getArea(LandProtectionType.CONVERTIBLE, a)); } } @@ -64,14 +65,14 @@ public class LandUseBinarySerializer { for (LandCoverType lcType : LandCoverType.values()) { LandCoverTile tile = tiles.get(lcType); for (int a = 0; a < NUM_AGE_CLASSES; a++) { - writer.writeDouble(tile.getProtectedArea(a)); + writer.writeDouble(tile.getArea(LandProtectionType.PROTECTED, a)); } } // Unavailable for (LandCoverType lcType : LandCoverType.values()) { LandCoverTile tile = tiles.get(lcType); - writer.writeDouble(tile.getUnavailableArea()); + writer.writeDouble(tile.getTotalArea(LandProtectionType.UNAVAILABLE)); } //LogWriter.println(""+count); } @@ -138,7 +139,8 @@ public class LandUseBinarySerializer { for (LandCoverType lcType : LandCoverType.values()) { for (int age = 0; age < NUM_AGE_CLASSES; age++) { double area = reader.readDouble(); - landCoverAreas.get(lcType).setConvertibleArea(age, area); + if (area > 0) + landCoverAreas.get(lcType).setArea(LandProtectionType.CONVERTIBLE, age, area); } } break; @@ -146,14 +148,16 @@ public class LandUseBinarySerializer { for (LandCoverType lcType : LandCoverType.values()) { for (int age = 0; age < NUM_AGE_CLASSES; age++) { double area = reader.readDouble(); - landCoverAreas.get(lcType).setProtectedArea(age, area); + if (area > 0) + landCoverAreas.get(lcType).setArea(LandProtectionType.PROTECTED, age, area); } } break; case UNVAVAILABLE_IDX: for (LandCoverType lcType : LandCoverType.values()) { double area = reader.readDouble(); - landCoverAreas.get(lcType).addUnavailableArea(area); + if (area > 0) + landCoverAreas.get(lcType).setArea(LandProtectionType.UNAVAILABLE, 0, area); // TODO Do we need to keep track of age? } } } diff --git a/src/ac/ed/lurg/landuse/LandUseItem.java b/src/ac/ed/lurg/landuse/LandUseItem.java index 63e93b16c6d19de8a4c56bf60304dedfa8aae6e0..6baa4028d6fb89f5946c92f5d36a87924a18c93e 100644 --- a/src/ac/ed/lurg/landuse/LandUseItem.java +++ b/src/ac/ed/lurg/landuse/LandUseItem.java @@ -8,6 +8,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.types.LandProtectionType; import ac.ed.lurg.utils.Interpolator; import ac.ed.lurg.utils.LogWriter; import ac.sac.raster.InterpolatingRasterItem; @@ -67,7 +68,7 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial // static land covers if (!lcType.isConvertible()) { - tiles.addConvertibleArea(totalArea); // Assumes land cover age is 0 + tiles.addArea(LandProtectionType.UNAVAILABLE, totalArea); // Assumes land cover age is 0 continue; } // convertible land covers @@ -104,8 +105,8 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial int minAge = (int) (ageGroup - 1) * AGE_GROUP_SIZE + 1; int maxAge = minAge + (AGE_GROUP_SIZE - 1); for (int a = minAge; a <= maxAge; a++) { - landCoverAreas.get(lcType).setConvertibleArea(a, unprotectedArea * prop); - landCoverAreas.get(lcType).setProtectedArea(a, protectedArea * prop); + landCoverAreas.get(lcType).setArea(LandProtectionType.CONVERTIBLE, a, unprotectedArea * prop); + landCoverAreas.get(lcType).setArea(LandProtectionType.PROTECTED, a, protectedArea * prop); } } } @@ -146,36 +147,36 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial double unavailFromConvertibleNatural = Math.min(shortfall, convertibleNatural); shortfall -= unavailFromConvertibleNatural; if (unavailFromConvertibleNatural > 0) { - landCoverAreas.get(LandCoverType.NATURAL).addUnavailableArea(unavailFromConvertibleNatural); - landCoverAreas.get(LandCoverType.NATURAL).removeConvertibleArea(unavailFromConvertibleNatural); + landCoverAreas.get(LandCoverType.NATURAL).addArea(LandProtectionType.UNAVAILABLE, unavailFromConvertibleNatural); + landCoverAreas.get(LandCoverType.NATURAL).removeArea(LandProtectionType.CONVERTIBLE, unavailFromConvertibleNatural); } double unavailFromProtectedNatural = Math.min(shortfall, protectedNatural); shortfall -= unavailFromProtectedNatural; if (unavailFromProtectedNatural > 0) { - landCoverAreas.get(LandCoverType.NATURAL).addUnavailableArea(unavailFromProtectedNatural); - landCoverAreas.get(LandCoverType.NATURAL).removeProtectedArea(unavailFromProtectedNatural); + landCoverAreas.get(LandCoverType.NATURAL).addArea(LandProtectionType.UNAVAILABLE, unavailFromProtectedNatural); + landCoverAreas.get(LandCoverType.NATURAL).removeArea(LandProtectionType.PROTECTED, unavailFromProtectedNatural); } double unavailFromTimberF = Math.min(shortfall, convertibleTimberF); shortfall -= unavailFromTimberF; if (unavailFromTimberF > 0) { - landCoverAreas.get(LandCoverType.TIMBER_FOREST).addUnavailableArea(unavailFromTimberF); - landCoverAreas.get(LandCoverType.TIMBER_FOREST).removeConvertibleArea(unavailFromTimberF); + landCoverAreas.get(LandCoverType.TIMBER_FOREST).addArea(LandProtectionType.UNAVAILABLE, unavailFromTimberF); + landCoverAreas.get(LandCoverType.TIMBER_FOREST).removeArea(LandProtectionType.CONVERTIBLE, unavailFromTimberF); } double unavailFromPasture = Math.min(shortfall, convertiblePasture); shortfall -= unavailFromPasture; if (unavailFromPasture > 0) { - landCoverAreas.get(LandCoverType.PASTURE).addUnavailableArea(unavailFromPasture); - landCoverAreas.get(LandCoverType.PASTURE).removeConvertibleArea(unavailFromPasture); + landCoverAreas.get(LandCoverType.PASTURE).addArea(LandProtectionType.UNAVAILABLE, unavailFromPasture); + landCoverAreas.get(LandCoverType.PASTURE).removeArea(LandProtectionType.CONVERTIBLE, unavailFromPasture); } double unavailFromCropland = Math.min(shortfall, convertibleCropland); shortfall -= unavailFromCropland; if (unavailFromCropland > 0) { - landCoverAreas.get(LandCoverType.CROPLAND).addUnavailableArea(unavailFromCropland); - landCoverAreas.get(LandCoverType.CROPLAND).removeConvertibleArea(unavailFromCropland); + landCoverAreas.get(LandCoverType.CROPLAND).addArea(LandProtectionType.UNAVAILABLE, unavailFromCropland); + landCoverAreas.get(LandCoverType.CROPLAND).removeArea(LandProtectionType.CONVERTIBLE, unavailFromCropland); } if (shortfall > 0) { @@ -200,7 +201,7 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial } public void setProtectedLandCoverArea(LandCoverType lcType, double area) { - landCoverAreas.get(lcType).setProtectedArea(0, area); + landCoverAreas.get(lcType).setArea(LandProtectionType.PROTECTED, 0, area); } public double getProtectedFraction() { @@ -209,13 +210,13 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial public double getTotalProtectedArea() { if(ModelConfig.PROTECTED_AREAS_ENABLED) - return landCoverAreas.values().stream().mapToDouble(o -> o.getTotalProtectedArea()).sum(); + return landCoverAreas.values().stream().mapToDouble(o -> o.getTotalArea(LandProtectionType.PROTECTED)).sum(); else return 0.0; } public double getProtectedLandCoverArea(LandCoverType lcType) { - return landCoverAreas.get(lcType).getTotalProtectedArea(); + return landCoverAreas.get(lcType).getTotalArea(LandProtectionType.PROTECTED); } public double getSuitableArea() { @@ -244,8 +245,8 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial LandCoverTile toTiles = landCoverAreas.get(toType); LandCoverTile fromTiles = landCoverAreas.get(fromType); - fromTiles.removeConvertibleArea(area); - toTiles.addConvertibleArea(area); + fromTiles.removeArea(LandProtectionType.CONVERTIBLE, area); + toTiles.addArea(LandProtectionType.CONVERTIBLE, area); return area - areaMoved; } @@ -267,7 +268,7 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial double landCover = (d < 0.0) ? 0.0 : d; landCoverAreas.get(c).removeAllArea(); - landCoverAreas.get(c).addConvertibleArea(landCover);; + landCoverAreas.get(c).addArea(LandProtectionType.CONVERTIBLE, landCover);; } public double getTotalLandCoverArea() { @@ -289,13 +290,13 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial public double getTotalConvertibleNaturalArea() { double unprotectedNatural = 0; for (LandCoverType landType : LandCoverType.getNaturalTypes()) { - unprotectedNatural += landCoverAreas.get(landType).getTotalConvertibleArea(); + unprotectedNatural += landCoverAreas.get(landType).getTotalArea(LandProtectionType.CONVERTIBLE); } return unprotectedNatural; } public double getConvertibleLandCoverArea(LandCoverType c) { - return landCoverAreas.get(c).getTotalConvertibleArea(); + return landCoverAreas.get(c).getTotalArea(LandProtectionType.CONVERTIBLE); } @@ -479,8 +480,8 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial public void doForestRotation(int rotationAge) { LandCoverTile tiles = landCoverAreas.get(LandCoverType.TIMBER_FOREST); - for (int a=rotationAge; a<=tiles.getMaxAgeBin(); a++) { - tiles.resetAreaForAge(a); + for (int a=rotationAge; a<=LandCoverTile.getMaxAgeBin(); a++) { + tiles.resetAreaForAge(LandProtectionType.CONVERTIBLE, a); } } @@ -532,20 +533,20 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial for (LandCoverType landCover : LandCoverType.values()) { for (int age = 0; age <= LandCoverTile.getMaxAgeBin(); age++) { - Double from = fromItem.landCoverAreas.get(landCover).getConvertibleArea(age); - Double to = toItem.landCoverAreas.get(landCover).getConvertibleArea(age); + Double from = fromItem.landCoverAreas.get(landCover).getArea(LandProtectionType.CONVERTIBLE, age); + Double to = toItem.landCoverAreas.get(landCover).getArea(LandProtectionType.CONVERTIBLE, age); Double d = Interpolator.interpolate(from, to, factor); LandCoverTile tile = landCoverAreas.computeIfAbsent(landCover, k -> new LandCoverTile()); - tile.setConvertibleArea(age, d); + tile.setArea(LandProtectionType.CONVERTIBLE, age, d); } } for (LandCoverType landCover : LandCoverType.values()) { - Double from = fromItem.landCoverAreas.get(landCover).getTotalProtectedArea(); - Double to = toItem.landCoverAreas.get(landCover).getTotalProtectedArea(); + Double from = fromItem.landCoverAreas.get(landCover).getTotalArea(LandProtectionType.PROTECTED); + Double to = toItem.landCoverAreas.get(landCover).getTotalArea(LandProtectionType.PROTECTED); Double d = Interpolator.interpolate(from, to, factor); LandCoverTile tile = landCoverAreas.computeIfAbsent(landCover, k -> new LandCoverTile()); - tile.addProtectedArea(d); + tile.addArea(LandProtectionType.PROTECTED, d); } } @@ -586,8 +587,8 @@ public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serial Map<LandCoverType, Double> convertibleAreas = new HashMap<LandCoverType, Double>(); Map<LandCoverType, Double> protectedAreas = new HashMap<LandCoverType, Double>(); for (LandCoverType lcType : LandCoverType.values()) { - convertibleAreas.put(lcType, landCoverAreas.get(lcType).getTotalConvertibleArea()); - protectedAreas.put(lcType, landCoverAreas.get(lcType).getTotalProtectedArea()); + convertibleAreas.put(lcType, landCoverAreas.get(lcType).getTotalArea(LandProtectionType.CONVERTIBLE)); + protectedAreas.put(lcType, landCoverAreas.get(lcType).getTotalArea(LandProtectionType.PROTECTED)); } return "LandUseItem: [landCoverAreas=" + convertibleAreas + ", protectedArea=" + protectedAreas + "]"; } diff --git a/src/ac/ed/lurg/landuse/LandUseSerializer.java b/src/ac/ed/lurg/landuse/LandUseSerializer.java index 3b9cdb4e7277839b6bd79f08fbbc3584e4aece24..9cfd1e829fc5f7de4d066963edca86df9154bf76 100644 --- a/src/ac/ed/lurg/landuse/LandUseSerializer.java +++ b/src/ac/ed/lurg/landuse/LandUseSerializer.java @@ -29,6 +29,7 @@ import javax.xml.parsers.ParserConfigurationException; import ac.ed.lurg.ModelConfig; import ac.ed.lurg.types.CropType; import ac.ed.lurg.types.LandCoverType; +import ac.ed.lurg.types.LandProtectionType; import ac.ed.lurg.utils.LogWriter; import ac.sac.raster.RasterKey; import ac.sac.raster.RasterSet; @@ -149,7 +150,7 @@ public class LandUseSerializer { xmlWriter.writeStartElement("convertible"); for (int a = 0; a <= LandCoverTile.getMaxAgeBin(); a++) { - double area = tiles.getConvertibleArea(a); + double area = tiles.getArea(LandProtectionType.CONVERTIBLE, a); if (area == 0) continue; writeElement("X"+Integer.toString(a), area); @@ -158,14 +159,14 @@ public class LandUseSerializer { xmlWriter.writeStartElement("protected"); for (int a = 0; a <= LandCoverTile.getMaxAgeBin(); a++) { - double area = tiles.getProtectedArea(a); + double area = tiles.getArea(LandProtectionType.PROTECTED, a); if (area == 0) continue; writeElement("X"+Integer.toString(a), area); } xmlWriter.writeEndElement(); - writeElement("unavailable", tiles.getUnavailableArea()); + writeElement("unavailable", tiles.getTotalArea(LandProtectionType.UNAVAILABLE)); xmlWriter.writeEndElement(); } @@ -237,14 +238,14 @@ public class LandUseSerializer { NodeList convElements = lcElement.getElementsByTagName("convertible").item(0).getChildNodes(); NodeList protElements = lcElement.getElementsByTagName("protected").item(0).getChildNodes(); double unavArea = Double.parseDouble(lcElement.getElementsByTagName("unavailable").item(0).getTextContent()); - landCoverAreas.get(lcType).addUnavailableArea(unavArea); + landCoverAreas.get(lcType).setArea(LandProtectionType.UNAVAILABLE, 0, unavArea); for (int k = 0; k < convElements.getLength(); k++) { Node areaNode = convElements.item(k); int age = Integer.parseInt(areaNode.getNodeName().replace("X", "")); //double area = Double.parseDouble(areaNode.getNodeValue()); double area = Double.parseDouble(areaNode.getChildNodes().item(0).getNodeValue()); - landCoverAreas.get(lcType).setConvertibleArea(age, area); + landCoverAreas.get(lcType).setArea(LandProtectionType.CONVERTIBLE, age, area); } for (int k = 0; k < protElements.getLength(); k++) { @@ -252,7 +253,7 @@ public class LandUseSerializer { int age = Integer.parseInt(areaNode.getNodeName().replace("X", "")); //double area = Double.parseDouble(areaNode.getNodeValue()); double area = Double.parseDouble(areaNode.getChildNodes().item(0).getNodeValue()); - landCoverAreas.get(lcType).setProtectedArea(age, area); + landCoverAreas.get(lcType).setArea(LandProtectionType.PROTECTED, age, area); } } } diff --git a/src/ac/ed/lurg/types/LandProtectionType.java b/src/ac/ed/lurg/types/LandProtectionType.java new file mode 100644 index 0000000000000000000000000000000000000000..4f68893e7d9df174a2c45c199890955245e1a6ec --- /dev/null +++ b/src/ac/ed/lurg/types/LandProtectionType.java @@ -0,0 +1,44 @@ +package ac.ed.lurg.types; + +import java.util.HashMap; +import java.util.Map; + +import ac.ed.lurg.utils.LogWriter; + +public enum LandProtectionType { + + CONVERTIBLE(1, "convertible"), + PROTECTED(2, "protected"), + UNAVAILABLE(3, "unavailable"); + + private int id; + private String name; + + private LandProtectionType(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + private static final Map<String, LandProtectionType> nameCache = new HashMap<String, LandProtectionType>(); + static { + for (LandProtectionType c : values()) { + nameCache.put(c.getName(), c); + } + } + + public static LandProtectionType getForName(String name) { + LandProtectionType type = nameCache.get(name); + if (type == null) { + LogWriter.printlnError("Can't find LandProtectionType for " + name); + } + return type; + } +}