From 249644d510c72a8c715efc55c731291ec94e4e04 Mon Sep 17 00:00:00 2001
From: Peter Alexander <peter@blackhillock.co.uk>
Date: Fri, 8 Mar 2019 12:33:00 +0000
Subject: [PATCH] Output detailed demand results for each country

---
 debug_config.properties                       |  6 +-
 src/ac/ed/lurg/ModelConfig.java               |  5 +-
 src/ac/ed/lurg/ModelMain.java                 | 29 ++-----
 .../ed/lurg/country/gams/GamsDemandInput.java |  7 +-
 .../country/gams/GamsDemandOptimiser.java     | 20 ++---
 .../lurg/country/gams/GamsDemandOutput.java   | 12 ++-
 .../lurg/demand/AbstractSSPDemandManager.java |  4 +-
 src/ac/ed/lurg/demand/DemandManagerSSP.java   |  2 +-
 .../ed/lurg/demand/ElasticDemandManager.java  | 77 +++++++++++++++++--
 src/ac/ed/lurg/utils/FileWriterHelper.java    | 39 ++++++++++
 10 files changed, 146 insertions(+), 55 deletions(-)
 create mode 100644 src/ac/ed/lurg/utils/FileWriterHelper.java

diff --git a/debug_config.properties b/debug_config.properties
index d7592662..69f55b1b 100644
--- a/debug_config.properties
+++ b/debug_config.properties
@@ -2,14 +2,14 @@ BASE_DIR=..
 
 YIELD_DIR=/Users/peteralexander/Documents/LURG/LPJ/LPJGPLUM_expt1.1_2006-2100_PLUM6xtra_20180412171654/rcp60
 
-DEBUG_LIMIT_COUNTRIES=true
-DEBUG_COUNTRY_NAME=United States of America
+DEBUG_LIMIT_COUNTRIES=false
+DEBUG_COUNTRY_NAME=Peru & Ecuador
 
 IS_CALIBRATION_RUN = false
 GENERATE_NEW_YIELD_CLUSTERS = false
 NUM_YIELD_CLUSTERS=8000
 
-END_TIMESTEP=18
+END_TIMESTEP=0
 TIMESTEP_SIZE=5
 
 INTERPOLATE_OUTPUT_YEARS = false
diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java
index 9f0b2db7..3f5a6510 100644
--- a/src/ac/ed/lurg/ModelConfig.java
+++ b/src/ac/ed/lurg/ModelConfig.java
@@ -205,8 +205,8 @@ public class ModelConfig {
 	public static final double INITAL_PRICE_MONOGASTRICS = getDoubleProperty("INITAL_PRICE_MONOGASTRICS", 0.4 * 0.5 * ModelConfig.INITIAL_PRICE_SHIFT); // quantities is in feed equivalent term (0.4 is weighted average price per feed, and 0.5 accounts for mark-up for additional processing)
 	public static final double INITAL_PRICE_RUMINANTS = getDoubleProperty("INITAL_PRICE_RUMINANTS", 0.1 * 0.6 * ModelConfig.INITIAL_PRICE_SHIFT); // quantities is in feed equivalent term
 	public static final double INITAL_PRICE_ENERGYCROPS = getDoubleProperty("INITAL_PRICE_ENERGYCROPS", 0.04 * ModelConfig.INITIAL_PRICE_SHIFT);
-	public static final double INITAL_PRICE_FRUITVEG = getDoubleProperty("INITAL_PRICE_FRUITVEG", 0.1 * ModelConfig.INITIAL_PRICE_SHIFT);
-	public static final double INITAL_PRICE_SUGAR = getDoubleProperty("INITAL_PRICE_SUGAR", 0.01 * ModelConfig.INITIAL_PRICE_SHIFT);
+	public static final double INITAL_PRICE_FRUITVEG = getDoubleProperty("INITAL_PRICE_FRUITVEG", 0.3 * ModelConfig.INITIAL_PRICE_SHIFT);
+	public static final double INITAL_PRICE_SUGAR = getDoubleProperty("INITAL_PRICE_SUGAR", 0.1 * ModelConfig.INITIAL_PRICE_SHIFT);
 
 	// These are initial demand system prices in 2000 kcal terms
 	public static final double INITAL_DEMAND_PRICE_CEREALS = getDoubleProperty("INITAL_DEMAND_PRICE_CEREALS", 120.2364695);
@@ -242,6 +242,7 @@ public class ModelConfig {
 	public static final String DEMAND_OUTPUT_FILE = OUTPUT_DIR + File.separator + "demand.txt";
 	public static final String DOMESTIC_OUTPUT_FILE = OUTPUT_DIR + File.separator + "domestic.txt";
 	public static final String COUNTRY_DEMAND_FILE = OUTPUT_DIR + File.separator + "countryDemand.txt";
+	public static final String DEMAND_OPTIMISATION_OUTPUT_FILE = OUTPUT_DIR + File.separator + "countryDemandOpt.txt";
 	public static final String FOOD_BALANCE_SHEET_FILE = OUTPUT_DIR + File.separator + "fbs.txt";
 	public static final String ANIMAL_NUMBERS_OUTPUT_FILE = OUTPUT_DIR + File.separator + "animals.txt";;
 
diff --git a/src/ac/ed/lurg/ModelMain.java b/src/ac/ed/lurg/ModelMain.java
index a4c86403..929070b8 100644
--- a/src/ac/ed/lurg/ModelMain.java
+++ b/src/ac/ed/lurg/ModelMain.java
@@ -4,7 +4,6 @@ import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
-import java.io.FileWriter;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
@@ -45,6 +44,7 @@ import ac.ed.lurg.output.LpjgOutputer;
 import ac.ed.lurg.types.CommodityType;
 import ac.ed.lurg.types.CropType;
 import ac.ed.lurg.types.LandCoverType;
+import ac.ed.lurg.utils.FileWriterHelper;
 import ac.ed.lurg.utils.LogWriter;
 import ac.ed.lurg.yield.LPJYieldResponseMapReader;
 import ac.ed.lurg.yield.YieldRaster;
@@ -136,23 +136,10 @@ public class ModelMain {
 		outputTimestepResults(timestep, globalLandUseRaster);
 	}
 
-	private BufferedWriter getFileWriter(Timestep timestep, String file, String columnHeadings) throws IOException {
-		if (timestep.isInitialTimestep()) {
-			FileWriter fstream = new FileWriter(file, false);
-			BufferedWriter outputFile = new BufferedWriter(fstream);
-			outputFile.write(columnHeadings);
-			outputFile.newLine();
-			return outputFile;
-		} else {
-			FileWriter fstream = new FileWriter(file, true);
-			return new BufferedWriter(fstream);
-		}
-	}
-
 	private void writeLandCoverFile(Timestep timestep, RasterSet<LandUseItem> landUseRaster) {
 		try {
 			StringBuffer sbHeadings = new StringBuffer("Year,Cropland,Pasture,ManForest,UnmanForest,Natural,AbPasture,EnergyCrop,FertCrop,IrrigCrop");
-			BufferedWriter outputFile = getFileWriter(timestep, ModelConfig.LAND_COVER_OUTPUT_FILE, sbHeadings.toString());
+			BufferedWriter outputFile = FileWriterHelper.getFileWriter(timestep, ModelConfig.LAND_COVER_OUTPUT_FILE, sbHeadings.toString());
 
 			StringBuffer sbData = new StringBuffer();
 			sbData.append(String.format("%d,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f", timestep.getYear(),
@@ -178,7 +165,7 @@ public class ModelMain {
 
 	private void writeGlobalMarketFile(Timestep timestep) {
 		try {
-			BufferedWriter outputFile = getFileWriter(timestep, ModelConfig.PRICES_OUTPUT_FILE, "Year,Crop,Imports (Mt),Exports (Mt),New export price, Stock Levels (Mt)");
+			BufferedWriter outputFile = FileWriterHelper.getFileWriter(timestep, ModelConfig.PRICES_OUTPUT_FILE, "Year,Crop,Imports (Mt),Exports (Mt),New export price, Stock Levels (Mt)");
 			internationalMarket.writeGlobalMarketFile(timestep, outputFile);
 			outputFile.close();
 		} catch (IOException e) {
@@ -188,7 +175,7 @@ public class ModelMain {
 	
 	private void writeGlobalFoodBalanceSheet(Timestep timestep, RasterSet<LandUseItem> landUseRaster) {
 		try {
-			BufferedWriter outputFile = getFileWriter(timestep, ModelConfig.FOOD_BALANCE_SHEET_FILE, "Year,Crop,Production,Imports,Export,TransportLosses,StockVar,Supply,MonogastricsFeed,RuminantsFeed,SeedAndOtherLosses,FoodAnd1stGen,ProdArea");
+			BufferedWriter outputFile = FileWriterHelper.getFileWriter(timestep, ModelConfig.FOOD_BALANCE_SHEET_FILE, "Year,Crop,Production,Imports,Export,TransportLosses,StockVar,Supply,MonogastricsFeed,RuminantsFeed,SeedAndOtherLosses,FoodAnd1stGen,ProdArea");
 			Map<CropType, GlobalPrice> worldPrices = internationalMarket.getWorldPrices();
 			double harvestedAndFallowArea = 0;
 			
@@ -248,7 +235,7 @@ public class ModelMain {
 
 	private void writeDemandFile(Timestep timestep) {
 		try {
-			BufferedWriter outputFile = getFileWriter(timestep, ModelConfig.DEMAND_OUTPUT_FILE, "Year,Commodity,Amount (Mt)");
+			BufferedWriter outputFile = FileWriterHelper.getFileWriter(timestep, ModelConfig.DEMAND_OUTPUT_FILE, "Year,Commodity,Amount (Mt)");
 
 			for (CommodityType comm : CommodityType.getAllFoodItems()) {
 				double demandAmount = 0;
@@ -277,7 +264,7 @@ public class ModelMain {
 	private void writeDomesticProductionFile(Timestep timestep) {
 		try {
 			StringBuffer sbHeadings = new StringBuffer("Year, Country, Crop, Area, Production, Production_cost, Import_price, Export_price, Net_imports, Net_import_cost, Rum_feed_amount, Mon_feed_amount");
-			BufferedWriter outputFile = getFileWriter(timestep, ModelConfig.DOMESTIC_OUTPUT_FILE, sbHeadings.toString());
+			BufferedWriter outputFile = FileWriterHelper.getFileWriter(timestep, ModelConfig.DOMESTIC_OUTPUT_FILE, sbHeadings.toString());
 
 			for (CropType crop : CropType.getAllItems()) {
 				for (AbstractCountryAgent country : countryAgents.getAll()) {
@@ -326,7 +313,7 @@ public class ModelMain {
 
 		try {
 			StringBuffer sbHeadings = new StringBuffer("Year, Country, Commodity, Demand, BioenergyDemand");
-			BufferedWriter outputFile = getFileWriter(timestep, ModelConfig.COUNTRY_DEMAND_FILE, sbHeadings.toString());
+			BufferedWriter outputFile = FileWriterHelper.getFileWriter(timestep, ModelConfig.COUNTRY_DEMAND_FILE, sbHeadings.toString());
 
 			for (AbstractCountryAgent country : countryAgents.getAll()) {
 				for (CommodityType commodity : CommodityType.getAllFoodItems()) {
@@ -351,7 +338,7 @@ public class ModelMain {
 	private void writeAnimalNumber(Timestep timestep) {
 		try {
 			StringBuffer sbHeadings = new StringBuffer("Year,Country,FAOItem,Heads(M)");
-			BufferedWriter outputFile = getFileWriter(timestep, ModelConfig.ANIMAL_NUMBERS_OUTPUT_FILE, sbHeadings.toString());
+			BufferedWriter outputFile = FileWriterHelper.getFileWriter(timestep, ModelConfig.ANIMAL_NUMBERS_OUTPUT_FILE, sbHeadings.toString());
 		
 			for (AbstractCountryAgent country : countryAgents.getAll()) {
 				Map<CropType, CropUsageData> cropUsageAllCrops = country.getCropUsageData();
diff --git a/src/ac/ed/lurg/country/gams/GamsDemandInput.java b/src/ac/ed/lurg/country/gams/GamsDemandInput.java
index d7cd2f3b..70979aee 100644
--- a/src/ac/ed/lurg/country/gams/GamsDemandInput.java
+++ b/src/ac/ed/lurg/country/gams/GamsDemandInput.java
@@ -7,14 +7,16 @@ import ac.ed.lurg.types.CommodityType;
 
 public class GamsDemandInput {
 	private SingleCountry country;
+	private int year;
 	private double gdpPc;
 	private Map<CommodityType, Double> prices;
 	private double usaGdpPc;
 	private GamsDemandOutput previousGamsDemands;
 	
-	public GamsDemandInput(SingleCountry country, double gdpPc, Map<CommodityType, Double> prices, double usaGdpPc, GamsDemandOutput previousGamsDemands) {
+	public GamsDemandInput(SingleCountry country, int year, double gdpPc, Map<CommodityType, Double> prices, double usaGdpPc, GamsDemandOutput previousGamsDemands) {
 		super();
 		this.country = country;
+		this.year = year;
 		this.gdpPc = gdpPc;
 		this.prices = prices;
 		this.usaGdpPc = usaGdpPc;
@@ -24,6 +26,9 @@ public class GamsDemandInput {
 	public SingleCountry getCountry() {
 		return country;
 	}
+	public int getYear() {
+		return year;
+	}
 	public double getGdpPc() {
 		return gdpPc;
 	}
diff --git a/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java b/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java
index f164c4d9..f64f0186 100644
--- a/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java
+++ b/src/ac/ed/lurg/country/gams/GamsDemandOptimiser.java
@@ -1,13 +1,9 @@
 package ac.ed.lurg.country.gams;
 
-import java.io.BufferedWriter;
 import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Vector;
-import java.util.Map.Entry;
 
 import com.gams.api.GAMSDatabase;
 import com.gams.api.GAMSGlobals;
@@ -21,11 +17,7 @@ import com.gams.api.GAMSWorkspace;
 import com.gams.api.GAMSWorkspaceInfo;
 
 import ac.ed.lurg.ModelConfig;
-import ac.ed.lurg.Timestep;
-import ac.ed.lurg.country.AbstractCountryAgent;
-import ac.ed.lurg.landuse.CropUsageData;
 import ac.ed.lurg.types.CommodityType;
-import ac.ed.lurg.types.CropType;
 import ac.ed.lurg.utils.LogWriter;
 
 public class GamsDemandOptimiser {
@@ -79,11 +71,9 @@ public class GamsDemandOptimiser {
 		for (Map.Entry<CommodityType, Double> entry : inputData.getPrices().entrySet()) {
 			CommodityType comm = entry.getKey();
 			double priceComm = entry.getValue();
-			doCommodity(inDB, priceP, prevSubsP, prevDiscP, gdpPc, previousGamsDemands, comm, priceComm, 0.1, 0.1);
+			doCommodity(inDB, priceP, prevSubsP, prevDiscP, gdpPc, previousGamsDemands, comm, priceComm, 
+					comm==CommodityType.NONFOOD ? 5 : 0.05, comm==CommodityType.NONFOOD ? 0.5 : 0.05);
 		}
-		
-		double nonfoodPrice = 45.376+53.036*gdpPc/inputData.getUsaGdpPc();
-		doCommodity(inDB, priceP, prevSubsP, prevDiscP, gdpPc, previousGamsDemands, CommodityType.NONFOOD, nonfoodPrice, 5, 1);
 	}
 
 	private void doCommodity(GAMSDatabase inDB, GAMSParameter priceP, GAMSParameter prevSubsP, GAMSParameter prevDiscP, double gdpPc, 
@@ -113,9 +103,9 @@ public class GamsDemandOptimiser {
 		
 	private GamsDemandOutput handleResults(GAMSDatabase outDB) {
 		int modelStatus = (int) outDB.getParameter("ms").findRecord().getValue();
+		String status = GAMSGlobals.ModelStat.lookup(modelStatus).toString();
 		LogWriter.println(String.format("\nDemamd %s: Modelstatus %s, Solvestatus %s", inputData.getCountry(),
-				GAMSGlobals.ModelStat.lookup( modelStatus ),
-				GAMSGlobals.SolveStat.lookup((int) outDB.getParameter("ss").findRecord().getValue()) ));
+				status,	GAMSGlobals.SolveStat.lookup((int) outDB.getParameter("ss").findRecord().getValue()) ));
 		
 		GAMSVariable varU = outDB.getVariable("u");
 		double utility = varU.getFirstRecord().getLevel();
@@ -141,6 +131,6 @@ public class GamsDemandOptimiser {
 			}
 		}
 		
-		return new GamsDemandOutput(demandMap, utility);
+		return new GamsDemandOutput(status, demandMap, utility);
 	}
 }
diff --git a/src/ac/ed/lurg/country/gams/GamsDemandOutput.java b/src/ac/ed/lurg/country/gams/GamsDemandOutput.java
index c8f12785..85fe7c45 100644
--- a/src/ac/ed/lurg/country/gams/GamsDemandOutput.java
+++ b/src/ac/ed/lurg/country/gams/GamsDemandOutput.java
@@ -7,10 +7,13 @@ import java.util.Map;
 import ac.ed.lurg.types.CommodityType;
 
 public class GamsDemandOutput {
-	public Collection<GamsCommodityDemand> demands;
-	public double utility;
+	private String status;
+	
+	private Collection<GamsCommodityDemand> demands;
+	private double utility;
 
-	public GamsDemandOutput(Collection<GamsCommodityDemand> demands, double utility) {
+	public GamsDemandOutput(String status, Collection<GamsCommodityDemand> demands, double utility) {
+		this.status = status;
 		this.demands = demands;
 		this.utility = utility;
 	}
@@ -35,4 +38,7 @@ public class GamsDemandOutput {
 	public double getUtility() {
 		return utility;
 	}
+	public String getStatus() {
+		return status;
+	}
 }
diff --git a/src/ac/ed/lurg/demand/AbstractSSPDemandManager.java b/src/ac/ed/lurg/demand/AbstractSSPDemandManager.java
index b9ae2188..5d6cb818 100644
--- a/src/ac/ed/lurg/demand/AbstractSSPDemandManager.java
+++ b/src/ac/ed/lurg/demand/AbstractSSPDemandManager.java
@@ -45,7 +45,7 @@ public abstract class AbstractSSPDemandManager extends AbstractDemandManager {
 		SspData usaSd = sspManager.get(ssp_scenario, year, usa);
 		
 		LogWriter.println("Got ssp data for " + c.getCountryName() + " of " + sd);
-		foodDemandMap = getFoodDemandMap(c, gdpPcYear * ModelConfig.SSP_GDP_PC_FACTOR, sd.getPopulation() * ModelConfig.SSP_POPULATION_FACTOR, prices, usaSd.getGdpPc());
+		foodDemandMap = getFoodDemandMap(c, year, gdpPcYear * ModelConfig.SSP_GDP_PC_FACTOR, sd.getPopulation() * ModelConfig.SSP_POPULATION_FACTOR, prices, usaSd.getGdpPc());
 		
 		if(!ModelConfig.SHOCKS_POSSIBLE){
 			return foodDemandMap;
@@ -63,5 +63,5 @@ public abstract class AbstractSSPDemandManager extends AbstractDemandManager {
 		return projectedCpc;
 	}
 
-	abstract Map<CommodityType, Double> getFoodDemandMap(SingleCountry c, double gdpPc, double population, Map<CommodityType, Double> prices, double usaGdpPc);
+	abstract Map<CommodityType, Double> getFoodDemandMap(SingleCountry c, int year, double gdpPc, double population, Map<CommodityType, Double> prices, double usaGdpPc);
 }
diff --git a/src/ac/ed/lurg/demand/DemandManagerSSP.java b/src/ac/ed/lurg/demand/DemandManagerSSP.java
index 41f5c319..3973e73b 100644
--- a/src/ac/ed/lurg/demand/DemandManagerSSP.java
+++ b/src/ac/ed/lurg/demand/DemandManagerSSP.java
@@ -19,7 +19,7 @@ public class DemandManagerSSP extends AbstractSSPDemandManager {
 	}
 
 	@Override
-	Map<CommodityType, Double> getFoodDemandMap(SingleCountry c, double gdpPc, double population, Map<CommodityType, Double> prices, double usaGdpPc) {
+	Map<CommodityType, Double> getFoodDemandMap(SingleCountry c, int year, double gdpPc, double population, Map<CommodityType, Double> prices, double usaGdpPc) {
 		Map<CommodityType, Double> aFoodDemandMap = new HashMap<CommodityType, Double>();
 		SspData baseSspData = sspManager.get(ssp_scenario, ModelConfig.BASE_YEAR, c);
 		double baseGdpPc = baseSspData.getGdpPc();
diff --git a/src/ac/ed/lurg/demand/ElasticDemandManager.java b/src/ac/ed/lurg/demand/ElasticDemandManager.java
index 4171d3e7..3b523c30 100644
--- a/src/ac/ed/lurg/demand/ElasticDemandManager.java
+++ b/src/ac/ed/lurg/demand/ElasticDemandManager.java
@@ -1,5 +1,7 @@
 package ac.ed.lurg.demand;
 
+import java.io.BufferedWriter;
+import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -10,26 +12,39 @@ import ac.ed.lurg.country.gams.GamsDemandInput;
 import ac.ed.lurg.country.gams.GamsDemandOptimiser;
 import ac.ed.lurg.country.gams.GamsDemandOutput;
 import ac.ed.lurg.types.CommodityType;
+import ac.ed.lurg.utils.FileWriterHelper;
+import ac.ed.lurg.utils.LogWriter;
 
 public class ElasticDemandManager extends AbstractSSPDemandManager {
-	
+
 	private Map<SingleCountry, Map<CommodityType, Double>> baseCpcCache = new HashMap<SingleCountry, Map<CommodityType, Double>>();
 	private Map<SingleCountry, GamsDemandOutput> previousGamsDemands = new HashMap<SingleCountry, GamsDemandOutput>();
-	
+	private BufferedWriter outputFile;
+
+
 	public ElasticDemandManager(String ssp_scenario, BaseConsumpManager baseConsumpManager, CompositeCountryManager compositeCountryManager) {
 		super(ssp_scenario, baseConsumpManager, compositeCountryManager);
+
+		try {
+			outputFile = FileWriterHelper.getFileWriter(true, true, ModelConfig.DEMAND_OPTIMISATION_OUTPUT_FILE, getDamsDemandOutputsHeader());
+		} catch (IOException e) {
+			LogWriter.print(e);
+		}
 	}
 
 	@Override
-	Map<CommodityType, Double> getFoodDemandMap(SingleCountry c, double gdpPc, double population, Map<CommodityType, Double> prices, double usaGdpPc) {
-		
-		GamsDemandInput inputData = new GamsDemandInput(c, gdpPc, prices, usaGdpPc, previousGamsDemands.get(c));
+	Map<CommodityType, Double> getFoodDemandMap(SingleCountry c, int year, double gdpPc, double population, Map<CommodityType, Double> prices, double usaGdpPc) {
+
+		double nonfoodPrice = 45.376+53.036*gdpPc/usaGdpPc;
+		prices.put(CommodityType.NONFOOD, nonfoodPrice);
 		
+		GamsDemandInput inputData = new GamsDemandInput(c, year, gdpPc, prices, usaGdpPc, previousGamsDemands.get(c));
+
 		// Do the projection
 		GamsDemandOutput gamsOutput = new GamsDemandOptimiser(inputData).getDemandPc();
 		previousGamsDemands.put(c, gamsOutput);
 		Map<CommodityType, Double> foodPc = gamsOutput.getPlumDemands();
-		
+
 		Map<CommodityType, Double> foodDemands = new HashMap<CommodityType, Double>();
 		SspData baseSspData = sspManager.get(ssp_scenario, ModelConfig.BASE_YEAR, c);
 		double baseGdpPc = baseSspData.getGdp();
@@ -45,12 +60,60 @@ public class ElasticDemandManager extends AbstractSSPDemandManager {
 			double newExpCpc = entry.getValue();
 			double baseExpCpc = baseExpCpcMap.get(commodity);
 			double baseCpc = baseConsumpManager.get(c, commodity);
-			
+
 			double cpc = rebaseConsumption(baseGdpPc, baseCpc, baseExpCpc, gdpPc, newExpCpc);					
 			double d = cpc * population;
 			foodDemands.put(commodity, d);
 		}
 
+		writeGamsDemandOutputs(inputData, gamsOutput, foodDemands);
+
 		return foodDemands;
 	}
+
+	private String getDamsDemandOutputsHeader() {
+		StringBuffer sbHeader = new StringBuffer("country,year,gdpPc");
+
+		for (CommodityType commodity : CommodityType.values())
+			sbHeader.append(",price_" + commodity.getGamsName());
+
+		sbHeader.append(",status,utility");
+
+		for (CommodityType commodity : CommodityType.values())
+			sbHeader.append(",gamssubs_" + commodity.getGamsName());
+		for (CommodityType commodity : CommodityType.values())
+			sbHeader.append(",gamsdisc_" + commodity.getGamsName());
+		for (CommodityType commodity : CommodityType.getAllFoodItems())
+			sbHeader.append(",plumdemand_" + commodity.getGamsName());
+		for (CommodityType commodity : CommodityType.getAllFoodItems())
+			sbHeader.append(",plumrebased_" + commodity.getGamsName());
+
+		return sbHeader.toString();
+	}
+
+	private void writeGamsDemandOutputs(GamsDemandInput inputData, GamsDemandOutput gamsOutput, Map<CommodityType, Double> foodDemands) {
+		try {
+			StringBuffer sbData = new StringBuffer(String.format("%s,%d,%.2f", inputData.getCountry(), inputData.getYear(),inputData.getGdpPc()));
+
+			for (CommodityType commodity : CommodityType.values())
+				sbData.append(String.format(",%.4f", inputData.getPrices().get(commodity)));
+
+			sbData.append(String.format(",%s,%.6f", gamsOutput.getStatus(), gamsOutput.getUtility()));
+
+			for (CommodityType commodity : CommodityType.values())
+				sbData.append(String.format(",%.4f", gamsOutput.getGamsDemands(commodity).getSubsistence()));
+			for (CommodityType commodity : CommodityType.values())
+				sbData.append(String.format(",%.4f", gamsOutput.getGamsDemands(commodity).getDiscretionary()));
+			for (CommodityType commodity : CommodityType.getAllFoodItems())
+				sbData.append(String.format(",%.4f", gamsOutput.getPlumDemands().get(commodity)));
+			for (CommodityType commodity : CommodityType.getAllFoodItems())
+				sbData.append(String.format(",%.4f", foodDemands.get(commodity)));
+
+			outputFile.write(sbData.toString());
+			outputFile.newLine();
+		}
+		catch (IOException e) {
+			LogWriter.print(e);
+		}
+	}
 }
\ No newline at end of file
diff --git a/src/ac/ed/lurg/utils/FileWriterHelper.java b/src/ac/ed/lurg/utils/FileWriterHelper.java
new file mode 100644
index 00000000..2da080a6
--- /dev/null
+++ b/src/ac/ed/lurg/utils/FileWriterHelper.java
@@ -0,0 +1,39 @@
+package ac.ed.lurg.utils;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import ac.ed.lurg.Timestep;
+
+public class FileWriterHelper {
+
+	static public BufferedWriter getFileWriter(Timestep timestep, String file, String columnHeadings) throws IOException {
+		return getFileWriter(timestep.isInitialTimestep(), false, file, columnHeadings);
+	}
+	
+	static public BufferedWriter getFileWriter(boolean initialise, boolean addShutdownHook, String file, String columnHeadings) throws IOException {
+		BufferedWriter outputFile;
+		FileWriter fstream = new FileWriter(file, !initialise);
+		outputFile = new BufferedWriter(fstream);
+		
+		if (initialise) {
+			outputFile.write(columnHeadings);
+			outputFile.newLine();
+		
+			if (addShutdownHook) {
+		 		Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+					public void run() {
+						try {
+							outputFile.close();
+						} catch (IOException e) {
+							LogWriter.print(e);
+						}
+					}
+				}));
+			}
+		}
+		
+		return outputFile;
+	}
+}
-- 
GitLab