def optimal_adapt_level(gross_damages, m, r): if value(m.adapt_g1[r]) * value(m.adapt_g2[r]) == 0: return 0 eps = 0.0005 return (soft_min(gross_damages, 0.01) / (m.adapt_g1[r] * m.adapt_g2[r]) + eps) ** ( 1 / (m.adapt_g2[r] - 1) )
def var_to_row(rows, m, var, is_regional): # If var is a list, second element is the name if isinstance(var, list): name = var[1] var = var[0] else: name = var.name # Check if var is a function or a pyomo variable if is_regional: fct = lambda t, r: (var(m.year(t), r) if callable(var) else value(var[t, r])) for r in m.regions: rows.append([name, r] + [fct(t, r) for t in m.t]) else: fct = lambda t: (var(m.year(t)) if callable(var) else value(var[t])) rows.append([name, "Global"] + [fct(t) for t in m.t])
def solve( self, verbose=True, halt_on_ampl_error="no", use_neos=False, neos_email=None, ipopt_output_file=None, ) -> None: """Sends the concrete model to a solver. Args: verbose (bool, optional): Prints intermediate IPOPT results. Defaults to True. halt_on_ampl_error (str, optional): Lets IPOPT stop when invalid values are encountered. Defaults to "no". use_neos (bool, optional): Uses the external NEOS server for solving. Defaults to False. neos_email (str or None, optional): E-mail address for NEOS server. Defaults to None. ipopt_output_file (str or None, optional): Filename for IPOPT intermediate output. Defaults to None. Raises: SolverException: raised if solver did not exit with status OK """ if use_neos: # Send concrete model to external solver on NEOS server # Requires authenticated email address os.environ["NEOS_EMAIL"] = neos_email solver_manager = SolverManagerFactory("neos") solver = "ipopt" # or "conopt' results = solver_manager.solve(self.concrete_model, opt=solver) else: # Solve locally using ipopt opt: OptSolver = SolverFactory("ipopt") opt.options["halt_on_ampl_error"] = halt_on_ampl_error if ipopt_output_file is not None: opt.options["output_file"] = ipopt_output_file results = opt.solve(self.concrete_model, tee=verbose, symbolic_solver_labels=True) if ipopt_output_file is not None: visualise_ipopt_output(ipopt_output_file) self.postprocessing() logger.info("Status: {}".format(results.solver.status)) if results.solver.status != SolverStatus.ok: logger.error("Status: {}, termination condition: {}".format( results.solver.status, results.solver.termination_condition)) if results.solver.status != SolverStatus.warning: raise SolverException("Solver did not exit with status OK") logger.info("Final NPV: {}".format( value(self.concrete_model.NPV[self.concrete_model.tf])))
def functional_form(x, m, r, is_slr=False): if is_slr: form = m.damage_slr_form[r] b1, b2, b3 = m.damage_slr_b1[r], m.damage_slr_b2[r], m.damage_slr_b3[r] a = m.damage_slr_a[r] else: form = m.damage_noslr_form[r] b1, b2, b3 = m.damage_noslr_b1[r], m.damage_noslr_b2[ r], m.damage_noslr_b3[r] a = m.damage_noslr_a[r] # Linear functional form if "Linear" in value(form): return a * b1 * x / 100.0 # Quadratic functional form if "Quadratic" in value(form): return a * (b1 * x + b2 * x**2) / 100.0 # Logistic functional form if "Logistic" in value(form): return a * logistic(x, b1, b2, b3) / 100.0 raise NotImplementedError
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]: """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]: """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