From f089362a229bff4c0cb59bbb2e59b579c38a3003 Mon Sep 17 00:00:00 2001 From: Peter Alexander <peter@blackhillock.co.uk> Date: Wed, 3 Dec 2014 16:03:14 +0000 Subject: [PATCH] Multiple locations per country --- GAMS/IntExtOpt.gms | 80 ++++++++++--------- .../country/gams/GamsLandUseOptimiser.java | 51 ++++++++---- src/ac/ed/lurg/country/gams/GamsTest.java | 4 +- 3 files changed, 80 insertions(+), 55 deletions(-) diff --git a/GAMS/IntExtOpt.gms b/GAMS/IntExtOpt.gms index 9be8ae43..7874b8a2 100644 --- a/GAMS/IntExtOpt.gms +++ b/GAMS/IntExtOpt.gms @@ -3,13 +3,14 @@ SET crop_less_pasture(crop) arable crops types includes treenuts but not pasture / cereals, fruits, oilcrops, starchyRoots, treenuts, vegetables, pulses /; SET feed_crop(crop) / cereals, oilcrops /; SET not_feed_crops(crop) / fruits, starchyRoots, treenuts, vegetables, pulses, pasture_or_meat /; + SET location / 1*2 /; - PARAMETER previous_area(crop) areas for previous timestep in ha; - PARAMETER demand(crop) yield in t per ha; - PARAMETER yield00(crop) yield in t per ha; - PARAMETER yield10(crop) yield in t per ha; - PARAMETER yield01(crop) yield in t per ha; - PARAMETER yield11(crop) yield in t per ha; + PARAMETER previous_area(crop, location) areas for previous timestep in ha; + PARAMETER yield00(crop, location) yield in t per ha; + PARAMETER yield10(crop, location) yield in t per ha; + PARAMETER yield01(crop, location) yield in t per ha; + PARAMETER yield11(crop, location) yield in t per ha; + PARAMETER demand(crop) in t; PARAMETER world_input_energy(crop) average input energy from world exports used to determine if we should import or export; PARAMETER maxNetImport(crop) maximum net import for each crop based on world market; PARAMETER minNetImport(crop) minimum net import for each crop based on world market; @@ -23,9 +24,9 @@ $gdxin %gdxincname% $load previous_area, demand, yield00, yield10, yield01, yield11, world_input_energy, maxNetImport, minNetImport, meatEfficency, maxLandUseChange, tradeBarrier, landChangeEnergy, minFeedRate $gdxin - - DISPLAY landChangeEnergy - + +DISPLAY yield00, yield10, yield01, yield11 + PARAMETER feedEnergy(crop) energy from feed in MJ per t / cereals 13.7 oilcrops 18.6 @@ -37,58 +38,59 @@ $gdxin pasture_or_meat 1.0 / ; VARIABLES - area(crop) total area for each crop - ha + area(crop, location) total area for each crop - ha + fertI(crop, location) fertilizer intensity for each crop - factor between 0 and 1 + 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 - t - fertI(crop) fertilizer intensity for each crop - factor between 0 and 1 - irrigI(crop) irrigation intensity for each crop - factor between 0 and 1 - otherIntensity(crop) other intensity for each crop - unit less netImportAmount(crop) export of crop - t - yield(crop) yield per area for each crop - t per ha - unit_energy(crop) energy per area for each crop - energy + yield(crop, location) yield per area for each crop - t per ha + unit_energy(crop, location) energy per area for each crop - energy energy total input energy - energy; POSITIVE VARIABLE area, fertI, irrigI, otherI, feedAmount; EQUATIONS - UNIT_ENERGY_EQ(crop) energy per area - YIELD_EQ(crop) yield given chosen intensity + UNIT_ENERGY_EQ(crop, location) energy per area + YIELD_EQ(crop, location) yield given chosen intensity CROP_DEMAND_CONSTRAINT(crop_less_pasture) satisfy demand for crop MEAT_DEMAND_CONSTRAINT satisfy demand for crop - MAX_FERT_INTENSITY_CONSTRAINT(crop) constraint on maximum fertilizer intensity - MAX_IRRIG_INTENSITY_CONSTRAINT(crop) constraint on maximum irrigation intensity - CROPLAND_CHANGE_CONSTRAINT constraint on the rate of land use change - PASTURE_CHANGE_CONSTRAINT constraint on the rate of land use change - AGRI_LAND_CHANGE_CONSTRAINT constraint expansion of agricultural land + MAX_FERT_INTENSITY_CONSTRAINT(crop, location) constraint on maximum fertilizer intensity + MAX_IRRIG_INTENSITY_CONSTRAINT(crop, location) constraint on maximum irrigation intensity + CROPLAND_CHANGE_CONSTRAINT(location) constraint on the rate of land use change + PASTURE_CHANGE_CONSTRAINT(location) constraint on the rate of land use change + AGRI_LAND_CHANGE_CONSTRAINT(location) constraint expansion of agricultural land NON_FEED_CROP_CONSTRAINT(not_feed_crops) 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 ENERGY_EQ total energy objective function; - UNIT_ENERGY_EQ(crop) .. unit_energy(crop) =E= (fertI(crop)+irrigI(crop)+otherIntensity(crop)) + sqr(fertI(crop)+irrigI(crop)+otherIntensity(crop)) / 8; + UNIT_ENERGY_EQ(crop, location) .. unit_energy(crop, location) =E= fertI(crop, location)+irrigI(crop, location)+otherIntensity(crop, location) + + sqr(fertI(crop, location)+irrigI(crop, location)+otherIntensity(crop, location)) / 2; - YIELD_EQ(crop) .. yield(crop) =E= ( - yield00(crop)*(1-fertI(crop))*(1-irrigI(crop)) + - yield10(crop)*fertI(crop)*(1-irrigI(crop)) + - yield01(crop)*(1-fertI(crop))*irrigI(crop) + - yield11(crop)*fertI(crop)*irrigI(crop) - ) * otherIntensity(crop); + YIELD_EQ(crop, location) .. yield(crop, location) =E= ( + yield00(crop, location)*(1-fertI(crop, location))*(1-irrigI(crop, location)) + + yield10(crop, location)*fertI(crop, location)*(1-irrigI(crop, location)) + + yield01(crop, location)*(1-fertI(crop, location))*irrigI(crop, location) + + yield11(crop, location)*fertI(crop, location)*irrigI(crop, location) + ) * otherIntensity(crop, location); - CROP_DEMAND_CONSTRAINT(crop_less_pasture) .. area(crop_less_pasture) * yield(crop_less_pasture) - feedAmount(crop_less_pasture) =G= + CROP_DEMAND_CONSTRAINT(crop_less_pasture) .. sum(location, area(crop_less_pasture, location) * yield(crop_less_pasture, location)) - feedAmount(crop_less_pasture) =G= demand(crop_less_pasture) - netImportAmount(crop_less_pasture); - MEAT_DEMAND_CONSTRAINT .. meatEfficency*sum(feed_crop, feedDM(feed_crop) * feedAmount(feed_crop)) + feedDM('pasture_or_meat') * area('pasture_or_meat') * yield('pasture_or_meat') =G= + 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'); - MAX_FERT_INTENSITY_CONSTRAINT(crop) .. fertI(crop) =L= 1; + MAX_FERT_INTENSITY_CONSTRAINT(crop, location) .. fertI(crop, location) =L= 1; - MAX_IRRIG_INTENSITY_CONSTRAINT(crop) .. irrigI(crop) =L= 1; + MAX_IRRIG_INTENSITY_CONSTRAINT(crop, location) .. irrigI(crop, location) =L= 1; - CROPLAND_CHANGE_CONSTRAINT .. 1 - sum(crop_less_pasture, area(crop_less_pasture))/sum(crop_less_pasture, previous_area(crop_less_pasture)) =L= maxLandUseChange; + CROPLAND_CHANGE_CONSTRAINT(location) .. 1 - sum(crop_less_pasture, area(crop_less_pasture, location))/sum(crop_less_pasture, previous_area(crop_less_pasture, location)) =L= maxLandUseChange; - PASTURE_CHANGE_CONSTRAINT .. 1 - area('pasture_or_meat')/previous_area('pasture_or_meat') =L= maxLandUseChange; + PASTURE_CHANGE_CONSTRAINT(location) .. 1 - area('pasture_or_meat', location)/previous_area('pasture_or_meat', location) =L= maxLandUseChange; - AGRI_LAND_CHANGE_CONSTRAINT .. abs(sum(crop, area(crop)) / sum(crop, previous_area(crop)) - 1) =L= maxLandUseChange; + AGRI_LAND_CHANGE_CONSTRAINT(location) .. abs(sum(crop, area(crop, location)) / sum(crop, previous_area(crop, location)) - 1) =L= maxLandUseChange; NON_FEED_CROP_CONSTRAINT(not_feed_crops) .. feedAmount(not_feed_crops) =E= 0; @@ -98,13 +100,15 @@ $gdxin MIN_FEED_CONSTRAINT .. sum(feed_crop, feedDM(feed_crop) * feedAmount(feed_crop)) =G= minFeedRate * (demand('pasture_or_meat') - netImportAmount('pasture_or_meat')); - ENERGY_EQ .. energy =E= SUM(crop, area(crop)*unit_energy(crop)) - + (sum(crop, area(crop)) - sum(crop, previous_area(crop))) * landChangeEnergy + ENERGY_EQ .. energy =E= SUM((crop, location), area(crop, location)*unit_energy(crop, location)) + + sum(location, sum(crop, area(crop, location)) - sum(crop, previous_area(crop, location)) * landChangeEnergy) + sum(crop, (netImportAmount(crop) * tradeBarrier) * world_input_energy(crop)); MODEL LAND_USE /ALL/ ; SOLVE LAND_USE USING DNLP MINIMIZING energy; + DISPLAY yield00, yield10, yield01, yield11 + Scalar ms 'model status', ss 'solve status'; ms=LAND_USE.modelstat; ss=LAND_USE.solvestat; diff --git a/src/ac/ed/lurg/country/gams/GamsLandUseOptimiser.java b/src/ac/ed/lurg/country/gams/GamsLandUseOptimiser.java index 953336f2..bd83bc77 100644 --- a/src/ac/ed/lurg/country/gams/GamsLandUseOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsLandUseOptimiser.java @@ -2,6 +2,7 @@ package ac.ed.lurg.country.gams; import java.io.File; import java.util.Map; +import java.util.Vector; import ac.ed.lurg.ModelConfig; import ac.ed.lurg.country.CropAreas; @@ -39,28 +40,33 @@ public class GamsLandUseOptimiser { GAMSDatabase db = ws.addDatabase(); LogWriter.println("\nPrevious areas"); - GAMSParameter parm = db.addParameter("previous_area", 1, "the previous area for each land use"); - addItemMapParm(parm, inputData.getPreviousCropArea()); + GAMSParameter parm = db.addParameter("previous_area", 2, "the previous area for each land use"); + addLocationMapParm(parm, inputData.getPreviousCropArea(), "1"); + addLocationMapParm(parm, inputData.getPreviousCropArea(), "2"); LogWriter.println("\nDemand"); parm = db.addParameter("demand", 1, "demand for crop"); addItemMapParm(parm, inputData.getProjectedDemand()); LogWriter.println("\nYield"); - parm = db.addParameter("yield00", 1, "ref yield t per ha"); - addItemMapParm(parm, inputData.getRefYield()); + parm = db.addParameter("yield00", 2, "ref yield t per ha"); + addLocationMapParm(parm, inputData.getRefYield(), "1"); + addLocationMapParm(parm, inputData.getRefYield(), "2"); LogWriter.println("\nYield"); - parm = db.addParameter("yield10", 1, "ref yield t per ha"); - addItemMapParm(parm, inputData.getRefYield()); + parm = db.addParameter("yield10", 2, "ref yield t per ha"); + addLocationMapParm(parm, inputData.getRefYield(), "1"); + addLocationMapParm(parm, inputData.getRefYield(), "2"); LogWriter.println("\nYield"); - parm = db.addParameter("yield01", 1, "ref yield t per ha"); - addItemMapParm(parm, inputData.getRefYield()); + parm = db.addParameter("yield01", 2, "ref yield t per ha"); + addLocationMapParm(parm, inputData.getRefYield(), "1"); + addLocationMapParm(parm, inputData.getRefYield(), "2"); LogWriter.println("\nYield"); - parm = db.addParameter("yield11", 1, "ref yield t per ha"); - addItemMapParm(parm, inputData.getRefYield()); + parm = db.addParameter("yield11", 2, "ref yield t per ha"); + addLocationMapParm(parm, inputData.getRefYield(), "1"); + addLocationMapParm(parm, inputData.getRefYield(), "2"); LogWriter.println("\nWorld input energy"); parm = db.addParameter("world_input_energy", 1, "average input energy from world exports used to determine if we should import or export energy per t"); @@ -102,16 +108,17 @@ public class GamsLandUseOptimiser { for (GAMSVariableRecord rec : varAreas) { String itemName = rec.getKeys()[0]; + String locationName = rec.getKeys()[1]; area = rec.getLevel(); - fertIntensity = varFertIntensities.findRecord(itemName).getLevel(); - irrigIntensity = varIrrigIntensities.findRecord(itemName).getLevel(); - otherIntensity = varOtherIntensities.findRecord(itemName).getLevel(); + fertIntensity = varFertIntensities.findRecord(itemName, locationName).getLevel(); + irrigIntensity = varIrrigIntensities.findRecord(itemName, locationName).getLevel(); + otherIntensity = varOtherIntensities.findRecord(itemName, locationName).getLevel(); feedAmount = varFeedAmount.findRecord(itemName).getLevel(); netImports = varNetImports.findRecord(itemName).getLevel(); totalArea += rec.getLevel(); - LogWriter.println(String.format("%15s:\tarea= %.1f,\tfert= %.3f,\tirrg= %.3f,\tintensity= %.3f,\tfeedAmount= %.0f,\tnetImports= %.0f", - itemName, area, fertIntensity, irrigIntensity, otherIntensity, feedAmount, netImports)); + LogWriter.println(String.format("%15s, l%s:\tarea= %.1f,\tfert= %.3f,\tirrg= %.3f,\tintensity= %.3f,\tfeedAmount= %.0f,\tnetImports= %.0f", + itemName, locationName, area, fertIntensity, irrigIntensity, otherIntensity, feedAmount, netImports)); output.addCropArea(CropType.getForGamsName(itemName), area, otherIntensity, feedAmount, netImports); } @@ -132,6 +139,20 @@ public class GamsLandUseOptimiser { } } + private void addLocationMapParm(GAMSParameter parm, Map<CropType, Double> itemMap, String locationId) { + for (Map.Entry<CropType, Double> entry : itemMap.entrySet()) { + LogWriter.println(String.format(" %15s,\t %.1f", entry.getKey().getGamsName(), entry.getValue())); + Vector<String> v = new Vector<String>(); + v.add(entry.getKey().getGamsName()); + v.add(locationId); + if (locationId.equals("2") & entry.getKey().getGamsName().equals("cereals")) + parm.addRecord(v).setValue(0.99); + else + parm.addRecord(v).setValue(entry.getValue()); + } + } + + @SuppressWarnings("unused") private void cleanup(String directory) { File directoryToDelete = new File(directory); diff --git a/src/ac/ed/lurg/country/gams/GamsTest.java b/src/ac/ed/lurg/country/gams/GamsTest.java index b780158c..94b5901a 100644 --- a/src/ac/ed/lurg/country/gams/GamsTest.java +++ b/src/ac/ed/lurg/country/gams/GamsTest.java @@ -23,13 +23,13 @@ public class GamsTest implements GamsInputData { @Override public Map<CropType, Double> getProjectedDemand() { Map<CropType, Double> dummyMap = new HashMap<CropType, Double>(); - dummyMap.put(CropType.CEREALS, 390.0); + dummyMap.put(CropType.CEREALS, 290.0); dummyMap.put(CropType.FRUIT, 50.0); dummyMap.put(CropType.OILCROPS, 100.0); dummyMap.put(CropType.STARCHY_ROOTS, 50.0); dummyMap.put(CropType.PULSES, 60.0); dummyMap.put(CropType.VEGETABLES, 20.0); - dummyMap.put(CropType.MEAT_OR_PASTURE, 800.0); + dummyMap.put(CropType.MEAT_OR_PASTURE, 80.0); dummyMap.put(CropType.TREENUTS, 5.0); return dummyMap; } -- GitLab