Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/source/configtables/electricity.csv
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ gaslimit,MWh thermal,float,"Cap on annual gas-fired primary energy from gas carr
,,,
demand:,,,
-- bus_allocation,--,"One of {``population``, ``breakthrough``}","How zone-level demand is distributed to individual buses. ``population`` (default) weights buses by 2020 Decennial Census county populations (split evenly across each county's substations, then each substation's buses). ``breakthrough`` uses the legacy nominal-demand column (``Pd``) from the 2016-vintage Breakthrough Energy grid model."
-- profile,--,"One of {``efs``, ``eia``, ``eer``}","Datasource for electrical load data. ``EFS`` pulls future state level electrical demand data. ``EIA`` pulls historical balancing level electrical demand data. ``EER`` pulls future state-level profiles from the EER dataset; when selected, ``planning_horizons`` must be one of 2021, 2025, 2030, 2035, 2040, 2045, or 2050 and ``renewable_weather_years`` must contain exactly one year from 2007-2013 or 2016-2023."
-- profile,--,"One of {``efs``, ``eia``, ``eer``, ``servm``}","Datasource for electrical load data. ``EFS`` pulls future state level electrical demand data. ``EIA`` pulls historical balancing level electrical demand data. ``EER`` pulls future state-level profiles from the EER dataset; when selected, ``planning_horizons`` must be one of 2021, 2025, 2030, 2035, 2040, 2045, or 2050 and ``renewable_weather_years`` must contain exactly one year from 2007-2013 or 2016-2023. ``SERVM`` pulls CPUC SERVM hourly load for the six California load regions (California models only); when selected, ``planning_horizons`` must be one of 2026, 2028, 2030, 2032, 2035, 2037, 2040, 2042, or 2045."
-- scenario:,,,
-- -- efs_case,--,"One of {``reference``, ``medium``, ``high``}",(UNDER DEVELOPMENT) Extracts EFS data according to level of adoption
-- -- efs_speed,--,"One of {``slow``, ``moderate``, ``fast``}",(UNDER DEVELOPMENT) Extracts EFS data according to speed of electrification
-- -- eer_file,--,"One of {``demand_EER2025_100by2050.h5``, ``demand_EER2025_Baseline_AEO2023.h5``, ``demand_EER2025_IRAlow.h5``}",Selects the EER demand dataset file to download and use when ``profile`` is ``eer``.
-- -- aeo,--,One of the AEO scenarios `here <https://www.eia.gov/outlooks/aeo/data/browser/>`_,(UNDER DEVELOPMENT) Scales future demand according to the AEO scenario
-- -- servm_weather_years,--,List with exactly one year from 2000-2024,"Weather year drawn from the stacked SERVM record when ``profile`` is ``servm``. Multiple entries are reserved for stochastic scenarios and currently raise ``NotImplementedError``. Keep equal to the top-level ``renewable_weather_years`` so load and renewable profiles share a weather year; a mismatch logs a warning."
,,,
demand_response:,,,Settings to activate and configure demand response
-- shift,per_unit,"float {0 <=, >= 1} or 'inf'",Allowable load to be shifted per snapshot. Set to 0 to turn off demand response. Set to 'inf' to not enforce capacity limits.
Expand Down
11 changes: 9 additions & 2 deletions workflow/repo_data/config/config.default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,20 @@ electricity:

# ---------------- Demand ----------------
demand:
profile: efs # demand time series source; efs (EIA-EFS) | eia (historical actuals) | eer (EER scenarios)
profile: efs # demand time series source; efs (EIA-EFS) | eia (historical actuals) | eer (EER scenarios) | servm (CPUC SERVM, California only)
bus_allocation: population # per-bus demand weight; population (2020 census counties) | breakthrough (legacy BE Pd)
scenario: # EFS/EER scenario knobs (ignored if profile=eia)
scenario: # EFS/EER/SERVM scenario knobs (ignored if profile=eia)
efs_case: reference # reference | medium | high
efs_speed: moderate # slow | moderate | rapid
eer_file: demand_EER2025_100by2050.h5 # EER h5 (profile=eer): demand_EER2025_100by2050 | demand_EER2025_Baseline_AEO2023 | demand_EER2025_IRAlow
aeo: reference # AEO (EIA Annual Energy Outlook) scaling case; reference | high | low
# ---- profile: servm (CPUC SERVM 2026, California regions) ----
# Weather year drawn from the stacked 2000-2024 SERVM record. Single-entry
# list = deterministic; multiple entries are reserved for stochastic
# scenarios (phase 3) and currently raise NotImplementedError.
# RECOMMENDED: keep equal to top-level `renewable_weather_years` so load
# and renewable profiles share a weather year (mismatch logs a warning).
servm_weather_years: [2019]

demand_response: # price-responsive shiftable load; 0 = disabled
shift: 0 # fraction of hourly load that can shift in time
Expand Down
39 changes: 34 additions & 5 deletions workflow/rules/build_electricity.smk
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,15 @@ def eer_demand_file():
return filename


SERVM_LOAD_FILE = "cpuc/servm/HourlyLoad_CA_Regions_V2025E_2224_Mon_{year}.csv"


def servm_demand_files():
"""One CPUC SERVM hourly-load file per planning horizon."""
horizons = sorted(set(config["scenario"]["planning_horizons"]))
return [DATA + SERVM_LOAD_FILE.format(year=year) for year in horizons]


def demand_raw_data(wildcards):
# get profile to use
end_use = wildcards.end_use
Expand Down Expand Up @@ -346,6 +355,8 @@ def demand_raw_data(wildcards):
return DATA + f"nrel_efs/EFSLoadProfile_{efs_case}_{efs_speed}.csv"
elif profile == "eer":
return DATA + f"eer/{eer_demand_file()}"
elif profile == "servm":
return servm_demand_files()
elif profile == "ferc":
return [
DATA + "pudl/out_ferc714__hourly_estimated_state_demand.parquet",
Expand Down Expand Up @@ -381,13 +392,23 @@ def demand_raw_data(wildcards):


def demand_disaggregate_data(wildcards):
"""CLIU county-level industrial loads are the only disaggregation input.
"""Extra per-profile input needed to spread zonal demand over buses.

All other end uses disaggregate by population and need no extra file.
CLIU county-level industrial loads serve the industry end use; the SERVM
profile needs its precomputed (region, bus) allocation weights. Everything
else disaggregates by population and needs no extra file.
"""
if wildcards.end_use != "industry":
return []
return DATA + "industry_load/2014_update_20170910-0116.csv"
if wildcards.end_use == "industry":
return DATA + "industry_load/2014_update_20170910-0116.csv"
if (
wildcards.end_use == "power"
and config["electricity"]["demand"]["profile"] == "servm"
):
return (
DEMAND
+ f"{wildcards.interconnect}/servm_load_weights_s{wildcards.simpl}.csv"
)
return []


def demand_scaling_data(wildcards):
Expand All @@ -410,6 +431,8 @@ def demand_scaling_data(wildcards):
return []
elif profile == "eer":
return []
elif profile == "servm":
return []
else:
return ""

Expand All @@ -423,14 +446,20 @@ rule build_electrical_demand:
profile_year=pd.to_datetime(config["snapshots"]["start"]).year,
planning_horizons=config["scenario"]["planning_horizons"],
renewable_weather_years=config["renewable_weather_years"],
servm_weather_years=config["electricity"]["demand"]["scenario"].get(
"servm_weather_years", []
),
snapshots=config["snapshots"],
pudl_path=config_provider("pudl_path"),
input:
network=NETWORKS + "{interconnect}/elec_s{simpl}.nc",
demand_files=demand_raw_data,
dissagregate_files=demand_disaggregate_data,
demand_scaling_file=demand_scaling_data,
output:
elec_demand=DEMAND + "{interconnect}/{end_use}_electricity_s{simpl}.csv",
zonal_components=DEMAND
+ "{interconnect}/{end_use}_zonal_components_s{simpl}.parquet",
log:
LOGS + "{interconnect}/{end_use}_build_demand_s{simpl}.log",
benchmark:
Expand Down
34 changes: 34 additions & 0 deletions workflow/rules/retrieve.smk
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,40 @@ rule retrieve_eer_demand_data:
"../scripts/retrieve_eer_data.py"


CPUC_SERVM_URL = "https://files.cpuc.ca.gov/energy/modeling/2026_servm_updates/"


rule retrieve_cpuc_servm_load:
wildcard_constraints:
servm_year="2026|2028|2030|2032|2035|2037|2040|2042|2045",
params:
url=lambda wildcards: CPUC_SERVM_URL
+ f"HourlyLoad_CA_Regions_V2025E_2224_Mon_{wildcards.servm_year}.csv",
output:
DATA + "cpuc/servm/HourlyLoad_CA_Regions_V2025E_2224_Mon_{servm_year}.csv",
resources:
mem_mb=5000,
log:
"logs/retrieve/retrieve_cpuc_servm_load_{servm_year}.log",
retries: 2
script:
"../scripts/retrieve_cpuc_data.py"


rule retrieve_cpuc_baseline_generators:
params:
url=CPUC_SERVM_URL + "BaselineGeneratorList_CAISO.xlsx",
output:
DATA + "cpuc/BaselineGeneratorList_CAISO.xlsx",
resources:
mem_mb=5000,
log:
"logs/retrieve/retrieve_cpuc_baseline_generators.log",
retries: 2
script:
"../scripts/retrieve_cpuc_data.py"


sector_datafiles = [
# heating sector
"population/DECENNIALDHC2020.P1-Data.csv",
Expand Down
Loading