diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java index a96c2bae71e551a26ef2e9380e9b55bbebce2106..c055bff12fd9c6c98dd124e444b6297f5a40f19a 100644 --- a/src/ac/ed/lurg/ModelConfig.java +++ b/src/ac/ed/lurg/ModelConfig.java @@ -135,4 +135,5 @@ public class ModelConfig { public static final double SEED_AND_WASTE_FRACTION = getDoubleProperty("SEED_AND_WASTE_FRACTION", 0.1); public static final double MARKET_LAMBA = getDoubleProperty("MARKET_LAMBA", 0.3); // controls market price adjustment rate + public static final double POPULATION_AGGREG_LIMIT = 40; // smaller countries are aggregated on a regional basis } \ No newline at end of file diff --git a/src/ac/ed/lurg/ModelMain.java b/src/ac/ed/lurg/ModelMain.java index 48d078bc15487b2ad0a081b783502cbfcfe3cda6..50063e58de83cb32b1e5e1b06615fbb61bbc5c25 100644 --- a/src/ac/ed/lurg/ModelMain.java +++ b/src/ac/ed/lurg/ModelMain.java @@ -3,8 +3,6 @@ package ac.ed.lurg; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -12,11 +10,13 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import ac.ed.lurg.country.Country; +import ac.ed.lurg.country.CompositeCountry; +import ac.ed.lurg.country.CompositeCountryManager; import ac.ed.lurg.country.CountryAgent; -import ac.ed.lurg.country.CountryBoundaryItem; +import ac.ed.lurg.country.CountryBoundaryRaster; import ac.ed.lurg.country.CountryBoundaryReader; import ac.ed.lurg.country.gams.GamsRasterOutput; +import ac.ed.lurg.demand.BaseConsumpManager; import ac.ed.lurg.demand.DemandManager; import ac.ed.lurg.landuse.AreasItem; import ac.ed.lurg.landuse.CropUsageData; @@ -43,8 +43,9 @@ import ac.sac.raster.RasterSet; public class ModelMain { private Collection<CountryAgent> countryAgents; - private Map<Country, List<RasterKey>> countryToKeysMap; + private CountryBoundaryRaster countryBoundaryRaster; private DemandManager demandManager; + private CompositeCountryManager compositeCountryManager; private Map<CropType, Double> prevWorldPrices; private RasterHeaderDetails desiredProjection; @@ -57,9 +58,13 @@ public class ModelMain { /* setup models, reading inputs, etc. */ private void setup() { desiredProjection = RasterHeaderDetails.getGlobalHeaderFromCellSize(ModelConfig.CELL_SIZE_X, ModelConfig.CELL_SIZE_Y, "999"); - countryToKeysMap = createCountryToKeysMap(); - demandManager = new DemandManager(ModelFitType.LOGISTIC, ModelConfig.SSP_SCENARIO); - countryAgents = createCountryAgents(); + + BaseConsumpManager baseConsumpManager = new BaseConsumpManager(); + compositeCountryManager = new CompositeCountryManager(baseConsumpManager); + demandManager = new DemandManager(ModelFitType.LOGISTIC, ModelConfig.SSP_SCENARIO, baseConsumpManager, compositeCountryManager); + + countryBoundaryRaster = getCountryBoundaryRaster(); + countryAgents = createCountryAgents(compositeCountryManager.getAll()); // in first timestep we don't have this info, but ok as constrained to import/export specified amount prevWorldPrices = new HashMap<CropType, Double>(); @@ -100,7 +105,7 @@ public class ModelMain { for (CountryAgent ca : countryAgents) { LogWriter.println("Country " + ca.getCountry()); - Collection<RasterKey> countryKeys = countryToKeysMap.get(ca.getCountry()); + Collection<RasterKey> countryKeys = countryBoundaryRaster.getKeysFor(ca.getCountry()); YieldRaster countryYieldSurfaces = yieldSurfaces.getSubsetRasterForKeys(countryKeys); // do the optimization @@ -234,49 +239,28 @@ public class ModelMain { }.writeOutput(); } - public Map<Country, List<RasterKey>> createCountryToKeysMap() { - - RasterSet<CountryBoundaryItem> countryBoundaries = new RasterSet<CountryBoundaryItem>(desiredProjection) { - private static final long serialVersionUID = -8449000692429399253L; - protected CountryBoundaryItem createRasterData() { - return new CountryBoundaryItem(); - } - }; - + public CountryBoundaryRaster getCountryBoundaryRaster() { + CountryBoundaryRaster countryBoundaries = new CountryBoundaryRaster(desiredProjection, compositeCountryManager); CountryBoundaryReader countryReader = new CountryBoundaryReader(countryBoundaries); countryReader.getRasterDataFromFile(ModelConfig.COUNTRY_BOUNDARY_FILE); - - Map<Country, List<RasterKey>> countryMap = new HashMap<Country, List<RasterKey>>(); - - for (Map.Entry<RasterKey, CountryBoundaryItem> entry : countryBoundaries.entrySet()) { - Country c = entry.getValue().getCountry(); - if (c == null) - continue; - - List<RasterKey> keys = countryMap.get(c); - - if (keys == null) { - keys = new ArrayList<RasterKey>(); - countryMap.put(c, keys); - } - keys.add(entry.getKey()); - } - return countryMap; + + return countryBoundaries; } - public Collection<CountryAgent> createCountryAgents() { + public Collection<CountryAgent> createCountryAgents(Collection<CompositeCountry> countryGrouping) { Collection<CountryAgent> countryAgents = new HashSet<CountryAgent>(); RasterSet<LandCoverItem> initLC = getInitialLandCover(); RasterSet<IrrigationCostItem> allIrrigationCosts = getIrrigationCosts(); - - Map<Country, Map<CropType, CropUsageData>> cropUsageDataMap = new CropUsageReader().getCommodityData(); - - HashSet<String> countryExclusionList = new HashSet<String>(Arrays.asList("Bangladesh", "Portugal", "Haiti", "Myanmar")); //"French Polynesia", "Cabo Verde", "Samoa", "Saint Vincent and the Grenadines")); - for (Map.Entry<Country, List<RasterKey>> entry : countryToKeysMap.entrySet()) { - Country country = entry.getKey(); - List<RasterKey> keys = entry.getValue(); + Map<CompositeCountry, Map<CropType, CropUsageData>> cropUsageDataMap = new CropUsageReader(compositeCountryManager).getCommodityData(); + + //HashSet<String> countryExclusionList = new HashSet<String>(Arrays.asList("Bangladesh", "Portugal", "Haiti", "Myanmar")); //"French Polynesia", "Cabo Verde", "Samoa", "Saint Vincent and the Grenadines")); + + for (CompositeCountry cc : countryGrouping) { + + //countryToKeysMap + List<RasterKey> keys = countryBoundaryRaster.getKeysFor(cc); // DEBUG code @@ -284,23 +268,23 @@ public class ModelMain { // continue; // } - if (demandManager.getPopulation(country, 2010) < 8 || countryExclusionList.contains(country.getCountryName())) { - LogWriter.printlnError("Skipping " + country); - continue; - } + // if (demandManager.getPopulation(country, 2010) < 8 || countryExclusionList.contains(country.getCountryName())) { + // LogWriter.printlnError("Skipping " + country); + // continue; + // } RasterSet<LandCoverItem> initCountryLC = initLC.popSubsetForKeys(new RasterSet<LandCoverItem>(initLC.getHeaderDetails()), keys); RasterSet<IrrigationCostItem> irrigationCosts = allIrrigationCosts.popSubsetForKeys(new RasterSet<IrrigationCostItem>(allIrrigationCosts.getHeaderDetails()), keys); - Map<CropType, CropUsageData> countryCommodityData = cropUsageDataMap.get(country); + Map<CropType, CropUsageData> countryCommodityData = cropUsageDataMap.get(cc); if (countryCommodityData == null) { - LogWriter.printlnError("No commodities data for " +country + ", so skipping"); + LogWriter.printlnError("No commodities data for " + cc + ", so skipping"); } else if (initCountryLC.size() == 0) { - LogWriter.printlnError("No initial land cover for " +country + ", so skipping"); + LogWriter.printlnError("No initial land cover for " +cc + ", so skipping"); } else { - CountryAgent ca = new CountryAgent(demandManager, country, initCountryLC, irrigationCosts, countryCommodityData); + CountryAgent ca = new CountryAgent(demandManager, cc, initCountryLC, irrigationCosts, countryCommodityData); countryAgents.add(ca); } } diff --git a/src/ac/ed/lurg/country/CompositeCountry.java b/src/ac/ed/lurg/country/CompositeCountry.java new file mode 100644 index 0000000000000000000000000000000000000000..db22abd7db63baf2c654847eeac13e664cb4292a --- /dev/null +++ b/src/ac/ed/lurg/country/CompositeCountry.java @@ -0,0 +1,22 @@ +package ac.ed.lurg.country; + + +public class CompositeCountry { + + private String name; + + public CompositeCountry (String name) { + super(); + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return name; + } + +} diff --git a/src/ac/ed/lurg/country/CompositeCountryManager.java b/src/ac/ed/lurg/country/CompositeCountryManager.java new file mode 100644 index 0000000000000000000000000000000000000000..34a461193002d37d79d558c08df48bfd65fef79e --- /dev/null +++ b/src/ac/ed/lurg/country/CompositeCountryManager.java @@ -0,0 +1,65 @@ +package ac.ed.lurg.country; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import ac.ed.lurg.ModelConfig; +import ac.ed.lurg.demand.BaseConsumpManager; +import ac.ed.lurg.utils.CollectionHelper; + +public class CompositeCountryManager { + + private Map<String, CompositeCountry> mapFromName = new HashMap<String, CompositeCountry>(); + private Map<SingleCountry, CompositeCountry> mapFromSingleCountry; + private Map<CompositeCountry, List<SingleCountry>> mapFromCompositeCountry; + + public CompositeCountryManager(BaseConsumpManager baseConsumpManager) { + super(); + populate(baseConsumpManager); + } + + private void populate(BaseConsumpManager baseConsumpManager) { + mapFromSingleCountry = new HashMap<SingleCountry, CompositeCountry>(); + + HashSet<String> countryExclusionList = new HashSet<String>(Arrays.asList("Bangladesh", "Portugal", "Haiti")); + + for (SingleCountry c : baseConsumpManager.getAllCountries()) { + CompositeCountry cc; + + if (baseConsumpManager.getBasePopulation(c) < ModelConfig.POPULATION_AGGREG_LIMIT || countryExclusionList.contains(c.getCountryName())) + cc = getForName(c.getRegion() + "_other"); + else + cc = getForName(c.getCountryName()); + + mapFromSingleCountry.put(c, cc); + } + + mapFromCompositeCountry = CollectionHelper.invertMap(mapFromSingleCountry); + } + + private CompositeCountry getForName(String name) { + CompositeCountry cc = mapFromName.get(name); + + if (cc == null) { + cc = new CompositeCountry(name); + mapFromName.put(name, cc); + } + return cc; + } + + public CompositeCountry getForSingleCountry(SingleCountry c) { + return mapFromSingleCountry.get(c); + } + + public Collection<CompositeCountry> getAll() { + return mapFromName.values(); + } + + public Collection<SingleCountry> getAllForCompositeCountry(CompositeCountry cc) { + return mapFromCompositeCountry.get(cc); + } +} diff --git a/src/ac/ed/lurg/country/CountryAgent.java b/src/ac/ed/lurg/country/CountryAgent.java index 0dc9ddf42fe92214bdd04d3ab41e40abb1dc57ff..550a05c433694657140fa6c79ba2432ab44fffa0 100644 --- a/src/ac/ed/lurg/country/CountryAgent.java +++ b/src/ac/ed/lurg/country/CountryAgent.java @@ -23,7 +23,7 @@ import ac.sac.raster.RasterSet; public class CountryAgent { private DemandManager demandManager; - private Country country; + private CompositeCountry country; private Map<Timestep, GamsRasterOutput> resultsTimeseries = new HashMap<Timestep, GamsRasterOutput>(); @@ -31,7 +31,7 @@ public class CountryAgent { private YieldRaster countryYieldSurfaces; private RasterSet<IrrigationCostItem> irrigationCostRaster; - public CountryAgent(DemandManager demandManager, Country country, RasterSet<LandCoverItem> initialLC, + public CountryAgent(DemandManager demandManager, CompositeCountry country, RasterSet<LandCoverItem> initialLC, RasterSet<IrrigationCostItem> irrigationCostRaster, Map<CropType, CropUsageData> cropUsageData) { this.demandManager = demandManager; @@ -58,7 +58,7 @@ public class CountryAgent { return cropAreaRaster; } - public Country getCountry() { + public CompositeCountry getCountry() { return country; } @@ -79,7 +79,7 @@ public class CountryAgent { // optimize areas and intensity GamsRasterInput input = getGamsRasterInput(projectedDemand, worldInputPrices); GamsRasterOptimiser opti = new GamsRasterOptimiser(input); - LogWriter.println("Running " + country.getCountryName() + ", currentTimestep " + currentTimestep); + LogWriter.println("Running " + country.getName() + ", currentTimestep " + currentTimestep); GamsRasterOutput result = opti.run(); resultsTimeseries.put(timestep, result); diff --git a/src/ac/ed/lurg/country/CountryBoundaryItem.java b/src/ac/ed/lurg/country/CountryBoundaryItem.java index 822a854ef414c31346a9dffd6fcde366b3c4e248..23d127fe6dc0fec376df4a9de6bbff4b5402c682 100644 --- a/src/ac/ed/lurg/country/CountryBoundaryItem.java +++ b/src/ac/ed/lurg/country/CountryBoundaryItem.java @@ -4,13 +4,13 @@ import ac.sac.raster.RasterItem; public class CountryBoundaryItem implements RasterItem { - Country country; + SingleCountry country; - public Country getCountry() { + public SingleCountry getCountry() { return country; } - public void setCountry(Country country) { + public void setCountry(SingleCountry country) { this.country = country; } diff --git a/src/ac/ed/lurg/country/CountryBoundaryRaster.java b/src/ac/ed/lurg/country/CountryBoundaryRaster.java new file mode 100644 index 0000000000000000000000000000000000000000..223a8d91e80482c5773e3b0073d4aee48970cbd3 --- /dev/null +++ b/src/ac/ed/lurg/country/CountryBoundaryRaster.java @@ -0,0 +1,58 @@ +package ac.ed.lurg.country; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import ac.sac.raster.RasterHeaderDetails; +import ac.sac.raster.RasterKey; +import ac.sac.raster.RasterSet; + +public class CountryBoundaryRaster extends RasterSet<CountryBoundaryItem> { + Collection<CompositeCountry> countryGrouping; + CompositeCountryManager compositeCountryManager; + + public CountryBoundaryRaster(RasterHeaderDetails header, CompositeCountryManager compositeCountryManager) { + super(header); + this.compositeCountryManager = compositeCountryManager; + } + + private static final long serialVersionUID = -8449000692429399253L; + protected CountryBoundaryItem createRasterData() { + return new CountryBoundaryItem(); + } + + private Map<CompositeCountry, List<RasterKey>> countryMap; + + private Map<CompositeCountry, List<RasterKey>> getCountryToKeysMap() { + + if (countryMap == null) { + countryMap = new HashMap<CompositeCountry, List<RasterKey>>(); + + for (Map.Entry<RasterKey, CountryBoundaryItem> entry : entrySet()) { + SingleCountry c = entry.getValue().getCountry(); + if (c == null) + continue; + + CompositeCountry cc = compositeCountryManager.getForSingleCountry(c); + List<RasterKey> keys = countryMap.get(cc); + + if (keys == null) { + keys = new ArrayList<RasterKey>(); + countryMap.put(cc, keys); + } + keys.add(entry.getKey()); + } + } + return countryMap; + } + + public List<RasterKey> getKeysFor(CompositeCountry cc) { + List<RasterKey> keys = getCountryToKeysMap().get(cc); + if (keys == null) + keys = new ArrayList<RasterKey>(); + return keys; + } +} diff --git a/src/ac/ed/lurg/country/CountryBoundaryReader.java b/src/ac/ed/lurg/country/CountryBoundaryReader.java index 74371d235a2dfe0d6528ef838a37f7de4f8f3796..e1eb38c56d026bfbcd2955f75ba0791b59568187 100644 --- a/src/ac/ed/lurg/country/CountryBoundaryReader.java +++ b/src/ac/ed/lurg/country/CountryBoundaryReader.java @@ -12,7 +12,7 @@ public class CountryBoundaryReader extends AbstractRasterReader<CountryBoundaryI @Override public void setData(CountryBoundaryItem item, String token) { int isoCode = Integer.parseInt(token); - Country c = CountryManager.getForCode(isoCode); + SingleCountry c = CountryManager.getForCode(isoCode); item.setCountry(c); } } \ No newline at end of file diff --git a/src/ac/ed/lurg/country/CountryManager.java b/src/ac/ed/lurg/country/CountryManager.java index 8f182320824d7ad2ae4008ac4fa20d59d5c1c3a2..00ba38a0d1aa582688cf5a30e222c99ce7f6bc13 100644 --- a/src/ac/ed/lurg/country/CountryManager.java +++ b/src/ac/ed/lurg/country/CountryManager.java @@ -15,8 +15,8 @@ public class CountryManager { private static final int REGION_COL = 2; private static final int NUM_CODE_COL = 4; - private final Map<String, Country> nameMap = new HashMap<String, Country>(); - private final Map<Integer, Country> numCodeMap = new HashMap<Integer, Country>(); + private final Map<String, SingleCountry> nameMap = new HashMap<String, SingleCountry>(); + private final Map<Integer, SingleCountry> numCodeMap = new HashMap<Integer, SingleCountry>(); private static CountryManager instance = null; @@ -46,7 +46,7 @@ public class CountryManager { region = tokens[REGION_COL]; numCode = Integer.parseInt(tokens[NUM_CODE_COL]); - Country c = new Country(name, charCode, numCode, region); + SingleCountry c = new SingleCountry(name, charCode, numCode, region); nameMap.put(name, c); numCodeMap.put(numCode, c); } @@ -60,13 +60,13 @@ public class CountryManager { } - public static Country getForName(String name) { - Country c = getInstance().nameMap.get(name); + public static SingleCountry getForName(String name) { + SingleCountry c = getInstance().nameMap.get(name); return c; } - public static Country getForCode(int isoCode) { - Country c = getInstance().numCodeMap.get(isoCode); + public static SingleCountry getForCode(int isoCode) { + SingleCountry c = getInstance().numCodeMap.get(isoCode); return c; } } diff --git a/src/ac/ed/lurg/country/Country.java b/src/ac/ed/lurg/country/SingleCountry.java similarity index 82% rename from src/ac/ed/lurg/country/Country.java rename to src/ac/ed/lurg/country/SingleCountry.java index d44edc77b146c4903aa23ab097e143ad3aacef9a..724bdf2d09d140e808993ac6ef619941c89b5ab8 100644 --- a/src/ac/ed/lurg/country/Country.java +++ b/src/ac/ed/lurg/country/SingleCountry.java @@ -1,14 +1,13 @@ package ac.ed.lurg.country; - -public class Country { +public class SingleCountry { private String countryName; private String iso3CharCode; private int iso3NumCode; private String region; - public Country(String countryName, String iso3CharCode, int iso3NumCode, String region) { + public SingleCountry(String countryName, String iso3CharCode, int iso3NumCode, String region) { super(); this.countryName = countryName; this.iso3CharCode = iso3CharCode; @@ -28,6 +27,10 @@ public class Country { return countryName; } + public String getRegion() { + return region; + } + @Override public String toString() { return countryName; @@ -50,7 +53,7 @@ public class Country { return false; if (getClass() != obj.getClass()) return false; - Country other = (Country) obj; + SingleCountry other = (SingleCountry) obj; if (countryName == null) { if (other.countryName != null) return false; @@ -58,4 +61,4 @@ public class Country { return false; return true; } -} +} \ No newline at end of file diff --git a/src/ac/ed/lurg/country/gams/GamsCountryInput.java b/src/ac/ed/lurg/country/gams/GamsCountryInput.java index bccfbe43cb62865ee22094d417d61a8461602a0e..ee041bf37a4f4ed7515b8131060371dff88652a6 100644 --- a/src/ac/ed/lurg/country/gams/GamsCountryInput.java +++ b/src/ac/ed/lurg/country/gams/GamsCountryInput.java @@ -4,13 +4,13 @@ import java.util.HashMap; import java.util.Map; import ac.ed.lurg.ModelConfig; -import ac.ed.lurg.country.Country; +import ac.ed.lurg.country.CompositeCountry; import ac.ed.lurg.types.CommodityType; import ac.ed.lurg.types.CropType; public class GamsCountryInput { - private Country country; // not really required but useful for debugging + private CompositeCountry country; // not really required but useful for debugging private Map<CommodityType, Double> projectedDemand; private Map<CropType, Double> worldInputPrices; private Map<CropType, Double> maxNetImport; @@ -27,7 +27,7 @@ public class GamsCountryInput { private double landChangeEnergy;*/ - private GamsCountryInput(Country country, Map<CommodityType, Double> projectedDemand, Map<CropType, Double> worldInputPrices, + private GamsCountryInput(CompositeCountry country, Map<CommodityType, Double> projectedDemand, Map<CropType, Double> worldInputPrices, Map<CropType, Double> maxNetImport, Map<CropType, Double> minNetImport, Map<CropType, Double> cropAdjustments, boolean calibrateToObserved) { super(); this.country = country; @@ -39,7 +39,7 @@ public class GamsCountryInput { this.calibrateToObserved = calibrateToObserved; } - public static GamsCountryInput createInput(Country country, Map<CommodityType, Double> projectedDemand, Map<CropType, Double> worldInputPrices, + public static GamsCountryInput createInput(CompositeCountry country, Map<CommodityType, Double> projectedDemand, Map<CropType, Double> worldInputPrices, Map<CropType, Double> baseNetImport, Map<CropType, Double> maxOfProdOrSupply, Map<CropType, Double> cropAdjustments, boolean calibrateToObserved) { Map<CropType, Double> maxNetImport; @@ -72,7 +72,7 @@ public class GamsCountryInput { } - public Country getCountry() { + public CompositeCountry getCountry() { return country; } diff --git a/src/ac/ed/lurg/country/gams/GamsLocationTest.java b/src/ac/ed/lurg/country/gams/GamsLocationTest.java index 1cdf9348aeecddd415091213f3fac02c47d72ac5..67e2b48e4b88fa306980455a72e213123d4b76b0 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationTest.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationTest.java @@ -4,7 +4,7 @@ import java.util.HashMap; import java.util.Map; import ac.ed.lurg.Timestep; -import ac.ed.lurg.country.Country; +import ac.ed.lurg.country.CompositeCountry; import ac.ed.lurg.landuse.AreasItem; import ac.ed.lurg.landuse.IrrigationCostItem; import ac.ed.lurg.types.CommodityType; @@ -22,7 +22,7 @@ public class GamsLocationTest { } private void run() { - GamsCountryInput countryLevelInputs = GamsCountryInput.createInput(new Country("Test", "TES", 123, "R1"), getProjectedDemand(), getWorldInputEnergy(), getBaseNetImport(), null, null, true); + GamsCountryInput countryLevelInputs = GamsCountryInput.createInput(new CompositeCountry("Test"), getProjectedDemand(), getWorldInputEnergy(), getBaseNetImport(), null, null, true); GamsLocationInput gamsInput = new GamsLocationInput(new Timestep(0), getYields(), getPreviousArea(), getIrrigationCosts(), countryLevelInputs); GamsLocationOptimiser opti = new GamsLocationOptimiser(gamsInput); diff --git a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java index fe5bafbf641656ca121b482c83cfcfab3493a7a4..906d62e41a06c71d767077fb0d6c31d1b71fd113 100644 --- a/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsRasterOptimiser.java @@ -94,7 +94,7 @@ public class GamsRasterOptimiser { AreasItem prevAreaAggItem = prevAreasAgg.get(locId); Set<RasterKey> keys = mapping.get(locId); - // if (DEBUG) + if (DEBUG) checkedTotalAreas(newAreaRaster.popSubsetForKeys(new RasterSet<AreasItem>(newAreaRaster.getHeaderDetails()), keys), locId + " before"); double pastureChange = newAreaAggItem.getLandCoverArea(LandCoverType.PASTURE) - prevAreaAggItem.getLandCoverArea(LandCoverType.PASTURE); @@ -136,7 +136,7 @@ public class GamsRasterOptimiser { if (shortfall > 0.00001) LogWriter.printlnError("This should never happen, due to GAMS constraint. Not able to incorporate all changes, as not enough forest or natural areas left: " + locId + ": " + shortfall); - // if (DEBUG) + if (DEBUG) checkedTotalAreas(newAreaRaster.popSubsetForKeys(new RasterSet<AreasItem>(newAreaRaster.getHeaderDetails()), keys), locId + " after"); for (RasterKey key : keys) { diff --git a/src/ac/ed/lurg/country/gams/GamsRasterTest.java b/src/ac/ed/lurg/country/gams/GamsRasterTest.java index 40c65ac261e8c8843ad6786e10c92b60e2a964f0..e4968ef61d07a7705b91dacf7a8b983795f1d730 100644 --- a/src/ac/ed/lurg/country/gams/GamsRasterTest.java +++ b/src/ac/ed/lurg/country/gams/GamsRasterTest.java @@ -1,7 +1,7 @@ package ac.ed.lurg.country.gams; import ac.ed.lurg.Timestep; -import ac.ed.lurg.country.Country; +import ac.ed.lurg.country.CompositeCountry; import ac.ed.lurg.landuse.AreasItem; import ac.ed.lurg.landuse.IrrigationCostItem; import ac.ed.lurg.utils.LogWriter; @@ -18,7 +18,7 @@ public class GamsRasterTest extends GamsLocationTest { } private void run() { - GamsCountryInput countryLevelInputs = GamsCountryInput.createInput(new Country("Test", "TES", 123, "R1"), getProjectedDemand(), getWorldInputEnergy(), getBaseNetImport(), null, null, true); + GamsCountryInput countryLevelInputs = GamsCountryInput.createInput(new CompositeCountry("Test"), getProjectedDemand(), getWorldInputEnergy(), getBaseNetImport(), null, null, true); GamsRasterInput input = new GamsRasterInput(new Timestep(0), getYieldRaster(), getPreviousAreaRaster(), getIrrigationCost(), countryLevelInputs); GamsRasterOptimiser opti = new GamsRasterOptimiser(input); diff --git a/src/ac/ed/lurg/demand/BaseConsumpManager.java b/src/ac/ed/lurg/demand/BaseConsumpManager.java index 18d1303fee7497a7b43330767d4b005b8d6ff7c9..062b6035f04779ef050c918ba2151c0aadcc1415 100644 --- a/src/ac/ed/lurg/demand/BaseConsumpManager.java +++ b/src/ac/ed/lurg/demand/BaseConsumpManager.java @@ -2,21 +2,24 @@ package ac.ed.lurg.demand; import java.io.BufferedReader; import java.io.FileReader; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import ac.ed.lurg.ModelConfig; -import ac.ed.lurg.country.Country; import ac.ed.lurg.country.CountryManager; +import ac.ed.lurg.country.SingleCountry; import ac.ed.lurg.types.CommodityType; import ac.ed.lurg.utils.LogWriter; public class BaseConsumpManager { private static final int COUNTRY_COL = 0; + private static final int BASE_POP_COL = 1; private static final int COMMODITY_COL = 3; private static final int BASE_CPC_COL = 7; - private Map<Country, Map<CommodityType, Double>> baseConsumpMap = new HashMap<Country, Map<CommodityType, Double>>(); + private Map<SingleCountry, Map<CommodityType, Double>> baseConsumpMap = new HashMap<SingleCountry, Map<CommodityType, Double>>(); + private Map<SingleCountry, Double> basePop = new HashMap<SingleCountry, Double>(); public BaseConsumpManager() { super(); @@ -28,7 +31,7 @@ public class BaseConsumpManager { try { BufferedReader fitReader = new BufferedReader(new FileReader(filename)); String line, countryName, commodityName; - double cpc; + double pop, cpc; fitReader.readLine(); // read header while ((line=fitReader.readLine()) != null) { @@ -38,10 +41,11 @@ public class BaseConsumpManager { LogWriter.printlnError("Too few columns in " + filename + ", " + line); countryName = tokens[COUNTRY_COL]; + pop = Double.parseDouble(tokens[BASE_POP_COL]); commodityName = tokens[COMMODITY_COL]; cpc = Double.parseDouble(tokens[BASE_CPC_COL]); - Country country = CountryManager.getForName(countryName); + SingleCountry country = CountryManager.getForName(countryName); CommodityType commodity = CommodityType.getForFaoName(commodityName); Map<CommodityType, Double> commodityMap = baseConsumpMap.get(country); @@ -51,6 +55,7 @@ public class BaseConsumpManager { } commodityMap.put(commodity, cpc); + basePop.put(country, pop); } fitReader.close(); @@ -61,7 +66,7 @@ public class BaseConsumpManager { LogWriter.println("Processed " + filename + ", create " + baseConsumpMap.size() + " base consumption values"); } - public double get(Country country, CommodityType commodity) { + public double get(SingleCountry country, CommodityType commodity) { Map<CommodityType, Double> commodityMap = baseConsumpMap.get(country); if (commodityMap == null || !commodityMap.containsKey(commodity)) { @@ -72,4 +77,13 @@ public class BaseConsumpManager { Double d = commodityMap.get(commodity); return d.doubleValue(); } + + public double getBasePopulation(SingleCountry country) { + Double d = basePop.get(country); + return (d != null) ? d.doubleValue() : Double.NaN; + } + + public Collection<SingleCountry> getAllCountries() { + return basePop.keySet(); + } } diff --git a/src/ac/ed/lurg/demand/BioenergyDemand.java b/src/ac/ed/lurg/demand/BioenergyDemand.java index 45dbb491d57242931f6132e07b02fc66805b98fd..4b5bbeb6ad25823331ca59743bfe3c8be79bc7df 100644 --- a/src/ac/ed/lurg/demand/BioenergyDemand.java +++ b/src/ac/ed/lurg/demand/BioenergyDemand.java @@ -7,8 +7,8 @@ import java.util.HashMap; import java.util.Map; import ac.ed.lurg.ModelConfig; -import ac.ed.lurg.country.Country; import ac.ed.lurg.country.CountryManager; +import ac.ed.lurg.country.SingleCountry; import ac.ed.lurg.types.CommodityType; import ac.ed.lurg.utils.LazyHashMap; import ac.ed.lurg.utils.LogWriter; @@ -19,9 +19,9 @@ public class BioenergyDemand { private static final int OTHER_COL = 3; @SuppressWarnings("serial") - public Map<Country, Map<CommodityType, Double>> getBioenergyData() { + public Map<SingleCountry, Map<CommodityType, Double>> getBioenergyData() { - LazyHashMap<Country, Map<CommodityType, Double>> bioenergyMap = new LazyHashMap<Country, Map<CommodityType, Double>>() { + LazyHashMap<SingleCountry, Map<CommodityType, Double>> bioenergyMap = new LazyHashMap<SingleCountry, Map<CommodityType, Double>>() { protected Map<CommodityType, Double> createValue() { return new HashMap<CommodityType, Double>(); } }; @@ -42,7 +42,7 @@ public class BioenergyDemand { commodityName = tokens[COMMODITY_COL]; other = Double.parseDouble(tokens[OTHER_COL]); - Country country = CountryManager.getForName(countryName); + SingleCountry country = CountryManager.getForName(countryName); CommodityType crop = CommodityType.getForFaoName(commodityName); Map<CommodityType, Double> countryData = bioenergyMap.lazyGet(country); diff --git a/src/ac/ed/lurg/demand/DemandManager.java b/src/ac/ed/lurg/demand/DemandManager.java index 0721321a3ef2048f9ebb5ec3a74e7dd3548b123f..547b7d9f008cdaf2f3337f0f133e52297c744b69 100644 --- a/src/ac/ed/lurg/demand/DemandManager.java +++ b/src/ac/ed/lurg/demand/DemandManager.java @@ -4,7 +4,9 @@ import java.util.HashMap; import java.util.Map; import ac.ed.lurg.ModelConfig; -import ac.ed.lurg.country.Country; +import ac.ed.lurg.country.CompositeCountry; +import ac.ed.lurg.country.CompositeCountryManager; +import ac.ed.lurg.country.SingleCountry; import ac.ed.lurg.types.CommodityType; import ac.ed.lurg.types.ModelFitType; import ac.ed.lurg.utils.LogWriter; @@ -14,45 +16,58 @@ public class DemandManager { private DemandCurveManager demandCurveManager; private SspManager sspManager; private BaseConsumpManager baseConsumpManager; - private Map<Country, Map<CommodityType, Double>> bioenergyBaseDemand; + private CompositeCountryManager compositeCountryManager; + private Map<SingleCountry, Map<CommodityType, Double>> bioenergyBaseDemand; - private ModelFitType fitType; // these could be mutable + private ModelFitType fitType; private String ssp_scenario; - public DemandManager (ModelFitType fitType, String ssp_scenario) { + public DemandManager (ModelFitType fitType, String ssp_scenario, BaseConsumpManager baseConsumpManager, CompositeCountryManager compositeCountryManager) { this.fitType = fitType; this.ssp_scenario = ssp_scenario; + this.baseConsumpManager = baseConsumpManager; + this.compositeCountryManager = compositeCountryManager; demandCurveManager = new DemandCurveManager(); sspManager = new SspManager(); - baseConsumpManager = new BaseConsumpManager(); bioenergyBaseDemand = new BioenergyDemand().getBioenergyData(); } - public Map<CommodityType, Double> getDemand(Country country, int year) { - SspData baseSspData = sspManager.get(ssp_scenario, ModelConfig.BASE_YEAR, country); - + public Map<CommodityType, Double> getDemand(CompositeCountry cc, int year) { Map<CommodityType, Double> demandMap = new HashMap<CommodityType, Double>(); - SspData sd = sspManager.get(ssp_scenario, year, country); - - LogWriter.println("Got ssp data for " + country.getCountryName() + " of " + sd); - - if (sd == null) { - LogWriter.printlnError("No ssp data for " + ssp_scenario + ", " + year + ", " + country.getCountryName()); - return demandMap; - } + + for (SingleCountry c : compositeCountryManager.getAllForCompositeCountry(cc)) { + SspData baseSspData = sspManager.get(ssp_scenario, ModelConfig.BASE_YEAR, c); - for (DemandCurve dc : demandCurveManager.get(fitType)) { - double cpc = dc.getConsumptionPc(baseSspData.getGdpPc(), baseConsumpManager.get(country, dc.getCommodityType()), sd.getGdpPc()); - double d = cpc * sd.getPopulation(); + SspData sd = sspManager.get(ssp_scenario, year, c); + + LogWriter.println("Got ssp data for " + c.getCountryName() + " of " + sd); - double bioenergy = getBioenergyDemand(country, year, dc.getCommodityType()); - // LogWriter.println(String.format("Country %s comm %s: %f", country, dc.getCommodityType(), bioenergy)); - demandMap.put(dc.getCommodityType(), d + bioenergy); + if (sd == null) { + LogWriter.printlnError("No ssp data for " + ssp_scenario + ", " + year + ", " + c.getCountryName()); + continue; + } + + for (DemandCurve dc : demandCurveManager.get(fitType)) { + double cpc = dc.getConsumptionPc(baseSspData.getGdpPc(), baseConsumpManager.get(c, dc.getCommodityType()), sd.getGdpPc()); + double d = cpc * sd.getPopulation(); + + double bioenergy = getBioenergyDemand(c, year, dc.getCommodityType()); + // LogWriter.println(String.format("Country %s comm %s: %f", country, dc.getCommodityType(), bioenergy)); + + double newDemand = d + bioenergy; + Double prevDemand = demandMap.get(dc.getCommodityType()); + + if (prevDemand != null) + newDemand += prevDemand.doubleValue(); // aggregate if composite country + + demandMap.put(dc.getCommodityType(), newDemand); + } } + return demandMap; } - private double getBioenergyDemand(Country country, int year, CommodityType commodity) { + private double getBioenergyDemand(SingleCountry country, int year, CommodityType commodity) { // could adjust for year somehow, but not doing this yet if (bioenergyBaseDemand != null && bioenergyBaseDemand.containsKey(country)) { Double d = bioenergyBaseDemand.get(country).get(commodity); @@ -61,7 +76,7 @@ public class DemandManager { return 0.0; } - public double getPopulation (Country country, int year) { +/* public double getPopulation (SingleCountry country, int year) { SspData sd = sspManager.get(ssp_scenario, year, country); if (sd == null) { LogWriter.printlnError("No ssp data for " + ssp_scenario + ", " + year + ", " + country.getCountryName()); @@ -69,9 +84,10 @@ public class DemandManager { } else return sd.getPopulation(); - } + } public String getModelAndScenarioDescription() { return fitType + " " + ssp_scenario; } + */ } diff --git a/src/ac/ed/lurg/demand/SspKey.java b/src/ac/ed/lurg/demand/SspKey.java index 725284bd07cedf2fd023451b625d87eccf6b7062..25b43f3bdde7e6674f2cc33d8312ae26bf9946f8 100644 --- a/src/ac/ed/lurg/demand/SspKey.java +++ b/src/ac/ed/lurg/demand/SspKey.java @@ -1,13 +1,14 @@ package ac.ed.lurg.demand; -import ac.ed.lurg.country.Country; +import ac.ed.lurg.country.SingleCountry; + public class SspKey { private String scenario; private int year; - private Country country; + private SingleCountry country; - public SspKey(String scenario, int year, Country country) { + public SspKey(String scenario, int year, SingleCountry country) { super(); this.scenario = scenario; this.year = year; @@ -22,7 +23,7 @@ public class SspKey { return year; } - public Country getCountry() { + public SingleCountry getCountry() { return country; } diff --git a/src/ac/ed/lurg/demand/SspManager.java b/src/ac/ed/lurg/demand/SspManager.java index e82b7c3ae57b07d9ae1ae586876e083087e6ba4a..fbd3fc566634680de2cc157a8fea7deaa6742628 100644 --- a/src/ac/ed/lurg/demand/SspManager.java +++ b/src/ac/ed/lurg/demand/SspManager.java @@ -6,8 +6,8 @@ import java.util.HashMap; import java.util.Map; import ac.ed.lurg.ModelConfig; -import ac.ed.lurg.country.Country; import ac.ed.lurg.country.CountryManager; +import ac.ed.lurg.country.SingleCountry; import ac.ed.lurg.utils.LogWriter; public class SspManager { @@ -65,7 +65,7 @@ public class SspManager { LogWriter.println("Processed " + filename + ", create " + sspMap.size() + " SSP entries"); } - public SspData get(String scenario, int year, Country country) { + public SspData get(String scenario, int year, SingleCountry country) { SspData targetYearData = lookup(scenario, year, country); if (targetYearData != null) return targetYearData; @@ -104,7 +104,7 @@ public class SspManager { return res; } - private SspData lookup(String scenario, int year, Country country) { + private SspData lookup(String scenario, int year, SingleCountry country) { SspKey sspKey = new SspKey(scenario, year, country); return sspMap.get(sspKey); } diff --git a/src/ac/ed/lurg/landuse/CropUsageReader.java b/src/ac/ed/lurg/landuse/CropUsageReader.java index f0f1297a44d3c1f5490b774e197377b3d392f799..1680b348f70a9a76fced8813936c58f3f9708939 100644 --- a/src/ac/ed/lurg/landuse/CropUsageReader.java +++ b/src/ac/ed/lurg/landuse/CropUsageReader.java @@ -7,8 +7,10 @@ import java.util.HashMap; import java.util.Map; import ac.ed.lurg.ModelConfig; -import ac.ed.lurg.country.Country; +import ac.ed.lurg.country.CompositeCountry; +import ac.ed.lurg.country.CompositeCountryManager; import ac.ed.lurg.country.CountryManager; +import ac.ed.lurg.country.SingleCountry; import ac.ed.lurg.types.CropType; import ac.ed.lurg.utils.LazyHashMap; import ac.ed.lurg.utils.LogWriter; @@ -20,10 +22,16 @@ public class CropUsageReader { private static final int NET_IMPORT_COL = 5; private static final int PROD_COL = 6; + private CompositeCountryManager compositeCountryManager; + + public CropUsageReader(CompositeCountryManager compositeCountryManager) { + this.compositeCountryManager = compositeCountryManager; + } + @SuppressWarnings("serial") - public Map<Country, Map<CropType, CropUsageData>> getCommodityData() { + public Map<CompositeCountry, Map<CropType, CropUsageData>> getCommodityData() { - LazyHashMap<Country, Map<CropType, CropUsageData>> commodityMap = new LazyHashMap<Country, Map<CropType, CropUsageData>>() { + LazyHashMap<CompositeCountry, Map<CropType, CropUsageData>> commodityMap = new LazyHashMap<CompositeCountry, Map<CropType, CropUsageData>>() { protected Map<CropType, CropUsageData> createValue() { return new HashMap<CropType, CropUsageData>(); } }; @@ -46,12 +54,23 @@ public class CropUsageReader { netImports = Double.parseDouble(tokens[NET_IMPORT_COL]); prod = Double.parseDouble(tokens[PROD_COL]); - Country country = CountryManager.getForName(countryName); + SingleCountry country = CountryManager.getForName(countryName); + CropType crop = CropType.getForFaoName(commodityName); + CompositeCountry cc = compositeCountryManager.getForSingleCountry(country); + + Map<CropType, CropUsageData> countryData = commodityMap.lazyGet(cc); + CropUsageData oldData = countryData.get(crop); + + // aggregate if multiple countries for cc + if (oldData != null) { + feedAmount += oldData.getFeedAmount(); + netImports += oldData.getNetImports(); + prod += oldData.getProduction(); + } - CropUsageData data = new CropUsageData(feedAmount, netImports, prod, Double.NaN); - Map<CropType, CropUsageData> countryData = commodityMap.lazyGet(country); - countryData.put(crop, data); + CropUsageData newData = new CropUsageData(feedAmount, netImports, prod, Double.NaN); + countryData.put(crop, newData); } fitReader.close(); diff --git a/src/ac/ed/lurg/utils/CollectionHelper.java b/src/ac/ed/lurg/utils/CollectionHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..131ae846b341be71bca1e66729f0733d4a42e534 --- /dev/null +++ b/src/ac/ed/lurg/utils/CollectionHelper.java @@ -0,0 +1,23 @@ +package ac.ed.lurg.utils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CollectionHelper { + + public static <K, V> Map<V, List<K>> invertMap(Map<K, V> map) { + + Map<V, List<K>> result = new HashMap<V, List<K>>(); + + for (Map.Entry<K, V> entry : map.entrySet()) { + if (!result.containsKey(entry.getValue())) { + result.put(entry.getValue(), new ArrayList<K>()); + } + result.get(entry.getValue()).add(entry.getKey()); + } + + return result; + } +} \ No newline at end of file