Newer
Older
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;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ac.ed.lurg.country.CompositeCountry;
import ac.ed.lurg.country.CompositeCountryManager;
import ac.ed.lurg.country.CountryAgent;
import ac.ed.lurg.country.CountryBoundaryRaster;
import ac.ed.lurg.country.CountryBoundaryReader;
import ac.ed.lurg.country.GlobalPrice;
import ac.ed.lurg.demand.AbstractDemandManager;
import ac.ed.lurg.demand.BaseConsumpManager;
import ac.ed.lurg.demand.DemandManagerFromFile;
import ac.ed.lurg.demand.DemandManagerSSP;
import ac.ed.lurg.landuse.CropUsageData;
import ac.ed.lurg.landuse.FPUManager;
import ac.ed.lurg.landuse.IrrigationConstraintReader;
import ac.ed.lurg.landuse.IrrigationItem;
import ac.ed.lurg.landuse.IrrigationMaxAmountReader;
import ac.ed.lurg.landuse.IrrigationRasterSet;
import ac.ed.lurg.landuse.LandCoverItem;
import ac.ed.lurg.landuse.LandCoverReader;
import ac.ed.lurg.landuse.LandUseItem;
import ac.ed.lurg.landuse.ProtectedAreasReader;
import ac.ed.lurg.output.LandUseOutputer;
import ac.ed.lurg.output.LpjgOutputer;
import ac.ed.lurg.types.LandCoverType;
import ac.ed.lurg.utils.LogWriter;
import ac.ed.lurg.yield.LPJYieldResponseMapReader;
import ac.ed.lurg.yield.YieldRaster;
import ac.ed.lurg.yield.YieldResponsesItem;
import ac.sac.raster.IntegerRasterReader;
import ac.sac.raster.RasterKey;
import ac.sac.raster.RasterOutputer;
public class ModelMain {
private Collection<CountryAgent> countryAgents;
private CountryBoundaryRaster countryBoundaryRaster;
private AbstractDemandManager demandManager;
private CompositeCountryManager compositeCountryManager;
private Map<CropType, GlobalPrice> prevWorldPrices;
private RasterSet<LandUseItem> prevLandUseRaster;
private RasterSet<LandUseItem> initLU;
private IrrigationRasterSet currentIrrigationData;
private RasterSet<LandUseItem> globalLandUseRaster;
private RasterSet<IntegerRasterItem> clusterIdRaster;
ModelMain theModel = new ModelMain();
theModel.setup();
theModel.run();
}
/* setup models, reading inputs, etc. */
private void setup() {
desiredProjection = RasterHeaderDetails.getGlobalHeaderFromCellSize(ModelConfig.CELL_SIZE_X, ModelConfig.CELL_SIZE_Y, "999");
BaseConsumpManager baseConsumpManager = new BaseConsumpManager();
compositeCountryManager = new CompositeCountryManager(baseConsumpManager);
if (ModelConfig.DEMAND_FROM_FILE)
demandManager = new DemandManagerFromFile(compositeCountryManager);
else
demandManager = new DemandManagerSSP(ModelConfig.SSP_SCENARIO, baseConsumpManager, compositeCountryManager);
tradeManager = new TradeManager(compositeCountryManager);
countryBoundaryRaster = getCountryBoundaryRaster();
clusterIdRaster = ModelConfig.GENERATE_NEW_YIELD_CLUSTERS ? new RasterSet<IntegerRasterItem>(desiredProjection) : getClusterRaster();
initLU = getInitialLandUse();
countryAgents = createCountryAgents(compositeCountryManager.getAll());
globalLandUseRaster = new RasterSet<LandUseItem>(desiredProjection);
// in first timestep we don't have this info, but ok as constrained to
// import/export specified amount, values based on
// http://www.indexmundi.com/commodities/ for Jun 2010
prevWorldPrices = new HashMap<CropType, GlobalPrice>();
prevWorldPrices.put(CropType.WHEAT, GlobalPrice.createInitial(0.157 * ModelConfig.INITIAL_PRICE_SHIFT));
prevWorldPrices.put(CropType.MAIZE, GlobalPrice.createInitial(0.152 * ModelConfig.INITIAL_PRICE_SHIFT));
prevWorldPrices.put(CropType.RICE, GlobalPrice.createInitial(0.182 * ModelConfig.INITIAL_PRICE_SHIFT));
prevWorldPrices.put(CropType.OILCROPS, GlobalPrice.createInitial((0.820 * .4 + 0.314 * .6) * 0.5 * ModelConfig.INITIAL_PRICE_SHIFT));
prevWorldPrices.put(CropType.PULSES, GlobalPrice.createInitial(0.4 * ModelConfig.INITIAL_PRICE_SHIFT));
prevWorldPrices.put(CropType.STARCHY_ROOTS, GlobalPrice.createInitial(0.1 * ModelConfig.INITIAL_PRICE_SHIFT));
prevWorldPrices.put(CropType.MONOGASTRICS, GlobalPrice.createInitial(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)
prevWorldPrices.put(CropType.RUMINANTS, GlobalPrice.createInitial(0.1 * 0.6 * ModelConfig.INITIAL_PRICE_SHIFT)); // quantities is in feed equivalent term
prevWorldPrices.put(CropType.ENERGY_CROPS, GlobalPrice.createInitial(0.04 * ModelConfig.INITIAL_PRICE_SHIFT));
for (int i = ModelConfig.START_TIMESTEP; i <= ModelConfig.END_TIMESTEP; i++) {
Timestep timestep = new Timestep(i);
LpjgOutputer.writeMarkerFile(timestep.getYear(), true);
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
RasterSet<IrrigationItem> allIrrigData = getUpdateIrrigationData(timestep, yieldSurfaces);
YieldResponsesItem yresp = yieldSurfaces.getFromCoordinates(-90.5, 45.5);
LogWriter.printlnError("Test key: " + yresp.getYieldMax(CropType.MAIZE) + ", " + yresp.getYieldFertOnly(CropType.MAIZE) + ", "
+ yresp.getYieldIrrigOnly(CropType.MAIZE) + ", " + yresp.getYieldNone(CropType.MAIZE));
double previousGen2EcDDemand = timestep.isInitialTimestep() ? 0: demandManager.getSecondGenBioenergyDemand(timestep.getPreviousTimestep());
double gen2EcDDemand = demandManager.getSecondGenBioenergyDemand(timestep);
CropToDoubleMap totalImportCommodities = new CropToDoubleMap();
CropToDoubleMap totalExportCommodities = new CropToDoubleMap();
Collection<RasterKey> countryKeys = countryBoundaryRaster.getKeysFor(ca.getCountry());
YieldRaster countryYieldSurfaces = yieldSurfaces.createSubsetForKeys(countryKeys);
RasterSet<IrrigationItem> irrigData = allIrrigData.createSubsetForKeys(countryKeys);
result = ca.determineProduction(timestep, countryYieldSurfaces, irrigData, prevWorldPrices, (gen2EcDDemand - previousGen2EcDDemand));
LogWriter.printlnError("Exception processing " + ca.getCountry() + " will continue with other countries");
if (result == null) {
LogWriter.printlnError("No results for " + ca.getCountry());
continue;
}
// some hacky code for debug purposes that keeps each gams gdx file
// for one country
if (ModelConfig.GAMS_COUNTRY_TO_SAVE != null && ca.getCountry().getName().equals(ModelConfig.GAMS_COUNTRY_TO_SAVE)) {
FileSystems.getDefault().getPath(ModelConfig.TEMP_DIR + File.separator + "_gams_java_gdb1.gdx"),
FileSystems.getDefault().getPath(ModelConfig.TEMP_DIR + File.separator + ModelConfig.GAMS_COUNTRY_TO_SAVE + timestep.getYear() + ".gdx"),
globalLandUseRaster.putAll(result.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());
// 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);
// energycrops are a special case where demand in global and exogenously specified
totalImportCommodities.incrementValue(CropType.ENERGY_CROPS, gen2EcDDemand);
// Look at trade balance and adjust appropriately
for (CropType crop : CropType.getImportedTypes()) {
GlobalPrice prevPrice = prevWorldPrices.get(crop);
double imports = totalImportCommodities.containsKey(crop) ? totalImportCommodities.get(crop) : 0.0;
double exports = totalExportCommodities.containsKey(crop) ? totalExportCommodities.get(crop) * (1.0 - ModelConfig.TRANSPORT_LOSSES) : 0.0;
GlobalPrice adjustedPrice = prevPrice.createWithUpdatedMarketPrices(imports, exports, (ModelConfig.MARKET_ADJ_PRICE));
LogWriter.println( String.format("Price for %s updated from %s (imports amount %.0f, exports amount %.0f) to %s ",
prevWorldPrices.put(crop, adjustedPrice);
LogWriter.println(String.format("Global stocks for %s updated from %s to %s ", crop.getGamsName(), previousStockLevel, updatedStockLevel));
LogWriter.println(String.format("Global stocks for %s is below zero ", crop.getGamsName(), previousStockLevel));
outputTimestepResults(timestep, globalLandUseRaster, yieldSurfaces);
prevLandUseRaster = globalLandUseRaster;
private BufferedWriter getFileWriter(Timestep timestep, String file, String columnHeadings) throws IOException {
if (timestep.isInitialTimestep()) {
BufferedWriter outputFile = new BufferedWriter(fstream);
outputFile.write(columnHeadings);
outputFile.newLine();
return outputFile;
return new BufferedWriter(fstream);
}
}
private void writeLandCoverFile(Timestep timestep, RasterSet<LandUseItem> landUseRaster) {
StringBuffer sbHeadings = new StringBuffer("Year,Cropland,Pasture,ManForest,UnmanForest,Natural,EnergyCrop,FertCrop,IrrigCrop");
BufferedWriter outputFile = getFileWriter(timestep, ModelConfig.LAND_COVER_OUTPUT_FILE, sbHeadings.toString());
StringBuffer sbData = new StringBuffer();
sbData.append(String.format("%d,%.1f,%.1f,%.1f,%.1f,%.1f", timestep.getYear(),
LandUseItem.getTotalLandCover(landUseRaster.values(), LandCoverType.CROPLAND),
LandUseItem.getTotalLandCover(landUseRaster.values(), LandCoverType.PASTURE),
Peter Alexander
committed
LandUseItem.getTotalLandCover(landUseRaster.values(), LandCoverType.MANAGED_FOREST),
LandUseItem.getTotalLandCover(landUseRaster.values(), LandCoverType.UNMANAGED_FOREST),
LandUseItem.getTotalLandCover(landUseRaster.values(), LandCoverType.OTHER_NATURAL)));
sbData.append(String.format(",%.1f", LandUseItem.getTotalCropArea(landUseRaster.values(), CropType.ENERGY_CROPS)));
sbData.append(String.format(",%.1f", LandUseItem.getFertiliserTotal(landUseRaster.values(), CropType.getCropsLessPasture()) / 1000));
sbData.append(String.format(",%.1f", LandUseItem.getIrrigationTotal(landUseRaster.values(), CropType.getCropsLessPasture())));
outputFile.write(sbData.toString());
outputFile.newLine();
outputFile.close();
private void writeGlobalMarketFile(Timestep timestep) {
try {
StringBuffer sbHeadings = new StringBuffer(
"Year,Crop,Imports (Mt),Exports (Mt),New export price, Stock Levels (Mt)");
BufferedWriter outputFile = getFileWriter(timestep, ModelConfig.PRICES_OUTPUT_FILE, sbHeadings.toString());
StringBuffer sbData = new StringBuffer();
sbData.append(String.format("%d,%s", timestep.getYear(), crop.getGamsName()));
sbData.append(String.format(",%.1f,%.1f", prevWorldPrices.get(crop).getImportAmount(), prevWorldPrices.get(crop).getExportAmount()));
sbData.append(String.format(",%.3f,%.3f", prevWorldPrices.get(crop).getExportPrice(), prevStockLevel.get(crop)));
outputFile.write(sbData.toString());
outputFile.newLine();
}
private void writeDemandFile(Timestep timestep) {
try {
StringBuffer sbHeadings = new StringBuffer("Year,Commodity,Amount (Mt)");
BufferedWriter outputFile = getFileWriter(timestep, ModelConfig.DEMAND_OUTPUT_FILE, sbHeadings.toString());
for (CountryAgent country : countryAgents) {
Double d = country.getCurrentProjectedDemand().get(comm);
LogWriter.println(String.format("%s,%s,%.4f", country.getCountry(), comm.getGamsName(), d));
}
sbData.append(String.format("%d,%s", timestep.getYear(), comm.getGamsName()));
sbData.append(String.format(",%.1f", demandAmount));
LogWriter.println("Global demand " + timestep.getYear() + " " + comm.getGamsName() + " " + demandAmount + "\n");
outputFile.write(sbData.toString());
outputFile.newLine();
}
outputFile.close();
private void outputTimestepResults(Timestep timestep, RasterSet<LandUseItem> landUseRaster, YieldRaster yieldSurfaces) {
writeLandCoverFile(timestep, landUseRaster);
writeGlobalMarketFile(timestep);
if (ModelConfig.OUTPUT_FOR_LPJG) {
for (int outputYear : timestep.getYearsFromLast()) {
LogWriter.printlnError("Outputing Year: " + outputYear);
RasterSet<LandUseItem> landUseToOutput = null;
landUseToOutput = landUseRaster;
}
else if (ModelConfig.INTERPOLATE_OUTPUT_YEARS) {
InterpolatingRasterSet<LandUseItem> intermediateLandUse = new InterpolatingRasterSet<LandUseItem>( landUseRaster.getHeaderDetails()) {
private static final long serialVersionUID = 1306045141011047760L;
protected LandUseItem createRasterData() {
return new LandUseItem();
intermediateLandUse.setup(prevLandUseRaster, landUseRaster, timestep.getPreviousTimestep().getYear(), timestep.getYear(), outputYear);
landUseToOutput = intermediateLandUse;
if (landUseToOutput != null) {
LpjgOutputer lpjOutputer = new LpjgOutputer(outputYear, landUseToOutput, yieldSurfaces);
lpjOutputer.writeOutput();
}
if (ModelConfig.IS_CALIBRATION_RUN)
if (timestep.isInitialTimestep()) {
if (ModelConfig.GENERATE_NEW_YIELD_CLUSTERS)
outputClusters(clusterIdRaster);
outputWaterAvailablity(currentIrrigationData);
// Output LandUses to tabular file, for analysis (perhaps)
LogWriter.println("Outputing land uses Year: " + timestep.getYear());
LandUseOutputer landuseOutputer = new LandUseOutputer(timestep.getYear(), landUseRaster);
landuseOutputer.writeOutput();
// don't really need this a LPJ outputs have same data, although in a slightly different format
// outputLandCover(timestep.getYear(), landUseRaster, LandCoverType.CROPLAND);
// outputLandCover(timestep.getYear(), landUseRaster, LandCoverType.PASTURE);
private void outputWaterAvailablity(IrrigationRasterSet irrigiationRS) {
new RasterOutputer<Double, IrrigationItem>(irrigiationRS, ModelConfig.OUTPUT_DIR + File.separator + "irrig_constraint.asc") {
@Override
public Double getValue(RasterKey location) {
IrrigationItem item = results.get(location);
if (item == null)
return null;
return item.getIrrigConstraint();
}
}.writeOutput();
}
private void outputClusters(RasterSet<IntegerRasterItem> landUseRaster) {
new RasterOutputer<Integer, IntegerRasterItem>(landUseRaster, ModelConfig.CLUSTERED_YIELD_FILE) {
public Integer getValue(RasterKey location) {
IntegerRasterItem item = results.get(location);
}.writeOutput();
public RasterSet<IntegerRasterItem> getClusterRaster() {
RasterSet<IntegerRasterItem> clusters = new RasterSet<IntegerRasterItem>(desiredProjection) {
private static final long serialVersionUID = 2467452274591854417L;
@Override
protected IntegerRasterItem createRasterData() {
return new IntegerRasterItem(0);
}
};
IntegerRasterReader clusterReader = new IntegerRasterReader(clusters);
clusterReader.getRasterDataFromFile(ModelConfig.CLUSTERED_YIELD_FILE);
return clusters;
}
public CountryBoundaryRaster getCountryBoundaryRaster() {
CountryBoundaryRaster countryBoundaries = new CountryBoundaryRaster(desiredProjection, compositeCountryManager);
CountryBoundaryReader countryReader = new CountryBoundaryReader(countryBoundaries);
countryReader.getRasterDataFromFile(ModelConfig.COUNTRY_BOUNDARY_FILE);
public Collection<CountryAgent> createCountryAgents(Collection<CompositeCountry> countryGrouping) {
Collection<CountryAgent> countryAgents = new HashSet<CountryAgent>();
Map<CompositeCountry, Map<CropType, CropUsageData>> cropUsageDataMap = new CropUsageReader(compositeCountryManager).getCommodityData();
for (CompositeCountry cc : countryGrouping) {
if (!(cc.getName().equals(ModelConfig.DEBUG_COUNTRY_NAME)))
List<RasterKey> keys = countryBoundaryRaster.getKeysFor(cc);
Map<CropType, CropUsageData> countryCommodityData = cropUsageDataMap.get(cc);
Map<CropType, Double> countryTradeBarriers = tradeManager.getTradeBarriers(cc);
LogWriter.printlnError("No commodities data for " + cc + ", so skipping");
RasterSet<LandUseItem> initCountryLandUse = initLU.createSubsetForKeys(keys);
RasterSet<IntegerRasterItem> yieldClusters = ModelConfig.GENERATE_NEW_YIELD_CLUSTERS ? null : clusterIdRaster.createSubsetForKeys(keys);
if (initCountryLandUse.size() == 0) {
LogWriter.printlnError("No initial land use for " + cc + ", so skipping");
CountryAgent ca = new CountryAgent(demandManager, cc, initCountryLandUse, countryCommodityData, countryTradeBarriers, yieldClusters);
private RasterSet<LandUseItem> getInitialLandUse() {
if (ModelConfig.IS_CALIBRATION_RUN)
return getLandUseFromBaseline();
else
return deserializeLandUse();
}
private void serializeLandUse(RasterSet<LandUseItem> landUseRaster) {
try {
LogWriter.println("Starting serializing LandUse to " + ModelConfig.SERIALIZED_LAND_USE_FILE);
FileOutputStream fileOut = new FileOutputStream(ModelConfig.SERIALIZED_LAND_USE_FILE);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(landUseRaster);
out.close();
fileOut.close();
LogWriter.println("Serialized data is saved");
@SuppressWarnings("unchecked")
private RasterSet<LandUseItem> deserializeLandUse() {
try {
RasterSet<LandUseItem> initLU;
FileInputStream fileIn = new FileInputStream(ModelConfig.SERIALIZED_LAND_USE_FILE);
ObjectInputStream in = new ObjectInputStream(fileIn);
initLU = (RasterSet<LandUseItem>) in.readObject();
in.close();
fileIn.close();
LogWriter.println("Deserialized " + ModelConfig.SERIALIZED_LAND_USE_FILE);
return initLU;
LogWriter.printlnError("Problem deserializing " + ModelConfig.SERIALIZED_LAND_USE_FILE);
LogWriter.print(i);
return null;
LogWriter.printlnError("RasterSet<LandUseItem> class not found");
c.printStackTrace();
return null;
}
/** this is if we are starting from Hurtt of other initial land covers (so we don't have land uses and intensity data) */
private RasterSet<LandUseItem> getLandUseFromBaseline() {
RasterSet<LandCoverItem> initialLC = new RasterSet<LandCoverItem>(desiredProjection) {
private static final long serialVersionUID = 4642550777741425501L;
protected LandCoverItem createRasterData() {
return new LandCoverItem();
}
new ProtectedAreasReader(initialLC).getRasterDataFromFile(ModelConfig.PROTECTED_AREAS_FILE);
new MaxCropAreaReader(initialLC).getRasterDataFromFile(ModelConfig.HIGH_SLOPE_AREAS_FILE);
new LandCoverReader(initialLC).getRasterDataFromFile(ModelConfig.INITAL_LAND_COVER_FILE);
RasterSet<LandUseItem> landUseRaster = new RasterSet<LandUseItem>(initialLC.getHeaderDetails());
for (Map.Entry<RasterKey, LandCoverItem> entry : initialLC.entrySet()) {
LandUseItem areasItem = new LandUseItem();
RasterKey key = entry.getKey();
LandCoverItem landCover = entry.getValue();
areasItem.setLandCoverAreas(landCover);
areasItem.setCropFraction(CropType.WHEAT, 0.5); // random start as don't have better data
areasItem.setCropFraction(CropType.MAIZE, 0.5);
areasItem.setProtectedArea(landCover.getProtectedArea());
landUseRaster.put(key, areasItem);
}
private YieldRaster getYieldSurfaces(Timestep timestep) {
LPJYieldResponseMapReader yieldReader = new LPJYieldResponseMapReader(desiredProjection);
private IrrigationRasterSet getFixedIrrigationData() {
IrrigationRasterSet fixedIrrigData = new IrrigationRasterSet(desiredProjection, fpuManager);
new IrrigiationCostReader(fixedIrrigData).getRasterDataFromFile(ModelConfig.IRRIGATION_COST_FILE);
if (ModelConfig.USE_BLUE_WATER_FILE_IRRIG_CONSTRAINT)
new IrrigationConstraintReader(fixedIrrigData).getRasterDataFromFile(ModelConfig.IRRIGATION_CONSTRAINT_FILE);
private RasterSet<IrrigationItem> getUpdateIrrigationData(Timestep timestep, YieldRaster yieldSurfaces) {
String rootDir = timestep.getYearSubDir(ModelConfig.YIELD_DIR);
new IrrigationMaxAmountReader(currentIrrigationData, yieldSurfaces).getRasterDataFromFile(rootDir + File.separator + ModelConfig.IRRIG_MAX_WATER_FILENAME);
if (!ModelConfig.USE_BLUE_WATER_FILE_IRRIG_CONSTRAINT) {
new RunOffReader(currentIrrigationData).getRasterDataFromFile(rootDir + File.separator + ModelConfig.IRRIG_RUNOFF_FILE);
currentIrrigationData.updateConstraintByFPU(timestep, initLU);
return currentIrrigationData;
}
Map<CropType, Double> initialStockLevels = new StockReader().read();
initialStockLevels.put(CropType.ENERGY_CROPS, 0.0);