Policy - Market Shares
Overview
This guide explains how to write policy files to modify fuel and technology market shares in ENERGY 2100 by adjusting marginal market share variables (MMSF). This allows you to model fuel switching policies, technology adoption mandates, and energy transition scenarios.
Key Concepts
Marginal vs. Average Market Share
- MMSF (Marginal Market Share): The market share of technologies that consumers choose in a given year. This is what you modify in policy files.
- AMSF (Average Market Share): The weighted historical average of technology choices over time. MMSF decisions accumulate into AMSF.
- Policy Impact: By changing MMSF for a technology, you shift what new installations/purchases are chosen, which gradually shifts the overall energy system over time as old capital retires and is replaced.
Model Sectors
The model has four demand sectors, each with its own set of technologies, end-uses, and economic categories:
- Residential (RDemand.jl)
- Commercial (CDemand.jl)
- Industrial (IDemand.jl)
- Transportation (TDemand.jl)
How Policies Affect the Model
There are two approaches to modifying market shares, depending on your policy objective:
Approach 1: Modify xMMSF (Most Common)
xMMSF is the policy driver used in most policy files:
- Initialization files (for example: Ind_MS_Initialize.jl) copy base case values of MMSF into xMMSF.These initialization files are automatically called before your policy file is executed.
- Policy files modify xMMSF values
- Normalization files (for example: Ind_MS_Normalize.jl) ensure xMMSF sums to 1.0 for each Enduse/EC/Area/Year. The normalization routines are called automatically after your policy file is executed.
- Coefficient files (for example: Ind_MS_Coefficient.jl) use normalized xMMSF to calculate marginal non-price factors (MMSM0), which are used as an input to the endogenous market share equations (MMSF). Theses coefficient routines are called automatically after the normalization routines and are designed to produce an MMSM0 value that aligns the output MMSF with the xMMSF input.
- *Demand.jl files read MMSM0 and use it to produce MMSF for technology choice.
Example use cases: Electrification mandates, technology phase-ins, technology bans
Approach 2: Modify MMSFExogenous (Exogenous/Fixed Cases)
MMSFExogenous directly sets the marginal market share without market calculation:
- Policy files modify MMSFExogenous directly.
- Policy files set MMSFSwitch = 0 (flag as exogenous, not price-competitive).
- Normalization files normalize these exogenous shares to sum to 1.0. These files are called automatically as part of a policy run.
- *Demand.jl files read: MMSF = MMSFExogenous.
Example use cases: Fixed technology requirement, technology held exogenous for calibration
Result: MMSF Controls Demand
Regardless of approach, the resulting MMSF determines:
- Technology fuel consumption
- Emissions by technology
- Equipment capital costs
- Overall energy system trajectory
Policy File Structure
Template
Each policy file follows this structure:
#
# [Sector]_MS_[PolicyName]_[Region].jl
#
# Brief description of policy objectives and data sources
#
using EnergyModel
module [ModuleName]
import ...EnergyModel: ReadDisk, WriteDisk, Select
import ...EnergyModel: HisTime, ITime, MaxTime, First, Future, Final, Yr
import ...EnergyModel: @finite_math, finite_inverse, finite_divide, finite_power, finite_exp, finite_log
import ...EnergyModel: DB
const VariableArray{N} = Array{Float32,N} where {N}
const SetArray = Vector{String}
Base.@kwdef struct [Control]
db::String
CalDB::String = "[R/C/I/T]CalDB"
Input::String = "[R/C/I/T]Input"
Outpt::String = "[R/C/I/T]Output"
# Define dimension sets
Area::SetArray = ReadDisk(db,"MainDB/AreaKey")
Areas::Vector{Int} = collect(Select(Area))
# ... other dimensions
# Load data variables (choose based on your approach):
xMMSF::VariableArray{5} = ReadDisk(db,"$CalDB/xMMSF") # For Approach 1
# MMSFExogenous::VariableArray{5} = ReadDisk(db,"$Input/MMSFExogenous") # For Approach 2
# MMSFSwitch::VariableArray{5} = ReadDisk(db,"$Input/MMSFSwitch") # For Approach 2
# ... other data as needed
end
function [PolicyName](db)
data = [Control](; db)
(; CalDB, Input) = data
(; Areas, ECs, Enduses, Techs) = data
(; xMMSF) = data # or MMSFExogenous, MMSFSwitch for Approach 2
# Define year range
years = collect(Future:Final)
# --- POLICY IMPLEMENTATION ---
# Select the dimensions you want to modify
# Modify xMMSF values (Approach 1) OR MMSFExogenous (Approach 2)
# Write results back to disk
# --- END POLICY ---
WriteDisk(db,"$CalDB/xMMSF",xMMSF) # For Approach 1
# WriteDisk(db,"$Input/MMSFSwitch",MMSFSwitch) # For Approach 2
# WriteDisk(db,"$Input/MMSFExogenous",MMSFExogenous) # For Approach 2
end
function PolicyControl(db)
@info("[PolicyName] PolicyControl function called")
[PolicyName](db) # Call to function that modifies the policy variable(s)
@info("Policy executed successfully")
end
if abspath(PROGRAM_FILE) == @__FILE__
PolicyControl(DB)
end
end
Module Naming Convention
Use the pattern: [Sector]_MS_[PolicyDescription]_[Region]
Examples:
- Res_MS_NewElectric_CA.jl - Residential electrification policy for California
- Ind_MS_Biomass_Exo.jl - Industrial exogenous biomass policy
- Com_MS_HeatPump_ON.jl - Commercial heat pump adoption in Ontario
- Trans_MS_FuelCell_AB.jl - Transportation fuel cell adoption in Alberta.
Choosing Your Approach: xMMSF vs MMSFExogenous
|
Aspect |
xMMSF |
MMSFExogenous |
|
When to use |
Standard policy (most cases) |
Fixed/exogenous requirement |
|
Variable database location |
CalDB |
Input |
|
After your changes |
Normalized by *_Normalize.jl |
Normalized by *_Normalize.jl |
|
Then |
Processed by *_Coefficient.jl |
Directly becomes MMSF |
|
Switch setting |
Usually MMSFSwitch = 1 (endogenous), which is the default |
MMSFSwitch = 0 (exogenous) |
|
Market logic |
Applies coefficients/elasticity |
Bypasses market calculations |
|
Example |
"Heat pumps increase to 50% by 2035" |
"Biomass is exogenous (fixed value)" |
Rule of thumb: Start with xMMSF unless you specifically need to fix technology shares independent of economic calculations.
By Sector - Technology Options
Residential (techres.csv):
- Electric, Gas, Coal, Oil, Biomass, Solar, LPG, Steam, Geothermal, HeatPump, DualHPump, FuelCell
Commercial (techcom.csv):
- Electric, Gas, Coal, Oil, Biomass, Solar, LPG, Steam, Geothermal, HeatPump, DualHPump, FuelCell
Industrial (techind.csv):
- Electric, Gas, Coal, Oil, Biomass, Solar, LPG, OffRoad, Steam, HeatPump, FuelCell, Storage
Transportation (techtrans.csv):
- LDV Gasoline/Diesel/Electric/NaturalGas/Propane/Ethanol/Hybrid/FuelCell (Light Duty Vehicles)
- LDT Gasoline/Diesel/Electric/NaturalGas/Propane/Ethanol/Hybrid/FuelCell (Light Duty Trucks)
- Motorcycle
- Bus Gasoline/Diesel/Electric/NaturalGas/Propane/FuelCell
- Train Diesel/Electric/FuelCell
- Plane JetFuel/Gasoline/FuelCell
- HDV2B3/HDV45/HDV67/HDV8 Gasoline/Diesel/Electric/NaturalGas/Propane/FuelCell (Heavy Duty Vehicles)
- Marine Heavy/Light/FuelCell
- Off-Road
By Sector - End-Use Options
Residential & Commercial (enduseRes.csv, enduseCom.csv):
- Heat (Space Heating)
- HW (Water Heating)
- OthSub (Other Substitutables)
- Refrig (Refrigeration) - Commercial only
- Light (Lighting) - Commercial only
- AC (Air Conditioning)
- OthNSub (Other Non-Substitutables)
Industrial (enduseInd.csv):
- Heat (Process Heat)
- Motors
- OthSub (Other Substitutables)
- OthNSub (Miscellaneous)
- OffRoad
- Steam (Excess Steam)
Transportation (enduseTrans.csv):
- Carriage
By Sector - Economic Category Options
Residential (ecres.csv):
- SingleFamilyDetached, SingleFamilyAttached, MultiFamily, OtherResidential
Commercial (ecCom.csv):
- Wholesale, Retail, Warehouse, Information, Offices, Education, Health, OtherCommercial, NGDistribution, OilPipeline, NGPipeline, StreetLighting
Industrial (ecind.csv):
- Food, Textiles, Lumber, Furniture, PulpPaperMills, Petrochemicals, IndustrialGas, OtherChemicals, Fertilizer, Petroleum, Rubber, Cement, Glass, LimeGypsum, OtherNonMetallic, IronSteel, Aluminum, OtherNonferrous, TransportEquipment, OtherManufacturing, IronOreMining, OtherMetalMining, NonMetalMining, LightOilMining, HeavyOilMining, FrontierOilMining, PrimaryOilSands, SAGDOilSands, CSSOilSands, OilSandsMining, OilSandsUpgraders, ConventionalGasProduction, SweetGasProcessing, UnconventionalGasProduction, SourGasProcessing, LNGProduction, CoalMining, Construction, Forestry, OnFarmFuelUse, CropProduction, AnimalProduction
Transportation (ectrans.csv):
- Passenger, Freight, AirPassenger, AirFreight, ForeignPassenger, ForeignFreight, ResidentialOffRoad, CommercialOffRoad
Geographic Options
Areas (area.csv):
- Canadian Provinces: ON, QC, BC, AB, MB, SK, NB, NS, NL, PE, YT, NT, NU
- US Regions: CA, NEng, MAtl, ENC, WNC, SAtl, ESC, WSC, Mtn, Pac
- Other: MX (Mexico), ROW (Rest of World)
Nations: US, CN (Canada), MX (Mexico), ROW (Rest of World)
Time Periods
- First - First historical year (typically 1986)
- Future - First forecast year (transition from historical to projection)
- Final - Last model year (typically 2050)
- Yr(yyyy) - Specific year (e.g., Yr(2030))
Using the Select() Function
The Select() function retrieves indices from dimension sets. It's essential for accessing specific dimensions:
|
# # Get index of a single value # Heat = Select(Enduse,"Heat") Electric = Select(Tech,"Electric") Ontario = Select(Area,"ON") # # Get indices of multiple values # areas = Select(Area,["ON","QC","BC"]) # Returns vector of indices Techs = Select(Tech) # Get all indices # # Get indices matching a condition # NonElectric = Select(Tech,!=("Electric")) # All except Electric |
|
|
🛈 |
See Selecting Elements of a Set for more information on the "Select" function. |
How to Find Which Technology/Enduse/EC to Modify
- Identify the policy goal: What technology transition do you want to model?
- Match to model dimensions:
- What end-use uses that technology? (e.g., "Heat" for heating fuels)
- What technology are you promoting/restricting? (e.g., "HeatPump", "Electric")
- What economic categories are affected? (e.g., all or specific industries)
- What geographic area does policy apply to? (e.g., "CA", or "CN" for all Canada)
- When does it start? (e.g., Yr(2030) or Future)
- Consult CSV files to verify exact names and confirm available combinations
Common Policy Patterns
Pattern 1: Mandate a Technology for New Construction (xMMSF Approach)
|
|
🕮 |
Example Policy goal: All new residential heating in Ontario must be electric heat pumps from 2026 onward.
|
The normalized and processed xMMSF will become MMSF, controlling technology choice through market logic.
Pattern 2: Exogenous Technology (No Cost Competition)
|
|
🕮 |
Example Policy goal: Biomass heating in Canadian industrial facilities is exogenous.
|
Pattern 3: Phase-In Over Multiple Years
|
|
🕮 |
Example Policy goal: Commercial heat pumps increase from 10% (2025) to 100% (2050).
|
Pattern 5: Transportation Electrification Targets
|
|
🕮 |
Example Policy goal: Heavy-duty vehicles in Canada shift to electric/fuel cell from 2026-2040.
|
What Happens When You Modify MMSFExogenous
The modified MMSFExogenous[enduse, tech, ec, area, year] values:
- Are normalized by *_MS_Normalize.jl so all technologies for a given Enduse/EC/Area/Year sum to 1.0
- Become MMSF in the *Demand.jl files: MMSF[enduse,tech,ec,area,year] = MMSFExogenous[...]
- Affect consumer decisions in demand calculations via:
- Technology selection based on relative costs and efficiency
- Fuel consumption allocation to chosen technologies
- Equipment capital requirements
- Accumulate over time as AMSF (average market share) through capital stock turnover
- Influence model outputs including:
- Sectoral fuel demand by technology and fuel type
- Energy-related emissions by source
- Technology adoption rates and capital investments
- Economic impacts of technology transitions
Testing Your Policy
- Verify dimensions: Ensure all Enduse/Tech/EC/Area combinations you reference exist
- Check normalization: After modification, all techs for a given Enduse/EC/Area/Year should sum to ~1.0
- Review time periods: Confirm policies apply to intended forecast years
- Validate values: Market share fractions should be between 0.0 and 1.0
- Run model: Execute model and examine outputs for expected technology adoption patterns
Examples in ENERGY 2100
Examine these policy files for working examples:
xMMSF Approach (most common):
- Res_MS_NewElectric_CA.jl - California all-electric new buildings with phase-in
- Res_MS_Biomass_NT.jl - Northwest Territories biomass targets with custom logic
- Com_MS_Biomass_NT.jl - Commercial biomass policy
- Trans_MS_Bus_Train.jl - Bus electrification targets
- Trans_MS_HDV_Electric_A.jl - Heavy-duty vehicle electrification
MMSFExogenous Approach (exogenous/fixed):
- Ind_MS_Biomass_Exo.jl - Industrial exogenous biomass (no market competition)
Tips for Policy Development
- Start simple: Begin with a single technology/enduse/region
- Use comments: Document policy assumptions and data sources
- Align with baselines: If comparing to no-policy, ensure baseline runs have MMSFSwitch = 1 (endogenous)
- Consider lead times: Real-world policies have delays; phase-in over multiple years if appropriate
- Document transitions: Show equations or tables defining how shares change over time
- Cross-sector effects: Some policies affect multiple sectors (e.g., electrification)
- Verify against data: Validate technology combinations against .csv dimension files
Debugging Common Issues
|
Issue |
Cause |
Solution |
|
Model crashes when running policy |
Invalid Tech/Enduse/EC/Area index |
Check CSV files for exact spelling/names |
|
Market shares don't sum to 1.0 |
Modified shares incorrectly |
Ensure normalization file runs after your edits |
|
Policy has no effect |
Setting wrong variable or switch |
Ensure writing to $Input/MMSFExogenous and $Input/MMSFSwitch |
|
Unexpected technology adoption |
Wrong year range |
Check Future and Final constants; use Yr(YYYY) for specific years |
|
NaN/infinite values in results |
Division by zero or invalid math |
Use @finite_math macro; check for zero denominators |
Contact & Support
For questions about:
- Model structure: Review RDemand.jl, CDemand.jl, IDemand.jl, TDemand.jl MShare() and MarketShareAC() functions
- Available dimensions: Check CSV files in Database/Sets/ folder
- Integration: Ensure policy file is included in either the reference case policy collection file (such as Ref25.jl) or a policy test file (such as PolicyFuelCell.jl or PolicyTest.jl).