def get_constraints(m: AbstractModel) -> Sequence[GeneralConstraint]: """Utility and welfare equations Necessary variables: m.utility m.welfare Returns: list of constraints (any of: - GlobalConstraint - GlobalInitConstraint - RegionalConstraint - RegionalInitConstraint ) """ constraints = [] # Parameters m.elasmu = Param() m.inequal_aversion = Param() m.utility = Var(m.t, m.regions, initialize=10) m.yearly_welfare = Var(m.t) constraints.extend([ RegionalConstraint( lambda m, t, r: m.utility[t, r] == m.consumption[t, r] / m.L( m.year(t), r), "utility", ), GlobalConstraint( lambda m, t: m.yearly_welfare[t] == sum( m.L(m.year(t), r) for r in m.regions) * calc_utility( sum(m.consumption[t, r] for r in m.regions), sum(m.L(m.year(t), r) for r in m.regions), m.elasmu, ), "yearly_welfare", ), ]) return constraints
def get_constraints( m: AbstractModel) -> Tuple[Objective, Sequence[GeneralConstraint]]: """Equations and constraints for the objective of the optimisation (utility specification) Necessary variables: - Returns: - Objective - list of constraints (any of: - GlobalConstraint - GlobalInitConstraint - RegionalConstraint - RegionalInitConstraint ) """ constraints = [] m.NPV = Var(m.t) m.PRTP = Param() constraints.extend([ GlobalConstraint( lambda m, t: m.NPV[t] == m.NPV[t - 1] + m.dt * exp(-m.PRTP * ( m.year(t) - m.beginyear)) * sum( m.L(m.year(t), r) * m.utility[t, r] for r in m.regions) if t > 0 else Constraint.Skip, name="NPV", ), GlobalInitConstraint(lambda m: m.NPV[0] == 0), ]) ## If carbon budget is a soft constraint (not in use now): # m.obj = Objective(rule=lambda m: m.NPV[m.tf] * ( # soft_switch(m.budget-( # m.cumulative_emissions[m.year2100] # + sum(soft_min(m.global_emissions[t]) for t in m.t if m.year(t) >= 2100) # ), scale=1) # ), sense=maximize) objective = Objective(rule=lambda m: m.NPV[m.tf], sense=maximize) return objective, constraints
def get_constraints( m: AbstractModel) -> Tuple[Objective, Sequence[GeneralConstraint]]: """Equations and constraints for the objective of the optimisation (global costs specification) Necessary variables: Returns: - Objective - list of constraints (any of: - GlobalConstraint - GlobalInitConstraint - RegionalConstraint - RegionalInitConstraint ) """ constraints = [] m.NPV = Var(m.t) m.PRTP = Param() constraints.extend([ GlobalConstraint( lambda m, t: m.NPV[t] == m.NPV[t - 1] + m.dt * exp(-m.PRTP * ( m.year(t) - m.beginyear)) * (sum(m.abatement_costs[t, r] for r in m.regions) + sum( m.damage_costs[t, r] * m.GDP_gross[t, r] for r in m.regions)) if t > 0 else Constraint.Skip, name="NPV", ), GlobalInitConstraint(lambda m: m.NPV[0] == 0), ]) objective = Objective(rule=lambda m: m.NPV[m.tf], sense=minimize) return objective, constraints
def get_constraints(m: AbstractModel) -> Sequence[GeneralConstraint]: """Emissions and temperature equations and constraints Necessary variables: m.relative_abatement m.cumulative_emissions m.T0 m.temperature Returns: list of constraints (any of: - GlobalConstraint - GlobalInitConstraint - RegionalConstraint - RegionalInitConstraint ) """ constraints = [] m.regional_emissions = Var(m.t, m.regions) m.baseline = Var(m.t, m.regions) m.baseline_carbon_intensity = Param() m.relative_abatement = Var(m.t, m.regions, initialize=0, bounds=(0, 2)) m.cumulative_emissions = Var(m.t) m.global_emissions = Var(m.t) constraints.extend([ # Baseline emissions based on emissions or carbon intensity RegionalConstraint( lambda m, t, r: (m.baseline[t, r] == m.carbon_intensity( m.year(t), r) * m.GDP_net[t, r]) if value(m.baseline_carbon_intensity) else (m.baseline[t, r] == m.baseline_emissions(m.year(t), r)), name="baseline_emissions", ), # Regional emissions from baseline and relative abatement RegionalConstraint( lambda m, t, r: m.regional_emissions[t, r] == (1 - m.relative_abatement[t, r]) * m.baseline_emissions( m.year(t), r), "regional_abatement", ), RegionalInitConstraint(lambda m, r: m.regional_emissions[0, r] == m. baseline_emissions(m.year(0), r)), # Global emissions (sum from regional emissions) GlobalConstraint( lambda m, t: m.global_emissions[t] == sum( m.regional_emissions[t, r] for r in m.regions), "global_emissions", ), GlobalInitConstraint( lambda m: m.global_emissions[0] == sum( m.baseline_emissions(m.year(0), r) for r in m.regions), "global_emissions_init", ), # Cumulative global emissions GlobalConstraint( lambda m, t: m.cumulative_emissions[t] == m.cumulative_emissions[ t - 1] + m.dt * m.global_emissions[t] if t > 0 else Constraint.Skip, "cumulative_emissions", ), GlobalInitConstraint(lambda m: m.cumulative_emissions[0] == 0), ]) m.T0 = Param() m.temperature = Var(m.t, initialize=lambda m, t: m.T0) m.TCRE = Param() m.temperature_target = Param() constraints.extend([ GlobalConstraint( lambda m, t: m.temperature[t] == m.T0 + m.TCRE * m. cumulative_emissions[t], "temperature", ), GlobalInitConstraint(lambda m: m.temperature[0] == m.T0), GlobalConstraint( lambda m, t: m.temperature[t] <= m.temperature_target if (m.year(t) >= 2100 and value(m.temperature_target) is not False) else Constraint.Skip, name="temperature_target", ), ]) m.perc_reversible_damages = Param() # m.overshoot = Var(m.t, initialize=0) # m.overshootdot = DerivativeVar(m.overshoot, wrt=m.t) # m.netnegative_emissions = Var(m.t) # global_constraints.extend( # [ # lambda m, t: m.netnegative_emissions[t] # == m.global_emissions[t] * (1 - tanh(m.global_emissions[t] * 10)) / 2 # if value(m.perc_reversible_damages) < 1 # else Constraint.Skip, # lambda m, t: m.overshootdot[t] # == (m.netnegative_emissions[t] if t <= value(m.year2100) and t > 0 else 0) # if value(m.perc_reversible_damages) < 1 # else Constraint.Skip, # ] # ) # global_constraints_init.extend([lambda m: m.overshoot[0] == 0]) # Emission constraints m.budget = Param() m.inertia_global = Param() m.inertia_regional = Param() m.global_min_level = Param() m.regional_min_level = Param() m.no_pos_emissions_after_budget_year = Param() constraints.extend([ # Carbon budget constraints: GlobalConstraint( lambda m, t: m.cumulative_emissions[t] - (m.budget + (m.overshoot[t] * (1 - m.perc_reversible_damages) if value(m.perc_reversible_damages) < 1 else 0)) <= 0 if (m.year(t) >= 2100 and value(m.budget) is not False ) else Constraint.Skip, name="carbon_budget", ), GlobalConstraint( lambda m, t: m.global_emissions[t] <= 0 if (m.year(t) >= 2100 and value(m.no_pos_emissions_after_budget_year) is True and value(m.budget) is not False) else Constraint.Skip, name="net_zero_after_2100", ), GlobalConstraint(lambda m, t: m.cumulative_emissions[t] >= 0), # Global and regional inertia constraints: GlobalConstraint( lambda m, t: m.global_emissions[t] - m.global_emissions[t - 1] >= m .dt * m.inertia_global * sum( m.baseline_emissions(m.year(0), r) for r in m.regions) if value(m.inertia_global ) is not False and t > 0 else Constraint.Skip, name="global_inertia", ), RegionalConstraint( lambda m, t, r: m.regional_emissions[t, r] - m.regional_emissions[ t - 1, r] >= m.dt * m.inertia_regional * m.baseline_emissions( m.year(0), r) if value(m.inertia_regional) is not False and t > 0 else Constraint.Skip, name="regional_inertia", ), GlobalConstraint( lambda m, t: m.global_emissions[t] >= m.global_min_level if value(m.global_min_level) is not False else Constraint.Skip, "global_min_level", ), RegionalConstraint( lambda m, t, r: m.regional_emissions[t, r] >= m.regional_min_level if value(m.regional_min_level) is not False else Constraint.Skip, "regional_min_level", ), ]) m.emission_relative_cumulative = Var(m.t, initialize=1) constraints.extend([ GlobalConstraint( lambda m, t: (m.emission_relative_cumulative[t] == m.cumulative_emissions[t] / m .baseline_cumulative_global(m, m.year(0), m.year(t))) if t > 0 else Constraint.Skip, name="relative_cumulative_emissions", ), GlobalInitConstraint(lambda m: m.emission_relative_cumulative[0] == 1), ]) return constraints
def get_constraints(m: AbstractModel) -> Sequence[GeneralConstraint]: """Damage and adaptation costs equations and constraints (RICE specification) Necessary variables: m.damage_costs (sum of residual damages and adaptation costs, as % of GDP) Returns: list of constraints (any of: - GlobalConstraint - GlobalInitConstraint - RegionalConstraint - RegionalInitConstraint ) """ constraints = [] m.damage_costs = Var(m.t, m.regions) m.smoothed_factor = Var(m.t, bounds=(0, 1)) m.gross_damages = Var(m.t, m.regions) m.resid_damages = Var(m.t, m.regions) m.adapt_costs = Var(m.t, m.regions) m.adapt_level = Var(m.t, m.regions, bounds=(0, 1)) m.damage_a1 = Param(m.regions) m.damage_a2 = Param(m.regions) m.damage_a3 = Param(m.regions) m.damage_scale_factor = Param() m.adapt_g1 = Param(m.regions) m.adapt_g2 = Param(m.regions) m.adapt_curr_level = Param() m.fixed_adaptation = Param() constraints.extend( [ # Smoothing factor for partially reversible damages GlobalConstraint( lambda m, t: m.smoothed_factor[t] == smoothed_factor(t, m.temperature, m.dt, m.perc_reversible_damages), name="smoothed_factor", ), # Gross damages RegionalConstraint( lambda m, t, r: m.gross_damages[t, r] == calc_gross_damages(m, t, r, m.perc_reversible_damages), name="gross_damages", ), RegionalConstraint(lambda m, t, r: m.gross_damages[t, r] >= 0), RegionalInitConstraint(lambda m, r: m.gross_damages[0, r] == 0), ] ) # Adaptation constraints.extend( [ RegionalConstraint( lambda m, t, r: m.adapt_level[t, r] == ( m.adapt_curr_level if value(m.fixed_adaptation) else optimal_adapt_level(m.gross_damages[t, r], m, r) ), name="adapt_level", ), RegionalConstraint( lambda m, t, r: m.resid_damages[t, r] == m.gross_damages[t, r] * (1 - m.adapt_level[t, r]), "resid_damages", ), RegionalConstraint( lambda m, t, r: m.adapt_costs[t, r] == adaptation_costs(m.adapt_level[t, r], m, r), "adapt_costs", ), RegionalConstraint( lambda m, t, r: m.damage_costs[t, r] == m.resid_damages[t, r] + m.adapt_costs[t, r], "damage_costs", ), ] ) return constraints
def get_constraints(m: AbstractModel) -> Sequence[GeneralConstraint]: """Damage and adaptation costs equations and constraints (RICE specification) Necessary variables: m.damage_costs (sum of residual damages and adaptation costs multiplied by gross GDP) Returns: list of constraints (any of: - GlobalConstraint - GlobalInitConstraint - RegionalConstraint - RegionalInitConstraint ) """ constraints = [] m.damage_costs = Var(m.t, m.regions) m.gross_damages = Var(m.t, m.regions) m.resid_damages = Var(m.t, m.regions) m.damage_a1 = Param(m.regions) m.damage_a2 = Param(m.regions) m.damage_a3 = Param(m.regions) m.damage_scale_factor = Param() m.adapt_level = Var(m.t, m.regions, within=NonNegativeReals) m.adapt_costs = Var(m.t, m.regions) m.adapt_FAD = Var(m.t, m.regions, bounds=(0, 0.15), initialize=0) m.adapt_IAD = Var(m.t, m.regions, bounds=(0, 0.15), initialize=0) m.adap1 = Param(m.regions) m.adap2 = Param(m.regions) m.adap3 = Param(m.regions) m.adapt_rho = Param() m.fixed_adaptation = Param() m.adapt_SAD = Var(m.t, m.regions, initialize=0.01, within=NonNegativeReals) # SLR damages m.SLRdam1 = Param(m.regions) m.SLRdam2 = Param(m.regions) m.SLR_damages = Var(m.t, m.regions) constraints.extend( [ RegionalConstraint( lambda m, t, r: m.SLR_damages[t, r] == slr_damages( m.total_SLR[t], m.GDP_gross[t, r], m.GDP_gross[0, r], m.SLRdam1[r], m.SLRdam2[r], ), "SLR_damages", ), ] ) # Gross damages and adaptation levels constraints.extend( [ RegionalConstraint( lambda m, t, r: m.gross_damages[t, r] == m.damage_scale_factor * damage_fct(m.temperature[t], m.T0, m, r), "gross_damages", ), RegionalConstraint( lambda m, t, r: m.resid_damages[t, r] == m.gross_damages[t, r] / (1 + m.adapt_level[t, r]) + m.SLR_damages[t, r], "resid_damages", ), RegionalConstraint( lambda m, t, r: m.adapt_SAD[t, r] == (1 - m.dk) ** m.dt * m.adapt_SAD[t - 1, r] + m.adapt_IAD[t, r] if t > 0 else Constraint.Skip, "adapt_SAD", ), RegionalInitConstraint(lambda m, r: m.adapt_SAD[0, r] == 0), RegionalInitConstraint(lambda m, r: m.adapt_IAD[0, r] == 0), RegionalInitConstraint(lambda m, r: m.adapt_FAD[0, r] == 0), RegionalConstraint( lambda m, t, r: ( m.adapt_level[t, r] == m.adap1[r] * ( m.adap2[r] * soft_min(m.adapt_FAD[t, r], scale=0.005) ** m.adapt_rho + (1 - m.adap2[r]) * soft_min(m.adapt_SAD[t, r], scale=0.005) ** m.adapt_rho ) ** (m.adap3[r] / m.adapt_rho) ) if t > 0 else (m.adapt_level[t, r] == 0), name="adapt_level", ), RegionalConstraint( lambda m, t, r: m.adapt_costs[t, r] == m.adapt_FAD[t, r] + m.adapt_IAD[t, r], "adapt_costs", ), RegionalConstraint( lambda m, t, r: m.damage_costs[t, r] == m.resid_damages[t, r] + m.adapt_costs[t, r], "damage_costs", ), ] ) return constraints
def get_constraints(m: AbstractModel) -> Sequence[GeneralConstraint]: """Abatement cost equations and constraints Necessary variables: m.abatement_costs Returns: list of constraints (any of: - GlobalConstraint - GlobalInitConstraint - RegionalConstraint - RegionalInitConstraint ) """ constraints = [] ### Technological learning # Learning by doing m.LBD_rate = Param() m.log_LBD_rate = Param(initialize=log(m.LBD_rate) / log(2)) m.LBD_scaling = Param() m.LBD_factor = Var(m.t) # , bounds=(0,1), initialize=1) constraints.append( GlobalConstraint( lambda m, t: m.LBD_factor[t] == soft_min( ( m.baseline_cumulative_global(m, m.year(0), m.year(t)) - m.cumulative_emissions[t] ) / m.LBD_scaling + 1.0 ) ** m.log_LBD_rate, name="LBD", ) ) # Learning over time and total learning factor m.LOT_rate = Param() m.LOT_factor = Var(m.t) m.learning_factor = Var(m.t) constraints.extend( [ GlobalConstraint( lambda m, t: m.LOT_factor[t] == 1 / (1 + m.LOT_rate) ** t, "LOT" ), GlobalConstraint( lambda m, t: m.learning_factor[t] == (m.LBD_factor[t] * m.LOT_factor[t]), "learning", ), ] ) # Abatement costs and MAC m.abatement_costs = Var(m.t, m.regions, within=NonNegativeReals, initialize=0) m.area_under_MAC = Var(m.t, m.regions, within=NonNegativeReals, initialize=0) m.rel_abatement_costs = Var(m.t, m.regions, bounds=(0, 0.3)) m.MAC_gamma = Param() m.MAC_beta = Param() m.MAC_scaling_factor = Param(m.regions) # Regional scaling of the MAC m.carbonprice = Var(m.t, m.regions, bounds=lambda m: (0, 1.5 * m.MAC_gamma)) constraints.extend( [ RegionalConstraint( lambda m, t, r: ( m.area_under_MAC[t, r] if value(m.allow_trade) else m.abatement_costs[t, r] ) == AC( m.relative_abatement[t, r], m.learning_factor[t], m.MAC_gamma, m.MAC_beta, m.MAC_scaling_factor[r], ) * m.baseline[t, r], "abatement_costs", ), RegionalConstraint( lambda m, t, r: m.rel_abatement_costs[t, r] == m.abatement_costs[t, r] / m.GDP_gross[t, r], "rel_abatement_costs", ), RegionalConstraint( lambda m, t, r: m.carbonprice[t, r] == MAC( m.relative_abatement[t, r], m.learning_factor[t], m.MAC_gamma, m.MAC_beta, m.MAC_scaling_factor[r], ), "carbonprice", ), RegionalInitConstraint( lambda m, r: m.carbonprice[0, r] == 0, "init_carbon_price" ), ] ) # How are mitigation costs distributed over regions? m.allow_trade = Param() constraints.extend( [ GlobalConstraint( lambda m, t: sum(m.abatement_costs[t, r] for r in m.regions) == sum(m.area_under_MAC[t, r] for r in m.regions) if m.allow_trade else Constraint.Skip ), RegionalConstraint( lambda m, t, r: m.abatement_costs[t, r] <= 1.5 * m.area_under_MAC[t, r] if m.allow_trade else Constraint.Skip ), # RegionalConstraint( # lambda m, t, r: m.abatement_costs[t, r] >= 0.5 * m.area_under_MAC[t, r] # if m.allow_trade # else Constraint.Skip # ), ] ) # Keep track of relative global costs m.global_rel_abatement_costs = Var(m.t) constraints.extend( [ GlobalConstraint( lambda m, t: m.global_rel_abatement_costs[t] == sum(m.abatement_costs[t, r] for r in m.regions) / sum(m.GDP_gross[t, r] for r in m.regions), "global_rel_abatement_costs", ) ] ) return constraints
def get_constraints(m: AbstractModel) -> Sequence[GeneralConstraint]: """Emissions and temperature equations and constraints Necessary variables: m.total_SLR Returns: list of constraints (any of: - GlobalConstraint - GlobalInitConstraint - RegionalConstraint - RegionalInitConstraint ) """ # Parameters and variables necessary for sea level rise m.slr_thermal = Var(m.t) m.slr_thermal_equil = Param() m.slr_thermal_init = Param() m.slr_thermal_adjust_rate = Param() m.slr_cumgsic = Var(m.t) m.slr_gsic_melt_rate = Param() m.slr_gsic_total_ice = Param() m.slr_gsic_equil_temp = Param() m.slr_cumgis = Var(m.t) m.slr_gis_melt_rate_above_thresh = Param() m.slr_gis_init_melt_rate = Param() m.slr_gis_init_ice_vol = Param() m.total_SLR = Var(m.t) # Constraints relating to SLR constraints = [ # Thermal expansion GlobalConstraint( lambda m, t: m.slr_thermal[t] == slr_thermal_expansion( m.slr_thermal[t - 1], m.temperature[t - 1], m) if t > 0 else Constraint.Skip, name="SLR_thermal", ), GlobalInitConstraint(lambda m: m.slr_thermal[ 0] == m.slr_thermal_init + m.slr_thermal_adjust_rate * ( m.T0 * m.slr_thermal_equil - m.slr_thermal_init)), # GSIC GlobalConstraint( lambda m, t: m.slr_cumgsic[t] == slr_gsic(m.slr_cumgsic[ t - 1], m.temperature[t - 1], m) if t > 0 else Constraint.Skip, name="SLR_GSIC", ), GlobalInitConstraint(lambda m: m.slr_cumgsic[0] == 0.015), # GIS GlobalConstraint( lambda m, t: m.slr_cumgis[t] == slr_gis(m.slr_cumgis[ t - 1], m.temperature[t - 1], m) if t > 0 else Constraint.Skip, name="SLR_GIS", ), GlobalInitConstraint(lambda m: m.slr_cumgis[0] == 0.006), # Total SLR is sum of each contributing factors GlobalConstraint( lambda m, t: m.total_SLR[t] == m.slr_thermal[t] + m.slr_cumgsic[t] + m.slr_cumgis[t], name="total_SLR", ), ] return constraints
def get_constraints(m: AbstractModel) -> Sequence[GeneralConstraint]: """Economics and Cobb-Douglas equations and constraints Necessary variables: m.L (equal to m.population) m.dk Returns: list of constraints (any of: - GlobalConstraint - GlobalInitConstraint - RegionalConstraint - RegionalInitConstraint ) """ constraints = [] m.init_capitalstock_factor = Param(m.regions) m.capital_stock = Var( m.t, m.regions, initialize=lambda m, t, r: m.init_capitalstock_factor[r] * m.GDP( m.year(t), r), ) # Parameters m.alpha = Param() m.dk = Param() m.sr = Param() m.GDP_gross = Var(m.t, m.regions, initialize=lambda m, t, r: m.GDP(m.year(0), r)) m.GDP_net = Var(m.t, m.regions) m.investments = Var(m.t, m.regions) m.consumption = Var(m.t, m.regions) m.ignore_damages = Param() # Cobb-Douglas, GDP, investments, capital and consumption constraints.extend([ RegionalConstraint( lambda m, t, r: m.GDP_gross[t, r] == economics.calc_GDP( m.TFP(m.year(t), r), m.L(m.year(t), r), soft_min(m.capital_stock[t, r], scale=10), m.alpha, ), "GDP_gross", ), RegionalConstraint( lambda m, t, r: m.GDP_net[t, r] == m.GDP_gross[t, r] * (1 - (m.damage_costs[t, r] if not value(m.ignore_damages) else 0) ) - m.abatement_costs[t, r], "GDP_net", ), RegionalConstraint( lambda m, t, r: m.investments[t, r] == m.sr * m.GDP_net[t, r], "investments", ), RegionalConstraint( lambda m, t, r: m.consumption[t, r] == (1 - m.sr) * m.GDP_net[t, r], "consumption", ), RegionalConstraint( lambda m, t, r: (m.capital_stock[t, r] == m.capital_stock[ t - 1, r] + m.dt * economics.calc_dKdt(m.capital_stock[ t, r], m.dk, m.investments[t, r], m.dt)) if t > 0 else Constraint.Skip, "capital_stock", ), RegionalInitConstraint(lambda m, r: m.capital_stock[ 0, r] == m.init_capitalstock_factor[r] * m.GDP(m.year(0), r)), ]) return constraints
def get_constraints(m: AbstractModel) -> Sequence[GeneralConstraint]: """Damage and adaptation costs equations and constraints (WITCH specification) Necessary variables: m.damage_costs (sum of residual damages and adaptation costs, % of GDP) Returns: list of constraints (any of: - GlobalConstraint - GlobalInitConstraint - RegionalConstraint - RegionalInitConstraint ) """ constraints = [] m.damage_costs = Var(m.t, m.regions) # Gross and residual damages m.gross_damages = Var(m.t, m.regions) m.resid_damages = Var(m.t, m.regions) m.adapt_Q_ada = Var(m.t, m.regions, initialize=0.1) m.damage_omega1_pos = Param(m.regions) m.damage_omega1_neg = Param(m.regions) m.damage_omega2_pos = Param(m.regions) m.damage_omega2_neg = Param(m.regions) m.damage_omega3_pos = Param(m.regions) m.damage_omega3_neg = Param(m.regions) m.damage_omega4_pos = Param(m.regions) m.damage_omega4_neg = Param(m.regions) m.adapt_eps = Param(m.regions) m.damage_scale_factor = Param() constraints.extend([ RegionalConstraint( lambda m, t, r: m.gross_damages[t, r] == m.damage_scale_factor * damage_fct(m.temperature[t], 0, m.T0, m, r), "gross_damages", ), RegionalConstraint( lambda m, t, r: m.resid_damages[t, r] == m.damage_scale_factor * damage_fct( m.temperature[t], pow(m.adapt_Q_ada[t, r], m.adapt_eps[r], True), m.T0, m, r, ), "resid_damages", ), ]) # Adaptation costs (protection costs, PC) m.adapt_costs = Var(m.t, m.regions) m.adapt_costs_reactive = Var(m.t, m.regions, bounds=(0, 1)) # I_RADA # m.adapt_costs_proactive = Var(m.t, m.regions, bounds=(0,1)) # I_PRADA # m.adapt_costs_speccap = Var(m.t, m.regions) # I_SCAP, specific adaptive capacity m.fixed_adaptation = Param() constraints.extend([ RegionalConstraint( lambda m, t, r: m.adapt_costs[t, r] == ( m.adapt_costs_reactive[t, r] # + # m.adapt_costs_proactive[t,r] + # m.adapt_costs_speccap[t,r] ), name="adapt_costs", ), RegionalInitConstraint(lambda m, r: m.adapt_costs_reactive[0, r] == 0), ]) ## Nested Constant Elasticity of Substitution (CES) m.adapt_omega_eff_ada = Param(m.regions) m.adapt_omega_act = Param(m.regions) m.adapt_omega_eff_act = Param(m.regions) m.adapt_omega_rada = Param(m.regions) m.adapt_rho_ada = Param(m.regions) m.adapt_rho_act = Param(m.regions) # Nest 1: adaptation activities vs adaptive capacity # m.adapt_Q_act = Var(m.t, m.regions, initialize=0.1) m.adapt_Q_cap = Var(m.t, m.regions, initialize=0.1) constraints.extend([ RegionalConstraint( lambda m, t, r: m.adapt_Q_ada[t, r] == m.adapt_omega_eff_ada[r] * m .adapt_omega_eff_act[r] * m.adapt_costs_reactive[t, r], "adapt_Q_ada", ), # Extra constraint necessary to avoid negative GDP RegionalConstraint(lambda m, t, r: m.GDP_net[t, r] >= 0), ]) # regional_constraints.append(lambda m,t,r: m.adapt_Q_ada[t,r] == CES( # m.adapt_costs_reactive[t,r], m.adapt_Q_cap[t,r], # # m.adapt_Q_act[t,r], m.adapt_Q_cap[t,r], # m.adapt_omega_eff_ada[r], m.adapt_omega_act[r], m.adapt_rho_ada[r] # )) # Nest 2: reactive adaptation vs proactive adaptation # m.adapt_K_proactive = Var(m.t, m.regions, initialize=0.1) # regional_constraints.append(lambda m,t,r: m.adapt_Q_act[t,r] == CES( # m.adapt_costs_reactive[t,r], m.adapt_K_proactive[t,r], # m.adapt_omega_eff_act[r], m.adapt_omega_rada[r], m.adapt_rho_act[r] # )) # Nest 3: we don't model R&D and human capital, so we use the description # of Bosello et al (2010) [original AD-WITCH] that Q_cap is simple stock variable # Stocks of capital # m.adapt_Q_capdot = DerivativeVar(m.adapt_Q_cap, wrt=m.t) # m.adapt_K_proactivedot = DerivativeVar(m.adapt_K_proactive, wrt=m.t) # regional_constraints.extend([ # lambda m,t,r: m.adapt_Q_capdot[t,r] == np.log(1-m.dk) * m.adapt_Q_cap[t,r] + m.adapt_costs_speccap[t,r], # # lambda m,t,r: m.adapt_K_proactivedot[t,r] == np.log(1-m.dk) * m.adapt_K_proactive[t,r] + m.adapt_costs_proactive[t,r], # ]) constraints.extend([ RegionalConstraint( lambda m, t, r: m.damage_costs[t, r] == m.resid_damages[t, r] + m. adapt_costs[t, r], "damage_costs", ) ]) return constraints
def get_constraints(m: AbstractModel) -> Sequence[GeneralConstraint]: """Damage and adaptation costs equations and constraints (COACCH specification) Necessary variables: m.damage_costs (sum of residual damages and adaptation costs multiplied by gross GDP) Returns: list of constraints (any of: - GlobalConstraint - GlobalInitConstraint - RegionalConstraint - RegionalInitConstraint ) """ constraints = [] m.damage_costs = Var(m.t, m.regions) m.damage_scale_factor = Param() # Damages not related to SLR (dependent on temperature) m.resid_damages = Var(m.t, m.regions) m.damage_noslr_form = Param(m.regions, within=Any) # String for functional form m.damage_noslr_b1 = Param(m.regions) m.damage_noslr_b2 = Param(m.regions) m.damage_noslr_b3 = Param(m.regions) # (b2 and b3 are only used for some functional forms) m.damage_noslr_a = Param(m.regions) # Quadratic damage function for non-SLR damages. Factor `a` represents # the damage quantile constraints.append( RegionalConstraint( lambda m, t, r: m.resid_damages[t, r] == damage_fct( m.temperature[t], m.T0, m, r, is_slr=False), "resid_damages", )) # SLR damages m.SLR_damages = Var(m.t, m.regions) m.damage_slr_form = Param(m.regions, within=Any) # String for functional form m.damage_slr_b1 = Param(m.regions) m.damage_slr_b2 = Param(m.regions) m.damage_slr_b3 = Param(m.regions) # (b2 and b3 are only used for some functional forms) m.damage_slr_a = Param(m.regions) # Linear damage function for SLR damages, including adaptation costs constraints.append( RegionalConstraint( lambda m, t, r: m.SLR_damages[t, r] == damage_fct( m.total_SLR[t], None, m, r, is_slr=True), "SLR_damages", )) # Total damages are sum of non-SLR and SLR damages constraints.append( RegionalConstraint( lambda m, t, r: m.damage_costs[t, r] == m.resid_damages[t, r] + m. SLR_damages[t, r], "damage_costs", ), ) return constraints