diff --git a/GAMS/IntExtOpt.gms b/GAMS/IntExtOpt.gms index 3efab21ee58b162991fbefeea1476fc87b6ff735..ead74f42e962410f55785204c2cb330cac49d2a4 100644 --- a/GAMS/IntExtOpt.gms +++ b/GAMS/IntExtOpt.gms @@ -361,16 +361,14 @@ $gdxin - sum((crop, farming_type, location), cropArea(crop, farming_type, location) * unitCost(crop, farming_type, location) * (1 - subsidyRate(crop))) * Cost of animal production - sum(animal, animalProdCost(animal) * totalProduction(animal) * (1 - subsidyRate(animal))) -* Cost of feed imports +* Cost of imports - sum(import_types, importPrices(import_types) * importAmount(import_types)) * Cost of wood production - sum(location, forestManagementCost * rotationIntensity(location) * landCoverArea('timberForest', 'unprotected', location)) * Cost of solar energy - sum((solar_land, location), solarCostRate(solar_land, location) * landCoverArea(solar_land, 'unprotected', location)) * Land cover conversion costs - - sum(location, totalConversionCost(location)) -* Value of carbon credits - + sum(location, carbonCredits(location)) + - sum(location, totalConversionCost(location)) * Reforestation cost - sum((location, land_cover)$[not sameAs(land_cover, 'carbonForest')], landCoverChange(land_cover, 'carbonForest', 'unprotected', location) * forestManagementCost) * Crop monoculture penalty. Derived from Simpson's diversity index, weighted by production diff --git a/data/carbon_options.csv b/data/carbon_options.csv index ac5ee9a9465b6c0193d6cbec07e6312e20fc0b77..36b1e57b145cbbb6ecc63e3fe8d2e0de5d7a8117 100644 --- a/data/carbon_options.csv +++ b/data/carbon_options.csv @@ -1,26 +1,50 @@ From,To,Enabled +agrivoltaics,agrivoltaics,FALSE +agrivoltaics,carbonForest,FALSE +agrivoltaics,cropland,FALSE +agrivoltaics,natural,FALSE +agrivoltaics,pasture,FALSE +agrivoltaics,photovoltaics,FALSE +agrivoltaics,timberForest,FALSE +carbonForest,agrivoltaics,FALSE carbonForest,carbonForest,FALSE carbonForest,cropland,FALSE carbonForest,natural,FALSE carbonForest,pasture,FALSE +carbonForest,photovoltaics,FALSE carbonForest,timberForest,FALSE +cropland,agrivoltaics,FALSE cropland,carbonForest,TRUE cropland,cropland,FALSE cropland,natural,FALSE cropland,pasture,FALSE +cropland,photovoltaics,FALSE cropland,timberForest,FALSE +natural,agrivoltaics,FALSE natural,carbonForest,FALSE natural,cropland,FALSE natural,natural,FALSE natural,pasture,FALSE +natural,photovoltaics,FALSE natural,timberForest,FALSE +pasture,agrivoltaics,FALSE pasture,carbonForest,TRUE pasture,cropland,FALSE pasture,natural,FALSE pasture,pasture,FALSE +pasture,photovoltaics,FALSE pasture,timberForest,FALSE +photovoltaics,agrivoltaics,FALSE +photovoltaics,carbonForest,FALSE +photovoltaics,cropland,FALSE +photovoltaics,natural,FALSE +photovoltaics,pasture,FALSE +photovoltaics,photovoltaics,FALSE +photovoltaics,timberForest,FALSE +timberForest,agrivoltaics,FALSE timberForest,carbonForest,FALSE timberForest,cropland,FALSE timberForest,natural,FALSE timberForest,pasture,FALSE +timberForest,photovoltaics,FALSE timberForest,timberForest,FALSE \ No newline at end of file diff --git a/src/ac/ed/lurg/ModelConfig.java b/src/ac/ed/lurg/ModelConfig.java index 469d52fc3b8734ba070a2bae8a73f9ff7f0a6081..318107754a4e36783e76235eb5ec19c94d1489d7 100755 --- a/src/ac/ed/lurg/ModelConfig.java +++ b/src/ac/ed/lurg/ModelConfig.java @@ -575,13 +575,13 @@ public class ModelConfig { public static final boolean IS_CARBON_ON = !IS_CALIBRATION_RUN && getBooleanProperty("IS_CARBON_ON", false); 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 int CARBON_HORIZON = getIntProperty("CARBON_HORIZON", 30); // time period for calculating carbon credits - public static final double INIT_CARBON_PRICE = IS_CARBON_ON ? getDoubleProperty("INIT_CARBON_PRICE", 0.03) : 0.0; // $1000/tC-eq + public static final int CARBON_HORIZON = getIntProperty("CARBON_HORIZON", 60); // time period for calculating carbon credits + public static final double INIT_CARBON_PRICE = IS_CARBON_ON ? getDoubleProperty("INIT_CARBON_PRICE", 0.005) : 0.0; // $1000/tC-eq public static final double INIT_CARBON_STOCK = getDoubleProperty("INIT_CARBON_STOCK", 100.0); // MtC-eq public static final String CARBON_OPTIONS_FILENAME = getProperty("CARBON_OPTIONS_FILENAME", "carbon_options.csv"); // config for what is included in carbon market public static final String CARBON_OPTIONS_FILE = getProperty("CARBON_OPTIONS_FILE", DATA_DIR + File.separator + CARBON_OPTIONS_FILENAME); public static final double CARBON_FOREST_MAX_PROPORTION = getDoubleProperty("CARBON_FOREST_MAX_PROPORTION", 1.0); // maximum proportion of land cover as carbon forest - public static final double CARBON_TRADE_ADJ_COST_MULTIPLIER = getDoubleProperty("CARBON_TRADE_ADJ_COST_MULTIPLIER", 0.3); // No physical goods traded so can have lower cost + public static final double CARBON_TRADE_ADJ_COST_MULTIPLIER = getDoubleProperty("CARBON_TRADE_ADJ_COST_MULTIPLIER", 0.0); // No physical goods traded so can have lower cost // How demand is allocated. Options: global (countries can export carbon credits to market), country (global demand allocated by GDP), price (no demand, exogenous price) public static final String CARBON_DEMAND_METHOD = getProperty("CARBON_DEMAND_METHOD", "global"); diff --git a/src/ac/ed/lurg/carbon/CarbonFluxReader.java b/src/ac/ed/lurg/carbon/CarbonFluxReader.java index 0b53283b23d076da5f60229401b2ffb99aeae4f1..b20af94a5f982b02dd1deb86d592963249b71522 100644 --- a/src/ac/ed/lurg/carbon/CarbonFluxReader.java +++ b/src/ac/ed/lurg/carbon/CarbonFluxReader.java @@ -20,7 +20,7 @@ import ac.sac.raster.RasterKey; import ac.sac.raster.RasterSet; public class CarbonFluxReader { - private static final double CONVERSION_FACTOR = 10.0; // convert kgC/m2 to tC/ha + private static final double CONVERSION_FACTOR = 10.0 * 44.0/12.0; // convert kgC/m2 to tCO2-eq/ha private final RasterHeaderDetails rasterProj; private int modelYear; private Map<Integer, RasterKey> keyMap; diff --git a/src/ac/ed/lurg/country/CountryAgent.java b/src/ac/ed/lurg/country/CountryAgent.java index 1fc62f446fb22b1500ecbada3b427bc3e71d6414..5238f69a78f0cdb4da1fc3a95953636caaf43468 100644 --- a/src/ac/ed/lurg/country/CountryAgent.java +++ b/src/ac/ed/lurg/country/CountryAgent.java @@ -228,9 +228,16 @@ public class CountryAgent extends AbstractCountryAgent { double currentDemand = getCurrentCarbonDemand(); double prevDemand = carbonUsageData.getCarbonCredits() + carbonUsageData.getNetCarbonImport(); + double maxNetImport, minNetImport; double change = Math.max(ModelConfig.MAX_IMPORT_CHANGE * maxOfProdOrSupply, 1); // max of 1 otherwise if only importing then can never export - double minNetImport = currentDemand < baseTrade ? currentDemand * 0.95 : baseTrade - change; // min imports can't be lower than demand - double maxNetImport = Math.max(baseTrade + change, baseTrade + currentDemand - prevDemand); // increase in demand can be imported + + if (ModelConfig.CARBON_DEMAND_METHOD.equals("country")) { + minNetImport = currentDemand < baseTrade ? currentDemand * 0.95 : baseTrade - change; // min imports can't be lower than demand + maxNetImport = Math.max(baseTrade + change, baseTrade + currentDemand - prevDemand); // increase in demand can be imported + } else { + minNetImport = baseTrade - change; + maxNetImport = baseTrade + change; + } carbonTradeConstraint = new TradeConstraint(minNetImport, maxNetImport); @@ -259,7 +266,8 @@ public class CountryAgent extends AbstractCountryAgent { // Calibrate parameters GamsCountryInput countryLevelInputs = new GamsCountryInput(country, getTotalDemand(), currentCountryPrices, importConstraints, - previousGamsRasterOutput.getCropUsageData(), subsidyRates, currentCarbonDemand, currentSolarDemand, currentCarbonPrice, carbonTradeConstraint, + previousGamsRasterOutput.getCropUsageData(), subsidyRates, currentCarbonDemand, currentSolarDemand, + currentCarbonPrice, carbonTradeConstraint, previousGamsRasterOutput.getCarbonUsageData(), getTotalWoodDemand(), currentWoodPrice, woodTradeConstraint, previousGamsRasterOutput.getWoodUsageData(), demandManager.getDiscountRate(country, currentTimestep.getYear())); diff --git a/src/ac/ed/lurg/country/gams/GamsCountryInput.java b/src/ac/ed/lurg/country/gams/GamsCountryInput.java index 2fb58ad2130c0779afb3beb1854b44710e0ba463..8b9fd4e4103383e5f574fb36a203f7a0a1674385 100644 --- a/src/ac/ed/lurg/country/gams/GamsCountryInput.java +++ b/src/ac/ed/lurg/country/gams/GamsCountryInput.java @@ -6,6 +6,7 @@ import java.util.Map; import ac.ed.lurg.country.CompositeCountry; import ac.ed.lurg.country.CountryPrice; import ac.ed.lurg.country.TradeConstraint; +import ac.ed.lurg.landuse.CarbonUsageData; import ac.ed.lurg.landuse.CropUsageData; import ac.ed.lurg.landuse.WoodUsageData; import ac.ed.lurg.types.CropType; @@ -25,6 +26,7 @@ public class GamsCountryInput { private Map<LandCoverType, Double> solarDemand; // TWh private CountryPrice carbonPrice; private TradeConstraint carbonTradeConstraint; + private CarbonUsageData previousCarbonUsage; private double woodDemand; private CountryPrice woodPrice; private TradeConstraint woodTradeConstraint; @@ -33,7 +35,8 @@ public class GamsCountryInput { public GamsCountryInput(CompositeCountry country, Map<CropType, Double> projectedDemand, Map<CropType, CountryPrice> countryPrices, Map<CropType, TradeConstraint> importConstraints, Map<CropType, CropUsageData> previousCropUsageData, - Map<CropType, Double> subsidyRates, double carbonDemand, Map<LandCoverType, Double> solarDemand, CountryPrice carbonPrice, TradeConstraint carbonTradeConstraint, + Map<CropType, Double> subsidyRates, double carbonDemand, Map<LandCoverType, Double> solarDemand, + CountryPrice carbonPrice, TradeConstraint carbonTradeConstraint, CarbonUsageData previousCarbonUsage, double woodDemand, CountryPrice woodPrice, TradeConstraint woodTradeConstraint, WoodUsageData previousWoodUsageData, double discountRate) { @@ -45,6 +48,7 @@ public class GamsCountryInput { this.previousCropUsageData = previousCropUsageData; this.subsidyRates = subsidyRates; this.carbonDemand = carbonDemand; + this.previousCarbonUsage = previousCarbonUsage; this.solarDemand = solarDemand; this.carbonPrice = carbonPrice; this.carbonTradeConstraint = carbonTradeConstraint; @@ -111,6 +115,10 @@ public class GamsCountryInput { return carbonTradeConstraint; } + public CarbonUsageData getPreviousCarbonUsage() { + return previousCarbonUsage; + } + public double getWoodDemand() { return woodDemand; } diff --git a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java index 6706f45090da6b90a3eaa9c699818b39d36c9954..4cad540f46cfb82c119d59a4c845f2c71ab03a9b 100644 --- a/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java +++ b/src/ac/ed/lurg/country/gams/GamsLocationOptimiser.java @@ -483,6 +483,10 @@ public class GamsLocationOptimiser { setGamsParamValue(minTradeP.addRecord("carbonCredits"), carbonTradeConstraint.getMinConstraint(), -1); setGamsParamValue(maxTradeP.addRecord("carbonCredits"), carbonTradeConstraint.getMaxConstraint(), -1); + double prevCarbonNetImport = countryInput.getPreviousCarbonUsage().getNetCarbonImport(); + setGamsParamValue(previousImportAmountP.addRecord("carbonCredits"), Math.max(0, prevCarbonNetImport), -1); + setGamsParamValue(previousExportAmountP.addRecord("carbonCredits"), Math.max(0, -prevCarbonNetImport), -1); + addScalar(inDB, "carbonForestMaxProportion", ModelConfig.CARBON_FOREST_MAX_PROPORTION, -1); GAMSParameter cFluxCreditRateP = inDB.addParameter("carbonCreditRate", 3);