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