From 824d57503c8e1885b17a2ea675f84565e0b768c0 Mon Sep 17 00:00:00 2001 From: Alex Lee Date: Thu, 8 Oct 2026 03:42:15 +0000 Subject: [PATCH 1/3] Add new option in CT to use Eversource dist MC --- rate_design/hp_rates/ct/Justfile | 21 +- tests/test_expand_month_hour_mc.py | 92 +++++++ .../generate_utility_tx_dx_mc.py | 260 +++++++++++++++++- 3 files changed, 367 insertions(+), 6 deletions(-) create mode 100644 tests/test_expand_month_hour_mc.py diff --git a/rate_design/hp_rates/ct/Justfile b/rate_design/hp_rates/ct/Justfile index e9ad9ada..747c54f0 100644 --- a/rate_design/hp_rates/ct/Justfile +++ b/rate_design/hp_rates/ct/Justfile @@ -14,6 +14,10 @@ set dotenv-path := "state.env" state := env_var_or_default('STATE', 'ct') path_s3_utility_loads := "s3://data.sb/isone/hourly_demand/utilities/" +path_s3_occ863_parquet := "s3://data.sb/switchbox/sources/ct/eversource/docket-26-05-10/occ-863/parquet" +path_local_dist_mc := "/ebs/data/switchbox/marginal_costs/ct/dist_and_sub_tx/" +eversource_mc_year := "2026" +use_eversource_marginal_cost := env_var_or_default('USE_EVERSOURCE_MARGINAL_COST', 'true') import '../Justfile' @@ -126,8 +130,16 @@ create-bulk-tx-mc-data-all *extra_args: # Generate dist+sub-tx MC for ct_eversource and one year. # -# just -f ct/Justfile create-dist-mc-data 2025 -# just -f ct/Justfile create-dist-mc-data 2025 --upload +# By default the 8760 comes from Eversource's OCC-863 Attachment 2 secondary +# month-hour $/kWh tables: weekends and federal holidays take the weekend +# table, other days the weekday table, on year_arg's calendar. It is written +# to year=eversource_mc_year (the rate year of those values), so it never +# overwrites the PoP 8760. Set use_eversource_marginal_cost=false for the PoP +# allocation of the $/kW-yr value, written to year=year_arg. +# +# just -f ct/Justfile create-dist-mc-data 2025 --upload +# just -f ct/Justfile use_eversource_marginal_cost=false create-dist-mc-data 2025 --upload +# USE_EVERSOURCE_MARGINAL_COST=false just s ct create-dist-mc-data 2025 --upload create-dist-mc-data year_arg *extra_args: cd {{ path_repo }} && uv run python {{ path_repo }}/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py \ --state CT \ @@ -137,7 +149,12 @@ create-dist-mc-data year_arg *extra_args: --mc-table-path {{ path_config }}/marginal_costs/ct_marginal_costs_{{ year_arg }}.csv \ --utility-load-s3-base {{ path_s3_utility_loads }} \ --output-s3-base s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/ \ + --path-local-output-base {{ path_local_dist_mc }} \ --n-hours {{ upstream_hours }} \ + --use-eversource-marginal-cost {{ use_eversource_marginal_cost }} \ + --path-weekday-mc {{ path_s3_occ863_parquet }}/month_hour_marginal_costs_weekday_secondary.parquet \ + --path-weekend-mc {{ path_s3_occ863_parquet }}/month_hour_marginal_costs_weekend_holidays_secondary.parquet \ + --eversource-mc-year {{ eversource_mc_year }} \ {{ extra_args }} # ============================================================================= diff --git a/tests/test_expand_month_hour_mc.py b/tests/test_expand_month_hour_mc.py new file mode 100644 index 00000000..491aa3d5 --- /dev/null +++ b/tests/test_expand_month_hour_mc.py @@ -0,0 +1,92 @@ +"""Month-hour marginal costs expanded onto a Cairo 8760.""" + +from __future__ import annotations + +from datetime import datetime + +import polars as pl +import pytest + +from utils.data_prep.marginal_costs.generate_utility_tx_dx_mc import ( + expand_month_hour_mc_to_8760, +) + + +def _table(value_for_month_hour: float, *, weekend: bool) -> pl.DataFrame: + sign = -1.0 if weekend else 1.0 + rows = [ + { + "month": month, + "hour": hour, + "num_days": 1, + "mc_total_per_kwh": sign * (month + hour / 100 + value_for_month_hour), + } + for month in range(1, 13) + for hour in range(24) + ] + return pl.DataFrame(rows) + + +def test_weekday_weekend_and_holiday_lookup() -> None: + expanded = expand_month_hour_mc_to_8760( + _table(0.0, weekend=False), + _table(0.0, weekend=True), + 2025, + "ct_eversource", + ) + assert expanded.columns == ["timestamp", "utility", "year", "mc_total_per_kwh"] + assert expanded.height == 8760 + assert expanded.schema["timestamp"] == pl.Datetime("us") + assert expanded.schema["year"] == pl.Int32 + + def value_at(stamp: str) -> float: + return expanded.filter(pl.col("timestamp") == datetime.fromisoformat(stamp))[ + "mc_total_per_kwh" + ].item() + + # Wednesday that is not a holiday. + assert value_at("2025-01-08 00:00:00") == pytest.approx(1.0) + # New Year's Day and July 4 use the weekend-and-holiday table. + assert value_at("2025-01-01 00:00:00") == pytest.approx(-1.0) + assert value_at("2025-07-04 16:00:00") == pytest.approx(-7.16) + # The Thursday before July 4 stays on the weekday table. + assert value_at("2025-07-03 16:00:00") == pytest.approx(7.16) + # Saturday and Sunday: weekend table, including the spring-forward 02:00 slot. + assert value_at("2025-01-04 16:00:00") == pytest.approx(-1.16) + assert value_at("2025-03-09 02:00:00") == pytest.approx(-3.02) + + +def test_saturday_holiday_is_observed_on_friday() -> None: + expanded = expand_month_hour_mc_to_8760( + _table(0.0, weekend=False), + _table(0.0, weekend=True), + 2026, + "ct_eversource", + ) + + def value_at(stamp: str) -> float: + return expanded.filter(pl.col("timestamp") == datetime.fromisoformat(stamp))[ + "mc_total_per_kwh" + ].item() + + # July 4, 2026 is a Saturday, so Friday July 3 is the observed holiday. + assert value_at("2026-07-03 16:00:00") == pytest.approx(-7.16) + assert value_at("2026-07-06 16:00:00") == pytest.approx(7.16) + + +def test_leap_year_drops_december_31() -> None: + expanded = expand_month_hour_mc_to_8760( + _table(0.0, weekend=False), + _table(0.0, weekend=True), + 2024, + "ct_eversource", + ) + assert expanded.height == 8760 + assert expanded.filter(pl.col("timestamp").dt.month() == 2).height == 29 * 24 + assert ( + expanded.filter( + (pl.col("timestamp").dt.month() == 12) + & (pl.col("timestamp").dt.day() == 31) + ).height + == 0 + ) diff --git a/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py b/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py index 147e8a02..156645fc 100644 --- a/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py +++ b/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py @@ -59,7 +59,7 @@ import argparse import io -from datetime import datetime, timedelta +from datetime import date, datetime, timedelta from pathlib import Path import polars as pl @@ -67,6 +67,7 @@ from dotenv import load_dotenv from utils.data_prep.marginal_costs.supply_utils import ( + build_cairo_8760_timestamps, output_base_for_load_year, remap_year_if_needed, warn_if_multiple_partition_parquets, @@ -253,6 +254,15 @@ def load_marginal_cost_table(mc_table_path: str) -> pl.DataFrame: return df +def _parse_bool(value: str) -> bool: + normalized = value.strip().lower() + if normalized in {"true", "1", "yes"}: + return True + if normalized in {"false", "0", "no"}: + return False + raise argparse.ArgumentTypeError(f"expected true or false, got {value!r}") + + def validate_mc_table_path(mc_table_path: str) -> None: """Fail early if marginal cost table path does not exist.""" if mc_table_path.startswith("s3://"): @@ -455,6 +465,128 @@ def validate_allocation( return validation_results +def expand_month_hour_mc_to_8760( + weekday: pl.DataFrame, + weekend: pl.DataFrame, + year: int, + utility: str, +) -> pl.DataFrame: + """Expand month-hour marginal costs onto one calendar year's Cairo 8760. + + ``weekday`` and ``weekend`` are the OCC-863 Attachment 2 matrices, each with + ``month`` (1–12), ``hour`` (0–23), and ``mc_total_per_kwh``. Saturday, + Sunday, and US federal holidays take the weekend value. A holiday that + falls on Saturday is observed on Friday, and one that falls on Sunday is + observed on Monday. Any other Monday through Friday takes the weekday + value. + + ``year`` is the calendar stamped on the timestamps. It is the output year + of the existing dist-and-sub-tx 8760, which is the year CAIRO joins on. + The PoP load year is not used: this series is a day-of-week lookup, not a + load-weighted allocation. + + Timestamps match ``build_cairo_8760_timestamps``: naive hour-beginning + local time, 8,760 rows, with December 31 dropped in a leap year. + """ + clock = build_cairo_8760_timestamps(year).with_columns( + pl.col("timestamp").cast(pl.Datetime("us")) + ) + holidays = _us_federal_holidays(year) + clock = clock.with_columns( + pl.col("timestamp").dt.month().alias("month"), + pl.col("timestamp").dt.hour().alias("hour"), + # Polars weekday is ISO: Monday = 1, Sunday = 7. + (pl.col("timestamp").dt.weekday() >= 6).alias("is_weekend"), + pl.col("timestamp").dt.date().is_in(sorted(holidays)).alias("is_holiday"), + ) + weekday_rates = _month_hour_rates(weekday, "weekday").rename( + {"mc_total_per_kwh": "weekday_mc"} + ) + weekend_rates = _month_hour_rates(weekend, "weekend").rename( + {"mc_total_per_kwh": "weekend_mc"} + ) + joined = clock.join(weekday_rates, on=["month", "hour"], how="left").join( + weekend_rates, on=["month", "hour"], how="left" + ) + expanded = joined.with_columns( + pl.when(pl.col("is_weekend") | pl.col("is_holiday")) + .then(pl.col("weekend_mc")) + .otherwise(pl.col("weekday_mc")) + .alias("mc_total_per_kwh") + ) + if expanded["mc_total_per_kwh"].null_count() != 0: + raise ValueError(f"month-hour lookup missed hours in {year}") + return expanded.select( + "timestamp", + pl.lit(utility).alias("utility"), + pl.lit(year).cast(pl.Int32).alias("year"), + "mc_total_per_kwh", + ) + + +def _us_federal_holidays(year: int) -> set[date]: + """US federal holidays observed during ``year``. + + The eleven holidays in 5 U.S.C. § 6103. A fixed-date holiday on Saturday is + observed the Friday before, and one on Sunday the Monday after. That + observed set is what Attachment 2's weekend-and-holiday day counts match + for 2025. + """ + fixed = [ + date(year, 1, 1), + date(year, 6, 19), + date(year, 7, 4), + date(year, 11, 11), + date(year, 12, 25), + date(year + 1, 1, 1), + ] + floating = [ + _nth_weekday(year, 1, 0, 3), + _nth_weekday(year, 2, 0, 3), + _nth_weekday(year, 5, 0, -1), + _nth_weekday(year, 9, 0, 1), + _nth_weekday(year, 10, 0, 2), + _nth_weekday(year, 11, 3, 4), + ] + observed = {_observe_holiday(day) for day in fixed + floating} + return {day for day in observed if day.year == year} + + +def _nth_weekday(year: int, month: int, weekday: int, n: int) -> date: + """The nth ``weekday`` of ``month`` (Monday = 0). ``n`` of -1 is the last.""" + if n > 0: + first = date(year, month, 1) + shift = (weekday - first.weekday()) % 7 + return first + timedelta(days=shift + 7 * (n - 1)) + if month == 12: + last = date(year, 12, 31) + else: + last = date(year, month + 1, 1) - timedelta(days=1) + return last - timedelta(days=(last.weekday() - weekday) % 7) + + +def _observe_holiday(day: date) -> date: + if day.weekday() == 5: + return day - timedelta(days=1) + if day.weekday() == 6: + return day + timedelta(days=1) + return day + + +def _month_hour_rates(frame: pl.DataFrame, label: str) -> pl.DataFrame: + required = {"month", "hour", "mc_total_per_kwh"} + missing = required - set(frame.columns) + if missing: + raise ValueError(f"{label} month-hour table is missing {sorted(missing)}") + rates = frame.select("month", "hour", "mc_total_per_kwh") + n_unique = rates.select("month", "hour").n_unique() + if rates.height != 12 * 24 or n_unique != rates.height: + raise ValueError( + f"{label} month-hour table must have 288 unique month-hour rows" + ) + return rates + + def save_allocated_costs( df: pl.DataFrame, utility: str, @@ -462,6 +594,7 @@ def save_allocated_costs( s3_base: str, validation_results: dict, storage_options: dict[str, str], + path_local_base: str | None = None, ): """Save allocated marginal costs to S3 with Hive-style partitioning. @@ -471,13 +604,15 @@ def save_allocated_costs( Args: df: DataFrame with allocated costs utility: Utility name - year: Output year for the Hive partition and timestamps. This is also - the default target dollar year of the allocated ``$/kW-yr`` (CPI - inflation to this year happens before save). Distinct from the + year: Output year for the Hive partition and the ``year`` column. For + the PoP allocation this is also the timestamp year and the default + target dollar year of the allocated ``$/kW-yr``. Distinct from the PoP allocation load year. s3_base: Base S3 path for marginal costs validation_results: Validation results (unused, kept for interface consistency) storage_options: Polars S3 storage options with AWS bucket region + path_local_base: Optional local mirror of ``s3_base``; the same + ``utility=X/year=YYYY/data.parquet`` is written there too. """ output_df = df.select( [ @@ -518,6 +653,16 @@ def save_allocated_costs( ) print(f"\n✓ Saved allocated costs to {output_path}") + if path_local_base: + path_local = ( + Path(path_local_base) + / f"utility={utility}" + / f"year={year}" + / "data.parquet" + ) + path_local.parent.mkdir(parents=True, exist_ok=True) + output_df.write_parquet(path_local) + print(f"✓ Saved local copy to {path_local}") print(f" Rows: {len(output_df):,}") print(f" Columns: {', '.join(output_df.columns)}") @@ -605,12 +750,57 @@ def main(): action="store_true", help="Upload results to S3 (default: False, for data inspection only)", ) + parser.add_argument( + "--use-eversource-marginal-cost", + type=_parse_bool, + default=False, + metavar="{true,false}", + help=( + "true: build the 8760 from Eversource's OCC-863 Attachment 2 " + "month-hour $/kWh tables (weekday vs. weekend-and-holiday). " + "false: PoP allocation of the $/kW-yr value. CT only; default false." + ), + ) + parser.add_argument( + "--path-weekday-mc", + type=str, + default=None, + help="Month-hour weekday $/kWh parquet (with --use-eversource-marginal-cost)", + ) + parser.add_argument( + "--path-weekend-mc", + type=str, + default=None, + help=( + "Month-hour weekend-and-holiday $/kWh parquet " + "(with --use-eversource-marginal-cost)" + ), + ) + parser.add_argument( + "--eversource-mc-year", + type=int, + default=None, + help=( + "Partition year for the Eversource 8760: the rate year of the " + "Attachment 2 values. Timestamps still use --year's calendar." + ), + ) + parser.add_argument( + "--path-local-output-base", + type=str, + default=None, + help="Local mirror of --output-s3-base; with --upload, also write there", + ) args = parser.parse_args() validate_mc_table_path(args.mc_table_path) load_dotenv() storage_options = get_aws_storage_options() + if args.use_eversource_marginal_cost: + _run_eversource_month_hour(args, storage_options) + return + output_year = args.year load_year = args.load_year if args.load_year else output_year target_dollar_year = ( @@ -705,6 +895,7 @@ def main(): output_s3_base, validation_results, storage_options, + path_local_base=args.path_local_output_base, ) print("\n" + "=" * 60) print("✓ Marginal cost allocation completed and uploaded") @@ -716,5 +907,66 @@ def main(): print("=" * 60) +def _run_eversource_month_hour( + args: argparse.Namespace, storage_options: dict[str, str] +) -> None: + """Build and optionally save the 8760 from OCC-863 month-hour tables.""" + if args.state != "CT": + raise ValueError("--use-eversource-marginal-cost is only defined for CT") + if not (args.path_weekday_mc and args.path_weekend_mc and args.eversource_mc_year): + raise ValueError( + "--use-eversource-marginal-cost needs --path-weekday-mc, " + "--path-weekend-mc, and --eversource-mc-year" + ) + calendar_year = args.year + partition_year = args.eversource_mc_year + + print("=" * 60) + print("EVERSOURCE MONTH-HOUR MARGINAL COST → 8760") + print("=" * 60) + print(f"Utility: {args.utility}") + print(f"Calendar year (weekday/weekend/holiday): {calendar_year}") + print(f"Partition year: {partition_year}") + print(f"Weekday table: {args.path_weekday_mc}") + print(f"Weekend-and-holiday table: {args.path_weekend_mc}") + print(f"Output S3 base: {args.output_s3_base}") + print(f"Upload to S3: {'Yes' if args.upload else 'No (inspection only)'}") + print("=" * 60) + + weekday = _read_parquet_any(args.path_weekday_mc, storage_options) + weekend = _read_parquet_any(args.path_weekend_mc, storage_options) + expanded = expand_month_hour_mc_to_8760( + weekday, weekend, calendar_year, args.utility + ) + + annual = float(expanded["mc_total_per_kwh"].sum()) + nonzero = expanded.filter(pl.col("mc_total_per_kwh") > 0).height + print(f"\n Rows: {expanded.height:,}") + print(f" Hours with nonzero MC: {nonzero:,}") + print(f" Sum over 8760 (flat 1 kW, $/kW-yr): ${annual:.4f}") + print("\nTop 10 hours by marginal cost:") + print(expanded.sort("mc_total_per_kwh", descending=True).head(10)) + + if args.upload: + save_allocated_costs( + expanded, + args.utility, + partition_year, + args.output_s3_base, + {}, + storage_options, + path_local_base=args.path_local_output_base, + ) + print("\n✓ Eversource month-hour 8760 completed and uploaded") + else: + print("\n⚠️ No data uploaded to S3 (use --upload flag to enable)") + + +def _read_parquet_any(path: str, storage_options: dict[str, str]) -> pl.DataFrame: + if path.startswith("s3://"): + return pl.read_parquet(path, storage_options=storage_options) + return pl.read_parquet(path) + + if __name__ == "__main__": main() From 95f79985486068d4e86369cbfdf533d08f2d1592 Mon Sep 17 00:00:00 2001 From: Alex Lee Date: Thu, 8 Oct 2026 16:17:08 +0000 Subject: [PATCH 2/3] Make include holiday optional, update output file path for eversource derived dist MC --- context/README.md | 24 ++-- .../ct_eversource_dist_mc_methodology.md | 101 ++++++++++++++-- .../dist_mc_definition_choice.md | 7 +- rate_design/hp_rates/ct/Justfile | 17 +-- .../ct_eversource_hp_vs_non-hp.yaml | 28 ++--- .../scenarios/pipeline_ct_eversource.yaml | 2 +- .../scenarios/scenarios_ct_eversource.yaml | 112 +++++++++--------- ...ource_hp_flat_percustomer_passthrough.json | 2 +- ...at_percustomer_passthrough_calibrated.json | 2 +- ...p_flat_percustomer_passthrough_supply.json | 2 +- ...ustomer_passthrough_supply_calibrated.json | 2 +- ...e_hp_seasonal_percustomer_passthrough.json | 2 +- ...al_percustomer_passthrough_calibrated.json | 4 +- ...asonal_percustomer_passthrough_supply.json | 4 +- ...ustomer_passthrough_supply_calibrated.json | 4 +- ...se_percustomer_passthrough_calibrated.json | 6 +- ...ustomer_passthrough_supply_calibrated.json | 8 +- tests/test_expand_month_hour_mc.py | 45 +++++++ .../generate_utility_tx_dx_mc.py | 91 +++++++++----- 19 files changed, 317 insertions(+), 146 deletions(-) diff --git a/context/README.md b/context/README.md index 79e71ac8..6b48c2b6 100644 --- a/context/README.md +++ b/context/README.md @@ -77,18 +77,18 @@ Cost-reflective TOU design: theory and window optimization. How we derive BAT marginal-cost inputs from regulatory studies. -| File | Purpose | -| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ny_dist_mc_bat_methodology.md | Shared methodology for deriving sub-TX and distribution BAT marginal cost inputs from the seven NY MCOS workbooks: pipeline overview, key conceptual choices (incremental not cumulative, levelized 7-year window, no discounting, 2026 dollar year), per-utility deviations and harmonization, final values and sanity check, research appendices. | -| ny_mcos_studies_comparison.md | Cross-utility comparison of the seven NY 2025 MCOS studies: what MCOS numbers mean (undiluted/diluted, grid topology), methodology comparison, annualization mechanics (workbook-verified step-by-step), system-wide diluted/undiluted tables, component taxonomy mapping (physical hierarchy → cost-center labels), bulk vs local TX scrub, reassessment of bulk TX MC gap. | -| ny_bulk_transmission_marginal_cost.md | How to construct bulk TX marginal cost for NY BAT: the gap, data sources (OATT ATRR, CLCPA project costs, FERC Order 1920), five options with tradeoffs, recommended approach (OATT as upper-bound proxy), hourly PoP allocation. | -| ri_bulk_transmission_marginal_cost.md | How to construct bulk TX marginal cost for RI BAT: data sources (RNS rate, AESC 2024 avoided PTF cost, ISO-NE 2050 study), four options with tradeoffs, recommended approach (AESC primary, RNS upper bound), hourly PoP allocation, comparison with NY. | -| ct_bulk_transmission_marginal_cost.md | How to construct bulk TX marginal cost for CT BAT: same AESC 2024 $69/kW-year and top-100 exceedance as RI, plus `--allocation-load` flag to toggle between NE system aggregate and CT zone load for peak-hour identification; utilities `ct_eversource` and `ct_ui`; implementation files and Just commands. | -| capacity_market_comparison_nyiso_isone.md | Comparison of NYISO ICAP (Strip/Monthly/Spot) vs ISO-NE FCM (FCA/ARA/MRA) capacity market structures: structural analogy table, forward horizons, price volatility differences, implications for BAT marginal cost signal (Spot vs FCA vs MRA), current approach in NY vs RI, trade-offs. | -| dist_mc_definition_choice.md | Cross-cutting: which LRMC definition the `sub_tx_and_dist` BAT input uses, and why it differs by state. Taxonomy (Turvey / AIC-avoided / FLIC) and why AIC and FLIC differ ~10-50x, source-number table (NY FLIC $1-8, RI AESC $80, BGE Brattle $32, BGE E3 $203-258, OPC $25-34, BAT paper $54.46), what is implemented per state (NY=FLIC, RI/MD=avoided), the platform tension (NY-vs-RI/MD; methodology-doc §3-vs-§7), rationale, and BGE sensitivities. | -| md_bge_dist_mc_methodology.md | BGE (MD) sub-TX + distribution MC implementation: adopts Brattle avoided distribution cost $32/kW-yr (2022$), RI-style single-scalar config + CPI handling, why avoided cost is consistent with BGE's own peak-driven COS, the ~82% volumetric over-recovery intervention hook, FLIC/E3 sensitivities, and the Stage-B allocator MD-enablement dependency. | -| ct_eversource_dist_mc_methodology.md | eversource (CT) sub-TX + dist MC: how to derive CL&P/Eversource CT's `sub_tx_and_dist` MC from Exhibits CLP-MCOS-1/2. Stage A: system-wide diluted $20.17/kW-yr (Table 3) vs locational $86.58/kW-yr, why diluted mirrors NY's FLIC convention. Stage B: CL&P's own hourly probability-of-peak method (std-dev of 2022-2025 substation load, BTM solar/HP-adoption forecast adjustment) vs. what data we actually have (Table 2A TOU/season buckets only — Back-Up 36's raw PoP curve is listed in the TOC but not in the PDF); Tier 1 TOU-bucket mapping (implementable now) vs Tier 2 load-based PoP proxy (stretch); task list and open questions (UI gap, locational sensitivity, TOU-window confirmation). | -| md_bulk_transmission.md | How to construct bulk TX marginal cost for MD BAT: PJM NITS rates as OATT ATRR proxy (E3 ICC-VDER precedent), zone-to-utility mapping (BGE/DPL/PEPCO/APS covering all 13 MD utilities), calendar-year day-weighted blending, full-year top-150 PCAF allocation (following E3), reference data at `data/pjm/bulk_tx/nits/`, implementation in `bulk_tx_pjm.py`. | +| File | Purpose | +| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ny_dist_mc_bat_methodology.md | Shared methodology for deriving sub-TX and distribution BAT marginal cost inputs from the seven NY MCOS workbooks: pipeline overview, key conceptual choices (incremental not cumulative, levelized 7-year window, no discounting, 2026 dollar year), per-utility deviations and harmonization, final values and sanity check, research appendices. | +| ny_mcos_studies_comparison.md | Cross-utility comparison of the seven NY 2025 MCOS studies: what MCOS numbers mean (undiluted/diluted, grid topology), methodology comparison, annualization mechanics (workbook-verified step-by-step), system-wide diluted/undiluted tables, component taxonomy mapping (physical hierarchy → cost-center labels), bulk vs local TX scrub, reassessment of bulk TX MC gap. | +| ny_bulk_transmission_marginal_cost.md | How to construct bulk TX marginal cost for NY BAT: the gap, data sources (OATT ATRR, CLCPA project costs, FERC Order 1920), five options with tradeoffs, recommended approach (OATT as upper-bound proxy), hourly PoP allocation. | +| ri_bulk_transmission_marginal_cost.md | How to construct bulk TX marginal cost for RI BAT: data sources (RNS rate, AESC 2024 avoided PTF cost, ISO-NE 2050 study), four options with tradeoffs, recommended approach (AESC primary, RNS upper bound), hourly PoP allocation, comparison with NY. | +| ct_bulk_transmission_marginal_cost.md | How to construct bulk TX marginal cost for CT BAT: same AESC 2024 $69/kW-year and top-100 exceedance as RI, plus `--allocation-load` flag to toggle between NE system aggregate and CT zone load for peak-hour identification; utilities `ct_eversource` and `ct_ui`; implementation files and Just commands. | +| capacity_market_comparison_nyiso_isone.md | Comparison of NYISO ICAP (Strip/Monthly/Spot) vs ISO-NE FCM (FCA/ARA/MRA) capacity market structures: structural analogy table, forward horizons, price volatility differences, implications for BAT marginal cost signal (Spot vs FCA vs MRA), current approach in NY vs RI, trade-offs. | +| dist_mc_definition_choice.md | Cross-cutting: which LRMC definition the `sub_tx_and_dist` BAT input uses, and why it differs by state. Taxonomy (Turvey / AIC-avoided / FLIC) and why AIC and FLIC differ ~10-50x, source-number table (NY FLIC $1-8, RI AESC $80, BGE Brattle $32, BGE E3 $203-258, OPC $25-34, BAT paper $54.46), what is implemented per state (NY=FLIC, RI/MD=avoided), the platform tension (NY-vs-RI/MD; methodology-doc §3-vs-§7), rationale, and BGE sensitivities. | +| md_bge_dist_mc_methodology.md | BGE (MD) sub-TX + distribution MC implementation: adopts Brattle avoided distribution cost $32/kW-yr (2022$), RI-style single-scalar config + CPI handling, why avoided cost is consistent with BGE's own peak-driven COS, the ~82% volumetric over-recovery intervention hook, FLIC/E3 sensitivities, and the Stage-B allocator MD-enablement dependency. | +| ct_eversource_dist_mc_methodology.md | Eversource (CT) sub-TX + dist MC. Stage A: MCOS-2 Table 3 system-wide diluted $20.17/kW-yr vs locational $86.58/kW-yr. Default 8760 (§6): OCC-863 Attachment 2 secondary month-hour $/kWh tables expanded by weekday/weekend, with `include_holidays` (default true; federal holidays, Saturday observed Friday and Sunday observed Monday). One `--year` for the calendar, timestamps, and Hive partition, written to `dist_and_sub_tx_eversource_derived/`. Fallback (§3): PoP of the $20.17 figure to `dist_and_sub_tx/` when `use_eversource_marginal_cost=false`. | +| md_bulk_transmission.md | How to construct bulk TX marginal cost for MD BAT: PJM NITS rates as OATT ATRR proxy (E3 ICC-VDER precedent), zone-to-utility mapping (BGE/DPL/PEPCO/APS covering all 13 MD utilities), calendar-year day-weighted blending, full-year top-150 PCAF allocation (following E3), reference data at `data/pjm/bulk_tx/nits/`, implementation in `bulk_tx_pjm.py`. | ### methods/ (root) diff --git a/context/methods/marginal_costs/ct_eversource_dist_mc_methodology.md b/context/methods/marginal_costs/ct_eversource_dist_mc_methodology.md index 6501afec..313ae285 100644 --- a/context/methods/marginal_costs/ct_eversource_dist_mc_methodology.md +++ b/context/methods/marginal_costs/ct_eversource_dist_mc_methodology.md @@ -2,11 +2,13 @@ **Status: IMPLEMENTED.** This document lays out how the `sub_tx_and_dist` BAT marginal-cost input for Eversource CT (CL&P) is derived from the two MCOS exhibits, and how it is allocated to an 8760 -hourly signal. The config CSV, allocator wiring, and S3 output described below exist and have been -run; see §3.4 for the implementation notes (including two upstream data gaps — ISO-NE utility-level -load and 2026 CPI data — that had to be filled first). Only CT **bulk transmission** MC was -implemented before this -([ct_bulk_transmission_marginal_cost.md](ct_bulk_transmission_marginal_cost.md)). +hourly signal. Two 8760s exist. The default `create-dist-mc-data` recipe expands Eversource's +OCC-863 Attachment 2 month-hour `$/kWh` tables (§6). The older path PoP-allocates the MCOS-2 +Table 3 `$20.17/kW-yr` figure (§3) and is what `use_eversource_marginal_cost=false` still runs. +The config CSV, allocator wiring, and S3 output described below exist and have been run; see §3.4 +for the PoP implementation notes (including two upstream data gaps — ISO-NE utility-level load and +2026 CPI data — that had to be filled first). Only CT **bulk transmission** MC was implemented +before this ([ct_bulk_transmission_marginal_cost.md](ct_bulk_transmission_marginal_cost.md)). For the underlying LRMC framework and cross-state definition choice, see [dist_mc_definition_choice.md](dist_mc_definition_choice.md). For the BGE/RI implementation pattern @@ -100,6 +102,12 @@ the existing CPI-inflation logic in `generate_utility_tx_dx_mc.py` handle any ru ## 3. Stage B — hourly allocation via Probability of Peak (PoP) +This is the fallback, not the default. `create-dist-mc-data` runs it only when +`use_eversource_marginal_cost=false` (or `USE_EVERSOURCE_MARGINAL_COST=false` through +`just s ct`). It writes `dist_and_sub_tx/utility=ct_eversource/year=/data.parquet`. +The default recipe is the OCC-863 month-hour expansion in §6, which does not use the +`$20.17/kW-yr` figure or the load curve. + ### 3.1 Method: standard PoP allocation (same as NY, RI, MD) Use the same Probability of Peak (PoP) allocation method already implemented in @@ -269,7 +277,82 @@ allocation or as a direct replacement. This is a nice-to-have, not a blocker for `tests/test_ct_dist_mc.py`. 6. ~~Update this doc and [dist_mc_definition_choice.md](dist_mc_definition_choice.md) §2–3, adding CT to the source-number and per-state tables.~~ Done. -7. **Remaining**: wire `path_dist_and_sub_tx_mc` into a CT scenario config (`scenarios_ct_eversource.yaml` - or equivalent) once CT scenario YAMLs exist, so a CAIRO run actually consumes this MC output. No CT - scenario configs exist yet in `rate_design/hp_rates/ct/config/scenarios/` — that's a separate, - larger piece of CT onboarding beyond this MC-generation task. +7. **CAIRO consumption.** `pipeline_ct_eversource.yaml` points + `marginal_costs.dist_and_sub_tx` at + `s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet`. + That file predates the §6 path split: its timestamps are the 2025 calendar and its `year` + column is 2026. Batch `ct_20261007_b` read it. New default runs of `create-dist-mc-data` write + §6's `dist_and_sub_tx_eversource_derived/` path instead and do not replace this file. + +--- + +## 6. OCC-863 Attachment 2 month-hour 8760 (current default) + +`create-dist-mc-data` defaults to `--use-eversource-marginal-cost true`. It does not +PoP-allocate §2's `$20.17/kW-yr`. It looks up each hour of one calendar year in Eversource's +OCC-863 Attachment 2 secondary month-hour `$/kWh` tables (Docket 26-05-10) and writes an 8760 +in the same schema as the PoP file (`timestamp`, `utility`, `year`, `mc_total_per_kwh`). + +The tables live at +`s3://data.sb/switchbox/sources/ct/eversource/docket-26-05-10/occ-863/parquet/`: + +- `month_hour_marginal_costs_weekday_secondary.parquet` +- `month_hour_marginal_costs_weekend_holidays_secondary.parquet` + +Each has 288 rows (`month` 1–12, `hour` 0–23, `num_days`, `mc_total_per_kwh`). The recipe uses +the **secondary** voltage pair. Implementation is `expand_month_hour_mc_to_8760` in +`utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py`. + +### 6.1 Day type + +Saturday and Sunday take the weekend-and-holiday table. Every other Monday–Friday takes the +weekday table, except federal holidays when holidays are included. + +`include_holidays` defaults to `true`. Those holidays are the eleven dates in 5 U.S.C. § 6103. +A fixed-date holiday that falls on Saturday is observed the Friday before, and one that falls +on Sunday is observed the Monday after. With `include_holidays=false`, a holiday on +Monday–Friday stays on the weekday table; Saturday and Sunday are unchanged. + +```bash +just -f ct/Justfile create-dist-mc-data 2025 --upload +just -f ct/Justfile include_holidays=false create-dist-mc-data 2025 --upload +INCLUDE_HOLIDAYS=false just s ct create-dist-mc-data 2025 --upload +``` + +### 6.2 One year for the calendar, the timestamps, and the partition + +`--year` (the recipe's `year_arg`) is the only year. It chooses the calendar used to classify +weekdays, weekends, and holidays, and it is stamped on `timestamp`, on the `year` column, and +on the Hive partition `year=YYYY`. There is no separate partition year. + +CAIRO does not join this file to the run on the timestamp year. When both series have 8,760 +hours, `utils/cairo.py`'s `_align_mc_to_index` copies the marginal-cost values by position onto +the run's hours. Hour 0 of the file lands on January 1 at midnight of the run. For weekends and +holidays to fall on the right days, `--year` has to be the run's calendar. The CT pipeline year +is 2025. A leap year still emits 8,760 rows (December 31 is dropped), but its positions diverge +from a non-leap run after February 28. + +### 6.3 Where it is written + +With the flag true, the script rewrites an output base that ends in `dist_and_sub_tx/` to +`dist_and_sub_tx_eversource_derived/`. The recipe still passes the `dist_and_sub_tx/` base; the +redirect is what keeps this file off the PoP path. + +```text +s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx_eversource_derived/utility=ct_eversource/year=YYYY/data.parquet +/ebs/data/switchbox/marginal_costs/ct/dist_and_sub_tx_eversource_derived/utility=ct_eversource/year=YYYY/data.parquet +``` + +`use_eversource_marginal_cost=false` leaves the base alone and writes the §3 PoP file: + +```text +s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=YYYY/data.parquet +``` + +```bash +just -f ct/Justfile use_eversource_marginal_cost=false create-dist-mc-data 2025 --upload +USE_EVERSOURCE_MARGINAL_COST=false just s ct create-dist-mc-data 2025 --upload +``` + +Tests for the lookup, the observed-holiday rule, the holiday toggle, leap-year length, and the +output-base rewrite are in `tests/test_expand_month_hour_mc.py`. diff --git a/context/methods/marginal_costs/dist_mc_definition_choice.md b/context/methods/marginal_costs/dist_mc_definition_choice.md index 0ee632de..ee408803 100644 --- a/context/methods/marginal_costs/dist_mc_definition_choice.md +++ b/context/methods/marginal_costs/dist_mc_definition_choice.md @@ -88,10 +88,13 @@ locational figure (`$86.58`) is itself much larger than NY's undiluted MCOS figu | **MD (BGE)** | **AIC / avoided** (Brattle replacement-value ÷ peak) | 32 (2022$) | BGE's own COS classifies the plant 100% peak-driven; BGE's own marginal numbers use a peak denominator (see §5) | | CT (ct_eversource / CL&P) | **FLIC-like** (system-wide diluted from MCOS-2 Table 3) | 20.17 (2026$) | CL&P's own MCOS dilutes locational cost by expansion-area load share, structurally the same move as NY's diluted FLIC (see [ct_eversource_dist_mc_methodology.md](ct_eversource_dist_mc_methodology.md) §2) | -All four feed the _same_ PoP allocator +NY, RI, and MD feed the same PoP allocator ([generate_utility_tx_dx_mc.py](../../../utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py)) in the identical `sub_tx_and_dist_mc_kw_yr` slot, with CPI inflation via the optional `dollar_year` -column. +column. CT's `$20.17` figure is that allocator's input only when +`use_eversource_marginal_cost=false`. The default CT 8760 is the OCC-863 Attachment 2 +month-hour expansion, which does not use this scalar +([ct_eversource_dist_mc_methodology.md](ct_eversource_dist_mc_methodology.md) §6). --- diff --git a/rate_design/hp_rates/ct/Justfile b/rate_design/hp_rates/ct/Justfile index 747c54f0..6ab6356b 100644 --- a/rate_design/hp_rates/ct/Justfile +++ b/rate_design/hp_rates/ct/Justfile @@ -16,8 +16,8 @@ state := env_var_or_default('STATE', 'ct') path_s3_utility_loads := "s3://data.sb/isone/hourly_demand/utilities/" path_s3_occ863_parquet := "s3://data.sb/switchbox/sources/ct/eversource/docket-26-05-10/occ-863/parquet" path_local_dist_mc := "/ebs/data/switchbox/marginal_costs/ct/dist_and_sub_tx/" -eversource_mc_year := "2026" use_eversource_marginal_cost := env_var_or_default('USE_EVERSOURCE_MARGINAL_COST', 'true') +include_holidays := env_var_or_default('INCLUDE_HOLIDAYS', 'true') import '../Justfile' @@ -131,14 +131,17 @@ create-bulk-tx-mc-data-all *extra_args: # Generate dist+sub-tx MC for ct_eversource and one year. # # By default the 8760 comes from Eversource's OCC-863 Attachment 2 secondary -# month-hour $/kWh tables: weekends and federal holidays take the weekend -# table, other days the weekday table, on year_arg's calendar. It is written -# to year=eversource_mc_year (the rate year of those values), so it never -# overwrites the PoP 8760. Set use_eversource_marginal_cost=false for the PoP -# allocation of the $/kW-yr value, written to year=year_arg. +# month-hour $/kWh tables: weekends take the weekend table, and federal +# holidays do too unless include_holidays=false. Other days take the weekday +# table, on year_arg's calendar. That same year is stamped on the timestamps +# and on the Hive partition. The file is written under +# dist_and_sub_tx_eversource_derived/, so it never overwrites the PoP 8760. +# Set use_eversource_marginal_cost=false for the PoP allocation of the +# $/kW-yr value, written under dist_and_sub_tx/year=year_arg. # # just -f ct/Justfile create-dist-mc-data 2025 --upload # just -f ct/Justfile use_eversource_marginal_cost=false create-dist-mc-data 2025 --upload +# just -f ct/Justfile include_holidays=false create-dist-mc-data 2025 --upload # USE_EVERSOURCE_MARGINAL_COST=false just s ct create-dist-mc-data 2025 --upload create-dist-mc-data year_arg *extra_args: cd {{ path_repo }} && uv run python {{ path_repo }}/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py \ @@ -154,7 +157,7 @@ create-dist-mc-data year_arg *extra_args: --use-eversource-marginal-cost {{ use_eversource_marginal_cost }} \ --path-weekday-mc {{ path_s3_occ863_parquet }}/month_hour_marginal_costs_weekday_secondary.parquet \ --path-weekend-mc {{ path_s3_occ863_parquet }}/month_hour_marginal_costs_weekend_holidays_secondary.parquet \ - --eversource-mc-year {{ eversource_mc_year }} \ + --include-holidays {{ include_holidays }} \ {{ extra_args }} # ============================================================================= diff --git a/rate_design/hp_rates/ct/config/rev_requirement/ct_eversource_hp_vs_non-hp.yaml b/rate_design/hp_rates/ct/config/rev_requirement/ct_eversource_hp_vs_non-hp.yaml index 2a8de7f0..9ccca507 100644 --- a/rate_design/hp_rates/ct/config/rev_requirement/ct_eversource_hp_vs_non-hp.yaml +++ b/rate_design/hp_rates/ct/config/rev_requirement/ct_eversource_hp_vs_non-hp.yaml @@ -1,6 +1,6 @@ utility: ct_eversource group_col: has_hp -source_run_dir: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/20261001_142749_ct_ct_eversource_default_precalc_delivery +source_run_dir: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/20261008_034607_ct_ct_eversource_default_precalc_delivery test_year_customer_count: 1182119.1 resstock_kwh_scale_factor: 0.9935444283506427 total_delivery_revenue_requirement: 1689584509.3 @@ -8,24 +8,24 @@ total_delivery_and_supply_revenue_requirement: 2742274995.0 subclass_revenue_requirements: delivery: percustomer: - non-hp: 1633529947.9599276 - hp: 56054561.340073064 + non-hp: 1633487601.6676385 + hp: 56096907.6323621 epmc: - non-hp: 1619587472.4360082 - hp: 69997036.86399275 + non-hp: 1619392505.1629734 + hp: 70192004.13702734 volumetric: - non-hp: 1595672197.662744 - hp: 93912311.63725626 + non-hp: 1595703498.2323527 + hp: 93881011.06764789 passthrough: non-hp: 1596231837.1069303 - hp: 93352672.19307567 + hp: 93352672.19307566 supply: passthrough: - non-hp: 992561380.9702992 - hp: 60129104.72970189 + non-hp: 992561380.9702997 + hp: 60129104.72970188 percustomer: - non-hp: 1018483250.363605 - hp: 34207235.33639449 + non-hp: 1018483250.3636048 + hp: 34207235.33639446 volumetric: - non-hp: 992948182.3618731 - hp: 59742303.33812502 + non-hp: 992948182.3618727 + hp: 59742303.338125005 diff --git a/rate_design/hp_rates/ct/config/scenarios/pipeline_ct_eversource.yaml b/rate_design/hp_rates/ct/config/scenarios/pipeline_ct_eversource.yaml index e7804ffb..f68925e7 100644 --- a/rate_design/hp_rates/ct/config/scenarios/pipeline_ct_eversource.yaml +++ b/rate_design/hp_rates/ct/config/scenarios/pipeline_ct_eversource.yaml @@ -15,7 +15,7 @@ resstock: upgrade_precalc: "00" upgrade_calibrated: "02" marginal_costs: - dist_and_sub_tx: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + dist_and_sub_tx: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet bulk_tx: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet # No supply MC 8760s exist for CT (no ISO-NE LMP/FCM pipeline wired up yet); # point directly at zero.parquet so both delivery and supply runs get zero supply MCs. diff --git a/rate_design/hp_rates/ct/config/scenarios/scenarios_ct_eversource.yaml b/rate_design/hp_rates/ct/config/scenarios/scenarios_ct_eversource.yaml index d62acc1e..2539afa0 100644 --- a/rate_design/hp_rates/ct/config/scenarios/scenarios_ct_eversource.yaml +++ b/rate_design/hp_rates/ct/config/scenarios/scenarios_ct_eversource.yaml @@ -12,11 +12,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_default.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_precalc_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_precalc_delivery utility_revenue_requirement: rev_requirement/ct_eversource_rate_case_test_year.yaml run_includes_supply: false run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -39,11 +39,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_default_supply.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_precalc_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_precalc_supply utility_revenue_requirement: rev_requirement/ct_eversource_rate_case_test_year.yaml run_includes_supply: true run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -66,11 +66,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_default_calibrated.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_calibrated_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_calibrated_delivery utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_test_year.yaml run_includes_supply: false run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -93,11 +93,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_default_supply_calibrated.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_calibrated_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_calibrated_supply utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_test_year.yaml run_includes_supply: true run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -120,11 +120,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate1_proposed.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r1_uncalibrated_precalc_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r1_uncalibrated_precalc_delivery utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: false run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -147,11 +147,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate1_proposed_supply.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r1_uncalibrated_precalc_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r1_uncalibrated_precalc_supply utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: true run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -174,11 +174,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate1_proposed.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r1_uncalibrated_calibrated_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r1_uncalibrated_calibrated_delivery utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: false run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -201,11 +201,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate1_proposed_supply.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r1_uncalibrated_calibrated_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r1_uncalibrated_calibrated_supply utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: true run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -228,11 +228,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate6.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r6_uncalibrated_precalc_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r6_uncalibrated_precalc_delivery utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: false run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -255,11 +255,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate6_supply.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r6_uncalibrated_precalc_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r6_uncalibrated_precalc_supply utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: true run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -282,11 +282,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate6.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r6_uncalibrated_calibrated_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r6_uncalibrated_calibrated_delivery utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: false run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -309,11 +309,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate6_supply.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r6_uncalibrated_calibrated_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r6_uncalibrated_calibrated_supply utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: true run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -336,11 +336,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate6_ratemc.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r6_ratemc_uncalibrated_precalc_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r6_ratemc_uncalibrated_precalc_delivery utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: false run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -363,11 +363,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate6_ratemc_supply.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r6_ratemc_uncalibrated_precalc_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r6_ratemc_uncalibrated_precalc_supply utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: true run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -390,11 +390,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate6_ratemc.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r6_ratemc_uncalibrated_calibrated_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r6_ratemc_uncalibrated_calibrated_delivery utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: false run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -417,11 +417,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate6_ratemc_supply.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r6_ratemc_uncalibrated_calibrated_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r6_ratemc_uncalibrated_calibrated_supply utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: true run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -444,11 +444,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate6_fixed_ratemc.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r6_fixed_ratemc_uncalibrated_precalc_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r6_fixed_ratemc_uncalibrated_precalc_delivery utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: false run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -471,11 +471,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate6_fixed_ratemc_supply.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r6_fixed_ratemc_uncalibrated_precalc_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r6_fixed_ratemc_uncalibrated_precalc_supply utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: true run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -498,11 +498,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate6_fixed_ratemc.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r6_fixed_ratemc_uncalibrated_calibrated_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r6_fixed_ratemc_uncalibrated_calibrated_delivery utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: false run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -525,11 +525,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_rate6_fixed_ratemc_supply.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_default_ry1_r6_fixed_ratemc_uncalibrated_calibrated_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_default_ry1_r6_fixed_ratemc_uncalibrated_calibrated_supply utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_rate_year_1.yaml run_includes_supply: true run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -553,11 +553,11 @@ runs: hp: tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough.json non-hp: tariffs/electric/ct_eversource_non-hp_base_percustomer_passthrough.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_hp_seasonal_percustomer_passthrough_precalc_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_hp_seasonal_percustomer_passthrough_precalc_delivery utility_revenue_requirement: rev_requirement/ct_eversource_hp_vs_non-hp.yaml run_includes_supply: false run_includes_subclasses: true - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -588,11 +588,11 @@ runs: hp: tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_supply.json non-hp: tariffs/electric/ct_eversource_non-hp_base_percustomer_passthrough_supply.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_hp_seasonal_percustomer_passthrough_precalc_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_hp_seasonal_percustomer_passthrough_precalc_supply utility_revenue_requirement: rev_requirement/ct_eversource_hp_vs_non-hp.yaml run_includes_supply: true run_includes_subclasses: true - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -622,11 +622,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_calibrated.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_hp_seasonal_percustomer_passthrough_calibrated_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_hp_seasonal_percustomer_passthrough_calibrated_delivery utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_test_year.yaml run_includes_supply: false run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -651,11 +651,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_supply_calibrated.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_hp_seasonal_percustomer_passthrough_calibrated_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_hp_seasonal_percustomer_passthrough_calibrated_supply utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_test_year.yaml run_includes_supply: true run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -681,11 +681,11 @@ runs: hp: tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough.json non-hp: tariffs/electric/ct_eversource_non-hp_base_percustomer_passthrough.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_hp_flat_percustomer_passthrough_precalc_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_hp_flat_percustomer_passthrough_precalc_delivery utility_revenue_requirement: rev_requirement/ct_eversource_hp_vs_non-hp.yaml run_includes_supply: false run_includes_subclasses: true - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -716,11 +716,11 @@ runs: hp: tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_supply.json non-hp: tariffs/electric/ct_eversource_non-hp_base_percustomer_passthrough_supply.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_hp_flat_percustomer_passthrough_precalc_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_hp_flat_percustomer_passthrough_precalc_supply utility_revenue_requirement: rev_requirement/ct_eversource_hp_vs_non-hp.yaml run_includes_supply: true run_includes_subclasses: true - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -750,11 +750,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_calibrated.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_hp_flat_percustomer_passthrough_calibrated_delivery + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_hp_flat_percustomer_passthrough_calibrated_delivery utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_test_year.yaml run_includes_supply: false run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet @@ -779,11 +779,11 @@ runs: path_tariffs_electric: all: tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_supply_calibrated.json path_tariffs_gas: tariffs/gas - path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261001_a/ct_ct_eversource_hp_flat_percustomer_passthrough_calibrated_supply + path_outputs: /data.sb/switchbox/cairo/outputs/hp_rates/ct/ct_eversource/ct_20261007_b/ct_ct_eversource_hp_flat_percustomer_passthrough_calibrated_supply utility_revenue_requirement: rev_requirement/ct_eversource_large_number_rate_case_test_year.yaml run_includes_supply: true run_includes_subclasses: false - path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2025/data.parquet + path_dist_and_sub_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/utility=ct_eversource/year=2026/data.parquet path_bulk_tx_mc: s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/utility=ct_eversource/year=2025/data.parquet path_supply_energy_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/energy/utility=ct_eversource/year=2025/zero.parquet path_supply_capacity_mc: s3://data.sb/switchbox/marginal_costs/ct/supply/capacity/utility=ct_eversource/year=2025/zero.parquet diff --git a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough.json b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough.json index e58d7558..a9ac9813 100644 --- a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough.json +++ b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough.json @@ -640,7 +640,7 @@ "energyratestructure": [ [ { - "rate": 0.08936387859680141, + "rate": 0.08943718772250871, "adj": 0.0, "unit": "kWh" } diff --git a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_calibrated.json b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_calibrated.json index 92aba370..9c38a702 100644 --- a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_calibrated.json +++ b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_calibrated.json @@ -640,7 +640,7 @@ "energyratestructure": [ [ { - "rate": 0.0899445219024096, + "rate": 0.09001830735539533, "adj": 0.0, "unit": "kWh" } diff --git a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_supply.json b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_supply.json index 0980e6ad..61779473 100644 --- a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_supply.json +++ b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_supply.json @@ -640,7 +640,7 @@ "energyratestructure": [ [ { - "rate": 0.14858281796126255, + "rate": 0.14865612708696985, "adj": 0.0, "unit": "kWh" } diff --git a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_supply_calibrated.json b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_supply_calibrated.json index f29d742a..32706c83 100644 --- a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_supply_calibrated.json +++ b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_flat_percustomer_passthrough_supply_calibrated.json @@ -640,7 +640,7 @@ "energyratestructure": [ [ { - "rate": 0.19471528199218457, + "rate": 0.19478906744517024, "adj": 0.0, "unit": "kWh" } diff --git a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough.json b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough.json index e9495a31..da31a9fd 100644 --- a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough.json +++ b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough.json @@ -647,7 +647,7 @@ ], [ { - "rate": 0.04985960419221816, + "rate": 0.049977764371030964, "adj": 0.0, "unit": "kWh" } diff --git a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_calibrated.json b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_calibrated.json index f4fc2a5f..383c227e 100644 --- a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_calibrated.json +++ b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_calibrated.json @@ -640,14 +640,14 @@ "energyratestructure": [ [ { - "rate": 0.15546663131980376, + "rate": 0.15546556931756486, "adj": 0.0, "unit": "kWh" } ], [ { - "rate": 0.050356826780618584, + "rate": 0.050475834194014566, "adj": 0.0, "unit": "kWh" } diff --git a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_supply.json b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_supply.json index bd6d0406..cef43ed0 100644 --- a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_supply.json +++ b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_supply.json @@ -640,14 +640,14 @@ "energyratestructure": [ [ { - "rate": 0.258028089992512, + "rate": 0.25802808999251203, "adj": 0.0, "unit": "kWh" } ], [ { - "rate": 0.08162340928382522, + "rate": 0.08174156946263797, "adj": 0.0, "unit": "kWh" } diff --git a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_supply_calibrated.json b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_supply_calibrated.json index c3bc8ed5..04eacad3 100644 --- a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_supply_calibrated.json +++ b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_hp_seasonal_percustomer_passthrough_supply_calibrated.json @@ -640,14 +640,14 @@ "energyratestructure": [ [ { - "rate": 0.3393284853244324, + "rate": 0.3392871606491099, "adj": 0.0, "unit": "kWh" } ], [ { - "rate": 0.1073416694054259, + "rate": 0.10748500305680475, "adj": 0.0, "unit": "kWh" } diff --git a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_non-hp_base_percustomer_passthrough_calibrated.json b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_non-hp_base_percustomer_passthrough_calibrated.json index 6b2b60e7..8e44437c 100644 --- a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_non-hp_base_percustomer_passthrough_calibrated.json +++ b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_non-hp_base_percustomer_passthrough_calibrated.json @@ -640,21 +640,21 @@ "energyratestructure": [ [ { - "rate": 0.16874088346405935, + "rate": 0.16873612452413014, "adj": 0.0, "unit": "kWh" } ], [ { - "rate": 0.15335896043117192, + "rate": 0.15335463530222085, "adj": 0.0, "unit": "kWh" } ], [ { - "rate": 0.14847416054910634, + "rate": 0.14846997318445238, "adj": 0.0, "unit": "kWh" } diff --git a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_non-hp_base_percustomer_passthrough_supply_calibrated.json b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_non-hp_base_percustomer_passthrough_supply_calibrated.json index 21ab4f8e..d249bc21 100644 --- a/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_non-hp_base_percustomer_passthrough_supply_calibrated.json +++ b/rate_design/hp_rates/ct/config/tariffs/electric/ct_eversource_non-hp_base_percustomer_passthrough_supply_calibrated.json @@ -640,28 +640,28 @@ "energyratestructure": [ [ { - "rate": 0.27992769016412195, + "rate": 0.2799229373150492, "adj": 0.0, "unit": "kWh" } ], [ { - "rate": 0.26462010286568954, + "rate": 0.26461560992178035, "adj": 0.0, "unit": "kWh" } ], [ { - "rate": 0.25017111421380384, + "rate": 0.25016686659704424, "adj": 0.0, "unit": "kWh" } ], [ { - "rate": 0.24531389901333972, + "rate": 0.24530973386648777, "adj": 0.0, "unit": "kWh" } diff --git a/tests/test_expand_month_hour_mc.py b/tests/test_expand_month_hour_mc.py index 491aa3d5..36733ceb 100644 --- a/tests/test_expand_month_hour_mc.py +++ b/tests/test_expand_month_hour_mc.py @@ -8,10 +8,34 @@ import pytest from utils.data_prep.marginal_costs.generate_utility_tx_dx_mc import ( + eversource_derived_output_base, expand_month_hour_mc_to_8760, ) +def test_eversource_derived_output_base() -> None: + assert ( + eversource_derived_output_base( + "s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/" + ) + == "s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx_eversource_derived/" + ) + assert ( + eversource_derived_output_base( + "/ebs/data/switchbox/marginal_costs/ct/dist_and_sub_tx" + ) + == "/ebs/data/switchbox/marginal_costs/ct/dist_and_sub_tx_eversource_derived/" + ) + already = ( + "s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx_eversource_derived/" + ) + assert eversource_derived_output_base(already) == already + with pytest.raises(ValueError, match="dist_and_sub_tx/"): + eversource_derived_output_base( + "s3://data.sb/switchbox/marginal_costs/ct/bulk_tx/" + ) + + def _table(value_for_month_hour: float, *, weekend: bool) -> pl.DataFrame: sign = -1.0 if weekend else 1.0 rows = [ @@ -74,6 +98,27 @@ def value_at(stamp: str) -> float: assert value_at("2026-07-06 16:00:00") == pytest.approx(7.16) +def test_weekday_holidays_stay_on_weekday_table_when_holidays_excluded() -> None: + expanded = expand_month_hour_mc_to_8760( + _table(0.0, weekend=False), + _table(0.0, weekend=True), + 2025, + "ct_eversource", + include_holidays=False, + ) + + def value_at(stamp: str) -> float: + return expanded.filter(pl.col("timestamp") == datetime.fromisoformat(stamp))[ + "mc_total_per_kwh" + ].item() + + # Wednesday New Year's and Friday July 4 stay on the weekday table. + assert value_at("2025-01-01 00:00:00") == pytest.approx(1.0) + assert value_at("2025-07-04 16:00:00") == pytest.approx(7.16) + # Saturday still uses the weekend table. + assert value_at("2025-01-04 16:00:00") == pytest.approx(-1.16) + + def test_leap_year_drops_december_31() -> None: expanded = expand_month_hour_mc_to_8760( _table(0.0, weekend=False), diff --git a/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py b/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py index 156645fc..a2ed9f8e 100644 --- a/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py +++ b/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py @@ -23,6 +23,9 @@ - RI default base: s3://data.sb/switchbox/marginal_costs/ri/dist_and_sub_tx/ - MD default base: s3://data.sb/switchbox/marginal_costs/md/dist_and_sub_tx/ - CT default base: s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx/ + - CT Eversource month-hour (--use-eversource-marginal-cost true): + s3://data.sb/switchbox/marginal_costs/ct/dist_and_sub_tx_eversource_derived/ + The partition year is --year, the same calendar stamped on the timestamps. - Default partition: utility=X/year=YYYY/data.parquet - Alternate-load-year base: _loadYYYY/ Example: dist_and_sub_tx_load2018/utility=X/year=2025/data.parquet @@ -254,6 +257,25 @@ def load_marginal_cost_table(mc_table_path: str) -> pl.DataFrame: return df +def eversource_derived_output_base(base: str) -> str: + """Point a dist-and-sub-tx output root at the Eversource-derived dataset. + + ``.../dist_and_sub_tx/`` becomes ``.../dist_and_sub_tx_eversource_derived/``. + A base that already names that dataset is returned unchanged. + """ + trimmed = base.rstrip("/") + parent, leaf = trimmed.rsplit("/", 1) + if leaf == "dist_and_sub_tx_eversource_derived": + return f"{trimmed}/" + if leaf != "dist_and_sub_tx": + raise ValueError( + "--use-eversource-marginal-cost writes under " + "dist_and_sub_tx_eversource_derived/, so the output base must end " + f"in dist_and_sub_tx/ (got {base!r})" + ) + return f"{parent}/dist_and_sub_tx_eversource_derived/" + + def _parse_bool(value: str) -> bool: normalized = value.strip().lower() if normalized in {"true", "1", "yes"}: @@ -470,20 +492,22 @@ def expand_month_hour_mc_to_8760( weekend: pl.DataFrame, year: int, utility: str, + *, + include_holidays: bool = True, ) -> pl.DataFrame: """Expand month-hour marginal costs onto one calendar year's Cairo 8760. ``weekday`` and ``weekend`` are the OCC-863 Attachment 2 matrices, each with - ``month`` (1–12), ``hour`` (0–23), and ``mc_total_per_kwh``. Saturday, - Sunday, and US federal holidays take the weekend value. A holiday that - falls on Saturday is observed on Friday, and one that falls on Sunday is - observed on Monday. Any other Monday through Friday takes the weekday - value. + ``month`` (1–12), ``hour`` (0–23), and ``mc_total_per_kwh``. Saturday and + Sunday take the weekend value. When ``include_holidays`` is true, US + federal holidays do too: a holiday that falls on Saturday is observed on + Friday, and one that falls on Sunday is observed on Monday. When it is + false, a holiday on Monday through Friday takes the weekday value. + Any other Monday through Friday takes the weekday value. - ``year`` is the calendar stamped on the timestamps. It is the output year - of the existing dist-and-sub-tx 8760, which is the year CAIRO joins on. - The PoP load year is not used: this series is a day-of-week lookup, not a - load-weighted allocation. + ``year`` is both the calendar used to classify each day and the year + stamped on ``timestamp`` and the ``year`` column. Passing 2018 classifies + 2018's weekdays, weekends, and holidays and writes 2018 timestamps. Timestamps match ``build_cairo_8760_timestamps``: naive hour-beginning local time, 8,760 rows, with December 31 dropped in a leap year. @@ -491,7 +515,7 @@ def expand_month_hour_mc_to_8760( clock = build_cairo_8760_timestamps(year).with_columns( pl.col("timestamp").cast(pl.Datetime("us")) ) - holidays = _us_federal_holidays(year) + holidays = _us_federal_holidays(year) if include_holidays else set() clock = clock.with_columns( pl.col("timestamp").dt.month().alias("month"), pl.col("timestamp").dt.hour().alias("hour"), @@ -777,12 +801,14 @@ def main(): ), ) parser.add_argument( - "--eversource-mc-year", - type=int, - default=None, + "--include-holidays", + type=_parse_bool, + default=True, + metavar="{true,false}", help=( - "Partition year for the Eversource 8760: the rate year of the " - "Attachment 2 values. Timestamps still use --year's calendar." + "true: federal holidays take the weekend-and-holiday table. " + "false: only Saturday and Sunday do; a weekday holiday stays on " + "the weekday table. Used with --use-eversource-marginal-cost." ), ) parser.add_argument( @@ -913,30 +939,41 @@ def _run_eversource_month_hour( """Build and optionally save the 8760 from OCC-863 month-hour tables.""" if args.state != "CT": raise ValueError("--use-eversource-marginal-cost is only defined for CT") - if not (args.path_weekday_mc and args.path_weekend_mc and args.eversource_mc_year): + if not (args.path_weekday_mc and args.path_weekend_mc): raise ValueError( - "--use-eversource-marginal-cost needs --path-weekday-mc, " - "--path-weekend-mc, and --eversource-mc-year" + "--use-eversource-marginal-cost needs --path-weekday-mc and " + "--path-weekend-mc" ) - calendar_year = args.year - partition_year = args.eversource_mc_year + year = args.year + output_s3_base = eversource_derived_output_base(args.output_s3_base) + path_local_base = ( + eversource_derived_output_base(args.path_local_output_base) + if args.path_local_output_base + else None + ) print("=" * 60) print("EVERSOURCE MONTH-HOUR MARGINAL COST → 8760") print("=" * 60) print(f"Utility: {args.utility}") - print(f"Calendar year (weekday/weekend/holiday): {calendar_year}") - print(f"Partition year: {partition_year}") + print(f"Year (calendar, timestamps, and partition): {year}") + print(f"Include federal holidays: {args.include_holidays}") print(f"Weekday table: {args.path_weekday_mc}") print(f"Weekend-and-holiday table: {args.path_weekend_mc}") - print(f"Output S3 base: {args.output_s3_base}") + print(f"Output S3 base: {output_s3_base}") + if path_local_base: + print(f"Local output base: {path_local_base}") print(f"Upload to S3: {'Yes' if args.upload else 'No (inspection only)'}") print("=" * 60) weekday = _read_parquet_any(args.path_weekday_mc, storage_options) weekend = _read_parquet_any(args.path_weekend_mc, storage_options) expanded = expand_month_hour_mc_to_8760( - weekday, weekend, calendar_year, args.utility + weekday, + weekend, + year, + args.utility, + include_holidays=args.include_holidays, ) annual = float(expanded["mc_total_per_kwh"].sum()) @@ -951,11 +988,11 @@ def _run_eversource_month_hour( save_allocated_costs( expanded, args.utility, - partition_year, - args.output_s3_base, + year, + output_s3_base, {}, storage_options, - path_local_base=args.path_local_output_base, + path_local_base=path_local_base, ) print("\n✓ Eversource month-hour 8760 completed and uploaded") else: From 14d1eddc8354fa7cb1c2935e735bb291a2c24819 Mon Sep 17 00:00:00 2001 From: Alex Lee Date: Thu, 8 Oct 2026 16:21:44 +0000 Subject: [PATCH 3/3] Fix total annual marginal cost file read error --- utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py b/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py index a2ed9f8e..9580c052 100644 --- a/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py +++ b/utils/data_prep/marginal_costs/generate_utility_tx_dx_mc.py @@ -819,7 +819,6 @@ def main(): ) args = parser.parse_args() - validate_mc_table_path(args.mc_table_path) load_dotenv() storage_options = get_aws_storage_options() @@ -827,6 +826,8 @@ def main(): _run_eversource_month_hour(args, storage_options) return + validate_mc_table_path(args.mc_table_path) + output_year = args.year load_year = args.load_year if args.load_year else output_year target_dollar_year = (