Policy - Pollution Limits & Renewables (EPS)
Developing an EPS Policy to Set Pollution Limits & and a Renewable Mix Target
An Electric Performance Standard (EPS) refers to regulatory policies that impose constraints or targets on electricity generation, such as limits on greenhouse gas (GHG) emissions, efficiency targets, or requirements for renewable energy shares. This page shows an example of developing a policy that sets pollution and renewable targets for electricity generation.
EPS policies in ENERGY 2100 simulate real-world regulations (e.g., Nova Scotia's GHG limits and Renewable Portfolio Standards) by modifying input variables that influence capacity expansion decisions and dispatch constraints. The model uses these inputs across multiple modules - ECapacityExpansion.jl, EDispatch.jl, and EPollution.jl - to determine how much new capacity is built, how generation is dispatched, and how emissions are accounted for and penalized.
The process for a user to implement an EPS involves creating or modifying policy files (similar to Electric_NS_GHGLimit.jl and Electric_NS_Renewable.jl) that set specific variables in the model's database. These variables cascade through the model's execution, affecting capacity expansion decisions, dispatch constraints, and pollution accounting. The section below outlines the step-by-step process, the key variables modified, and their impacts throughout the model pipeline.
Step-by-Step Process for a User to Build an EPS
- Understand the Policy Context and Model Structure:
- Identify the regulatory goal (e.g., GHG emission caps or renewable energy mandates) and the affected areas (e.g., provinces like Nova Scotia, represented by "NS" in the code).
- Review the model's database structure: Policies modify arrays stored in HDF5 files (e.g., via ReadDisk and WriteDisk functions). Key databases include "EGInput" for electric generation inputs and "MainDB" for core sets like areas, years, and pollutants.
- Examine existing policy files (e.g., Electric_NS_GHGLimit.jl and Electric_NS_Renewable.jl) as templates. These are Julia modules that define structs for data control and functions to apply policies.
- Create or Modify a Policy File:
- Write a new Julia file in the Policy/ directory (e.g., Electric_[Province]_PolicyName.jl).
- Define a module with a struct (e.g., EControl) that reads relevant data from the database using ReadDisk.
- Implement a policy function (e.g., ElecPolicy(db)) that modifies variables based on the EPS rules. Use loops over years and areas to set values.
- Include a PolicyControl(db) function to log and execute the policy, and an if abspath(PROGRAM_FILE) == @__FILE__ block for standalone testing.
- Ensure the file uses the EnergyModel module for utilities like Select, Yr, and finite math operations.
- Set Policy Variables:
- Modify arrays to reflect the EPS (see details below). For example, set emission limits or renewable fractions for specific years and areas.
- Write the modified arrays back to the database using WriteDisk.
- Integrate and Test the Policy:
- Run the policy file to update the database (e.g., via batch scripts like those in the 2020Model/ folder).
- Execute the full model run (e.g., using RunE2020Runs.jl or related scripts). The policy variables will cascade through three main stages:
- Capacity expansion stage (ECapacityExpansion.jl): Determines what plants get built based on economic and policy constraints.
- Dispatch stage (EDispatch.jl): Allocates generation by plant type for each time period, subject to pollution limits.
- Pollution accounting stage (EPollution.jl): Calculates total emissions, permit costs, and compliance reporting.
- Validate outputs: Check capacity build decisions, generation dispatch, and emissions for compliance with the EPS.
- Iterate and Refine:
- Adjust variables based on model outputs (e.g., if GHG limits force retirements, tweak values to avoid infeasible builds).
- Document the policy in comments, including sources (e.g., government regulations), as seen in the example files.
Key Variables Modified and Their Impacts Across Model Stages
Policies modify input variables that constrain or incentivize decisions at three stages of model execution. The variables set in policy files are read and applied in cascading fashion. Below are the main policy variables to modify and their comprehensive impacts:
Variables and Their Cascading Effects
- PollLimitGHGFlag (from Electric_NS_GHGLimit.jl):
- Modification: Set to 1 for specific areas/years (e.g., NS from 2024–2050) to activate GHG emission limits.
- Stage 1 - Capacity Expansion: This flag signals to ECapacityExpansion.jl that emission constraints are active for an area. It influences which plant types are economically viable to build (e.g., low-carbon plants may receive preferential treatment).
- Stage 2 - Dispatch: In EDispatch.jl, this flag activates AssignUnitsToEmissionGroups in EDispatchLP.jl. When PollLimitGHGFlag[area] > 1, units are grouped by emission intensity. The dispatch LP (linear program) then writes PollutionConstraints that limit total generation from high-emission units in each time period. This prevents the dispatch algorithm from ignoring the emission cap.
- Stage 3 - Pollution Accounting: In EPollution.jl, this flag ensures emissions are tracked and compared against the limit, and permit costs are calculated if trading is enabled.
- PollutionLimit (from Electric_NS_GHGLimit.jl):
- Modification: Set absolute annual emission limits (e.g., CO2 tonnes for NS, escalating from 6.875M in 2024 to 4.5M in 2035+).
- Stage 1 - Capacity Expansion: This caps total allowable emissions, constraining high-emission plants. Functions like CapacityRequirementsForecast and BuildNewCapacity must account for whether sufficient capacity can be added without exceeding limits. If limits are tight, endogenous builds shift toward renewables or gas.
- Stage 2 - Dispatch: In EDispatch.jl, AvaliablePollutionLimits calculates the remaining emission budget for the year. AllocatePollutionLimits divides this budget across time periods (months and time-of-day), and UpdatePollutionLimits tracks actual emissions. The dispatch LP incorporates these as hard constraints in PollutionConstraints within EDispatchLP.jl, ensuring no time period violates its allocated limit. If a limit is breached, the LP fails or uses emergency generation.
- Stage 3 - Pollution Accounting: In EPollution.jl, functions like TotalElectricUtilityPollution and GrossPollution sum actual emissions and verify compliance. If emissions exceed the limit (unlikely given dispatch constraints), permit costs spike or penalties apply.
- Overall Effect: Emission limits drive capacity mix decisions (more renewables, less coal), constrain dispatch (generation is rationed across time periods), and create cost pressures through permit markets.
- RnGoalSwitch (from Electric_NS_Renewable.jl):
- Modification: Set to 1 for sales-based goals (generation-based) vs. capacity-based.
- Stage 1 - Capacity Expansion: In RnRPS, if RnGoalSwitch=1 means the model calculates required renewable capacity based on total system generation forecast, not just existing capacity. This aligns builds with demand growth.
- Stage 2 - Dispatch: This switch does not directly affect dispatch, but the capacity built based on this flag influences available renewable capacity for dispatch.
- Stage 3 - Pollution Accounting: Renewable accounting tallies sales met by renewables (generation), confirming policy compliance.
- Overall Effect: Controls whether the renewable target is tied to total generation or just capacity, affecting timing and scale of builds.
- RnFr (Renewable Fraction) (from Electric_NS_Renewable.jl):
- Modification: Set target renewable shares (e.g., 40% for NS in 2024–2025, rising to 80% by 2030+).
- Stage 1 - Capacity Expansion: In ECapacityExpansion.jl, the RnRPS function calculates required renewable capacity additions to meet the target. If RnGoalSwitch=1, the target is based on sales (generation), and the model ensures new builds prioritize renewables in IntermittentPowerExpansion. This directly increases renewable capacity.
- Stage 2 - Dispatch: In EDispatch.jl, renewable units (wind, solar) are typically bid at low or zero variable cost (marginal cost of zero fuel), so they are prioritized in dispatch. High renewable fractions ensure these units are dispatched first, reducing fossil fuel generation. The LP respects dispatch priority through bid costs.
- Stage 3 - Pollution Accounting: In EPollution.jl, renewable generation reduces total emissions since renewables have zero (or near-zero) emission factors. This helps meet GHG limits and reduces permit costs.
- Overall Effect: Renewable mandates drive capacity mix (build renewables), influence dispatch (dispatch renewables first), and directly reduce system emissions.
- RnOption (from Electric_NS_Renewable.jl):
- Modification: Set to 0 for exogenous capacity builds, 1 for local RPS, 2 for regional RPS, 3 for FIT (Feed-In Tariff).
- Stage 1 - Capacity Expansion: At 0, renewable capacity is built exogenously (not via market optimization), ensuring policy targets are met regardless of economics. At 1–3, renewable builds compete in the market with cost factors.
- Stage 2 - Dispatch: No direct effect; renewable units are dispatched based on availability and costs regardless of how they were built.
- Stage 3 - Pollution Accounting: Accounting reflects the renewable generation regardless of build mode.
- Overall Effect: Controls how policy targets are enforced (mandate vs. market incentive).
Additional Pollution-Related Variables (from EDispatch.jl and EPollution.jl):
These are not typically modified by users in policy files but are calculated based on the policy variables above:
- PollAvailable (calculated in EDispatch.jl):
- Represents the remaining emission budget for the year at each time period. Calculated from PollutionLimit minus prior actual emissions.
- Used to allocate pollution budgets across months and time-of-day periods in AllocatePollutionLimits.
- PollActual (tracked in EDispatch.jl and EPollution.jl):
- Records actual emissions in each time period based on dispatched generation and unit emission factors.
- Updated after each dispatch cycle to track cumulative emissions against PollAvailable.
- UnPRAccounting, UnPRCapacity, GratisPermits (from EPollution.jl):
- If a pollution market is enabled (e.g., cap-and-trade), these variables calculate pollution reduction investments, reduction capacity, and gratis permits for units.
- Gratis permits are allocated based on plant type and vintage; new plants may receive fewer permits, incentivizing cleaner technology.
Summary: The Policy-to-Impact Pipeline
When a user sets policy variables in a policy file, the impacts cascade as follows:
- Policy File Execution → Database updated with PollLimitGHGFlag, PollutionLimit, RnFr, etc.
- Capacity Expansion → ECapacityExpansion.jl reads policy variables and adjusts capacity build decisions:
- Renewable mandates (RnFr) → Build more renewables
- Emission limits (PollutionLimit, PollLimitGHGFlag) → Build less fossil fuel capacity
- Result: Capacity mix changes, with potentially higher renewable and lower coal capacity
- Dispatch → EDispatch.jl and EDispatchLP.jl read updated capacity and policy variables:
- PollLimitGHGFlag → Assign units to emission groups, activate pollution constraints in LP
- PollutionLimit → Allocate emission budgets across time periods
- Result: Generation dispatch respects pollution limits, dispatch prices adjust based on emission scarcity
- Pollution Accounting → EPollution.jl calculates actual emissions, permits, and costs:
- Total generation × emission factors → Total emissions
- Compare against PollutionLimit → Verify compliance
- Calculate permit costs → Add to total system cost
- Result: Emissions reported, compliance verified, policy effectiveness quantified
User Guidance
- To simulate a GHG cap: Set PollLimitGHGFlag=1 and PollutionLimit for the affected area and years. The model will constrain capacity builds and dispatch to stay within the cap.
- To simulate a renewable mandate: Set RnFr to target percentage and RnGoalSwitch=1 for sales-based compliance. The model will build and prioritize renewable capacity.
- To combine policies (e.g., GHG cap + renewable mandate): Set both variables. The model will ensure both constraints are satisfied, potentially leading to over-building renewables if the GHG cap is easier to meet with renewables alone.
- To debug: Check outputs at each stage:
- Capacity: EGOutput/HDIPGC (new capacity initiated), EGOutput/UnGC (unit generation capacity)
- Dispatch: EGOutput/UnEG (unit generation), EGOutput/HDPrA (spot prices)
- Emissions: EGOutput/UnPol (unit pollution), SOutput/TSPol (total system pollution)
For more details, users should reference the full code in ECapacityExpansion.jl, EDispatch.jl, and EPollution.jl, and test runs to observe variable interactions.