Skip to content
Snippets Groups Projects
ModelMain.java 13.5 KiB
Newer Older
package ac.ed.lurg;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
Peter Alexander's avatar
Peter Alexander committed
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
Peter Alexander's avatar
Peter Alexander committed
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import ac.ed.lurg.country.Country;
import ac.ed.lurg.country.CountryAgent;
import ac.ed.lurg.country.CountryBoundaryItem;
import ac.ed.lurg.country.CountryBoundaryReader;
Peter Alexander's avatar
Peter Alexander committed
import ac.ed.lurg.country.gams.GamsRasterOutput;
import ac.ed.lurg.demand.DemandManager;
import ac.ed.lurg.landuse.AreasItem;
import ac.ed.lurg.landuse.CropUsageData;
Peter Alexander's avatar
Peter Alexander committed
import ac.ed.lurg.landuse.CropUsageReader;
import ac.ed.lurg.landuse.IntensitiesItem;
Peter Alexander's avatar
Peter Alexander committed
import ac.ed.lurg.landuse.IrrigationCostItem;
import ac.ed.lurg.landuse.IrrigiationCostReader;
Peter Alexander's avatar
Peter Alexander committed
import ac.ed.lurg.landuse.LandCoverItem;
import ac.ed.lurg.landuse.LandCoverReader;
import ac.ed.lurg.output.LpjgOutputer;
Peter Alexander's avatar
Peter Alexander committed
import ac.ed.lurg.types.CropToDoubleMap;
Peter Alexander's avatar
Peter Alexander committed
import ac.ed.lurg.types.CropType;
import ac.ed.lurg.types.LandCoverType;
import ac.ed.lurg.types.ModelFitType;
import ac.ed.lurg.utils.LogWriter;
import ac.ed.lurg.yield.LPJYieldResponseMapReader;
import ac.ed.lurg.yield.YieldRaster;
import ac.sac.raster.IntegerRasterItem;
Peter Alexander's avatar
Peter Alexander committed
import ac.sac.raster.RasterHeaderDetails;
import ac.sac.raster.RasterKey;
import ac.sac.raster.RasterOutputer;
Peter Alexander's avatar
Peter Alexander committed
import ac.sac.raster.RasterSet;

public class ModelMain {

	private Collection<CountryAgent> countryAgents;
	private Map<Country, List<RasterKey>> countryToKeysMap;
Peter Alexander's avatar
Peter Alexander committed
	private DemandManager demandManager;
	private Map<CropType, Double> prevWorldPrices;
Peter Alexander's avatar
Peter Alexander committed
	private RasterHeaderDetails desiredProjection;
Peter Alexander's avatar
Peter Alexander committed

	public static void main(String[] args)  {
		ModelMain theModel = new ModelMain();
		theModel.setup();
		theModel.run();
	}
Peter Alexander's avatar
Peter Alexander committed

	/* setup models, reading inputs, etc. */
	private void setup() {
		desiredProjection = RasterHeaderDetails.getGlobalHeaderFromCellSize(ModelConfig.CELL_SIZE_X, ModelConfig.CELL_SIZE_Y, "999");
Peter Alexander's avatar
Peter Alexander committed
		countryToKeysMap = createCountryToKeysMap();
		demandManager = new DemandManager(ModelFitType.LOGISTIC, ModelConfig.SSP_SCENARIO);
		countryAgents = createCountryAgents();
Peter Alexander's avatar
Peter Alexander committed
		// in first timestep we don't have this info, but ok as constrained to import/export specified amount
		prevWorldPrices = new HashMap<CropType, Double>();  
Peter Alexander's avatar
Peter Alexander committed
		for (CropType c : CropType.getImportedTypes()) 
			prevWorldPrices.put(c, 1.0);
Peter Alexander's avatar
Peter Alexander committed
	}
Peter Alexander's avatar
Peter Alexander committed
	/* run the model */
	private void run() {
		for (int i = ModelConfig.START_TIMESTEP; i <= ModelConfig.END_TIMESTEP; i++) {
			Timestep timestep = new Timestep(i);
			try {
				doTimestep(timestep);
			}
			catch (Exception e) {
				LpjgOutputer.writeMarkerFile(timestep, true);
				LogWriter.printlnError(e.getMessage());
				throw new RuntimeException(e);
			}
		}
	private void doTimestep(Timestep timestep) {
		LogWriter.println(timestep.toString());
		YieldRaster yieldSurfaces = getYieldSurfaces(timestep);  // this will wait for the marker file from LPJ if configured to do so

		//		YieldResponsesItem yresp = yieldSurfaces.getFromCoordinates(-50.0, -4.0);
		//		LogWriter.printlnError("Test key: " + yresp.getYieldMax(CropType.CEREALS)  + ", " + yresp.getYieldFertOnly(CropType.CEREALS) + ", " + yresp.getYieldIrrigOnly(CropType.CEREALS));
		CropToDoubleMap totalImportCommodities = new CropToDoubleMap();
		CropToDoubleMap totalExportCommodities = new CropToDoubleMap();
		RasterSet<IntensitiesItem> globalIntensityRaster = new RasterSet<IntensitiesItem>(desiredProjection);
		RasterSet<AreasItem> globalCropAreaRaster = new RasterSet<AreasItem>(desiredProjection);
		RasterSet<IntegerRasterItem> globalLocationIdRaster = new RasterSet<IntegerRasterItem>(desiredProjection);
				
Peter Alexander's avatar
Peter Alexander committed
		for (CountryAgent ca : countryAgents) {
Peter Alexander's avatar
Peter Alexander committed
			LogWriter.println("Country " + ca.getCountry());
			Collection<RasterKey> countryKeys = countryToKeysMap.get(ca.getCountry());
			YieldRaster countryYieldSurfaces = yieldSurfaces.getSubsetRasterForKeys(countryKeys);
Peter Alexander's avatar
Peter Alexander committed
						
Peter Alexander's avatar
Peter Alexander committed
			// do the optimization
			GamsRasterOutput result = ca.determineProduction(timestep, countryYieldSurfaces, prevWorldPrices);
Peter Alexander's avatar
Peter Alexander committed
			if (result == null) {
				LogWriter.printlnError("No results for " + ca.getCountry());
				continue;
			}

			// update global rasters
			globalIntensityRaster.putAll(result.getIntensityRaster());
			globalCropAreaRaster.putAll(result.getCropAreaRaster());
			globalLocationIdRaster.putAll(result.getLocationIdRaster());
			// Get values for world input costs
			Map<CropType, CropUsageData> cropUsage = result.getCropUsageData();

			for (Entry<CropType, CropUsageData> entry : cropUsage.entrySet()) {
				CropType c = entry.getKey();
				double countryNetImports = entry.getValue().getNetImports();
				if (countryNetImports > 0)
					totalImportCommodities.incrementValue(c, countryNetImports);
				else
					totalExportCommodities.incrementValue(c, -countryNetImports);
Peter Alexander's avatar
Peter Alexander committed
			}
Peter Alexander's avatar
Peter Alexander committed
		}
		// Look at trade balance and adjust appropriately
		for (CropType crop : CropType.getImportedTypes()) {
			double imports = totalImportCommodities.get(crop);
			double exports = totalExportCommodities.get(crop);
			double prevPrice = prevWorldPrices.get(crop);
			double adjustedPrice = updateMarketPrices(prevPrice, imports, exports);
			LogWriter.println(String.format("Price for %s updated from %.3f (imports %.0f, exports %.0f) to %.3f ", crop.getGamsName(), prevPrice, imports, exports, adjustedPrice));
			prevWorldPrices.put(crop, adjustedPrice);
		}
		// output results
		outputTimestepResults(timestep, globalIntensityRaster, globalCropAreaRaster, globalLocationIdRaster, yieldSurfaces);
		writeMarketFile(timestep, globalCropAreaRaster);
	}
	
	public double updateMarketPrices(double previousPrice, double demand, double supply) {

		if (demand > 0 || supply > 0) {
			double ratio;
			
			if (demand > supply)
				ratio = (demand-supply)/demand;
			else
				ratio = (demand-supply)/supply;
			double adjustment = Math.exp(ratio * ModelConfig.MARKET_LAMBA);
			return previousPrice * adjustment;
		}
		else {
			return previousPrice;
		}
	}

	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 double getTotalArea(LandCoverType lcType, RasterSet<AreasItem> globalCropAreaRaster) {
		double totalArea = 0;
		for (AreasItem item : globalCropAreaRaster.values()) {
			totalArea += item.getLandCoverArea(lcType);
		}
		return totalArea;
	}

	private void writeMarketFile(Timestep timestep, RasterSet<AreasItem> cropAreaRaster) {
		try {
			StringBuffer sbHeadings = new StringBuffer("Year, Cropland (Mha), Pasture (Mha), Natural (Mha)");
			for (CropType crop : CropType.getImportedTypes() )
				sbHeadings.append(",Px_" + crop.getGamsName());
			
			BufferedWriter outputFile = getFileWriter(timestep, ModelConfig.TOTAL_LAND_COVER_FILE, sbHeadings.toString());

			StringBuffer sbData = new StringBuffer();
			sbData.append(String.format("%d,%.1f,%.1f,%.1f", 
					timestep.getYear(), getTotalArea(LandCoverType.CROPLAND, cropAreaRaster), getTotalArea(LandCoverType.PASTURE, cropAreaRaster), getTotalArea(LandCoverType.OTHER_NATURAL, cropAreaRaster)));
			
			for (CropType crop : CropType.getImportedTypes() )
				sbData.append(String.format(",%.3f", prevWorldPrices.get(crop)));
			
			outputFile.write(sbData.toString());
			outputFile.newLine();
			outputFile.close();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
Peter Alexander's avatar
Peter Alexander committed
	}

	private void outputTimestepResults(Timestep timestep, RasterSet<IntensitiesItem> intensityRaster, RasterSet<AreasItem> cropAreaRaster, RasterSet<IntegerRasterItem> locationIdRaster, YieldRaster yieldSurfaces) {
Peter Alexander's avatar
Peter Alexander committed
		
		LpjgOutputer lpjOutputer = new LpjgOutputer(timestep, intensityRaster, cropAreaRaster, yieldSurfaces);
		lpjOutputer.writeOutput();
		
		/*	new RasterOutputer<IntegerRasterItem>(locationIdRaster, "locId" + year) {
			@Override
			public Double getValue(RasterKey location) {
				IntegerRasterItem locItem = results.get(location);
				if (locItem == null)
					return null;

				return (double)locItem.getInt();
			}

			@Override
			public int convertToPixelValue(double value) {
Peter Alexander's avatar
Peter Alexander committed
				return (int) (value * 3 + 1);
			}	
		}.writeOutput(ModelConfig.WRITE_JPEG_IMAGES);


		new RasterOutputer<IntensitiesItem>(intensityRaster, "wheatIntensity" + year) {
			@Override
			public Double getValue(RasterKey location) {
				IntensitiesItem intensityItem = results.get(location);
				if (intensityItem == null)
					return null;

				Intensity cropIntensity = intensityItem.getIntensity(CropType.WHEAT);

				return cropIntensity == null ? 0 : cropIntensity.getFertiliserIntensity();
			}

			@Override
			public int convertToPixelValue(double value) {
Peter Alexander's avatar
Peter Alexander committed
				return (int) (value * 20) + 1;
			}	
		}.writeOutput(ModelConfig.WRITE_JPEG_IMAGES);

		outputAreas(year, cropAreaRaster, CropType.MAIZE); */
Peter Alexander's avatar
Peter Alexander committed
		outputLandCover(timestep.getYear(), cropAreaRaster, LandCoverType.CROPLAND);
		outputLandCover(timestep.getYear(), cropAreaRaster, LandCoverType.PASTURE); 
Peter Alexander's avatar
Peter Alexander committed
	}

Peter Alexander's avatar
Peter Alexander committed
	private void outputLandCover(int year, RasterSet<AreasItem> cropAreaRaster, final LandCoverType lcType) {
		new RasterOutputer<AreasItem>(cropAreaRaster, lcType.getName() + "Area" + year) {
			@Override
			public Double getValue(RasterKey location) {
				AreasItem area = results.get(location);
				if (area == null)
					return null;

Peter Alexander's avatar
Peter Alexander committed
				return area.getLandCoverArea(lcType);
			}

			@Override
			public int convertToPixelValue(double value) {
Peter Alexander's avatar
Peter Alexander committed
				return value > 0 ? 10 : 1;
			}	
		}.writeOutput(ModelConfig.WRITE_JPEG_IMAGES);
	}

	public Map<Country, List<RasterKey>> createCountryToKeysMap() {

Peter Alexander's avatar
Peter Alexander committed
		RasterSet<CountryBoundaryItem> countryBoundaries = new RasterSet<CountryBoundaryItem>(desiredProjection) {
			private static final long serialVersionUID = -8449000692429399253L;
			protected CountryBoundaryItem createRasterData() {
				return new CountryBoundaryItem();
			}
		};
Peter Alexander's avatar
Peter Alexander committed
		CountryBoundaryReader countryReader = new CountryBoundaryReader(countryBoundaries);
		countryReader.getRasterDataFromFile(ModelConfig.COUNTRY_BOUNDARY_FILE);
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
		Map<Country, List<RasterKey>> countryMap = new HashMap<Country, List<RasterKey>>();

		for (Map.Entry<RasterKey, CountryBoundaryItem> entry : countryBoundaries.entrySet()) {
Peter Alexander's avatar
Peter Alexander committed
			Country c = entry.getValue().getCountry();
			if (c == null)
				continue;
Peter Alexander's avatar
Peter Alexander committed
			List<RasterKey> keys = countryMap.get(c);
Peter Alexander's avatar
Peter Alexander committed

			if (keys == null) {
				keys = new ArrayList<RasterKey>();
Peter Alexander's avatar
Peter Alexander committed
				countryMap.put(c, keys);
			}
			keys.add(entry.getKey());
Peter Alexander's avatar
Peter Alexander committed
		}
Peter Alexander's avatar
Peter Alexander committed
		return countryMap;
Peter Alexander's avatar
Peter Alexander committed

Peter Alexander's avatar
Peter Alexander committed
	public Collection<CountryAgent> createCountryAgents() {
Peter Alexander's avatar
Peter Alexander committed
		Collection<CountryAgent> countryAgents = new HashSet<CountryAgent>();

		RasterSet<LandCoverItem> initLC = getInitialLandCover();
Peter Alexander's avatar
Peter Alexander committed
		RasterSet<IrrigationCostItem> allIrrigationCosts = getIrrigationCosts();
Peter Alexander's avatar
Peter Alexander committed
		
		Map<Country, Map<CropType, CropUsageData>> cropUsageDataMap = new CropUsageReader().getCommodityData();
Peter Alexander's avatar
Peter Alexander committed

		HashSet<String> countryExclusionList = new HashSet<String>(Arrays.asList("Bangladesh", "Portugal", "Haiti", "Myanmar")); //"French Polynesia", "Cabo Verde", "Samoa", "Saint Vincent and the Grenadines"));
Peter Alexander's avatar
Peter Alexander committed
		for (Map.Entry<Country, List<RasterKey>> entry : countryToKeysMap.entrySet()) {
			Country country = entry.getKey();
			List<RasterKey> keys = entry.getValue();
Peter Alexander's avatar
Peter Alexander committed
			// DEBUG code
Peter Alexander's avatar
Peter Alexander committed
	//		if (!(country.getCountryName().equals("United States of Americaxx") || country.getCountryName().equals("Russian Federationxx") || country.getCountryName().equals("China")) ) { //|| country.getCountryName().equals("China")
	//			continue;
	//		}
			if (demandManager.getPopulation(country, 2010) < 80 || countryExclusionList.contains(country.getCountryName())) {
Peter Alexander's avatar
Peter Alexander committed
				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);
Peter Alexander's avatar
Peter Alexander committed
			if (countryCommodityData == null) {
				LogWriter.printlnError("No commodities data for " +country + ", so skipping");
			}
			else if (initCountryLC.size() == 0) {
				LogWriter.printlnError("No initial land cover for " +country + ", so skipping");
			}
			else {
				CountryAgent ca = new CountryAgent(demandManager, country, initCountryLC, irrigationCosts, countryCommodityData);
				countryAgents.add(ca);
			}
Peter Alexander's avatar
Peter Alexander committed
		}

		return countryAgents;
Peter Alexander's avatar
Peter Alexander committed
	private RasterSet<LandCoverItem> getInitialLandCover() {
		LandCoverReader lcReader = new LandCoverReader(desiredProjection);
		RasterSet<LandCoverItem>  initLC = lcReader.getRasterDataFromFile(ModelConfig.INITAL_LAND_COVER_FILE);
Peter Alexander's avatar
Peter Alexander committed
		return initLC;
Peter Alexander's avatar
Peter Alexander committed
	}

	private YieldRaster getYieldSurfaces(Timestep timestep) {
		LPJYieldResponseMapReader yieldReader = new LPJYieldResponseMapReader(desiredProjection);
		return yieldReader.getRasterData(timestep); 
Peter Alexander's avatar
Peter Alexander committed
	}
Peter Alexander's avatar
Peter Alexander committed
	private RasterSet<IrrigationCostItem> getIrrigationCosts() {
Peter Alexander's avatar
Peter Alexander committed
		RasterSet<IrrigationCostItem> irigCosts = new RasterSet<IrrigationCostItem>(desiredProjection) {
			private static final long serialVersionUID = 8393130687550888654L;

			protected IrrigationCostItem createRasterData() {
				return new IrrigationCostItem();
			}
		};
Peter Alexander's avatar
Peter Alexander committed
		IrrigiationCostReader irigCostReader = new IrrigiationCostReader(irigCosts);
		irigCostReader.getRasterDataFromFile(ModelConfig.IRRIGATION_COST_FILE); 
Peter Alexander's avatar
Peter Alexander committed
		return irigCosts;
	}
Peter Alexander's avatar
Peter Alexander committed
}