Newer
Older
import java.util.Collection;
import ac.ed.lurg.ModelConfig;
import ac.sac.raster.InterpolatingRasterItem;
public class LandUseItem implements InterpolatingRasterItem<LandUseItem>, Serializable {
private static final long serialVersionUID = 763526147224355158L;
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 double protectedArea; //protected area in Mha
Roslyn Henry
committed
private double unavailableArea; //area unavailable due to altitude etc
private double suitableArea;
R0slyn
committed
public LandUseItem(LandCoverItem landCover) {
this();
if (landCover != null) {
for (LandCoverType lcType : LandCoverType.values())
landCoverAreas.put(lcType, landCover.getLandCoverArea(lcType));
setCropFraction(CropType.WHEAT, 0.5); // random start as don't have better data
setCropFraction(CropType.MAIZE, 0.5);
Roslyn Henry
committed
setUnavailableArea(landCover.getUnavailableFract());
updateSuitableArea(ModelConfig.BASE_YEAR);
}
}
public LandUseItem(LandUseItem luItemToCopy) {
this();
intensityMap.putAll(luItemToCopy.intensityMap);
cropFractions.putAll(luItemToCopy.cropFractions);
landCoverAreas.putAll(luItemToCopy.landCoverAreas);
unprotectedAreas.putAll(luItemToCopy.unprotectedAreas);
Roslyn Henry
committed
suitableArea = (luItemToCopy.suitableArea);
public void setProtectedFract(double protFrac) {
if (!Double.isNaN(ModelConfig.CONSTANT_PROTECTED_AREA_RATE))
protFrac=ModelConfig.CONSTANT_PROTECTED_AREA_RATE;
Roslyn Henry
committed
double totalArea = getTotalLandCoverArea();
double urbanArea = getLandCoverArea(LandCoverType.URBAN);
double barrenArea = getLandCoverArea(LandCoverType.BARREN);
this.protectedArea = Math.min(totalArea-urbanArea-barrenArea, protFrac*(totalArea-urbanArea));
}
public void setProtectedArea(double protectedArea) {
this.protectedArea = protectedArea;
}
public double getProtectedArea() {
return protectedArea;
else
return 0.0;
}
Roslyn Henry
committed
public void setSuitableArea(double suitable) {
this.suitableArea = suitable;
Roslyn Henry
committed
public double getSuitableArea() {
return suitableArea;
}
public void setUnavailableArea(double unavailF) {
unavailableArea = unavailF*getTotalLandCoverArea();
}
public double getUnavailableArea() {
return unavailableArea;
public Intensity getIntensity(CropType crop) {
return intensityMap.get(crop);
}
public void setIntensity(CropType crop, Intensity intensityData) {
intensityMap.put(crop, intensityData);
}
/** Fertiliser rate in kg/ha */
public double getFertiliserRate(CropType crop) {
Intensity i = getIntensity(crop);
return (i == null) ? 0 : i.getFertiliserAmount();
}
/** Fertiliser amount in kt (1000 tonnes), for this location */
public double getFertiliserAmount(CropType c) {
double rate = getFertiliserRate(c);
double area = getCropArea(c);
return rate * area;
}
public double getFertiliserAverageRate(CropType... crops) {
double fertTotal = 0;
double areaTotal = 0;
for (CropType c : crops) {
fertTotal += getFertiliserAmount(c);
areaTotal += getCropArea(c);
return areaTotal > 0 ? fertTotal / areaTotal : 0;
}
public static double getFertiliserTotal(Collection<? extends LandUseItem> items, CropType... crops) {
double total = 0;
for (LandUseItem a : items) {
if (a == null)
continue;
for (CropType c : crops)
total += a.getFertiliserAmount(c);
}
return total;
}
public static double getFertiliserTotal(Collection<? extends LandUseItem> items, Collection<CropType> crops) {
return getFertiliserTotal(items, crops.toArray(new CropType[crops.size()]));
}
/** Irrigation Intensity (unit less) */
public double getIrrigationIntensity(CropType crop) {
Intensity i = getIntensity(crop);
return (i == null) ? 0 : i.getIrrigationIntensity();
}
/** Irrigation rate in litre/m2 */
public double getIrrigationRate(CropType crop) {
Intensity i = getIntensity(crop);
return (i == null) ? 0 : i.getIrrigationRate();
/** Irrigation amount in km3 or 10^9 m3, for this location */
R0slyn
committed
public double getIrrigationAmount(CropType c) {
double rate = getIrrigationRate(c);
double area = getCropArea(c);
return rate * area * 0.01; // rate(10^-3m or mm or l/m2) * area(10^6ha) = 10^3 m.ha = 10^7 m3 = 1/100 km3
/** Irrigation Intensity (unit less) */
public double getIrrigationAverageIntensity(CropType... crops) {
double irrigTotal = 0;
double areaTotal = 0;
for (CropType c : crops) {
irrigTotal += getIrrigationIntensity(c) * area;
}
return areaTotal > 0 ? irrigTotal / areaTotal : 0;
}
/** Irrigation amount in km3, for this location */
public static double getIrrigationTotal(Collection<? extends LandUseItem> items, CropType... crops) {
double total = 0;
for (LandUseItem a : items) {
if (a == null)
continue;
for (CropType c : crops)
total += a.getIrrigationAmount(c);
}
return total;
}
public static double getIrrigationTotal(Collection<? extends LandUseItem> items, Collection<CropType> crops) {
return getIrrigationTotal(items, crops.toArray(new CropType[crops.size()]));
}
/** move areas from one land cover to another, return any residual not possible */
public double moveAreas(LandCoverType toType, LandCoverType fromType, double changeReq) {
double prevTo = getLandCoverArea(toType);
double prevFrom = getLandCoverArea(fromType);
double availLC = fromType.isProtectable() ? Math.min(prevFrom, unprotectedAreas.get(fromType)) : prevFrom; // if protected can not go past protected area
double actuallyChanged = Math.min(availLC, changeReq);
setLandCoverArea(toType, prevTo + actuallyChanged);
setLandCoverArea(fromType, prevFrom - actuallyChanged);
return changeReq - actuallyChanged;
}
Double d = getLandCoverArea(LandCoverType.CROPLAND) * getCropFraction(c);
return d;
}
public double getCropFraction(CropType c) {
Double d = cropFractions.get(c);
return d == null ? 0.0 : d;
public double getCropFraction(CropType... cropsToFind) {
double totalFract = 0;
for (CropType crop : cropsToFind) {
totalFract += getCropFraction(crop);
}
return totalFract;
}
public void setCropFraction(CropType c, double areaFract) {
cropFractions.put(c, areaFract);
public double getLandCoverArea(LandCoverType c) {
return d == null ? 0.0 : d;
public double getLandCoverFract(LandCoverType c) {
double totalArea = getTotalLandCoverArea();
return totalArea==0 ? 0.0 : getLandCoverArea(c) / totalArea;
public void setLandCoverArea(LandCoverType c, double d) {
throw new RuntimeException("AreasItem for " + c + " is " + d);
public double getTotalLandCoverArea() {
double d = 0;
for (LandCoverType l : LandCoverType.values())
public static double getAbandonedPasture(Collection<? extends LandUseItem> landUses) {
double total = 0;
for (LandUseItem a : landUses) {
if (a!=null) {
Intensity intensity = a.getIntensity(CropType.PASTURE);
if (intensity!=null && d!=null && intensity.getFertiliserAmount()==0 && intensity.getIrrigationRate()==0 && intensity.getOtherIntensity()==0)
total += d;
}
}
return total;
}
R0slyn
committed
public static double getSuitableTotal(Collection<? extends LandUseItem> landUses, int year) {
double total = 0;
for (LandUseItem a : landUses) {
if (a!=null) {
Roslyn Henry
committed
Double suitable = a.getSuitableArea();
R0slyn
committed
total += suitable;
}
}
return total;
}
public double getTotalNatural() {
double totalNatural = getLandCoverArea(LandCoverType.OTHER_NATURAL) + getLandCoverArea(LandCoverType.MANAGED_FOREST) + getLandCoverArea(LandCoverType.UNMANAGED_FOREST);
return totalNatural;
}
public double getTotalUnprotectedNatural() {
double unprotectedNatural = 0;
for (LandCoverType landType : LandCoverType.values()) {
if (landType.isProtectable()) {
unprotectedNatural += unprotectedAreas.get(landType);
}
}
return unprotectedNatural;
}
public double getUnprotectedLandCoverArea(LandCoverType landType) {
return unprotectedAreas.get(landType);
}
Roslyn Henry
committed
private double getProtectedandUnavailable() {
double totalSuitableLandCover = getTotalLandCoverArea()-getLandCoverArea(LandCoverType.BARREN)-getLandCoverArea(LandCoverType.URBAN);
if (totalSuitableLandCover <=0)
return 0;
Roslyn Henry
committed
double minAndProtectedA = getUnavailableArea() + getProtectedArea() + totalSuitableLandCover * ModelConfig.MIN_NATURAL_RATE;
return Math.min(totalSuitableLandCover, minAndProtectedA);
/** averages protected areas across land cover types */
private void updateUnprotectedAreas() {
Roslyn Henry
committed
double desiredProtected = getProtectedandUnavailable();
double totalNatural = getTotalNatural();
double unprotectedNat = Math.max(0, totalNatural - desiredProtected); // if we are already using more than is protected then the unprotectedArea is 0
double unprotectedFract = (totalNatural > 0) ? unprotectedNat/totalNatural : 0;
for (LandCoverType landType : LandCoverType.values()) {
if (landType.isProtectable()) {
unprotectedAreas.put(landType, getLandCoverArea(landType)*unprotectedFract);
}
else unprotectedAreas.put(landType, getLandCoverArea(landType));
}
}
Roslyn Henry
committed
public void updateSuitableArea(int year) {
updateUnprotectedAreas(); //update unprotected areas
double currentAgri = getLandCoverArea(LandCoverType.PASTURE) + getLandCoverArea(LandCoverType.CROPLAND);
double totalNatural = getTotalNatural();
Roslyn Henry
committed
double natAvailForAgri = totalNatural - getProtectedandUnavailable(); // could be negative, i.e. excess agricultural area already used
Roslyn Henry
committed
//this forces protected areas, min_natural_rate and slope constraints to be obeyed
if (ModelConfig.FORCE_PROTECTED_AREAS && natAvailForAgri < 0 && year >= ModelConfig.FORCE_PROTECTED_AREAS_START_YEAR) {
R0slyn
committed
double proportion = 1.0;
R0slyn
committed
if (year < ModelConfig.FORCE_PROTECTED_AREAS_END_YEAR)
proportion = 1.0 / (ModelConfig.FORCE_PROTECTED_AREAS_END_YEAR - year);
Roslyn Henry
committed
suitableArea = Math.max(0, currentAgri + natAvailForAgri * proportion); // netNatAvailForAgri is negative, but suitable area < 0 is not sensible (seems to happen with high barren areas)
Roslyn Henry
committed
else //not honouring protected areas if agriculture > natural that should be protected
suitableArea = currentAgri + getTotalUnprotectedNatural();
Peter Alexander
committed
public double getForestManagedFraction() {
double managed = getLandCoverArea(LandCoverType.MANAGED_FOREST);
double unmanaged = getLandCoverArea(LandCoverType.UNMANAGED_FOREST);
double d = managed / (managed + unmanaged);
return (Double.isNaN(d) || Double.isInfinite(d)) ? 1.0 : d;
}
public CropToDouble getCropChanges(LandUseItem prevAreaAggItem) {
for (CropType c : CropType.getCropsLessPasture()) {
double change = getCropArea(c) - prevAreaAggItem.getCropArea(c);
changes.put(c, change);
private boolean isZeroOrNull(Double d) {
return d == null || d == 0;
}
public void interpolateAll(LandUseItem fromItem, LandUseItem toItem, double factor) {
cropFractions = new HashMap<CropType, Double>();
landCoverAreas = new HashMap<LandCoverType, Double>();
Double fromCropCover = fromItem.landCoverAreas.get(LandCoverType.CROPLAND);
Double toCropCover = toItem.landCoverAreas.get(LandCoverType.CROPLAND);
if (!isZeroOrNull(fromCropCover) && isZeroOrNull(toCropCover)) { // if start with crop but end with none, take starting crop fractions
cropFractions.putAll(fromItem.cropFractions);
intensityMap.putAll(fromItem.intensityMap);
}
else if (isZeroOrNull(fromCropCover) && !isZeroOrNull(toCropCover)) { // if start with no crop but end with some, take end crop fractions
cropFractions.putAll(toItem.cropFractions);
intensityMap.putAll(toItem.intensityMap);
}
else { // otherwise we need to interpolate crop fractions
for (CropType crop : CropType.values()) {
Double from = fromItem.cropFractions.get(crop);
Double to = toItem.cropFractions.get(crop);
Double d = Interpolator.interpolate(from, to, factor);
cropFractions.put(crop, d);
Intensity fromIntensity = fromItem.intensityMap.get(crop);
Intensity toIntensity = toItem.intensityMap.get(crop);
Intensity interpolateIntensity = toIntensity; // might still be null
if (fromIntensity != null && toIntensity != null)
interpolateIntensity = new Intensity(fromIntensity, toIntensity, factor); // both non-null really interpolate
else if (fromIntensity != null)
interpolateIntensity = fromIntensity; // just fromIntensity non-null
intensityMap.put(crop, interpolateIntensity);
}
}
for (LandCoverType landCover : LandCoverType.values()) {
Double from = fromItem.landCoverAreas.get(landCover);
Double to = toItem.landCoverAreas.get(landCover);
Double d = Interpolator.interpolate(from, to, factor);
landCoverAreas.put(landCover, d);
}
}
public static double getTotalLandCover(Collection<? extends LandUseItem> landUses, LandCoverType landCover) {
for (LandUseItem a : landUses) {
if (a!=null) {
Double d = a.getLandCoverArea(landCover);
if (d!=null)
total += d;
}
}
public static double getTotalCropArea(Collection<LandUseItem> landUses, CropType crop) {
double total = 0;
for (LandUseItem a : landUses)
total += a.getCropArea(crop);
return total;
}
@Override
public String toString() {
Roslyn Henry
committed
return "LandUseItem: [landCoverAreas=" + landCoverAreas + ", protectedArea=" + protectedArea + ", unavailableArea=" + unavailableArea + "]";