Skip to content
Snippets Groups Projects
GamsLocationOptimiser.java 15.2 KiB
Newer Older
Peter Alexander's avatar
Peter Alexander committed
package ac.ed.lurg.country.gams;

import java.io.File;
Peter Alexander's avatar
Peter Alexander committed
import java.util.HashMap;
Peter Alexander's avatar
Peter Alexander committed
import java.util.Map;
Peter Alexander's avatar
Peter Alexander committed
import java.util.Map.Entry;
import java.util.Vector;
Peter Alexander's avatar
Peter Alexander committed

import ac.ed.lurg.ModelConfig;
import ac.ed.lurg.country.GlobalPrice;
import ac.ed.lurg.country.ImportExportConstraint;
import ac.ed.lurg.landuse.CropUsageData;
Peter Alexander's avatar
Peter Alexander committed
import ac.ed.lurg.landuse.Intensity;
import ac.ed.lurg.landuse.IrrigationItem;
import ac.ed.lurg.landuse.LandUseItem;
import ac.ed.lurg.types.CommodityType;
Peter Alexander's avatar
Peter Alexander committed
import ac.ed.lurg.types.CropType;
import ac.ed.lurg.types.LandCoverType;
import ac.ed.lurg.utils.LazyHashMap;
Peter Alexander's avatar
Peter Alexander committed
import ac.ed.lurg.utils.LogWriter;
Peter Alexander's avatar
Peter Alexander committed
import ac.ed.lurg.yield.YieldResponsesItem;
Peter Alexander's avatar
Peter Alexander committed

import com.gams.api.GAMSDatabase;
import com.gams.api.GAMSException;
Peter Alexander's avatar
Peter Alexander committed
import com.gams.api.GAMSGlobals;
import com.gams.api.GAMSJob;
import com.gams.api.GAMSOptions;
import com.gams.api.GAMSParameter;
import com.gams.api.GAMSSet;
Peter Alexander's avatar
Peter Alexander committed
import com.gams.api.GAMSVariable;
import com.gams.api.GAMSVariableRecord;
import com.gams.api.GAMSWorkspace;
import com.gams.api.GAMSWorkspaceInfo;

public class GamsLocationOptimiser {
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
	private static final boolean DEBUG = true;
Peter Alexander's avatar
Peter Alexander committed

	private GamsLocationInput inputData;
Peter Alexander's avatar
Peter Alexander committed

	public GamsLocationOptimiser(GamsLocationInput inputData) {
Peter Alexander's avatar
Peter Alexander committed
		this.inputData = inputData;
	}
Peter Alexander's avatar
Peter Alexander committed

	public GamsLocationOutput run() {
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
		File workingDirectory = new File(ModelConfig.TEMP_DIR, "GamsTmp");
Peter Alexander's avatar
Peter Alexander committed
		workingDirectory.mkdir();

		GAMSWorkspaceInfo  wsInfo  = new GAMSWorkspaceInfo();
		wsInfo.setWorkingDirectory(workingDirectory.getAbsolutePath());
Peter Alexander's avatar
Peter Alexander committed
		//	wsInfo.setDebugLevel(DebugLevel.VERBOSE);

Peter Alexander's avatar
Peter Alexander committed
		GAMSWorkspace ws = new GAMSWorkspace(wsInfo);
Peter Alexander's avatar
Peter Alexander committed
		GAMSDatabase inDB = ws.addDatabase();

		setupInDB(inDB);

		GAMSJob gamsJob = ws.addJobFromFile(ModelConfig.GAMS_MODEL);
		GAMSOptions opt = ws.addOptions();
Peter Alexander's avatar
Peter Alexander committed

		opt.setAllModelTypes("conopt");
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
		opt.defines("gdxincname", inDB.getName());

		long startTime = System.currentTimeMillis();
		gamsJob.run(opt, inDB);
		
		if (ModelConfig.CLEANUP_GAMS_DIR) 
			cleanup(ws.workingDirectory());
		
Peter Alexander's avatar
Peter Alexander committed
		LogWriter.println("Took " + (System.currentTimeMillis() - startTime) + " ms to run");

		return handleResults(gamsJob.OutDB());
	}

	private void setupInDB(GAMSDatabase inDB) {
		//if (DEBUG) LogWriter.println("\nLocation set");
		GAMSSet locationSet = inDB.addSet("location", 1);
		for (Integer locId : inputData.getPreviousLandUse().keySet()) {
			//if (DEBUG) LogWriter.println("     " + locId);
			locationSet.addRecord(locId.toString());
		}
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
		if (DEBUG) LogWriter.println("\nPrevious crop and land areas");	
Peter Alexander's avatar
Peter Alexander committed
		GAMSParameter prevCropP = inDB.addParameter("previousArea", 2);
Peter Alexander's avatar
Peter Alexander committed
		GAMSParameter landP = inDB.addParameter("suitableLandArea", 1);
Peter Alexander's avatar
Peter Alexander committed
		double totalAgriLand = 0;
Peter Alexander's avatar
Peter Alexander committed

		for (Map.Entry<Integer, ? extends LandUseItem> entry : inputData.getPreviousLandUse().entrySet()) {
Peter Alexander's avatar
Peter Alexander committed
			Integer locationId = entry.getKey();
Peter Alexander's avatar
Peter Alexander committed
			String locString = Integer.toString(locationId);
			LandUseItem landUseItem = entry.getValue();
			double suitableLand = landUseItem.getSuitableLand();
			if (DEBUG) LogWriter.println(String.format("  %d   %15s,\t %.1f", locationId, "suitableLand", suitableLand));
			landP.addRecord(locString).setValue(suitableLand);
			
			double pastureArea = landUseItem.getLandCoverArea(LandCoverType.PASTURE);
			if (DEBUG) LogWriter.println(String.format("  %d   %15s,\t %.1f", locationId, "pastureArea", pastureArea));
			setPreviousArea(prevCropP, locString, CropType.PASTURE.getGamsName(), pastureArea);
			totalAgriLand += pastureArea;
Peter Alexander's avatar
Peter Alexander committed

			for (CropType cropType : CropType.getCropsLessPasture()) {
				double d = landUseItem.getCropArea(cropType);
Peter Alexander's avatar
Peter Alexander committed
				if (DEBUG && d != 0) LogWriter.println(String.format("  %d   %15s,\t %.1f", locationId, cropType.getGamsName(), d));
				setPreviousArea(prevCropP, locString, cropType.getGamsName(), d);
Peter Alexander's avatar
Peter Alexander committed
				totalAgriLand += d;
Peter Alexander's avatar
Peter Alexander committed
			}
		}
Peter Alexander's avatar
Peter Alexander committed
		if (DEBUG) LogWriter.println(String.format("  Total agricultural\t %.1f", totalAgriLand));

Peter Alexander's avatar
Peter Alexander committed
		if (DEBUG) LogWriter.println("\nIrrigation data (cost, constraint)");
		GAMSParameter irrigCostP = inDB.addParameter("irrigCost", 1);		
		GAMSParameter irrigConstraintP = inDB.addParameter("irrigConstraint", 1);
		Map<Integer, ? extends IrrigationItem> irrigationData = inputData.getIrrigationCosts();
		
		for (Entry<Integer, ? extends IrrigationItem> entry : irrigationData.entrySet()) {
Peter Alexander's avatar
Peter Alexander committed
			Integer locationId = entry.getKey();
			IrrigationItem irrigCostItem = entry.getValue();
Peter Alexander's avatar
Peter Alexander committed
			double irrigCost = irrigCostItem.getIrrigCost();
Peter Alexander's avatar
Peter Alexander committed
			double irrigConstraint = irrigCostItem.getIrrigConstraint();
			if (DEBUG) LogWriter.println(String.format("  %d  \t %.3f,\t %.1f", locationId, irrigCost, irrigConstraint));
Peter Alexander's avatar
Peter Alexander committed
			irrigCostP.addRecord(Integer.toString(locationId)).setValue(irrigCost);
			irrigConstraintP.addRecord(Integer.toString(locationId)).setValue(irrigConstraint);
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
		if (DEBUG) LogWriter.println("\nDemand");
Peter Alexander's avatar
Peter Alexander committed
		GamsCountryInput countryInput = inputData.getCountryInput();
		addCommodityMapParm(inDB.addParameter("demand", 1), countryInput.getProjectedDemand());
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
		if (DEBUG) LogWriter.println("\nYield (fert/irrig) None/None, Max/None, None/Max, Max/Max,\t [fert p],\t [irrig p],\t {max irrig}");
Peter Alexander's avatar
Peter Alexander committed
		GAMSParameter yNoneP = inDB.addParameter("yieldNone", 2);
		GAMSParameter y_fert = inDB.addParameter("yieldFertOnly", 2);
		GAMSParameter y_irrig = inDB.addParameter("yieldIrrigOnly", 2);
		GAMSParameter y_both = inDB.addParameter("yieldBoth", 2);
		GAMSParameter fert_p = inDB.addParameter("fertParam", 2);
		GAMSParameter irrig_p = inDB.addParameter("irrigParam", 2);
Peter Alexander's avatar
Peter Alexander committed
		GAMSParameter irrigMaxP = inDB.addParameter("irrigMaxRate", 2);
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
		for (Entry<Integer, ? extends YieldResponsesItem> entry : inputData.getYields().entrySet()) {
			Integer locationId = entry.getKey();
Peter Alexander's avatar
Peter Alexander committed
			String locString = Integer.toString(locationId);
Peter Alexander's avatar
Peter Alexander committed
			YieldResponsesItem yresp = entry.getValue();
Peter Alexander's avatar
Peter Alexander committed
			IrrigationItem irrigationItem = irrigationData.get(locationId);
			for (CropType crop : CropType.getNonMeatTypes()) {
Peter Alexander's avatar
Peter Alexander committed
				double maxIrrig = irrigationItem.getMaxIrrigAmount(crop);
				
				if (DEBUG) LogWriter.println(String.format("%d     %15s,\t %.1f,\t %.1f, \t %.1f,\t %.1f,\t\t [%.2f],\t [%.2f],\t {%.2f}", 
Peter Alexander's avatar
Peter Alexander committed
						locationId, crop.getGamsName(), yresp.getYieldNone(crop), yresp.getYieldFertOnly(crop), yresp.getYieldIrrigOnly(crop), yresp.getYieldMax(crop), 
						yresp.getFertParam(crop), yresp.getIrrigParam(crop), maxIrrig));
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
				Vector<String> v = new Vector<String>();
Peter Alexander's avatar
Peter Alexander committed
				v.add(crop.getGamsName());
Peter Alexander's avatar
Peter Alexander committed
				v.add(locString);
Peter Alexander's avatar
Peter Alexander committed
				yNoneP.addRecord(v).setValue(yresp.getYieldNone(crop));
				y_fert.addRecord(v).setValue(yresp.getYieldFertOnly(crop));
				y_irrig.addRecord(v).setValue(yresp.getYieldIrrigOnly(crop));
				y_both.addRecord(v).setValue(yresp.getYieldMax(crop));
				fert_p.addRecord(v).setValue(yresp.getFertParam(crop));
				irrig_p.addRecord(v).setValue(yresp.getIrrigParam(crop));
Peter Alexander's avatar
Peter Alexander committed
				irrigMaxP.addRecord(v).setValue(maxIrrig);
Peter Alexander's avatar
Peter Alexander committed
			}
		}
Peter Alexander's avatar
Peter Alexander committed

		if (DEBUG) { 
			LogWriter.println("\nImport-export, min net imports, max net imports,  import price,   export price");
			for (CropType crop : CropType.getImportedTypes()) {
				ImportExportConstraint iec = countryInput.getImportConstraints().get(crop);
				double minNetImport = 0, maxNetImport = 0;
				if (iec != null) {
					minNetImport = iec.getMinNetImport();
					maxNetImport = iec.getMaxNetImport();
				}
				GlobalPrice gp = countryInput.getWorldPrices().get(crop);
								
				LogWriter.println(String.format("     %15s, \t %5.1f, \t %5.1f, \t %5.3f, \t %5.3f", 
						crop.getGamsName(), minNetImport, maxNetImport, gp.getImportPrice(), gp.getExportPrice()));
			}
		}
		
		addItemMapParm(inDB.addParameter("minNetImport", 1), countryInput.getMinNetImport(), false);
		addItemMapParm(inDB.addParameter("maxNetImport", 1), countryInput.getMaxNetImport(), false);
		addItemMapParm(inDB.addParameter("worldImportPrices", 1), countryInput.getWorldImportPrices(), false);
		addItemMapParm(inDB.addParameter("worldExportPrices", 1), countryInput.getWorldExportPrices(), false);
Peter Alexander's avatar
Peter Alexander committed

		addScalar(inDB, "meatEfficency", countryInput.getMeatEfficiency());		
		addScalar(inDB, "fertiliserUnitCost", ModelConfig.FERTILISER_MAX_COST);
		addScalar(inDB, "otherICost",ModelConfig.OTHER_INTENSITY_COST);
		addScalar(inDB, "otherIParam", ModelConfig.OTHER_INTENSITY_PARAM);
		addScalar(inDB, "landChangeEnergy", countryInput.getLandChangeEnergy());
		addScalar(inDB, "minFeedRate", countryInput.getMinFeedRate());
		addScalar(inDB, "unhandledCropArea", ModelConfig.UNHANDLED_CROP_AREA);
Peter Alexander's avatar
Peter Alexander committed
		addScalar(inDB, "domesticPriceMarkup", ModelConfig.DOMESTIC_PRICE_MARKUP);
Peter Alexander's avatar
Peter Alexander committed
	}

	private void addScalar(GAMSDatabase gamsDb, String recordName, double val) {
		GAMSParameter param = gamsDb.addParameter(recordName, 0);
		param.addRecord().setValue(val);
		if (DEBUG) LogWriter.println("\n" + recordName + ": " + val);
	}
	
	private void setPreviousArea(GAMSParameter prevCropP, String locString, String cropTypeString, double d) {
		Vector<String> v = new Vector<String>();
		v.add(cropTypeString);
		v.add(locString);
		prevCropP.addRecord(v).setValue(d);
	}

	@SuppressWarnings("serial")
	private GamsLocationOutput handleResults(GAMSDatabase outDB) {
Peter Alexander's avatar
Peter Alexander committed
		int modelStatus = (int) outDB.getParameter("ms").findRecord().getValue();
		LogWriter.println(String.format("\n%s %s: Modelstatus %s, Solvestatus %s", 
				inputData.getCountryInput().getCountry(),
				inputData.getTimestep().getYear(),
				GAMSGlobals.ModelStat.lookup( modelStatus ),
				GAMSGlobals.SolveStat.lookup((int) outDB.getParameter("ss").findRecord().getValue()) ));
Peter Alexander's avatar
Peter Alexander committed

		GAMSVariable varAreas = outDB.getVariable("area");
		GAMSVariable varFertIntensities = outDB.getVariable("fertI");
		GAMSVariable varIrrigIntensities = outDB.getVariable("irrigI");
		GAMSVariable varOtherIntensities = outDB.getVariable("otherIntensity");
Peter Alexander's avatar
Peter Alexander committed
		GAMSVariable varFeedAmount = outDB.getVariable("feedAmount");
		GAMSParameter parmNetImports = outDB.getParameter("netImportAmount");
Peter Alexander's avatar
Peter Alexander committed
		GAMSVariable varYields = outDB.getVariable("yield");
		GAMSVariable varUnitEnergies = outDB.getVariable("unitEnergy");
Peter Alexander's avatar
Peter Alexander committed
//		GAMSParameter parmCropAdj = outDB.getParameter("cropAdj");
		GAMSParameter parmProd = outDB.getParameter("totalProd");
		GAMSParameter parmProdCost = outDB.getParameter("totalProdCost");
		GAMSParameter parmCroplandArea = outDB.getParameter("totalCropland");
Peter Alexander's avatar
Peter Alexander committed

		double totalCropArea = 0;
		double totalPastureArea = 0;
		double area, fertIntensity, irrigIntensity, otherIntensity = Double.NaN, feedAmount, netImport, yield, unitEnergy, cropAdj, prod, prodCost;
Peter Alexander's avatar
Peter Alexander committed

		final LazyHashMap<Integer, LandUseItem> landUses = new LazyHashMap<Integer, LandUseItem>() { 
			protected LandUseItem createValue() { return new LandUseItem(); }
		};		
		Map<Integer, ? extends IrrigationItem> allIrrigationRefData = inputData.getIrrigationCosts();

		Map<CropType, CropUsageData> cropUsageData = new HashMap<CropType, CropUsageData>();
Peter Alexander's avatar
Peter Alexander committed
		Map<CropType, Double> cropAdjs = new HashMap<CropType, Double>();
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
		for (GAMSVariableRecord rec : varAreas) {
Peter Alexander's avatar
Peter Alexander committed
			String itemName = rec.getKeys()[0];
			String locationName = rec.getKeys()[1];
Peter Alexander's avatar
Peter Alexander committed
			area = rec.getLevel();
			fertIntensity = varFertIntensities.findRecord(itemName, locationName).getLevel();
			irrigIntensity = varIrrigIntensities.findRecord(itemName, locationName).getLevel();
			otherIntensity = varOtherIntensities.findRecord(itemName, locationName).getLevel();
Peter Alexander's avatar
Peter Alexander committed
			yield = varYields.findRecord(itemName, locationName).getLevel();
			unitEnergy = varUnitEnergies.findRecord(itemName, locationName).getLevel();
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
			int locId = Integer.parseInt(locationName);
			CropType cropType = CropType.getForGamsName(itemName);
Peter Alexander's avatar
Peter Alexander committed

			if (!cropUsageData.containsKey(cropType)) {  // then we must not have seen this crop type before, so need to do all non location specific stuff
Peter Alexander's avatar
Peter Alexander committed
				feedAmount = varFeedAmount.findRecord(itemName).getLevel();
				netImport = cropType.isImportedCrop() ? getParmValue(parmNetImports, itemName) : 0;
Peter Alexander's avatar
Peter Alexander committed
//				cropAdj = getParmValue(parmCropAdj, itemName);
				prod =  getParmValue(parmProd, itemName);
				prodCost = getParmValue(parmProdCost, itemName);
Peter Alexander's avatar
Peter Alexander committed
				cropUsageData.put(cropType, new CropUsageData(feedAmount, netImport, prod, prodCost));
Peter Alexander's avatar
Peter Alexander committed
//				cropAdjs.put(cropType, cropAdj);
				if (DEBUG) LogWriter.println(String.format("\n%s:\tfeedAmount= %.1f,\tnetImports= %.3f,\tprod= %.3f,\tprodCost= %.3f,\tcropAdj= %.3f", itemName, feedAmount, netImport, prod, prodCost, Double.NaN)); 
Peter Alexander's avatar
Peter Alexander committed
			}

			LandUseItem landUseItem = landUses.lazyGet(locId);
Peter Alexander's avatar
Peter Alexander committed
			if (area > 0) { 
				if (DEBUG) LogWriter.println(String.format("\t location %s, %s:\tarea= %.1f,\tfert= %.3f,\tirrg= %.3f,\tintensity= %.3f", locationName, itemName, area, fertIntensity, irrigIntensity, otherIntensity));				
				IrrigationItem irrigRefData = allIrrigationRefData.get(locId);
				landUseItem.setIntensity(cropType, new Intensity(fertIntensity, irrigIntensity, otherIntensity, yield, unitEnergy, irrigRefData.getMaxIrrigAmount(cropType)));
Peter Alexander's avatar
Peter Alexander committed
			}
Peter Alexander's avatar
Peter Alexander committed

			double croplandArea = getParmValue(parmCroplandArea, locationName);
			if (cropType.equals(CropType.PASTURE)) {
				landUseItem.setLandCoverArea(LandCoverType.PASTURE, area);
				totalPastureArea += area;
			}
			else {
				landUseItem.setLandCoverArea(LandCoverType.CROPLAND, croplandArea);  // will set this multiple times, once for each arable crop, but doesn't really matter
				totalCropArea += area;
			}
			
			landUseItem.setCropFraction(cropType, croplandArea > 0 ? area/croplandArea : 0);
Peter Alexander's avatar
Peter Alexander committed
		}
Peter Alexander's avatar
Peter Alexander committed

		netImport = getParmValue(parmNetImports, CropType.MEAT.getGamsName());
		prod = getParmValue(parmProd, CropType.MEAT.getGamsName());
		prodCost = getParmValue(parmProdCost, CropType.MEAT.getGamsName());
		
Peter Alexander's avatar
Peter Alexander committed
		cropUsageData.put(CropType.MEAT, new CropUsageData(0.0, netImport, prod, prodCost));
Peter Alexander's avatar
Peter Alexander committed
		if (DEBUG) {
			LogWriter.println(String.format("\n%s:\t\t\t\t\tnetImports= %.3f,\tprod= %.3f,\tprodCost= %.3f", CropType.MEAT.getGamsName(), netImport, prod, prodCost)); 
			LogWriter.println(String.format("\nTotal area= %.1f (crop=%.1f, pasture %.1f)", totalCropArea+totalPastureArea, totalCropArea, totalPastureArea));
Peter Alexander's avatar
Peter Alexander committed
		}
Peter Alexander's avatar
Peter Alexander committed

		GamsLocationOutput results = new GamsLocationOutput(modelStatus, landUses, cropUsageData, cropAdjs);
Peter Alexander's avatar
Peter Alexander committed
		return results;
Peter Alexander's avatar
Peter Alexander committed
	}
Peter Alexander's avatar
Peter Alexander committed

	private double getParmValue(GAMSParameter aParm, String itemName) {
		try {
			double d = aParm.findRecord(itemName).getValue();
			return d;
		}
		catch (GAMSException gamsEx) {
			//LogWriter.println("GAMSException thrown for " + itemName);
			return 0;
		}
	}
Peter Alexander's avatar
Peter Alexander committed

	private void addItemMapParm(GAMSParameter parm, Map<CropType, Double> itemMap, boolean printOutput) {
Peter Alexander's avatar
Peter Alexander committed
		for (Map.Entry<CropType, Double> entry : itemMap.entrySet()) {
Peter Alexander's avatar
Peter Alexander committed
			double d = entry.getValue();
			if (printOutput) LogWriter.println(String.format("     %15s,\t %.3f", entry.getKey().getGamsName(), d));
Peter Alexander's avatar
Peter Alexander committed
			if (!Double.isNaN(d))
				parm.addRecord(entry.getKey().getGamsName()).setValue(d);
Peter Alexander's avatar
Peter Alexander committed
		}
	}
Peter Alexander's avatar
Peter Alexander committed

	private void addCommodityMapParm(GAMSParameter parm, Map<CommodityType, Double> itemMap) {
		for (Map.Entry<CommodityType, Double> entry : itemMap.entrySet()) {
			double d = entry.getValue();
			if (DEBUG) LogWriter.println(String.format("     %15s,\t %.1f", entry.getKey().getGamsName(), d));
			if (!Double.isNaN(d))
				parm.addRecord(entry.getKey().getGamsName()).setValue(d);
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
	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);
Peter Alexander's avatar
Peter Alexander committed
			}
		}
		try {
			directoryToDelete.delete();
		} catch(Exception e) {
			LogWriter.print(e);
Peter Alexander's avatar
Peter Alexander committed
		}
	}
Peter Alexander's avatar
Peter Alexander committed
}