From 8fe590e6af6ade7a9f5d08a615a40a1b28797240 Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Thu, 16 Apr 2026 15:20:40 -0600 Subject: [PATCH 01/14] Move natural gas price regression code to here --- .../natural_gas_price_regression/.gitignore | 34 + .../natural_gas_price_regression/README.md | 91 ++ .../aeo_alpha_regression.py | 1249 +++++++++++++++++ .../aeo_beta_regression.py | 735 ++++++++++ .../aeo_pipeline_config.json | 73 + .../inputs for alpha regression/cd_beta0.csv | 10 + .../national_beta.csv | 2 + .../ng_AEO_historical.csv | 15 + .../ng_demand_AEO_historical.csv | 15 + .../ng_tot_demand_AEO_historical.csv | 15 + .../inputs for alpha regression/st_cendiv.csv | 49 + .../alpha_AEO_2025_HOG.csv | 42 + .../alpha_AEO_2025_LOG.csv | 42 + .../alpha_AEO_2025_reference.csv | 42 + .../outputs of alpha regression/cd_beta0.csv | 10 + .../cd_beta0_allsector.csv | 10 + .../ng_AEO_2025_HOG.csv | 42 + .../ng_AEO_2025_LOG.csv | 42 + .../ng_AEO_2025_reference.csv | 42 + .../ng_demand_AEO_2025_HOG.csv | 42 + .../ng_demand_AEO_2025_LOG.csv | 42 + .../ng_demand_AEO_2025_reference.csv | 42 + .../ng_tot_demand_AEO_2025_HOG.csv | 42 + .../ng_tot_demand_AEO_2025_LOG.csv | 42 + .../ng_tot_demand_AEO_2025_reference.csv | 42 + .../beta_regression_summary.csv | 11 + .../outputs of beta regression/cd_beta0.csv | 10 + .../national_beta.csv | 2 + .../run_ng_pipeline.bat | 39 + .../sync_beta_to_alpha_inputs.py | 122 ++ .../visualization.py | 1191 ++++++++++++++++ 31 files changed, 4187 insertions(+) create mode 100644 aeo_updates/natural_gas_price_regression/.gitignore create mode 100644 aeo_updates/natural_gas_price_regression/README.md create mode 100644 aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py create mode 100644 aeo_updates/natural_gas_price_regression/aeo_beta_regression.py create mode 100644 aeo_updates/natural_gas_price_regression/aeo_pipeline_config.json create mode 100644 aeo_updates/natural_gas_price_regression/inputs for alpha regression/cd_beta0.csv create mode 100644 aeo_updates/natural_gas_price_regression/inputs for alpha regression/national_beta.csv create mode 100644 aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_AEO_historical.csv create mode 100644 aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_demand_AEO_historical.csv create mode 100644 aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_tot_demand_AEO_historical.csv create mode 100644 aeo_updates/natural_gas_price_regression/inputs for alpha regression/st_cendiv.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_HOG.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_LOG.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_reference.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0_allsector.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_HOG.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_LOG.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_reference.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_HOG.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_LOG.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_reference.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_HOG.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_LOG.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_reference.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of beta regression/beta_regression_summary.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of beta regression/cd_beta0.csv create mode 100644 aeo_updates/natural_gas_price_regression/outputs of beta regression/national_beta.csv create mode 100644 aeo_updates/natural_gas_price_regression/run_ng_pipeline.bat create mode 100644 aeo_updates/natural_gas_price_regression/sync_beta_to_alpha_inputs.py create mode 100644 aeo_updates/natural_gas_price_regression/visualization.py diff --git a/aeo_updates/natural_gas_price_regression/.gitignore b/aeo_updates/natural_gas_price_regression/.gitignore new file mode 100644 index 0000000..9b648df --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/.gitignore @@ -0,0 +1,34 @@ +# Python cache +__pycache__/ +*.pyc + +# Visualization outputs (PNGs, PDFs) +*.png +*.pdf + +# Validation and visualization results (all generated output) +results validation/ + +# Raw API data dumps (reproducible from EIA API) +outputs of alpha regression/raw_aeo_data/ +outputs of beta regression/raw_aeo_data/ + +# Beta raw data visualization subfolder +outputs of beta regression/bata raw data visualization/ + +# Beta regression intermediate outputs (keep cd_beta0.csv, national_beta.csv, beta_regression_summary.csv) +outputs of beta regression/regression_points.csv +outputs of beta regression/alpha_from_beta_by_scenario.csv +outputs of beta regression/alpha_from_beta_regression.csv +outputs of beta regression/alpha from beta regression/ + +# Notebook checkpoints +.ipynb_checkpoints/ + +# Stale nested duplicate directory +AEO_Updates/ + +# Old scripts (replaced by visualization.py) +results_visualization.py +results_validation.py +beta_raw_data_visualization.py diff --git a/aeo_updates/natural_gas_price_regression/README.md b/aeo_updates/natural_gas_price_regression/README.md new file mode 100644 index 0000000..5522342 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/README.md @@ -0,0 +1,91 @@ +# Natural Gas Price Regression + +This folder has the natural gas update workflow for ReEDS. + +## Model Note + +`alpha` differs by step: + +- Beta step (`alpha1`) is `alpha1(region, year)` and is shared across scenarios. +- Alpha step (`alpha2`) is `alpha2(region, year, scenario)`, so each output + scenario has its own alpha path. + +## Prerequisites + +### EIA API Key + +The pipeline fetches data from the EIA API and requires an API key. Set it as an environment variable before running: + +**Windows (persistent — open a new terminal after running):** +```cmd +setx EIA_API_KEY your_api_key_here +``` + +**Windows (current session only):** +```cmd +set EIA_API_KEY=your_api_key_here +``` + +**macOS/Linux:** +```bash +export EIA_API_KEY=your_api_key_here +``` + +> The key is read from the `EIA_API_KEY` environment variable. Do **not** hardcode it in `aeo_pipeline_config.json`. + +## Run order + +1. Edit `aeo_pipeline_config.json` with your settings. + +2. Run **beta regression first**. + +```bash +python aeo_beta_regression.py --config aeo_pipeline_config.json +``` + +3. Sync beta outputs into alpha inputs. + +```bash +python sync_beta_to_alpha_inputs.py --config aeo_pipeline_config.json +``` + +4. Run **alpha regression**. + +```bash +python aeo_alpha_regression.py --config aeo_pipeline_config.json +``` + +5. Generate all diagnostic plots and validation. + +```bash +python visualization.py --config aeo_pipeline_config.json +``` + +Skip individual parts with flags: +```bash +python visualization.py --skip-raw-scatter --skip-validation +``` + +Default output folder: `results validation` (all plots and validation CSVs). + +## Scenario Configuration + +Set explicit scenarios in `aeo_pipeline_config.json` under `scenarios`: + +- `scenarios.beta_regression.include`: scenarios used to estimate beta. +- `scenarios.alpha_regression.fetch`: scenarios fetched for alpha preprocessing. +- `scenarios.alpha_regression.outputs`: mapping from output suffix (`reference`, `HOG`, `LOG`, etc.) to scenario aliases. + +Use canonical IDs (for example `ref{aeo_year}`, `highogs`, `lowogs`) for a clear setup. + +## One-command batch (Windows) + +```bat +run_ng_pipeline.bat +``` + +Optional custom config: + +```bat +run_ng_pipeline.bat my_config.json +``` diff --git a/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py b/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py new file mode 100644 index 0000000..fa89d71 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py @@ -0,0 +1,1249 @@ +""" +AEO Natural Gas Price Preprocessing Pipeline for ReEDS Inputs +============================================================= + +This script automates the preprocessing of AEO (Annual Energy Outlook) +natural gas data from the EIA API into input files for the ReEDS capacity +expansion model. + +NG Supply Curve Model +--------------------- +ReEDS models regional natural gas prices using a linear supply curve +framework. The regional delivered price of natural gas in each census +division is decomposed into three components: + + Price(r,t,s) = Alpha(r,t,s) + Beta_regional(r) × Demand_regional(r,t,s) + + Beta_national × Demand_national(t,s) + +Where: + - Price(r,t,s) : AEO NG price for region r, year t, scenario s (2024$/MMBtu) + - Alpha(r,t,s) : Intercept / base price component (2004$/MMBtu) + - Beta_regional(r) : Region-specific demand sensitivity (2004$/MMBtu per Quad) + - Demand_regional(r,t,s) : Electric sector NG demand in region r (Quads) + - Beta_national : National demand sensitivity (2004$/MMBtu per Quad) + - Demand_national(t,s) : Total national electric sector NG demand (Quads) + +Alpha is solved as the residual after removing demand-driven price effects: + + Alpha(r,t,s) = Price(r,t,s) × deflator - Beta_regional(r) × Demand_regional(r,t,s) + - Beta_national × Demand_national(t,s) + +Alpha is solved at scenario level and indexed by (region, year, scenario), +so each scenario keeps its own residual alpha path. + +The deflator converts from the AEO's native dollar year (e.g., 2024$) to +2004$, the base dollar year used internally by ReEDS for NG pricing. + +Data Sources +------------ +- Prices and demand projections: EIA AEO API (3 scenarios: Reference, High/Low O&G) +- Historical backfill: Local CSV files for pre-projection years +- Betas: Pre-computed regional and national sensitivity coefficients + +Output Files (per scenario) +--------------------------- +- alpha_AEO_{year}_{scenario}.csv : Regional alpha values (2004$/MMBtu) +- ng_AEO_{year}_{scenario}.csv : Regional NG prices (AEO dollar year) +- ng_demand_AEO_{year}_{scenario}.csv : Electric sector demand (Quads) +- ng_tot_demand_AEO_{year}_{scenario}.csv : Total sector demand (Quads) +- cd_beta0.csv : Electric sector regional betas +- cd_beta0_allsector.csv : All-sector regional betas + +Usage +----- + python aeo_alpha_regression.py --config aeo_pipeline_config.json + +Example config: see aeo_pipeline_config.json +""" + +from __future__ import annotations + +import argparse +import json +import logging +import os +import re +import shutil +import sys +from pathlib import Path +from typing import Any + +import pandas as pd +import requests +from requests.adapters import HTTPAdapter +from urllib3 import disable_warnings +from urllib3.exceptions import InsecureRequestWarning +from urllib3.util.retry import Retry + +LOGGER = logging.getLogger("aeo_pipeline") + +# ============================================================================ +# Constants +# ============================================================================ + +# Mapping from normalized region names to canonical internal keys +CENDIV_CANONICAL = { + "newengland": "NewEngland", + "middleatlantic": "MiddleAtlantic", + "eastnorthcentral": "EastNorthCentral", + "westnorthcentral": "WestNorthCentral", + "southatlantic": "SouthAtlantic", + "eastsouthcentral": "EastSouthCentral", + "westsouthcentral": "WestSouthCentral", + "mountain": "Mountain", + "pacific": "Pacific", + "unitedstates": "UnitedStates", +} + +# Mapping from internal keys to ReEDS output format (underscore-separated) +CENDIV_OUTPUT = { + "NewEngland": "New_England", + "MiddleAtlantic": "Mid_Atlantic", + "EastNorthCentral": "East_North_Central", + "WestNorthCentral": "West_North_Central", + "SouthAtlantic": "South_Atlantic", + "EastSouthCentral": "East_South_Central", + "WestSouthCentral": "West_South_Central", + "Mountain": "Mountain", + "Pacific": "Pacific", +} + +# EIA AEO series names for NG data +NG_SERIES_NAMES = { + "price": "Energy Prices : Electric Power : Natural Gas", + "demand_elec": "Energy Use : Electric Power : Natural Gas", + "demand_total": "Energy Use : Total : Natural Gas", +} + +# Required output scenarios and their EIA API aliases +NG_OUTPUT_SCENARIOS = { + "reference": ["ref{aeo_year}", "Reference case", "Reference Case"], + "HOG": ["highogs", "High Oil and Gas Supply"], + "LOG": ["lowogs", "Low Oil and Gas Supply"], +} + +HISTORY_SUFFIX = "historical" + + +# ============================================================================ +# Utility Functions +# ============================================================================ + +def parse_args() -> argparse.Namespace: + p = argparse.ArgumentParser(description="AEO NG update pipeline") + p.add_argument("--config", default="aeo_pipeline_config.json") + p.add_argument("--log-level", default="INFO", + choices=["DEBUG", "INFO", "WARNING", "ERROR"]) + p.add_argument("--aeo-year", type=int, default=None) + return p.parse_args() + + +def setup_logging(level: str) -> None: + logging.basicConfig( + level=getattr(logging, level.upper()), + format="%(asctime)s | %(levelname)s | %(message)s", + ) + + +def require(condition: bool, message: str) -> None: + """Assert a condition with a descriptive error message.""" + if not condition: + raise ValueError(message) + + +def normalize_token(value: Any) -> str: + """Normalize a string for case-insensitive, whitespace-insensitive matching.""" + if value is None: + return "" + return re.sub(r"[^a-z0-9]+", "", str(value).replace("\xa0", " ").strip().lower()) + + +def canonical_cendiv(value: Any) -> str: + """Convert a region name to its canonical internal key.""" + key = normalize_token(value) + return CENDIV_CANONICAL.get(key, re.sub(r"[^A-Za-z0-9]", "", str(value))) + + +def cendiv_output_label(cendiv: str) -> str: + """Convert an internal key to ReEDS output format (e.g., 'New_England').""" + require(cendiv in CENDIV_OUTPUT, + f"Unsupported census division for NG output: {cendiv}") + return CENDIV_OUTPUT[cendiv] + + +def output_label_to_cendiv(label: str) -> str: + """Convert a ReEDS output label back to the internal key.""" + norm = normalize_token(label.replace("_", " ")) + for cendiv, output in CENDIV_OUTPUT.items(): + if normalize_token(output.replace("_", " ")) == norm: + return cendiv + return canonical_cendiv(label) + + +def resolve_case_insensitive(path: Path) -> Path: + """Resolve a path with case-insensitive matching on each component.""" + if path.exists(): + return path + path = path.resolve() + current = Path(path.anchor) + for part in path.parts[1:]: + if not current.exists(): + return path + try: + matches = [p for p in current.iterdir() + if p.name.lower() == part.lower()] + except PermissionError: + return path + if not matches: + return path + current = matches[0] + return current + + +def resolve_path(base_dir: Path, configured_path: str) -> Path: + """Resolve a configured path relative to the base directory.""" + p = Path(configured_path) + if not p.is_absolute(): + p = base_dir / p + return resolve_case_insensitive(p) + + +def load_config(config_path: Path) -> dict[str, Any]: + """Load and validate the JSON configuration file.""" + require(config_path.exists(), f"Config not found: {config_path}") + with config_path.open("r", encoding="utf-8") as f: + cfg = json.load(f) + require(isinstance(cfg, dict), f"Config root must be an object: {config_path}") + return cfg + + +def resolve_api_key(config: dict[str, Any]) -> str: + """Resolve the EIA API key from environment, config, or legacy fallback.""" + api_cfg = config["api"] + env_var = api_cfg.get("key_env_var", "EIA_API_KEY") + env_key = os.getenv(env_var, "").strip() + if env_key: + return env_key + fallback = api_cfg.get("key_fallback", "").strip() + if fallback: + LOGGER.warning("Using key_fallback from config.") + return fallback + try: + from _eia_api_functions import api_key as legacy_api_key # type: ignore + if legacy_api_key: + LOGGER.warning("Using API key from _eia_api_functions.py fallback.") + return str(legacy_api_key) + except Exception: + pass + raise ValueError(f"Missing EIA API key. Set {env_var} or api.key_fallback.") + + +# ============================================================================ +# EIA API Client +# ============================================================================ + +class EiaClient: + """Client for fetching data from the EIA AEO API with retry logic.""" + + def __init__(self, api_cfg: dict[str, Any], api_key: str): + self.base_url = api_cfg["base_url"].rstrip("/") + self.verify_ssl = bool(api_cfg.get("verify_ssl", True)) + self.timeout = int(api_cfg.get("timeout_seconds", 60)) + self.api_key = api_key + if not self.verify_ssl: + disable_warnings(InsecureRequestWarning) + retries = Retry( + total=int(api_cfg.get("max_retries", 4)), + connect=int(api_cfg.get("max_retries", 4)), + read=int(api_cfg.get("max_retries", 4)), + status=int(api_cfg.get("max_retries", 4)), + backoff_factor=float(api_cfg.get("backoff_seconds", 1.0)), + status_forcelist=[429, 500, 502, 503, 504], + allowed_methods=["GET"], + raise_on_status=False, + ) + self.session = requests.Session() + adapter = HTTPAdapter(max_retries=retries) + self.session.mount("https://", adapter) + self.session.mount("http://", adapter) + + def get_json(self, path: str, + params: list[tuple[str, str]] | None = None) -> dict[str, Any]: + full_path = path if path.startswith("/") else f"/{path}" + query = [("api_key", self.api_key)] + if params: + query.extend(params) + resp = self.session.get( + f"{self.base_url}{full_path}", + params=query, + timeout=self.timeout, + verify=self.verify_ssl, + ) + resp.raise_for_status() + payload = resp.json() + require("response" in payload, + f"Unexpected payload from {path}: {payload}") + return payload + + def get_facets(self, aeo_year: int, facet: str) -> list[dict[str, Any]]: + return self.get_json( + f"/aeo/{aeo_year}/facet/{facet}")["response"]["facets"] + + def get_data(self, path: str, + params: list[tuple[str, str]]) -> pd.DataFrame: + payload = self.get_json(path, params) + warnings = payload["response"].get("warnings", []) + for w in warnings: + LOGGER.warning("EIA warning: %s | %s", + w.get("warning"), w.get("description")) + data = payload["response"].get("data", []) + require(data, f"No data from endpoint {path}") + return pd.DataFrame(data) + + +# ============================================================================ +# EIA API Resolution Helpers +# ============================================================================ + +def resolve_region_ids(client: EiaClient, aeo_year: int, + regions: list[str]) -> dict[str, str]: + """Map region display names to EIA region IDs.""" + facets = client.get_facets(aeo_year, "regionId") + region_map = {normalize_token(item["name"]): str(item["id"]) + for item in facets} + out: dict[str, str] = {} + for name in regions: + key = normalize_token(name) + require(key in region_map, f"Region not found in EIA facets: {name}") + out[name] = region_map[key] + return out + + +def resolve_series_ids(client: EiaClient, aeo_year: int, + series_name: str) -> list[str]: + """Find EIA series IDs matching a given series name.""" + facets = client.get_facets(aeo_year, "seriesId") + ids = [str(item["id"]) for item in facets + if normalize_token(item.get("name")) == normalize_token(series_name)] + require(ids, f"Series not found: {series_name}") + return ids + + +def resolve_ng_scenarios( + client: EiaClient, + aeo_year: int, + include_scenarios: list[str] | None = None, +) -> pd.DataFrame: + """ + Discover available AEO scenarios for NG data. + + If include_scenarios is provided, only those scenarios are kept + (matching by scenario id or scenario name, case-insensitive). + """ + facets = client.get_facets(aeo_year, "scenario") + rows: list[dict[str, str]] = [] + for item in facets: + scenario_id = str(item.get("id", "")).strip() + scenario_name = str(item.get("name", "")).strip() + if not scenario_id: + continue + # Skip legacy composite IDs (e.g., "aeo2023ref") + if normalize_token(scenario_id).startswith("aeo"): + continue + rows.append({"scenario_id": scenario_id, + "scenario_name": scenario_name}) + require(rows, "No NG scenarios left after filtering legacy IDs.") + + if include_scenarios: + picked: list[dict[str, str]] = [] + missing: list[str] = [] + for raw in include_scenarios: + token = normalize_token(str(raw).replace("{aeo_year}", str(aeo_year))) + found = None + for row in rows: + sid = str(row["scenario_id"]) + sname = str(row["scenario_name"]) + if normalize_token(sid) == token or normalize_token(sname) == token: + found = row + break + if found is None: + missing.append(str(raw)) + continue + if all(str(r["scenario_id"]) != str(found["scenario_id"]) for r in picked): + picked.append(found) + require( + not missing, + f"Configured alpha_regression.fetch scenarios not found: {missing}", + ) + out = pd.DataFrame(picked) + LOGGER.info( + "Selected NG scenarios from config (%d): %s", + len(out), + out["scenario_id"].tolist(), + ) + return out.reset_index(drop=True) + + out = ( + pd.DataFrame(rows) + .drop_duplicates(subset=["scenario_id"]) + .sort_values("scenario_id") + .reset_index(drop=True) + ) + LOGGER.info("Selected NG scenarios (%d): %s", len(out), out["scenario_id"].tolist()) + return out + + +def resolve_output_scenario_aliases( + aeo_year: int, + configured_outputs: Any, +) -> dict[str, list[str]]: + """Build output scenario alias map from config, with defaults.""" + if configured_outputs is None: + raw_map: dict[str, list[str]] = NG_OUTPUT_SCENARIOS + elif isinstance(configured_outputs, dict): + raw_map = {} + for suffix, aliases in configured_outputs.items(): + require( + isinstance(aliases, list), + f"alpha_regression.outputs['{suffix}'] must be a list.", + ) + raw_map[str(suffix)] = [str(a) for a in aliases] + elif isinstance(configured_outputs, list): + raw_map = {} + for row in configured_outputs: + require( + isinstance(row, dict), + "alpha_regression.outputs list entries must be objects.", + ) + suffix = str(row.get("file_suffix", "")).strip() + require(suffix, "alpha_regression.outputs entry missing file_suffix.") + aliases = row.get("aliases", []) + require( + isinstance(aliases, list), + f"alpha_regression.outputs entry '{suffix}' aliases must be a list.", + ) + vals = [str(a).strip() for a in aliases if str(a).strip()] + scenario_id = str(row.get("scenario_id", "")).strip() + if scenario_id: + vals.insert(0, scenario_id) + require(vals, f"alpha_regression.outputs entry '{suffix}' has no aliases.") + raw_map[suffix] = vals + else: + raise ValueError( + "alpha_regression.outputs must be either an object or a list of objects." + ) + + out: dict[str, list[str]] = {} + for suffix, aliases in raw_map.items(): + suffix_txt = str(suffix).strip() + require(suffix_txt, "alpha_regression.outputs contains an empty file_suffix.") + clean_aliases = [str(a).strip() for a in aliases if str(a).strip()] + require(clean_aliases, f"alpha_regression.outputs['{suffix_txt}'] has no aliases.") + # Keep original strings for logs and output; matching happens via normalize_token. + out[suffix_txt] = clean_aliases + require(out, "alpha_regression.outputs resolved to an empty mapping.") + LOGGER.info( + "Configured alpha output scenario map for AEO %d: %s", + aeo_year, + {k: v for k, v in out.items()}, + ) + return out + + +def resolve_output_scenarios( + available_scenarios: pd.DataFrame, + aeo_year: int, + output_aliases: dict[str, list[str]], +) -> pd.DataFrame: + """Match available scenarios to configured output scenario aliases.""" + require(not available_scenarios.empty, + "No available scenarios to resolve NG output scenarios.") + rows: list[dict[str, str]] = [] + for suffix, aliases in output_aliases.items(): + alias_tokens = {normalize_token(a.replace("{aeo_year}", str(aeo_year))) + for a in aliases} + found_row = None + for row in available_scenarios.itertuples(index=False): + sid = str(row.scenario_id) + sname = str(row.scenario_name) + if (normalize_token(sid) in alias_tokens + or normalize_token(sname) in alias_tokens): + found_row = row + break + require(found_row is not None, + f"Could not resolve required NG output scenario: '{suffix}'") + rows.append({ + "scenario_id": str(found_row.scenario_id), + "scenario_name": str(found_row.scenario_name), + "file_suffix": str(suffix), + }) + out = pd.DataFrame(rows).reset_index(drop=True) + require( + out["scenario_id"].nunique() == len(out), + "alpha_regression.outputs resolved to duplicate scenario_id values. " + "Use distinct output scenarios.", + ) + LOGGER.info("Resolved NG output scenarios: %s", + out[["scenario_id", "file_suffix"]].to_dict(orient="records")) + return out + + +def resolve_ng_region_order(config: dict[str, Any]) -> list[str]: + """Get the ordered list of census divisions from the config.""" + configured = config["ng"]["regions"] + order = [output_label_to_cendiv(x) for x in configured] + require(len(order) == len(set(order)), "NG regions contains duplicates.") + return order + + +# ============================================================================ +# Data Fetching +# ============================================================================ + +def fetch_aeo_series_by_scenario( + client: EiaClient, + aeo_year: int, + series_name: str, + scenario_ids: list[str], + region_ids: list[str], + value_col: str, + start_year: int, + end_year: int, + raw_output_path: Path | None = None, +) -> pd.DataFrame: + """ + Fetch a single AEO series (price/demand) for all scenarios and regions. + + Returns a DataFrame with columns: + [scenario_id, cendiv, year, ] + """ + series_ids = resolve_series_ids(client, aeo_year, series_name) + params: list[tuple[str, str]] = [ + ("data[]", "value"), + ("start", str(start_year)), + ("end", str(end_year)), + ] + params.extend(("facets[scenario][]", sid) for sid in scenario_ids) + params.extend(("facets[regionId][]", rid) for rid in region_ids) + params.extend(("facets[seriesId][]", sid) for sid in series_ids) + + df = client.get_data(f"/aeo/{aeo_year}/data", params=params) + if raw_output_path is not None: + raw_output_path.parent.mkdir(parents=True, exist_ok=True) + raw_export = df.copy() + raw_export.insert(0, "series_name", series_name) + raw_export.to_csv(raw_output_path, index=False, float_format="%.6f") + LOGGER.info( + "Wrote raw AEO rows for '%s' to %s (%d rows)", + series_name, raw_output_path, len(raw_export) + ) + need = {"scenario", "regionName", "period", "value"} + require( + not (need - set(df.columns)), + f"Missing columns for series '{series_name}': " + f"{sorted(need - set(df.columns))}", + ) + + df["scenario_id"] = df["scenario"].astype(str) + df["cendiv"] = df["regionName"].map(canonical_cendiv) + df["year"] = pd.to_numeric(df["period"], errors="coerce") + df[value_col] = pd.to_numeric(df["value"], errors="coerce") + df = df.dropna(subset=["scenario_id", "cendiv", "year", value_col]).copy() + df["year"] = df["year"].astype(int) + df = df[df["scenario_id"].isin(scenario_ids)].copy() + + # Verify no conflicting duplicate values + uniq = df.groupby(["scenario_id", "cendiv", "year"])[value_col].nunique() + require( + (uniq <= 1).all(), + f"Conflicting duplicate values for series '{series_name}'. " + f"Samples: {uniq[uniq > 1].head().to_dict()}", + ) + out = df.groupby( + ["scenario_id", "cendiv", "year"], as_index=False + )[value_col].mean() + LOGGER.info("Fetched %s rows for series '%s': %d", + value_col, series_name, len(out)) + return out + + +# ============================================================================ +# Data Validation and Filtering +# ============================================================================ + +def filter_complete_ng_scenarios( + scenario_table: pd.DataFrame, + series_frames: dict[str, pd.DataFrame], + region_order: list[str], + start_year: int, + end_year: int, +) -> tuple[pd.DataFrame, dict[str, pd.DataFrame]]: + """Drop scenarios that have incomplete region × year coverage.""" + expected_count = len(region_order) * (end_year - start_year + 1) + keep = set(scenario_table["scenario_id"].tolist()) + + for name, frame in series_frames.items(): + counts = frame.groupby("scenario_id").size().to_dict() + complete = {sid for sid in keep + if counts.get(sid, 0) == expected_count} + dropped = sorted(keep - complete) + if dropped: + LOGGER.warning( + "Series '%s' has incomplete coverage for %s-%s. " + "Dropping scenarios: %s", + name, start_year, end_year, dropped, + ) + keep = complete + + require(keep, "No NG scenarios remain after coverage filtering.") + out_scen = (scenario_table[scenario_table["scenario_id"].isin(keep)] + .copy().reset_index(drop=True)) + out_frames = { + name: frame[frame["scenario_id"].isin(keep)].copy() + for name, frame in series_frames.items() + } + return out_scen, out_frames + + +def validate_ng_coverage( + frame: pd.DataFrame, + scenarios: list[str], + region_order: list[str], + start_year: int, + end_year: int, + label: str, +) -> None: + """Verify that a DataFrame has complete scenario × region × year coverage.""" + expected = { + (sid, reg, yr) + for sid in scenarios + for reg in region_order + for yr in range(start_year, end_year + 1) + } + actual = { + (r.scenario_id, r.cendiv, int(r.year)) + for r in frame[["scenario_id", "cendiv", "year"]].itertuples(index=False) + } + missing = expected - actual + require( + not missing, + f"{label} missing scenario/region/year combos. " + f"Sample: {list(sorted(missing))[:10]}", + ) + + +# ============================================================================ +# Historical Data Handling +# ============================================================================ + +def resolve_history_file(input_dir: Path, stem: str, + history_suffix: str) -> Path: + """Locate a historical data CSV file.""" + file_path = input_dir / f"{stem}_{history_suffix}.csv" + require(file_path.exists(), + f"History source file not found: {file_path}") + return file_path + + +def load_history_wide_file( + file_path: Path, + value_col: str, + region_order: list[str], +) -> pd.DataFrame: + """ + Load a wide-format historical CSV and melt to long format. + + Expected CSV format: year/t column + one column per region (output labels). + Returns: DataFrame with [cendiv, year, ]. + """ + require(file_path.exists(), + f"History source file not found: {file_path}") + df = pd.read_csv(file_path) + year_col = ("year" if "year" in df.columns + else ("t" if "t" in df.columns else None)) + require(year_col is not None, + f"History file missing 'year' or 't' column: {file_path}") + df = df.rename(columns={year_col: "year"}) + for col in df.columns: + if col != "year": + df[col] = pd.to_numeric(df[col], errors="coerce") + melted = (df.melt(id_vars=["year"], var_name="region_out", + value_name=value_col) + .dropna(subset=[value_col]).copy()) + melted["cendiv"] = melted["region_out"].map(output_label_to_cendiv) + melted["year"] = pd.to_numeric(melted["year"], errors="coerce").astype(int) + melted = melted[melted["cendiv"].isin(region_order)].copy() + return melted[["cendiv", "year", value_col]] + + +def apply_reference_history_to_all_scenarios( + frame: pd.DataFrame, + value_col: str, + history_frame: pd.DataFrame, + scenario_ids: list[str], + projection_start_year: int, +) -> pd.DataFrame: + """ + Backfill pre-projection years with historical data. + + Historical data is replicated identically across all scenarios, + since AEO scenarios share the same historical period. + """ + hist = history_frame[history_frame["year"] < projection_start_year].copy() + if hist.empty: + return frame + replicated = pd.concat( + [hist.assign(scenario_id=sid) for sid in scenario_ids], + ignore_index=True, + ) + future = frame[frame["year"] >= projection_start_year].copy() + out = pd.concat([future, replicated], ignore_index=True) + out = out.groupby( + ["scenario_id", "cendiv", "year"], as_index=False + )[value_col].mean() + return out + + +# ============================================================================ +# Beta Loading +# ============================================================================ + +def load_regional_betas(beta_path: Path, + region_order: list[str]) -> dict[str, float]: + """ + Load regional beta coefficients from a CSV file. + + The beta file (cd_beta0.csv) contains electric-sector-only betas, + representing the price sensitivity to regional electric sector demand: + Beta_regional(r) in units of 2004$/MMBtu per Quad + + A separate file (cd_beta0_allsector.csv) contains betas for total + economy-wide NG demand, used when modeling all-sector price feedback. + """ + require(beta_path.exists(), + f"Regional beta file not found: {beta_path}") + df = pd.read_csv(beta_path) + cendiv_col = next( + (c for c in df.columns if normalize_token(c).endswith("cendiv")), + None, + ) + value_col = next( + (c for c in df.columns if normalize_token(c) == "value"), + None, + ) + require(cendiv_col is not None and value_col is not None, + "Regional beta file missing cendiv/value columns.") + df["cendiv"] = df[cendiv_col].map(output_label_to_cendiv) + df["value"] = pd.to_numeric(df[value_col], errors="coerce") + df = df.dropna(subset=["cendiv", "value"]).copy() + betas = {row.cendiv: float(row.value) + for row in df[["cendiv", "value"]].itertuples(index=False)} + missing = [c for c in region_order if c not in betas] + require(not missing, f"Regional beta file missing regions: {missing}") + return betas + + +# ============================================================================ +# Alpha Computation (Core Calculation) +# ============================================================================ + +def compute_ng_alpha( + price_2004: pd.DataFrame, + demand_elec: pd.DataFrame, + beta_regional: dict[str, float], + beta_national: float, + first_model_year: int, +) -> pd.DataFrame: + """ + Compute NG alpha with a scenario-specific index alpha(region, year, scenario). + + For each scenario we compute an implied residual: + + alpha_2004 = price_2004 - beta_reg * q_reg - beta_nat * q_nat + + ReEDS sets both NG beta terms to zero in the first model year, so the + first-year alpha must carry the full converted price level. + + Parameters + ---------- + price_2004 : DataFrame + Columns: [scenario_id, cendiv, year, price_2004] + demand_elec : DataFrame + Columns: [scenario_id, cendiv, year, demand_elec_quads] + beta_regional : dict + {cendiv: beta_value} for each census division + beta_national : float + National beta coefficient (2004$/MMBtu per Quad) + first_model_year : int + First modeled year in ReEDS. NG elasticity is disabled in this year. + + Returns + ------- + DataFrame with columns: [scenario_id, cendiv, year, alpha_2004]. + """ + # Merge price and regional demand. + merged = price_2004.merge( + demand_elec, + on=["scenario_id", "cendiv", "year"], + how="inner", + ) + + # Compute national demand: sum of regional electric demands per scenario-year. + q_nat = ( + demand_elec + .groupby(["scenario_id", "year"], as_index=False)["demand_elec_quads"] + .sum() + .rename(columns={"demand_elec_quads": "q_nat"}) + ) + merged = merged.merge(q_nat, on=["scenario_id", "year"], how="left") + + # Map regional betas. + merged["beta_reg"] = merged["cendiv"].map(beta_regional) + require( + not merged["beta_reg"].isna().any(), + "Missing regional beta values while computing NG alpha.", + ) + require( + not merged["q_nat"].isna().any(), + "Missing national demand values while computing NG alpha.", + ) + + # Scenario-level residual alpha. + merged["alpha_2004"] = ( + merged["price_2004"] + - merged["beta_reg"] * merged["demand_elec_quads"] + - beta_national * merged["q_nat"] + ) + first_year_mask = merged["year"] == first_model_year + merged.loc[first_year_mask, "alpha_2004"] = merged.loc[first_year_mask, "price_2004"] + out = merged[["scenario_id", "cendiv", "year", "alpha_2004"]].copy() + out = out.sort_values(["scenario_id", "cendiv", "year"]).reset_index(drop=True) + return out + + +# ============================================================================ +# Output Writing +# ============================================================================ +def pivot_ng_series( + frame: pd.DataFrame, + scenario_id: str, + value_col: str, + region_order: list[str], +) -> pd.DataFrame: + """Pivot a long-format series into wide format (year × region).""" + subset = frame[frame["scenario_id"] == scenario_id].copy() + subset["region_out"] = subset["cendiv"].map(cendiv_output_label) + pivot = subset.pivot_table( + index="year", columns="region_out", + values=value_col, aggfunc="mean", + ) + ordered_cols = [cendiv_output_label(c) for c in region_order] + pivot = pivot.reindex(columns=ordered_cols) + pivot = pivot.sort_index().reset_index() + return pivot + + +def write_ng_outputs( + scenario_table: pd.DataFrame, + price_raw: pd.DataFrame, + demand_elec: pd.DataFrame, + demand_total: pd.DataFrame, + alpha_2004: pd.DataFrame, + beta_regional: dict[str, float], + region_order: list[str], + config: dict[str, Any], + base_dir: Path, +) -> None: + """ + Write all NG output files to the configured output directory. + + Output files per scenario: + - ng_AEO_{year}_{suffix}.csv : NG prices (AEO native dollar year) + - ng_demand_AEO_{year}_{suffix}.csv : Electric sector demand (Quads) + - ng_tot_demand_AEO_{year}_{suffix}.csv : Total sector demand (Quads) + - alpha_AEO_{year}_{suffix}.csv : Alpha values (2004$/MMBtu) + + Shared output files: + - cd_beta0.csv : Electric sector regional betas + - cd_beta0_allsector.csv : All-sector regional betas (copied from input) + """ + ng_cfg = config["ng"] + aeo_year = int(config["aeo_year"]) + out_dir = resolve_path(base_dir, config["paths"]["output_dir"]) + out_dir.mkdir(parents=True, exist_ok=True) + + written_files: list[Path] = [] + + # --- Per-scenario output files --- + for row in scenario_table.itertuples(index=False): + scenario_id = str(row.scenario_id) + file_suffix = getattr(row, "file_suffix", None) + require(bool(file_suffix), + f"Missing output suffix for NG scenario '{scenario_id}'") + suffix = str(file_suffix) + + price_wide = pivot_ng_series( + price_raw, scenario_id, "ng_price", region_order) + elec_wide = pivot_ng_series( + demand_elec, scenario_id, "demand_elec_quads", region_order) + total_wide = pivot_ng_series( + demand_total, scenario_id, "demand_total_quads", region_order) + alpha_wide = pivot_ng_series( + alpha_2004, scenario_id, "alpha_2004", region_order + ).rename(columns={"year": "t"}) + + fn_price = out_dir / f"ng_AEO_{aeo_year}_{suffix}.csv" + fn_elec = out_dir / f"ng_demand_AEO_{aeo_year}_{suffix}.csv" + fn_total = out_dir / f"ng_tot_demand_AEO_{aeo_year}_{suffix}.csv" + fn_alpha = out_dir / f"alpha_AEO_{aeo_year}_{suffix}.csv" + + price_wide.to_csv(fn_price, index=False, float_format="%.6f") + elec_wide.to_csv(fn_elec, index=False, float_format="%.6f") + total_wide.to_csv(fn_total, index=False, float_format="%.6f") + alpha_wide.to_csv(fn_alpha, index=False, float_format="%.6f") + written_files.extend([fn_price, fn_elec, fn_total, fn_alpha]) + + # --- Beta output files --- + + # Preserve the ordering from the source beta file if possible + beta_order = list(region_order) + try: + beta_src = resolve_path(base_dir, ng_cfg["regional_beta_path"]) + if beta_src.exists(): + src_df = pd.read_csv(beta_src) + cendiv_col = next( + (c for c in src_df.columns + if normalize_token(c).endswith("cendiv")), + None, + ) + if cendiv_col: + src_order = [] + for label in src_df[cendiv_col].tolist(): + cendiv = output_label_to_cendiv(str(label)) + if cendiv in beta_regional and cendiv not in src_order: + src_order.append(cendiv) + if len(src_order) == len(region_order): + beta_order = src_order + except Exception as exc: + LOGGER.warning("Could not use regional beta source ordering: %s", exc) + + # cd_beta0.csv: electric sector betas + beta_df = pd.DataFrame({ + "*cendiv": [cendiv_output_label(c) for c in beta_order], + "value": [beta_regional[c] for c in beta_order], + }) + beta_file = out_dir / "cd_beta0.csv" + beta_df.to_csv(beta_file, index=False, float_format="%.6f") + written_files.append(beta_file) + + # cd_beta0_allsector.csv: all-sector betas (copied from input if available) + allsector_src = resolve_path(base_dir, ng_cfg["cd_beta0_allsector_path"]) + allsector_dst = out_dir / "cd_beta0_allsector.csv" + if allsector_src.exists(): + shutil.copy2(allsector_src, allsector_dst) + else: + LOGGER.warning( + "Configured cd_beta0_allsector source not found (%s). " + "Writing cd_beta0 values instead.", + allsector_src, + ) + beta_df = pd.DataFrame({ + "*cendiv": [cendiv_output_label(c) for c in region_order], + "value": [beta_regional[c] for c in region_order], + }) + beta_df.to_csv(allsector_dst, index=False, float_format="%.6f") + written_files.append(allsector_dst) + + LOGGER.info("Wrote NG outputs to %s (%d files)", out_dir, len(written_files)) + + +# ============================================================================ +# Main Pipeline +# ============================================================================ + +def run_ng_pipeline(config: dict[str, Any], base_dir: Path) -> None: + """ + Execute the full NG preprocessing pipeline: + + 1. Connect to EIA API and discover available scenarios + 2. Fetch price & demand series for all scenarios and regions + 3. Backfill historical data for pre-projection years + 4. Validate completeness of all data + 5. Convert prices from AEO dollar year to 2004$ using the deflator + 6. Compute alpha values using the supply curve inversion: + Alpha = Price_2004 - Beta_reg × Q_reg - Beta_nat × Q_nat + 7. Write output CSV files for ReEDS consumption + """ + api_key = resolve_api_key(config) + client = EiaClient(config["api"], api_key) + + ng_cfg = config["ng"] + aeo_year = int(config["aeo_year"]) + start_year = int(config["start_year"]) + end_year = int(config["end_year"]) + region_order = resolve_ng_region_order(config) + out_dir = resolve_path(base_dir, config["paths"]["output_dir"]) + out_dir.mkdir(parents=True, exist_ok=True) + raw_dir = out_dir / "raw_aeo_data" + raw_dir.mkdir(parents=True, exist_ok=True) + + scenarios_cfg = config.get("scenarios", {}) + if scenarios_cfg is None: + scenarios_cfg = {} + require(isinstance(scenarios_cfg, dict), "Config key 'scenarios' must be an object.") + alpha_scen_cfg = scenarios_cfg.get("alpha_regression", {}) + if alpha_scen_cfg is None: + alpha_scen_cfg = {} + require(isinstance(alpha_scen_cfg, dict), "Config key 'scenarios.alpha_regression' must be an object.") + + fetch_cfg = alpha_scen_cfg.get("fetch") + require( + fetch_cfg is None or isinstance(fetch_cfg, list), + "Config key 'scenarios.alpha_regression.fetch' must be a list when provided.", + ) + fetch_scenarios = [str(x).strip() for x in (fetch_cfg or []) if str(x).strip()] + output_aliases = resolve_output_scenario_aliases( + aeo_year, + alpha_scen_cfg.get("outputs"), + ) + + # ---- Step 1: Discover and resolve scenarios ---- + LOGGER.info("Step 1: Resolving AEO %d scenarios...", aeo_year) + all_scenarios = resolve_ng_scenarios( + client, + aeo_year, + include_scenarios=fetch_scenarios or None, + ) + output_scenarios = resolve_output_scenarios( + available_scenarios=all_scenarios, + aeo_year=aeo_year, + output_aliases=output_aliases, + ) + pd.DataFrame(client.get_facets(aeo_year, "scenario")).to_csv( + raw_dir / "scenario_facets.csv", index=False + ) + all_scenarios.to_csv(raw_dir / "selected_scenarios_all.csv", index=False) + output_scenarios.to_csv(raw_dir / "selected_scenarios_outputs.csv", index=False) + scenario_ids = all_scenarios["scenario_id"].tolist() + region_ids = list( + resolve_region_ids(client, aeo_year, ng_cfg["regions"]).values() + ) + pd.DataFrame(client.get_facets(aeo_year, "regionId")).to_csv( + raw_dir / "region_facets.csv", index=False + ) + + # ---- Step 2: Fetch price and demand data from EIA API ---- + LOGGER.info("Step 2: Fetching AEO data from EIA API...") + price_raw = fetch_aeo_series_by_scenario( + client, aeo_year, + NG_SERIES_NAMES["price"], + scenario_ids, region_ids, + "ng_price", start_year, end_year, + raw_output_path=raw_dir / "aeo_raw_ng_price.csv", + ) + demand_elec = fetch_aeo_series_by_scenario( + client, aeo_year, + NG_SERIES_NAMES["demand_elec"], + scenario_ids, region_ids, + "demand_elec_quads", start_year, end_year, + raw_output_path=raw_dir / "aeo_raw_ng_demand_electric_power.csv", + ) + demand_total = fetch_aeo_series_by_scenario( + client, aeo_year, + NG_SERIES_NAMES["demand_total"], + scenario_ids, region_ids, + "demand_total_quads", start_year, end_year, + raw_output_path=raw_dir / "aeo_raw_ng_demand_total.csv", + ) + + # ---- Step 3: Backfill historical data ---- + LOGGER.info("Step 3: Backfilling historical data...") + projection_start_year = int(min( + price_raw["year"].min(), + demand_elec["year"].min(), + demand_total["year"].min(), + )) + validation_start_year = projection_start_year + + if start_year < projection_start_year: + input_dir = resolve_path( + base_dir, + config["paths"].get("input_dir", config["paths"]["output_dir"]), + ) + try: + history_price = load_history_wide_file( + resolve_history_file(input_dir, "ng_AEO", HISTORY_SUFFIX), + "ng_price", region_order, + ) + history_elec = load_history_wide_file( + resolve_history_file( + input_dir, "ng_demand_AEO", HISTORY_SUFFIX), + "demand_elec_quads", region_order, + ) + history_total = load_history_wide_file( + resolve_history_file( + input_dir, "ng_tot_demand_AEO", HISTORY_SUFFIX), + "demand_total_quads", region_order, + ) + price_raw = apply_reference_history_to_all_scenarios( + price_raw, "ng_price", history_price, + scenario_ids, projection_start_year, + ) + demand_elec = apply_reference_history_to_all_scenarios( + demand_elec, "demand_elec_quads", history_elec, + scenario_ids, projection_start_year, + ) + demand_total = apply_reference_history_to_all_scenarios( + demand_total, "demand_total_quads", history_total, + scenario_ids, projection_start_year, + ) + validation_start_year = start_year + LOGGER.info( + "Backfilled %d-%d from historical files in %s.", + start_year, projection_start_year - 1, input_dir, + ) + except Exception as exc: + LOGGER.warning( + "Could not backfill NG history (%s). " + "Using available years %d-%d only.", + exc, projection_start_year, end_year, + ) + validation_start_year = projection_start_year + + # ---- Step 4: Filter and validate data completeness ---- + LOGGER.info("Step 4: Validating data completeness...") + all_scenarios, series_frames = filter_complete_ng_scenarios( + scenario_table=all_scenarios, + series_frames={ + "price": price_raw, + "demand_elec": demand_elec, + "demand_total": demand_total, + }, + region_order=region_order, + start_year=validation_start_year, + end_year=end_year, + ) + price_raw = series_frames["price"] + demand_elec = series_frames["demand_elec"] + demand_total = series_frames["demand_total"] + scenario_ids = all_scenarios["scenario_id"].tolist() + output_scenarios = ( + output_scenarios[output_scenarios["scenario_id"].isin(scenario_ids)] + .copy().reset_index(drop=True) + ) + require( + len(output_scenarios) == len(output_aliases), + "One or more required output scenarios were dropped by coverage filtering.", + ) + validate_ng_coverage( + price_raw, scenario_ids, region_order, + validation_start_year, end_year, "NG price", + ) + validate_ng_coverage( + demand_elec, scenario_ids, region_order, + validation_start_year, end_year, "NG electric demand", + ) + validate_ng_coverage( + demand_total, scenario_ids, region_order, + validation_start_year, end_year, "NG total demand", + ) + + # ---- Step 5: Convert prices to 2004$ ---- + LOGGER.info("Step 5: Converting prices to 2004$ (deflator=%.6f)...", + float(ng_cfg["price_deflator_to_2004"])) + deflator = float(ng_cfg["price_deflator_to_2004"]) + price_2004 = price_raw.copy() + price_2004["price_2004"] = price_2004["ng_price"] * deflator + + # ---- Step 6: Compute alpha values ---- + LOGGER.info("Step 6: Computing NG alpha values...") + beta_path = resolve_path(base_dir, ng_cfg["regional_beta_path"]) + beta_regional = load_regional_betas(beta_path, region_order) + national_beta_path = resolve_case_insensitive(beta_path.parent / "national_beta.csv") + require( + national_beta_path.exists(), + f"National beta file not found: {national_beta_path}", + ) + national_beta_df = pd.read_csv(national_beta_path) + require( + "beta" in national_beta_df.columns, + f"National beta file missing 'beta' column: {national_beta_path}", + ) + beta_vals = pd.to_numeric(national_beta_df["beta"], errors="coerce").dropna() + require( + not beta_vals.empty, + f"National beta file has no numeric beta value: {national_beta_path}", + ) + beta_national = float(beta_vals.iloc[0]) + LOGGER.info( + " Beta_national = %.10f (2004$/MMBtu per Quad, source=%s)", + beta_national, + national_beta_path, + ) + LOGGER.info( + " Beta_regional: %s", + {cendiv_output_label(k): f"{v:.6f}" for k, v in beta_regional.items()}, + ) + + alpha_2004 = compute_ng_alpha( + price_2004, + demand_elec, + beta_regional, + beta_national, + first_model_year=start_year, + ) + validate_ng_coverage( + alpha_2004, scenario_ids, region_order, + validation_start_year, end_year, "NG alpha", + ) + + # ---- Step 7: Write output files ---- + LOGGER.info("Step 7: Writing output files...") + write_ng_outputs( + scenario_table=output_scenarios, + price_raw=price_raw, + demand_elec=demand_elec, + demand_total=demand_total, + alpha_2004=alpha_2004, + beta_regional=beta_regional, + region_order=region_order, + config=config, + base_dir=base_dir, + ) + + +# ============================================================================ +# Entry Point +# ============================================================================ + +def main() -> int: + args = parse_args() + setup_logging(args.log_level) + + script_dir = Path(__file__).resolve().parent + cfg_path = Path(args.config) + if not cfg_path.is_absolute(): + cwd_candidate = resolve_case_insensitive( + (Path.cwd() / cfg_path).resolve()) + script_candidate = resolve_case_insensitive( + (script_dir / cfg_path).resolve()) + cfg_path = (cwd_candidate if cwd_candidate.exists() + else script_candidate) + + cfg = load_config(cfg_path) + if args.aeo_year is not None: + cfg["aeo_year"] = int(args.aeo_year) + + run_ng_pipeline(cfg, script_dir) + LOGGER.info("NG pipeline complete.") + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Exception as exc: + LOGGER.exception("Pipeline failed: %s", exc) + sys.exit(1) + + diff --git a/aeo_updates/natural_gas_price_regression/aeo_beta_regression.py b/aeo_updates/natural_gas_price_regression/aeo_beta_regression.py new file mode 100644 index 0000000..5413931 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/aeo_beta_regression.py @@ -0,0 +1,735 @@ +""" +NG Beta Regression: Estimate Regional and National Betas from AEO Scenarios +============================================================================ + +This script is a preprocessing step that runs BEFORE the main aeo_pipeline.py. +It estimates the beta coefficients used in the ReEDS NG supply curve model. + +Method +------ +The NG supply curve decomposes regional prices as: + + Price(r,t) = Alpha(r,t) + Beta_reg(r) * Q_reg(r,t) + Beta_nat * Q_nat(t) + +Alpha varies by region and year (absorbing all time-varying effects). +Beta_reg and Beta_nat are structural parameters estimated via regression. + +Estimation uses a joint fixed-effects regression across all regions: + + Price_2004(r,t,s) = Alpha(r,t) + Beta_reg(r) * Q_reg(r,t,s) + Beta_nat * Q_nat(t,s) + +Alpha(r,t) is absorbed by demeaning each variable across scenarios within +each (region, year) group. The joint OLS then estimates Beta_nat and all +regional Beta_reg values simultaneously. + +Data: By default uses ALL available years for selected AEO scenarios +EXCEPT High/Low O&G Supply (held out for alpha computation), but +scenario and year selection can be overridden in config under +scenarios.beta_regression. + +Usage +----- + python aeo_beta_regression.py --config aeo_pipeline_config.json + +Outputs +------- + outputs of beta regression/cd_beta0.csv : Regional betas + outputs of beta regression/national_beta.csv : National beta + outputs of beta regression/beta_regression_summary.csv : Full summary + outputs of beta regression/alpha_from_beta_regression.csv : Shared alpha(region, year) + outputs of beta regression/alpha_from_beta_by_scenario.csv : Scenario residual alpha candidates + outputs of beta regression/alpha from beta regression/alpha_from_beta_shared.csv : Wide shared alpha + outputs of beta regression/*.png : Generated by results_visualization.py +""" + +from __future__ import annotations + +import argparse +import json +import logging +import os +import re +import sys +from pathlib import Path +from typing import Any + +import numpy as np +import pandas as pd +import requests +from requests.adapters import HTTPAdapter + +from urllib3 import disable_warnings +from urllib3.exceptions import InsecureRequestWarning +from urllib3.util.retry import Retry + +LOGGER = logging.getLogger("beta_regression") + +# ============================================================================ +# Constants +# ============================================================================ + +REGION_TO_LABEL = { + "New England": "New_England", + "Middle Atlantic": "Mid_Atlantic", + "East North Central": "East_North_Central", + "West North Central": "West_North_Central", + "South Atlantic": "South_Atlantic", + "East South Central": "East_South_Central", + "West South Central": "West_South_Central", + "Mountain": "Mountain", + "Pacific": "Pacific", +} + +NG_SERIES_NAMES = { + "price": "Energy Prices : Electric Power : Natural Gas", + "demand_elec": "Energy Use : Electric Power : Natural Gas", +} + +# Scenarios to EXCLUDE from regression (held out for alpha computation) +EXCLUDE_SCENARIOS = {"highogs", "lowogs", "high oil and gas supply", + "low oil and gas supply"} + + +# ============================================================================ +# Helpers +# ============================================================================ + +def _norm(value: Any) -> str: + if value is None: + return "" + return re.sub(r"[^a-z0-9]+", "", + str(value).replace("\xa0", " ").strip().lower()) + + +def _region_label(region_name: str) -> str: + if region_name in REGION_TO_LABEL: + return REGION_TO_LABEL[region_name] + norm = _norm(region_name) + for name, label in REGION_TO_LABEL.items(): + if _norm(name) == norm or _norm(label) == norm: + return label + raise ValueError(f"Unknown region: {region_name}") + + +def _calc_r2(y: np.ndarray, y_hat: np.ndarray) -> float: + """R2 for demeaned data (where mean ~= 0, so SS_tot = sum(y^2)).""" + ss_res = float(np.sum((y - y_hat) ** 2)) + ss_tot = float(np.sum(y ** 2)) + return 1 - ss_res / ss_tot if ss_tot > 0 else 0.0 + + +def _parse_optional_int(value: Any, config_key: str) -> int | None: + if value is None: + return None + try: + return int(value) + except (TypeError, ValueError) as exc: + raise ValueError(f"Config key '{config_key}' must be an integer.") from exc + + +# ============================================================================ +# EIA API Client +# ============================================================================ + +class EiaClient: + def __init__(self, api_cfg: dict[str, Any], api_key: str): + self.base_url = api_cfg["base_url"].rstrip("/") + self.verify_ssl = bool(api_cfg.get("verify_ssl", True)) + self.timeout = int(api_cfg.get("timeout_seconds", 60)) + self.api_key = api_key + if not self.verify_ssl: + disable_warnings(InsecureRequestWarning) + retries = Retry( + total=int(api_cfg.get("max_retries", 4)), + backoff_factor=float(api_cfg.get("backoff_seconds", 1.0)), + status_forcelist=[429, 500, 502, 503, 504], + allowed_methods=["GET"], + raise_on_status=False, + ) + self.session = requests.Session() + self.session.mount("https://", HTTPAdapter(max_retries=retries)) + self.session.mount("http://", HTTPAdapter(max_retries=retries)) + + def _get(self, path: str, + params: list[tuple[str, str]] | None = None) -> dict: + url = f"{self.base_url}/{path.lstrip('/')}" + query = [("api_key", self.api_key)] + (params or []) + resp = self.session.get(url, params=query, + timeout=self.timeout, verify=self.verify_ssl) + resp.raise_for_status() + payload = resp.json() + if "response" not in payload: + raise ValueError(f"Unexpected payload from {path}") + return payload + + def get_facets(self, aeo_year: int, facet: str) -> list[dict]: + return self._get( + f"/aeo/{aeo_year}/facet/{facet}")["response"]["facets"] + + def get_data(self, aeo_year: int, + params: list[tuple[str, str]]) -> pd.DataFrame: + payload = self._get(f"/aeo/{aeo_year}/data", params) + for w in payload["response"].get("warnings", []): + LOGGER.warning("EIA: %s | %s", + w.get("warning"), w.get("description")) + data = payload["response"].get("data", []) + if not data: + raise ValueError(f"No data returned for AEO {aeo_year}") + return pd.DataFrame(data) + + +# ============================================================================ +# Scenario Discovery +# ============================================================================ + +def discover_regression_scenarios( + client: EiaClient, + aeo_year: int, + include_scenarios: list[str] | None = None, + exclude_aliases: list[str] | None = None, +) -> list[str]: + """ + Resolve beta-regression scenarios. + + If include_scenarios is provided, only those scenarios are used + (matching by scenario id or scenario name, case-insensitive). + Otherwise, all non-legacy scenarios are used except exclude_aliases. + """ + facets = client.get_facets(aeo_year, "scenario") + rows: list[dict[str, str]] = [] + for item in facets: + sid = str(item.get("id", "")).strip() + sname = str(item.get("name", "")).strip() + if not sid or _norm(sid).startswith("aeo"): + continue + rows.append({"scenario_id": sid, "scenario_name": sname}) + + if include_scenarios: + selected: list[str] = [] + missing: list[str] = [] + for raw in include_scenarios: + token = _norm(str(raw).replace("{aeo_year}", str(aeo_year))) + found = None + for row in rows: + sid = str(row["scenario_id"]) + sname = str(row["scenario_name"]) + if _norm(sid) == token or _norm(sname) == token: + found = sid + break + if found is None: + missing.append(str(raw)) + continue + if found not in selected: + selected.append(found) + if missing: + raise ValueError( + f"Configured beta_regression.include scenarios not found: {missing}" + ) + LOGGER.info("Regression scenarios from config (%d): %s", len(selected), selected) + if len(selected) < 3: + LOGGER.warning( + "Only %d scenarios in beta_regression.include - regression may be unreliable.", + len(selected), + ) + return selected + + excluded_tokens = {_norm(x) for x in (exclude_aliases or sorted(EXCLUDE_SCENARIOS))} + selected: list[str] = [] + excluded: list[str] = [] + for row in rows: + sid = str(row["scenario_id"]) + sname = str(row["scenario_name"]) + if _norm(sid) in excluded_tokens or _norm(sname) in excluded_tokens: + excluded.append(f"{sid} ({sname})") + continue + selected.append(sid) + LOGGER.info("Regression scenarios (%d): %s", len(selected), selected) + if excluded: + LOGGER.info("Excluded scenarios: %s", excluded) + if len(selected) < 3: + LOGGER.warning("Only %d scenarios - regression may be unreliable.", + len(selected)) + return selected + + +# ============================================================================ +# Data Fetching +# ============================================================================ + +def fetch_series(client: EiaClient, aeo_year: int, series_name: str, + scenario_ids: list[str], region_ids: list[str], + value_col: str, + raw_output_path: Path | None = None, + start_year: int | None = None, + end_year: int | None = None) -> pd.DataFrame: + """Fetch an AEO series for all scenarios/regions.""" + if (start_year is None) != (end_year is None): + raise ValueError( + "Both start_year and end_year must be provided together for fetch_series." + ) + if start_year is not None and end_year is not None and start_year > end_year: + raise ValueError(f"Invalid year window: start_year={start_year} > end_year={end_year}") + + series_facets = client.get_facets(aeo_year, "seriesId") + series_ids = [str(item["id"]) for item in series_facets + if _norm(item.get("name")) == _norm(series_name)] + if not series_ids: + raise ValueError(f"Series not found: {series_name}") + + params: list[tuple[str, str]] = [("data[]", "value")] + if start_year is not None and end_year is not None: + params.append(("start", str(start_year))) + params.append(("end", str(end_year))) + params.extend(("facets[scenario][]", s) for s in scenario_ids) + params.extend(("facets[regionId][]", r) for r in region_ids) + params.extend(("facets[seriesId][]", s) for s in series_ids) + + df = client.get_data(aeo_year, params) + if raw_output_path is not None: + raw_output_path.parent.mkdir(parents=True, exist_ok=True) + df.to_csv(raw_output_path, index=False, float_format="%.6f") + LOGGER.info("Wrote raw data for '%s' to %s (%d rows)", + series_name, raw_output_path, len(df)) + + df = df.rename(columns={"scenario": "scenario_id"}) + df["region"] = df["regionName"].map(_region_label) + df["year"] = pd.to_numeric(df["period"], errors="coerce").astype(int) + df[value_col] = pd.to_numeric(df["value"], errors="coerce") + df = df.dropna(subset=[value_col]) + df = df[df["scenario_id"].isin(scenario_ids)] + + out = (df.groupby(["scenario_id", "region", "year"], as_index=False) + [value_col].mean()) + LOGGER.info("Fetched '%s': %d rows (%d scenarios x %d regions x %d years)", + series_name, len(out), out["scenario_id"].nunique(), + out["region"].nunique(), out["year"].nunique()) + return out + + +# ============================================================================ +# Joint Beta Regression +# ============================================================================ + +def estimate_joint_betas( + price: pd.DataFrame, + demand: pd.DataFrame, + deflator: float, + regions: list[str], +) -> tuple[float, float, dict[str, float], dict[str, dict], pd.DataFrame, float]: + """ + Estimate all betas jointly from the full equation: + + Price_2004(r,t,s) = Alpha(r,t) + Beta_reg(r)*Q_reg(r,t,s) + Beta_nat*Q_nat(t,s) + + Demeaning across scenarios within each (region, year) removes Alpha. + OLS on the demeaned system estimates Beta_nat and all Beta_reg simultaneously. + + Returns: (beta_nat, beta_nat_r2, beta_reg_dict, regional_diagnostics, + regression_data, model_r2) + """ + # National demand = sum of regional demands per scenario-year + demand_nat = (demand.groupby(["scenario_id", "year"], as_index=False) + ["demand"].sum() + .rename(columns={"demand": "demand_nat"})) + + merged = price.merge(demand, on=["scenario_id", "region", "year"]) + merged = merged.merge(demand_nat, on=["scenario_id", "year"]) + merged["price_2004"] = merged["price"] * deflator + + # Demean across scenarios within each (region, year) group + for col, dcol in [("price_2004", "dp"), ("demand", "dq_reg"), + ("demand_nat", "dq_nat")]: + means = merged.groupby(["year", "region"])[col].transform("mean") + merged[dcol] = merged[col] - means + + # Build X matrix: [dq_nat, dq_reg(region1), dq_reg(region2), ...] + region_arr = merged["region"].to_numpy() + dq_reg_x = merged["dq_reg"].to_numpy() + x_cols = [merged["dq_nat"].to_numpy()] + for region in regions: + x_cols.append(np.where(region_arr == region, dq_reg_x, 0.0)) + X = np.column_stack(x_cols) + y = merged["dp"].to_numpy() + + # OLS + coeffs = np.linalg.lstsq(X, y, rcond=None)[0] + beta_nat = float(coeffs[0]) + beta_reg = {region: float(coeffs[i + 1]) for i, region in enumerate(regions)} + + # Diagnostics + y_hat = X @ coeffs + model_r2 = _calc_r2(y, y_hat) + + # Partial R2 for national beta (residualize out regional terms) + merged["dp_hat"] = y_hat + merged["beta_reg_val"] = merged["region"].map(beta_reg) + merged["dp_partial_nat"] = ( + merged["dp"] - merged["beta_reg_val"] * merged["dq_reg"] + ) + beta_nat_r2 = _calc_r2( + merged["dp_partial_nat"].to_numpy(), + beta_nat * merged["dq_nat"].to_numpy()) + + # Per-region partial R2 (residualize out national term) + merged["dp_partial_reg"] = merged["dp"] - beta_nat * merged["dq_nat"] + regional_diag: dict[str, dict] = {} + for region in regions: + reg = merged[merged["region"] == region] + if reg.empty: + continue + regional_diag[region] = { + "r2_partial": _calc_r2( + reg["dp_partial_reg"].to_numpy(), + beta_reg[region] * reg["dq_reg"].to_numpy()), + "r2_full": _calc_r2( + reg["dp"].to_numpy(), reg["dp_hat"].to_numpy()), + "n_obs": len(reg), + } + + # Log results + LOGGER.info("Joint model: beta_nat=%.10f (partial R2=%.4f, model R2=%.4f)", + beta_nat, beta_nat_r2, model_r2) + for region in regions: + diag = regional_diag.get(region, {}) + LOGGER.info(" %-25s beta=%.10f (partial R2=%.4f, n=%d)", + region, beta_reg[region], + diag.get("r2_partial", float("nan")), + diag.get("n_obs", 0)) + + return beta_nat, beta_nat_r2, beta_reg, regional_diag, merged, model_r2 + + +# ============================================================================ +# Output: CSVs +# ============================================================================ + +def save_outputs( + out_dir: Path, + beta_nat: float, + beta_nat_r2: float, + beta_reg: dict[str, float], + regional_diag: dict[str, dict], + reg_data: pd.DataFrame, + model_r2: float, + first_model_year: int, +) -> None: + """Write beta tables and regression diagnostics.""" + out_dir.mkdir(parents=True, exist_ok=True) + + # cd_beta0.csv + pd.DataFrame({ + "*cendiv": list(beta_reg.keys()), + "value": list(beta_reg.values()), + }).to_csv(out_dir / "cd_beta0.csv", index=False, float_format="%.6f") + + # national_beta.csv + pd.DataFrame([{ + "beta": beta_nat, + }]).to_csv(out_dir / "national_beta.csv", index=False, float_format="%.6f") + + # Summary table + rows = [{ + "scope": "national", "region": "ALL", "beta": beta_nat, + "r2": beta_nat_r2, "r2_full": model_r2, "n_obs": len(reg_data), + }] + for region, beta in beta_reg.items(): + diag = regional_diag.get(region, {}) + rows.append({ + "scope": "regional", "region": region, "beta": beta, + "r2": diag.get("r2_partial", float("nan")), + "r2_full": diag.get("r2_full", float("nan")), + "n_obs": diag.get("n_obs", 0), + }) + pd.DataFrame(rows).to_csv( + out_dir / "beta_regression_summary.csv", + index=False, float_format="%.6f") + + # Regression point data for review + point_cols = ["scenario_id", "year", "region", "demand", "demand_nat", + "price", "price_2004", "dp", "dq_reg", "dq_nat", + "dp_partial_reg", "dp_partial_nat", "dp_hat"] + available = [c for c in point_cols if c in reg_data.columns] + reg_data[available].to_csv( + out_dir / "regression_points.csv", index=False, float_format="%.6f") + + # Alpha from beta-step data: + # 1) Scenario residual alpha candidate: + # alpha_candidate(r,t,s) = price_2004 - beta_reg*regional_demand - beta_nat*national_demand + # except in the first modeled year, where ReEDS disables both beta terms + # and alpha must therefore equal the full converted price. + # 2) Model alpha indexed by (region, year): + # alpha_shared(r,t) = mean_s(alpha_candidate(r,t,s)) + alpha_need = {"scenario_id", "year", "region", "price_2004", "demand", "demand_nat"} + missing_alpha_cols = sorted(alpha_need - set(reg_data.columns)) + if missing_alpha_cols: + raise ValueError( + f"Regression data missing columns needed for alpha export: {missing_alpha_cols}" + ) + + alpha_long = reg_data[ + ["scenario_id", "year", "region", "price_2004", "demand", "demand_nat"] + ].copy() + alpha_long = alpha_long.rename( + columns={"demand": "demand_elec_quads", "demand_nat": "q_nat"} + ) + alpha_long["beta_reg"] = alpha_long["region"].map(beta_reg) + if alpha_long["beta_reg"].isna().any(): + bad = sorted(alpha_long.loc[alpha_long["beta_reg"].isna(), "region"].astype(str).unique().tolist()) + raise ValueError(f"Missing regional beta values while exporting alpha: {bad}") + alpha_long["beta_nat"] = beta_nat + alpha_long["alpha_candidate"] = ( + alpha_long["price_2004"] + - alpha_long["beta_reg"] * alpha_long["demand_elec_quads"] + - alpha_long["beta_nat"] * alpha_long["q_nat"] + ) + first_year_mask = alpha_long["year"] == first_model_year + alpha_long.loc[first_year_mask, "alpha_candidate"] = alpha_long.loc[first_year_mask, "price_2004"] + alpha_long = alpha_long.sort_values(["scenario_id", "year", "region"]).reset_index(drop=True) + alpha_long.to_csv( + out_dir / "alpha_from_beta_by_scenario.csv", + index=False, + float_format="%.6f", + ) + + alpha_shared = ( + alpha_long.groupby(["region", "year"], as_index=False)["alpha_candidate"] + .mean() + .rename(columns={"alpha_candidate": "alpha_2004"}) + ) + n_scenarios = ( + alpha_long.groupby(["region", "year"], as_index=False)["scenario_id"] + .nunique() + .rename(columns={"scenario_id": "n_scenarios_used"}) + ) + alpha_shared = alpha_shared.merge(n_scenarios, on=["region", "year"], how="left") + alpha_shared = alpha_shared.sort_values(["region", "year"]).reset_index(drop=True) + alpha_shared.to_csv( + out_dir / "alpha_from_beta_regression.csv", + index=False, + float_format="%.6f", + ) + + alpha_wide_dir = out_dir / "alpha from beta regression" + alpha_wide_dir.mkdir(parents=True, exist_ok=True) + # Remove stale per-scenario files from earlier output format. + for old in alpha_wide_dir.glob("alpha_from_beta_*.csv"): + old.unlink() + old_index = alpha_wide_dir / "alpha_from_beta_files.csv" + if old_index.exists(): + old_index.unlink() + + alpha_wide = ( + alpha_shared.pivot_table( + index="year", + columns="region", + values="alpha_2004", + aggfunc="mean", + ) + .sort_index() + .reset_index() + ) + alpha_wide.to_csv( + alpha_wide_dir / "alpha_from_beta_shared.csv", + index=False, + float_format="%.6f", + ) + + LOGGER.info("Wrote outputs to %s", out_dir) + + +# ============================================================================ +# Pipeline +# ============================================================================ + +def run(config: dict[str, Any], base_dir: Path) -> None: + ng_cfg = config["ng"] + aeo_year = int(config["aeo_year"]) + deflator = float(ng_cfg["price_deflator_to_2004"]) + regions_config = ng_cfg["regions"] + regions = [REGION_TO_LABEL[r] for r in regions_config] + + # API key + api_key = os.getenv( + config["api"].get("key_env_var", "EIA_API_KEY"), + config["api"].get("key_fallback", ""), + ).strip() + if not api_key: + raise ValueError( + "Missing EIA API key. Set EIA_API_KEY or api.key_fallback.") + client = EiaClient(config["api"], api_key) + + scenarios_cfg = config.get("scenarios", {}) + if scenarios_cfg is None: + scenarios_cfg = {} + if not isinstance(scenarios_cfg, dict): + raise ValueError("Config key 'scenarios' must be an object.") + beta_scen_cfg = scenarios_cfg.get("beta_regression", {}) + if beta_scen_cfg is None: + beta_scen_cfg = {} + if not isinstance(beta_scen_cfg, dict): + raise ValueError("Config key 'scenarios.beta_regression' must be an object.") + + include_cfg = beta_scen_cfg.get("include") + if include_cfg is not None and not isinstance(include_cfg, list): + raise ValueError("Config key 'scenarios.beta_regression.include' must be a list.") + include_scenarios = [str(x).strip() for x in (include_cfg or []) if str(x).strip()] + + exclude_cfg = beta_scen_cfg.get("exclude_aliases") + if exclude_cfg is not None and not isinstance(exclude_cfg, list): + raise ValueError("Config key 'scenarios.beta_regression.exclude_aliases' must be a list.") + exclude_aliases = [str(x).strip() for x in (exclude_cfg or []) if str(x).strip()] + + beta_start_year = _parse_optional_int( + beta_scen_cfg.get("start_year"), "scenarios.beta_regression.start_year" + ) + beta_end_year = _parse_optional_int( + beta_scen_cfg.get("end_year"), "scenarios.beta_regression.end_year" + ) + if (beta_start_year is None) != (beta_end_year is None): + raise ValueError( + "Config keys 'scenarios.beta_regression.start_year' and " + "'scenarios.beta_regression.end_year' must be provided together." + ) + if beta_start_year is not None and beta_end_year is not None and beta_start_year > beta_end_year: + raise ValueError( + "Config key 'scenarios.beta_regression': start_year cannot be greater than end_year." + ) + if beta_start_year is not None and beta_end_year is not None: + LOGGER.info( + "Beta regression year range from config: %s-%s", + beta_start_year, beta_end_year, + ) + else: + LOGGER.info("Beta regression year range: all available AEO years.") + + # Step 1: Discover scenarios + LOGGER.info("Step 1: Discovering AEO %d scenarios...", aeo_year) + scenario_ids = discover_regression_scenarios( + client, + aeo_year, + include_scenarios=include_scenarios or None, + exclude_aliases=exclude_aliases or None, + ) + + # Resolve region IDs + facets = client.get_facets(aeo_year, "regionId") + region_lookup = {_norm(item["name"]): str(item["id"]) for item in facets} + region_ids = [] + for name in regions_config: + key = _norm(name) + if key not in region_lookup: + raise ValueError(f"Region not in EIA facets: {name}") + region_ids.append(region_lookup[key]) + + # Save raw facets for reference + out_dir = base_dir / "outputs of beta regression" + raw_dir = out_dir / "raw_aeo_data" + raw_dir.mkdir(parents=True, exist_ok=True) + pd.DataFrame(client.get_facets(aeo_year, "scenario")).to_csv( + raw_dir / "scenario_facets.csv", index=False) + pd.DataFrame({"selected_scenario_id": scenario_ids}).to_csv( + raw_dir / "selected_scenarios.csv", index=False) + + # Step 2: Fetch data + LOGGER.info("Step 2: Fetching price and demand data...") + price_raw = fetch_series( + client, aeo_year, NG_SERIES_NAMES["price"], + scenario_ids, region_ids, "price", + raw_output_path=raw_dir / "raw_ng_price.csv", + start_year=beta_start_year, + end_year=beta_end_year, + ) + demand_raw = fetch_series( + client, aeo_year, NG_SERIES_NAMES["demand_elec"], + scenario_ids, region_ids, "demand", + raw_output_path=raw_dir / "raw_ng_demand_elec.csv", + start_year=beta_start_year, + end_year=beta_end_year, + ) + if price_raw.empty or demand_raw.empty: + raise ValueError( + "No data available for configured beta regression year range." + ) + LOGGER.info( + "Price years used: %s-%s", + int(price_raw["year"].min()), + int(price_raw["year"].max()), + ) + LOGGER.info( + "Demand years used: %s-%s", + int(demand_raw["year"].min()), + int(demand_raw["year"].max()), + ) + + # Step 3: Estimate betas + LOGGER.info("Step 3: Estimating betas (joint fixed-effects regression)...") + (beta_nat, beta_nat_r2, beta_reg, regional_diag, + reg_data, model_r2) = estimate_joint_betas( + price_raw, + demand_raw, + deflator, + regions, + ) + + # Step 4: Save outputs + LOGGER.info("Step 4: Saving outputs...") + save_outputs(out_dir, beta_nat, beta_nat_r2, beta_reg, + regional_diag, reg_data, model_r2, + first_model_year=int(config["start_year"])) + + # Print summary + print("\n" + "=" * 60) + print("RESULTS") + print("=" * 60) + print(f"\nNational beta: {beta_nat:.15f}") + print(f"Model R2: {model_r2:.6f}") + print(f"\nRegional betas:") + for region, beta in beta_reg.items(): + diag = regional_diag.get(region, {}) + print(f" {region:25s} {beta:.12f} " + f"(partial R2={diag.get('r2_partial', float('nan')):.4f})") + print(f"\nOutputs: {out_dir}") + print("\nNext commands:") + print(" python sync_beta_to_alpha_inputs.py --config aeo_pipeline_config.json") + print(" python aeo_alpha_regression.py --config aeo_pipeline_config.json") + print(" python results_visualization.py --config aeo_pipeline_config.json") + print("=" * 60) + + +# ============================================================================ +# Entry Point +# ============================================================================ + +def main() -> int: + parser = argparse.ArgumentParser( + description="Estimate NG beta coefficients from AEO scenarios") + parser.add_argument("--config", default="aeo_pipeline_config.json") + parser.add_argument("--log-level", default="INFO", + choices=["DEBUG", "INFO", "WARNING", "ERROR"]) + parser.add_argument("--aeo-year", type=int, default=None) + args = parser.parse_args() + + logging.basicConfig(level=getattr(logging, args.log_level), + format="%(asctime)s | %(levelname)s | %(message)s") + + script_dir = Path(__file__).resolve().parent + cfg_path = Path(args.config) + if not cfg_path.is_absolute(): + cfg_path = (Path.cwd() / cfg_path if (Path.cwd() / cfg_path).exists() + else script_dir / cfg_path) + + with cfg_path.open() as f: + config = json.load(f) + if args.aeo_year is not None: + config["aeo_year"] = args.aeo_year + + run(config, script_dir) + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Exception as exc: + LOGGER.exception("Failed: %s", exc) + sys.exit(1) diff --git a/aeo_updates/natural_gas_price_regression/aeo_pipeline_config.json b/aeo_updates/natural_gas_price_regression/aeo_pipeline_config.json new file mode 100644 index 0000000..1a3efc8 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/aeo_pipeline_config.json @@ -0,0 +1,73 @@ +{ + "aeo_year": 2025, + "start_year": 2010, + "end_year": 2050, + "paths": { + "output_dir": "outputs of alpha regression", + "input_dir": "inputs for alpha regression" + }, + "scenarios": { + "beta_regression": { + "start_year": 2024, + "end_year": 2050, + "include": [ + "lm2025", + "hm2025", + "highZTC", + "lowZTC", + "alttrnp", + "nocaa111", + "ref2025" + ], + "exclude_aliases": [ + "highogs", + "highprice", + "lowprice", + "lowogs" + ] + }, + "alpha_regression": { + "fetch": [ + "ref{aeo_year}", + "highogs", + "lowogs" + ], + "outputs": { + "reference": [ + "ref{aeo_year}" + ], + "HOG": [ + "highogs" + ], + "LOG": [ + "lowogs" + ] + } + } + }, + "api": { + "base_url": "https://api.eia.gov/v2", + "key_env_var": "EIA_API_KEY", + "key_fallback": "", + "verify_ssl": false, + "timeout_seconds": 60, + "max_retries": 4, + "backoff_seconds": 1 + }, + "ng": { + "regions": [ + "New England", + "Middle Atlantic", + "East North Central", + "West North Central", + "South Atlantic", + "East South Central", + "West South Central", + "Mountain", + "Pacific" + ], + "price_deflator_to_2004": 0.602782, + "regional_beta_path": "inputs for alpha regression/cd_beta0.csv", + "cd_beta0_allsector_path": "inputs for alpha regression/cd_beta0_allsector.csv" + } +} diff --git a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/cd_beta0.csv b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/cd_beta0.csv new file mode 100644 index 0000000..946cf33 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/cd_beta0.csv @@ -0,0 +1,10 @@ +*cendiv,value +New_England,3.875323 +Mid_Atlantic,0.151497 +East_North_Central,0.033492 +West_North_Central,0.856915 +South_Atlantic,0.175498 +East_South_Central,0.139571 +West_South_Central,-0.054900 +Mountain,0.670353 +Pacific,1.341567 diff --git a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/national_beta.csv b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/national_beta.csv new file mode 100644 index 0000000..abd889b --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/national_beta.csv @@ -0,0 +1,2 @@ +beta +0.080017 diff --git a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_AEO_historical.csv b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_AEO_historical.csv new file mode 100644 index 0000000..03349e5 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_AEO_historical.csv @@ -0,0 +1,15 @@ +year,East_North_Central,East_South_Central,Mid_Atlantic,Mountain,New_England,Pacific,South_Atlantic,West_North_Central,West_South_Central +2010,7.090994509,6.864627039,7.816364499,7.214633076,7.770429471,6.922075026,8.645587478,7.734288289,6.613847095 +2011,6.415244319,6.035802983,7.181609870,6.759039679,6.976605820,6.523092028,7.612683090,7.187830351,6.021934080 +2012,4.318396288,4.171336784,4.920954844,4.812692187,5.125687655,4.981962978,5.744142178,4.836968152,4.086242117 +2013,5.644571605,5.425661349,6.221772114,6.026713986,8.068124701,5.966594412,6.488062275,6.217397452,5.311725257 +2014,6.901573833,6.196133723,6.749785557,6.533248299,8.769201530,6.652865218,7.217679522,7.398615429,6.141907830 +2015,3.728469276,3.831858045,3.850319999,4.283486413,5.664139452,4.318227659,5.209638268,4.428216598,3.709608103 +2016,3.604329269,3.348941929,3.661067671,3.544383574,5.148299225,3.667086135,4.514280196,3.500406617,3.097469786 +2017,4.251331621,4.060241034,4.159690249,4.195250431,5.355284536,4.189158392,4.872571007,4.469496963,3.814340823 +2018,4.083060596,4.025984863,4.228362317,4.311701697,5.881253780,4.317322045,4.693187815,4.334410199,3.784559467 +2019,3.074154645,3.292143502,3.569319762,3.555691398,5.476462081,3.748837112,4.098978687,3.352608181,2.850897331 +2020,2.433600778,2.771317586,2.922260883,3.117010526,4.894556598,3.305044956,3.535609065,2.854163977,2.372945838 +2021,5.212049868,5.940867196,5.323929817,6.295938071,7.947848278,6.712710202,6.632815785,5.658208013,5.441225141 +2022,6.736810455,7.910931077,6.175171066,7.816437211,8.928908764,8.040398193,8.543692060,7.627994713,7.360516678 +2023,2.576696503,2.934271060,3.094089823,3.300290745,5.182356526,3.499381599,3.743502878,3.021988819,2.512475054 diff --git a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_demand_AEO_historical.csv b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_demand_AEO_historical.csv new file mode 100644 index 0000000..1f13e82 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_demand_AEO_historical.csv @@ -0,0 +1,15 @@ +year,East_North_Central,East_South_Central,Mid_Atlantic,Mountain,New_England,Pacific,South_Atlantic,West_North_Central,West_South_Central +2010,0.326000000,0.567000000,0.890000000,0.641000000,0.420000000,0.989000000,1.544000000,0.124000000,2.049000000 +2011,0.395000000,0.639000000,0.965000000,0.567000000,0.456000000,0.766000000,1.671000000,0.117000000,2.188000000 +2012,0.656000000,0.797000000,1.154000000,0.663000000,0.448000000,1.045000000,2.043000000,0.171000000,2.337000000 +2013,0.475000000,0.629000000,1.066000000,0.651000000,0.372000000,1.069000000,1.883000000,0.140000000,2.075000000 +2014,0.482860000,0.671910000,1.131480000,0.648910000,0.341750000,1.073730000,1.896250000,0.108070000,2.025670000 +2015,0.713310000,0.875420000,1.236450000,0.750920000,0.397610000,1.084430000,2.330100000,0.147160000,2.434110000 +2016,0.912140000,0.961900000,1.344500000,0.765760000,0.393180000,0.917910000,2.469830000,0.191920000,2.351840000 +2017,0.810260000,0.910900000,1.196160000,0.690330000,0.371410000,0.840900000,2.475890000,0.172190000,2.063170000 +2018,1.002570000,0.994602000,1.300064000,0.760259000,0.400407000,0.871735000,2.535531000,0.189613000,2.661307000 +2019,1.185716000,1.029824000,1.451554000,0.988215000,0.338651000,0.834003000,2.790259000,0.228314000,2.928261000 +2020,1.262778000,1.047204000,1.684218000,0.954761000,0.360853000,0.847681000,2.768037000,0.247312000,2.940385000 +2021,1.082247000,0.913914000,1.654776000,0.947247000,0.344592000,0.887034000,2.468727000,0.195056000,2.732240000 +2022,1.477695000,0.900480000,1.998293000,0.947744000,0.366773000,0.850175000,2.605338000,0.257507000,2.797009000 +2023,1.337029346,1.108779595,1.783250018,1.010900947,0.382071156,0.897524643,2.930797576,0.261853946,3.113279638 diff --git a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_tot_demand_AEO_historical.csv b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_tot_demand_AEO_historical.csv new file mode 100644 index 0000000..3fd49d3 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_tot_demand_AEO_historical.csv @@ -0,0 +1,15 @@ +year,East_North_Central,East_South_Central,Mid_Atlantic,Mountain,New_England,Pacific,South_Atlantic,West_North_Central,West_South_Central +2010,3.358270000,1.354117000,2.642740000,4.756302000,0.858180000,2.707125000,2.864664000,1.549812000,5.379282000 +2011,3.525401000,1.416257000,2.719853000,4.793510000,0.915348000,2.548560000,2.934925000,1.555518000,5.529355000 +2012,3.547677000,1.540446000,2.770951000,4.903691000,0.879083000,2.803605000,3.280124000,1.491081000,5.730931000 +2013,3.818099000,1.455897000,2.891799000,4.972179000,0.859505000,2.896845000,3.261053000,1.645916000,5.577358000 +2014,4.045156000,1.544663000,3.120449000,5.000559000,0.857731000,2.784841000,3.326574000,1.680470000,5.646739000 +2015,3.886718000,1.696394000,3.099138000,5.255469000,0.905922000,2.763970000,3.663951000,1.574979000,5.951674000 +2016,3.920965000,1.746690000,3.156144000,1.581652000,0.856641000,2.775395000,3.735140000,1.638642000,5.803449000 +2017,3.997107000,1.767733000,3.113560000,1.576464000,0.879541000,2.827698000,3.888779000,1.729600000,5.922212000 +2018,4.395236000,1.912479000,3.316355000,1.676031000,0.930977000,2.952353000,4.067651000,1.846236000,6.697608000 +2019,4.665439000,1.962087000,3.507681000,1.985243000,0.884965000,2.949311000,4.325762000,1.972424000,7.134515000 +2020,4.578500000,1.967894000,3.615312000,1.900725000,0.849804000,2.847719000,4.221534000,1.915619000,7.066121000 +2021,4.418462000,1.844552000,3.665614000,1.921409000,0.878472000,2.947445000,3.971677000,1.893204000,6.865973000 +2022,4.940085000,1.892741000,4.044715000,1.914708000,0.923152000,2.857152000,4.159855000,1.998683000,7.156394000 +2023,4.648726000,1.861391000,3.709178000,1.734919000,0.914369000,2.869450000,4.158048000,1.877739000,6.910273000 diff --git a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/st_cendiv.csv b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/st_cendiv.csv new file mode 100644 index 0000000..ddd1f6c --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/st_cendiv.csv @@ -0,0 +1,49 @@ +st,cendiv +WA,Pacific +OR,Pacific +CA,Pacific +NV,Mountain +ID,Mountain +MT,Mountain +WY,Mountain +UT,Mountain +AZ,Mountain +NM,Mountain +CO,Mountain +ND,WestNorthCentral +SD,WestNorthCentral +NE,WestNorthCentral +MN,WestNorthCentral +IA,WestNorthCentral +WI,EastNorthCentral +TX,WestSouthCentral +OK,WestSouthCentral +KS,WestNorthCentral +MO,WestNorthCentral +AR,WestSouthCentral +LA,WestSouthCentral +MI,EastNorthCentral +IL,EastNorthCentral +MS,EastSouthCentral +AL,EastSouthCentral +FL,SouthAtlantic +TN,EastSouthCentral +KY,EastSouthCentral +GA,SouthAtlantic +SC,SouthAtlantic +NC,SouthAtlantic +VA,SouthAtlantic +IN,EastNorthCentral +OH,EastNorthCentral +PA,MiddleAtlantic +WV,SouthAtlantic +MD,SouthAtlantic +DE,SouthAtlantic +NJ,MiddleAtlantic +NY,MiddleAtlantic +VT,NewEngland +NH,NewEngland +MA,NewEngland +CT,NewEngland +RI,NewEngland +ME,NewEngland diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_HOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_HOG.csv new file mode 100644 index 0000000..bd15a24 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_HOG.csv @@ -0,0 +1,42 @@ +t,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific +2010,4.683875,4.711564,4.274324,4.662090,5.211405,4.137874,3.986708,4.348851,4.172502 +2011,1.816973,3.561499,3.232512,3.611184,3.674279,2.927836,3.128783,3.072885,2.283110 +2012,0.608249,2.046157,1.835802,2.023827,2.358645,1.657890,1.846136,1.711282,0.855822 +2013,2.752758,2.919934,2.717595,2.958825,2.911482,2.513759,2.646788,2.527453,1.493478 +2014,3.290932,3.226641,3.473380,3.696553,3.347306,2.970546,3.142848,2.832533,1.899154 +2015,1.075644,1.335855,1.425834,1.745415,1.933618,1.389862,1.571987,1.280897,0.350384 +2016,0.754709,1.178244,1.317182,1.120629,1.462783,1.059535,1.171321,0.798267,0.154122 +2017,1.026077,1.563513,1.772830,1.783921,1.739926,1.557646,1.649825,1.303398,0.634367 +2018,1.135938,1.494356,1.570148,1.592753,1.526519,1.430504,1.569901,1.231905,0.575444 +2019,1.046547,0.989432,0.871149,0.883062,1.038922,0.898527,0.937047,0.538670,0.198677 +2020,0.582664,0.537068,0.455374,0.539249,0.676152,0.555077,0.622532,0.269587,-0.114263 +2021,2.557157,2.060218,2.207226,2.345262,2.666628,2.555234,2.531615,2.261831,1.958028 +2022,2.984533,2.443258,3.035049,3.401068,3.716464,3.666597,3.614054,3.099996,2.729752 +2023,0.616925,0.568648,0.482150,0.570957,0.715910,0.587715,0.659137,0.285438,-0.120982 +2024,-0.468010,-0.031321,0.210737,0.184579,0.497425,0.345082,0.398380,-0.191626,-0.546024 +2025,-0.454252,0.112763,0.344876,0.320929,0.499549,0.410939,0.468171,-0.100039,-0.445625 +2026,-0.252073,0.019707,0.197131,0.206801,0.316351,0.224597,0.318176,-0.232231,-0.439900 +2027,-0.258877,-0.033279,0.157925,0.160226,0.353443,0.175124,0.277408,-0.229435,-0.439578 +2028,-0.289135,-0.037449,0.207416,0.252221,0.437009,0.262914,0.367318,-0.125625,-0.368992 +2029,-0.322310,-0.032144,0.242622,0.276503,0.477042,0.314815,0.415802,-0.066422,-0.365759 +2030,-0.251269,-0.033219,0.269754,0.334502,0.533248,0.378667,0.493271,0.001634,-0.312151 +2031,-0.182167,-0.023406,0.268865,0.299335,0.481149,0.424748,0.550534,0.069528,-0.296495 +2032,-0.176144,-0.010662,0.332092,0.340568,0.630270,0.490504,0.644607,0.153234,-0.183365 +2033,-0.082352,0.064029,0.371831,0.450130,0.590180,0.539430,0.707330,0.282865,-0.174894 +2034,-0.011003,0.122283,0.403914,0.500722,0.619309,0.565403,0.733782,0.370414,-0.123494 +2035,0.056341,0.171979,0.439723,0.566309,0.668940,0.607326,0.777152,0.464788,-0.103677 +2036,0.093461,0.217097,0.495611,0.691647,0.737113,0.667947,0.818150,0.464172,0.082731 +2037,0.092945,0.236787,0.497352,0.689038,0.757634,0.683358,0.805579,0.502848,0.041974 +2038,0.198916,0.280015,0.536568,0.770227,0.813723,0.734539,0.833305,0.692031,0.112107 +2039,0.222122,0.334648,0.576221,0.812897,0.867698,0.788379,0.877299,0.836469,0.184849 +2040,0.164746,0.307851,0.575600,0.855858,0.862221,0.801046,0.902691,0.861927,0.224821 +2041,0.221233,0.307528,0.575753,0.895945,0.870508,0.810443,0.930069,0.924016,0.204696 +2042,0.198786,0.317525,0.557631,0.881745,0.867713,0.813421,0.943432,0.923621,0.243462 +2043,0.097936,0.235768,0.489477,0.812074,0.819954,0.749603,0.912820,0.831754,0.237156 +2044,0.027747,0.142980,0.424122,0.753046,0.782351,0.713009,0.886083,0.730459,0.171369 +2045,0.070819,0.076273,0.370421,0.713242,0.758601,0.681674,0.876443,0.676002,0.217207 +2046,0.043637,0.029397,0.349860,0.715050,0.743219,0.669778,0.883537,0.695452,0.199327 +2047,-0.012972,-0.008888,0.310455,0.696182,0.833784,0.649055,0.856814,0.660313,0.230160 +2048,-0.033075,-0.029444,0.296592,0.695373,0.847091,0.657421,0.868570,0.662000,0.294965 +2049,-0.062187,-0.064672,0.245406,0.700461,0.791758,0.617461,0.841883,0.593020,0.265435 +2050,-0.061527,-0.095693,0.225173,0.701374,0.756995,0.585727,0.823963,0.525706,0.281430 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_LOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_LOG.csv new file mode 100644 index 0000000..2b3490f --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_LOG.csv @@ -0,0 +1,42 @@ +t,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific +2010,4.683875,4.711564,4.274324,4.662090,5.211405,4.137874,3.986708,4.348851,4.172502 +2011,1.816973,3.561499,3.232512,3.611184,3.674279,2.927836,3.128783,3.072885,2.283110 +2012,0.608249,2.046157,1.835802,2.023827,2.358645,1.657890,1.846136,1.711282,0.855822 +2013,2.752758,2.919934,2.717595,2.958825,2.911482,2.513759,2.646788,2.527453,1.493478 +2014,3.290932,3.226641,3.473380,3.696553,3.347306,2.970546,3.142848,2.832533,1.899154 +2015,1.075644,1.335855,1.425834,1.745415,1.933618,1.389862,1.571987,1.280897,0.350384 +2016,0.754709,1.178244,1.317182,1.120629,1.462783,1.059535,1.171321,0.798267,0.154122 +2017,1.026077,1.563513,1.772830,1.783921,1.739926,1.557646,1.649825,1.303398,0.634367 +2018,1.135938,1.494356,1.570148,1.592753,1.526519,1.430504,1.569901,1.231905,0.575444 +2019,1.046547,0.989432,0.871149,0.883062,1.038922,0.898527,0.937047,0.538670,0.198677 +2020,0.582664,0.537068,0.455374,0.539249,0.676152,0.555077,0.622532,0.269587,-0.114263 +2021,2.557157,2.060218,2.207226,2.345262,2.666628,2.555234,2.531615,2.261831,1.958028 +2022,2.984533,2.443258,3.035049,3.401068,3.716464,3.666597,3.614054,3.099996,2.729752 +2023,0.616925,0.568648,0.482150,0.570957,0.715910,0.587715,0.659137,0.285438,-0.120982 +2024,-0.484707,-0.029711,0.215051,0.187075,0.490094,0.339058,0.400083,-0.191824,-0.544057 +2025,0.320668,0.889994,1.169469,1.126793,1.370276,1.322634,1.365049,0.743120,0.468185 +2026,0.993648,1.277484,1.435401,1.432441,1.674898,1.591261,1.515472,1.117014,0.752048 +2027,0.980905,1.273043,1.502568,1.511037,1.757396,1.668365,1.596232,1.214643,0.838834 +2028,1.115336,1.426261,1.681291,1.729195,1.990057,1.917707,1.845684,1.497429,1.103785 +2029,1.380942,1.682775,1.977326,2.076482,2.297298,2.224647,2.187165,1.860526,1.387974 +2030,1.840662,2.120230,2.498073,2.597319,2.855960,2.814701,2.806373,2.476454,1.950263 +2031,2.351311,2.540952,2.922170,3.044480,3.339785,3.231337,3.234114,2.981482,2.424394 +2032,2.669670,2.992064,3.379454,3.481538,3.697091,3.625742,3.664041,3.420201,2.877220 +2033,3.059481,3.288055,3.661245,3.739282,3.982265,3.901682,3.892631,3.630120,3.098685 +2034,3.327007,3.470360,3.835762,3.868858,4.168600,4.056546,4.057258,3.855987,3.313662 +2035,3.407640,3.607970,3.940490,3.954335,4.302966,4.191552,4.110478,4.031437,3.491140 +2036,3.491305,3.658682,4.100178,4.105921,4.517574,4.374171,4.338926,4.314109,3.745742 +2037,3.563082,3.640128,4.073614,4.119122,4.676863,4.422630,4.451877,4.387943,3.863371 +2038,3.496389,3.579627,4.013947,4.087316,4.663879,4.282977,4.440391,4.456922,3.936299 +2039,3.442832,3.570535,3.965983,3.972211,4.789079,4.428681,4.607058,4.655245,4.161951 +2040,3.426911,3.551047,4.031987,4.088288,4.760876,4.429668,4.625246,4.705194,4.199913 +2041,3.355756,3.562317,4.022913,4.099254,4.802329,4.621356,4.622140,4.565469,4.239417 +2042,3.316872,3.460866,3.963444,4.055829,4.750108,4.518745,4.571450,4.480272,4.109517 +2043,3.212400,3.392686,3.895821,4.008246,4.675000,4.415660,4.488237,4.357078,4.036913 +2044,3.171646,3.403920,3.905402,4.001124,4.676325,4.547160,4.638910,4.514365,4.149064 +2045,3.150600,3.423385,3.930714,4.048498,4.583925,4.517120,4.686094,4.607649,4.239064 +2046,3.230419,3.472359,4.060075,4.183568,4.623913,4.547413,4.733054,4.655728,4.276129 +2047,3.330979,3.606305,4.195563,4.287413,4.773827,4.762990,4.918477,4.865448,4.463472 +2048,3.450908,3.740855,4.353308,4.443471,4.956059,4.887999,5.152434,5.097561,4.618085 +2049,3.627606,3.934228,4.524340,4.607130,5.109198,5.046874,5.350720,5.257141,4.741983 +2050,3.805277,4.124450,4.696611,4.764436,5.306124,5.230470,5.537398,5.452070,4.890810 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_reference.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_reference.csv new file mode 100644 index 0000000..bb30fc0 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_reference.csv @@ -0,0 +1,42 @@ +t,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific +2010,4.683875,4.711564,4.274324,4.662090,5.211405,4.137874,3.986708,4.348851,4.172502 +2011,1.816973,3.561499,3.232512,3.611184,3.674279,2.927836,3.128783,3.072885,2.283110 +2012,0.608249,2.046157,1.835802,2.023827,2.358645,1.657890,1.846136,1.711282,0.855822 +2013,2.752758,2.919934,2.717595,2.958825,2.911482,2.513759,2.646788,2.527453,1.493478 +2014,3.290932,3.226641,3.473380,3.696553,3.347306,2.970546,3.142848,2.832533,1.899154 +2015,1.075644,1.335855,1.425834,1.745415,1.933618,1.389862,1.571987,1.280897,0.350384 +2016,0.754709,1.178244,1.317182,1.120629,1.462783,1.059535,1.171321,0.798267,0.154122 +2017,1.026077,1.563513,1.772830,1.783921,1.739926,1.557646,1.649825,1.303398,0.634367 +2018,1.135938,1.494356,1.570148,1.592753,1.526519,1.430504,1.569901,1.231905,0.575444 +2019,1.046547,0.989432,0.871149,0.883062,1.038922,0.898527,0.937047,0.538670,0.198677 +2020,0.582664,0.537068,0.455374,0.539249,0.676152,0.555077,0.622532,0.269587,-0.114263 +2021,2.557157,2.060218,2.207226,2.345262,2.666628,2.555234,2.531615,2.261831,1.958028 +2022,2.984533,2.443258,3.035049,3.401068,3.716464,3.666597,3.614054,3.099996,2.729752 +2023,0.616925,0.568648,0.482150,0.570957,0.715910,0.587715,0.659137,0.285438,-0.120982 +2024,-0.505133,-0.041746,0.202311,0.174344,0.557962,0.323449,0.391092,-0.207917,-0.576337 +2025,-0.229539,0.347671,0.602813,0.572750,0.772238,0.692976,0.749541,0.205100,-0.115501 +2026,0.116280,0.431180,0.613034,0.607796,0.782696,0.694058,0.728853,0.230798,-0.054895 +2027,0.025300,0.312819,0.540627,0.519140,0.799770,0.615471,0.672565,0.178473,-0.086562 +2028,-0.005586,0.295013,0.581150,0.597140,0.796321,0.707458,0.769714,0.304707,-0.041584 +2029,0.067221,0.342341,0.669987,0.689225,1.001846,0.822394,0.892482,0.459622,0.070685 +2030,0.201912,0.407551,0.746032,0.790169,1.023289,0.956262,1.043240,0.616757,0.206840 +2031,0.270865,0.511255,0.851821,0.911957,1.103114,1.056561,1.155028,0.763157,0.321341 +2032,0.383170,0.615433,1.019251,1.080553,1.263653,1.236409,1.392116,1.014594,0.526482 +2033,0.667851,0.857661,1.250259,1.359765,1.550552,1.509990,1.683922,1.402480,0.878486 +2034,0.851366,1.009215,1.397943,1.597190,1.725658,1.689997,1.869690,1.640171,1.045899 +2035,0.910406,1.079863,1.492374,1.688441,1.819346,1.788715,1.911618,1.722907,1.135310 +2036,0.978942,1.117161,1.541326,1.757318,1.874950,1.811399,1.912304,1.746874,1.165524 +2037,0.991961,1.155582,1.536159,1.773991,1.942654,1.834123,1.941018,1.796241,1.212068 +2038,0.941332,1.140687,1.487182,1.777185,1.946024,1.834754,1.955180,1.836029,1.255656 +2039,0.903317,1.106120,1.483093,1.738510,1.942899,1.813399,1.955097,1.852664,1.292380 +2040,0.902075,1.076208,1.465823,1.783399,1.951433,1.816640,1.997464,1.929209,1.386383 +2041,0.940136,1.079738,1.485430,1.852105,1.952438,1.837854,2.062283,2.034826,1.503686 +2042,0.974734,1.120315,1.518709,1.936311,1.987258,1.858898,2.136794,2.110740,1.655205 +2043,1.000147,1.132037,1.529437,1.962805,2.038861,1.936040,2.223861,2.199057,1.697789 +2044,1.041327,1.123951,1.519776,1.987807,2.050695,1.964234,2.287435,2.219031,1.774132 +2045,1.086377,1.099421,1.520266,1.967755,2.027370,1.974527,2.312392,2.234710,1.797817 +2046,1.034779,1.143505,1.528193,2.025646,2.053118,2.019305,2.355159,2.302125,1.933259 +2047,1.059170,1.127624,1.514791,1.996091,2.015636,2.018503,2.409184,2.347354,1.939243 +2048,0.948902,1.098686,1.495751,1.948797,1.953655,1.965800,2.405515,2.275422,1.943456 +2049,0.957797,1.069420,1.466790,1.903059,1.896208,1.856363,2.375852,2.194083,1.949716 +2050,0.950400,1.008986,1.448063,1.910854,1.828244,1.769984,2.347436,2.211597,1.936905 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0.csv new file mode 100644 index 0000000..946cf33 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0.csv @@ -0,0 +1,10 @@ +*cendiv,value +New_England,3.875323 +Mid_Atlantic,0.151497 +East_North_Central,0.033492 +West_North_Central,0.856915 +South_Atlantic,0.175498 +East_South_Central,0.139571 +West_South_Central,-0.054900 +Mountain,0.670353 +Pacific,1.341567 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0_allsector.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0_allsector.csv new file mode 100644 index 0000000..946cf33 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0_allsector.csv @@ -0,0 +1,10 @@ +*cendiv,value +New_England,3.875323 +Mid_Atlantic,0.151497 +East_North_Central,0.033492 +West_North_Central,0.856915 +South_Atlantic,0.175498 +East_South_Central,0.139571 +West_South_Central,-0.054900 +Mountain,0.670353 +Pacific,1.341567 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_HOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_HOG.csv new file mode 100644 index 0000000..fc1046e --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_HOG.csv @@ -0,0 +1,42 @@ +year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific +2010,7.770429,7.816364,7.090995,7.734288,8.645587,6.864627,6.613847,7.214633,6.922075 +2011,6.976606,7.181610,6.415244,7.187830,7.612683,6.035803,6.021934,6.759040,6.523092 +2012,5.125688,4.920955,4.318396,4.836968,5.744142,4.171337,4.086242,4.812692,4.981963 +2013,8.068125,6.221772,5.644572,6.217397,6.488062,5.425661,5.311725,6.026714,5.966594 +2014,8.769202,6.749786,6.901574,7.398615,7.217680,6.196134,6.141908,6.533248,6.652865 +2015,5.664139,3.850320,3.728469,4.428217,5.209638,3.831858,3.709608,4.283486,4.318228 +2016,5.148299,3.661068,3.604329,3.500407,4.514280,3.348942,3.097470,3.544384,3.667086 +2017,5.355285,4.159690,4.251332,4.469497,4.872571,4.060241,3.814341,4.195250,4.189158 +2018,5.881254,4.228362,4.083061,4.334410,4.693188,4.025985,3.784559,4.311702,4.317322 +2019,5.476462,3.569320,3.074155,3.352608,4.098979,3.292144,2.850897,3.555691,3.748837 +2020,4.894557,2.922261,2.433601,2.854164,3.535609,2.771318,2.372946,3.117011,3.305045 +2021,7.947848,5.323930,5.212050,5.658208,6.632816,5.940867,5.441225,6.295938,6.712710 +2022,8.928909,6.175171,6.736810,7.627995,8.543692,7.910931,7.360517,7.816437,8.040398 +2023,5.182357,3.094090,2.576697,3.021989,3.743503,2.934271,2.512475,3.300291,3.499382 +2024,3.942886,2.287270,2.298708,2.621773,3.481087,2.680677,2.210615,2.863694,3.208913 +2025,3.545907,2.313296,2.394202,2.708847,3.371045,2.663157,2.218614,2.777358,2.887983 +2026,3.424357,2.298251,2.279395,2.664633,3.222955,2.498695,2.059296,2.712186,2.803907 +2027,3.179948,2.255369,2.267412,2.702573,3.352517,2.484879,2.033904,2.717369,2.824805 +2028,2.963628,2.219732,2.342423,2.822133,3.471617,2.607332,2.178029,2.860942,2.993797 +2029,2.897579,2.237025,2.422638,2.905383,3.536583,2.709477,2.279984,2.964342,3.117639 +2030,2.761189,2.309547,2.509715,3.080562,3.637365,2.835151,2.440423,3.228207,3.405689 +2031,2.747252,2.337410,2.525936,3.122771,3.510499,2.905147,2.544189,3.393098,3.586969 +2032,3.035183,2.531026,2.816504,3.501460,3.964278,3.177044,2.843096,3.814344,4.013958 +2033,3.119033,2.633990,2.860132,3.516799,3.848393,3.242102,2.926303,3.950235,4.208856 +2034,3.235024,2.714677,2.896689,3.576314,3.874689,3.271004,2.959214,4.049577,4.334771 +2035,3.332014,2.718911,2.911631,3.632553,3.886527,3.285653,2.990757,4.106940,4.363559 +2036,3.345162,2.679176,2.902459,3.651698,3.871522,3.277782,2.995825,4.154849,4.288165 +2037,3.331612,2.655793,2.849265,3.584962,3.826073,3.248419,2.955194,4.159271,4.251697 +2038,3.345557,2.610942,2.787631,3.559825,3.806650,3.233404,2.903788,4.197432,4.234464 +2039,3.217742,2.571926,2.754783,3.507277,3.787173,3.219203,2.895023,4.173839,4.281111 +2040,3.172366,2.542018,2.765788,3.599415,3.826042,3.249156,2.954316,4.291714,4.376058 +2041,3.339386,2.589555,2.809392,3.717389,3.902796,3.310269,3.031373,4.404143,4.470148 +2042,3.391913,2.603526,2.803964,3.731760,3.909537,3.326160,3.068110,4.446998,4.516488 +2043,3.330580,2.536290,2.752379,3.703559,3.898544,3.289931,3.063311,4.391260,4.504367 +2044,3.113896,2.437677,2.683260,3.646818,3.864220,3.263479,3.049417,4.328261,4.424861 +2045,2.985338,2.366950,2.627810,3.651798,3.847422,3.248250,3.060245,4.364906,4.511312 +2046,2.984034,2.338613,2.628173,3.720915,3.857837,3.277446,3.101784,4.417610,4.539052 +2047,2.934076,2.304000,2.562113,3.699291,4.006942,3.260696,3.061580,4.407011,4.557307 +2048,2.892148,2.251554,2.512380,3.689516,4.003499,3.256391,3.065140,4.434324,4.586201 +2049,2.865312,2.203854,2.461685,3.655248,3.966560,3.213834,3.041644,4.389663,4.565211 +2050,2.790408,2.150464,2.421813,3.591890,3.907777,3.162359,3.010422,4.376517,4.556719 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_LOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_LOG.csv new file mode 100644 index 0000000..ebfea64 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_LOG.csv @@ -0,0 +1,42 @@ +year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific +2010,7.770429,7.816364,7.090995,7.734288,8.645587,6.864627,6.613847,7.214633,6.922075 +2011,6.976606,7.181610,6.415244,7.187830,7.612683,6.035803,6.021934,6.759040,6.523092 +2012,5.125688,4.920955,4.318396,4.836968,5.744142,4.171337,4.086242,4.812692,4.981963 +2013,8.068125,6.221772,5.644572,6.217397,6.488062,5.425661,5.311725,6.026714,5.966594 +2014,8.769202,6.749786,6.901574,7.398615,7.217680,6.196134,6.141908,6.533248,6.652865 +2015,5.664139,3.850320,3.728469,4.428217,5.209638,3.831858,3.709608,4.283486,4.318228 +2016,5.148299,3.661068,3.604329,3.500407,4.514280,3.348942,3.097470,3.544384,3.667086 +2017,5.355285,4.159690,4.251332,4.469497,4.872571,4.060241,3.814341,4.195250,4.189158 +2018,5.881254,4.228362,4.083061,4.334410,4.693188,4.025985,3.784559,4.311702,4.317322 +2019,5.476462,3.569320,3.074155,3.352608,4.098979,3.292144,2.850897,3.555691,3.748837 +2020,4.894557,2.922261,2.433601,2.854164,3.535609,2.771318,2.372946,3.117011,3.305045 +2021,7.947848,5.323930,5.212050,5.658208,6.632816,5.940867,5.441225,6.295938,6.712710 +2022,8.928909,6.175171,6.736810,7.627995,8.543692,7.910931,7.360517,7.816437,8.040398 +2023,5.182357,3.094090,2.576697,3.021989,3.743503,2.934271,2.512475,3.300291,3.499382 +2024,3.951021,2.291188,2.306225,2.628691,3.470091,2.671443,2.214949,2.867855,3.213850 +2025,4.825856,3.629599,3.757886,4.032818,4.788136,4.158859,3.699224,4.146041,4.247904 +2026,4.605783,3.834864,3.800100,4.000161,4.790429,4.182667,3.667104,4.116380,4.119196 +2027,4.343827,3.835330,3.930441,4.200141,4.924905,4.337811,3.808350,4.269623,4.225954 +2028,4.395217,4.009411,4.168205,4.513605,5.188810,4.686580,4.175693,4.650997,4.694008 +2029,4.783993,4.403663,4.620580,5.094242,5.605813,5.149542,4.716477,5.207363,5.210474 +2030,5.429995,5.116742,5.483608,6.184416,6.492614,6.110940,5.740700,6.219917,6.208527 +2031,6.023727,5.623803,6.032155,6.668324,7.070742,6.622880,6.323299,6.823698,6.887148 +2032,6.769484,6.455877,6.900975,7.624558,7.802534,7.392770,7.123114,7.823699,7.795189 +2033,7.239462,6.816369,7.243104,7.822190,8.118889,7.728008,7.409045,8.029579,8.010993 +2034,7.573184,7.007079,7.448060,7.872682,8.326830,7.892791,7.609113,8.258191,8.196181 +2035,7.670228,7.163031,7.551923,7.904687,8.486915,8.054188,7.651300,8.444173,8.278070 +2036,7.708939,7.137417,7.728963,8.052999,8.726404,8.253443,7.956063,8.753573,8.491802 +2037,7.558604,6.949639,7.568828,7.982419,8.848077,8.212115,8.047225,8.739521,8.407489 +2038,7.343988,6.762915,7.392748,7.834982,8.740216,7.899144,7.963167,8.673278,8.322899 +2039,7.251116,6.737899,7.297922,7.645207,8.910620,8.110153,8.226623,9.006240,8.591912 +2040,7.218706,6.678354,7.382362,7.822319,8.836534,8.071926,8.232173,9.026676,8.661890 +2041,7.065958,6.644736,7.322939,7.732145,8.862980,8.334088,8.189538,8.673353,8.644938 +2042,6.963392,6.447856,7.199334,7.611486,8.753935,8.141396,8.084666,8.462022,8.381509 +2043,6.808531,6.334739,7.084161,7.540718,8.612486,7.972393,7.942930,8.241702,8.252924 +2044,6.503371,6.344906,7.090244,7.552183,8.590377,8.179617,8.183352,8.507860,8.446995 +2045,6.349429,6.351938,7.115554,7.610549,8.392526,8.105153,8.243489,8.658021,8.574844 +2046,6.509525,6.429235,7.327775,7.833263,8.438897,8.147901,8.316871,8.684699,8.631374 +2047,6.689818,6.661896,7.564465,8.053114,8.687522,8.513703,8.630199,9.064015,8.964581 +2048,6.918985,6.915947,7.853740,8.339838,9.020991,8.746612,9.039744,9.510916,9.287422 +2049,7.237922,7.254817,8.156782,8.634782,9.287102,9.029250,9.384081,9.833487,9.528601 +2050,7.553951,7.582260,8.458136,8.921481,9.627280,9.348893,9.705161,10.207071,9.821965 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_reference.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_reference.csv new file mode 100644 index 0000000..f3e1eec --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_reference.csv @@ -0,0 +1,42 @@ +year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific +2010,7.770429,7.816364,7.090995,7.734288,8.645587,6.864627,6.613847,7.214633,6.922075 +2011,6.976606,7.181610,6.415244,7.187830,7.612683,6.035803,6.021934,6.759040,6.523092 +2012,5.125688,4.920955,4.318396,4.836968,5.744142,4.171337,4.086242,4.812692,4.981963 +2013,8.068125,6.221772,5.644572,6.217397,6.488062,5.425661,5.311725,6.026714,5.966594 +2014,8.769202,6.749786,6.901574,7.398615,7.217680,6.196134,6.141908,6.533248,6.652865 +2015,5.664139,3.850320,3.728469,4.428217,5.209638,3.831858,3.709608,4.283486,4.318228 +2016,5.148299,3.661068,3.604329,3.500407,4.514280,3.348942,3.097470,3.544384,3.667086 +2017,5.355285,4.159690,4.251332,4.469497,4.872571,4.060241,3.814341,4.195250,4.189158 +2018,5.881254,4.228362,4.083061,4.334410,4.693188,4.025985,3.784559,4.311702,4.317322 +2019,5.476462,3.569320,3.074155,3.352608,4.098979,3.292144,2.850897,3.555691,3.748837 +2020,4.894557,2.922261,2.433601,2.854164,3.535609,2.771318,2.372946,3.117011,3.305045 +2021,7.947848,5.323930,5.212050,5.658208,6.632816,5.940867,5.441225,6.295938,6.712710 +2022,8.928909,6.175171,6.736810,7.627995,8.543692,7.910931,7.360517,7.816437,8.040398 +2023,5.182357,3.094090,2.576697,3.021989,3.743503,2.934271,2.512475,3.300291,3.499382 +2024,3.914745,2.269530,2.285080,2.605072,3.581676,2.645327,2.199480,2.841191,3.178771 +2025,3.945919,2.724665,2.837277,3.162053,3.846201,3.142428,2.702884,3.296411,3.449765 +2026,3.819109,2.780215,2.763278,3.076137,3.765639,3.055122,2.602545,3.156343,3.232441 +2027,3.435360,2.636923,2.703812,3.054238,3.837702,2.988694,2.549224,3.122164,3.154894 +2028,3.240752,2.576812,2.762565,3.195382,3.785440,3.127218,2.701754,3.269873,3.344125 +2029,3.229812,2.643674,2.918250,3.398271,4.085795,3.306478,2.910596,3.513918,3.634970 +2030,3.129285,2.773706,3.049576,3.646155,4.087484,3.512392,3.163967,3.861304,4.019860 +2031,3.326129,2.866469,3.170081,3.762861,4.101537,3.613755,3.303848,4.079747,4.274564 +2032,3.779099,3.222987,3.635774,4.423059,4.559186,4.085257,3.843493,4.733683,4.891140 +2033,4.071227,3.483385,3.881344,4.704285,4.842482,4.388517,4.214373,5.040173,5.191451 +2034,4.168971,3.598001,3.987692,4.772688,4.962396,4.544195,4.409548,5.230925,5.384827 +2035,4.199443,3.631619,4.045470,4.784186,5.016607,4.609845,4.425838,5.303466,5.412060 +2036,4.265835,3.610814,4.036805,4.780307,5.044314,4.556694,4.374448,5.251937,5.282920 +2037,4.120316,3.518157,3.899876,4.672058,4.979167,4.464017,4.317363,5.176685,5.104523 +2038,3.993610,3.376865,3.733063,4.566430,4.909653,4.376263,4.273121,5.154803,5.010477 +2039,3.816716,3.256926,3.681409,4.408439,4.850672,4.286094,4.233821,5.160571,4.923649 +2040,3.872509,3.215503,3.662889,4.491251,4.854046,4.299133,4.305593,5.306404,5.055543 +2041,3.966687,3.252421,3.723782,4.649086,4.880734,4.361627,4.432408,5.505489,5.287903 +2042,4.091134,3.298153,3.773970,4.751801,4.925858,4.390012,4.548378,5.683669,5.408764 +2043,4.169929,3.344024,3.805754,4.807343,5.008918,4.522407,4.704851,5.836872,5.563621 +2044,4.087124,3.347215,3.800041,4.817755,5.012309,4.578125,4.813431,5.905303,5.645613 +2045,3.891919,3.329523,3.798050,4.839172,4.970164,4.596054,4.858135,5.945200,5.636967 +2046,3.902629,3.393556,3.810532,4.945189,4.994895,4.665256,4.923351,6.013248,5.758965 +2047,3.945969,3.383668,3.770669,4.909540,4.917217,4.652761,5.001916,6.069484,5.808951 +2048,3.787596,3.349662,3.740844,4.859097,4.802450,4.571362,5.000763,6.010077,5.813332 +2049,3.870886,3.274235,3.685088,4.774216,4.690213,4.388964,4.946911,5.912456,5.796697 +2050,3.788044,3.161351,3.642668,4.791852,4.578797,4.235358,4.904408,5.972120,5.745820 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_HOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_HOG.csv new file mode 100644 index 0000000..20a30c6 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_HOG.csv @@ -0,0 +1,42 @@ +year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific +2010,0.420000,0.890000,0.326000,0.124000,1.544000,0.567000,2.049000,0.641000,0.989000 +2011,0.456000,0.965000,0.395000,0.117000,1.671000,0.639000,2.188000,0.567000,0.766000 +2012,0.448000,1.154000,0.656000,0.171000,2.043000,0.797000,2.337000,0.663000,1.045000 +2013,0.372000,1.066000,0.475000,0.140000,1.883000,0.629000,2.075000,0.651000,1.069000 +2014,0.341750,1.131480,0.482860,0.108070,1.896250,0.671910,2.025670,0.648910,1.073730 +2015,0.397610,1.236450,0.713310,0.147160,2.330100,0.875420,2.434110,0.750920,1.084430 +2016,0.393180,1.344500,0.912140,0.191920,2.469830,0.961900,2.351840,0.765760,0.917910 +2017,0.371410,1.196160,0.810260,0.172190,2.475890,0.910900,2.063170,0.690330,0.840900 +2018,0.400407,1.300064,1.002570,0.189613,2.535531,0.994602,2.661307,0.760259,0.871735 +2019,0.338651,1.451554,1.185716,0.228314,2.790259,1.029824,2.928261,0.988215,0.834003 +2020,0.360853,1.684218,1.262778,0.247312,2.768037,1.047204,2.940385,0.954761,0.847681 +2021,0.344592,1.654776,1.082247,0.195056,2.468727,0.913914,2.732240,0.947247,0.887034 +2022,0.366773,1.998293,1.477695,0.257507,2.605338,0.900480,2.797009,0.947744,0.850175 +2023,0.382071,1.783250,1.337029,0.261854,2.930798,1.108780,3.113280,1.010901,0.897525 +2024,0.446506,1.951789,1.807217,0.328414,2.772431,1.120767,3.282638,1.198553,1.018170 +2025,0.400232,1.590906,1.721987,0.316580,2.802444,1.101454,3.123186,1.094271,0.854088 +2026,0.311662,1.697816,2.042994,0.339554,2.951403,1.240576,3.375084,1.131739,0.761514 +2027,0.268560,1.701938,2.206338,0.389654,3.033981,1.345413,3.394222,1.092678,0.750901 +2028,0.244934,1.644293,2.334784,0.376410,3.015770,1.306726,3.293242,1.079716,0.780610 +2029,0.241361,1.630497,2.512054,0.398223,2.969723,1.324362,3.188257,1.073624,0.828471 +2030,0.196057,1.778863,2.602928,0.427727,2.868471,1.249770,3.244220,1.176084,0.901304 +2031,0.174589,1.787377,2.751464,0.491814,2.697150,1.181122,3.251625,1.214582,0.966842 +2032,0.193283,1.845946,3.253971,0.599109,2.864202,1.202948,3.415374,1.326644,1.003485 +2033,0.185470,1.848220,3.239930,0.497179,2.768513,1.226310,3.408022,1.274809,1.094409 +2034,0.187396,1.843454,3.205562,0.490385,2.743542,1.228781,3.366460,1.246807,1.119302 +2035,0.192078,1.710656,3.212188,0.484944,2.655394,1.185304,3.317858,1.197920,1.137609 +2036,0.199700,1.642419,3.132051,0.420684,2.550056,1.137773,2.939176,1.329532,1.008565 +2037,0.206521,1.644400,3.140409,0.416561,2.471244,1.144755,2.535467,1.326660,1.047966 +2038,0.197384,1.590891,2.716094,0.376668,2.439109,1.158549,2.472733,1.171483,1.034278 +2039,0.185696,1.437783,2.581804,0.354041,2.377795,1.105213,2.369297,1.016782,1.041979 +2040,0.191300,1.440836,2.550396,0.359027,2.495180,1.084304,2.332093,1.072407,1.048653 +2041,0.196422,1.471445,2.603838,0.366828,2.572892,1.106517,2.428086,1.044572,1.087787 +2042,0.208031,1.400841,2.774909,0.382864,2.560002,1.088461,2.434259,1.070091,1.072913 +2043,0.215927,1.453301,2.887747,0.405494,2.604740,1.150788,2.535568,1.107367,1.047360 +2044,0.195102,1.539554,2.989638,0.410800,2.585567,1.153446,2.570477,1.171576,1.045559 +2045,0.159384,1.580606,3.061960,0.439917,2.561460,1.184258,2.601221,1.259128,1.036926 +2046,0.161159,1.648451,3.099662,0.463651,2.573675,1.255747,2.629858,1.248391,1.048170 +2047,0.167061,1.739527,2.979110,0.466230,2.549114,1.305926,2.650514,1.285874,1.030689 +2048,0.168816,1.745558,2.855375,0.474269,2.529676,1.313169,2.607504,1.325776,1.004289 +2049,0.167950,1.680766,2.984837,0.425213,2.625262,1.298944,2.676126,1.364214,1.004726 +2050,0.156610,1.685399,2.927017,0.381755,2.632061,1.317363,2.658570,1.455590,0.990377 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_LOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_LOG.csv new file mode 100644 index 0000000..c848a10 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_LOG.csv @@ -0,0 +1,42 @@ +year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific +2010,0.420000,0.890000,0.326000,0.124000,1.544000,0.567000,2.049000,0.641000,0.989000 +2011,0.456000,0.965000,0.395000,0.117000,1.671000,0.639000,2.188000,0.567000,0.766000 +2012,0.448000,1.154000,0.656000,0.171000,2.043000,0.797000,2.337000,0.663000,1.045000 +2013,0.372000,1.066000,0.475000,0.140000,1.883000,0.629000,2.075000,0.651000,1.069000 +2014,0.341750,1.131480,0.482860,0.108070,1.896250,0.671910,2.025670,0.648910,1.073730 +2015,0.397610,1.236450,0.713310,0.147160,2.330100,0.875420,2.434110,0.750920,1.084430 +2016,0.393180,1.344500,0.912140,0.191920,2.469830,0.961900,2.351840,0.765760,0.917910 +2017,0.371410,1.196160,0.810260,0.172190,2.475890,0.910900,2.063170,0.690330,0.840900 +2018,0.400407,1.300064,1.002570,0.189613,2.535531,0.994602,2.661307,0.760259,0.871735 +2019,0.338651,1.451554,1.185716,0.228314,2.790259,1.029824,2.928261,0.988215,0.834003 +2020,0.360853,1.684218,1.262778,0.247312,2.768037,1.047204,2.940385,0.954761,0.847681 +2021,0.344592,1.654776,1.082247,0.195056,2.468727,0.913914,2.732240,0.947247,0.887034 +2022,0.366773,1.998293,1.477695,0.257507,2.605338,0.900480,2.797009,0.947744,0.850175 +2023,0.382071,1.783250,1.337029,0.261854,2.930798,1.108780,3.113280,1.010901,0.897525 +2024,0.452001,1.954733,1.804559,0.330010,2.774692,1.121850,3.271640,1.202133,1.018694 +2025,0.400253,1.720835,1.748320,0.311531,2.728033,1.053865,3.139995,1.072385,0.786553 +2026,0.251434,1.490830,1.402841,0.199013,2.304525,0.872166,2.062922,0.829442,0.687765 +2027,0.211858,1.467800,1.498055,0.238384,2.249545,0.930938,2.132700,0.809352,0.664922 +2028,0.194398,1.385326,1.509668,0.246067,2.034196,0.907154,1.991213,0.783828,0.704409 +2029,0.192247,1.412108,1.496857,0.275980,1.846410,0.871673,1.856138,0.776658,0.741716 +2030,0.174559,1.373499,1.534067,0.437111,1.719123,0.808875,1.857033,0.770984,0.772348 +2031,0.157962,1.197684,1.384653,0.358888,1.451879,0.668381,1.640671,0.692458,0.789767 +2032,0.176228,1.132102,1.565061,0.451031,1.585336,0.734924,1.789956,0.847123,0.815216 +2033,0.166235,1.060135,1.333007,0.368381,1.433254,0.691406,1.579497,0.820230,0.797631 +2034,0.161400,0.929961,1.233128,0.308266,1.357102,0.634744,1.513954,0.759908,0.756096 +2035,0.165505,0.893260,1.111427,0.275428,1.358099,0.637080,1.327169,0.722170,0.688957 +2036,0.162913,0.788534,1.031229,0.261540,1.244350,0.549481,1.226203,0.653720,0.632692 +2037,0.137538,0.586714,0.854965,0.271243,1.119637,0.482770,1.115833,0.626503,0.554879 +2038,0.132298,0.522783,0.732474,0.254090,1.064564,0.435245,1.057815,0.527240,0.494092 +2039,0.134267,0.549630,0.758101,0.266654,0.993744,0.374653,1.017851,0.545790,0.454257 +2040,0.136717,0.527879,0.698537,0.271079,0.974679,0.296413,1.049425,0.509211,0.467174 +2041,0.137923,0.488661,0.664124,0.224717,0.975145,0.238602,0.994796,0.438115,0.449188 +2042,0.135460,0.463385,0.615075,0.206150,0.974492,0.237566,0.978935,0.395162,0.437638 +2043,0.138723,0.473387,0.606697,0.213672,0.925296,0.257154,0.991719,0.383094,0.435116 +2044,0.103130,0.474389,0.587082,0.236184,0.871767,0.247615,1.000719,0.395633,0.442636 +2045,0.087387,0.444759,0.607441,0.234486,0.779892,0.218179,1.004305,0.407519,0.440998 +2046,0.092547,0.450912,0.663438,0.237393,0.730188,0.209494,0.993623,0.364727,0.441239 +2047,0.092992,0.450285,0.687064,0.263399,0.693493,0.198955,1.047300,0.383422,0.446543 +2048,0.093810,0.473709,0.734405,0.265423,0.714790,0.201429,1.086109,0.416587,0.465141 +2049,0.095297,0.480987,0.789578,0.270487,0.700422,0.213645,1.095479,0.453987,0.473856 +2050,0.096417,0.472205,0.816287,0.278686,0.698386,0.217900,1.125022,0.486470,0.488408 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_reference.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_reference.csv new file mode 100644 index 0000000..1f7f0bd --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_reference.csv @@ -0,0 +1,42 @@ +year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific +2010,0.420000,0.890000,0.326000,0.124000,1.544000,0.567000,2.049000,0.641000,0.989000 +2011,0.456000,0.965000,0.395000,0.117000,1.671000,0.639000,2.188000,0.567000,0.766000 +2012,0.448000,1.154000,0.656000,0.171000,2.043000,0.797000,2.337000,0.663000,1.045000 +2013,0.372000,1.066000,0.475000,0.140000,1.883000,0.629000,2.075000,0.651000,1.069000 +2014,0.341750,1.131480,0.482860,0.108070,1.896250,0.671910,2.025670,0.648910,1.073730 +2015,0.397610,1.236450,0.713310,0.147160,2.330100,0.875420,2.434110,0.750920,1.084430 +2016,0.393180,1.344500,0.912140,0.191920,2.469830,0.961900,2.351840,0.765760,0.917910 +2017,0.371410,1.196160,0.810260,0.172190,2.475890,0.910900,2.063170,0.690330,0.840900 +2018,0.400407,1.300064,1.002570,0.189613,2.535531,0.994602,2.661307,0.760259,0.871735 +2019,0.338651,1.451554,1.185716,0.228314,2.790259,1.029824,2.928261,0.988215,0.834003 +2020,0.360853,1.684218,1.262778,0.247312,2.768037,1.047204,2.940385,0.954761,0.847681 +2021,0.344592,1.654776,1.082247,0.195056,2.468727,0.913914,2.732240,0.947247,0.887034 +2022,0.366773,1.998293,1.477695,0.257507,2.605338,0.900480,2.797009,0.947744,0.850175 +2023,0.382071,1.783250,1.337029,0.261854,2.930798,1.108780,3.113280,1.010901,0.897525 +2024,0.451624,1.947869,1.803768,0.328229,2.771119,1.120752,3.278091,1.202134,1.026979 +2025,0.402601,1.629397,1.779150,0.333078,2.839481,1.098819,3.062861,1.095031,0.855043 +2026,0.307184,1.645651,1.709301,0.292994,2.802256,1.090066,2.831672,1.009045,0.751345 +2027,0.263452,1.664455,1.930932,0.347046,2.786452,1.157464,2.922580,1.012900,0.718387 +2028,0.243434,1.601191,2.042475,0.365627,2.676992,1.160019,2.856328,0.970603,0.776476 +2029,0.223449,1.567711,2.250298,0.403164,2.548651,1.124709,2.763967,0.961866,0.824927 +2030,0.172437,1.638802,2.271644,0.456933,2.418587,1.037678,2.771827,1.036249,0.894584 +2031,0.193628,1.537363,2.249849,0.434738,2.196743,0.989105,2.681658,1.062644,0.947843 +2032,0.210223,1.631743,2.753094,0.589867,2.304419,1.045986,2.831487,1.131738,1.000090 +2033,0.202380,1.585095,2.610210,0.553112,2.088257,0.955824,2.650223,0.945356,0.930929 +2034,0.189251,1.527352,2.315766,0.410186,1.922410,0.866626,2.548273,0.872272,0.947975 +2035,0.192515,1.546738,2.128180,0.374010,1.878592,0.824893,2.161885,0.893621,0.933309 +2036,0.197367,1.530112,1.923508,0.346125,1.926551,0.771852,1.876698,0.882123,0.888036 +2037,0.189569,1.373293,1.718799,0.332811,1.718812,0.714015,1.742069,0.846004,0.825748 +2038,0.194608,1.208284,1.530699,0.307617,1.718832,0.654886,1.661109,0.834513,0.784750 +2039,0.183550,1.129269,1.492246,0.271675,1.680835,0.603034,1.621889,0.853311,0.737564 +2040,0.191371,1.131776,1.538328,0.272217,1.617794,0.603428,1.688687,0.863450,0.723354 +2041,0.192375,1.157560,1.606427,0.285775,1.619307,0.615171,1.746875,0.862811,0.729275 +2042,0.203848,1.098378,1.636847,0.264481,1.598931,0.615970,1.757097,0.915820,0.673652 +2043,0.207948,1.162631,1.703603,0.265405,1.554882,0.590668,1.737841,0.912592,0.706872 +2044,0.183532,1.205421,1.783943,0.239437,1.479005,0.604031,1.767898,0.939069,0.684177 +2045,0.141631,1.299167,1.743539,0.278295,1.469072,0.610125,1.725534,0.952057,0.662889 +2046,0.157335,1.281461,1.815236,0.288586,1.423282,0.608258,1.737410,0.916862,0.618836 +2047,0.158988,1.377790,1.637457,0.303452,1.396680,0.593526,1.773730,0.906929,0.640318 +2048,0.162292,1.420297,1.609448,0.320825,1.344266,0.605255,1.755996,0.957831,0.637655 +2049,0.174212,1.345600,1.616478,0.320191,1.313927,0.636592,1.718013,0.998673,0.629154 +2050,0.165085,1.342685,1.626209,0.331866,1.359366,0.643452,1.536503,1.036890,0.621188 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_HOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_HOG.csv new file mode 100644 index 0000000..c50b4aa --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_HOG.csv @@ -0,0 +1,42 @@ +year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific +2010,0.858180,2.642740,3.358270,1.549812,2.864664,1.354117,5.379282,4.756302,2.707125 +2011,0.915348,2.719853,3.525401,1.555518,2.934925,1.416257,5.529355,4.793510,2.548560 +2012,0.879083,2.770951,3.547677,1.491081,3.280124,1.540446,5.730931,4.903691,2.803605 +2013,0.859505,2.891799,3.818099,1.645916,3.261053,1.455897,5.577358,4.972179,2.896845 +2014,0.857731,3.120449,4.045156,1.680470,3.326574,1.544663,5.646739,5.000559,2.784841 +2015,0.905922,3.099138,3.886718,1.574979,3.663951,1.696394,5.951674,5.255469,2.763970 +2016,0.856641,3.156144,3.920965,1.638642,3.735140,1.746690,5.803449,1.581652,2.775395 +2017,0.879541,3.113560,3.997107,1.729600,3.888779,1.767733,5.922212,1.576464,2.827698 +2018,0.930977,3.316355,4.395236,1.846236,4.067651,1.912479,6.697608,1.676031,2.952353 +2019,0.884965,3.507681,4.665439,1.972424,4.325762,1.962087,7.134515,1.985243,2.949311 +2020,0.849804,3.615312,4.578500,1.915619,4.221534,1.967894,7.066121,1.900725,2.847719 +2021,0.878472,3.665614,4.418462,1.893204,3.971677,1.844552,6.865973,1.921409,2.947445 +2022,0.923152,4.044715,4.940085,1.998683,4.159855,1.892741,7.156394,1.914708,2.857152 +2023,0.914369,3.709178,4.648726,1.877739,4.158048,1.861391,6.910273,1.734919,2.869450 +2024,0.957036,3.906965,4.966578,2.048244,4.376607,2.097415,7.426676,2.155910,2.973608 +2025,0.937966,3.654048,5.179120,2.077749,4.469378,2.111273,7.503117,2.100823,2.843258 +2026,0.860033,3.759808,5.488719,2.125013,4.646142,2.230853,7.636079,2.131084,2.739021 +2027,0.818995,3.774266,5.671466,2.190878,4.738679,2.335734,7.659956,2.100113,2.732933 +2028,0.795159,3.716908,5.789507,2.173376,4.717777,2.291502,7.557886,2.087887,2.772114 +2029,0.790301,3.712479,5.954311,2.195643,4.672873,2.306812,7.466064,2.086488,2.829799 +2030,0.744455,3.873317,6.039167,2.226819,4.578413,2.233391,7.538048,2.194306,2.921344 +2031,0.722228,3.884992,6.186546,2.296895,4.417633,2.170599,7.592106,2.241075,2.999857 +2032,0.741138,3.944881,6.693543,2.414316,4.601673,2.200978,7.769639,2.365347,3.048926 +2033,0.733747,3.943127,6.668369,2.318362,4.486273,2.200232,7.632854,2.325531,3.145908 +2034,0.735347,3.933705,6.625295,2.316933,4.505866,2.237109,7.758178,2.308635,3.176948 +2035,0.739885,3.800751,6.627602,2.316072,4.430108,2.198426,7.729087,2.271489,3.205086 +2036,0.747582,3.739552,6.545062,2.257230,4.338734,2.156050,7.367331,2.397209,3.013469 +2037,0.757997,3.743082,6.556759,2.263292,4.274085,2.167767,6.954051,2.404191,3.038831 +2038,0.749867,3.694221,6.133348,2.231797,4.256666,2.189104,6.922351,2.272732,3.078229 +2039,0.738831,3.544951,6.001094,2.216016,4.208876,2.141802,6.825901,2.137090,3.124984 +2040,0.745195,3.550549,5.973637,2.230641,4.339911,2.126414,6.780476,2.205422,3.147804 +2041,0.750859,3.586475,6.025984,2.242017,4.432344,2.154529,6.878246,2.189955,3.201372 +2042,0.762990,3.519784,6.201727,2.267177,4.433652,2.144847,6.934600,2.228513,3.202829 +2043,0.771564,3.577761,6.316656,2.304414,4.492250,2.215720,7.085598,2.279858,3.196146 +2044,0.751563,3.673051,6.423592,2.318251,4.486453,2.223858,7.117551,2.359413,3.216992 +2045,0.716803,3.723683,6.500850,2.359171,4.477860,2.262689,7.170787,2.461398,3.226556 +2046,0.718965,3.795890,6.540277,2.392810,4.501936,2.342593,7.244801,2.465548,3.255445 +2047,0.724840,3.895167,6.419639,2.406723,4.490632,2.399555,7.288305,2.517160,3.255843 +2048,0.726701,3.907527,6.308069,2.422065,4.457742,2.390973,7.159330,2.572379,3.249705 +2049,0.725793,3.848761,6.439577,2.387223,4.593865,2.408647,7.386389,2.626165,3.269576 +2050,0.713332,3.860977,6.387714,2.353932,4.613367,2.433508,7.393847,2.731677,3.273041 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_LOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_LOG.csv new file mode 100644 index 0000000..3ac2e3a --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_LOG.csv @@ -0,0 +1,42 @@ +year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific +2010,0.858180,2.642740,3.358270,1.549812,2.864664,1.354117,5.379282,4.756302,2.707125 +2011,0.915348,2.719853,3.525401,1.555518,2.934925,1.416257,5.529355,4.793510,2.548560 +2012,0.879083,2.770951,3.547677,1.491081,3.280124,1.540446,5.730931,4.903691,2.803605 +2013,0.859505,2.891799,3.818099,1.645916,3.261053,1.455897,5.577358,4.972179,2.896845 +2014,0.857731,3.120449,4.045156,1.680470,3.326574,1.544663,5.646739,5.000559,2.784841 +2015,0.905922,3.099138,3.886718,1.574979,3.663951,1.696394,5.951674,5.255469,2.763970 +2016,0.856641,3.156144,3.920965,1.638642,3.735140,1.746690,5.803449,1.581652,2.775395 +2017,0.879541,3.113560,3.997107,1.729600,3.888779,1.767733,5.922212,1.576464,2.827698 +2018,0.930977,3.316355,4.395236,1.846236,4.067651,1.912479,6.697608,1.676031,2.952353 +2019,0.884965,3.507681,4.665439,1.972424,4.325762,1.962087,7.134515,1.985243,2.949311 +2020,0.849804,3.615312,4.578500,1.915619,4.221534,1.967894,7.066121,1.900725,2.847719 +2021,0.878472,3.665614,4.418462,1.893204,3.971677,1.844552,6.865973,1.921409,2.947445 +2022,0.923152,4.044715,4.940085,1.998683,4.159855,1.892741,7.156394,1.914708,2.857152 +2023,0.914369,3.709178,4.648726,1.877739,4.158048,1.861391,6.910273,1.734919,2.869450 +2024,0.962553,3.909995,4.964130,2.049968,4.378995,2.098575,7.414999,2.159559,2.974449 +2025,0.930546,3.749795,5.087374,2.005418,4.343349,2.031063,7.370770,2.058202,2.728772 +2026,0.781939,3.475330,4.620926,1.842845,3.891988,1.784934,5.958117,1.781902,2.557914 +2027,0.742323,3.444869,4.707423,1.880801,3.828328,1.835414,6.003426,1.754856,2.526092 +2028,0.725009,3.364414,4.696098,1.881701,3.591180,1.783213,5.845942,1.713990,2.556307 +2029,0.720008,3.386134,4.647316,1.897199,3.361863,1.719558,5.699160,1.696235,2.585802 +2030,0.699351,3.335698,4.641392,2.038857,3.190711,1.629336,5.668550,1.677637,2.614153 +2031,0.679255,3.142804,4.456717,1.944253,2.885270,1.470770,5.419774,1.608598,2.628891 +2032,0.694852,3.056186,4.594091,2.025953,2.987373,1.521027,5.548148,1.763594,2.637849 +2033,0.682768,2.965106,4.325788,1.940535,2.804255,1.469214,5.332105,1.746244,2.634555 +2034,0.676451,2.821101,4.196589,1.874597,2.729338,1.399418,5.265339,1.690408,2.577221 +2035,0.679203,2.774165,4.056654,1.840279,2.722006,1.387416,5.066918,1.656034,2.517057 +2036,0.675569,2.661531,3.955245,1.820973,2.598980,1.295392,4.959162,1.584508,2.446003 +2037,0.649520,2.454186,3.762507,1.831730,2.459701,1.225727,4.837954,1.567165,2.364758 +2038,0.645287,2.387821,3.630200,1.815282,2.406118,1.169368,4.794869,1.473797,2.291434 +2039,0.653401,2.414410,3.649924,1.826088,2.401801,1.127985,4.765383,1.487857,2.252511 +2040,0.655786,2.393730,3.580663,1.829875,2.404084,1.060108,4.802187,1.457779,2.281605 +2041,0.656713,2.350435,3.536101,1.785332,2.420143,1.008874,4.750147,1.393410,2.238770 +2042,0.654128,2.321419,3.480375,1.763587,2.433650,1.021078,4.739210,1.361234,2.244678 +2043,0.657176,2.332030,3.467469,1.775419,2.402768,1.043947,4.753344,1.362778,2.247817 +2044,0.621498,2.330870,3.439527,1.802037,2.371214,1.045289,4.766046,1.392945,2.278843 +2045,0.605406,2.309155,3.448897,1.802026,2.302510,1.024428,4.775317,1.404418,2.285449 +2046,0.609633,2.310539,3.494394,1.805467,2.268174,1.023384,4.763526,1.375992,2.290656 +2047,0.609062,2.304937,3.507108,1.829551,2.242798,1.011038,4.806602,1.401801,2.294402 +2048,0.608704,2.319615,3.543561,1.830128,2.267759,1.015026,4.840192,1.456912,2.322879 +2049,0.608873,2.317298,3.585941,1.837048,2.260479,1.036841,4.846149,1.501403,2.333663 +2050,0.608951,2.297522,3.602013,1.850036,2.244589,1.030486,4.884940,1.540658,2.361397 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_reference.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_reference.csv new file mode 100644 index 0000000..da86224 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_reference.csv @@ -0,0 +1,42 @@ +year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific +2010,0.858180,2.642740,3.358270,1.549812,2.864664,1.354117,5.379282,4.756302,2.707125 +2011,0.915348,2.719853,3.525401,1.555518,2.934925,1.416257,5.529355,4.793510,2.548560 +2012,0.879083,2.770951,3.547677,1.491081,3.280124,1.540446,5.730931,4.903691,2.803605 +2013,0.859505,2.891799,3.818099,1.645916,3.261053,1.455897,5.577358,4.972179,2.896845 +2014,0.857731,3.120449,4.045156,1.680470,3.326574,1.544663,5.646739,5.000559,2.784841 +2015,0.905922,3.099138,3.886718,1.574979,3.663951,1.696394,5.951674,5.255469,2.763970 +2016,0.856641,3.156144,3.920965,1.638642,3.735140,1.746690,5.803449,1.581652,2.775395 +2017,0.879541,3.113560,3.997107,1.729600,3.888779,1.767733,5.922212,1.576464,2.827698 +2018,0.930977,3.316355,4.395236,1.846236,4.067651,1.912479,6.697608,1.676031,2.952353 +2019,0.884965,3.507681,4.665439,1.972424,4.325762,1.962087,7.134515,1.985243,2.949311 +2020,0.849804,3.615312,4.578500,1.915619,4.221534,1.967894,7.066121,1.900725,2.847719 +2021,0.878472,3.665614,4.418462,1.893204,3.971677,1.844552,6.865973,1.921409,2.947445 +2022,0.923152,4.044715,4.940085,1.998683,4.159855,1.892741,7.156394,1.914708,2.857152 +2023,0.914369,3.709178,4.648726,1.877739,4.158048,1.861391,6.910273,1.734919,2.869450 +2024,0.962173,3.903117,4.963340,2.048189,4.375371,2.097466,7.421416,2.159530,2.982530 +2025,0.935287,3.661196,5.156418,2.129834,4.476222,2.089903,7.237640,2.086673,2.807245 +2026,0.848885,3.692177,5.073037,2.030126,4.465045,2.052864,6.971332,1.988881,2.694449 +2027,0.807334,3.721632,5.310193,2.096073,4.458486,2.121335,7.088854,1.999269,2.667008 +2028,0.788003,3.668039,5.422043,2.115744,4.351885,2.120489,7.020803,1.959295,2.730486 +2029,0.767319,3.644482,5.623929,2.153275,4.227018,2.085303,6.950130,1.954141,2.789246 +2030,0.715819,3.723123,5.640369,2.207593,4.102344,2.000149,6.981818,2.035256,2.874931 +2031,0.736064,3.624680,5.612779,2.187774,3.890681,1.956317,6.930852,2.067181,2.935515 +2032,0.752671,3.716164,6.106751,2.346345,4.012863,2.020668,7.100438,2.145240,2.998962 +2033,0.746767,3.659340,5.944864,2.309086,3.806603,1.933828,6.931971,1.967468,2.933176 +2034,0.733941,3.596563,5.637051,2.168169,3.651626,1.848481,6.835082,1.903266,2.945720 +2035,0.737544,3.614042,5.440754,2.135197,3.610039,1.810854,6.454259,1.936649,2.938173 +2036,0.742872,3.597095,5.228507,2.114645,3.659100,1.762085,6.180867,1.936809,2.895602 +2037,0.736183,3.445315,5.027087,2.105235,3.464379,1.709159,6.054377,1.914083,2.844030 +2038,0.742570,3.288879,4.835952,2.094151,3.479662,1.657892,6.006368,1.916980,2.813577 +2039,0.732698,3.218215,4.804575,2.066591,3.457128,1.614115,5.997215,1.950361,2.782817 +2040,0.741344,3.226690,4.854189,2.076052,3.408876,1.621953,6.087286,1.974375,2.780822 +2041,0.742691,3.255468,4.917473,2.094103,3.422421,1.639145,6.161439,1.985551,2.793409 +2042,0.754417,3.196219,4.942109,2.077646,3.412856,1.644759,6.188160,2.049288,2.748004 +2043,0.758587,3.258941,5.006926,2.081888,3.378010,1.624161,6.185266,2.057952,2.793068 +2044,0.734295,3.302742,5.082698,2.062417,3.311311,1.641373,6.232446,2.095899,2.783741 +2045,0.692461,3.395932,5.035407,2.105197,3.316263,1.651322,6.209975,2.119609,2.772924 +2046,0.707880,3.377838,5.099153,2.118033,3.285728,1.651759,6.231880,2.093664,2.733654 +2047,0.709487,3.474578,4.917622,2.137938,3.267011,1.640283,6.275684,2.094466,2.770767 +2048,0.713195,3.520399,4.895315,2.163854,3.225357,1.657869,6.278858,2.157986,2.782060 +2049,0.725422,3.449674,4.902303,2.172264,3.207612,1.695295,6.269968,2.213768,2.792679 +2050,0.716690,3.453480,4.926717,2.197461,3.263909,1.705988,6.099909,2.264314,2.801707 diff --git a/aeo_updates/natural_gas_price_regression/outputs of beta regression/beta_regression_summary.csv b/aeo_updates/natural_gas_price_regression/outputs of beta regression/beta_regression_summary.csv new file mode 100644 index 0000000..31f0295 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of beta regression/beta_regression_summary.csv @@ -0,0 +1,11 @@ +scope,region,beta,r2,r2_full,n_obs +national,ALL,0.080017,0.727887,0.847220,1701 +regional,New_England,3.875323,0.587849,0.867459,189 +regional,Mid_Atlantic,0.151497,0.191732,0.850741,189 +regional,East_North_Central,0.033492,0.037937,0.842476,189 +regional,West_North_Central,0.856915,0.452614,0.852631,189 +regional,South_Atlantic,0.175498,0.407799,0.840697,189 +regional,East_South_Central,0.139571,0.135091,0.853755,189 +regional,West_South_Central,-0.054900,0.048903,0.721250,189 +regional,Mountain,0.670353,0.575211,0.854568,189 +regional,Pacific,1.341567,0.669742,0.855878,189 diff --git a/aeo_updates/natural_gas_price_regression/outputs of beta regression/cd_beta0.csv b/aeo_updates/natural_gas_price_regression/outputs of beta regression/cd_beta0.csv new file mode 100644 index 0000000..946cf33 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of beta regression/cd_beta0.csv @@ -0,0 +1,10 @@ +*cendiv,value +New_England,3.875323 +Mid_Atlantic,0.151497 +East_North_Central,0.033492 +West_North_Central,0.856915 +South_Atlantic,0.175498 +East_South_Central,0.139571 +West_South_Central,-0.054900 +Mountain,0.670353 +Pacific,1.341567 diff --git a/aeo_updates/natural_gas_price_regression/outputs of beta regression/national_beta.csv b/aeo_updates/natural_gas_price_regression/outputs of beta regression/national_beta.csv new file mode 100644 index 0000000..abd889b --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of beta regression/national_beta.csv @@ -0,0 +1,2 @@ +beta +0.080017 diff --git a/aeo_updates/natural_gas_price_regression/run_ng_pipeline.bat b/aeo_updates/natural_gas_price_regression/run_ng_pipeline.bat new file mode 100644 index 0000000..3413f4e --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/run_ng_pipeline.bat @@ -0,0 +1,39 @@ +@echo off +setlocal + +cd /d "%~dp0" + +set "CONFIG=%~1" +if "%CONFIG%"=="" set "CONFIG=aeo_pipeline_config.json" + +python --version >nul 2>&1 +if errorlevel 1 ( + echo ERROR: Python is not available on PATH. + exit /b 9009 +) + +echo [1/4] Running beta regression... +python aeo_beta_regression.py --config "%CONFIG%" +if errorlevel 1 goto :fail + +echo [2/4] Syncing beta outputs to alpha inputs... +python sync_beta_to_alpha_inputs.py --config "%CONFIG%" +if errorlevel 1 goto :fail + +echo [3/4] Running alpha regression... +python aeo_alpha_regression.py --config "%CONFIG%" +if errorlevel 1 goto :fail + +echo [4/4] Generating visualization and validation... +python visualization.py --config "%CONFIG%" +if errorlevel 1 goto :fail + +echo. +echo NG pipeline finished successfully. +exit /b 0 + +:fail +set "CODE=%errorlevel%" +echo. +echo NG pipeline failed with exit code %CODE%. +exit /b %CODE% diff --git a/aeo_updates/natural_gas_price_regression/sync_beta_to_alpha_inputs.py b/aeo_updates/natural_gas_price_regression/sync_beta_to_alpha_inputs.py new file mode 100644 index 0000000..300aed4 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/sync_beta_to_alpha_inputs.py @@ -0,0 +1,122 @@ +""" +Copy beta regression outputs into alpha regression inputs. + +This removes the manual handoff step between: +1) aeo_beta_regression.py +2) aeo_alpha_regression.py + +Copied files: +- outputs of beta regression/cd_beta0.csv -> inputs for alpha regression/cd_beta0.csv +- outputs of beta regression/national_beta.csv -> inputs for alpha regression/national_beta.csv +""" + +from __future__ import annotations + +import argparse +import json +import shutil +import sys +from pathlib import Path +from typing import Any + + +def require(condition: bool, message: str) -> None: + """Raise ValueError when condition is false.""" + if not condition: + raise ValueError(message) + + +def resolve_case_insensitive(path: Path) -> Path: + """Resolve a path with case-insensitive matching on each component.""" + if path.exists(): + return path + path = path.resolve() + current = Path(path.anchor) + for part in path.parts[1:]: + if not current.exists(): + return path + try: + matches = [p for p in current.iterdir() if p.name.lower() == part.lower()] + except PermissionError: + return path + if not matches: + return path + current = matches[0] + return current + + +def resolve_path(base_dir: Path, configured_path: str) -> Path: + """Resolve a configured path relative to base_dir.""" + p = Path(configured_path) + if not p.is_absolute(): + p = base_dir / p + return resolve_case_insensitive(p) + + +def load_config(config_path: Path) -> dict[str, Any]: + """Load JSON config file.""" + require(config_path.exists(), f"Config not found: {config_path}") + with config_path.open("r", encoding="utf-8") as f: + cfg = json.load(f) + require(isinstance(cfg, dict), f"Config root must be an object: {config_path}") + return cfg + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Copy beta outputs into alpha input directory.") + parser.add_argument("--config", default="aeo_pipeline_config.json") + parser.add_argument("--beta-output-dir", default="outputs of beta regression") + parser.add_argument( + "--alpha-input-dir", + default=None, + help="Override alpha input directory (default: config paths.input_dir).", + ) + return parser.parse_args() + + +def copy_required_files(beta_out_dir: Path, alpha_input_dir: Path) -> None: + """Copy cd_beta0.csv and national_beta.csv from beta outputs to alpha inputs.""" + copies = [ + ("cd_beta0.csv", "cd_beta0.csv"), + ("national_beta.csv", "national_beta.csv"), + ] + alpha_input_dir.mkdir(parents=True, exist_ok=True) + + for src_name, dst_name in copies: + src = beta_out_dir / src_name + dst = alpha_input_dir / dst_name + require(src.exists(), f"Missing beta output file: {src}") + shutil.copy2(src, dst) + print(f"Copied: {src} -> {dst}") + + +def main() -> int: + args = parse_args() + + script_dir = Path(__file__).resolve().parent + cfg_path = Path(args.config) + if not cfg_path.is_absolute(): + cwd_candidate = resolve_case_insensitive((Path.cwd() / cfg_path).resolve()) + script_candidate = resolve_case_insensitive((script_dir / cfg_path).resolve()) + cfg_path = cwd_candidate if cwd_candidate.exists() else script_candidate + + config = load_config(cfg_path) + base_dir = cfg_path.parent + + input_dir_cfg = str(config.get("paths", {}).get("input_dir", "inputs for alpha regression")) + alpha_input_dir = resolve_path(base_dir, args.alpha_input_dir or input_dir_cfg) + beta_out_dir = resolve_path(base_dir, args.beta_output_dir) + require(beta_out_dir.exists(), f"Beta output directory not found: {beta_out_dir}") + + copy_required_files(beta_out_dir, alpha_input_dir) + print("Beta-to-alpha input sync completed.") + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Exception as exc: + print(f"ERROR: {exc}", file=sys.stderr) + sys.exit(1) diff --git a/aeo_updates/natural_gas_price_regression/visualization.py b/aeo_updates/natural_gas_price_regression/visualization.py new file mode 100644 index 0000000..48bbaf5 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/visualization.py @@ -0,0 +1,1191 @@ +""" +Unified visualization and validation for the NG regression pipeline. + +Consolidates three prior scripts into one entry point: + - Beta raw-data scatter grid (was beta_raw_data_visualization.py) + - Beta/alpha diagnostic plots (was results_visualization.py) + - Validation: actual vs predicted, parity, alpha comparison (was results_validation.py) + +Usage +----- + python visualization.py --config aeo_pipeline_config.json + +Run after: + 1) aeo_beta_regression.py + 2) sync_beta_to_alpha_inputs.py + 3) aeo_alpha_regression.py +""" + +from __future__ import annotations + +import argparse +import json +import logging +import re +import sys +from pathlib import Path +from typing import Any + +import numpy as np +import pandas as pd + +try: + import matplotlib + matplotlib.use("Agg") + import matplotlib.pyplot as plt + from matplotlib.lines import Line2D +except Exception as exc: # pragma: no cover + raise RuntimeError("matplotlib is required for visualization.py") from exc + +LOGGER = logging.getLogger("visualization") + +# ============================================================================ +# Constants +# ============================================================================ + +CENDIV_CANONICAL = { + "newengland": "NewEngland", + "middleatlantic": "MiddleAtlantic", + "eastnorthcentral": "EastNorthCentral", + "westnorthcentral": "WestNorthCentral", + "southatlantic": "SouthAtlantic", + "eastsouthcentral": "EastSouthCentral", + "westsouthcentral": "WestSouthCentral", + "mountain": "Mountain", + "pacific": "Pacific", +} + +CENDIV_OUTPUT = { + "NewEngland": "New_England", + "MiddleAtlantic": "Mid_Atlantic", + "EastNorthCentral": "East_North_Central", + "WestNorthCentral": "West_North_Central", + "SouthAtlantic": "South_Atlantic", + "EastSouthCentral": "East_South_Central", + "WestSouthCentral": "West_South_Central", + "Mountain": "Mountain", + "Pacific": "Pacific", +} + +SCENARIO_COLOR = { + "reference": "#1f77b4", + "HOG": "#2ca02c", + "LOG": "#d62728", +} + + +# ============================================================================ +# Shared helpers +# ============================================================================ + +def require(condition: bool, message: str) -> None: + if not condition: + raise ValueError(message) + + +def normalize_token(value: Any) -> str: + return re.sub( + r"[^a-z0-9]+", "", + str(value).replace("\xa0", " ").strip().lower(), + ) + + +def any_to_cendiv(value: str) -> str: + token = normalize_token(value) + if token in CENDIV_CANONICAL: + return CENDIV_CANONICAL[token] + for cendiv, out_label in CENDIV_OUTPUT.items(): + if token in {normalize_token(cendiv), normalize_token(out_label)}: + return cendiv + raise ValueError(f"Unknown region label: {value}") + + +def cendiv_output_label(cendiv: str) -> str: + require(cendiv in CENDIV_OUTPUT, f"Unknown cendiv key: {cendiv}") + return CENDIV_OUTPUT[cendiv] + + +def resolve_case_insensitive(path: Path) -> Path: + if path.exists(): + return path + path = path.resolve() + current = Path(path.anchor) + for part in path.parts[1:]: + if not current.exists(): + return path + try: + matches = [p for p in current.iterdir() if p.name.lower() == part.lower()] + except PermissionError: + return path + if not matches: + return path + current = matches[0] + return current + + +def resolve_path(base_dir: Path, configured_path: str) -> Path: + p = Path(configured_path) + if not p.is_absolute(): + p = base_dir / p + return resolve_case_insensitive(p) + + +def load_config(config_path: Path) -> dict[str, Any]: + require(config_path.exists(), f"Config not found: {config_path}") + with config_path.open("r", encoding="utf-8") as f: + cfg = json.load(f) + require(isinstance(cfg, dict), f"Config root must be an object: {config_path}") + return cfg + + +def region_order_from_config(config: dict[str, Any]) -> list[str]: + configured = config["ng"]["regions"] + return [cendiv_output_label(any_to_cendiv(x)) for x in configured] + + +def zero_ng_betas_in_first_model_year( + frame: pd.DataFrame, + first_model_year: int, + beta_reg_col: str = "beta_reg", + beta_nat_col: str = "beta_nat", +) -> None: + first_year_mask = frame["year"] == first_model_year + frame.loc[first_year_mask, beta_reg_col] = 0.0 + frame.loc[first_year_mask, beta_nat_col] = 0.0 + + +def zero_ng_terms_in_first_model_year( + frame: pd.DataFrame, + first_model_year: int, + regional_term_col: str = "term_reg", + national_term_col: str = "term_nat", +) -> None: + first_year_mask = frame["year"] == first_model_year + frame.loc[first_year_mask, regional_term_col] = 0.0 + frame.loc[first_year_mask, national_term_col] = 0.0 + + +def sanitize_file_component(value: str) -> str: + return re.sub(r"[^A-Za-z0-9_.-]+", "_", value) + + +def compute_r2(actual: pd.Series | np.ndarray, predicted: pd.Series | np.ndarray) -> float: + a = np.asarray(actual, dtype=float) + p = np.asarray(predicted, dtype=float) + mask = np.isfinite(a) & np.isfinite(p) + if not np.any(mask): + return float("nan") + a, p = a[mask], p[mask] + ss_res = float(np.sum(np.square(a - p))) + ss_tot = float(np.sum(np.square(a - np.mean(a)))) + if ss_tot <= 0: + return float("nan") + return 1.0 - (ss_res / ss_tot) + + +def compute_fit_metrics(actual: pd.Series | np.ndarray, predicted: pd.Series | np.ndarray) -> dict[str, float]: + a = np.asarray(actual, dtype=float) + p = np.asarray(predicted, dtype=float) + mask = np.isfinite(a) & np.isfinite(p) + if not np.any(mask): + return {"n_obs": 0.0, "mae": float("nan"), "rmse": float("nan"), + "max_abs": float("nan"), "r2": float("nan")} + a, p = a[mask], p[mask] + err = a - p + return { + "n_obs": float(len(a)), + "mae": float(np.mean(np.abs(err))), + "rmse": float(np.sqrt(np.mean(np.square(err)))), + "max_abs": float(np.max(np.abs(err))), + "r2": compute_r2(a, p), + } + + +def summarize_fit( + frame: pd.DataFrame, + group_cols: list[str], + actual_col: str, + predicted_col: str, + mae_col: str, + rmse_col: str, + max_abs_col: str, + r2_col: str, +) -> pd.DataFrame: + rows: list[dict[str, Any]] = [] + for keys, grp in frame.groupby(group_cols, sort=True): + if not isinstance(keys, tuple): + keys = (keys,) + row = {group_cols[i]: keys[i] for i in range(len(group_cols))} + m = compute_fit_metrics(grp[actual_col], grp[predicted_col]) + row["n_obs"] = int(m["n_obs"]) + row[mae_col] = m["mae"] + row[rmse_col] = m["rmse"] + row[max_abs_col] = m["max_abs"] + row[r2_col] = m["r2"] + rows.append(row) + out = pd.DataFrame(rows) + if out.empty: + return out + return out.sort_values(group_cols).reset_index(drop=True) + + +# ============================================================================ +# Beta / alpha CSV loaders +# ============================================================================ + +def load_regional_beta_from_csv(source_path: Path) -> dict[str, float]: + require(source_path.exists(), f"Missing regional beta file: {source_path}") + df = pd.read_csv(source_path) + cendiv_col = next( + (c for c in df.columns if normalize_token(c).endswith("cendiv")), None) + value_col = next( + (c for c in df.columns if normalize_token(c) == "value"), None) + require(cendiv_col is not None and value_col is not None, + f"Missing cendiv/value columns in {source_path}") + beta_map: dict[str, float] = {} + for raw_label, raw_beta in zip(df[cendiv_col], df[value_col]): + beta_val = pd.to_numeric([raw_beta], errors="coerce")[0] + if pd.isna(beta_val): + continue + region_label = cendiv_output_label(any_to_cendiv(str(raw_label))) + beta_map[region_label] = float(beta_val) + return beta_map + + +def load_national_beta_from_csv(source_path: Path) -> float: + require(source_path.exists(), f"Missing national beta file: {source_path}") + df = pd.read_csv(source_path) + require("beta" in df.columns, f"Missing 'beta' column in {source_path}") + beta_vals = pd.to_numeric(df["beta"], errors="coerce").dropna() + require(not beta_vals.empty, f"No numeric beta value found in {source_path}") + return float(beta_vals.iloc[0]) + + +def load_regional_beta_map(alpha_out_dir: Path, alpha_input_dir: Path) -> tuple[dict[str, float], Path]: + candidates = [alpha_out_dir / "cd_beta0.csv", alpha_input_dir / "cd_beta0.csv"] + source_path = next((p for p in candidates if p.exists()), None) + require(source_path is not None, f"Could not find cd_beta0.csv in: {candidates}") + return load_regional_beta_from_csv(source_path), source_path + + +def load_national_beta(alpha_out_dir: Path, alpha_input_dir: Path, beta_out_dir: Path) -> tuple[float, Path]: + candidates = [ + alpha_out_dir / "national_beta.csv", + alpha_input_dir / "national_beta.csv", + beta_out_dir / "national_beta.csv", + ] + source_path = next((p for p in candidates if p.exists()), None) + require(source_path is not None, f"Could not find national_beta.csv in: {candidates}") + return load_national_beta_from_csv(source_path), source_path + + +def load_alpha_from_beta_step(beta_out_dir: Path) -> tuple[pd.DataFrame, Path, list[str]]: + source_path = beta_out_dir / "alpha_from_beta_regression.csv" + require(source_path.exists(), + "Missing alpha_from_beta_regression.csv. Re-run aeo_beta_regression.py first.") + df = pd.read_csv(source_path) + if "scenario_id" in df.columns: + need = {"scenario_id", "region", "year", "alpha_2004"} + require(not (need - set(df.columns)), + f"Missing columns in {source_path}: {sorted(need - set(df.columns))}") + out = df[["scenario_id", "region", "year", "alpha_2004"]].copy() + out["scenario_id"] = out["scenario_id"].astype(str) + merge_cols = ["scenario_id", "region", "year"] + else: + need = {"region", "year", "alpha_2004"} + require(not (need - set(df.columns)), + f"Missing columns in {source_path}: {sorted(need - set(df.columns))}") + out = df[["region", "year", "alpha_2004"]].copy() + merge_cols = ["region", "year"] + + out["region"] = out["region"].astype(str).map( + lambda x: cendiv_output_label(any_to_cendiv(x))) + out["year"] = pd.to_numeric(out["year"], errors="coerce") + out["alpha_2004"] = pd.to_numeric(out["alpha_2004"], errors="coerce") + require(not out["year"].isna().any(), f"Non-numeric year in {source_path}") + require(not out["alpha_2004"].isna().any(), f"Non-numeric alpha_2004 in {source_path}") + out["year"] = out["year"].astype(int) + out = out.rename(columns={"alpha_2004": "alpha1"}) + return out[merge_cols + ["alpha1"]], source_path, merge_cols + + +# ============================================================================ +# Scenario discovery helpers +# ============================================================================ + +def scenario_display_label(suffix: str, scenario_id: str) -> str: + t = normalize_token(suffix) + if t.startswith("ref"): + return "reference" + if t in {"hog", "highogs"}: + return "HOG" + if t in {"log", "lowogs"}: + return "LOG" + return scenario_id + + +def discover_output_scenarios_with_labels( + alpha_out_dir: Path, aeo_year: int, +) -> list[tuple[str, str, str]]: + """Returns list of (suffix, scenario_id, display_label).""" + mapping_path = alpha_out_dir / "raw_aeo_data" / "selected_scenarios_outputs.csv" + suffix_to_scenario: dict[str, str] = {} + if mapping_path.exists(): + map_df = pd.read_csv(mapping_path) + if {"file_suffix", "scenario_id"}.issubset(map_df.columns): + for row in map_df.itertuples(index=False): + suffix_to_scenario[str(row.file_suffix)] = str(row.scenario_id) + + pattern = re.compile(rf"^alpha_AEO_{aeo_year}_(.+)\.csv$") + rows: list[tuple[str, str, str]] = [] + for path in sorted(alpha_out_dir.glob(f"alpha_AEO_{aeo_year}_*.csv")): + match = pattern.match(path.name) + if not match: + continue + suffix = match.group(1) + scenario_id = suffix_to_scenario.get(suffix, suffix) + label = scenario_display_label(suffix, scenario_id) + rows.append((suffix, scenario_id, label)) + require(rows, f"No alpha scenario files found in {alpha_out_dir}") + order_index = {"reference": 0, "HOG": 1, "LOG": 2} + rows.sort(key=lambda x: (order_index.get(x[2], 99), x[2], x[1])) + return rows + + +def discover_output_scenarios(alpha_out_dir: Path, aeo_year: int) -> list[tuple[str, str]]: + """Returns list of (suffix, scenario_id).""" + return [(s, sid) for s, sid, _ in discover_output_scenarios_with_labels(alpha_out_dir, aeo_year)] + + +# ============================================================================ +# Wide-series loader +# ============================================================================ + +def load_wide_series( + csv_path: Path, + value_col: str, + scenario_id: str, + region_order: list[str], + scenario_label: str | None = None, +) -> pd.DataFrame: + require(csv_path.exists(), f"Missing file: {csv_path}") + wide = pd.read_csv(csv_path) + year_col = "t" if "t" in wide.columns else ("year" if "year" in wide.columns else None) + require(year_col is not None, f"Missing year column (t/year): {csv_path}") + missing_regions = [c for c in region_order if c not in wide.columns] + require(not missing_regions, f"Missing region columns in {csv_path}: {missing_regions}") + long = wide[[year_col, *region_order]].melt( + id_vars=[year_col], var_name="region", value_name=value_col) + long["year"] = pd.to_numeric(long[year_col], errors="coerce") + long[value_col] = pd.to_numeric(long[value_col], errors="coerce") + require(not long["year"].isna().any(), f"Non-numeric year in {csv_path}") + require(not long[value_col].isna().any(), f"Non-numeric values in {csv_path}") + long["year"] = long["year"].astype(int) + long["scenario_id"] = scenario_id + cols = ["scenario_id", "region", "year", value_col] + if scenario_label is not None: + long["scenario_label"] = scenario_label + cols = ["scenario_id", "scenario_label", "region", "year", value_col] + return long[cols] + + +# ============================================================================ +# Part 1: Beta raw-data scatter grid +# ============================================================================ + +_RAW_KEY_COLS = ["period", "scenario", "regionId"] +_RAW_READ_COLS = ["period", "scenario", "scenarioDescription", "regionId", + "regionName", "value"] + + +def _coerce_numeric(df: pd.DataFrame, col: str) -> pd.DataFrame: + df[col] = pd.to_numeric(df[col], errors="coerce") + return df.dropna(subset=[col]) + + +def _load_beta_include_scenarios(config: dict[str, Any]) -> list[str]: + aeo_year = config.get("aeo_year") + include = (config.get("scenarios", {}) + .get("beta_regression", {}) + .get("include", [])) + if not isinstance(include, list): + raise ValueError("Expected list at scenarios.beta_regression.include") + resolved: list[str] = [] + for item in include: + token = str(item) + if aeo_year is not None: + token = token.replace("{aeo_year}", str(aeo_year)) + resolved.append(token) + return resolved + + +def _filter_to_beta_include(df: pd.DataFrame, include_tokens: list[str]) -> pd.DataFrame: + if not include_tokens: + return df + include_norm = {normalize_token(t) for t in include_tokens} + scenario_norm = df["scenario"].map(normalize_token) + desc_norm = df["scenarioDescription"].fillna("").map(normalize_token) + keep_mask = scenario_norm.isin(include_norm) | desc_norm.isin(include_norm) + filtered = df[keep_mask].copy() + if filtered.empty: + available = sorted(df["scenario"].unique()) + raise ValueError( + f"No rows matched beta_regression.include. " + f"Configured: {include_tokens}. Available: {available}") + return filtered + + +def _load_and_merge_raw(demand_csv: Path, price_csv: Path) -> pd.DataFrame: + demand = pd.read_csv(demand_csv, usecols=_RAW_READ_COLS).rename( + columns={"value": "demand"}) + price = pd.read_csv(price_csv, usecols=_RAW_READ_COLS).rename( + columns={"value": "price"}) + demand = _coerce_numeric(demand, "demand") + price = _coerce_numeric(price, "price") + for df in [demand, price]: + df["period"] = pd.to_numeric(df["period"], errors="coerce") + df.dropna(subset=["period"], inplace=True) + df["period"] = df["period"].astype(int) + demand = demand.groupby(_RAW_KEY_COLS, as_index=False).agg( + {"scenarioDescription": "first", "regionName": "first", "demand": "mean"}) + price = price.groupby(_RAW_KEY_COLS, as_index=False).agg({"price": "mean"}) + merged = demand.merge(price, on=_RAW_KEY_COLS, how="inner", validate="one_to_one") + return merged.sort_values(["period", "scenario", "regionId"]).reset_index(drop=True) + + +def _fit_line(panel_df: pd.DataFrame) -> tuple[np.ndarray, np.ndarray, float] | None: + x = panel_df["demand"].to_numpy() + y = panel_df["price"].to_numpy() + if x.size < 2 or np.unique(x).size < 2: + return None + slope, intercept = np.polyfit(x, y, deg=1) + x_line = np.linspace(x.min(), x.max(), 50) + y_line = slope * x_line + intercept + return x_line, y_line, float(slope) + + +def generate_raw_scatter_grid( + beta_out_dir: Path, + config: dict[str, Any], + output_dir: Path, + dpi: int = 150, +) -> None: + """Generate beta raw-data scatter grid (demand vs price by year/region).""" + raw_dir = beta_out_dir / "raw_aeo_data" + demand_csv = raw_dir / "raw_ng_demand_elec.csv" + price_csv = raw_dir / "raw_ng_price.csv" + if not demand_csv.exists() or not price_csv.exists(): + LOGGER.warning("Skipping raw scatter grid: raw CSVs not found in %s", raw_dir) + return + + merged = _load_and_merge_raw(demand_csv, price_csv) + include_scenarios = _load_beta_include_scenarios(config) + merged = _filter_to_beta_include(merged, include_scenarios) + + years = sorted(merged["period"].unique()) + scenarios = sorted(merged["scenario"].unique()) + region_table = (merged[["regionId", "regionName"]].drop_duplicates() + .sort_values(["regionId", "regionName"]).reset_index(drop=True)) + regions = region_table.to_dict("records") + scenario_colors = {s: plt.cm.tab10(i % 10) for i, s in enumerate(scenarios)} + + n_rows, n_cols = len(years), len(regions) + fig_w = max(15, n_cols * 2.6) + fig_h = max(12, n_rows * 1.8) + fig, axes = plt.subplots(nrows=n_rows, ncols=n_cols, + figsize=(fig_w, fig_h), sharex=True, sharey=True, squeeze=False) + + x_min, x_max = merged["demand"].min(), merged["demand"].max() + y_min, y_max = merged["price"].min(), merged["price"].max() + x_pad = 0.05 * (x_max - x_min) if x_max > x_min else 0.1 + y_pad = 0.05 * (y_max - y_min) if y_max > y_min else 0.1 + + for row_idx, year in enumerate(years): + for col_idx, region in enumerate(regions): + ax = axes[row_idx, col_idx] + panel = merged[(merged["period"] == year) & (merged["regionId"] == region["regionId"])] + ax.scatter(panel["demand"], panel["price"], s=20, alpha=0.95, + c=panel["scenario"].map(scenario_colors), edgecolors="none") + fit = _fit_line(panel) + if fit is not None: + x_line, y_line, slope = fit + is_negative = slope < 0 + line_color = "#c62828" if is_negative else "#4d4d4d" + ax.plot(x_line, y_line, color=line_color, linewidth=1.1) + slope_text = f"slope={slope:.3f}" + if is_negative: + slope_text += " (NEG)" + ax.text(0.03, 0.97, slope_text, transform=ax.transAxes, + ha="left", va="top", fontsize=6, + color="#8b0000" if is_negative else "#303030", + bbox={"boxstyle": "round,pad=0.2", + "facecolor": "#ffe6e6" if is_negative else "white", + "alpha": 0.85, + "edgecolor": "#c62828" if is_negative else "none", + "linewidth": 0.6 if is_negative else 0.0}) + if is_negative: + ax.set_facecolor("#fff5f5") + for spine in ax.spines.values(): + spine.set_edgecolor("#c62828") + spine.set_linewidth(0.9) + ax.set_xlim(x_min - x_pad, x_max + x_pad) + ax.set_ylim(y_min - y_pad, y_max + y_pad) + ax.grid(True, alpha=0.25, linewidth=0.5) + ax.tick_params(axis="both", labelsize=6, length=2) + if row_idx == 0: + ax.set_title(str(region["regionName"]), fontsize=8, pad=3) + if col_idx == 0: + ax.set_ylabel(str(year), fontsize=8, rotation=0, labelpad=18, va="center") + + legend_handles = [ + Line2D([0], [0], marker="o", linestyle="", markersize=5, + markerfacecolor=scenario_colors[s], markeredgecolor="none", label=s) + for s in scenarios + ] + fig.supxlabel("Natural Gas Demand (quads)", fontsize=11) + fig.supylabel("Natural Gas Price (2024 $/MMBtu)", fontsize=11) + fig.suptitle( + "Raw AEO NG Data: Demand vs Price\n" + "(Scatter + Linear Regression by Year and Region; negative slopes highlighted)", + fontsize=13, y=0.995) + fig.legend(handles=legend_handles, loc="upper center", + bbox_to_anchor=(0.5, 0.978), ncol=min(len(scenarios), 5), + fontsize=8, frameon=False, title="Scenario", title_fontsize=8) + fig.tight_layout(rect=[0.04, 0.02, 1, 0.95]) + + output_dir.mkdir(parents=True, exist_ok=True) + fig.savefig(output_dir / "beta_raw_data_scatter_linear_grid.png", dpi=dpi) + plt.close(fig) + LOGGER.info("Wrote raw scatter grid to %s", output_dir) + + +# ============================================================================ +# Part 2: Beta / alpha diagnostic plots +# ============================================================================ + +def generate_beta_plots(beta_out_dir: Path, region_order: list[str], plots_dir: Path) -> None: + plots_dir.mkdir(parents=True, exist_ok=True) + summary_path = beta_out_dir / "beta_regression_summary.csv" + points_path = beta_out_dir / "regression_points.csv" + require(summary_path.exists(), f"Missing file: {summary_path}") + require(points_path.exists(), f"Missing file: {points_path}") + + summary = pd.read_csv(summary_path) + points = pd.read_csv(points_path) + nat_y_col = "dp_partial_nat" + reg_x_col = "dq_reg" + for col in ["scope", "region", "beta"]: + require(col in summary.columns, f"Missing '{col}' in {summary_path}") + for col in ["region", "dq_nat", nat_y_col, reg_x_col, "dp_partial_reg"]: + require(col in points.columns, f"Missing '{col}' in {points_path}") + + national_rows = summary[summary["scope"].astype(str).str.lower() == "national"] + require(not national_rows.empty, f"No national row found in {summary_path}") + nrow = national_rows.iloc[0] + beta_nat = float(pd.to_numeric([nrow["beta"]], errors="coerce")[0]) + beta_nat_r2 = (float(pd.to_numeric([nrow["r2"]], errors="coerce")[0]) + if "r2" in summary.columns else float("nan")) + model_r2 = (float(pd.to_numeric([nrow["r2_full"]], errors="coerce")[0]) + if "r2_full" in summary.columns else float("nan")) + + # National beta plot + nat_points = points[["dq_nat", nat_y_col]].dropna() + require(not nat_points.empty, + f"No valid national plotting rows in {points_path}") + fig, ax = plt.subplots(figsize=(8, 6)) + ax.scatter(nat_points["dq_nat"], nat_points[nat_y_col], s=12, alpha=0.5, color="#1f77b4") + x_min, x_max = float(nat_points["dq_nat"].min()), float(nat_points["dq_nat"].max()) + x_range = np.linspace(x_min, x_max, 200) + ax.plot(x_range, beta_nat * x_range, color="#d62728", linewidth=2) + ax.axhline(0, color="#888888", linewidth=0.8) + ax.axvline(0, color="#888888", linewidth=0.8) + ax.set_xlabel("Demeaned national demand (partial)") + ax.set_ylabel("Price residual net of regional term (partial)") + ax.set_title(f"National beta | beta={beta_nat:.6f}, partial R2={beta_nat_r2:.3f}, model R2={model_r2:.3f}") + fig.tight_layout() + fig.savefig(plots_dir / "national_beta_regression.png", dpi=220) + plt.close(fig) + + # Regional beta plot + regional = summary[summary["scope"].astype(str).str.lower() == "regional"].copy() + regional["region"] = regional["region"].astype(str) + beta_map: dict[str, float] = {} + r2_map: dict[str, float] = {} + for row in regional.itertuples(index=False): + beta_val = pd.to_numeric([getattr(row, "beta")], errors="coerce")[0] + r2_val = (pd.to_numeric([getattr(row, "r2")], errors="coerce")[0] + if "r2" in regional.columns else float("nan")) + if pd.notna(beta_val): + beta_map[str(getattr(row, "region"))] = float(beta_val) + if pd.notna(r2_val): + r2_map[str(getattr(row, "region"))] = float(r2_val) + + regions = [r for r in region_order if r in beta_map] + if not regions: + regions = sorted(points["region"].dropna().astype(str).unique().tolist()) + + ncols = 3 + nrows = int(np.ceil(len(regions) / ncols)) + fig, axes = plt.subplots(nrows, ncols, figsize=(5.2 * ncols, 4.2 * nrows)) + axes = np.atleast_1d(axes).ravel() + for i, region in enumerate(regions): + ax = axes[i] + reg_r = points[points["region"] == region][[reg_x_col, "dp_partial_reg"]].dropna() + beta = beta_map.get(region, float("nan")) + r2 = r2_map.get(region, float("nan")) + ax.scatter(reg_r[reg_x_col], reg_r["dp_partial_reg"], s=10, alpha=0.65, color="#1f77b4") + if not reg_r.empty: + x_line = np.linspace(float(reg_r[reg_x_col].min()), float(reg_r[reg_x_col].max()), 120) + ax.plot(x_line, beta * x_line, color="#d62728", linewidth=1.6) + ax.axhline(0, color="#999999", linewidth=0.6) + ax.axvline(0, color="#999999", linewidth=0.6) + ax.set_title(f"{region}\nbeta={beta:.4f}, partial R2={r2:.3f}", fontsize=10) + ax.set_xlabel(f"{reg_x_col} (partial)") + ax.set_ylabel("dp_reg (partial)") + for i in range(len(regions), len(axes)): + axes[i].axis("off") + fig.suptitle("Regional betas (joint fixed-effects regression)", fontsize=14) + fig.tight_layout(rect=[0, 0, 1, 0.97]) + fig.savefig(plots_dir / "regional_beta_regression.png", dpi=220) + plt.close(fig) + LOGGER.info("Wrote beta plots to %s", plots_dir) + + +def generate_alpha_plots( + alpha_out_dir: Path, + alpha_input_dir: Path, + beta_out_dir: Path, + plots_dir: Path, + region_order: list[str], + aeo_year: int, + deflator_to_2004: float, + first_model_year: int, +) -> None: + plots_dir.mkdir(parents=True, exist_ok=True) + beta_regional, _ = load_regional_beta_map(alpha_out_dir, alpha_input_dir) + beta_national, _ = load_national_beta(alpha_out_dir, alpha_input_dir, beta_out_dir) + missing_regions = [r for r in region_order if r not in beta_regional] + require(not missing_regions, f"Missing regional beta values: {missing_regions}") + + scenarios = discover_output_scenarios(alpha_out_dir, aeo_year) + + for suffix, scenario_id in scenarios: + alpha_path = alpha_out_dir / f"alpha_AEO_{aeo_year}_{suffix}.csv" + price_path = alpha_out_dir / f"ng_AEO_{aeo_year}_{suffix}.csv" + demand_path = alpha_out_dir / f"ng_demand_AEO_{aeo_year}_{suffix}.csv" + if not (alpha_path.exists() and price_path.exists() and demand_path.exists()): + LOGGER.warning("Skipping suffix '%s' due to missing files.", suffix) + continue + + alpha_df = load_wide_series(alpha_path, "alpha_2004", scenario_id, region_order) + price_df = load_wide_series(price_path, "ng_price", scenario_id, region_order) + demand_df = load_wide_series(demand_path, "demand_elec_quads", scenario_id, region_order) + + merged = alpha_df.merge(price_df, on=["scenario_id", "region", "year"], how="inner") + merged = merged.merge(demand_df, on=["scenario_id", "region", "year"], how="inner") + require(not merged.empty, f"No merged data for scenario suffix '{suffix}'") + + q_nat = (demand_df.groupby(["scenario_id", "year"], as_index=False)["demand_elec_quads"] + .sum().rename(columns={"demand_elec_quads": "q_nat"})) + merged = merged.merge(q_nat, on=["scenario_id", "year"], how="left") + merged["price_2004"] = merged["ng_price"] * deflator_to_2004 + merged["beta_reg"] = merged["region"].map(beta_regional) + merged["term_reg"] = merged["beta_reg"] * merged["demand_elec_quads"] + merged["term_nat"] = beta_national * merged["q_nat"] + zero_ng_terms_in_first_model_year(merged, first_model_year) + + ncols = 3 + nrows = int(np.ceil(len(region_order) / ncols)) + fig, axes = plt.subplots(nrows, ncols, figsize=(5.5 * ncols, 4.0 * nrows), sharex=True) + axes = np.atleast_1d(axes).ravel() + for i, region in enumerate(region_order): + ax = axes[i] + reg = merged[merged["region"] == region].sort_values("year") + if reg.empty: + continue + years = reg["year"].to_numpy() + ax.fill_between(years, 0, reg["alpha_2004"].to_numpy(), + alpha=0.5, color="#2ca02c", label="Alpha") + ax.fill_between(years, reg["alpha_2004"].to_numpy(), + reg["alpha_2004"].to_numpy() + reg["term_reg"].to_numpy(), + alpha=0.5, color="#1f77b4", label="Beta_reg * Q_reg") + ax.fill_between(years, + reg["alpha_2004"].to_numpy() + reg["term_reg"].to_numpy(), + reg["alpha_2004"].to_numpy() + reg["term_reg"].to_numpy() + reg["term_nat"].to_numpy(), + alpha=0.5, color="#ff7f0e", label="Beta_nat * Q_nat") + ax.plot(years, reg["price_2004"].to_numpy(), color="#d62728", + linewidth=1.5, linestyle="--", label="Actual price") + ax.set_title(region, fontsize=12, pad=6) + ax.set_ylabel("2004$/MMBtu", fontsize=11) + ax.grid(True, alpha=0.3) + for i in range(len(region_order), len(axes)): + axes[i].axis("off") + handles, labels = axes[0].get_legend_handles_labels() + fig.legend(handles, labels, loc="lower center", ncol=4, fontsize=10, + bbox_to_anchor=(0.5, -0.02)) + fig.suptitle(f"Price decomposition: {scenario_id}\n" + "Price = Alpha + Beta_reg*Q_reg + Beta_nat*Q_nat", fontsize=15) + fig.tight_layout(rect=[0, 0.04, 1, 0.95]) + safe_id = sanitize_file_component(scenario_id) + fig.savefig(plots_dir / f"alpha_price_decomposition_{safe_id}.png", + dpi=220, bbox_inches="tight") + plt.close(fig) + LOGGER.info("Wrote alpha plot for %s", scenario_id) + + +# ============================================================================ +# Part 3: Validation +# ============================================================================ + +def build_validation_frame( + alpha_out_dir: Path, + aeo_year: int, + region_order: list[str], +) -> pd.DataFrame: + LOGGER.info("Building validation frame from alpha outputs in %s", alpha_out_dir) + frames: list[pd.DataFrame] = [] + for suffix, scenario_id, scenario_label in discover_output_scenarios_with_labels(alpha_out_dir, aeo_year): + alpha_path = alpha_out_dir / f"alpha_AEO_{aeo_year}_{suffix}.csv" + price_path = alpha_out_dir / f"ng_AEO_{aeo_year}_{suffix}.csv" + demand_path = alpha_out_dir / f"ng_demand_AEO_{aeo_year}_{suffix}.csv" + if not (alpha_path.exists() and price_path.exists() and demand_path.exists()): + LOGGER.warning("Skipping suffix '%s' due to missing files.", suffix) + continue + alpha_df = load_wide_series(alpha_path, "alpha_2004", scenario_id, region_order, scenario_label) + price_df = load_wide_series(price_path, "ng_price", scenario_id, region_order, scenario_label) + demand_df = load_wide_series(demand_path, "demand_elec_quads", scenario_id, region_order, scenario_label) + merged = alpha_df.merge(price_df, on=["scenario_id", "scenario_label", "region", "year"], how="inner") + merged = merged.merge(demand_df, on=["scenario_id", "scenario_label", "region", "year"], how="inner") + require(not merged.empty, f"No merged rows for scenario '{scenario_id}' ({suffix})") + frames.append(merged) + require(frames, "No scenario frames available for validation.") + out = pd.concat(frames, ignore_index=True) + q_nat = (out.groupby(["scenario_id", "scenario_label", "year"], as_index=False)["demand_elec_quads"] + .sum().rename(columns={"demand_elec_quads": "q_nat"})) + return out.merge(q_nat, on=["scenario_id", "scenario_label", "year"], how="left") + + +def load_beta_regression_points(beta_out_dir: Path) -> tuple[pd.DataFrame, Path]: + path = beta_out_dir / "regression_points.csv" + require(path.exists(), f"Missing regression_points.csv: {path}") + df = pd.read_csv(path) + need = {"scenario_id", "year", "region", "demand", "demand_nat", "price_2004", "dp", "dp_hat"} + require(not (need - set(df.columns)), f"Missing columns in {path}: {sorted(need - set(df.columns))}") + out = df[list(need)].copy() + out["scenario_id"] = out["scenario_id"].astype(str) + out["region"] = out["region"].astype(str).map(lambda x: cendiv_output_label(any_to_cendiv(x))) + for c in ["year", "demand", "demand_nat", "price_2004", "dp", "dp_hat"]: + out[c] = pd.to_numeric(out[c], errors="coerce") + require(not out[["year", "demand", "demand_nat", "price_2004", "dp", "dp_hat"]].isna().any().any(), + f"Non-numeric value(s) in {path}") + out["year"] = out["year"].astype(int) + return out, path + + +def build_step1_beta_validation_frame( + beta_out_dir: Path, + beta_reg_step_map: dict[str, float], + beta_nat_step: float, + alpha1_frame: pd.DataFrame, + alpha1_merge_cols: list[str], + first_model_year: int, +) -> tuple[pd.DataFrame, Path]: + points, points_path = load_beta_regression_points(beta_out_dir) + frame = points.rename(columns={ + "demand": "demand_elec_quads", "demand_nat": "q_nat", + "price_2004": "actual_2004", "dp": "actual_dprice", "dp_hat": "predicted_dprice", + }).copy() + frame["scenario_label"] = frame["scenario_id"] + frame["beta_reg"] = frame["region"].map(beta_reg_step_map) + require(not frame["beta_reg"].isna().any(), + "Missing regional beta mapping in step-1 validation.") + frame["beta_nat"] = beta_nat_step + frame = frame.merge(alpha1_frame, on=alpha1_merge_cols, how="left") + require(not frame["alpha1"].isna().any(), + "Missing alpha1 rows in step-1 validation.") + zero_ng_betas_in_first_model_year(frame, first_model_year) + frame["predicted_2004"] = (frame["alpha1"] + + frame["beta_reg"] * frame["demand_elec_quads"] + + frame["beta_nat"] * frame["q_nat"]) + frame["error"] = frame["actual_2004"] - frame["predicted_2004"] + frame["error_dprice"] = frame["actual_dprice"] - frame["predicted_dprice"] + return frame, points_path + + +def _parity_panel(ax, frame, title, actual_col, predicted_col, xlabel, ylabel): + m = compute_fit_metrics(frame[actual_col], frame[predicted_col]) + x = frame[actual_col].to_numpy(dtype=float) + y = frame[predicted_col].to_numpy(dtype=float) + mask = np.isfinite(x) & np.isfinite(y) + x, y = x[mask], y[mask] + ax.scatter(x, y, s=8, alpha=0.35, color="#1f77b4", edgecolors="none") + if len(x) > 0: + lo = float(min(np.min(x), np.min(y))) + hi = float(max(np.max(x), np.max(y))) + if hi <= lo: + hi = lo + 1.0 + pad = 0.05 * (hi - lo) + ax.plot([lo - pad, hi + pad], [lo - pad, hi + pad], color="#333333", + linestyle="--", linewidth=1.2) + ax.set_xlim(lo - pad, hi + pad) + ax.set_ylim(lo - pad, hi + pad) + ax.set_title(title, fontsize=11, pad=4) + ax.set_xlabel(xlabel) + ax.set_ylabel(ylabel) + ax.grid(True, alpha=0.25) + ax.text(0.02, 0.98, + f"N={int(m['n_obs'])}\nR2={m['r2']:.4f}\nRMSE={m['rmse']:.4f}\nMAE={m['mae']:.4f}", + transform=ax.transAxes, va="top", ha="left", fontsize=9, + bbox={"boxstyle": "round,pad=0.2", "facecolor": "white", + "alpha": 0.75, "edgecolor": "#bbbbbb"}) + return m + + +def plot_overall_parity(step1_frame, step2_frame, out_path): + fig, axes = plt.subplots(1, 2, figsize=(12.8, 5.6)) + step1_m = _parity_panel(axes[0], step1_frame, + "Step 1: beta-regression fit\n(demeaned price: dp vs dp_hat)", + "actual_dprice", "predicted_dprice", + "Actual demeaned price (2004$/MMBtu)", + "Predicted demeaned price (2004$/MMBtu)") + step2_m = _parity_panel(axes[1], step2_frame, + "Step 2: alpha-regression scenarios\n(level price: alpha2 + beta x demand)", + "actual_2004", "predicted_2004", + "Actual (2004$/MMBtu)", "Predicted (2004$/MMBtu)") + fig.suptitle("Results validation parity: step1 demeaned fit vs step2 level fit", + fontsize=14, y=0.98) + fig.tight_layout(rect=[0, 0, 1, 0.95]) + out_path.parent.mkdir(parents=True, exist_ok=True) + fig.savefig(out_path, dpi=220, bbox_inches="tight") + plt.close(fig) + return step1_m, step2_m + + +def plot_actual_vs_predicted(frame, region_order, out_path): + scenarios = list(dict.fromkeys(frame["scenario_label"].astype(str).tolist())) + ncols = 3 + nrows = int(np.ceil(len(region_order) / ncols)) + fig, axes = plt.subplots(nrows, ncols, figsize=(5.3 * ncols, 4.0 * nrows), sharex=True) + axes = np.atleast_1d(axes).ravel() + for i, region in enumerate(region_order): + ax = axes[i] + reg = frame[frame["region"] == region].copy() + if reg.empty: + ax.set_title(region, fontsize=10) + ax.grid(True, alpha=0.25) + continue + for scen in scenarios: + sdf = reg[reg["scenario_label"] == scen].sort_values("year") + if sdf.empty: + continue + color = SCENARIO_COLOR.get(scen) + ax.plot(sdf["year"], sdf["actual_2004"], color=color, linewidth=1.6) + ax.plot(sdf["year"], sdf["predicted_2004"], color=color, + linewidth=3.0, linestyle="--", alpha=0.98, zorder=4) + ax.set_title(region, fontsize=10, pad=4) + ax.set_ylabel("2004$/MMBtu") + ax.grid(True, alpha=0.25) + for i in range(len(region_order), len(axes)): + axes[i].axis("off") + legend_handles = [] + for scen in scenarios: + color = SCENARIO_COLOR.get(scen, "#333333") + legend_handles.append(Line2D([0], [0], color=color, lw=2.0, linestyle="-", + label=f"{scen} actual")) + legend_handles.append(Line2D([0], [0], color=color, lw=2.0, linestyle="--", + alpha=0.7, label=f"{scen} predicted")) + fig.legend(handles=legend_handles, loc="lower center", + ncol=max(2, min(6, len(legend_handles))), fontsize=8, + bbox_to_anchor=(0.5, -0.005)) + fig.suptitle("Results validation: actual price vs predicted\n" + "(predicted = alpha(region,year,scenario) + beta x scenario demand)", + fontsize=14, y=0.98) + fig.tight_layout(rect=[0, 0.04, 1, 0.95]) + out_path.parent.mkdir(parents=True, exist_ok=True) + fig.savefig(out_path, dpi=220, bbox_inches="tight") + plt.close(fig) + + +def plot_alpha_vs_alpha1(frame, region_order, out_path): + scenarios = list(dict.fromkeys(frame["scenario_label"].astype(str).tolist())) + alpha1_shared = bool( + frame.groupby(["region", "year"], as_index=False)["alpha1"].nunique()["alpha1"].max() <= 1) + ncols = 3 + nrows = int(np.ceil(len(region_order) / ncols)) + fig, axes = plt.subplots(nrows, ncols, figsize=(5.3 * ncols, 4.0 * nrows), sharex=True) + axes = np.atleast_1d(axes).ravel() + for i, region in enumerate(region_order): + ax = axes[i] + reg = frame[frame["region"] == region].copy() + if reg.empty: + ax.set_title(region, fontsize=10) + ax.grid(True, alpha=0.25) + continue + for scen in scenarios: + sdf = reg[reg["scenario_label"] == scen].sort_values("year") + if sdf.empty: + continue + color = SCENARIO_COLOR.get(scen) + ax.plot(sdf["year"], sdf["alpha_2004"], color=color, linewidth=1.7) + if not alpha1_shared: + ax.plot(sdf["year"], sdf["alpha1"], color=color, linewidth=2.6, + linestyle="--", alpha=0.98, zorder=4) + if alpha1_shared: + a1 = reg[["year", "alpha1"]].drop_duplicates(subset=["year"]).sort_values("year") + ax.plot(a1["year"], a1["alpha1"], color="#222222", linewidth=2.8, + linestyle="--", alpha=0.98, zorder=5, label="alpha1 shared") + ax.set_title(region, fontsize=10, pad=4) + ax.set_ylabel("alpha") + ax.grid(True, alpha=0.25) + for i in range(len(region_order), len(axes)): + axes[i].axis("off") + legend_handles = [] + for scen in scenarios: + color = SCENARIO_COLOR.get(scen, "#333333") + legend_handles.append(Line2D([0], [0], color=color, lw=2.2, linestyle="-", + label=f"{scen} alpha2")) + if not alpha1_shared: + legend_handles.append(Line2D([0], [0], color=color, lw=2.6, linestyle="--", + alpha=0.98, label=f"{scen} alpha1")) + if alpha1_shared: + legend_handles.append(Line2D([0], [0], color="#222222", lw=2.8, linestyle="--", + alpha=0.98, label="alpha1 shared")) + fig.legend(handles=legend_handles, loc="lower center", + ncol=max(2, min(6, len(legend_handles))), fontsize=8, + bbox_to_anchor=(0.5, -0.005)) + fig.suptitle("Results validation: alpha2 vs alpha1\n" + "(alpha2 = alpha regression output, alpha1 = beta regression output)", + fontsize=14, y=0.98) + fig.tight_layout(rect=[0, 0.04, 1, 0.95]) + out_path.parent.mkdir(parents=True, exist_ok=True) + fig.savefig(out_path, dpi=220, bbox_inches="tight") + plt.close(fig) + + +def run_validation( + config: dict[str, Any], + base_dir: Path, + beta_out_dir: Path, + alpha_out_dir: Path, + alpha_input_dir: Path, + validation_dir: Path, + region_order: list[str], +) -> None: + """Run full validation: CSV metrics + plots.""" + aeo_year = int(config["aeo_year"]) + first_model_year = int(config["start_year"]) + deflator = float(config["ng"]["price_deflator_to_2004"]) + validation_dir.mkdir(parents=True, exist_ok=True) + + # Load betas + beta_reg_map, beta_reg_src = load_regional_beta_map(alpha_out_dir, alpha_input_dir) + beta_nat, beta_nat_src = load_national_beta(alpha_out_dir, alpha_input_dir, beta_out_dir) + missing_regions = [r for r in region_order if r not in beta_reg_map] + require(not missing_regions, f"Missing regional beta: {missing_regions}") + + beta_reg_step_map = load_regional_beta_from_csv(beta_out_dir / "cd_beta0.csv") + beta_nat_step = load_national_beta_from_csv(beta_out_dir / "national_beta.csv") + + # Beta comparison CSV + beta_compare_rows = [{ + "scope": "national", "region": "ALL", + "beta1_from_beta_step": beta_nat_step, + "beta2_used_in_alpha_step": beta_nat, + "diff_beta1_minus_beta2": beta_nat_step - beta_nat, + }] + for region in region_order: + b1, b2 = beta_reg_step_map[region], beta_reg_map[region] + beta_compare_rows.append({ + "scope": "regional", "region": region, + "beta1_from_beta_step": b1, + "beta2_used_in_alpha_step": b2, + "diff_beta1_minus_beta2": b1 - b2, + }) + pd.DataFrame(beta_compare_rows).to_csv( + validation_dir / "results_validation_beta_comparison.csv", + index=False, float_format="%.6f") + + # Build step-2 validation frame + frame = build_validation_frame(alpha_out_dir, aeo_year, region_order) + frame["actual_2004"] = frame["ng_price"] * deflator + frame["beta_reg"] = frame["region"].map(beta_reg_map) + frame["beta_nat"] = beta_nat + zero_ng_betas_in_first_model_year(frame, first_model_year) + frame["predicted_2004"] = (frame["alpha_2004"] + + frame["beta_reg"] * frame["demand_elec_quads"] + + frame["beta_nat"] * frame["q_nat"]) + frame["error"] = frame["actual_2004"] - frame["predicted_2004"] + + # Alpha1 from beta step + alpha1_frame, _, alpha1_merge_cols = load_alpha_from_beta_step(beta_out_dir) + step1_frame, _ = build_step1_beta_validation_frame( + beta_out_dir, beta_reg_step_map, beta_nat_step, + alpha1_frame, alpha1_merge_cols, first_model_year) + + frame = frame.merge(alpha1_frame, on=alpha1_merge_cols, how="left") + frame["alpha_vs_alpha1_error"] = frame["alpha_2004"] - frame["alpha1"] + alpha_cmp_frame = frame[~frame["alpha1"].isna()].copy() + + # Write detail/summary CSVs + step1_frame[[ + "scenario_id", "scenario_label", "region", "year", + "actual_2004", "predicted_2004", "error", + "actual_dprice", "predicted_dprice", "error_dprice", + "alpha1", "beta_reg", "beta_nat", "demand_elec_quads", "q_nat", + ]].to_csv(validation_dir / "results_validation_step1_beta_actual_vs_predicted_detail.csv", + index=False, float_format="%.6f") + + summarize_fit(step1_frame, ["scenario_label", "region"], + "actual_dprice", "predicted_dprice", + "mae_error", "rmse_error", "max_abs_error", "r2").to_csv( + validation_dir / "results_validation_step1_beta_actual_vs_predicted_summary.csv", + index=False, float_format="%.6f") + + frame[[ + "scenario_id", "scenario_label", "region", "year", + "actual_2004", "predicted_2004", "error", + "alpha_2004", "beta_reg", "beta_nat", "demand_elec_quads", "q_nat", + "alpha1", "alpha_vs_alpha1_error", + ]].to_csv(validation_dir / "results_validation_actual_vs_predicted_detail.csv", + index=False, float_format="%.6f") + + summarize_fit(frame, ["scenario_label", "region"], + "actual_2004", "predicted_2004", + "mae_error", "rmse_error", "max_abs_error", "r2").to_csv( + validation_dir / "results_validation_actual_vs_predicted_summary.csv", + index=False, float_format="%.6f") + + if not alpha_cmp_frame.empty: + summarize_fit(alpha_cmp_frame, ["scenario_label", "region"], + "alpha_2004", "alpha1", + "mae_alpha1_error", "rmse_alpha1_error", + "max_abs_alpha1_error", "r2_alpha1").to_csv( + validation_dir / "results_validation_alpha_vs_alpha1_summary.csv", + index=False, float_format="%.6f") + + alpha_spread = (alpha_cmp_frame.groupby(["region", "year"], as_index=False)["alpha_2004"] + .agg(alpha_min="min", alpha_max="max")) + alpha_spread["alpha_spread"] = alpha_spread["alpha_max"] - alpha_spread["alpha_min"] + alpha_spread.to_csv(validation_dir / "results_validation_alpha_vs_alpha1_spread.csv", + index=False, float_format="%.6f") + + alpha_cmp_frame[[ + "scenario_id", "scenario_label", "region", "year", + "alpha_2004", "alpha1", "alpha_vs_alpha1_error", + ]].to_csv(validation_dir / "results_validation_alpha_vs_alpha1_detail.csv", + index=False, float_format="%.6f") + + # Plots + plot_actual_vs_predicted(frame, region_order, + validation_dir / "results_validation_actual_vs_predicted.png") + if not alpha_cmp_frame.empty: + plot_alpha_vs_alpha1(alpha_cmp_frame, region_order, + validation_dir / "results_validation_alpha_vs_alpha1.png") + step1_m, step2_m = plot_overall_parity(step1_frame, frame, + validation_dir / "results_validation_parity_overall.png") + + pd.DataFrame([ + {"step": "step1_beta_regression_scenarios", "metric_basis": "demeaned_price_dp", + "n_obs": int(step1_m["n_obs"]), "mae_error": step1_m["mae"], + "rmse_error": step1_m["rmse"], "max_abs_error": step1_m["max_abs"], "r2": step1_m["r2"]}, + {"step": "step2_alpha_regression_scenarios", "metric_basis": "level_price_2004_per_mmbtu", + "n_obs": int(step2_m["n_obs"]), "mae_error": step2_m["mae"], + "rmse_error": step2_m["rmse"], "max_abs_error": step2_m["max_abs"], "r2": step2_m["r2"]}, + ]).to_csv(validation_dir / "results_validation_overall_metrics.csv", + index=False, float_format="%.6f") + + LOGGER.info("Validation complete. Outputs in %s", validation_dir) + + +# ============================================================================ +# CLI +# ============================================================================ + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Unified visualization and validation for NG regression pipeline.") + parser.add_argument("--config", default="aeo_pipeline_config.json") + parser.add_argument("--beta-output-dir", default="outputs of beta regression") + parser.add_argument("--alpha-output-dir", default=None) + parser.add_argument("--alpha-input-dir", default=None) + parser.add_argument("--output-dir", default="results validation", + help="Directory for all plots and validation CSVs.") + parser.add_argument("--skip-raw-scatter", action="store_true", + help="Skip beta raw-data scatter grid.") + parser.add_argument("--skip-beta", action="store_true", + help="Skip beta diagnostic plots.") + parser.add_argument("--skip-alpha", action="store_true", + help="Skip alpha decomposition plots.") + parser.add_argument("--skip-validation", action="store_true", + help="Skip validation plots and CSVs.") + parser.add_argument("--log-level", default="INFO", + choices=["DEBUG", "INFO", "WARNING", "ERROR"]) + return parser.parse_args() + + +def main() -> int: + args = parse_args() + logging.basicConfig(level=getattr(logging, args.log_level), + format="%(asctime)s | %(levelname)s | %(message)s") + + script_dir = Path(__file__).resolve().parent + cfg_path = Path(args.config) + if not cfg_path.is_absolute(): + cwd_candidate = resolve_case_insensitive((Path.cwd() / cfg_path).resolve()) + script_candidate = resolve_case_insensitive((script_dir / cfg_path).resolve()) + cfg_path = cwd_candidate if cwd_candidate.exists() else script_candidate + + config = load_config(cfg_path) + base_dir = cfg_path.parent + + beta_out_dir = resolve_path(base_dir, args.beta_output_dir) + alpha_out_dir = resolve_path(base_dir, + args.alpha_output_dir or config["paths"]["output_dir"]) + alpha_input_dir = resolve_path(base_dir, + args.alpha_input_dir or config["paths"].get("input_dir", "inputs for alpha regression")) + output_dir = resolve_path(base_dir, args.output_dir) + output_dir.mkdir(parents=True, exist_ok=True) + region_order = region_order_from_config(config) + aeo_year = int(config["aeo_year"]) + first_model_year = int(config["start_year"]) + deflator = float(config["ng"]["price_deflator_to_2004"]) + + if not args.skip_raw_scatter: + generate_raw_scatter_grid(beta_out_dir, config, output_dir) + + if not args.skip_beta: + generate_beta_plots(beta_out_dir, region_order, output_dir) + + if not args.skip_alpha: + generate_alpha_plots( + alpha_out_dir=alpha_out_dir, + alpha_input_dir=alpha_input_dir, + beta_out_dir=beta_out_dir, + plots_dir=output_dir, + region_order=region_order, + aeo_year=aeo_year, + deflator_to_2004=deflator, + first_model_year=first_model_year, + ) + + if not args.skip_validation: + run_validation( + config=config, + base_dir=base_dir, + beta_out_dir=beta_out_dir, + alpha_out_dir=alpha_out_dir, + alpha_input_dir=alpha_input_dir, + validation_dir=output_dir, + region_order=region_order, + ) + + LOGGER.info("All visualization and validation complete.") + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Exception as exc: + LOGGER.exception("Failed: %s", exc) + sys.exit(1) From 1f797f91941004d54ad261a8844a3384989a601d Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Mon, 20 Apr 2026 16:38:58 -0600 Subject: [PATCH 02/14] Add auto-update for historical NG data and backfill 2024 --- .../aeo_alpha_regression.py | 61 +++++++++++++++++++ .../ng_AEO_historical.csv | 29 ++++----- .../ng_demand_AEO_historical.csv | 29 ++++----- .../ng_tot_demand_AEO_historical.csv | 29 ++++----- 4 files changed, 106 insertions(+), 42 deletions(-) diff --git a/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py b/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py index fa89d71..7c2b66a 100644 --- a/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py +++ b/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py @@ -704,6 +704,47 @@ def apply_reference_history_to_all_scenarios( return out +def _append_year_to_history_csv( + csv_path: Path, + year: int, + data_frame: pd.DataFrame, + scenario_id: str, + value_col: str, +) -> None: + """Append a single year from the reference scenario to a history CSV if missing.""" + if not csv_path.exists(): + return + existing = pd.read_csv(csv_path) + year_col = "year" if "year" in existing.columns else "t" + if year_col not in existing.columns: + return + if year in existing[year_col].values: + return # Already present + + row_data = data_frame[ + (data_frame["scenario_id"] == scenario_id) + & (data_frame["year"] == year) + ].copy() + if row_data.empty: + LOGGER.warning("No data for year %d to append to %s.", year, csv_path.name) + return + + row_data["region_out"] = row_data["cendiv"].map(cendiv_output_label) + wide = row_data.pivot_table( + index="year", columns="region_out", values=value_col, aggfunc="mean", + ).reset_index().rename(columns={"year": year_col}) + + for col in existing.columns: + if col not in wide.columns: + wide[col] = float("nan") + wide = wide[existing.columns] + + updated = pd.concat([existing, wide], ignore_index=True) + updated = updated.sort_values(year_col).reset_index(drop=True) + updated.to_csv(csv_path, index=False, float_format="%.5f") + LOGGER.info("Appended year %d to %s.", year, csv_path.name) + + # ============================================================================ # Beta Loading # ============================================================================ @@ -1211,6 +1252,26 @@ def run_ng_pipeline(config: dict[str, Any], base_dir: Path) -> None: base_dir=base_dir, ) + # ---- Step 8: Append projection_start_year to history CSVs ---- + ref_rows = output_scenarios[ + output_scenarios["file_suffix"] == "reference" + ] + if not ref_rows.empty: + ref_sid = str(ref_rows.iloc[0]["scenario_id"]) + hist_dir = resolve_path( + base_dir, + config["paths"].get("input_dir", config["paths"]["output_dir"]), + ) + for stem, vcol, df in [ + ("ng_AEO", "ng_price", price_raw), + ("ng_demand_AEO", "demand_elec_quads", demand_elec), + ("ng_tot_demand_AEO", "demand_total_quads", demand_total), + ]: + _append_year_to_history_csv( + hist_dir / f"{stem}_{HISTORY_SUFFIX}.csv", + projection_start_year, df, ref_sid, vcol, + ) + # ============================================================================ # Entry Point diff --git a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_AEO_historical.csv b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_AEO_historical.csv index 03349e5..21c2a70 100644 --- a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_AEO_historical.csv +++ b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_AEO_historical.csv @@ -1,15 +1,16 @@ year,East_North_Central,East_South_Central,Mid_Atlantic,Mountain,New_England,Pacific,South_Atlantic,West_North_Central,West_South_Central -2010,7.090994509,6.864627039,7.816364499,7.214633076,7.770429471,6.922075026,8.645587478,7.734288289,6.613847095 -2011,6.415244319,6.035802983,7.181609870,6.759039679,6.976605820,6.523092028,7.612683090,7.187830351,6.021934080 -2012,4.318396288,4.171336784,4.920954844,4.812692187,5.125687655,4.981962978,5.744142178,4.836968152,4.086242117 -2013,5.644571605,5.425661349,6.221772114,6.026713986,8.068124701,5.966594412,6.488062275,6.217397452,5.311725257 -2014,6.901573833,6.196133723,6.749785557,6.533248299,8.769201530,6.652865218,7.217679522,7.398615429,6.141907830 -2015,3.728469276,3.831858045,3.850319999,4.283486413,5.664139452,4.318227659,5.209638268,4.428216598,3.709608103 -2016,3.604329269,3.348941929,3.661067671,3.544383574,5.148299225,3.667086135,4.514280196,3.500406617,3.097469786 -2017,4.251331621,4.060241034,4.159690249,4.195250431,5.355284536,4.189158392,4.872571007,4.469496963,3.814340823 -2018,4.083060596,4.025984863,4.228362317,4.311701697,5.881253780,4.317322045,4.693187815,4.334410199,3.784559467 -2019,3.074154645,3.292143502,3.569319762,3.555691398,5.476462081,3.748837112,4.098978687,3.352608181,2.850897331 -2020,2.433600778,2.771317586,2.922260883,3.117010526,4.894556598,3.305044956,3.535609065,2.854163977,2.372945838 -2021,5.212049868,5.940867196,5.323929817,6.295938071,7.947848278,6.712710202,6.632815785,5.658208013,5.441225141 -2022,6.736810455,7.910931077,6.175171066,7.816437211,8.928908764,8.040398193,8.543692060,7.627994713,7.360516678 -2023,2.576696503,2.934271060,3.094089823,3.300290745,5.182356526,3.499381599,3.743502878,3.021988819,2.512475054 +2010,7.09099,6.86463,7.81636,7.21463,7.77043,6.92208,8.64559,7.73429,6.61385 +2011,6.41524,6.03580,7.18161,6.75904,6.97661,6.52309,7.61268,7.18783,6.02193 +2012,4.31840,4.17134,4.92095,4.81269,5.12569,4.98196,5.74414,4.83697,4.08624 +2013,5.64457,5.42566,6.22177,6.02671,8.06812,5.96659,6.48806,6.21740,5.31173 +2014,6.90157,6.19613,6.74979,6.53325,8.76920,6.65287,7.21768,7.39862,6.14191 +2015,3.72847,3.83186,3.85032,4.28349,5.66414,4.31823,5.20964,4.42822,3.70961 +2016,3.60433,3.34894,3.66107,3.54438,5.14830,3.66709,4.51428,3.50041,3.09747 +2017,4.25133,4.06024,4.15969,4.19525,5.35528,4.18916,4.87257,4.46950,3.81434 +2018,4.08306,4.02598,4.22836,4.31170,5.88125,4.31732,4.69319,4.33441,3.78456 +2019,3.07415,3.29214,3.56932,3.55569,5.47646,3.74884,4.09898,3.35261,2.85090 +2020,2.43360,2.77132,2.92226,3.11701,4.89456,3.30504,3.53561,2.85416,2.37295 +2021,5.21205,5.94087,5.32393,6.29594,7.94785,6.71271,6.63282,5.65821,5.44123 +2022,6.73681,7.91093,6.17517,7.81644,8.92891,8.04040,8.54369,7.62799,7.36052 +2023,2.57670,2.93427,3.09409,3.30029,5.18236,3.49938,3.74350,3.02199,2.51248 +2024,2.28508,2.64533,2.26953,2.84119,3.91474,3.17877,3.58168,2.60507,2.19948 diff --git a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_demand_AEO_historical.csv b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_demand_AEO_historical.csv index 1f13e82..906ac82 100644 --- a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_demand_AEO_historical.csv +++ b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_demand_AEO_historical.csv @@ -1,15 +1,16 @@ year,East_North_Central,East_South_Central,Mid_Atlantic,Mountain,New_England,Pacific,South_Atlantic,West_North_Central,West_South_Central -2010,0.326000000,0.567000000,0.890000000,0.641000000,0.420000000,0.989000000,1.544000000,0.124000000,2.049000000 -2011,0.395000000,0.639000000,0.965000000,0.567000000,0.456000000,0.766000000,1.671000000,0.117000000,2.188000000 -2012,0.656000000,0.797000000,1.154000000,0.663000000,0.448000000,1.045000000,2.043000000,0.171000000,2.337000000 -2013,0.475000000,0.629000000,1.066000000,0.651000000,0.372000000,1.069000000,1.883000000,0.140000000,2.075000000 -2014,0.482860000,0.671910000,1.131480000,0.648910000,0.341750000,1.073730000,1.896250000,0.108070000,2.025670000 -2015,0.713310000,0.875420000,1.236450000,0.750920000,0.397610000,1.084430000,2.330100000,0.147160000,2.434110000 -2016,0.912140000,0.961900000,1.344500000,0.765760000,0.393180000,0.917910000,2.469830000,0.191920000,2.351840000 -2017,0.810260000,0.910900000,1.196160000,0.690330000,0.371410000,0.840900000,2.475890000,0.172190000,2.063170000 -2018,1.002570000,0.994602000,1.300064000,0.760259000,0.400407000,0.871735000,2.535531000,0.189613000,2.661307000 -2019,1.185716000,1.029824000,1.451554000,0.988215000,0.338651000,0.834003000,2.790259000,0.228314000,2.928261000 -2020,1.262778000,1.047204000,1.684218000,0.954761000,0.360853000,0.847681000,2.768037000,0.247312000,2.940385000 -2021,1.082247000,0.913914000,1.654776000,0.947247000,0.344592000,0.887034000,2.468727000,0.195056000,2.732240000 -2022,1.477695000,0.900480000,1.998293000,0.947744000,0.366773000,0.850175000,2.605338000,0.257507000,2.797009000 -2023,1.337029346,1.108779595,1.783250018,1.010900947,0.382071156,0.897524643,2.930797576,0.261853946,3.113279638 +2010,0.32600,0.56700,0.89000,0.64100,0.42000,0.98900,1.54400,0.12400,2.04900 +2011,0.39500,0.63900,0.96500,0.56700,0.45600,0.76600,1.67100,0.11700,2.18800 +2012,0.65600,0.79700,1.15400,0.66300,0.44800,1.04500,2.04300,0.17100,2.33700 +2013,0.47500,0.62900,1.06600,0.65100,0.37200,1.06900,1.88300,0.14000,2.07500 +2014,0.48286,0.67191,1.13148,0.64891,0.34175,1.07373,1.89625,0.10807,2.02567 +2015,0.71331,0.87542,1.23645,0.75092,0.39761,1.08443,2.33010,0.14716,2.43411 +2016,0.91214,0.96190,1.34450,0.76576,0.39318,0.91791,2.46983,0.19192,2.35184 +2017,0.81026,0.91090,1.19616,0.69033,0.37141,0.84090,2.47589,0.17219,2.06317 +2018,1.00257,0.99460,1.30006,0.76026,0.40041,0.87174,2.53553,0.18961,2.66131 +2019,1.18572,1.02982,1.45155,0.98821,0.33865,0.83400,2.79026,0.22831,2.92826 +2020,1.26278,1.04720,1.68422,0.95476,0.36085,0.84768,2.76804,0.24731,2.94039 +2021,1.08225,0.91391,1.65478,0.94725,0.34459,0.88703,2.46873,0.19506,2.73224 +2022,1.47769,0.90048,1.99829,0.94774,0.36677,0.85018,2.60534,0.25751,2.79701 +2023,1.33703,1.10878,1.78325,1.01090,0.38207,0.89752,2.93080,0.26185,3.11328 +2024,1.80377,1.12075,1.94787,1.20213,0.45162,1.02698,2.77112,0.32823,3.27809 diff --git a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_tot_demand_AEO_historical.csv b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_tot_demand_AEO_historical.csv index 3fd49d3..12fc1e0 100644 --- a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_tot_demand_AEO_historical.csv +++ b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/ng_tot_demand_AEO_historical.csv @@ -1,15 +1,16 @@ year,East_North_Central,East_South_Central,Mid_Atlantic,Mountain,New_England,Pacific,South_Atlantic,West_North_Central,West_South_Central -2010,3.358270000,1.354117000,2.642740000,4.756302000,0.858180000,2.707125000,2.864664000,1.549812000,5.379282000 -2011,3.525401000,1.416257000,2.719853000,4.793510000,0.915348000,2.548560000,2.934925000,1.555518000,5.529355000 -2012,3.547677000,1.540446000,2.770951000,4.903691000,0.879083000,2.803605000,3.280124000,1.491081000,5.730931000 -2013,3.818099000,1.455897000,2.891799000,4.972179000,0.859505000,2.896845000,3.261053000,1.645916000,5.577358000 -2014,4.045156000,1.544663000,3.120449000,5.000559000,0.857731000,2.784841000,3.326574000,1.680470000,5.646739000 -2015,3.886718000,1.696394000,3.099138000,5.255469000,0.905922000,2.763970000,3.663951000,1.574979000,5.951674000 -2016,3.920965000,1.746690000,3.156144000,1.581652000,0.856641000,2.775395000,3.735140000,1.638642000,5.803449000 -2017,3.997107000,1.767733000,3.113560000,1.576464000,0.879541000,2.827698000,3.888779000,1.729600000,5.922212000 -2018,4.395236000,1.912479000,3.316355000,1.676031000,0.930977000,2.952353000,4.067651000,1.846236000,6.697608000 -2019,4.665439000,1.962087000,3.507681000,1.985243000,0.884965000,2.949311000,4.325762000,1.972424000,7.134515000 -2020,4.578500000,1.967894000,3.615312000,1.900725000,0.849804000,2.847719000,4.221534000,1.915619000,7.066121000 -2021,4.418462000,1.844552000,3.665614000,1.921409000,0.878472000,2.947445000,3.971677000,1.893204000,6.865973000 -2022,4.940085000,1.892741000,4.044715000,1.914708000,0.923152000,2.857152000,4.159855000,1.998683000,7.156394000 -2023,4.648726000,1.861391000,3.709178000,1.734919000,0.914369000,2.869450000,4.158048000,1.877739000,6.910273000 +2010,3.35827,1.35412,2.64274,4.75630,0.85818,2.70713,2.86466,1.54981,5.37928 +2011,3.52540,1.41626,2.71985,4.79351,0.91535,2.54856,2.93492,1.55552,5.52935 +2012,3.54768,1.54045,2.77095,4.90369,0.87908,2.80361,3.28012,1.49108,5.73093 +2013,3.81810,1.45590,2.89180,4.97218,0.85950,2.89684,3.26105,1.64592,5.57736 +2014,4.04516,1.54466,3.12045,5.00056,0.85773,2.78484,3.32657,1.68047,5.64674 +2015,3.88672,1.69639,3.09914,5.25547,0.90592,2.76397,3.66395,1.57498,5.95167 +2016,3.92096,1.74669,3.15614,1.58165,0.85664,2.77540,3.73514,1.63864,5.80345 +2017,3.99711,1.76773,3.11356,1.57646,0.87954,2.82770,3.88878,1.72960,5.92221 +2018,4.39524,1.91248,3.31636,1.67603,0.93098,2.95235,4.06765,1.84624,6.69761 +2019,4.66544,1.96209,3.50768,1.98524,0.88497,2.94931,4.32576,1.97242,7.13452 +2020,4.57850,1.96789,3.61531,1.90072,0.84980,2.84772,4.22153,1.91562,7.06612 +2021,4.41846,1.84455,3.66561,1.92141,0.87847,2.94745,3.97168,1.89320,6.86597 +2022,4.94008,1.89274,4.04472,1.91471,0.92315,2.85715,4.15986,1.99868,7.15639 +2023,4.64873,1.86139,3.70918,1.73492,0.91437,2.86945,4.15805,1.87774,6.91027 +2024,4.96334,2.09747,3.90312,2.15953,0.96217,2.98253,4.37537,2.04819,7.42142 From 77d3367d631560771111bedcc28643955912d211 Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Tue, 21 Apr 2026 00:13:01 -0600 Subject: [PATCH 03/14] Update aeo_alpha_regression.py --- .../aeo_alpha_regression.py | 64 ++++--------------- 1 file changed, 14 insertions(+), 50 deletions(-) diff --git a/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py b/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py index 7c2b66a..54da116 100644 --- a/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py +++ b/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py @@ -944,56 +944,20 @@ def write_ng_outputs( alpha_wide.to_csv(fn_alpha, index=False, float_format="%.6f") written_files.extend([fn_price, fn_elec, fn_total, fn_alpha]) - # --- Beta output files --- - - # Preserve the ordering from the source beta file if possible - beta_order = list(region_order) - try: - beta_src = resolve_path(base_dir, ng_cfg["regional_beta_path"]) - if beta_src.exists(): - src_df = pd.read_csv(beta_src) - cendiv_col = next( - (c for c in src_df.columns - if normalize_token(c).endswith("cendiv")), - None, - ) - if cendiv_col: - src_order = [] - for label in src_df[cendiv_col].tolist(): - cendiv = output_label_to_cendiv(str(label)) - if cendiv in beta_regional and cendiv not in src_order: - src_order.append(cendiv) - if len(src_order) == len(region_order): - beta_order = src_order - except Exception as exc: - LOGGER.warning("Could not use regional beta source ordering: %s", exc) - - # cd_beta0.csv: electric sector betas - beta_df = pd.DataFrame({ - "*cendiv": [cendiv_output_label(c) for c in beta_order], - "value": [beta_regional[c] for c in beta_order], - }) - beta_file = out_dir / "cd_beta0.csv" - beta_df.to_csv(beta_file, index=False, float_format="%.6f") - written_files.append(beta_file) - - # cd_beta0_allsector.csv: all-sector betas (copied from input if available) - allsector_src = resolve_path(base_dir, ng_cfg["cd_beta0_allsector_path"]) - allsector_dst = out_dir / "cd_beta0_allsector.csv" - if allsector_src.exists(): - shutil.copy2(allsector_src, allsector_dst) - else: - LOGGER.warning( - "Configured cd_beta0_allsector source not found (%s). " - "Writing cd_beta0 values instead.", - allsector_src, - ) - beta_df = pd.DataFrame({ - "*cendiv": [cendiv_output_label(c) for c in region_order], - "value": [beta_regional[c] for c in region_order], - }) - beta_df.to_csv(allsector_dst, index=False, float_format="%.6f") - written_files.append(allsector_dst) + # --- Beta output files (copy from input) --- + input_dir = resolve_path( + base_dir, + config["paths"].get("input_dir", config["paths"]["output_dir"]), + ) + beta_files = ["cd_beta0.csv", "cd_beta0_allsector.csv", "national_beta.csv"] + for beta_name in beta_files: + src = resolve_case_insensitive(input_dir / beta_name) + dst = out_dir / beta_name + if src.exists(): + shutil.copy2(src, dst) + written_files.append(dst) + else: + LOGGER.warning("%s not found at %s; skipping copy.", beta_name, src) LOGGER.info("Wrote NG outputs to %s (%d files)", out_dir, len(written_files)) From abc49f1712743e3b6ddb2a833268e0b8b6cb5e3e Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Tue, 21 Apr 2026 00:19:19 -0600 Subject: [PATCH 04/14] Create national_beta.csv --- .../outputs of alpha regression/national_beta.csv | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/national_beta.csv diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/national_beta.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/national_beta.csv new file mode 100644 index 0000000..abd889b --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/national_beta.csv @@ -0,0 +1,2 @@ +beta +0.080017 From 8dc81135c467c51553ce249f307a40a758da7e85 Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Tue, 21 Apr 2026 00:26:44 -0600 Subject: [PATCH 05/14] Remove cd_beta0_allsector --- .../natural_gas_price_regression/aeo_alpha_regression.py | 7 +------ .../natural_gas_price_regression/aeo_pipeline_config.json | 3 +-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py b/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py index 54da116..a21a6b0 100644 --- a/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py +++ b/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py @@ -47,7 +47,6 @@ - ng_demand_AEO_{year}_{scenario}.csv : Electric sector demand (Quads) - ng_tot_demand_AEO_{year}_{scenario}.csv : Total sector demand (Quads) - cd_beta0.csv : Electric sector regional betas -- cd_beta0_allsector.csv : All-sector regional betas Usage ----- @@ -757,9 +756,6 @@ def load_regional_betas(beta_path: Path, The beta file (cd_beta0.csv) contains electric-sector-only betas, representing the price sensitivity to regional electric sector demand: Beta_regional(r) in units of 2004$/MMBtu per Quad - - A separate file (cd_beta0_allsector.csv) contains betas for total - economy-wide NG demand, used when modeling all-sector price feedback. """ require(beta_path.exists(), f"Regional beta file not found: {beta_path}") @@ -906,7 +902,6 @@ def write_ng_outputs( Shared output files: - cd_beta0.csv : Electric sector regional betas - - cd_beta0_allsector.csv : All-sector regional betas (copied from input) """ ng_cfg = config["ng"] aeo_year = int(config["aeo_year"]) @@ -949,7 +944,7 @@ def write_ng_outputs( base_dir, config["paths"].get("input_dir", config["paths"]["output_dir"]), ) - beta_files = ["cd_beta0.csv", "cd_beta0_allsector.csv", "national_beta.csv"] + beta_files = ["cd_beta0.csv", "national_beta.csv"] for beta_name in beta_files: src = resolve_case_insensitive(input_dir / beta_name) dst = out_dir / beta_name diff --git a/aeo_updates/natural_gas_price_regression/aeo_pipeline_config.json b/aeo_updates/natural_gas_price_regression/aeo_pipeline_config.json index 1a3efc8..45191e8 100644 --- a/aeo_updates/natural_gas_price_regression/aeo_pipeline_config.json +++ b/aeo_updates/natural_gas_price_regression/aeo_pipeline_config.json @@ -67,7 +67,6 @@ "Pacific" ], "price_deflator_to_2004": 0.602782, - "regional_beta_path": "inputs for alpha regression/cd_beta0.csv", - "cd_beta0_allsector_path": "inputs for alpha regression/cd_beta0_allsector.csv" + "regional_beta_path": "inputs for alpha regression/cd_beta0.csv" } } From d997b25510afe0b47799251408a458339a84d15e Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Tue, 21 Apr 2026 00:31:30 -0600 Subject: [PATCH 06/14] Delete cd_beta0_allsector.csv --- .../outputs of alpha regression/cd_beta0_allsector.csv | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0_allsector.csv diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0_allsector.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0_allsector.csv deleted file mode 100644 index 946cf33..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0_allsector.csv +++ /dev/null @@ -1,10 +0,0 @@ -*cendiv,value -New_England,3.875323 -Mid_Atlantic,0.151497 -East_North_Central,0.033492 -West_North_Central,0.856915 -South_Atlantic,0.175498 -East_South_Central,0.139571 -West_South_Central,-0.054900 -Mountain,0.670353 -Pacific,1.341567 From a8f5489d73ba8121b5d84285f7d54c14ab08bd05 Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Tue, 21 Apr 2026 14:20:15 -0600 Subject: [PATCH 07/14] Update the results for minor difference due to the rounding somewhere --- .../alpha_AEO_2025_HOG.csv | 28 +++++++++---------- .../alpha_AEO_2025_LOG.csv | 28 +++++++++---------- .../alpha_AEO_2025_reference.csv | 28 +++++++++---------- .../ng_AEO_2025_HOG.csv | 28 +++++++++---------- .../ng_AEO_2025_LOG.csv | 28 +++++++++---------- .../ng_AEO_2025_reference.csv | 28 +++++++++---------- .../ng_demand_AEO_2025_HOG.csv | 12 ++++---- .../ng_demand_AEO_2025_LOG.csv | 12 ++++---- .../ng_demand_AEO_2025_reference.csv | 12 ++++---- .../ng_tot_demand_AEO_2025_HOG.csv | 28 +++++++++---------- .../ng_tot_demand_AEO_2025_LOG.csv | 28 +++++++++---------- .../ng_tot_demand_AEO_2025_reference.csv | 28 +++++++++---------- 12 files changed, 144 insertions(+), 144 deletions(-) diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_HOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_HOG.csv index bd15a24..1147d3d 100644 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_HOG.csv +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_HOG.csv @@ -1,18 +1,18 @@ t,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,4.683875,4.711564,4.274324,4.662090,5.211405,4.137874,3.986708,4.348851,4.172502 -2011,1.816973,3.561499,3.232512,3.611184,3.674279,2.927836,3.128783,3.072885,2.283110 -2012,0.608249,2.046157,1.835802,2.023827,2.358645,1.657890,1.846136,1.711282,0.855822 -2013,2.752758,2.919934,2.717595,2.958825,2.911482,2.513759,2.646788,2.527453,1.493478 -2014,3.290932,3.226641,3.473380,3.696553,3.347306,2.970546,3.142848,2.832533,1.899154 -2015,1.075644,1.335855,1.425834,1.745415,1.933618,1.389862,1.571987,1.280897,0.350384 -2016,0.754709,1.178244,1.317182,1.120629,1.462783,1.059535,1.171321,0.798267,0.154122 -2017,1.026077,1.563513,1.772830,1.783921,1.739926,1.557646,1.649825,1.303398,0.634367 -2018,1.135938,1.494356,1.570148,1.592753,1.526519,1.430504,1.569901,1.231905,0.575444 -2019,1.046547,0.989432,0.871149,0.883062,1.038922,0.898527,0.937047,0.538670,0.198677 -2020,0.582664,0.537068,0.455374,0.539249,0.676152,0.555077,0.622532,0.269587,-0.114263 -2021,2.557157,2.060218,2.207226,2.345262,2.666628,2.555234,2.531615,2.261831,1.958028 -2022,2.984533,2.443258,3.035049,3.401068,3.716464,3.666597,3.614054,3.099996,2.729752 -2023,0.616925,0.568648,0.482150,0.570957,0.715910,0.587715,0.659137,0.285438,-0.120982 +2010,4.683875,4.711561,4.274321,4.662091,5.211406,4.137875,3.986710,4.348849,4.172505 +2011,1.816976,3.561499,3.232510,3.611184,3.674277,2.927834,3.128780,3.072886,2.283109 +2012,0.608251,2.046154,1.835805,2.023828,2.358643,1.657892,1.846135,1.711281,0.855820 +2013,2.752755,2.919933,2.717594,2.958827,2.911481,2.513758,2.646791,2.527450,1.493476 +2014,3.290931,3.226643,3.473377,3.696555,3.347307,2.970544,3.142849,2.832534,1.899157 +2015,1.075644,1.335855,1.425834,1.745417,1.933619,1.389863,1.571988,1.280899,0.350386 +2016,0.754709,1.178246,1.317182,1.120631,1.462783,1.059534,1.171322,0.798265,0.154124 +2017,1.026074,1.563513,1.772829,1.783923,1.739925,1.557646,1.649825,1.303398,0.634368 +2018,1.135924,1.494355,1.570148,1.592755,1.526521,1.430502,1.569901,1.231903,0.575436 +2019,1.046551,0.989434,0.871148,0.883068,1.038924,0.898527,0.937050,0.538674,0.198684 +2020,0.582678,0.537067,0.455373,0.539248,0.676152,0.555079,0.622535,0.269587,-0.114265 +2021,2.557165,2.060217,2.207225,2.345259,2.666629,2.555236,2.531617,2.261829,1.958033 +2022,2.984546,2.443258,3.035049,3.401063,3.716462,3.666597,3.614057,3.100001,2.729747 +2023,0.616932,0.568648,0.482152,0.570962,0.715908,0.587715,0.659140,0.285439,-0.120976 2024,-0.468010,-0.031321,0.210737,0.184579,0.497425,0.345082,0.398380,-0.191626,-0.546024 2025,-0.454252,0.112763,0.344876,0.320929,0.499549,0.410939,0.468171,-0.100039,-0.445625 2026,-0.252073,0.019707,0.197131,0.206801,0.316351,0.224597,0.318176,-0.232231,-0.439900 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_LOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_LOG.csv index 2b3490f..e377651 100644 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_LOG.csv +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_LOG.csv @@ -1,18 +1,18 @@ t,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,4.683875,4.711564,4.274324,4.662090,5.211405,4.137874,3.986708,4.348851,4.172502 -2011,1.816973,3.561499,3.232512,3.611184,3.674279,2.927836,3.128783,3.072885,2.283110 -2012,0.608249,2.046157,1.835802,2.023827,2.358645,1.657890,1.846136,1.711282,0.855822 -2013,2.752758,2.919934,2.717595,2.958825,2.911482,2.513759,2.646788,2.527453,1.493478 -2014,3.290932,3.226641,3.473380,3.696553,3.347306,2.970546,3.142848,2.832533,1.899154 -2015,1.075644,1.335855,1.425834,1.745415,1.933618,1.389862,1.571987,1.280897,0.350384 -2016,0.754709,1.178244,1.317182,1.120629,1.462783,1.059535,1.171321,0.798267,0.154122 -2017,1.026077,1.563513,1.772830,1.783921,1.739926,1.557646,1.649825,1.303398,0.634367 -2018,1.135938,1.494356,1.570148,1.592753,1.526519,1.430504,1.569901,1.231905,0.575444 -2019,1.046547,0.989432,0.871149,0.883062,1.038922,0.898527,0.937047,0.538670,0.198677 -2020,0.582664,0.537068,0.455374,0.539249,0.676152,0.555077,0.622532,0.269587,-0.114263 -2021,2.557157,2.060218,2.207226,2.345262,2.666628,2.555234,2.531615,2.261831,1.958028 -2022,2.984533,2.443258,3.035049,3.401068,3.716464,3.666597,3.614054,3.099996,2.729752 -2023,0.616925,0.568648,0.482150,0.570957,0.715910,0.587715,0.659137,0.285438,-0.120982 +2010,4.683875,4.711561,4.274321,4.662091,5.211406,4.137875,3.986710,4.348849,4.172505 +2011,1.816976,3.561499,3.232510,3.611184,3.674277,2.927834,3.128780,3.072886,2.283109 +2012,0.608251,2.046154,1.835805,2.023828,2.358643,1.657892,1.846135,1.711281,0.855820 +2013,2.752755,2.919933,2.717594,2.958827,2.911481,2.513758,2.646791,2.527450,1.493476 +2014,3.290931,3.226643,3.473377,3.696555,3.347307,2.970544,3.142849,2.832534,1.899157 +2015,1.075644,1.335855,1.425834,1.745417,1.933619,1.389863,1.571988,1.280899,0.350386 +2016,0.754709,1.178246,1.317182,1.120631,1.462783,1.059534,1.171322,0.798265,0.154124 +2017,1.026074,1.563513,1.772829,1.783923,1.739925,1.557646,1.649825,1.303398,0.634368 +2018,1.135924,1.494355,1.570148,1.592755,1.526521,1.430502,1.569901,1.231903,0.575436 +2019,1.046551,0.989434,0.871148,0.883068,1.038924,0.898527,0.937050,0.538674,0.198684 +2020,0.582678,0.537067,0.455373,0.539248,0.676152,0.555079,0.622535,0.269587,-0.114265 +2021,2.557165,2.060217,2.207225,2.345259,2.666629,2.555236,2.531617,2.261829,1.958033 +2022,2.984546,2.443258,3.035049,3.401063,3.716462,3.666597,3.614057,3.100001,2.729747 +2023,0.616932,0.568648,0.482152,0.570962,0.715908,0.587715,0.659140,0.285439,-0.120976 2024,-0.484707,-0.029711,0.215051,0.187075,0.490094,0.339058,0.400083,-0.191824,-0.544057 2025,0.320668,0.889994,1.169469,1.126793,1.370276,1.322634,1.365049,0.743120,0.468185 2026,0.993648,1.277484,1.435401,1.432441,1.674898,1.591261,1.515472,1.117014,0.752048 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_reference.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_reference.csv index bb30fc0..8fb87b9 100644 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_reference.csv +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_reference.csv @@ -1,18 +1,18 @@ t,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,4.683875,4.711564,4.274324,4.662090,5.211405,4.137874,3.986708,4.348851,4.172502 -2011,1.816973,3.561499,3.232512,3.611184,3.674279,2.927836,3.128783,3.072885,2.283110 -2012,0.608249,2.046157,1.835802,2.023827,2.358645,1.657890,1.846136,1.711282,0.855822 -2013,2.752758,2.919934,2.717595,2.958825,2.911482,2.513759,2.646788,2.527453,1.493478 -2014,3.290932,3.226641,3.473380,3.696553,3.347306,2.970546,3.142848,2.832533,1.899154 -2015,1.075644,1.335855,1.425834,1.745415,1.933618,1.389862,1.571987,1.280897,0.350384 -2016,0.754709,1.178244,1.317182,1.120629,1.462783,1.059535,1.171321,0.798267,0.154122 -2017,1.026077,1.563513,1.772830,1.783921,1.739926,1.557646,1.649825,1.303398,0.634367 -2018,1.135938,1.494356,1.570148,1.592753,1.526519,1.430504,1.569901,1.231905,0.575444 -2019,1.046547,0.989432,0.871149,0.883062,1.038922,0.898527,0.937047,0.538670,0.198677 -2020,0.582664,0.537068,0.455374,0.539249,0.676152,0.555077,0.622532,0.269587,-0.114263 -2021,2.557157,2.060218,2.207226,2.345262,2.666628,2.555234,2.531615,2.261831,1.958028 -2022,2.984533,2.443258,3.035049,3.401068,3.716464,3.666597,3.614054,3.099996,2.729752 -2023,0.616925,0.568648,0.482150,0.570957,0.715910,0.587715,0.659137,0.285438,-0.120982 +2010,4.683875,4.711561,4.274321,4.662091,5.211406,4.137875,3.986710,4.348849,4.172505 +2011,1.816976,3.561499,3.232510,3.611184,3.674277,2.927834,3.128780,3.072886,2.283109 +2012,0.608251,2.046154,1.835805,2.023828,2.358643,1.657892,1.846135,1.711281,0.855820 +2013,2.752755,2.919933,2.717594,2.958827,2.911481,2.513758,2.646791,2.527450,1.493476 +2014,3.290931,3.226643,3.473377,3.696555,3.347307,2.970544,3.142849,2.832534,1.899157 +2015,1.075644,1.335855,1.425834,1.745417,1.933619,1.389863,1.571988,1.280899,0.350386 +2016,0.754709,1.178246,1.317182,1.120631,1.462783,1.059534,1.171322,0.798265,0.154124 +2017,1.026074,1.563513,1.772829,1.783923,1.739925,1.557646,1.649825,1.303398,0.634368 +2018,1.135924,1.494355,1.570148,1.592755,1.526521,1.430502,1.569901,1.231903,0.575436 +2019,1.046551,0.989434,0.871148,0.883068,1.038924,0.898527,0.937050,0.538674,0.198684 +2020,0.582678,0.537067,0.455373,0.539248,0.676152,0.555079,0.622535,0.269587,-0.114265 +2021,2.557165,2.060217,2.207225,2.345259,2.666629,2.555236,2.531617,2.261829,1.958033 +2022,2.984546,2.443258,3.035049,3.401063,3.716462,3.666597,3.614057,3.100001,2.729747 +2023,0.616932,0.568648,0.482152,0.570962,0.715908,0.587715,0.659140,0.285439,-0.120976 2024,-0.505133,-0.041746,0.202311,0.174344,0.557962,0.323449,0.391092,-0.207917,-0.576337 2025,-0.229539,0.347671,0.602813,0.572750,0.772238,0.692976,0.749541,0.205100,-0.115501 2026,0.116280,0.431180,0.613034,0.607796,0.782696,0.694058,0.728853,0.230798,-0.054895 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_HOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_HOG.csv index fc1046e..cd617a2 100644 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_HOG.csv +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_HOG.csv @@ -1,18 +1,18 @@ year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,7.770429,7.816364,7.090995,7.734288,8.645587,6.864627,6.613847,7.214633,6.922075 -2011,6.976606,7.181610,6.415244,7.187830,7.612683,6.035803,6.021934,6.759040,6.523092 -2012,5.125688,4.920955,4.318396,4.836968,5.744142,4.171337,4.086242,4.812692,4.981963 -2013,8.068125,6.221772,5.644572,6.217397,6.488062,5.425661,5.311725,6.026714,5.966594 -2014,8.769202,6.749786,6.901574,7.398615,7.217680,6.196134,6.141908,6.533248,6.652865 -2015,5.664139,3.850320,3.728469,4.428217,5.209638,3.831858,3.709608,4.283486,4.318228 -2016,5.148299,3.661068,3.604329,3.500407,4.514280,3.348942,3.097470,3.544384,3.667086 -2017,5.355285,4.159690,4.251332,4.469497,4.872571,4.060241,3.814341,4.195250,4.189158 -2018,5.881254,4.228362,4.083061,4.334410,4.693188,4.025985,3.784559,4.311702,4.317322 -2019,5.476462,3.569320,3.074155,3.352608,4.098979,3.292144,2.850897,3.555691,3.748837 -2020,4.894557,2.922261,2.433601,2.854164,3.535609,2.771318,2.372946,3.117011,3.305045 -2021,7.947848,5.323930,5.212050,5.658208,6.632816,5.940867,5.441225,6.295938,6.712710 -2022,8.928909,6.175171,6.736810,7.627995,8.543692,7.910931,7.360517,7.816437,8.040398 -2023,5.182357,3.094090,2.576697,3.021989,3.743503,2.934271,2.512475,3.300291,3.499382 +2010,7.770430,7.816360,7.090990,7.734290,8.645590,6.864630,6.613850,7.214630,6.922080 +2011,6.976610,7.181610,6.415240,7.187830,7.612680,6.035800,6.021930,6.759040,6.523090 +2012,5.125690,4.920950,4.318400,4.836970,5.744140,4.171340,4.086240,4.812690,4.981960 +2013,8.068120,6.221770,5.644570,6.217400,6.488060,5.425660,5.311730,6.026710,5.966590 +2014,8.769200,6.749790,6.901570,7.398620,7.217680,6.196130,6.141910,6.533250,6.652870 +2015,5.664140,3.850320,3.728470,4.428220,5.209640,3.831860,3.709610,4.283490,4.318230 +2016,5.148300,3.661070,3.604330,3.500410,4.514280,3.348940,3.097470,3.544380,3.667090 +2017,5.355280,4.159690,4.251330,4.469500,4.872570,4.060240,3.814340,4.195250,4.189160 +2018,5.881250,4.228360,4.083060,4.334410,4.693190,4.025980,3.784560,4.311700,4.317320 +2019,5.476460,3.569320,3.074150,3.352610,4.098980,3.292140,2.850900,3.555690,3.748840 +2020,4.894560,2.922260,2.433600,2.854160,3.535610,2.771320,2.372950,3.117010,3.305040 +2021,7.947850,5.323930,5.212050,5.658210,6.632820,5.940870,5.441230,6.295940,6.712710 +2022,8.928910,6.175170,6.736810,7.627990,8.543690,7.910930,7.360520,7.816440,8.040400 +2023,5.182360,3.094090,2.576700,3.021990,3.743500,2.934270,2.512480,3.300290,3.499380 2024,3.942886,2.287270,2.298708,2.621773,3.481087,2.680677,2.210615,2.863694,3.208913 2025,3.545907,2.313296,2.394202,2.708847,3.371045,2.663157,2.218614,2.777358,2.887983 2026,3.424357,2.298251,2.279395,2.664633,3.222955,2.498695,2.059296,2.712186,2.803907 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_LOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_LOG.csv index ebfea64..4e7afb5 100644 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_LOG.csv +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_LOG.csv @@ -1,18 +1,18 @@ year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,7.770429,7.816364,7.090995,7.734288,8.645587,6.864627,6.613847,7.214633,6.922075 -2011,6.976606,7.181610,6.415244,7.187830,7.612683,6.035803,6.021934,6.759040,6.523092 -2012,5.125688,4.920955,4.318396,4.836968,5.744142,4.171337,4.086242,4.812692,4.981963 -2013,8.068125,6.221772,5.644572,6.217397,6.488062,5.425661,5.311725,6.026714,5.966594 -2014,8.769202,6.749786,6.901574,7.398615,7.217680,6.196134,6.141908,6.533248,6.652865 -2015,5.664139,3.850320,3.728469,4.428217,5.209638,3.831858,3.709608,4.283486,4.318228 -2016,5.148299,3.661068,3.604329,3.500407,4.514280,3.348942,3.097470,3.544384,3.667086 -2017,5.355285,4.159690,4.251332,4.469497,4.872571,4.060241,3.814341,4.195250,4.189158 -2018,5.881254,4.228362,4.083061,4.334410,4.693188,4.025985,3.784559,4.311702,4.317322 -2019,5.476462,3.569320,3.074155,3.352608,4.098979,3.292144,2.850897,3.555691,3.748837 -2020,4.894557,2.922261,2.433601,2.854164,3.535609,2.771318,2.372946,3.117011,3.305045 -2021,7.947848,5.323930,5.212050,5.658208,6.632816,5.940867,5.441225,6.295938,6.712710 -2022,8.928909,6.175171,6.736810,7.627995,8.543692,7.910931,7.360517,7.816437,8.040398 -2023,5.182357,3.094090,2.576697,3.021989,3.743503,2.934271,2.512475,3.300291,3.499382 +2010,7.770430,7.816360,7.090990,7.734290,8.645590,6.864630,6.613850,7.214630,6.922080 +2011,6.976610,7.181610,6.415240,7.187830,7.612680,6.035800,6.021930,6.759040,6.523090 +2012,5.125690,4.920950,4.318400,4.836970,5.744140,4.171340,4.086240,4.812690,4.981960 +2013,8.068120,6.221770,5.644570,6.217400,6.488060,5.425660,5.311730,6.026710,5.966590 +2014,8.769200,6.749790,6.901570,7.398620,7.217680,6.196130,6.141910,6.533250,6.652870 +2015,5.664140,3.850320,3.728470,4.428220,5.209640,3.831860,3.709610,4.283490,4.318230 +2016,5.148300,3.661070,3.604330,3.500410,4.514280,3.348940,3.097470,3.544380,3.667090 +2017,5.355280,4.159690,4.251330,4.469500,4.872570,4.060240,3.814340,4.195250,4.189160 +2018,5.881250,4.228360,4.083060,4.334410,4.693190,4.025980,3.784560,4.311700,4.317320 +2019,5.476460,3.569320,3.074150,3.352610,4.098980,3.292140,2.850900,3.555690,3.748840 +2020,4.894560,2.922260,2.433600,2.854160,3.535610,2.771320,2.372950,3.117010,3.305040 +2021,7.947850,5.323930,5.212050,5.658210,6.632820,5.940870,5.441230,6.295940,6.712710 +2022,8.928910,6.175170,6.736810,7.627990,8.543690,7.910930,7.360520,7.816440,8.040400 +2023,5.182360,3.094090,2.576700,3.021990,3.743500,2.934270,2.512480,3.300290,3.499380 2024,3.951021,2.291188,2.306225,2.628691,3.470091,2.671443,2.214949,2.867855,3.213850 2025,4.825856,3.629599,3.757886,4.032818,4.788136,4.158859,3.699224,4.146041,4.247904 2026,4.605783,3.834864,3.800100,4.000161,4.790429,4.182667,3.667104,4.116380,4.119196 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_reference.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_reference.csv index f3e1eec..09c83f6 100644 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_reference.csv +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_reference.csv @@ -1,18 +1,18 @@ year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,7.770429,7.816364,7.090995,7.734288,8.645587,6.864627,6.613847,7.214633,6.922075 -2011,6.976606,7.181610,6.415244,7.187830,7.612683,6.035803,6.021934,6.759040,6.523092 -2012,5.125688,4.920955,4.318396,4.836968,5.744142,4.171337,4.086242,4.812692,4.981963 -2013,8.068125,6.221772,5.644572,6.217397,6.488062,5.425661,5.311725,6.026714,5.966594 -2014,8.769202,6.749786,6.901574,7.398615,7.217680,6.196134,6.141908,6.533248,6.652865 -2015,5.664139,3.850320,3.728469,4.428217,5.209638,3.831858,3.709608,4.283486,4.318228 -2016,5.148299,3.661068,3.604329,3.500407,4.514280,3.348942,3.097470,3.544384,3.667086 -2017,5.355285,4.159690,4.251332,4.469497,4.872571,4.060241,3.814341,4.195250,4.189158 -2018,5.881254,4.228362,4.083061,4.334410,4.693188,4.025985,3.784559,4.311702,4.317322 -2019,5.476462,3.569320,3.074155,3.352608,4.098979,3.292144,2.850897,3.555691,3.748837 -2020,4.894557,2.922261,2.433601,2.854164,3.535609,2.771318,2.372946,3.117011,3.305045 -2021,7.947848,5.323930,5.212050,5.658208,6.632816,5.940867,5.441225,6.295938,6.712710 -2022,8.928909,6.175171,6.736810,7.627995,8.543692,7.910931,7.360517,7.816437,8.040398 -2023,5.182357,3.094090,2.576697,3.021989,3.743503,2.934271,2.512475,3.300291,3.499382 +2010,7.770430,7.816360,7.090990,7.734290,8.645590,6.864630,6.613850,7.214630,6.922080 +2011,6.976610,7.181610,6.415240,7.187830,7.612680,6.035800,6.021930,6.759040,6.523090 +2012,5.125690,4.920950,4.318400,4.836970,5.744140,4.171340,4.086240,4.812690,4.981960 +2013,8.068120,6.221770,5.644570,6.217400,6.488060,5.425660,5.311730,6.026710,5.966590 +2014,8.769200,6.749790,6.901570,7.398620,7.217680,6.196130,6.141910,6.533250,6.652870 +2015,5.664140,3.850320,3.728470,4.428220,5.209640,3.831860,3.709610,4.283490,4.318230 +2016,5.148300,3.661070,3.604330,3.500410,4.514280,3.348940,3.097470,3.544380,3.667090 +2017,5.355280,4.159690,4.251330,4.469500,4.872570,4.060240,3.814340,4.195250,4.189160 +2018,5.881250,4.228360,4.083060,4.334410,4.693190,4.025980,3.784560,4.311700,4.317320 +2019,5.476460,3.569320,3.074150,3.352610,4.098980,3.292140,2.850900,3.555690,3.748840 +2020,4.894560,2.922260,2.433600,2.854160,3.535610,2.771320,2.372950,3.117010,3.305040 +2021,7.947850,5.323930,5.212050,5.658210,6.632820,5.940870,5.441230,6.295940,6.712710 +2022,8.928910,6.175170,6.736810,7.627990,8.543690,7.910930,7.360520,7.816440,8.040400 +2023,5.182360,3.094090,2.576700,3.021990,3.743500,2.934270,2.512480,3.300290,3.499380 2024,3.914745,2.269530,2.285080,2.605072,3.581676,2.645327,2.199480,2.841191,3.178771 2025,3.945919,2.724665,2.837277,3.162053,3.846201,3.142428,2.702884,3.296411,3.449765 2026,3.819109,2.780215,2.763278,3.076137,3.765639,3.055122,2.602545,3.156343,3.232441 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_HOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_HOG.csv index 20a30c6..d8a5763 100644 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_HOG.csv +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_HOG.csv @@ -7,12 +7,12 @@ year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlant 2015,0.397610,1.236450,0.713310,0.147160,2.330100,0.875420,2.434110,0.750920,1.084430 2016,0.393180,1.344500,0.912140,0.191920,2.469830,0.961900,2.351840,0.765760,0.917910 2017,0.371410,1.196160,0.810260,0.172190,2.475890,0.910900,2.063170,0.690330,0.840900 -2018,0.400407,1.300064,1.002570,0.189613,2.535531,0.994602,2.661307,0.760259,0.871735 -2019,0.338651,1.451554,1.185716,0.228314,2.790259,1.029824,2.928261,0.988215,0.834003 -2020,0.360853,1.684218,1.262778,0.247312,2.768037,1.047204,2.940385,0.954761,0.847681 -2021,0.344592,1.654776,1.082247,0.195056,2.468727,0.913914,2.732240,0.947247,0.887034 -2022,0.366773,1.998293,1.477695,0.257507,2.605338,0.900480,2.797009,0.947744,0.850175 -2023,0.382071,1.783250,1.337029,0.261854,2.930798,1.108780,3.113280,1.010901,0.897525 +2018,0.400410,1.300060,1.002570,0.189610,2.535530,0.994600,2.661310,0.760260,0.871740 +2019,0.338650,1.451550,1.185720,0.228310,2.790260,1.029820,2.928260,0.988210,0.834000 +2020,0.360850,1.684220,1.262780,0.247310,2.768040,1.047200,2.940390,0.954760,0.847680 +2021,0.344590,1.654780,1.082250,0.195060,2.468730,0.913910,2.732240,0.947250,0.887030 +2022,0.366770,1.998290,1.477690,0.257510,2.605340,0.900480,2.797010,0.947740,0.850180 +2023,0.382070,1.783250,1.337030,0.261850,2.930800,1.108780,3.113280,1.010900,0.897520 2024,0.446506,1.951789,1.807217,0.328414,2.772431,1.120767,3.282638,1.198553,1.018170 2025,0.400232,1.590906,1.721987,0.316580,2.802444,1.101454,3.123186,1.094271,0.854088 2026,0.311662,1.697816,2.042994,0.339554,2.951403,1.240576,3.375084,1.131739,0.761514 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_LOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_LOG.csv index c848a10..ce2ed11 100644 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_LOG.csv +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_LOG.csv @@ -7,12 +7,12 @@ year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlant 2015,0.397610,1.236450,0.713310,0.147160,2.330100,0.875420,2.434110,0.750920,1.084430 2016,0.393180,1.344500,0.912140,0.191920,2.469830,0.961900,2.351840,0.765760,0.917910 2017,0.371410,1.196160,0.810260,0.172190,2.475890,0.910900,2.063170,0.690330,0.840900 -2018,0.400407,1.300064,1.002570,0.189613,2.535531,0.994602,2.661307,0.760259,0.871735 -2019,0.338651,1.451554,1.185716,0.228314,2.790259,1.029824,2.928261,0.988215,0.834003 -2020,0.360853,1.684218,1.262778,0.247312,2.768037,1.047204,2.940385,0.954761,0.847681 -2021,0.344592,1.654776,1.082247,0.195056,2.468727,0.913914,2.732240,0.947247,0.887034 -2022,0.366773,1.998293,1.477695,0.257507,2.605338,0.900480,2.797009,0.947744,0.850175 -2023,0.382071,1.783250,1.337029,0.261854,2.930798,1.108780,3.113280,1.010901,0.897525 +2018,0.400410,1.300060,1.002570,0.189610,2.535530,0.994600,2.661310,0.760260,0.871740 +2019,0.338650,1.451550,1.185720,0.228310,2.790260,1.029820,2.928260,0.988210,0.834000 +2020,0.360850,1.684220,1.262780,0.247310,2.768040,1.047200,2.940390,0.954760,0.847680 +2021,0.344590,1.654780,1.082250,0.195060,2.468730,0.913910,2.732240,0.947250,0.887030 +2022,0.366770,1.998290,1.477690,0.257510,2.605340,0.900480,2.797010,0.947740,0.850180 +2023,0.382070,1.783250,1.337030,0.261850,2.930800,1.108780,3.113280,1.010900,0.897520 2024,0.452001,1.954733,1.804559,0.330010,2.774692,1.121850,3.271640,1.202133,1.018694 2025,0.400253,1.720835,1.748320,0.311531,2.728033,1.053865,3.139995,1.072385,0.786553 2026,0.251434,1.490830,1.402841,0.199013,2.304525,0.872166,2.062922,0.829442,0.687765 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_reference.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_reference.csv index 1f7f0bd..666e7c3 100644 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_reference.csv +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_reference.csv @@ -7,12 +7,12 @@ year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlant 2015,0.397610,1.236450,0.713310,0.147160,2.330100,0.875420,2.434110,0.750920,1.084430 2016,0.393180,1.344500,0.912140,0.191920,2.469830,0.961900,2.351840,0.765760,0.917910 2017,0.371410,1.196160,0.810260,0.172190,2.475890,0.910900,2.063170,0.690330,0.840900 -2018,0.400407,1.300064,1.002570,0.189613,2.535531,0.994602,2.661307,0.760259,0.871735 -2019,0.338651,1.451554,1.185716,0.228314,2.790259,1.029824,2.928261,0.988215,0.834003 -2020,0.360853,1.684218,1.262778,0.247312,2.768037,1.047204,2.940385,0.954761,0.847681 -2021,0.344592,1.654776,1.082247,0.195056,2.468727,0.913914,2.732240,0.947247,0.887034 -2022,0.366773,1.998293,1.477695,0.257507,2.605338,0.900480,2.797009,0.947744,0.850175 -2023,0.382071,1.783250,1.337029,0.261854,2.930798,1.108780,3.113280,1.010901,0.897525 +2018,0.400410,1.300060,1.002570,0.189610,2.535530,0.994600,2.661310,0.760260,0.871740 +2019,0.338650,1.451550,1.185720,0.228310,2.790260,1.029820,2.928260,0.988210,0.834000 +2020,0.360850,1.684220,1.262780,0.247310,2.768040,1.047200,2.940390,0.954760,0.847680 +2021,0.344590,1.654780,1.082250,0.195060,2.468730,0.913910,2.732240,0.947250,0.887030 +2022,0.366770,1.998290,1.477690,0.257510,2.605340,0.900480,2.797010,0.947740,0.850180 +2023,0.382070,1.783250,1.337030,0.261850,2.930800,1.108780,3.113280,1.010900,0.897520 2024,0.451624,1.947869,1.803768,0.328229,2.771119,1.120752,3.278091,1.202134,1.026979 2025,0.402601,1.629397,1.779150,0.333078,2.839481,1.098819,3.062861,1.095031,0.855043 2026,0.307184,1.645651,1.709301,0.292994,2.802256,1.090066,2.831672,1.009045,0.751345 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_HOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_HOG.csv index c50b4aa..a87d2f3 100644 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_HOG.csv +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_HOG.csv @@ -1,18 +1,18 @@ year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,0.858180,2.642740,3.358270,1.549812,2.864664,1.354117,5.379282,4.756302,2.707125 -2011,0.915348,2.719853,3.525401,1.555518,2.934925,1.416257,5.529355,4.793510,2.548560 -2012,0.879083,2.770951,3.547677,1.491081,3.280124,1.540446,5.730931,4.903691,2.803605 -2013,0.859505,2.891799,3.818099,1.645916,3.261053,1.455897,5.577358,4.972179,2.896845 -2014,0.857731,3.120449,4.045156,1.680470,3.326574,1.544663,5.646739,5.000559,2.784841 -2015,0.905922,3.099138,3.886718,1.574979,3.663951,1.696394,5.951674,5.255469,2.763970 -2016,0.856641,3.156144,3.920965,1.638642,3.735140,1.746690,5.803449,1.581652,2.775395 -2017,0.879541,3.113560,3.997107,1.729600,3.888779,1.767733,5.922212,1.576464,2.827698 -2018,0.930977,3.316355,4.395236,1.846236,4.067651,1.912479,6.697608,1.676031,2.952353 -2019,0.884965,3.507681,4.665439,1.972424,4.325762,1.962087,7.134515,1.985243,2.949311 -2020,0.849804,3.615312,4.578500,1.915619,4.221534,1.967894,7.066121,1.900725,2.847719 -2021,0.878472,3.665614,4.418462,1.893204,3.971677,1.844552,6.865973,1.921409,2.947445 -2022,0.923152,4.044715,4.940085,1.998683,4.159855,1.892741,7.156394,1.914708,2.857152 -2023,0.914369,3.709178,4.648726,1.877739,4.158048,1.861391,6.910273,1.734919,2.869450 +2010,0.858180,2.642740,3.358270,1.549810,2.864660,1.354120,5.379280,4.756300,2.707130 +2011,0.915350,2.719850,3.525400,1.555520,2.934920,1.416260,5.529350,4.793510,2.548560 +2012,0.879080,2.770950,3.547680,1.491080,3.280120,1.540450,5.730930,4.903690,2.803610 +2013,0.859500,2.891800,3.818100,1.645920,3.261050,1.455900,5.577360,4.972180,2.896840 +2014,0.857730,3.120450,4.045160,1.680470,3.326570,1.544660,5.646740,5.000560,2.784840 +2015,0.905920,3.099140,3.886720,1.574980,3.663950,1.696390,5.951670,5.255470,2.763970 +2016,0.856640,3.156140,3.920960,1.638640,3.735140,1.746690,5.803450,1.581650,2.775400 +2017,0.879540,3.113560,3.997110,1.729600,3.888780,1.767730,5.922210,1.576460,2.827700 +2018,0.930980,3.316360,4.395240,1.846240,4.067650,1.912480,6.697610,1.676030,2.952350 +2019,0.884970,3.507680,4.665440,1.972420,4.325760,1.962090,7.134520,1.985240,2.949310 +2020,0.849800,3.615310,4.578500,1.915620,4.221530,1.967890,7.066120,1.900720,2.847720 +2021,0.878470,3.665610,4.418460,1.893200,3.971680,1.844550,6.865970,1.921410,2.947450 +2022,0.923150,4.044720,4.940080,1.998680,4.159860,1.892740,7.156390,1.914710,2.857150 +2023,0.914370,3.709180,4.648730,1.877740,4.158050,1.861390,6.910270,1.734920,2.869450 2024,0.957036,3.906965,4.966578,2.048244,4.376607,2.097415,7.426676,2.155910,2.973608 2025,0.937966,3.654048,5.179120,2.077749,4.469378,2.111273,7.503117,2.100823,2.843258 2026,0.860033,3.759808,5.488719,2.125013,4.646142,2.230853,7.636079,2.131084,2.739021 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_LOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_LOG.csv index 3ac2e3a..43ad1c0 100644 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_LOG.csv +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_LOG.csv @@ -1,18 +1,18 @@ year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,0.858180,2.642740,3.358270,1.549812,2.864664,1.354117,5.379282,4.756302,2.707125 -2011,0.915348,2.719853,3.525401,1.555518,2.934925,1.416257,5.529355,4.793510,2.548560 -2012,0.879083,2.770951,3.547677,1.491081,3.280124,1.540446,5.730931,4.903691,2.803605 -2013,0.859505,2.891799,3.818099,1.645916,3.261053,1.455897,5.577358,4.972179,2.896845 -2014,0.857731,3.120449,4.045156,1.680470,3.326574,1.544663,5.646739,5.000559,2.784841 -2015,0.905922,3.099138,3.886718,1.574979,3.663951,1.696394,5.951674,5.255469,2.763970 -2016,0.856641,3.156144,3.920965,1.638642,3.735140,1.746690,5.803449,1.581652,2.775395 -2017,0.879541,3.113560,3.997107,1.729600,3.888779,1.767733,5.922212,1.576464,2.827698 -2018,0.930977,3.316355,4.395236,1.846236,4.067651,1.912479,6.697608,1.676031,2.952353 -2019,0.884965,3.507681,4.665439,1.972424,4.325762,1.962087,7.134515,1.985243,2.949311 -2020,0.849804,3.615312,4.578500,1.915619,4.221534,1.967894,7.066121,1.900725,2.847719 -2021,0.878472,3.665614,4.418462,1.893204,3.971677,1.844552,6.865973,1.921409,2.947445 -2022,0.923152,4.044715,4.940085,1.998683,4.159855,1.892741,7.156394,1.914708,2.857152 -2023,0.914369,3.709178,4.648726,1.877739,4.158048,1.861391,6.910273,1.734919,2.869450 +2010,0.858180,2.642740,3.358270,1.549810,2.864660,1.354120,5.379280,4.756300,2.707130 +2011,0.915350,2.719850,3.525400,1.555520,2.934920,1.416260,5.529350,4.793510,2.548560 +2012,0.879080,2.770950,3.547680,1.491080,3.280120,1.540450,5.730930,4.903690,2.803610 +2013,0.859500,2.891800,3.818100,1.645920,3.261050,1.455900,5.577360,4.972180,2.896840 +2014,0.857730,3.120450,4.045160,1.680470,3.326570,1.544660,5.646740,5.000560,2.784840 +2015,0.905920,3.099140,3.886720,1.574980,3.663950,1.696390,5.951670,5.255470,2.763970 +2016,0.856640,3.156140,3.920960,1.638640,3.735140,1.746690,5.803450,1.581650,2.775400 +2017,0.879540,3.113560,3.997110,1.729600,3.888780,1.767730,5.922210,1.576460,2.827700 +2018,0.930980,3.316360,4.395240,1.846240,4.067650,1.912480,6.697610,1.676030,2.952350 +2019,0.884970,3.507680,4.665440,1.972420,4.325760,1.962090,7.134520,1.985240,2.949310 +2020,0.849800,3.615310,4.578500,1.915620,4.221530,1.967890,7.066120,1.900720,2.847720 +2021,0.878470,3.665610,4.418460,1.893200,3.971680,1.844550,6.865970,1.921410,2.947450 +2022,0.923150,4.044720,4.940080,1.998680,4.159860,1.892740,7.156390,1.914710,2.857150 +2023,0.914370,3.709180,4.648730,1.877740,4.158050,1.861390,6.910270,1.734920,2.869450 2024,0.962553,3.909995,4.964130,2.049968,4.378995,2.098575,7.414999,2.159559,2.974449 2025,0.930546,3.749795,5.087374,2.005418,4.343349,2.031063,7.370770,2.058202,2.728772 2026,0.781939,3.475330,4.620926,1.842845,3.891988,1.784934,5.958117,1.781902,2.557914 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_reference.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_reference.csv index da86224..d2d82e3 100644 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_reference.csv +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_reference.csv @@ -1,18 +1,18 @@ year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,0.858180,2.642740,3.358270,1.549812,2.864664,1.354117,5.379282,4.756302,2.707125 -2011,0.915348,2.719853,3.525401,1.555518,2.934925,1.416257,5.529355,4.793510,2.548560 -2012,0.879083,2.770951,3.547677,1.491081,3.280124,1.540446,5.730931,4.903691,2.803605 -2013,0.859505,2.891799,3.818099,1.645916,3.261053,1.455897,5.577358,4.972179,2.896845 -2014,0.857731,3.120449,4.045156,1.680470,3.326574,1.544663,5.646739,5.000559,2.784841 -2015,0.905922,3.099138,3.886718,1.574979,3.663951,1.696394,5.951674,5.255469,2.763970 -2016,0.856641,3.156144,3.920965,1.638642,3.735140,1.746690,5.803449,1.581652,2.775395 -2017,0.879541,3.113560,3.997107,1.729600,3.888779,1.767733,5.922212,1.576464,2.827698 -2018,0.930977,3.316355,4.395236,1.846236,4.067651,1.912479,6.697608,1.676031,2.952353 -2019,0.884965,3.507681,4.665439,1.972424,4.325762,1.962087,7.134515,1.985243,2.949311 -2020,0.849804,3.615312,4.578500,1.915619,4.221534,1.967894,7.066121,1.900725,2.847719 -2021,0.878472,3.665614,4.418462,1.893204,3.971677,1.844552,6.865973,1.921409,2.947445 -2022,0.923152,4.044715,4.940085,1.998683,4.159855,1.892741,7.156394,1.914708,2.857152 -2023,0.914369,3.709178,4.648726,1.877739,4.158048,1.861391,6.910273,1.734919,2.869450 +2010,0.858180,2.642740,3.358270,1.549810,2.864660,1.354120,5.379280,4.756300,2.707130 +2011,0.915350,2.719850,3.525400,1.555520,2.934920,1.416260,5.529350,4.793510,2.548560 +2012,0.879080,2.770950,3.547680,1.491080,3.280120,1.540450,5.730930,4.903690,2.803610 +2013,0.859500,2.891800,3.818100,1.645920,3.261050,1.455900,5.577360,4.972180,2.896840 +2014,0.857730,3.120450,4.045160,1.680470,3.326570,1.544660,5.646740,5.000560,2.784840 +2015,0.905920,3.099140,3.886720,1.574980,3.663950,1.696390,5.951670,5.255470,2.763970 +2016,0.856640,3.156140,3.920960,1.638640,3.735140,1.746690,5.803450,1.581650,2.775400 +2017,0.879540,3.113560,3.997110,1.729600,3.888780,1.767730,5.922210,1.576460,2.827700 +2018,0.930980,3.316360,4.395240,1.846240,4.067650,1.912480,6.697610,1.676030,2.952350 +2019,0.884970,3.507680,4.665440,1.972420,4.325760,1.962090,7.134520,1.985240,2.949310 +2020,0.849800,3.615310,4.578500,1.915620,4.221530,1.967890,7.066120,1.900720,2.847720 +2021,0.878470,3.665610,4.418460,1.893200,3.971680,1.844550,6.865970,1.921410,2.947450 +2022,0.923150,4.044720,4.940080,1.998680,4.159860,1.892740,7.156390,1.914710,2.857150 +2023,0.914370,3.709180,4.648730,1.877740,4.158050,1.861390,6.910270,1.734920,2.869450 2024,0.962173,3.903117,4.963340,2.048189,4.375371,2.097466,7.421416,2.159530,2.982530 2025,0.935287,3.661196,5.156418,2.129834,4.476222,2.089903,7.237640,2.086673,2.807245 2026,0.848885,3.692177,5.073037,2.030126,4.465045,2.052864,6.971332,1.988881,2.694449 From 5851f3c115bb6e329f9e52216718861424d168e6 Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Thu, 23 Apr 2026 15:54:14 -0600 Subject: [PATCH 08/14] Don't push outputs and intermediate csv files to Github --- .../natural_gas_price_regression/.gitignore | 17 +++++++++-------- .../outputs of alpha regression/README.md | 13 +++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/README.md diff --git a/aeo_updates/natural_gas_price_regression/.gitignore b/aeo_updates/natural_gas_price_regression/.gitignore index 9b648df..b7356a8 100644 --- a/aeo_updates/natural_gas_price_regression/.gitignore +++ b/aeo_updates/natural_gas_price_regression/.gitignore @@ -9,19 +9,20 @@ __pycache__/ # Validation and visualization results (all generated output) results validation/ -# Raw API data dumps (reproducible from EIA API) +# Alpha regression outputs (all CSVs are generated, reproducible) +outputs of alpha regression/*.csv outputs of alpha regression/raw_aeo_data/ -outputs of beta regression/raw_aeo_data/ -# Beta raw data visualization subfolder +# Beta regression outputs (all generated, reproducible) +outputs of beta regression/*.csv +outputs of beta regression/raw_aeo_data/ outputs of beta regression/bata raw data visualization/ - -# Beta regression intermediate outputs (keep cd_beta0.csv, national_beta.csv, beta_regression_summary.csv) -outputs of beta regression/regression_points.csv -outputs of beta regression/alpha_from_beta_by_scenario.csv -outputs of beta regression/alpha_from_beta_regression.csv outputs of beta regression/alpha from beta regression/ +# Intermediate beta inputs (copied by sync_beta_to_alpha_inputs.py, not source data) +inputs for alpha regression/cd_beta0.csv +inputs for alpha regression/national_beta.csv + # Notebook checkpoints .ipynb_checkpoints/ diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/README.md b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/README.md new file mode 100644 index 0000000..64cb5a1 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/README.md @@ -0,0 +1,13 @@ +# Outputs of Alpha Regression + +This directory contains the **final outputs** of the natural gas price regression pipeline. + +## Copying outputs to ReEDS + +Copy **all CSV files except `national_beta.csv`** to: + +``` +ReEDS/inputs/fuelprices/ +``` + +For `national_beta.csv`, copy its value into `ReEDS/inputs/scalars.csv` under the key **`nat_beta_nonenergy`**. From 41eb99085cd67e578db7ac8018eddf0e6f95b590 Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Thu, 23 Apr 2026 16:05:10 -0600 Subject: [PATCH 09/14] Use python to kick off the pipeline rather than the batch file (to facilitate Mac and Linux user) --- .../natural_gas_price_regression/README.md | 10 ++-- .../run_ng_pipeline.bat | 39 --------------- .../run_ng_pipeline.py | 48 +++++++++++++++++++ 3 files changed, 53 insertions(+), 44 deletions(-) delete mode 100644 aeo_updates/natural_gas_price_regression/run_ng_pipeline.bat create mode 100644 aeo_updates/natural_gas_price_regression/run_ng_pipeline.py diff --git a/aeo_updates/natural_gas_price_regression/README.md b/aeo_updates/natural_gas_price_regression/README.md index 5522342..374d88e 100644 --- a/aeo_updates/natural_gas_price_regression/README.md +++ b/aeo_updates/natural_gas_price_regression/README.md @@ -78,14 +78,14 @@ Set explicit scenarios in `aeo_pipeline_config.json` under `scenarios`: Use canonical IDs (for example `ref{aeo_year}`, `highogs`, `lowogs`) for a clear setup. -## One-command batch (Windows) +## One-command run (all platforms) -```bat -run_ng_pipeline.bat +```bash +python run_ng_pipeline.py ``` Optional custom config: -```bat -run_ng_pipeline.bat my_config.json +```bash +python run_ng_pipeline.py --config my_config.json ``` diff --git a/aeo_updates/natural_gas_price_regression/run_ng_pipeline.bat b/aeo_updates/natural_gas_price_regression/run_ng_pipeline.bat deleted file mode 100644 index 3413f4e..0000000 --- a/aeo_updates/natural_gas_price_regression/run_ng_pipeline.bat +++ /dev/null @@ -1,39 +0,0 @@ -@echo off -setlocal - -cd /d "%~dp0" - -set "CONFIG=%~1" -if "%CONFIG%"=="" set "CONFIG=aeo_pipeline_config.json" - -python --version >nul 2>&1 -if errorlevel 1 ( - echo ERROR: Python is not available on PATH. - exit /b 9009 -) - -echo [1/4] Running beta regression... -python aeo_beta_regression.py --config "%CONFIG%" -if errorlevel 1 goto :fail - -echo [2/4] Syncing beta outputs to alpha inputs... -python sync_beta_to_alpha_inputs.py --config "%CONFIG%" -if errorlevel 1 goto :fail - -echo [3/4] Running alpha regression... -python aeo_alpha_regression.py --config "%CONFIG%" -if errorlevel 1 goto :fail - -echo [4/4] Generating visualization and validation... -python visualization.py --config "%CONFIG%" -if errorlevel 1 goto :fail - -echo. -echo NG pipeline finished successfully. -exit /b 0 - -:fail -set "CODE=%errorlevel%" -echo. -echo NG pipeline failed with exit code %CODE%. -exit /b %CODE% diff --git a/aeo_updates/natural_gas_price_regression/run_ng_pipeline.py b/aeo_updates/natural_gas_price_regression/run_ng_pipeline.py new file mode 100644 index 0000000..0e163d9 --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/run_ng_pipeline.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +""" +Cross-platform runner for the natural gas price regression pipeline. + +Usage: + python run_ng_pipeline.py [--config CONFIG_FILE] + +Replaces run_ng_pipeline.bat for compatibility with macOS / Linux. +""" + +import argparse +import subprocess +import sys +from pathlib import Path + + +STEPS = [ + ("1/4", "Running beta regression...", "aeo_beta_regression.py"), + ("2/4", "Syncing beta outputs to alpha inputs...", "sync_beta_to_alpha_inputs.py"), + ("3/4", "Running alpha regression...", "aeo_alpha_regression.py"), + ("4/4", "Generating visualization and validation...", "visualization.py"), +] + + +def main() -> int: + parser = argparse.ArgumentParser(description="Run the NG price regression pipeline.") + parser.add_argument("--config", default="aeo_pipeline_config.json", + help="Path to the pipeline config JSON (default: aeo_pipeline_config.json)") + args = parser.parse_args() + + script_dir = Path(__file__).resolve().parent + + for tag, msg, script in STEPS: + print(f"[{tag}] {msg}") + result = subprocess.run( + [sys.executable, script, "--config", args.config], + cwd=script_dir, + ) + if result.returncode != 0: + print(f"\nNG pipeline failed at step {tag} with exit code {result.returncode}.") + return result.returncode + + print("\nNG pipeline finished successfully.") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From dfc9c7d6209c097531c7644ab551921724ff401d Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Thu, 23 Apr 2026 16:18:24 -0600 Subject: [PATCH 10/14] Clean up --- .../natural_gas_price_regression/aeo_alpha_regression.py | 8 ++++++-- .../natural_gas_price_regression/aeo_pipeline_config.json | 3 +-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py b/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py index a21a6b0..e0a19b7 100644 --- a/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py +++ b/aeo_updates/natural_gas_price_regression/aeo_alpha_regression.py @@ -1157,9 +1157,13 @@ def run_ng_pipeline(config: dict[str, Any], base_dir: Path) -> None: # ---- Step 6: Compute alpha values ---- LOGGER.info("Step 6: Computing NG alpha values...") - beta_path = resolve_path(base_dir, ng_cfg["regional_beta_path"]) + input_dir = resolve_path( + base_dir, + config["paths"].get("input_dir", config["paths"]["output_dir"]), + ) + beta_path = resolve_case_insensitive(input_dir / "cd_beta0.csv") beta_regional = load_regional_betas(beta_path, region_order) - national_beta_path = resolve_case_insensitive(beta_path.parent / "national_beta.csv") + national_beta_path = resolve_case_insensitive(input_dir / "national_beta.csv") require( national_beta_path.exists(), f"National beta file not found: {national_beta_path}", diff --git a/aeo_updates/natural_gas_price_regression/aeo_pipeline_config.json b/aeo_updates/natural_gas_price_regression/aeo_pipeline_config.json index 45191e8..a1134bd 100644 --- a/aeo_updates/natural_gas_price_regression/aeo_pipeline_config.json +++ b/aeo_updates/natural_gas_price_regression/aeo_pipeline_config.json @@ -66,7 +66,6 @@ "Mountain", "Pacific" ], - "price_deflator_to_2004": 0.602782, - "regional_beta_path": "inputs for alpha regression/cd_beta0.csv" + "price_deflator_to_2004": 0.602782 } } From 8fddf96b622a6c3fad0643a1b4612332cb7224ad Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Thu, 23 Apr 2026 16:31:01 -0600 Subject: [PATCH 11/14] Remove csv files --- .../inputs for alpha regression/cd_beta0.csv | 10 ----- .../national_beta.csv | 2 - .../alpha_AEO_2025_HOG.csv | 42 ------------------- .../alpha_AEO_2025_LOG.csv | 42 ------------------- .../alpha_AEO_2025_reference.csv | 42 ------------------- .../outputs of alpha regression/cd_beta0.csv | 10 ----- .../national_beta.csv | 2 - .../ng_AEO_2025_HOG.csv | 42 ------------------- .../ng_AEO_2025_LOG.csv | 42 ------------------- .../ng_AEO_2025_reference.csv | 42 ------------------- .../ng_demand_AEO_2025_HOG.csv | 42 ------------------- .../ng_demand_AEO_2025_LOG.csv | 42 ------------------- .../ng_demand_AEO_2025_reference.csv | 42 ------------------- .../ng_tot_demand_AEO_2025_HOG.csv | 42 ------------------- .../ng_tot_demand_AEO_2025_LOG.csv | 42 ------------------- .../ng_tot_demand_AEO_2025_reference.csv | 42 ------------------- .../beta_regression_summary.csv | 11 ----- .../outputs of beta regression/cd_beta0.csv | 10 ----- .../national_beta.csv | 2 - 19 files changed, 551 deletions(-) delete mode 100644 aeo_updates/natural_gas_price_regression/inputs for alpha regression/cd_beta0.csv delete mode 100644 aeo_updates/natural_gas_price_regression/inputs for alpha regression/national_beta.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_HOG.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_LOG.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_reference.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/national_beta.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_HOG.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_LOG.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_reference.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_HOG.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_LOG.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_reference.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_HOG.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_LOG.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_reference.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of beta regression/beta_regression_summary.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of beta regression/cd_beta0.csv delete mode 100644 aeo_updates/natural_gas_price_regression/outputs of beta regression/national_beta.csv diff --git a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/cd_beta0.csv b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/cd_beta0.csv deleted file mode 100644 index 946cf33..0000000 --- a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/cd_beta0.csv +++ /dev/null @@ -1,10 +0,0 @@ -*cendiv,value -New_England,3.875323 -Mid_Atlantic,0.151497 -East_North_Central,0.033492 -West_North_Central,0.856915 -South_Atlantic,0.175498 -East_South_Central,0.139571 -West_South_Central,-0.054900 -Mountain,0.670353 -Pacific,1.341567 diff --git a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/national_beta.csv b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/national_beta.csv deleted file mode 100644 index abd889b..0000000 --- a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/national_beta.csv +++ /dev/null @@ -1,2 +0,0 @@ -beta -0.080017 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_HOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_HOG.csv deleted file mode 100644 index 1147d3d..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_HOG.csv +++ /dev/null @@ -1,42 +0,0 @@ -t,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,4.683875,4.711561,4.274321,4.662091,5.211406,4.137875,3.986710,4.348849,4.172505 -2011,1.816976,3.561499,3.232510,3.611184,3.674277,2.927834,3.128780,3.072886,2.283109 -2012,0.608251,2.046154,1.835805,2.023828,2.358643,1.657892,1.846135,1.711281,0.855820 -2013,2.752755,2.919933,2.717594,2.958827,2.911481,2.513758,2.646791,2.527450,1.493476 -2014,3.290931,3.226643,3.473377,3.696555,3.347307,2.970544,3.142849,2.832534,1.899157 -2015,1.075644,1.335855,1.425834,1.745417,1.933619,1.389863,1.571988,1.280899,0.350386 -2016,0.754709,1.178246,1.317182,1.120631,1.462783,1.059534,1.171322,0.798265,0.154124 -2017,1.026074,1.563513,1.772829,1.783923,1.739925,1.557646,1.649825,1.303398,0.634368 -2018,1.135924,1.494355,1.570148,1.592755,1.526521,1.430502,1.569901,1.231903,0.575436 -2019,1.046551,0.989434,0.871148,0.883068,1.038924,0.898527,0.937050,0.538674,0.198684 -2020,0.582678,0.537067,0.455373,0.539248,0.676152,0.555079,0.622535,0.269587,-0.114265 -2021,2.557165,2.060217,2.207225,2.345259,2.666629,2.555236,2.531617,2.261829,1.958033 -2022,2.984546,2.443258,3.035049,3.401063,3.716462,3.666597,3.614057,3.100001,2.729747 -2023,0.616932,0.568648,0.482152,0.570962,0.715908,0.587715,0.659140,0.285439,-0.120976 -2024,-0.468010,-0.031321,0.210737,0.184579,0.497425,0.345082,0.398380,-0.191626,-0.546024 -2025,-0.454252,0.112763,0.344876,0.320929,0.499549,0.410939,0.468171,-0.100039,-0.445625 -2026,-0.252073,0.019707,0.197131,0.206801,0.316351,0.224597,0.318176,-0.232231,-0.439900 -2027,-0.258877,-0.033279,0.157925,0.160226,0.353443,0.175124,0.277408,-0.229435,-0.439578 -2028,-0.289135,-0.037449,0.207416,0.252221,0.437009,0.262914,0.367318,-0.125625,-0.368992 -2029,-0.322310,-0.032144,0.242622,0.276503,0.477042,0.314815,0.415802,-0.066422,-0.365759 -2030,-0.251269,-0.033219,0.269754,0.334502,0.533248,0.378667,0.493271,0.001634,-0.312151 -2031,-0.182167,-0.023406,0.268865,0.299335,0.481149,0.424748,0.550534,0.069528,-0.296495 -2032,-0.176144,-0.010662,0.332092,0.340568,0.630270,0.490504,0.644607,0.153234,-0.183365 -2033,-0.082352,0.064029,0.371831,0.450130,0.590180,0.539430,0.707330,0.282865,-0.174894 -2034,-0.011003,0.122283,0.403914,0.500722,0.619309,0.565403,0.733782,0.370414,-0.123494 -2035,0.056341,0.171979,0.439723,0.566309,0.668940,0.607326,0.777152,0.464788,-0.103677 -2036,0.093461,0.217097,0.495611,0.691647,0.737113,0.667947,0.818150,0.464172,0.082731 -2037,0.092945,0.236787,0.497352,0.689038,0.757634,0.683358,0.805579,0.502848,0.041974 -2038,0.198916,0.280015,0.536568,0.770227,0.813723,0.734539,0.833305,0.692031,0.112107 -2039,0.222122,0.334648,0.576221,0.812897,0.867698,0.788379,0.877299,0.836469,0.184849 -2040,0.164746,0.307851,0.575600,0.855858,0.862221,0.801046,0.902691,0.861927,0.224821 -2041,0.221233,0.307528,0.575753,0.895945,0.870508,0.810443,0.930069,0.924016,0.204696 -2042,0.198786,0.317525,0.557631,0.881745,0.867713,0.813421,0.943432,0.923621,0.243462 -2043,0.097936,0.235768,0.489477,0.812074,0.819954,0.749603,0.912820,0.831754,0.237156 -2044,0.027747,0.142980,0.424122,0.753046,0.782351,0.713009,0.886083,0.730459,0.171369 -2045,0.070819,0.076273,0.370421,0.713242,0.758601,0.681674,0.876443,0.676002,0.217207 -2046,0.043637,0.029397,0.349860,0.715050,0.743219,0.669778,0.883537,0.695452,0.199327 -2047,-0.012972,-0.008888,0.310455,0.696182,0.833784,0.649055,0.856814,0.660313,0.230160 -2048,-0.033075,-0.029444,0.296592,0.695373,0.847091,0.657421,0.868570,0.662000,0.294965 -2049,-0.062187,-0.064672,0.245406,0.700461,0.791758,0.617461,0.841883,0.593020,0.265435 -2050,-0.061527,-0.095693,0.225173,0.701374,0.756995,0.585727,0.823963,0.525706,0.281430 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_LOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_LOG.csv deleted file mode 100644 index e377651..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_LOG.csv +++ /dev/null @@ -1,42 +0,0 @@ -t,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,4.683875,4.711561,4.274321,4.662091,5.211406,4.137875,3.986710,4.348849,4.172505 -2011,1.816976,3.561499,3.232510,3.611184,3.674277,2.927834,3.128780,3.072886,2.283109 -2012,0.608251,2.046154,1.835805,2.023828,2.358643,1.657892,1.846135,1.711281,0.855820 -2013,2.752755,2.919933,2.717594,2.958827,2.911481,2.513758,2.646791,2.527450,1.493476 -2014,3.290931,3.226643,3.473377,3.696555,3.347307,2.970544,3.142849,2.832534,1.899157 -2015,1.075644,1.335855,1.425834,1.745417,1.933619,1.389863,1.571988,1.280899,0.350386 -2016,0.754709,1.178246,1.317182,1.120631,1.462783,1.059534,1.171322,0.798265,0.154124 -2017,1.026074,1.563513,1.772829,1.783923,1.739925,1.557646,1.649825,1.303398,0.634368 -2018,1.135924,1.494355,1.570148,1.592755,1.526521,1.430502,1.569901,1.231903,0.575436 -2019,1.046551,0.989434,0.871148,0.883068,1.038924,0.898527,0.937050,0.538674,0.198684 -2020,0.582678,0.537067,0.455373,0.539248,0.676152,0.555079,0.622535,0.269587,-0.114265 -2021,2.557165,2.060217,2.207225,2.345259,2.666629,2.555236,2.531617,2.261829,1.958033 -2022,2.984546,2.443258,3.035049,3.401063,3.716462,3.666597,3.614057,3.100001,2.729747 -2023,0.616932,0.568648,0.482152,0.570962,0.715908,0.587715,0.659140,0.285439,-0.120976 -2024,-0.484707,-0.029711,0.215051,0.187075,0.490094,0.339058,0.400083,-0.191824,-0.544057 -2025,0.320668,0.889994,1.169469,1.126793,1.370276,1.322634,1.365049,0.743120,0.468185 -2026,0.993648,1.277484,1.435401,1.432441,1.674898,1.591261,1.515472,1.117014,0.752048 -2027,0.980905,1.273043,1.502568,1.511037,1.757396,1.668365,1.596232,1.214643,0.838834 -2028,1.115336,1.426261,1.681291,1.729195,1.990057,1.917707,1.845684,1.497429,1.103785 -2029,1.380942,1.682775,1.977326,2.076482,2.297298,2.224647,2.187165,1.860526,1.387974 -2030,1.840662,2.120230,2.498073,2.597319,2.855960,2.814701,2.806373,2.476454,1.950263 -2031,2.351311,2.540952,2.922170,3.044480,3.339785,3.231337,3.234114,2.981482,2.424394 -2032,2.669670,2.992064,3.379454,3.481538,3.697091,3.625742,3.664041,3.420201,2.877220 -2033,3.059481,3.288055,3.661245,3.739282,3.982265,3.901682,3.892631,3.630120,3.098685 -2034,3.327007,3.470360,3.835762,3.868858,4.168600,4.056546,4.057258,3.855987,3.313662 -2035,3.407640,3.607970,3.940490,3.954335,4.302966,4.191552,4.110478,4.031437,3.491140 -2036,3.491305,3.658682,4.100178,4.105921,4.517574,4.374171,4.338926,4.314109,3.745742 -2037,3.563082,3.640128,4.073614,4.119122,4.676863,4.422630,4.451877,4.387943,3.863371 -2038,3.496389,3.579627,4.013947,4.087316,4.663879,4.282977,4.440391,4.456922,3.936299 -2039,3.442832,3.570535,3.965983,3.972211,4.789079,4.428681,4.607058,4.655245,4.161951 -2040,3.426911,3.551047,4.031987,4.088288,4.760876,4.429668,4.625246,4.705194,4.199913 -2041,3.355756,3.562317,4.022913,4.099254,4.802329,4.621356,4.622140,4.565469,4.239417 -2042,3.316872,3.460866,3.963444,4.055829,4.750108,4.518745,4.571450,4.480272,4.109517 -2043,3.212400,3.392686,3.895821,4.008246,4.675000,4.415660,4.488237,4.357078,4.036913 -2044,3.171646,3.403920,3.905402,4.001124,4.676325,4.547160,4.638910,4.514365,4.149064 -2045,3.150600,3.423385,3.930714,4.048498,4.583925,4.517120,4.686094,4.607649,4.239064 -2046,3.230419,3.472359,4.060075,4.183568,4.623913,4.547413,4.733054,4.655728,4.276129 -2047,3.330979,3.606305,4.195563,4.287413,4.773827,4.762990,4.918477,4.865448,4.463472 -2048,3.450908,3.740855,4.353308,4.443471,4.956059,4.887999,5.152434,5.097561,4.618085 -2049,3.627606,3.934228,4.524340,4.607130,5.109198,5.046874,5.350720,5.257141,4.741983 -2050,3.805277,4.124450,4.696611,4.764436,5.306124,5.230470,5.537398,5.452070,4.890810 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_reference.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_reference.csv deleted file mode 100644 index 8fb87b9..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/alpha_AEO_2025_reference.csv +++ /dev/null @@ -1,42 +0,0 @@ -t,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,4.683875,4.711561,4.274321,4.662091,5.211406,4.137875,3.986710,4.348849,4.172505 -2011,1.816976,3.561499,3.232510,3.611184,3.674277,2.927834,3.128780,3.072886,2.283109 -2012,0.608251,2.046154,1.835805,2.023828,2.358643,1.657892,1.846135,1.711281,0.855820 -2013,2.752755,2.919933,2.717594,2.958827,2.911481,2.513758,2.646791,2.527450,1.493476 -2014,3.290931,3.226643,3.473377,3.696555,3.347307,2.970544,3.142849,2.832534,1.899157 -2015,1.075644,1.335855,1.425834,1.745417,1.933619,1.389863,1.571988,1.280899,0.350386 -2016,0.754709,1.178246,1.317182,1.120631,1.462783,1.059534,1.171322,0.798265,0.154124 -2017,1.026074,1.563513,1.772829,1.783923,1.739925,1.557646,1.649825,1.303398,0.634368 -2018,1.135924,1.494355,1.570148,1.592755,1.526521,1.430502,1.569901,1.231903,0.575436 -2019,1.046551,0.989434,0.871148,0.883068,1.038924,0.898527,0.937050,0.538674,0.198684 -2020,0.582678,0.537067,0.455373,0.539248,0.676152,0.555079,0.622535,0.269587,-0.114265 -2021,2.557165,2.060217,2.207225,2.345259,2.666629,2.555236,2.531617,2.261829,1.958033 -2022,2.984546,2.443258,3.035049,3.401063,3.716462,3.666597,3.614057,3.100001,2.729747 -2023,0.616932,0.568648,0.482152,0.570962,0.715908,0.587715,0.659140,0.285439,-0.120976 -2024,-0.505133,-0.041746,0.202311,0.174344,0.557962,0.323449,0.391092,-0.207917,-0.576337 -2025,-0.229539,0.347671,0.602813,0.572750,0.772238,0.692976,0.749541,0.205100,-0.115501 -2026,0.116280,0.431180,0.613034,0.607796,0.782696,0.694058,0.728853,0.230798,-0.054895 -2027,0.025300,0.312819,0.540627,0.519140,0.799770,0.615471,0.672565,0.178473,-0.086562 -2028,-0.005586,0.295013,0.581150,0.597140,0.796321,0.707458,0.769714,0.304707,-0.041584 -2029,0.067221,0.342341,0.669987,0.689225,1.001846,0.822394,0.892482,0.459622,0.070685 -2030,0.201912,0.407551,0.746032,0.790169,1.023289,0.956262,1.043240,0.616757,0.206840 -2031,0.270865,0.511255,0.851821,0.911957,1.103114,1.056561,1.155028,0.763157,0.321341 -2032,0.383170,0.615433,1.019251,1.080553,1.263653,1.236409,1.392116,1.014594,0.526482 -2033,0.667851,0.857661,1.250259,1.359765,1.550552,1.509990,1.683922,1.402480,0.878486 -2034,0.851366,1.009215,1.397943,1.597190,1.725658,1.689997,1.869690,1.640171,1.045899 -2035,0.910406,1.079863,1.492374,1.688441,1.819346,1.788715,1.911618,1.722907,1.135310 -2036,0.978942,1.117161,1.541326,1.757318,1.874950,1.811399,1.912304,1.746874,1.165524 -2037,0.991961,1.155582,1.536159,1.773991,1.942654,1.834123,1.941018,1.796241,1.212068 -2038,0.941332,1.140687,1.487182,1.777185,1.946024,1.834754,1.955180,1.836029,1.255656 -2039,0.903317,1.106120,1.483093,1.738510,1.942899,1.813399,1.955097,1.852664,1.292380 -2040,0.902075,1.076208,1.465823,1.783399,1.951433,1.816640,1.997464,1.929209,1.386383 -2041,0.940136,1.079738,1.485430,1.852105,1.952438,1.837854,2.062283,2.034826,1.503686 -2042,0.974734,1.120315,1.518709,1.936311,1.987258,1.858898,2.136794,2.110740,1.655205 -2043,1.000147,1.132037,1.529437,1.962805,2.038861,1.936040,2.223861,2.199057,1.697789 -2044,1.041327,1.123951,1.519776,1.987807,2.050695,1.964234,2.287435,2.219031,1.774132 -2045,1.086377,1.099421,1.520266,1.967755,2.027370,1.974527,2.312392,2.234710,1.797817 -2046,1.034779,1.143505,1.528193,2.025646,2.053118,2.019305,2.355159,2.302125,1.933259 -2047,1.059170,1.127624,1.514791,1.996091,2.015636,2.018503,2.409184,2.347354,1.939243 -2048,0.948902,1.098686,1.495751,1.948797,1.953655,1.965800,2.405515,2.275422,1.943456 -2049,0.957797,1.069420,1.466790,1.903059,1.896208,1.856363,2.375852,2.194083,1.949716 -2050,0.950400,1.008986,1.448063,1.910854,1.828244,1.769984,2.347436,2.211597,1.936905 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0.csv deleted file mode 100644 index 946cf33..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/cd_beta0.csv +++ /dev/null @@ -1,10 +0,0 @@ -*cendiv,value -New_England,3.875323 -Mid_Atlantic,0.151497 -East_North_Central,0.033492 -West_North_Central,0.856915 -South_Atlantic,0.175498 -East_South_Central,0.139571 -West_South_Central,-0.054900 -Mountain,0.670353 -Pacific,1.341567 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/national_beta.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/national_beta.csv deleted file mode 100644 index abd889b..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/national_beta.csv +++ /dev/null @@ -1,2 +0,0 @@ -beta -0.080017 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_HOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_HOG.csv deleted file mode 100644 index cd617a2..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_HOG.csv +++ /dev/null @@ -1,42 +0,0 @@ -year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,7.770430,7.816360,7.090990,7.734290,8.645590,6.864630,6.613850,7.214630,6.922080 -2011,6.976610,7.181610,6.415240,7.187830,7.612680,6.035800,6.021930,6.759040,6.523090 -2012,5.125690,4.920950,4.318400,4.836970,5.744140,4.171340,4.086240,4.812690,4.981960 -2013,8.068120,6.221770,5.644570,6.217400,6.488060,5.425660,5.311730,6.026710,5.966590 -2014,8.769200,6.749790,6.901570,7.398620,7.217680,6.196130,6.141910,6.533250,6.652870 -2015,5.664140,3.850320,3.728470,4.428220,5.209640,3.831860,3.709610,4.283490,4.318230 -2016,5.148300,3.661070,3.604330,3.500410,4.514280,3.348940,3.097470,3.544380,3.667090 -2017,5.355280,4.159690,4.251330,4.469500,4.872570,4.060240,3.814340,4.195250,4.189160 -2018,5.881250,4.228360,4.083060,4.334410,4.693190,4.025980,3.784560,4.311700,4.317320 -2019,5.476460,3.569320,3.074150,3.352610,4.098980,3.292140,2.850900,3.555690,3.748840 -2020,4.894560,2.922260,2.433600,2.854160,3.535610,2.771320,2.372950,3.117010,3.305040 -2021,7.947850,5.323930,5.212050,5.658210,6.632820,5.940870,5.441230,6.295940,6.712710 -2022,8.928910,6.175170,6.736810,7.627990,8.543690,7.910930,7.360520,7.816440,8.040400 -2023,5.182360,3.094090,2.576700,3.021990,3.743500,2.934270,2.512480,3.300290,3.499380 -2024,3.942886,2.287270,2.298708,2.621773,3.481087,2.680677,2.210615,2.863694,3.208913 -2025,3.545907,2.313296,2.394202,2.708847,3.371045,2.663157,2.218614,2.777358,2.887983 -2026,3.424357,2.298251,2.279395,2.664633,3.222955,2.498695,2.059296,2.712186,2.803907 -2027,3.179948,2.255369,2.267412,2.702573,3.352517,2.484879,2.033904,2.717369,2.824805 -2028,2.963628,2.219732,2.342423,2.822133,3.471617,2.607332,2.178029,2.860942,2.993797 -2029,2.897579,2.237025,2.422638,2.905383,3.536583,2.709477,2.279984,2.964342,3.117639 -2030,2.761189,2.309547,2.509715,3.080562,3.637365,2.835151,2.440423,3.228207,3.405689 -2031,2.747252,2.337410,2.525936,3.122771,3.510499,2.905147,2.544189,3.393098,3.586969 -2032,3.035183,2.531026,2.816504,3.501460,3.964278,3.177044,2.843096,3.814344,4.013958 -2033,3.119033,2.633990,2.860132,3.516799,3.848393,3.242102,2.926303,3.950235,4.208856 -2034,3.235024,2.714677,2.896689,3.576314,3.874689,3.271004,2.959214,4.049577,4.334771 -2035,3.332014,2.718911,2.911631,3.632553,3.886527,3.285653,2.990757,4.106940,4.363559 -2036,3.345162,2.679176,2.902459,3.651698,3.871522,3.277782,2.995825,4.154849,4.288165 -2037,3.331612,2.655793,2.849265,3.584962,3.826073,3.248419,2.955194,4.159271,4.251697 -2038,3.345557,2.610942,2.787631,3.559825,3.806650,3.233404,2.903788,4.197432,4.234464 -2039,3.217742,2.571926,2.754783,3.507277,3.787173,3.219203,2.895023,4.173839,4.281111 -2040,3.172366,2.542018,2.765788,3.599415,3.826042,3.249156,2.954316,4.291714,4.376058 -2041,3.339386,2.589555,2.809392,3.717389,3.902796,3.310269,3.031373,4.404143,4.470148 -2042,3.391913,2.603526,2.803964,3.731760,3.909537,3.326160,3.068110,4.446998,4.516488 -2043,3.330580,2.536290,2.752379,3.703559,3.898544,3.289931,3.063311,4.391260,4.504367 -2044,3.113896,2.437677,2.683260,3.646818,3.864220,3.263479,3.049417,4.328261,4.424861 -2045,2.985338,2.366950,2.627810,3.651798,3.847422,3.248250,3.060245,4.364906,4.511312 -2046,2.984034,2.338613,2.628173,3.720915,3.857837,3.277446,3.101784,4.417610,4.539052 -2047,2.934076,2.304000,2.562113,3.699291,4.006942,3.260696,3.061580,4.407011,4.557307 -2048,2.892148,2.251554,2.512380,3.689516,4.003499,3.256391,3.065140,4.434324,4.586201 -2049,2.865312,2.203854,2.461685,3.655248,3.966560,3.213834,3.041644,4.389663,4.565211 -2050,2.790408,2.150464,2.421813,3.591890,3.907777,3.162359,3.010422,4.376517,4.556719 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_LOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_LOG.csv deleted file mode 100644 index 4e7afb5..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_LOG.csv +++ /dev/null @@ -1,42 +0,0 @@ -year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,7.770430,7.816360,7.090990,7.734290,8.645590,6.864630,6.613850,7.214630,6.922080 -2011,6.976610,7.181610,6.415240,7.187830,7.612680,6.035800,6.021930,6.759040,6.523090 -2012,5.125690,4.920950,4.318400,4.836970,5.744140,4.171340,4.086240,4.812690,4.981960 -2013,8.068120,6.221770,5.644570,6.217400,6.488060,5.425660,5.311730,6.026710,5.966590 -2014,8.769200,6.749790,6.901570,7.398620,7.217680,6.196130,6.141910,6.533250,6.652870 -2015,5.664140,3.850320,3.728470,4.428220,5.209640,3.831860,3.709610,4.283490,4.318230 -2016,5.148300,3.661070,3.604330,3.500410,4.514280,3.348940,3.097470,3.544380,3.667090 -2017,5.355280,4.159690,4.251330,4.469500,4.872570,4.060240,3.814340,4.195250,4.189160 -2018,5.881250,4.228360,4.083060,4.334410,4.693190,4.025980,3.784560,4.311700,4.317320 -2019,5.476460,3.569320,3.074150,3.352610,4.098980,3.292140,2.850900,3.555690,3.748840 -2020,4.894560,2.922260,2.433600,2.854160,3.535610,2.771320,2.372950,3.117010,3.305040 -2021,7.947850,5.323930,5.212050,5.658210,6.632820,5.940870,5.441230,6.295940,6.712710 -2022,8.928910,6.175170,6.736810,7.627990,8.543690,7.910930,7.360520,7.816440,8.040400 -2023,5.182360,3.094090,2.576700,3.021990,3.743500,2.934270,2.512480,3.300290,3.499380 -2024,3.951021,2.291188,2.306225,2.628691,3.470091,2.671443,2.214949,2.867855,3.213850 -2025,4.825856,3.629599,3.757886,4.032818,4.788136,4.158859,3.699224,4.146041,4.247904 -2026,4.605783,3.834864,3.800100,4.000161,4.790429,4.182667,3.667104,4.116380,4.119196 -2027,4.343827,3.835330,3.930441,4.200141,4.924905,4.337811,3.808350,4.269623,4.225954 -2028,4.395217,4.009411,4.168205,4.513605,5.188810,4.686580,4.175693,4.650997,4.694008 -2029,4.783993,4.403663,4.620580,5.094242,5.605813,5.149542,4.716477,5.207363,5.210474 -2030,5.429995,5.116742,5.483608,6.184416,6.492614,6.110940,5.740700,6.219917,6.208527 -2031,6.023727,5.623803,6.032155,6.668324,7.070742,6.622880,6.323299,6.823698,6.887148 -2032,6.769484,6.455877,6.900975,7.624558,7.802534,7.392770,7.123114,7.823699,7.795189 -2033,7.239462,6.816369,7.243104,7.822190,8.118889,7.728008,7.409045,8.029579,8.010993 -2034,7.573184,7.007079,7.448060,7.872682,8.326830,7.892791,7.609113,8.258191,8.196181 -2035,7.670228,7.163031,7.551923,7.904687,8.486915,8.054188,7.651300,8.444173,8.278070 -2036,7.708939,7.137417,7.728963,8.052999,8.726404,8.253443,7.956063,8.753573,8.491802 -2037,7.558604,6.949639,7.568828,7.982419,8.848077,8.212115,8.047225,8.739521,8.407489 -2038,7.343988,6.762915,7.392748,7.834982,8.740216,7.899144,7.963167,8.673278,8.322899 -2039,7.251116,6.737899,7.297922,7.645207,8.910620,8.110153,8.226623,9.006240,8.591912 -2040,7.218706,6.678354,7.382362,7.822319,8.836534,8.071926,8.232173,9.026676,8.661890 -2041,7.065958,6.644736,7.322939,7.732145,8.862980,8.334088,8.189538,8.673353,8.644938 -2042,6.963392,6.447856,7.199334,7.611486,8.753935,8.141396,8.084666,8.462022,8.381509 -2043,6.808531,6.334739,7.084161,7.540718,8.612486,7.972393,7.942930,8.241702,8.252924 -2044,6.503371,6.344906,7.090244,7.552183,8.590377,8.179617,8.183352,8.507860,8.446995 -2045,6.349429,6.351938,7.115554,7.610549,8.392526,8.105153,8.243489,8.658021,8.574844 -2046,6.509525,6.429235,7.327775,7.833263,8.438897,8.147901,8.316871,8.684699,8.631374 -2047,6.689818,6.661896,7.564465,8.053114,8.687522,8.513703,8.630199,9.064015,8.964581 -2048,6.918985,6.915947,7.853740,8.339838,9.020991,8.746612,9.039744,9.510916,9.287422 -2049,7.237922,7.254817,8.156782,8.634782,9.287102,9.029250,9.384081,9.833487,9.528601 -2050,7.553951,7.582260,8.458136,8.921481,9.627280,9.348893,9.705161,10.207071,9.821965 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_reference.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_reference.csv deleted file mode 100644 index 09c83f6..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_AEO_2025_reference.csv +++ /dev/null @@ -1,42 +0,0 @@ -year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,7.770430,7.816360,7.090990,7.734290,8.645590,6.864630,6.613850,7.214630,6.922080 -2011,6.976610,7.181610,6.415240,7.187830,7.612680,6.035800,6.021930,6.759040,6.523090 -2012,5.125690,4.920950,4.318400,4.836970,5.744140,4.171340,4.086240,4.812690,4.981960 -2013,8.068120,6.221770,5.644570,6.217400,6.488060,5.425660,5.311730,6.026710,5.966590 -2014,8.769200,6.749790,6.901570,7.398620,7.217680,6.196130,6.141910,6.533250,6.652870 -2015,5.664140,3.850320,3.728470,4.428220,5.209640,3.831860,3.709610,4.283490,4.318230 -2016,5.148300,3.661070,3.604330,3.500410,4.514280,3.348940,3.097470,3.544380,3.667090 -2017,5.355280,4.159690,4.251330,4.469500,4.872570,4.060240,3.814340,4.195250,4.189160 -2018,5.881250,4.228360,4.083060,4.334410,4.693190,4.025980,3.784560,4.311700,4.317320 -2019,5.476460,3.569320,3.074150,3.352610,4.098980,3.292140,2.850900,3.555690,3.748840 -2020,4.894560,2.922260,2.433600,2.854160,3.535610,2.771320,2.372950,3.117010,3.305040 -2021,7.947850,5.323930,5.212050,5.658210,6.632820,5.940870,5.441230,6.295940,6.712710 -2022,8.928910,6.175170,6.736810,7.627990,8.543690,7.910930,7.360520,7.816440,8.040400 -2023,5.182360,3.094090,2.576700,3.021990,3.743500,2.934270,2.512480,3.300290,3.499380 -2024,3.914745,2.269530,2.285080,2.605072,3.581676,2.645327,2.199480,2.841191,3.178771 -2025,3.945919,2.724665,2.837277,3.162053,3.846201,3.142428,2.702884,3.296411,3.449765 -2026,3.819109,2.780215,2.763278,3.076137,3.765639,3.055122,2.602545,3.156343,3.232441 -2027,3.435360,2.636923,2.703812,3.054238,3.837702,2.988694,2.549224,3.122164,3.154894 -2028,3.240752,2.576812,2.762565,3.195382,3.785440,3.127218,2.701754,3.269873,3.344125 -2029,3.229812,2.643674,2.918250,3.398271,4.085795,3.306478,2.910596,3.513918,3.634970 -2030,3.129285,2.773706,3.049576,3.646155,4.087484,3.512392,3.163967,3.861304,4.019860 -2031,3.326129,2.866469,3.170081,3.762861,4.101537,3.613755,3.303848,4.079747,4.274564 -2032,3.779099,3.222987,3.635774,4.423059,4.559186,4.085257,3.843493,4.733683,4.891140 -2033,4.071227,3.483385,3.881344,4.704285,4.842482,4.388517,4.214373,5.040173,5.191451 -2034,4.168971,3.598001,3.987692,4.772688,4.962396,4.544195,4.409548,5.230925,5.384827 -2035,4.199443,3.631619,4.045470,4.784186,5.016607,4.609845,4.425838,5.303466,5.412060 -2036,4.265835,3.610814,4.036805,4.780307,5.044314,4.556694,4.374448,5.251937,5.282920 -2037,4.120316,3.518157,3.899876,4.672058,4.979167,4.464017,4.317363,5.176685,5.104523 -2038,3.993610,3.376865,3.733063,4.566430,4.909653,4.376263,4.273121,5.154803,5.010477 -2039,3.816716,3.256926,3.681409,4.408439,4.850672,4.286094,4.233821,5.160571,4.923649 -2040,3.872509,3.215503,3.662889,4.491251,4.854046,4.299133,4.305593,5.306404,5.055543 -2041,3.966687,3.252421,3.723782,4.649086,4.880734,4.361627,4.432408,5.505489,5.287903 -2042,4.091134,3.298153,3.773970,4.751801,4.925858,4.390012,4.548378,5.683669,5.408764 -2043,4.169929,3.344024,3.805754,4.807343,5.008918,4.522407,4.704851,5.836872,5.563621 -2044,4.087124,3.347215,3.800041,4.817755,5.012309,4.578125,4.813431,5.905303,5.645613 -2045,3.891919,3.329523,3.798050,4.839172,4.970164,4.596054,4.858135,5.945200,5.636967 -2046,3.902629,3.393556,3.810532,4.945189,4.994895,4.665256,4.923351,6.013248,5.758965 -2047,3.945969,3.383668,3.770669,4.909540,4.917217,4.652761,5.001916,6.069484,5.808951 -2048,3.787596,3.349662,3.740844,4.859097,4.802450,4.571362,5.000763,6.010077,5.813332 -2049,3.870886,3.274235,3.685088,4.774216,4.690213,4.388964,4.946911,5.912456,5.796697 -2050,3.788044,3.161351,3.642668,4.791852,4.578797,4.235358,4.904408,5.972120,5.745820 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_HOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_HOG.csv deleted file mode 100644 index d8a5763..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_HOG.csv +++ /dev/null @@ -1,42 +0,0 @@ -year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,0.420000,0.890000,0.326000,0.124000,1.544000,0.567000,2.049000,0.641000,0.989000 -2011,0.456000,0.965000,0.395000,0.117000,1.671000,0.639000,2.188000,0.567000,0.766000 -2012,0.448000,1.154000,0.656000,0.171000,2.043000,0.797000,2.337000,0.663000,1.045000 -2013,0.372000,1.066000,0.475000,0.140000,1.883000,0.629000,2.075000,0.651000,1.069000 -2014,0.341750,1.131480,0.482860,0.108070,1.896250,0.671910,2.025670,0.648910,1.073730 -2015,0.397610,1.236450,0.713310,0.147160,2.330100,0.875420,2.434110,0.750920,1.084430 -2016,0.393180,1.344500,0.912140,0.191920,2.469830,0.961900,2.351840,0.765760,0.917910 -2017,0.371410,1.196160,0.810260,0.172190,2.475890,0.910900,2.063170,0.690330,0.840900 -2018,0.400410,1.300060,1.002570,0.189610,2.535530,0.994600,2.661310,0.760260,0.871740 -2019,0.338650,1.451550,1.185720,0.228310,2.790260,1.029820,2.928260,0.988210,0.834000 -2020,0.360850,1.684220,1.262780,0.247310,2.768040,1.047200,2.940390,0.954760,0.847680 -2021,0.344590,1.654780,1.082250,0.195060,2.468730,0.913910,2.732240,0.947250,0.887030 -2022,0.366770,1.998290,1.477690,0.257510,2.605340,0.900480,2.797010,0.947740,0.850180 -2023,0.382070,1.783250,1.337030,0.261850,2.930800,1.108780,3.113280,1.010900,0.897520 -2024,0.446506,1.951789,1.807217,0.328414,2.772431,1.120767,3.282638,1.198553,1.018170 -2025,0.400232,1.590906,1.721987,0.316580,2.802444,1.101454,3.123186,1.094271,0.854088 -2026,0.311662,1.697816,2.042994,0.339554,2.951403,1.240576,3.375084,1.131739,0.761514 -2027,0.268560,1.701938,2.206338,0.389654,3.033981,1.345413,3.394222,1.092678,0.750901 -2028,0.244934,1.644293,2.334784,0.376410,3.015770,1.306726,3.293242,1.079716,0.780610 -2029,0.241361,1.630497,2.512054,0.398223,2.969723,1.324362,3.188257,1.073624,0.828471 -2030,0.196057,1.778863,2.602928,0.427727,2.868471,1.249770,3.244220,1.176084,0.901304 -2031,0.174589,1.787377,2.751464,0.491814,2.697150,1.181122,3.251625,1.214582,0.966842 -2032,0.193283,1.845946,3.253971,0.599109,2.864202,1.202948,3.415374,1.326644,1.003485 -2033,0.185470,1.848220,3.239930,0.497179,2.768513,1.226310,3.408022,1.274809,1.094409 -2034,0.187396,1.843454,3.205562,0.490385,2.743542,1.228781,3.366460,1.246807,1.119302 -2035,0.192078,1.710656,3.212188,0.484944,2.655394,1.185304,3.317858,1.197920,1.137609 -2036,0.199700,1.642419,3.132051,0.420684,2.550056,1.137773,2.939176,1.329532,1.008565 -2037,0.206521,1.644400,3.140409,0.416561,2.471244,1.144755,2.535467,1.326660,1.047966 -2038,0.197384,1.590891,2.716094,0.376668,2.439109,1.158549,2.472733,1.171483,1.034278 -2039,0.185696,1.437783,2.581804,0.354041,2.377795,1.105213,2.369297,1.016782,1.041979 -2040,0.191300,1.440836,2.550396,0.359027,2.495180,1.084304,2.332093,1.072407,1.048653 -2041,0.196422,1.471445,2.603838,0.366828,2.572892,1.106517,2.428086,1.044572,1.087787 -2042,0.208031,1.400841,2.774909,0.382864,2.560002,1.088461,2.434259,1.070091,1.072913 -2043,0.215927,1.453301,2.887747,0.405494,2.604740,1.150788,2.535568,1.107367,1.047360 -2044,0.195102,1.539554,2.989638,0.410800,2.585567,1.153446,2.570477,1.171576,1.045559 -2045,0.159384,1.580606,3.061960,0.439917,2.561460,1.184258,2.601221,1.259128,1.036926 -2046,0.161159,1.648451,3.099662,0.463651,2.573675,1.255747,2.629858,1.248391,1.048170 -2047,0.167061,1.739527,2.979110,0.466230,2.549114,1.305926,2.650514,1.285874,1.030689 -2048,0.168816,1.745558,2.855375,0.474269,2.529676,1.313169,2.607504,1.325776,1.004289 -2049,0.167950,1.680766,2.984837,0.425213,2.625262,1.298944,2.676126,1.364214,1.004726 -2050,0.156610,1.685399,2.927017,0.381755,2.632061,1.317363,2.658570,1.455590,0.990377 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_LOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_LOG.csv deleted file mode 100644 index ce2ed11..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_LOG.csv +++ /dev/null @@ -1,42 +0,0 @@ -year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,0.420000,0.890000,0.326000,0.124000,1.544000,0.567000,2.049000,0.641000,0.989000 -2011,0.456000,0.965000,0.395000,0.117000,1.671000,0.639000,2.188000,0.567000,0.766000 -2012,0.448000,1.154000,0.656000,0.171000,2.043000,0.797000,2.337000,0.663000,1.045000 -2013,0.372000,1.066000,0.475000,0.140000,1.883000,0.629000,2.075000,0.651000,1.069000 -2014,0.341750,1.131480,0.482860,0.108070,1.896250,0.671910,2.025670,0.648910,1.073730 -2015,0.397610,1.236450,0.713310,0.147160,2.330100,0.875420,2.434110,0.750920,1.084430 -2016,0.393180,1.344500,0.912140,0.191920,2.469830,0.961900,2.351840,0.765760,0.917910 -2017,0.371410,1.196160,0.810260,0.172190,2.475890,0.910900,2.063170,0.690330,0.840900 -2018,0.400410,1.300060,1.002570,0.189610,2.535530,0.994600,2.661310,0.760260,0.871740 -2019,0.338650,1.451550,1.185720,0.228310,2.790260,1.029820,2.928260,0.988210,0.834000 -2020,0.360850,1.684220,1.262780,0.247310,2.768040,1.047200,2.940390,0.954760,0.847680 -2021,0.344590,1.654780,1.082250,0.195060,2.468730,0.913910,2.732240,0.947250,0.887030 -2022,0.366770,1.998290,1.477690,0.257510,2.605340,0.900480,2.797010,0.947740,0.850180 -2023,0.382070,1.783250,1.337030,0.261850,2.930800,1.108780,3.113280,1.010900,0.897520 -2024,0.452001,1.954733,1.804559,0.330010,2.774692,1.121850,3.271640,1.202133,1.018694 -2025,0.400253,1.720835,1.748320,0.311531,2.728033,1.053865,3.139995,1.072385,0.786553 -2026,0.251434,1.490830,1.402841,0.199013,2.304525,0.872166,2.062922,0.829442,0.687765 -2027,0.211858,1.467800,1.498055,0.238384,2.249545,0.930938,2.132700,0.809352,0.664922 -2028,0.194398,1.385326,1.509668,0.246067,2.034196,0.907154,1.991213,0.783828,0.704409 -2029,0.192247,1.412108,1.496857,0.275980,1.846410,0.871673,1.856138,0.776658,0.741716 -2030,0.174559,1.373499,1.534067,0.437111,1.719123,0.808875,1.857033,0.770984,0.772348 -2031,0.157962,1.197684,1.384653,0.358888,1.451879,0.668381,1.640671,0.692458,0.789767 -2032,0.176228,1.132102,1.565061,0.451031,1.585336,0.734924,1.789956,0.847123,0.815216 -2033,0.166235,1.060135,1.333007,0.368381,1.433254,0.691406,1.579497,0.820230,0.797631 -2034,0.161400,0.929961,1.233128,0.308266,1.357102,0.634744,1.513954,0.759908,0.756096 -2035,0.165505,0.893260,1.111427,0.275428,1.358099,0.637080,1.327169,0.722170,0.688957 -2036,0.162913,0.788534,1.031229,0.261540,1.244350,0.549481,1.226203,0.653720,0.632692 -2037,0.137538,0.586714,0.854965,0.271243,1.119637,0.482770,1.115833,0.626503,0.554879 -2038,0.132298,0.522783,0.732474,0.254090,1.064564,0.435245,1.057815,0.527240,0.494092 -2039,0.134267,0.549630,0.758101,0.266654,0.993744,0.374653,1.017851,0.545790,0.454257 -2040,0.136717,0.527879,0.698537,0.271079,0.974679,0.296413,1.049425,0.509211,0.467174 -2041,0.137923,0.488661,0.664124,0.224717,0.975145,0.238602,0.994796,0.438115,0.449188 -2042,0.135460,0.463385,0.615075,0.206150,0.974492,0.237566,0.978935,0.395162,0.437638 -2043,0.138723,0.473387,0.606697,0.213672,0.925296,0.257154,0.991719,0.383094,0.435116 -2044,0.103130,0.474389,0.587082,0.236184,0.871767,0.247615,1.000719,0.395633,0.442636 -2045,0.087387,0.444759,0.607441,0.234486,0.779892,0.218179,1.004305,0.407519,0.440998 -2046,0.092547,0.450912,0.663438,0.237393,0.730188,0.209494,0.993623,0.364727,0.441239 -2047,0.092992,0.450285,0.687064,0.263399,0.693493,0.198955,1.047300,0.383422,0.446543 -2048,0.093810,0.473709,0.734405,0.265423,0.714790,0.201429,1.086109,0.416587,0.465141 -2049,0.095297,0.480987,0.789578,0.270487,0.700422,0.213645,1.095479,0.453987,0.473856 -2050,0.096417,0.472205,0.816287,0.278686,0.698386,0.217900,1.125022,0.486470,0.488408 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_reference.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_reference.csv deleted file mode 100644 index 666e7c3..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_demand_AEO_2025_reference.csv +++ /dev/null @@ -1,42 +0,0 @@ -year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,0.420000,0.890000,0.326000,0.124000,1.544000,0.567000,2.049000,0.641000,0.989000 -2011,0.456000,0.965000,0.395000,0.117000,1.671000,0.639000,2.188000,0.567000,0.766000 -2012,0.448000,1.154000,0.656000,0.171000,2.043000,0.797000,2.337000,0.663000,1.045000 -2013,0.372000,1.066000,0.475000,0.140000,1.883000,0.629000,2.075000,0.651000,1.069000 -2014,0.341750,1.131480,0.482860,0.108070,1.896250,0.671910,2.025670,0.648910,1.073730 -2015,0.397610,1.236450,0.713310,0.147160,2.330100,0.875420,2.434110,0.750920,1.084430 -2016,0.393180,1.344500,0.912140,0.191920,2.469830,0.961900,2.351840,0.765760,0.917910 -2017,0.371410,1.196160,0.810260,0.172190,2.475890,0.910900,2.063170,0.690330,0.840900 -2018,0.400410,1.300060,1.002570,0.189610,2.535530,0.994600,2.661310,0.760260,0.871740 -2019,0.338650,1.451550,1.185720,0.228310,2.790260,1.029820,2.928260,0.988210,0.834000 -2020,0.360850,1.684220,1.262780,0.247310,2.768040,1.047200,2.940390,0.954760,0.847680 -2021,0.344590,1.654780,1.082250,0.195060,2.468730,0.913910,2.732240,0.947250,0.887030 -2022,0.366770,1.998290,1.477690,0.257510,2.605340,0.900480,2.797010,0.947740,0.850180 -2023,0.382070,1.783250,1.337030,0.261850,2.930800,1.108780,3.113280,1.010900,0.897520 -2024,0.451624,1.947869,1.803768,0.328229,2.771119,1.120752,3.278091,1.202134,1.026979 -2025,0.402601,1.629397,1.779150,0.333078,2.839481,1.098819,3.062861,1.095031,0.855043 -2026,0.307184,1.645651,1.709301,0.292994,2.802256,1.090066,2.831672,1.009045,0.751345 -2027,0.263452,1.664455,1.930932,0.347046,2.786452,1.157464,2.922580,1.012900,0.718387 -2028,0.243434,1.601191,2.042475,0.365627,2.676992,1.160019,2.856328,0.970603,0.776476 -2029,0.223449,1.567711,2.250298,0.403164,2.548651,1.124709,2.763967,0.961866,0.824927 -2030,0.172437,1.638802,2.271644,0.456933,2.418587,1.037678,2.771827,1.036249,0.894584 -2031,0.193628,1.537363,2.249849,0.434738,2.196743,0.989105,2.681658,1.062644,0.947843 -2032,0.210223,1.631743,2.753094,0.589867,2.304419,1.045986,2.831487,1.131738,1.000090 -2033,0.202380,1.585095,2.610210,0.553112,2.088257,0.955824,2.650223,0.945356,0.930929 -2034,0.189251,1.527352,2.315766,0.410186,1.922410,0.866626,2.548273,0.872272,0.947975 -2035,0.192515,1.546738,2.128180,0.374010,1.878592,0.824893,2.161885,0.893621,0.933309 -2036,0.197367,1.530112,1.923508,0.346125,1.926551,0.771852,1.876698,0.882123,0.888036 -2037,0.189569,1.373293,1.718799,0.332811,1.718812,0.714015,1.742069,0.846004,0.825748 -2038,0.194608,1.208284,1.530699,0.307617,1.718832,0.654886,1.661109,0.834513,0.784750 -2039,0.183550,1.129269,1.492246,0.271675,1.680835,0.603034,1.621889,0.853311,0.737564 -2040,0.191371,1.131776,1.538328,0.272217,1.617794,0.603428,1.688687,0.863450,0.723354 -2041,0.192375,1.157560,1.606427,0.285775,1.619307,0.615171,1.746875,0.862811,0.729275 -2042,0.203848,1.098378,1.636847,0.264481,1.598931,0.615970,1.757097,0.915820,0.673652 -2043,0.207948,1.162631,1.703603,0.265405,1.554882,0.590668,1.737841,0.912592,0.706872 -2044,0.183532,1.205421,1.783943,0.239437,1.479005,0.604031,1.767898,0.939069,0.684177 -2045,0.141631,1.299167,1.743539,0.278295,1.469072,0.610125,1.725534,0.952057,0.662889 -2046,0.157335,1.281461,1.815236,0.288586,1.423282,0.608258,1.737410,0.916862,0.618836 -2047,0.158988,1.377790,1.637457,0.303452,1.396680,0.593526,1.773730,0.906929,0.640318 -2048,0.162292,1.420297,1.609448,0.320825,1.344266,0.605255,1.755996,0.957831,0.637655 -2049,0.174212,1.345600,1.616478,0.320191,1.313927,0.636592,1.718013,0.998673,0.629154 -2050,0.165085,1.342685,1.626209,0.331866,1.359366,0.643452,1.536503,1.036890,0.621188 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_HOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_HOG.csv deleted file mode 100644 index a87d2f3..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_HOG.csv +++ /dev/null @@ -1,42 +0,0 @@ -year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,0.858180,2.642740,3.358270,1.549810,2.864660,1.354120,5.379280,4.756300,2.707130 -2011,0.915350,2.719850,3.525400,1.555520,2.934920,1.416260,5.529350,4.793510,2.548560 -2012,0.879080,2.770950,3.547680,1.491080,3.280120,1.540450,5.730930,4.903690,2.803610 -2013,0.859500,2.891800,3.818100,1.645920,3.261050,1.455900,5.577360,4.972180,2.896840 -2014,0.857730,3.120450,4.045160,1.680470,3.326570,1.544660,5.646740,5.000560,2.784840 -2015,0.905920,3.099140,3.886720,1.574980,3.663950,1.696390,5.951670,5.255470,2.763970 -2016,0.856640,3.156140,3.920960,1.638640,3.735140,1.746690,5.803450,1.581650,2.775400 -2017,0.879540,3.113560,3.997110,1.729600,3.888780,1.767730,5.922210,1.576460,2.827700 -2018,0.930980,3.316360,4.395240,1.846240,4.067650,1.912480,6.697610,1.676030,2.952350 -2019,0.884970,3.507680,4.665440,1.972420,4.325760,1.962090,7.134520,1.985240,2.949310 -2020,0.849800,3.615310,4.578500,1.915620,4.221530,1.967890,7.066120,1.900720,2.847720 -2021,0.878470,3.665610,4.418460,1.893200,3.971680,1.844550,6.865970,1.921410,2.947450 -2022,0.923150,4.044720,4.940080,1.998680,4.159860,1.892740,7.156390,1.914710,2.857150 -2023,0.914370,3.709180,4.648730,1.877740,4.158050,1.861390,6.910270,1.734920,2.869450 -2024,0.957036,3.906965,4.966578,2.048244,4.376607,2.097415,7.426676,2.155910,2.973608 -2025,0.937966,3.654048,5.179120,2.077749,4.469378,2.111273,7.503117,2.100823,2.843258 -2026,0.860033,3.759808,5.488719,2.125013,4.646142,2.230853,7.636079,2.131084,2.739021 -2027,0.818995,3.774266,5.671466,2.190878,4.738679,2.335734,7.659956,2.100113,2.732933 -2028,0.795159,3.716908,5.789507,2.173376,4.717777,2.291502,7.557886,2.087887,2.772114 -2029,0.790301,3.712479,5.954311,2.195643,4.672873,2.306812,7.466064,2.086488,2.829799 -2030,0.744455,3.873317,6.039167,2.226819,4.578413,2.233391,7.538048,2.194306,2.921344 -2031,0.722228,3.884992,6.186546,2.296895,4.417633,2.170599,7.592106,2.241075,2.999857 -2032,0.741138,3.944881,6.693543,2.414316,4.601673,2.200978,7.769639,2.365347,3.048926 -2033,0.733747,3.943127,6.668369,2.318362,4.486273,2.200232,7.632854,2.325531,3.145908 -2034,0.735347,3.933705,6.625295,2.316933,4.505866,2.237109,7.758178,2.308635,3.176948 -2035,0.739885,3.800751,6.627602,2.316072,4.430108,2.198426,7.729087,2.271489,3.205086 -2036,0.747582,3.739552,6.545062,2.257230,4.338734,2.156050,7.367331,2.397209,3.013469 -2037,0.757997,3.743082,6.556759,2.263292,4.274085,2.167767,6.954051,2.404191,3.038831 -2038,0.749867,3.694221,6.133348,2.231797,4.256666,2.189104,6.922351,2.272732,3.078229 -2039,0.738831,3.544951,6.001094,2.216016,4.208876,2.141802,6.825901,2.137090,3.124984 -2040,0.745195,3.550549,5.973637,2.230641,4.339911,2.126414,6.780476,2.205422,3.147804 -2041,0.750859,3.586475,6.025984,2.242017,4.432344,2.154529,6.878246,2.189955,3.201372 -2042,0.762990,3.519784,6.201727,2.267177,4.433652,2.144847,6.934600,2.228513,3.202829 -2043,0.771564,3.577761,6.316656,2.304414,4.492250,2.215720,7.085598,2.279858,3.196146 -2044,0.751563,3.673051,6.423592,2.318251,4.486453,2.223858,7.117551,2.359413,3.216992 -2045,0.716803,3.723683,6.500850,2.359171,4.477860,2.262689,7.170787,2.461398,3.226556 -2046,0.718965,3.795890,6.540277,2.392810,4.501936,2.342593,7.244801,2.465548,3.255445 -2047,0.724840,3.895167,6.419639,2.406723,4.490632,2.399555,7.288305,2.517160,3.255843 -2048,0.726701,3.907527,6.308069,2.422065,4.457742,2.390973,7.159330,2.572379,3.249705 -2049,0.725793,3.848761,6.439577,2.387223,4.593865,2.408647,7.386389,2.626165,3.269576 -2050,0.713332,3.860977,6.387714,2.353932,4.613367,2.433508,7.393847,2.731677,3.273041 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_LOG.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_LOG.csv deleted file mode 100644 index 43ad1c0..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_LOG.csv +++ /dev/null @@ -1,42 +0,0 @@ -year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,0.858180,2.642740,3.358270,1.549810,2.864660,1.354120,5.379280,4.756300,2.707130 -2011,0.915350,2.719850,3.525400,1.555520,2.934920,1.416260,5.529350,4.793510,2.548560 -2012,0.879080,2.770950,3.547680,1.491080,3.280120,1.540450,5.730930,4.903690,2.803610 -2013,0.859500,2.891800,3.818100,1.645920,3.261050,1.455900,5.577360,4.972180,2.896840 -2014,0.857730,3.120450,4.045160,1.680470,3.326570,1.544660,5.646740,5.000560,2.784840 -2015,0.905920,3.099140,3.886720,1.574980,3.663950,1.696390,5.951670,5.255470,2.763970 -2016,0.856640,3.156140,3.920960,1.638640,3.735140,1.746690,5.803450,1.581650,2.775400 -2017,0.879540,3.113560,3.997110,1.729600,3.888780,1.767730,5.922210,1.576460,2.827700 -2018,0.930980,3.316360,4.395240,1.846240,4.067650,1.912480,6.697610,1.676030,2.952350 -2019,0.884970,3.507680,4.665440,1.972420,4.325760,1.962090,7.134520,1.985240,2.949310 -2020,0.849800,3.615310,4.578500,1.915620,4.221530,1.967890,7.066120,1.900720,2.847720 -2021,0.878470,3.665610,4.418460,1.893200,3.971680,1.844550,6.865970,1.921410,2.947450 -2022,0.923150,4.044720,4.940080,1.998680,4.159860,1.892740,7.156390,1.914710,2.857150 -2023,0.914370,3.709180,4.648730,1.877740,4.158050,1.861390,6.910270,1.734920,2.869450 -2024,0.962553,3.909995,4.964130,2.049968,4.378995,2.098575,7.414999,2.159559,2.974449 -2025,0.930546,3.749795,5.087374,2.005418,4.343349,2.031063,7.370770,2.058202,2.728772 -2026,0.781939,3.475330,4.620926,1.842845,3.891988,1.784934,5.958117,1.781902,2.557914 -2027,0.742323,3.444869,4.707423,1.880801,3.828328,1.835414,6.003426,1.754856,2.526092 -2028,0.725009,3.364414,4.696098,1.881701,3.591180,1.783213,5.845942,1.713990,2.556307 -2029,0.720008,3.386134,4.647316,1.897199,3.361863,1.719558,5.699160,1.696235,2.585802 -2030,0.699351,3.335698,4.641392,2.038857,3.190711,1.629336,5.668550,1.677637,2.614153 -2031,0.679255,3.142804,4.456717,1.944253,2.885270,1.470770,5.419774,1.608598,2.628891 -2032,0.694852,3.056186,4.594091,2.025953,2.987373,1.521027,5.548148,1.763594,2.637849 -2033,0.682768,2.965106,4.325788,1.940535,2.804255,1.469214,5.332105,1.746244,2.634555 -2034,0.676451,2.821101,4.196589,1.874597,2.729338,1.399418,5.265339,1.690408,2.577221 -2035,0.679203,2.774165,4.056654,1.840279,2.722006,1.387416,5.066918,1.656034,2.517057 -2036,0.675569,2.661531,3.955245,1.820973,2.598980,1.295392,4.959162,1.584508,2.446003 -2037,0.649520,2.454186,3.762507,1.831730,2.459701,1.225727,4.837954,1.567165,2.364758 -2038,0.645287,2.387821,3.630200,1.815282,2.406118,1.169368,4.794869,1.473797,2.291434 -2039,0.653401,2.414410,3.649924,1.826088,2.401801,1.127985,4.765383,1.487857,2.252511 -2040,0.655786,2.393730,3.580663,1.829875,2.404084,1.060108,4.802187,1.457779,2.281605 -2041,0.656713,2.350435,3.536101,1.785332,2.420143,1.008874,4.750147,1.393410,2.238770 -2042,0.654128,2.321419,3.480375,1.763587,2.433650,1.021078,4.739210,1.361234,2.244678 -2043,0.657176,2.332030,3.467469,1.775419,2.402768,1.043947,4.753344,1.362778,2.247817 -2044,0.621498,2.330870,3.439527,1.802037,2.371214,1.045289,4.766046,1.392945,2.278843 -2045,0.605406,2.309155,3.448897,1.802026,2.302510,1.024428,4.775317,1.404418,2.285449 -2046,0.609633,2.310539,3.494394,1.805467,2.268174,1.023384,4.763526,1.375992,2.290656 -2047,0.609062,2.304937,3.507108,1.829551,2.242798,1.011038,4.806602,1.401801,2.294402 -2048,0.608704,2.319615,3.543561,1.830128,2.267759,1.015026,4.840192,1.456912,2.322879 -2049,0.608873,2.317298,3.585941,1.837048,2.260479,1.036841,4.846149,1.501403,2.333663 -2050,0.608951,2.297522,3.602013,1.850036,2.244589,1.030486,4.884940,1.540658,2.361397 diff --git a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_reference.csv b/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_reference.csv deleted file mode 100644 index d2d82e3..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of alpha regression/ng_tot_demand_AEO_2025_reference.csv +++ /dev/null @@ -1,42 +0,0 @@ -year,New_England,Mid_Atlantic,East_North_Central,West_North_Central,South_Atlantic,East_South_Central,West_South_Central,Mountain,Pacific -2010,0.858180,2.642740,3.358270,1.549810,2.864660,1.354120,5.379280,4.756300,2.707130 -2011,0.915350,2.719850,3.525400,1.555520,2.934920,1.416260,5.529350,4.793510,2.548560 -2012,0.879080,2.770950,3.547680,1.491080,3.280120,1.540450,5.730930,4.903690,2.803610 -2013,0.859500,2.891800,3.818100,1.645920,3.261050,1.455900,5.577360,4.972180,2.896840 -2014,0.857730,3.120450,4.045160,1.680470,3.326570,1.544660,5.646740,5.000560,2.784840 -2015,0.905920,3.099140,3.886720,1.574980,3.663950,1.696390,5.951670,5.255470,2.763970 -2016,0.856640,3.156140,3.920960,1.638640,3.735140,1.746690,5.803450,1.581650,2.775400 -2017,0.879540,3.113560,3.997110,1.729600,3.888780,1.767730,5.922210,1.576460,2.827700 -2018,0.930980,3.316360,4.395240,1.846240,4.067650,1.912480,6.697610,1.676030,2.952350 -2019,0.884970,3.507680,4.665440,1.972420,4.325760,1.962090,7.134520,1.985240,2.949310 -2020,0.849800,3.615310,4.578500,1.915620,4.221530,1.967890,7.066120,1.900720,2.847720 -2021,0.878470,3.665610,4.418460,1.893200,3.971680,1.844550,6.865970,1.921410,2.947450 -2022,0.923150,4.044720,4.940080,1.998680,4.159860,1.892740,7.156390,1.914710,2.857150 -2023,0.914370,3.709180,4.648730,1.877740,4.158050,1.861390,6.910270,1.734920,2.869450 -2024,0.962173,3.903117,4.963340,2.048189,4.375371,2.097466,7.421416,2.159530,2.982530 -2025,0.935287,3.661196,5.156418,2.129834,4.476222,2.089903,7.237640,2.086673,2.807245 -2026,0.848885,3.692177,5.073037,2.030126,4.465045,2.052864,6.971332,1.988881,2.694449 -2027,0.807334,3.721632,5.310193,2.096073,4.458486,2.121335,7.088854,1.999269,2.667008 -2028,0.788003,3.668039,5.422043,2.115744,4.351885,2.120489,7.020803,1.959295,2.730486 -2029,0.767319,3.644482,5.623929,2.153275,4.227018,2.085303,6.950130,1.954141,2.789246 -2030,0.715819,3.723123,5.640369,2.207593,4.102344,2.000149,6.981818,2.035256,2.874931 -2031,0.736064,3.624680,5.612779,2.187774,3.890681,1.956317,6.930852,2.067181,2.935515 -2032,0.752671,3.716164,6.106751,2.346345,4.012863,2.020668,7.100438,2.145240,2.998962 -2033,0.746767,3.659340,5.944864,2.309086,3.806603,1.933828,6.931971,1.967468,2.933176 -2034,0.733941,3.596563,5.637051,2.168169,3.651626,1.848481,6.835082,1.903266,2.945720 -2035,0.737544,3.614042,5.440754,2.135197,3.610039,1.810854,6.454259,1.936649,2.938173 -2036,0.742872,3.597095,5.228507,2.114645,3.659100,1.762085,6.180867,1.936809,2.895602 -2037,0.736183,3.445315,5.027087,2.105235,3.464379,1.709159,6.054377,1.914083,2.844030 -2038,0.742570,3.288879,4.835952,2.094151,3.479662,1.657892,6.006368,1.916980,2.813577 -2039,0.732698,3.218215,4.804575,2.066591,3.457128,1.614115,5.997215,1.950361,2.782817 -2040,0.741344,3.226690,4.854189,2.076052,3.408876,1.621953,6.087286,1.974375,2.780822 -2041,0.742691,3.255468,4.917473,2.094103,3.422421,1.639145,6.161439,1.985551,2.793409 -2042,0.754417,3.196219,4.942109,2.077646,3.412856,1.644759,6.188160,2.049288,2.748004 -2043,0.758587,3.258941,5.006926,2.081888,3.378010,1.624161,6.185266,2.057952,2.793068 -2044,0.734295,3.302742,5.082698,2.062417,3.311311,1.641373,6.232446,2.095899,2.783741 -2045,0.692461,3.395932,5.035407,2.105197,3.316263,1.651322,6.209975,2.119609,2.772924 -2046,0.707880,3.377838,5.099153,2.118033,3.285728,1.651759,6.231880,2.093664,2.733654 -2047,0.709487,3.474578,4.917622,2.137938,3.267011,1.640283,6.275684,2.094466,2.770767 -2048,0.713195,3.520399,4.895315,2.163854,3.225357,1.657869,6.278858,2.157986,2.782060 -2049,0.725422,3.449674,4.902303,2.172264,3.207612,1.695295,6.269968,2.213768,2.792679 -2050,0.716690,3.453480,4.926717,2.197461,3.263909,1.705988,6.099909,2.264314,2.801707 diff --git a/aeo_updates/natural_gas_price_regression/outputs of beta regression/beta_regression_summary.csv b/aeo_updates/natural_gas_price_regression/outputs of beta regression/beta_regression_summary.csv deleted file mode 100644 index 31f0295..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of beta regression/beta_regression_summary.csv +++ /dev/null @@ -1,11 +0,0 @@ -scope,region,beta,r2,r2_full,n_obs -national,ALL,0.080017,0.727887,0.847220,1701 -regional,New_England,3.875323,0.587849,0.867459,189 -regional,Mid_Atlantic,0.151497,0.191732,0.850741,189 -regional,East_North_Central,0.033492,0.037937,0.842476,189 -regional,West_North_Central,0.856915,0.452614,0.852631,189 -regional,South_Atlantic,0.175498,0.407799,0.840697,189 -regional,East_South_Central,0.139571,0.135091,0.853755,189 -regional,West_South_Central,-0.054900,0.048903,0.721250,189 -regional,Mountain,0.670353,0.575211,0.854568,189 -regional,Pacific,1.341567,0.669742,0.855878,189 diff --git a/aeo_updates/natural_gas_price_regression/outputs of beta regression/cd_beta0.csv b/aeo_updates/natural_gas_price_regression/outputs of beta regression/cd_beta0.csv deleted file mode 100644 index 946cf33..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of beta regression/cd_beta0.csv +++ /dev/null @@ -1,10 +0,0 @@ -*cendiv,value -New_England,3.875323 -Mid_Atlantic,0.151497 -East_North_Central,0.033492 -West_North_Central,0.856915 -South_Atlantic,0.175498 -East_South_Central,0.139571 -West_South_Central,-0.054900 -Mountain,0.670353 -Pacific,1.341567 diff --git a/aeo_updates/natural_gas_price_regression/outputs of beta regression/national_beta.csv b/aeo_updates/natural_gas_price_regression/outputs of beta regression/national_beta.csv deleted file mode 100644 index abd889b..0000000 --- a/aeo_updates/natural_gas_price_regression/outputs of beta regression/national_beta.csv +++ /dev/null @@ -1,2 +0,0 @@ -beta -0.080017 From 9d144d5a8f859b7205a4357f4d69ca61234bdce5 Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Thu, 23 Apr 2026 17:03:35 -0600 Subject: [PATCH 12/14] Create README.md --- .../outputs of beta regression/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 aeo_updates/natural_gas_price_regression/outputs of beta regression/README.md diff --git a/aeo_updates/natural_gas_price_regression/outputs of beta regression/README.md b/aeo_updates/natural_gas_price_regression/outputs of beta regression/README.md new file mode 100644 index 0000000..191151b --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/outputs of beta regression/README.md @@ -0,0 +1,3 @@ +# Outputs of Beta Regression + +This directory stores intermediate files generated by the beta regression step of the pipeline. These files are consumed by downstream steps (sync and alpha regression) and are not final outputs. From 2a1fbe030f4c6b0fa485556feb0bcbf3bc0a4899 Mon Sep 17 00:00:00 2001 From: Yunzhi-Chen Date: Thu, 23 Apr 2026 17:06:27 -0600 Subject: [PATCH 13/14] Create README.md --- .../inputs for alpha regression/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 aeo_updates/natural_gas_price_regression/inputs for alpha regression/README.md diff --git a/aeo_updates/natural_gas_price_regression/inputs for alpha regression/README.md b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/README.md new file mode 100644 index 0000000..5a6f04a --- /dev/null +++ b/aeo_updates/natural_gas_price_regression/inputs for alpha regression/README.md @@ -0,0 +1,16 @@ +# Inputs for Alpha Regression + +This directory contains input files used by the alpha regression step. + +## Historical CSVs (manual inputs) + +The following files are manually maintained and provide historical data to backfill years (2010 – most recent year) that are not covered by AEO projections: + +- `ng_AEO_historical.csv` — Historical NG prices +- `ng_demand_AEO_historical.csv` — Historical electric sector NG demand +- `ng_tot_demand_AEO_historical.csv` — Historical total sector NG demand +- `st_cendiv.csv` — State to Census Division mapping + +## Auto-generated files + +During the pipeline run, `sync_beta_to_alpha_inputs.py` copies beta regression results (`cd_beta0.csv`, `national_beta.csv`) into this directory. These are then read by `aeo_alpha_regression.py`. From b6874b0fed5d9434df2038240ad7bc5bd15c6ad4 Mon Sep 17 00:00:00 2001 From: wcole Date: Fri, 24 Apr 2026 15:20:52 -0600 Subject: [PATCH 14/14] Remove old method for updating natural gas values. --- ...G Prices Preprocessing for AEO Inputs.xlsx | Bin 155584 -> 0 bytes aeo_updates/README.md | 18 ++---------------- .../natural_gas_price_regression/README.md | 2 ++ 3 files changed, 4 insertions(+), 16 deletions(-) delete mode 100644 aeo_updates/NG Prices Preprocessing for AEO Inputs.xlsx diff --git a/aeo_updates/NG Prices Preprocessing for AEO Inputs.xlsx b/aeo_updates/NG Prices Preprocessing for AEO Inputs.xlsx deleted file mode 100644 index 3a1b3afe36d61f200381088653f89f9a48090d79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 155584 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

G08}|L1iKkG=tVdgAqF%?Iftay8o) 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 diff --git a/aeo_updates/README.md b/aeo_updates/README.md index f02f09f..b50cf8b 100644 --- a/aeo_updates/README.md +++ b/aeo_updates/README.md @@ -42,22 +42,8 @@ Once you have obtained your api key, create a new environment variable to store ### Input Data Changes When Updating AEO Data #### Natural Gas Prices and Demand -Natural gas prices and demand can be pulled using the EIA AEO data grabber. The spreadsheet "NG Prices Preprocessing for AEO Inputs.xlsx" is used to calculate the alphas using the preset betas. You need to paste in the NG prices and NG electricity sector demand into the relevant tabs. Historical data needs to be updated to the current dollar year. The deflator to convert the alphas back to 2004$ also need to be updated. The alphas are then put into a csv file to be added to the inputs/fuelprices folder of the ReEDS model repo. - -The prices and demand (both for the electricity sector and for all sectors) are also put into the relevant csv files in the inputs/fuelprices folder of the ReEDS model repo. Here are the NG input files that should be updated: - -* ng_tot_demand_AEO_{year}_HOG.csv -* ng_tot_demand_AEO_{year}_LOG.csv -* ng_tot_demand_AEO_{year}_reference.csv -* ng_demand_AEO_{year}_LOG.csv -* ng_demand_AEO_{year}_HOG.csv -* ng_demand_AEO_{year}_reference.csv -* ng_AEO_{year}_LOG.csv -* ng_AEO_{year}_HOG.csv -* ng_AEO_{year}_reference.csv -* alpha_AEO_{year}_LOG.csv -* alpha_AEO_{year}_HOG.csv -* alpha_AEO_{year}_reference.csv +Natural gas prices and demand are updated using the files in natural_gas_price_regression. +See the README.md in that folder for more information. #### Coal Prices Pulled using the EIA data grabber. Coal data are input into the coal_AEO_{year}_reference.csv. diff --git a/aeo_updates/natural_gas_price_regression/README.md b/aeo_updates/natural_gas_price_regression/README.md index 374d88e..ea59dcb 100644 --- a/aeo_updates/natural_gas_price_regression/README.md +++ b/aeo_updates/natural_gas_price_regression/README.md @@ -2,6 +2,8 @@ This folder has the natural gas update workflow for ReEDS. +Files to update in the ReEDS repository are described in "outputs of alpha regression/README.md". + ## Model Note `alpha` differs by step: