diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java
index 8cb8be40f6dead5bf35ed696064351c5d126d7d4..41da003d1f408bf67e40470782b917c4d3df10e4 100755
--- a/src/ac/ed/lurg/ModelConfig.java
+++ b/src/ac/ed/lurg/ModelConfig.java
@@ -135,13 +135,16 @@ public class ModelConfig {
 	public static final String TEMP_DIR = getProperty("TEMP_DIR", OUTPUT_DIR + File.separator + "GamsTmp");
 	public static final String DATA_DIR = getProperty("DATA_DIR", BASE_DIR + File.separator + "data");
 	public static final String GAMS_DIR = getProperty("GAMS_DIR", BASE_DIR + File.separator + "GAMS");
-	public static final boolean CLEANUP_GAMS_DIR = getBooleanProperty("CLEANUP_GAMS_DIR", false);
+	public static final boolean CLEANUP_GAMS_DIR = getBooleanProperty("CLEANUP_GAMS_DIR", true);
 
 	public static final boolean ORIG_LEAST_COST_MIN = getBooleanProperty("ORIG_LEAST_COST_MIN", true);
 	public static final String GAMS_MODEL_NAME = getProperty("GAMS_MODEL_NAME", ORIG_LEAST_COST_MIN==true ? "IntExtOpt.gms" : "LUOpt.gms");
 	public static final String GAMS_MODEL = getProperty("GAMS_MODEL", GAMS_DIR + File.separator + GAMS_MODEL_NAME);
 	public static final String DEMAND_GAMS_MODEL = getProperty("DEMAND_GAMS_MODEL", GAMS_DIR + File.separator + "elasticDemand.gms");
 	public static final String DEMAND_PARAM_FILE = getProperty("DEMAND_PARAM_FILE", DATA_DIR + File.separator + "DemandParamConv.gdx");
+	
+	// Runtime options
+	public static final int MULTITHREAD_NUM = getIntProperty("MULTITHREAD_NUM", 4); // number of parallel threads
 
 	// Country (non-gridded) data
 	public static final boolean DEMAND_FROM_FILE = getBooleanProperty("DEMAND_FROM_FILE", false); // used in hindcasting
@@ -233,7 +236,8 @@ public class ModelConfig {
 	public static final String FPU_GROUPING_FILE = SPATIAL_DATA_DIR + File.separator + "fpuGrouping.txt";
 	public static final String IRRIG_MAX_WATER_FILENAME = getProperty("IRRIG_MAX_WATER_FILENAME", "gsirrigation.out");
 	public static final String IRRIG_RUNOFF_FILE = getProperty("IRRIG_RUNOFF_FILE", "tot_runoff.out");
-	public static final String PROTECTED_AREAS_FILE = getProperty("PROTECTED_AREAS_FILE",SPATIAL_DATA_DIR + File.separator + "protectedAreas2019.asc");
+	public static final String PROTECTED_AREAS_FILENAME = getProperty("PROTECTED_AREAS_FILENAME","protectedAreas2019.asc");
+	public static final String PROTECTED_AREAS_FILE = getProperty("PROTECTED_AREAS_FILE",SPATIAL_DATA_DIR + File.separator + PROTECTED_AREAS_FILENAME);
 	public static final String HALF_EARTH_FILE = getProperty("HALF_EARTH_FILE",SPATIAL_DATA_DIR + File.separator + "global_biodiversity_priorities50perc.asc");
 	public static final String HIGH_SLOPE_AREAS_FILE = SPATIAL_DATA_DIR + File.separator + "maxcropfrac2.txt";
 	public static final String YIELDSHOCK_MAP_DIR = SPATIAL_DATA_DIR + File.separator + "yieldshockmaps";
@@ -255,8 +259,8 @@ public class ModelConfig {
 	public static final String LAND_COVER_AGE_DIST_FILENAME = SPATIAL_DATA_DIR + File.separator + "land_cover_age_dist.txt";
 	public static final int LAND_COVER_INIT_AGE_GROUP_SIZE = getIntProperty("CARBON_WOOD_AGE_CLASSES", 10); // years
 	public static final int WOOD_AND_CARBON_TIMESTEP_SIZE = getIntProperty("WOOD_AND_CARBON_TIMESTEP_SIZE", 20); // years
-	public static final double WOOD_YIELD_CALIB_FACTOR = getDoubleProperty("WOOD_YIELD_CALIB_FACTOR", 6.0); 
-	public static final int CARBON_WOOD_MAX_TIME = getIntProperty("CARBON_WOOD_AGE_CLASSES", 165);
+	public static final double WOOD_YIELD_CALIB_FACTOR = getDoubleProperty("WOOD_YIELD_CALIB_FACTOR", 1.0); 
+	public static final int CARBON_WOOD_MAX_TIME = getIntProperty("CARBON_WOOD_MAX_TIME", 165);
 
 	// Output
 	public static final String LAND_COVER_OUTPUT_FILE = OUTPUT_DIR + File.separator + "lc.txt";
@@ -291,6 +295,7 @@ public class ModelConfig {
 	public static final String CHECKPOINT_INTERNATIONAL_MARKET_FILE = getProperty("CHECKPOINT_INTERNATIONAL_MARKET_FILE", OUTPUT_DIR + File.separator +  SERIALIZED_INTERNATIONAL_MARKET_FILENAME);
 	public static final String CHECKPOINT_LAND_COVER_FILE = getProperty("CHECKPOINT_LAND_COVER_FILE", OUTPUT_DIR + File.separator +  SERIALIZED_LAND_COVER_FILENAME);
 	public static final String CHECKPOINT_WOOD_USAGE_FILE = getProperty("CHECKPOINT_WOOD_USAGE_FILE", OUTPUT_DIR + File.separator +  SERIALIZED_WOOD_USAGE_FILENAME);
+	public static final boolean DISABLE_SERIALIZATION = getBooleanProperty("DISABLE_SERIALIZATION", false);
 	
 	public static final boolean MARKET_ADJ_PRICE = getBooleanProperty("MARKET_ADJ_PRICE", true);
 	public static final boolean CHANGE_YIELD_DATA_YEAR = IS_CALIBRATION_RUN ? false : getBooleanProperty("CHANGE_YIELD_DATA_YEAR", true);
@@ -346,9 +351,7 @@ public class ModelConfig {
 	public static final double PASTURE_DECREASE_COST = getDoubleProperty("PASTURE_DECREASE_COST", LAND_CHANGE_COST);
 	public static final double CROP_DECREASE_COST = getDoubleProperty("CROP_DECREASE_COST", 1.65 * LAND_CHANGE_COST);
 	public static final double PASTURE_INCREASE_COST = getDoubleProperty("PASTURE_INCREASE_COST", 0.35 * LAND_CHANGE_COST * CROP_TO_PASTURE_COST_FACTOR * AGRI_LAND_EXPANSION_COST_FACTOR);
-	public static final double AGRI_EXPANSION_COST_BASE = getDoubleProperty("AGRI_EXPANSION_COST_BASE", 0.03 * LAND_CHANGE_COST * AGRI_LAND_EXPANSION_COST_FACTOR);
-	public static final double MANAGED_FOREST_INCREASE_COST = getDoubleProperty("MANAGED_FOREST_INCREASE_COST", 0.5 * LAND_CHANGE_COST); // $1000/ha
-	public static final double MANAGED_FOREST_DECREASE_COST = getDoubleProperty("MANAGED_FOREST_DECREASE_COST", 0.5 * LAND_CHANGE_COST); // $1000/ha
+	public static final double MANAGED_FOREST_INCREASE_COST = getDoubleProperty("MANAGED_FOREST_INCREASE_COST", 2 * LAND_CHANGE_COST); // $1000/ha
 
 	public static final double TECHNOLOGY_CHANGE_ANNUAL_RATE = getDoubleProperty("TECHNOLOGY_CHANGE_ANNUAL_RATE", 0.002);
 	public static final int TECHNOLOGY_CHANGE_START_STEP = getIntProperty("TECHNOLOGY_CHANGE_START_STEP", 0);
@@ -420,6 +423,7 @@ public class ModelConfig {
 	public static final long RANDOM_SEED = getIntProperty("RANDOM_SEED", 1974329);  // any number will do
 	
 	public static final String CHECKPOINT_YEARS = getProperty("CHECKPOINT_YEARS", null); // 2020,2050
+	public static final boolean SERIALIZE_FINAL_TIMESTEP_ONLY = getBooleanProperty("SERIALIZE_FINAL_TIMESTEP_ONLY", false);
 	
 	// Protected areas forcing parameters
 	public static final boolean FORCE_PROTECTED_AREAS = IS_CALIBRATION_RUN ? false : getBooleanProperty("FORCE_PROTECTED_AREAS", false);
@@ -444,28 +448,29 @@ public class ModelConfig {
 	public static final String MIN_MAX_TRADE_FILE = getProperty("MIN_MAX_TRADE_FILE", OUTPUT_DIR + File.separator + "minMaxNetImport.csv");
 	
 	// Forestry and carbon market parameters
-	public static final String CONVERSION_COST_FILE = DATA_DIR + File.separator + "conversion_costs.csv"; // cost of converting from one land cover to another, $1000/ha
+	public static final String CONVERSION_COST_FILE = getProperty("CONVERSION_COST_FILE", DATA_DIR + File.separator + "conversion_costs.csv"); // cost of converting from one land cover to another, $1000/ha
 	public static final String CARBON_DEMAND_FILENAME = getProperty("CARBON_DEMAND_FILENAME", "carbon_demand.csv");
 	public static final String CARBON_DEMAND_FILE = getProperty("CARBON_DEMAND_FILE", DATA_DIR + File.separator + CARBON_DEMAND_FILENAME);
-	public static final String TIMBER_DEMAND_FILENAME = getProperty("TIMBER_DEMAND_FILENAME", "timber_demand.csv");
-	public static final String TIMBER_DEMAND_FILE = getProperty("TIMBER_DEMAND_FILE", DATA_DIR + File.separator + TIMBER_DEMAND_FILENAME);
+	public static final String WOOD_DEMAND_FILENAME = getProperty("WOOD_DEMAND_FILENAME", "wood_demand.csv");
+	public static final String WOOD_DEMAND_FILE = getProperty("WOOD_DEMAND_FILE", DATA_DIR + File.separator + WOOD_DEMAND_FILENAME);
 
 	public static final double INIT_WOOD_STOCK = getDoubleProperty("INIT_WOOD_STOCK", 500.0); // tC-eq
 	public static final double IND_ROUNDWOOD_DEMAND_ELASTICITY = getDoubleProperty("IND_ROUNDWOOD_DEMAND_ELASTICITY",  0.3123881);
 	public static final double FUELWOOD_DEMAND_ELASTICITY = getDoubleProperty("FUELDWOOD_DEMAND_ELASTICITY", -0.3598551);
-	public static final String WOOD_NET_IMPORTS_FILENAME = getProperty("WOOD_NET_IMPORTS_FILENAME", "wood_net_imports.csv");
-	public static final String WOOD_NET_IMPORTS_FILE = getProperty("WOOD_NET_IMPORTS_FILE", DATA_DIR + File.separator + WOOD_NET_IMPORTS_FILENAME);
 	public static final double WOOD_BIOMASS_CONVERSION_FACTOR = getDoubleProperty("WOOD_BIOMASS_CONVERSION_FACTOR", 3e-7); // m3 to MtC-eq p.16 [https://doi.org/10.5194/gmd-13-5425-2020] 
 	public static final double DISCOUNT_RATE = getDoubleProperty("DISCOUNT_RATE", 0.07);
 	public static final double VEGETATION_CLEARING_COST = getDoubleProperty("VEGETATION_CLEARING_COST", 0.005); //$1000/tC
 	public static final boolean CONVERSION_COSTS_FROM_FILE = getBooleanProperty("CONVERSION_COSTS_FROM_FILE", false);
 	public static final boolean IS_FORESTRY_ON = getBooleanProperty("IS_FORESTRY_ON", true);
 	public static final boolean IS_CARBON_ON = getBooleanProperty("IS_CARBON_ON", true);
-	public static final double FOREST_ESTABLISHMENT_COST = IS_FORESTRY_ON ? getDoubleProperty("FOREST_ESTABLISHMENT_COST", 2.0) : 0.0; // $1000/ha
+	public static final double FOREST_ESTABLISHMENT_COST = IS_FORESTRY_ON ? getDoubleProperty("FOREST_ESTABLISHMENT_COST", 8.0) : 0.0; // $1000/ha
 	public static final int CARBON_HORIZON = getIntProperty("CARBON_HORIZON", 30);
-	public static final double WOOD_TRADE_BARRIER = getDoubleProperty("WOOD_TRADE_BARRIER", 0.05); //$1000/tC
+	public static final double WOOD_TRADE_BARRIER = getDoubleProperty("WOOD_TRADE_BARRIER", 0.2); //$1000/tC
 	public static final double INIT_CARBON_PRICE = IS_CARBON_ON ? getDoubleProperty("INIT_CARBON_PRICE", 0.02) : 0.0; // $1000/tC-eq
-	public static final double INIT_WOOD_PRICE = IS_FORESTRY_ON ? getDoubleProperty("INIT_WOOD_PRICE", 0.4) : 0.0; // $1000/tC-eq
+	public static final double INIT_WOOD_PRICE = IS_FORESTRY_ON ? getDoubleProperty("INIT_WOOD_PRICE", 0.387) : 0.0; // $1000/tC-eq
 	public static final boolean RESET_ENERGYCROP_PRICE = getBooleanProperty("RESET_ENERGYCROP_PRICE", true);
-	public static final boolean ENABLE_VEGETATION_CLEARANCE_COST = getBooleanProperty("ENABLE_VEGETATION_CLEARANCE_COST", true);
+	public static final boolean ENABLE_VEGETATION_CLEARANCE_COST = getBooleanProperty("ENABLE_VEGETATION_CLEARANCE_COST", false);
+	// When forestry enabled, conversion cost based on amount of biomass cleared
+	public static final double MANAGED_FOREST_DECREASE_COST = IS_FORESTRY_ON || ENABLE_VEGETATION_CLEARANCE_COST ? getDoubleProperty("MANAGED_FOREST_DECREASE_COST", 0.1 * LAND_CHANGE_COST) : getDoubleProperty("MANAGED_FOREST_DECREASE_COST", 0.5 * LAND_CHANGE_COST); // $1000/ha
+	public static final String HIST_WOOD_CONSUMP_FILE = getProperty("HIST_WOOD_CONSUMP_FILE", DATA_DIR + File.separator + "hist_wood_consumption.csv");
 }
diff --git a/src/ac/ed/lurg/ModelMain.java b/src/ac/ed/lurg/ModelMain.java
index 3ff119d4bf124eb5cfd0a80b2b8b293c58bbd31d..b163d0fc0a0f45c742df1cc032502e07cd7e8d0c 100644
--- a/src/ac/ed/lurg/ModelMain.java
+++ b/src/ac/ed/lurg/ModelMain.java
@@ -190,7 +190,8 @@ public class ModelMain {
 		
 		// output results
 		outputTimestepResults(timestep);
-		checkAndSaveCheckpoint(timestep);
+		if (((ModelConfig.SERIALIZE_FINAL_TIMESTEP_ONLY && timestep.getTimestep() == ModelConfig.END_TIMESTEP) || !ModelConfig.SERIALIZE_FINAL_TIMESTEP_ONLY) && !ModelConfig.DISABLE_SERIALIZATION)
+			checkAndSaveCheckpoint(timestep);
 
 	}
 	
@@ -402,7 +403,7 @@ public class ModelMain {
 	
 	private void writeWoodAndCarbonProdFile(Timestep timestep) {
 		try {
-			StringBuffer sbHeadings = new StringBuffer("Year, Country, Item, Production, Import_price, Export_price, Net_imports,");
+			StringBuffer sbHeadings = new StringBuffer("Year, Country, Item, Production, Import_price, Export_price, Net_imports");
 			BufferedWriter outputFile = FileWriterHelper.getFileWriter(timestep, ModelConfig.WOOD_CARBON_OUTPUT_FILE, sbHeadings.toString());
 
 			for (AbstractCountryAgent country : countryAgents.getAll()) {
diff --git a/src/ac/ed/lurg/country/CountryAgent.java b/src/ac/ed/lurg/country/CountryAgent.java
index 7a1b60aa56cc44aa9cb81c55a82b4bfa469b923b..686315598475c85741416c2dcd79953c1ad89bf3 100644
--- a/src/ac/ed/lurg/country/CountryAgent.java
+++ b/src/ac/ed/lurg/country/CountryAgent.java
@@ -1,10 +1,5 @@
 package ac.ed.lurg.country;
 
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -18,6 +13,7 @@ import ac.ed.lurg.country.gams.GamsRasterOptimiser;
 import ac.ed.lurg.country.gams.GamsRasterOutput;
 import ac.ed.lurg.demand.AbstractDemandManager;
 import ac.ed.lurg.forestry.WoodYieldItem;
+import ac.ed.lurg.forestry.WoodYieldRasterSet;
 import ac.ed.lurg.landuse.CropUsageData;
 import ac.ed.lurg.landuse.IrrigationItem;
 import ac.ed.lurg.landuse.LandUseItem;
@@ -47,8 +43,6 @@ public class CountryAgent extends AbstractCountryAgent {
 	private Map<CropType, Double> subsidyRates;
 	private Map<Integer, Map<CropType, Double>> exportRestrictions;
 	private Map<Integer, Map<LimitType, Map<CropType, Double>>> minMaxTradeLimits;
-	private boolean saveGamsGdxFiles;
-
 	public CountryAgent(AbstractDemandManager demandManager,CompositeCountry country, RasterSet<LandUseItem> cropAreaRaster,
 			Map<CropType, CropUsageData> cropUsageData, Map<CropType, Double> tradeBarriers, RasterSet<IntegerRasterItem> yieldClusters,
 			Map<CropType, Double> subsidyRates, Map<WoodType, WoodUsageData> countryWoodData,
@@ -62,8 +56,6 @@ public class CountryAgent extends AbstractCountryAgent {
 		
 		GamsRasterOutput initialData = new GamsRasterOutput(cropAreaRaster, cropUsageData, countryWoodData);
 		previousGamsRasterOutput = initialData;
-		
-		saveGamsGdxFiles = (ModelConfig.GAMS_COUNTRY_TO_SAVE != null && country.getName().equals(ModelConfig.GAMS_COUNTRY_TO_SAVE));
 	}
 
 	public RasterSet<IntegerRasterItem> getYieldClusters() {
@@ -126,9 +118,6 @@ public class CountryAgent extends AbstractCountryAgent {
 			savePreviousProducerCropPrices();
 		}
 		
-		if (saveGamsGdxFiles && ModelConfig.PRICE_ELASTIC_DEMAND)
-			saveGDXFile("demand");
-		
 		if (currentProjectedDemand.size() == 0) {
 			LogWriter.printlnError("No demand for country " + country + " so skipping it");
 		}
@@ -150,9 +139,6 @@ public class CountryAgent extends AbstractCountryAgent {
 
 			GamsRasterOutput result = opti.run();
 
-			if (saveGamsGdxFiles)
-				saveGDXFile("landuse");
-
 			previousGamsRasterOutput = result;
 			
 			if (!ModelConfig.IS_CALIBRATION_RUN)
@@ -170,22 +156,6 @@ public class CountryAgent extends AbstractCountryAgent {
 		updateNetImportsFromProdAndDemand(currentProjectedDemand, currentDemandFract, previousGamsRasterOutput.getCropUsageData());
 	}
 	
-	private void saveGDXFile(String ext) {
-		// some hacky code for debug purposes that keeps each gams gdx file
-		try {
-			Files.copy(
-					FileSystems.getDefault().getPath(ModelConfig.TEMP_DIR + File.separator + "_gams_java_gdb2.gdx"),
-					FileSystems.getDefault().getPath(ModelConfig.TEMP_DIR + File.separator + country.getName().replaceAll("\\s+","") + currentTimestep.getYear() + ext + ".gdx"),
-					StandardCopyOption.REPLACE_EXISTING);
-			Files.copy(
-					FileSystems.getDefault().getPath(ModelConfig.TEMP_DIR + File.separator + "_gams_java_gjo1.lst"),
-					FileSystems.getDefault().getPath(ModelConfig.TEMP_DIR + File.separator + country.getName().replaceAll("\\s+","") + currentTimestep.getYear() + ext + "Listing" + ".lst"),
-					StandardCopyOption.REPLACE_EXISTING);
-		} catch (IOException e) {
-			LogWriter.print(e);
-		}
-	}
-
 	private GamsRasterInput getGamsRasterInput(RasterSet<IrrigationItem> irrigData, YieldRaster countryYieldSurfaces,
 			RasterSet<WoodYieldItem> woodYieldData, RasterSet<CarbonFluxItem> carbonFluxData, Map<LccKey, Double> conversionCosts,
 			double carbonDemandIncrease) {
@@ -193,8 +163,10 @@ public class CountryAgent extends AbstractCountryAgent {
 
 		if (ModelConfig.IS_CALIBRATION_RUN && currentTimestep.getTimestep() <= ModelConfig.END_FIRST_STAGE_CALIBRATION) {  // initialisation time-step
 			allowedImportChange = 0.0;
-		}
-		else { // normal (not the initial) time-step
+		} else if (ModelConfig.IS_CALIBRATION_RUN && currentTimestep.getTimestep() > ModelConfig.END_FIRST_STAGE_CALIBRATION) {
+			double cooldownFactor = 4 / (1 + Math.exp((currentTimestep.getTimestep() - 20) * 0.5)) + 1;
+			allowedImportChange = ModelConfig.MAX_IMPORT_CHANGE * cooldownFactor; // gradually decrease allowed import change
+		} else { // normal (not the initial) time-step
 			allowedImportChange = ModelConfig.MAX_IMPORT_CHANGE;  // when running is calibration model calibrate (ModelConfig.IS_CALIBRATION_RUN==true) MAX_IMPORT_CHANGE is already 0.
 		}
 
@@ -251,8 +223,10 @@ public class CountryAgent extends AbstractCountryAgent {
 
 		// Timber import/export constraints
 		Map<WoodType, TradeConstraint> woodTradeConstraints = new HashMap<WoodType, TradeConstraint>();
+		Map<WoodType, WoodUsageData> woodUsageData = previousGamsRasterOutput.getWoodUsageData();
+		double totalWoodProd = woodUsageData.values().stream().mapToDouble(o -> o.getHarvest()).reduce(0.0, Double::sum);
 		
-		for (Map.Entry<WoodType, WoodUsageData> entry : previousGamsRasterOutput.getWoodUsageData().entrySet()) {
+		for (Map.Entry<WoodType, WoodUsageData> entry : woodUsageData.entrySet()) {
 			WoodType woodType = entry.getKey();
 			if (!ModelConfig.IS_FORESTRY_ON) {
 				woodTradeConstraints.put(woodType, new TradeConstraint(0, 0)); // No exports or imports if forestry off
@@ -263,13 +237,16 @@ public class CountryAgent extends AbstractCountryAgent {
 			double baseTrade = woodUsage.getNetImport();
 			
 			// Make sure country can import sufficient wood
+			// Some countries produce wood from irrigated forests e.g. Egypt which are not modelled here.
+			// Therefore we need to adjust the initial FAO imports/exports.
+			
 			if (ModelConfig.IS_CALIBRATION_RUN && currentTimestep.isInitialTimestep()) {
-				// assume 1tC/ha/year
-				double potentialYield = LandUseItem.getTotalLandCover(previousGamsRasterOutput.getLandUses().values(), LandCoverType.TIMBER_FOREST);
+				double prodFract = woodUsage.getHarvest() / totalWoodProd; 
+				double potentialMaxYield = WoodYieldRasterSet.getMaxWoodHarvest(woodYieldData, previousGamsRasterOutput.getLandUses());
+				double potentialAdjYield = potentialMaxYield * prodFract * 0.5; // adjust based on demand and cap at max 50% realised
 				double currentDemand = currentWoodDemand.get(woodType);
-				double importsNeeded = Math.max(0, currentDemand - potentialYield * 3);
+				double importsNeeded = Math.max(0, currentDemand - potentialAdjYield);
 				baseTrade = importsNeeded > 0 ? importsNeeded : baseTrade;
-				baseTrade = baseTrade < 0 ? baseTrade * 20 : baseTrade;
 			}
 			
 			double changeUp = 0.0;
diff --git a/src/ac/ed/lurg/country/CountryAgentManager.java b/src/ac/ed/lurg/country/CountryAgentManager.java
index 257b80ee544c6d4c7a0353d7128070f5898d14d0..31412acadd7c1d64371c0d5280c124174f329bb8 100644
--- a/src/ac/ed/lurg/country/CountryAgentManager.java
+++ b/src/ac/ed/lurg/country/CountryAgentManager.java
@@ -8,6 +8,9 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 import ac.ed.lurg.InternationalMarket;
 import ac.ed.lurg.ModelConfig;
@@ -117,11 +120,13 @@ public class CountryAgentManager {
 	public void determineProductionForAll(Timestep timestep, YieldRaster yieldSurfaces, IrrigationRasterSet currentIrrigationData,
 			CarbonFluxRasterSet currentCarbonFluxData, WoodYieldRasterSet currentWoodYieldData, Map<LccKey, Double> conversionCosts,
 			double carbonDemandIncrease) {
-		
+
 		for (AbstractCountryAgent aca : countryAgents) {		
 			aca.setCurrentTimestep(timestep);
 		}
-		
+
+		ExecutorService execService = Executors.newFixedThreadPool(ModelConfig.MULTITHREAD_NUM);
+
 		for (CountryAgent ca : gamsCountryAgents) {		
 			LogWriter.println("Country " + ca.getCountry());
 			Collection<RasterKey> countryKeys = countryBoundaryRaster.getKeysFor(ca.getCountry());
@@ -129,24 +134,36 @@ public class CountryAgentManager {
 			RasterSet<IrrigationItem> irrigData = currentIrrigationData.createSubsetForKeys(countryKeys);
 			RasterSet<CarbonFluxItem> carbonFluxData = currentCarbonFluxData.createSubsetForKeys(countryKeys);
 			RasterSet<WoodYieldItem> woodYieldData = currentWoodYieldData.createSubsetForKeys(countryKeys);
-			
-			try {
-				ca.determineProduction(countryYieldSurfaces, irrigData, internationalMarket.getWorldPrices(), carbonFluxData, woodYieldData, 
-						conversionCosts, carbonDemandIncrease, internationalMarket.getCarbonPrice(), internationalMarket.getWoodPrice());
-				
-				// update global rasters
-				globalLandUseRaster.putAll(ca.getLandUses());
 
-				// if first timestep and calibration get the clustering info, which doesn't change through time
-				if (ModelConfig.GENERATE_NEW_YIELD_CLUSTERS && timestep.isInitialTimestep())
-					clusterIdRaster.putAll(ca.getYieldClusters());
-				
-			} catch (Exception e) {
- 				LogWriter.printlnError("Exception processing " + ca.getCountry() + " will continue with other countries");
-				LogWriter.print(e);
-			}
+			execService.execute(new Runnable() {
+				@Override
+				public void run() {
+
+					try {
+						ca.determineProduction(countryYieldSurfaces, irrigData, internationalMarket.getWorldPrices(), carbonFluxData, woodYieldData, 
+								conversionCosts, carbonDemandIncrease, internationalMarket.getCarbonPrice(), internationalMarket.getWoodPrice());
+
+						// update global rasters
+						globalLandUseRaster.putAll(ca.getLandUses());
+
+						// if first timestep and calibration get the clustering info, which doesn't change through time
+						if (ModelConfig.GENERATE_NEW_YIELD_CLUSTERS && timestep.isInitialTimestep())
+							clusterIdRaster.putAll(ca.getYieldClusters());
+					} catch (Exception e) {
+						LogWriter.printlnError("Exception processing " + ca.getCountry() + " will continue with other countries");
+					}
+
+				}
+			});
 		}
-		
+
+		try {
+			execService.shutdown();
+			execService.awaitTermination(30, TimeUnit.MINUTES);
+		} catch (InterruptedException e) {
+			LogWriter.printlnError(e.toString());
+		}
+
 		if (craftyCountryAgents.size() > 0) {
 			craftyManager.updateWithCraftyData(craftyCountryAgents, timestep, internationalMarket.getWorldPrices(), 
 					internationalMarket.getCarbonPrice(), internationalMarket.getWoodPrice());  // this will wait for the marker file from CRAFTY
diff --git a/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java b/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java
index c107b32939c5402e91b8e1c380d0f003e560ede7..823bcc2153ad6c71e1262231e56777ac4ef2a15e 100755
--- a/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java
+++ b/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java
@@ -1,6 +1,10 @@
 package ac.ed.lurg.country.gams;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
@@ -31,10 +35,19 @@ public class GamsDemandOptimiser {
 	}
 	
 	public GamsDemandOutput getDemandPc() {
-		File workingDirectory = new File(ModelConfig.TEMP_DIR);
-		workingDirectory.mkdir();
+		File tempDir = new File(ModelConfig.TEMP_DIR);
+		tempDir.mkdir();
+
+		Path workingDirectory = null;
+		try {
+			workingDirectory = Files.createTempDirectory(Paths.get(ModelConfig.TEMP_DIR), "dem");
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			LogWriter.printlnError(e.toString());
+		}
+		//File workingDirectory = new File(ModelConfig.TEMP_DIR);
 		GAMSWorkspaceInfo  wsInfo  = new GAMSWorkspaceInfo();
-		wsInfo.setWorkingDirectory(workingDirectory.getAbsolutePath());
+		wsInfo.setWorkingDirectory(workingDirectory.toAbsolutePath().toString());
 
 		GAMSWorkspace ws = new GAMSWorkspace(wsInfo);
 		GAMSOptions opt = ws.addOptions();
@@ -62,7 +75,15 @@ public class GamsDemandOptimiser {
 		gamsJob.run(opt, dbs.toArray(new GAMSDatabase[dbs.size()]));
 		
 		LogWriter.println("Took " + (System.currentTimeMillis() - startTime) + " ms to run");
-		return handleResults(gamsJob.OutDB());
+
+		GamsDemandOutput gamsOutput = handleResults(gamsJob.OutDB());
+		
+		if (ModelConfig.CLEANUP_GAMS_DIR)  {
+			gamsJob.OutDB().dispose();
+			deleteDirectory(workingDirectory.toFile());
+		}
+		
+		return(gamsOutput);
 	}
 
 	private void adjustDietParams(GAMSDatabase adjustedParamDb) {
@@ -177,4 +198,15 @@ public class GamsDemandOptimiser {
 		
 		return new GamsDemandOutput(status, demandMap, utility, desiredConsumpFactor);
 	}
+	
+	
+	boolean deleteDirectory(File dir) {
+	    File[] dirContents = dir.listFiles();
+	    if (dirContents != null) {
+	        for (File file : dirContents) {
+	            deleteDirectory(file);
+	        }
+	    }
+	    return dir.delete();
+	}
 }
diff --git a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java
index 85208f09f0da4061d5115ab9fa24402ae0c761b5..cf1d88a43a7976782ebcb0a6cd0b27be561e92c3 100644
--- a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java
+++ b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java
@@ -1,6 +1,12 @@
 package ac.ed.lurg.country.gams;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
@@ -46,20 +52,29 @@ import ac.ed.lurg.yield.YieldResponsesItem;
 public class GamsLocationOptimiser {
 
 	private static final boolean DEBUG = true;
+	private boolean saveGamsGdxFiles;
 
 	private GamsLocationInput inputData;
 
 	public GamsLocationOptimiser(GamsLocationInput inputData) {
 		this.inputData = inputData;
+		saveGamsGdxFiles = (ModelConfig.GAMS_COUNTRY_TO_SAVE != null && inputData.getCountryInput().getCountry().getName().equals(ModelConfig.GAMS_COUNTRY_TO_SAVE));
 	}
 
 	public GamsLocationOutput run() {
+		File tempDir = new File(ModelConfig.TEMP_DIR);
+		tempDir.mkdir();
 
-		File workingDirectory = new File(ModelConfig.TEMP_DIR);
-		workingDirectory.mkdir();
+		Path workingDirectory = null;
+		try {
+			workingDirectory = Files.createTempDirectory(Paths.get(ModelConfig.TEMP_DIR), "loc");
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			LogWriter.printlnError(e.toString());
+		}
 
 		GAMSWorkspaceInfo  wsInfo  = new GAMSWorkspaceInfo();
-		wsInfo.setWorkingDirectory(workingDirectory.getAbsolutePath());
+		wsInfo.setWorkingDirectory(workingDirectory.toAbsolutePath().toString());
 		//	wsInfo.setDebugLevel(DebugLevel.VERBOSE);
 
 		GAMSWorkspace ws = new GAMSWorkspace(wsInfo);
@@ -77,12 +92,19 @@ public class GamsLocationOptimiser {
 		long startTime = System.currentTimeMillis();
 		gamsJob.run(opt, inDB);
 		
-		if (ModelConfig.CLEANUP_GAMS_DIR) 
-			cleanup(ws.workingDirectory());
-		
 		LogWriter.println("Took " + (System.currentTimeMillis() - startTime) + " ms to run");
 
-		return handleResults(gamsJob.OutDB());
+		GamsLocationOutput gamsOutput = handleResults(gamsJob.OutDB());
+		
+		if (saveGamsGdxFiles)
+			saveGDXFile("landuse", workingDirectory.toFile());
+		
+		if (ModelConfig.CLEANUP_GAMS_DIR)  {
+			gamsJob.OutDB().dispose();
+			deleteDirectory(workingDirectory.toFile());
+		}
+
+		return(gamsOutput);
 	}
 
 	private void setupInDB(GAMSDatabase inDB) {
@@ -623,21 +645,30 @@ public class GamsLocationOptimiser {
 		}
 	}
 
-
-	private void cleanup(String directory)  {
-		File directoryToDelete = new File(directory);
-		String files[] = directoryToDelete.list();
-		for (String file : files) {
-			File fileToDelete = new File(directoryToDelete, file);
-			try {
-				fileToDelete.delete();
-			} catch(Exception e){
-				LogWriter.print(e);
-			}
-		}
+	boolean deleteDirectory(File dir) {
+	    File[] dirContents = dir.listFiles();
+	    if (dirContents != null) {
+	        for (File file : dirContents) {
+	            deleteDirectory(file);
+	        }
+	    }
+	    return dir.delete();
+	}
+	
+	private void saveGDXFile(String ext, File tempDir) {
+		// some hacky code for debug purposes that keeps each gams gdx file
+		String country = inputData.getCountryInput().getCountry().getName().replaceAll("\\s+","");
+		int year = inputData.getTimestep().getYear();
 		try {
-			directoryToDelete.delete();
-		} catch(Exception e) {
+			Files.copy(
+					FileSystems.getDefault().getPath(tempDir + File.separator + "_gams_java_gdb2.gdx"),
+					FileSystems.getDefault().getPath(ModelConfig.TEMP_DIR + File.separator + country + year + ext + ".gdx"),
+					StandardCopyOption.REPLACE_EXISTING);
+			Files.copy(
+					FileSystems.getDefault().getPath(tempDir + File.separator + "_gams_java_gjo1.lst"),
+					FileSystems.getDefault().getPath(ModelConfig.TEMP_DIR + File.separator + country + year + ext + "Listing" + ".lst"),
+					StandardCopyOption.REPLACE_EXISTING);
+		} catch (IOException e) {
 			LogWriter.print(e);
 		}
 	}
diff --git a/src/ac/ed/lurg/demand/BioenergyDemandManager.java b/src/ac/ed/lurg/demand/BioenergyDemandManager.java
index c01e0cbf273251deae81e35755c09103ef653921..627186c5d741e295893c43ffadbf73606489db8a 100644
--- a/src/ac/ed/lurg/demand/BioenergyDemandManager.java
+++ b/src/ac/ed/lurg/demand/BioenergyDemandManager.java
@@ -169,7 +169,10 @@ public class BioenergyDemandManager {
 			double bioenergyDemandAdj = 0;
 			
 			if (ModelConfig.USE_BIOENERGY_TRAJECTORY) {
-				bioenergyDemandAdj = interpolateDemand(firstGenGlobalMass, year, 5) / firstGenGlobalMass.get(ModelConfig.BASE_YEAR);
+				double globalBaseDemand = firstGenGlobalMass.get(ModelConfig.BASE_YEAR);
+				if (globalBaseDemand > 0) {
+					bioenergyDemandAdj = interpolateDemand(firstGenGlobalMass, year, 5) / firstGenGlobalMass.get(ModelConfig.BASE_YEAR);
+				}
 			}
 			else {
 				int yearsOfChange = Math.min(ModelConfig.BIOENERGY_CHANGE_END_YEAR - ModelConfig.BIOENERGY_CHANGE_START_YEAR, year - ModelConfig.BIOENERGY_CHANGE_START_YEAR);
diff --git a/src/ac/ed/lurg/demand/DemandManagerFromFile.java b/src/ac/ed/lurg/demand/DemandManagerFromFile.java
index d9a3c2ecc880f638c4657f5075b87f01807b3ecb..a50b3555db120e03df92157d114dab7f09e5a3b3 100644
--- a/src/ac/ed/lurg/demand/DemandManagerFromFile.java
+++ b/src/ac/ed/lurg/demand/DemandManagerFromFile.java
@@ -15,11 +15,15 @@ import ac.ed.lurg.utils.StringTabularReader;
 public class DemandManagerFromFile extends AbstractDemandManager {
 
 	private StringTabularReader historicalConsumptionReader;
+	private StringTabularReader histWoodConsumpReader;
 
 	public DemandManagerFromFile(CompositeCountryManager compositeCountryManager, CalorieManager calorieManager) {
 		super(compositeCountryManager, calorieManager);
 		historicalConsumptionReader = new StringTabularReader(",", new String[]{"Year", "Country", "Item", "population", "cpc"});
 		historicalConsumptionReader.read(ModelConfig.DEMAND_CONSUMPTION_FILE);
+		
+		histWoodConsumpReader = new StringTabularReader(",", new String[]{"Year", "Country", "Item", "Demand"});
+		histWoodConsumpReader.read(ModelConfig.HIST_WOOD_CONSUMP_FILE);
 	}
 
 	@Override
@@ -56,7 +60,24 @@ public class DemandManagerFromFile extends AbstractDemandManager {
 	
 	@Override
 	protected Map<WoodType, Double> getWoodDemand(SingleCountry country, int year) {
-		// TODO Auto-generated method stub
-		return null;
+		Map<WoodType, Double> woodDemandMap = new HashMap<WoodType, Double>();
+
+		for (WoodType woodType : WoodType.values()) {
+			Map<String, String> queryMap = new HashMap<String, String>();
+			queryMap.put("Year", Integer.toString(year));
+			queryMap.put("Country", country.getCountryName());
+			queryMap.put("Item", woodType.getName());
+			try {
+				Map<String, String> row = histWoodConsumpReader.querySingle(queryMap);
+				String demand = row.get("Demand");
+				double d = Double.valueOf(demand) * ModelConfig.WOOD_BIOMASS_CONVERSION_FACTOR;
+				woodDemandMap.put(woodType, d);
+			}
+			catch (Exception e) {
+				LogWriter.println("Problem finding wood demand: " + woodType.getName() + ", " + year + ", " + country.getCountryName());
+			}
+		}
+
+		return woodDemandMap;
 	}	
 }
\ No newline at end of file
diff --git a/src/ac/ed/lurg/demand/WoodDemandManager.java b/src/ac/ed/lurg/demand/WoodDemandManager.java
index 633673a0e3f68268e7123e586098688dff539410..35d237af92501c72931ee0eb1d64e5def3092756 100644
--- a/src/ac/ed/lurg/demand/WoodDemandManager.java
+++ b/src/ac/ed/lurg/demand/WoodDemandManager.java
@@ -14,8 +14,9 @@ import ac.ed.lurg.utils.LogWriter;
 
 public class WoodDemandManager {
 	private static final int COUNTY_COL = 0;
-	private static final int WOOD_TYPE_COL = 1; 
-	private static final int DEMAND_COL = 2; 
+	private static final int YEAR_COL = 1;
+	private static final int WOOD_TYPE_COL = 2; 
+	private static final int DEMAND_COL = 3; 
 	
 	private Map<SingleCountry, Map<WoodType, Double>> baseWoodDemand = new HashMap<SingleCountry, Map<WoodType, Double>>();
 	
@@ -25,23 +26,30 @@ public class WoodDemandManager {
 	
 	public void readWoodDemandData() {
 		
-		String filename = ModelConfig.TIMBER_DEMAND_FILE;
+		String filename = ModelConfig.WOOD_DEMAND_FILE;
 		try {
 			BufferedReader reader = new BufferedReader(new FileReader(filename)); 
 			String line, countryName, woodTypeName;
 			Double demand;
+			Integer year;
 			reader.readLine(); // read header
 
 			while ((line=reader.readLine()) != null) {
 				String[] tokens = line.split(",");
 				
-				if (tokens.length < 3)
+				if (tokens.length < 6)
 					LogWriter.printlnError("Too few columns in " + filename + ", " + line);
 				
+				year = Integer.valueOf(tokens[YEAR_COL]);
+				
+				if (year != ModelConfig.BASE_YEAR)
+					continue;
+				
 				countryName = tokens[COUNTY_COL];
 				woodTypeName = tokens[WOOD_TYPE_COL];
 				demand = Double.valueOf(tokens[DEMAND_COL]);
 				
+
 				SingleCountry country = CountryManager.getForName(countryName);
 				if (country == null)
 					LogWriter.printlnError("Null country for" + countryName);
diff --git a/src/ac/ed/lurg/forestry/WoodYieldRasterSet.java b/src/ac/ed/lurg/forestry/WoodYieldRasterSet.java
index 995c88f2945b5d2049b714844ebbb3aade2772df..c9853457b0e6a63cef469e870fcd6f86bb5a44e2 100644
--- a/src/ac/ed/lurg/forestry/WoodYieldRasterSet.java
+++ b/src/ac/ed/lurg/forestry/WoodYieldRasterSet.java
@@ -1,7 +1,11 @@
 package ac.ed.lurg.forestry;
 
 import java.util.Collection;
+import java.util.Map;
 
+import ac.ed.lurg.landuse.LandUseItem;
+import ac.ed.lurg.types.LandCoverType;
+import ac.ed.lurg.types.LandProtectionType;
 import ac.sac.raster.RasterHeaderDetails;
 import ac.sac.raster.RasterKey;
 import ac.sac.raster.RasterSet;
@@ -24,4 +28,20 @@ public class WoodYieldRasterSet extends RasterSet<WoodYieldItem> {
 		popSubsetForKeys(subsetForestGrowthRaster, keys);		
 		return subsetForestGrowthRaster;
 	}
+	
+	public static double getMaxWoodHarvest(RasterSet<WoodYieldItem> woodYields, RasterSet<LandUseItem> landUses) {
+		double total = 0;
+		for (Map.Entry<RasterKey, WoodYieldItem> entry : woodYields.entrySet()) {
+			RasterKey key = entry.getKey();
+			WoodYieldItem wyItem = entry.getValue();
+			LandUseItem luItem = landUses.get(key);
+			if (wyItem == null)
+				continue;
+			double area = luItem.getLandCoverArea(LandCoverType.TIMBER_FOREST, LandProtectionType.CONVERTIBLE) + 
+					luItem.getLandCoverArea(LandCoverType.NATURAL, LandProtectionType.CONVERTIBLE);
+			double rotaYield = wyItem.getYieldAtRotation() / wyItem.getOptimalRotation();
+			total += area * rotaYield;
+		}
+		return total;
+	}
 }
diff --git a/src/ac/ed/lurg/landuse/ConversionCostReader.java b/src/ac/ed/lurg/landuse/ConversionCostReader.java
index bc87eeaffa2a7b4e5083bcd9385037548de14e14..4648601b1b5cc06d598508c0efcefaf7b00e4361 100644
--- a/src/ac/ed/lurg/landuse/ConversionCostReader.java
+++ b/src/ac/ed/lurg/landuse/ConversionCostReader.java
@@ -64,18 +64,18 @@ public class ConversionCostReader {
 		conversionCosts.put(new LccKey(LandCoverType.PASTURE, LandCoverType.TIMBER_FOREST), ModelConfig.PASTURE_DECREASE_COST + ModelConfig.MANAGED_FOREST_INCREASE_COST);
 		conversionCosts.put(new LccKey(LandCoverType.PASTURE, LandCoverType.CARBON_FOREST), ModelConfig.PASTURE_DECREASE_COST + ModelConfig.MANAGED_FOREST_INCREASE_COST);
 		
-		conversionCosts.put(new LccKey(LandCoverType.NATURAL, LandCoverType.CROPLAND), ModelConfig.AGRI_EXPANSION_COST_BASE + ModelConfig.CROP_INCREASE_COST);
-		conversionCosts.put(new LccKey(LandCoverType.NATURAL, LandCoverType.PASTURE), ModelConfig.AGRI_EXPANSION_COST_BASE + ModelConfig.PASTURE_INCREASE_COST);
+		conversionCosts.put(new LccKey(LandCoverType.NATURAL, LandCoverType.CROPLAND), ModelConfig.CROP_INCREASE_COST);
+		conversionCosts.put(new LccKey(LandCoverType.NATURAL, LandCoverType.PASTURE), ModelConfig.PASTURE_INCREASE_COST);
 		conversionCosts.put(new LccKey(LandCoverType.NATURAL, LandCoverType.TIMBER_FOREST), ModelConfig.MANAGED_FOREST_INCREASE_COST);
 		conversionCosts.put(new LccKey(LandCoverType.NATURAL, LandCoverType.CARBON_FOREST), ModelConfig.MANAGED_FOREST_INCREASE_COST);
 		
-		conversionCosts.put(new LccKey(LandCoverType.TIMBER_FOREST, LandCoverType.CROPLAND), ModelConfig.AGRI_EXPANSION_COST_BASE + ModelConfig.MANAGED_FOREST_DECREASE_COST + ModelConfig.CROP_INCREASE_COST);
-		conversionCosts.put(new LccKey(LandCoverType.TIMBER_FOREST, LandCoverType.PASTURE), ModelConfig.AGRI_EXPANSION_COST_BASE + ModelConfig.MANAGED_FOREST_DECREASE_COST + ModelConfig.PASTURE_INCREASE_COST);
+		conversionCosts.put(new LccKey(LandCoverType.TIMBER_FOREST, LandCoverType.CROPLAND), ModelConfig.MANAGED_FOREST_DECREASE_COST + ModelConfig.CROP_INCREASE_COST);
+		conversionCosts.put(new LccKey(LandCoverType.TIMBER_FOREST, LandCoverType.PASTURE), ModelConfig.MANAGED_FOREST_DECREASE_COST + ModelConfig.PASTURE_INCREASE_COST);
 		conversionCosts.put(new LccKey(LandCoverType.TIMBER_FOREST, LandCoverType.NATURAL), ModelConfig.MANAGED_FOREST_DECREASE_COST);
 		conversionCosts.put(new LccKey(LandCoverType.TIMBER_FOREST, LandCoverType.CARBON_FOREST), ModelConfig.MANAGED_FOREST_INCREASE_COST + ModelConfig.MANAGED_FOREST_DECREASE_COST);
 		
-		conversionCosts.put(new LccKey(LandCoverType.CARBON_FOREST, LandCoverType.CROPLAND), ModelConfig.AGRI_EXPANSION_COST_BASE + ModelConfig.MANAGED_FOREST_DECREASE_COST + ModelConfig.CROP_INCREASE_COST);
-		conversionCosts.put(new LccKey(LandCoverType.CARBON_FOREST, LandCoverType.PASTURE), ModelConfig.AGRI_EXPANSION_COST_BASE + ModelConfig.MANAGED_FOREST_DECREASE_COST + ModelConfig.PASTURE_INCREASE_COST);
+		conversionCosts.put(new LccKey(LandCoverType.CARBON_FOREST, LandCoverType.CROPLAND), ModelConfig.MANAGED_FOREST_DECREASE_COST + ModelConfig.CROP_INCREASE_COST);
+		conversionCosts.put(new LccKey(LandCoverType.CARBON_FOREST, LandCoverType.PASTURE), ModelConfig.MANAGED_FOREST_DECREASE_COST + ModelConfig.PASTURE_INCREASE_COST);
 		conversionCosts.put(new LccKey(LandCoverType.CARBON_FOREST, LandCoverType.NATURAL), ModelConfig.MANAGED_FOREST_DECREASE_COST);
 		conversionCosts.put(new LccKey(LandCoverType.CARBON_FOREST, LandCoverType.TIMBER_FOREST), ModelConfig.MANAGED_FOREST_INCREASE_COST + ModelConfig.MANAGED_FOREST_DECREASE_COST);
 		
diff --git a/src/ac/ed/lurg/landuse/WoodUsageReader.java b/src/ac/ed/lurg/landuse/WoodUsageReader.java
index add6e10380049ef7ee38bfbad0e1c6b531c684cd..efc978947b35d46552218ace27e2815aeb808206 100644
--- a/src/ac/ed/lurg/landuse/WoodUsageReader.java
+++ b/src/ac/ed/lurg/landuse/WoodUsageReader.java
@@ -17,9 +17,10 @@ import ac.ed.lurg.utils.LogWriter;
 
 public class WoodUsageReader {
 	private static final int COUNTRY_COL = 0;
-	private static final int WOOD_TYPE_COL = 1;
-	private static final int HARVEST_COL = 2;
-	private static final int NET_IMPORT_COL = 3;
+	private static final int YEAR_COL = 1;
+	private static final int WOOD_TYPE_COL = 2;
+	private static final int NET_IMPORT_COL = 4;
+	private static final int HARVEST_COL = 5;
 	
 	private CompositeCountryManager compositeCountryManager;
 	
@@ -38,19 +39,25 @@ public class WoodUsageReader {
 			}
 		};
 		
-		String filename = ModelConfig.WOOD_NET_IMPORTS_FILE;
+		String filename = ModelConfig.WOOD_DEMAND_FILE;
 		try {
 			BufferedReader reader = new BufferedReader(new FileReader(filename));
 			String line, countryName, woodTypeName;
+			Integer year;
 			double harvest, netImport;
 			reader.readLine(); // read header
 			
 			while ((line = reader.readLine()) != null) {
 				String[] tokens = line.split(",");
 				
-				if (tokens.length < 4)
+				if (tokens.length < 6)
 					LogWriter.printlnError("Too few columns in file: " + filename + ", line: " + line);
 				
+				year = Integer.valueOf(tokens[YEAR_COL]);
+				
+				if (year != ModelConfig.BASE_YEAR)
+					continue;
+				
 				countryName = tokens[COUNTRY_COL];
 				woodTypeName = tokens[WOOD_TYPE_COL];
 				harvest = ModelConfig.IS_FORESTRY_ON ? Double.parseDouble(tokens[HARVEST_COL]) * ModelConfig.WOOD_BIOMASS_CONVERSION_FACTOR : 0; // m3 to MtC-eq