From ed37b6289e0cf8a555e5a173a9731d2c779040ec Mon Sep 17 00:00:00 2001 From: Peter Alexander <peter@blackhillock.co.uk> Date: Wed, 8 Jul 2015 12:11:08 +0100 Subject: [PATCH] Split pasture and meat and fixes --- GAMS/IntExtOpt.gms | 58 +++++++++++-------- src/ac/ed/lurg/country/CountryAgent.java | 2 +- .../country/gams/GamsLocationOptimiser.java | 4 +- .../lurg/country/gams/GamsLocationTest.java | 12 ++-- .../country/gams/GamsRasterOptimiser.java | 10 ++-- src/ac/ed/lurg/types/CommodityType.java | 2 +- src/ac/ed/lurg/types/CropType.java | 2 +- src/ac/ed/lurg/yield/YieldResponse.java | 2 +- 8 files changed, 50 insertions(+), 42 deletions(-) diff --git a/GAMS/IntExtOpt.gms b/GAMS/IntExtOpt.gms index 3aa6f79b..4ed20694 100644 --- a/GAMS/IntExtOpt.gms +++ b/GAMS/IntExtOpt.gms @@ -1,11 +1,11 @@ - SET all_types / cereals, wheat, maize, rice, tropicalCereals, oilcrops, soybean, pulses, starchyRoots, pasture_or_meat /; + SET all_types / meat, cereals, wheat, maize, rice, tropicalCereals, oilcrops, soybean, pulses, starchyRoots, pasture /; - SET crop(all_types) / wheat, maize, rice, tropicalCereals, oilcrops, soybean, pulses, starchyRoots, pasture_or_meat /; - SET crop_less_pasture(crop) / wheat, maize, rice, tropicalCereals, oilcrops, soybean, pulses, starchyRoots /; - SET cereal_crop(crop) / wheat, maize, rice, tropicalCereals /; - SET non_cereal_crop(crop) / oilcrops, soybean, pulses, starchyRoots /; - SET feed_crop(crop) / wheat, maize, oilcrops, soybean /; - SET not_feed_crops(crop) / rice, tropicalCereals, pulses, starchyRoots, pasture_or_meat /; + SET crop(all_types) / wheat, maize, rice, tropicalCereals, oilcrops, soybean, pulses, starchyRoots, pasture /; + SET crop_less_pasture(crop) / wheat, maize, rice, tropicalCereals, oilcrops, soybean, pulses, starchyRoots /; + SET cereal_crop(crop_less_pasture) / wheat, maize, rice, tropicalCereals /; + SET non_cereal_crop(crop_less_pasture) / oilcrops, soybean, pulses, starchyRoots /; + SET feed_crop(crop) / wheat, maize, oilcrops, soybean /; + SET not_feed_crop(crop) / rice, tropicalCereals, pulses, starchyRoots, pasture /; SET location; PARAMETER suitableLandArea(location) areas of land in Mha; @@ -25,7 +25,7 @@ SCALAR meatEfficency efficiency of converting feed and pasture into animal products; SCALAR maxLandUseChange max rate of land use change; SCALAR landChangeEnergy energy required to add ha of agricultural land; - SCALAR minFeedRate minimum rate of feed for producing animal products; + SCALAR minFeedRate minimum rate of feed for producing animal products (why is this needed?); $gdxin %gdxincname% $load location, suitableLandArea, previousArea, demand, landChangeEnergy @@ -36,14 +36,16 @@ $gdxin SCALAR delta use to smooth power function see 7.5 www.gams.com dd docs solversconopt.pdf / 0.00000000001 / - display previousArea +* display demand; + + SCALAR minDemandPerCereal / 0.1 / PARAMETER feedDM(crop) energy from feed in MJ per t (wet) (need to check these figures) / wheat 0.87 maize 0.87 oilcrops 0.32 soybean 0.87 - pasture_or_meat 1.0 / ; + pasture 0.2 / ; VARIABLES area(crop, location) total area for each crop - Mha @@ -51,9 +53,10 @@ $gdxin irrigI(crop, location) irrigation intensity for each crop - factor between 0 and 1 otherIntensity(crop, location) other intensity for each crop - unit less feedAmount(crop) amount of feed for each crop - Mt - netImportAmount(crop) export of crop - Mt + netImportAmount(all_types) net imports of crops and meat - Mt yield(crop, location) yield per area for each crop - t per ha unitEnergy(crop, location) energy per area for each crop - energy + net_supply(crop_less_pasture) supply after exports and feed energy total input energy - energy; POSITIVE VARIABLE area, fertI, irrigI, otherIntensity, feedAmount; @@ -67,7 +70,8 @@ $gdxin UNIT_ENERGY_EQ(crop, location) energy per area YIELD_EQ(crop, location) yield given chosen intensity NON_CEREAL_DEMAND_CONSTRAINT(non_cereal_crop) satisfy demand for non-cereal crop - CEREAL_DEMAND_CONSTRAINT satisfy demand for cereal + CEREAL_DEMAND_CONSTRAINT(cereal_crop) satisfy demand for cereal so that exports can at least be met. Could also allow min. proporation of cereal consumption of each type + TOTAL_CEREAL_DEMAND_CONSTRAINT satisfy demand for cereal MEAT_DEMAND_CONSTRAINT satisfy demand for meat MAX_FERT_INTENSITY_CONSTRAINT(crop, location) constraint on maximum fertilizer intensity MAX_IRRIG_INTENSITY_CONSTRAINT(crop, location) constraint on maximum irrigation intensity @@ -76,10 +80,11 @@ $gdxin PASTURE_CHANGE_CONSTRAINT(location) constraint on the rate of land use change AGRI_LAND_INCREASE_CONSTRAINT(location) constraint expansion of agricultural land AGRI_LAND_DECREASE_CONSTRAINT(location) constraint expansion of agricultural land - NON_FEED_CROP_CONSTRAINT(not_feed_crops) constraint to set non feed crop feed usage to zero + NON_FEED_CROP_CONSTRAINT(not_feed_crop) constraint to set non feed crop feed usage to zero MAX_NET_IMPORT_CONSTRAINT(crop) constraint on max net imports MIN_NET_IMPORT_CONSTRAINT(crop) constraint on min net imports MIN_FEED_CONSTRAINT constraint on min feed rate + NET_SUPPLY_EQ(crop_less_pasture) calc net supply for crops ENERGY_EQ total energy objective function; UNIT_ENERGY_EQ(crop, location) .. unitEnergy(crop, location) =E= fertI(crop, location) + @@ -101,36 +106,37 @@ $gdxin * (yieldBoth(crop, location) + yieldNone(crop, location) - yieldFertOnly(crop, location) - yieldIrrigOnly(crop, location)) * (1 - exp(-fertParam(crop, location)*fertI(crop, location))) * (1 - exp(-irrigParam(crop, location)*irrigI(crop, location))) * ) * otherIntensity(crop, location); - NON_CEREAL_DEMAND_CONSTRAINT(non_cereal_crop) .. sum(location, area(non_cereal_crop, location) * yield(non_cereal_crop, location)) - feedAmount(non_cereal_crop) =G= - demand(non_cereal_crop) - netImportAmount(non_cereal_crop); - - CEREAL_DEMAND_CONSTRAINT .. sum(cereal_crop, sum(location, area(cereal_crop, location) * yield(cereal_crop, location)) - feedAmount(cereal_crop)) =G= - demand('cereals') - sum(cereal_crop, netImportAmount(cereal_crop)); + NET_SUPPLY_EQ(crop_less_pasture) .. net_supply(crop_less_pasture) =E= sum(location, area(crop_less_pasture, location) * yield(crop_less_pasture, location)) - feedAmount(crop_less_pasture) + netImportAmount(crop_less_pasture); + + NON_CEREAL_DEMAND_CONSTRAINT(non_cereal_crop) .. net_supply(non_cereal_crop) =G= demand(non_cereal_crop); + + CEREAL_DEMAND_CONSTRAINT(cereal_crop) .. net_supply(cereal_crop) =G= demand('cereals') * minDemandPerCereal; + + TOTAL_CEREAL_DEMAND_CONSTRAINT .. sum(cereal_crop, net_supply(cereal_crop)) =G= demand('cereals'); - MEAT_DEMAND_CONSTRAINT .. meatEfficency*sum(feed_crop, feedDM(feed_crop) * feedAmount(feed_crop)) + feedDM('pasture_or_meat') * sum(location, area('pasture_or_meat', location) * yield('pasture_or_meat', location)) =G= - demand('pasture_or_meat') - netImportAmount('pasture_or_meat'); + MEAT_DEMAND_CONSTRAINT .. meatEfficency*sum(feed_crop, feedDM(feed_crop) * feedAmount(feed_crop)) + feedDM('pasture') * sum(location, area('pasture', location) * yield('pasture', location)) =G= + demand('meat') - netImportAmount('meat'); MAX_FERT_INTENSITY_CONSTRAINT(crop, location) .. fertI(crop, location) =L= 1; - MAX_IRRIG_INTENSITY_CONSTRAINT(crop, location) .. irrigI(crop, location) =L= 1; TOTAL_LAND_CHANGE_CONSTRAINT(location) .. suitableLandArea(location) =G= sum(crop, area(crop, location)); CROPLAND_CHANGE_CONSTRAINT(location) .. sum(crop_less_pasture, area(crop_less_pasture, location)) =L= (1 + maxLandUseChange) * sum(crop_less_pasture, previousArea(crop_less_pasture, location)); - PASTURE_CHANGE_CONSTRAINT(location) .. area('pasture_or_meat', location) =L= (1 + maxLandUseChange) * previousArea('pasture_or_meat', location); + PASTURE_CHANGE_CONSTRAINT(location) .. area('pasture', location) =L= (1 + maxLandUseChange) * previousArea('pasture', location); AGRI_LAND_INCREASE_CONSTRAINT(location) .. sum(crop, area(crop, location)) =L= (1 + maxLandUseChange) * sum(crop, previousArea(crop, location)); AGRI_LAND_DECREASE_CONSTRAINT(location) .. sum(crop, area(crop, location)) =G= (1 - maxLandUseChange) * sum(crop, previousArea(crop, location)); - NON_FEED_CROP_CONSTRAINT(not_feed_crops) .. feedAmount(not_feed_crops) =E= 0; + NON_FEED_CROP_CONSTRAINT(not_feed_crop) .. feedAmount(not_feed_crop) =E= 0; MAX_NET_IMPORT_CONSTRAINT(crop) .. netImportAmount(crop) =L= maxNetImport(crop); MIN_NET_IMPORT_CONSTRAINT(crop) .. netImportAmount(crop) =G= minNetImport(crop); - MIN_FEED_CONSTRAINT .. sum(feed_crop, feedDM(feed_crop) * feedAmount(feed_crop)) =G= minFeedRate * (demand('pasture_or_meat') - netImportAmount('pasture_or_meat')); + MIN_FEED_CONSTRAINT .. sum(feed_crop, feedDM(feed_crop) * feedAmount(feed_crop)) =G= minFeedRate * (demand('meat') - netImportAmount('meat')); ENERGY_EQ .. energy =E= (SUM((crop, location), area(crop, location) * unitEnergy(crop, location)) + sum(location, sum(crop, area(crop, location)) - sum(crop, previousArea(crop, location)) * landChangeEnergy) @@ -138,7 +144,9 @@ $gdxin MODEL LAND_USE /ALL/ ; SOLVE LAND_USE USING NLP MINIMIZING energy; - + +display net_supply.l, area.l, yield.l, feedAmount.l, netImportAmount.l + Scalar ms 'model status', ss 'solve status'; ms=LAND_USE.modelstat; ss=LAND_USE.solvestat; diff --git a/src/ac/ed/lurg/country/CountryAgent.java b/src/ac/ed/lurg/country/CountryAgent.java index d90227cd..4045f40d 100644 --- a/src/ac/ed/lurg/country/CountryAgent.java +++ b/src/ac/ed/lurg/country/CountryAgent.java @@ -56,7 +56,7 @@ public class CountryAgent { if (landCover != null) { areasItem.setCropArea(CropType.WHEAT, landCover.getLandCover(LandDataType.CROPLAND)); // we allow free substitution between crop types so this is ok-ish - areasItem.setCropArea(CropType.MEAT_OR_PASTURE, landCover.getLandCover(LandDataType.PASTURE)); + areasItem.setCropArea(CropType.PASTURE, landCover.getLandCover(LandDataType.PASTURE)); areasItem.setLandCoverArea(LandDataType.FOREST, landCover.getLandCover(LandDataType.FOREST)); areasItem.setLandCoverArea(LandDataType.OTHER_NATURAL, landCover.getLandCover(LandDataType.OTHER_NATURAL)); } diff --git a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java index 39a3bf30..0fc28992 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java @@ -254,9 +254,9 @@ public class GamsLocationOptimiser { private void addCommodityMapParm(GAMSParameter parm, Map<CommodityType, Double> itemMap) { for (Map.Entry<CommodityType, Double> entry : itemMap.entrySet()) { double d = entry.getValue(); - if (DEBUG) LogWriter.println(String.format(" %15s,\t %.1f", entry.getKey().getFaoName(), d)); + if (DEBUG) LogWriter.println(String.format(" %15s,\t %.1f", entry.getKey().getGamsName(), d)); if (!Double.isNaN(d)) - parm.addRecord(entry.getKey().getFaoName()).setValue(d); + parm.addRecord(entry.getKey().getGamsName()).setValue(d); } } diff --git a/src/ac/ed/lurg/country/gams/GamsLocationTest.java b/src/ac/ed/lurg/country/gams/GamsLocationTest.java index 18d5dc88..d9112d76 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationTest.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationTest.java @@ -35,7 +35,7 @@ public class GamsLocationTest { dummyMap.put(CommodityType.OILCROPS, 50.0); dummyMap.put(CommodityType.PULSES, 60.0); dummyMap.put(CommodityType.STARCHY_ROOTS, 150.0); - dummyMap.put(CommodityType.MEAT_OR_PASTURE, 480.0); + dummyMap.put(CommodityType.MEAT, 480.0); return dummyMap; } @@ -56,7 +56,7 @@ public class GamsLocationTest { for (CropType crop : CropType.getAllItems()) { double factor = base; - if (CropType.MEAT_OR_PASTURE == crop) + if (CropType.PASTURE == crop) factor = base * pastureFactor; yresp.setYield(YieldType.NO_FERT_NO_IRRIG, crop, factor); @@ -102,7 +102,7 @@ public class GamsLocationTest { dummyMap.setCropArea(CropType.OILCROPS, 5.0); dummyMap.setCropArea(CropType.PULSES, 5.0); dummyMap.setCropArea(CropType.STARCHY_ROOTS, 5.0); - dummyMap.setCropArea(CropType.MEAT_OR_PASTURE, 5.0 + pasture); + dummyMap.setCropArea(CropType.PASTURE, 5.0 + pasture); dummyMap.setLandCoverArea(LandDataType.FOREST, 200 - pasture - cereal); dummyMap.setLandCoverArea(LandDataType.OTHER_NATURAL, 30); @@ -119,7 +119,7 @@ public class GamsLocationTest { dummyMap.put(CropType.OILCROPS, 10.0); dummyMap.put(CropType.PULSES, 20.0); dummyMap.put(CropType.STARCHY_ROOTS, 5.0); - dummyMap.put(CropType.MEAT_OR_PASTURE, 80.0); + dummyMap.put(CropType.PASTURE, 80.0); return dummyMap; } @@ -133,7 +133,7 @@ public class GamsLocationTest { dummyMap.put(CropType.OILCROPS, 10.0); dummyMap.put(CropType.PULSES, 20.0); dummyMap.put(CropType.STARCHY_ROOTS, 5.0); - dummyMap.put(CropType.MEAT_OR_PASTURE, 5.0); + dummyMap.put(CropType.PASTURE, 5.0); return dummyMap; } @@ -147,7 +147,7 @@ public class GamsLocationTest { dummyMap.put(CropType.OILCROPS, -10.0); dummyMap.put(CropType.PULSES, -20.0); dummyMap.put(CropType.STARCHY_ROOTS, -5.0); - dummyMap.put(CropType.MEAT_OR_PASTURE, -5.0); + dummyMap.put(CropType.PASTURE, -5.0); return dummyMap; } } diff --git a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java index b47ff427..7d839add 100644 --- a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java @@ -191,12 +191,12 @@ public class GamsRasterOptimiser { } - int numCerealCats = 3; - int numPastureCats = 3; + int numCerealCats = 1; + int numPastureCats = 1; int thisShouldLookAtCropsOtherThanJustWheat; // need to consider other crops, and perhaps other yieldTypes as well List<Double> wheatlDivisions = getDivisions(yieldRaster, CropType.WHEAT, numCerealCats); - List<Double> pastureDivisions = getDivisions(yieldRaster, CropType.MEAT_OR_PASTURE, numPastureCats); + List<Double> pastureDivisions = getDivisions(yieldRaster, CropType.PASTURE, numPastureCats); if (DEBUG) LogWriter.println("Making " + numCerealCats * numPastureCats + " categories"); @@ -236,7 +236,7 @@ public class GamsRasterOptimiser { IrrigationCostItem irrigCost = irrigCostRaster.get(key); int cerealCat = findCategory(wheatlDivisions, yresp.getYieldMax(CropType.WHEAT)); - int pastureCat = findCategory(pastureDivisions, yresp.getYieldMax(CropType.MEAT_OR_PASTURE)); + int pastureCat = findCategory(pastureDivisions, yresp.getYieldMax(CropType.PASTURE)); Integer id = cerealCat + pastureCat * numCerealCats; AveragingYieldResponsesItem avgYResp = aggregatedYields.lazyGet(id); @@ -278,7 +278,7 @@ public class GamsRasterOptimiser { for (Map.Entry<Integer, Set<RasterKey>> e : mapping.entrySet()) { LogWriter.println(e.getKey() + " category has " + e.getValue().size() + " raster areas"); if (DEBUG) for (RasterKey key : e.getValue()) { - LogWriter.println(String.format("\t%s: yields pasture=%.1f, cereal=%.1f", key, yieldRaster.get(key).getYieldMax(CropType.MEAT_OR_PASTURE), yieldRaster.get(key).getYieldMax(CropType.WHEAT))); + LogWriter.println(String.format("\t%s: yields pasture=%.1f, cereal=%.1f", key, yieldRaster.get(key).getYieldMax(CropType.PASTURE), yieldRaster.get(key).getYieldMax(CropType.WHEAT))); } } diff --git a/src/ac/ed/lurg/types/CommodityType.java b/src/ac/ed/lurg/types/CommodityType.java index aa51104e..ae9090a9 100644 --- a/src/ac/ed/lurg/types/CommodityType.java +++ b/src/ac/ed/lurg/types/CommodityType.java @@ -11,7 +11,7 @@ public enum CommodityType { PULSES("Pulses + (Total)", "pulses"), SOYBEAN("Soyabeans", "soybean"), STARCHY_ROOTS("Starchy Roots + (Total)", "starchyRoots"), - MEAT_OR_PASTURE("meatmilkeggs", "pasture_or_meat"); + MEAT("meatmilkeggs", "meat"); private String faoName; private String gamsName; diff --git a/src/ac/ed/lurg/types/CropType.java b/src/ac/ed/lurg/types/CropType.java index 33543231..6f7d5a69 100644 --- a/src/ac/ed/lurg/types/CropType.java +++ b/src/ac/ed/lurg/types/CropType.java @@ -16,7 +16,7 @@ public enum CropType { SOYBEAN("Soyabeans", "soybean"), PULSES("Pulses + (Total)", "pulses"), STARCHY_ROOTS("Starchy Roots + (Total)", "starchyRoots"), - MEAT_OR_PASTURE("meatmilkeggs", "pasture_or_meat"); + PASTURE("meatmilkeggs", "pasture"); private String faoName; private String gamsName; diff --git a/src/ac/ed/lurg/yield/YieldResponse.java b/src/ac/ed/lurg/yield/YieldResponse.java index 5aeb8d98..de53cad2 100644 --- a/src/ac/ed/lurg/yield/YieldResponse.java +++ b/src/ac/ed/lurg/yield/YieldResponse.java @@ -30,7 +30,7 @@ public class YieldResponse { public double getFertParam() { if (fertParm == 0) - fertParm = calcParam(getYield(YieldType.NO_FERT_NO_IRRIG), getYield(YieldType.FERT_MID_NO_IRRIG), getYield(YieldType.FERT_MAX_NO_IRRIG)); + fertParm = calcParam (0, 0.6, 1); // we do have MID fert data, but looks wrong calcParam(getYield(YieldType.NO_FERT_NO_IRRIG), getYield(YieldType.FERT_MID_NO_IRRIG), getYield(YieldType.FERT_MAX_NO_IRRIG)); return fertParm; } -- GitLab