Skip to content

Commit 43dd520

Browse files
Add function for gas tariff mapping (#146)
* Add skeleton code for gas tariff mapper * Finish python script for gas tariff key mapping * Clean up python code for gas tariff key mapping * Add Justfile command for gas tariff_key mapping * Address comments and reformat scripts * Address comments and reformat scripts * Add some useful enumerations for just commands * Fix formatting in justfiles * Remove relational path defining and fix justfile enumerations * Address comments and reformat scripts
1 parent 1a6f7df commit 43dd520

File tree

6 files changed

+333
-49
lines changed

6 files changed

+333
-49
lines changed
Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,86 @@
11
# Resolve project root via git (works from any subdirectory in the repo)
22
project_root := `git rev-parse --show-toplevel`
33
path_s3_resstock_metadata := "s3://data.sb/nrel/resstock/res_2024_amy2018_2/metadata"
4+
tariff_map_dir_ny := "{{project_root}}/rate_design/ny/hp_rates/data/tariff_map"
45

5-
# Usage: just map-electric-tariff [electric_utility] [SB_scenario_type] [SB_scenario_year] [upgrade_id]
6-
# Example: just map-electric-tariff Coned default 1 00
7-
map-electric-tariff electric_utility SB_scenario_type SB_scenario_year upgrade_id output_dir="":
6+
# Usage: just map-electric-tariff [electric_utility] [SB_scenario_type] [SB_scenario_year] [upgrade_id] [output_dir]
7+
# Example: just map-electric-tariff Coned default 1 00 ./rate_design/ny/hp_rates/data/tariff_map
8+
map-electric-tariff electric_utility SB_scenario_type SB_scenario_year upgrade_id output_dir:
89
uv run python {{project_root}}/utils/electric_tariff_mapper.py \
910
--metadata_path "{{path_s3_resstock_metadata}}" \
1011
--state NY \
1112
--upgrade_id "{{upgrade_id}}" \
1213
--electric_utility "{{electric_utility}}" \
1314
--SB_scenario_type "{{SB_scenario_type}}" \
1415
--SB_scenario_year "{{SB_scenario_year}}" \
15-
{{ if output_dir != "" { "--output_dir \"" + output_dir + "\"" } else { "" } }}
16+
--output_dir "{{output_dir}}"
17+
18+
# Some useful enumerations:
19+
20+
map-electric-coned-default:
21+
just map-electric-tariff Coned default 1 00 {{tariff_map_dir_ny}}
22+
23+
map-electric-coned-seasonal:
24+
just map-electric-tariff Coned seasonal 1 00 {{tariff_map_dir_ny}}
25+
26+
map-celectric-oned-class-specific-seasonal:
27+
just map-electric-tariff Coned class_specific_seasonal 1 00 {{tariff_map_dir_ny}}
28+
29+
map-electric-national-grid-default:
30+
just map-electric-tariff "National Grid" default 1 00 {{tariff_map_dir_ny}}
31+
32+
map-electric-national-grid-seasonal:
33+
just map-electric-tariff "National Grid" seasonal 1 00 {{tariff_map_dir_ny}}
34+
35+
map-electric-national-grid-class-specific-seasonal:
36+
just map-electric-tariff "National Grid" class_specific_seasonal 1 00 {{tariff_map_dir_ny}}
37+
38+
map-electric-nyseg-default:
39+
just map-electric-tariff NYSEG default 1 00 {{tariff_map_dir_ny}}
40+
41+
map-electric-nyseg-seasonal:
42+
just map-electric-tariff NYSEG seasonal 1 00 {{tariff_map_dir_ny}}
43+
44+
map-electric-nyseg-class-specific-seasonal:
45+
just map-electric-tariff NYSEG class_specific_seasonal 1 00 {{tariff_map_dir_ny}}
46+
47+
# Usage: just map-gas-tariff [electric_utility] [upgrade_id] [output_dir]
48+
# Example: just map-gas-tariff NYSEG 00 ./rate_design/ny/hp_rates/data/tariff_map
49+
map-gas-tariff electric_utility upgrade_id output_dir:
50+
uv run python {{project_root}}/utils/gas_tariff_mapper.py \
51+
--metadata_path "{{path_s3_resstock_metadata}}" \
52+
--state NY \
53+
--upgrade_id "{{upgrade_id}}" \
54+
--electric_utility "{{electric_utility}}" \
55+
--output_dir "{{output_dir}}"
56+
57+
# Some useful enumerations:
58+
59+
map-gas-coned-default:
60+
just map-gas-tariff Coned 00 {{tariff_map_dir_ny}}
61+
62+
map-gas-coned-seasonal:
63+
just map-gas-tariff Coned 00 {{tariff_map_dir_ny}}
64+
65+
map-gas-coned-class-specific-seasonal:
66+
just map-gas-tariff Coned 00 {{tariff_map_dir_ny}}
67+
68+
map-gas-national-grid-default:
69+
just map-gas-tariff "National Grid" 00 {{tariff_map_dir_ny}}
70+
71+
map-gas-national-grid-seasonal:
72+
just map-gas-tariff "National Grid" 00 {{tariff_map_dir_ny}}
73+
74+
map-gas-national-grid-class-specific-seasonal:
75+
just map-gas-tariff "National Grid" 00 {{tariff_map_dir_ny}}
76+
77+
map-gas-nyseg-default:
78+
just map-gas-tariff NYSEG 00 {{tariff_map_dir_ny}}
79+
80+
map-gas-nyseg-seasonal:
81+
just map-gas-tariff NYSEG 00 {{tariff_map_dir_ny}}
82+
83+
map-gas-nyseg-class-specific-seasonal:
84+
just map-gas-tariff NYSEG 00 {{tariff_map_dir_ny}}
85+
86+
Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,85 @@
11
# Resolve project root via git (works from any subdirectory in the repo)
22
project_root := `git rev-parse --show-toplevel`
33
path_s3_resstock_metadata := "s3://data.sb/nrel/resstock/res_2024_amy2018_2/metadata"
4+
tariff_map_dir_ri := "{{project_root}}/rate_design/ri/hp_rates/data/tariff_map"
45

5-
# Usage: just map-electric-tariff [electric_utility] [SB_scenario_type] [SB_scenario_year] [upgrade_id]
6-
# Example: just map-electric-tariff Coned default 1 00
7-
map-electric-tariff electric_utility SB_scenario_type SB_scenario_year upgrade_id output_dir="":
6+
# Usage: just map-electric-tariff [electric_utility] [SB_scenario_type] [SB_scenario_year] [upgrade_id] [output_dir]
7+
# Example: just map-electric-tariff Coned default 1 00 ./rate_design/ri/hp_rates/data/tariff_map
8+
map-electric-tariff electric_utility SB_scenario_type SB_scenario_year upgrade_id output_dir:
89
uv run python {{project_root}}/utils/electric_tariff_mapper.py \
910
--metadata_path "{{path_s3_resstock_metadata}}" \
1011
--state RI \
1112
--upgrade_id "{{upgrade_id}}" \
1213
--electric_utility "{{electric_utility}}" \
1314
--SB_scenario_type "{{SB_scenario_type}}" \
14-
--SB_scenario_year "{{SB_scenario_year}}"
15-
{{ if output_dir != "" { "--output_dir \"" + output_dir + "\"" } else { "" } }}
15+
--SB_scenario_year "{{SB_scenario_year}}" \
16+
--output_dir "{{output_dir}}"
17+
18+
# Some useful enumerations:
19+
20+
map-electric-coned-default:
21+
just map-electric-tariff Coned default 1 00 {{tariff_map_dir_ri}}
22+
23+
map-electric-coned-seasonal:
24+
just map-electric-tariff Coned seasonal 1 00 {{tariff_map_dir_ri}}
25+
26+
map-celectric-oned-class-specific-seasonal:
27+
just map-electric-tariff Coned class_specific_seasonal 1 00 {{tariff_map_dir_ri}}
28+
29+
map-electric-national-grid-default:
30+
just map-electric-tariff "National Grid" default 1 00 {{tariff_map_dir_ri}}
31+
32+
map-electric-national-grid-seasonal:
33+
just map-electric-tariff "National Grid" seasonal 1 00 {{tariff_map_dir_ri}}
34+
35+
map-electric-national-grid-class-specific-seasonal:
36+
just map-electric-tariff "National Grid" class_specific_seasonal 1 00 {{tariff_map_dir_ri}}
37+
38+
map-electric-nyseg-default:
39+
just map-electric-tariff NYSEG default 1 00 {{tariff_map_dir_ri}}
40+
41+
map-electric-nyseg-seasonal:
42+
just map-electric-tariff NYSEG seasonal 1 00 {{tariff_map_dir_ri}}
43+
44+
map-electric-nyseg-class-specific-seasonal:
45+
just map-electric-tariff NYSEG class_specific_seasonal 1 00 {{tariff_map_dir_ri}}
46+
47+
48+
# Usage: just map-gas-tariff [electric_utility] [upgrade_id] [output_dir]
49+
# Example: just map-gas-tariff "National Grid" 00 ./rate_design/ri/hp_rates/data/tariff_map
50+
map-gas-tariff electric_utility upgrade_id output_dir:
51+
uv run python {{project_root}}/utils/gas_tariff_mapper.py \
52+
--metadata_path "{{path_s3_resstock_metadata}}" \
53+
--state RI \
54+
--upgrade_id "{{upgrade_id}}" \
55+
--electric_utility "{{electric_utility}}" \
56+
--output_dir "{{output_dir}}"
57+
58+
# Some useful enumerations:
59+
60+
map-gas-coned-default:
61+
just map-gas-tariff Coned 00 {{tariff_map_dir_ri}}
62+
63+
map-gas-coned-seasonal:
64+
just map-gas-tariff Coned 00 {{tariff_map_dir_ri}}
65+
66+
map-gas-coned-class-specific-seasonal:
67+
just map-gas-tariff Coned 00 {{tariff_map_dir_ri}}
68+
69+
map-gas-national-grid-default:
70+
just map-gas-tariff "National Grid" 00 {{tariff_map_dir_ri}}
71+
72+
map-gas-national-grid-seasonal:
73+
just map-gas-tariff "National Grid" 00 {{tariff_map_dir_ri}}
74+
75+
map-gas-national-grid-class-specific-seasonal:
76+
just map-gas-tariff "National Grid" 00 {{tariff_map_dir_ri}}
77+
78+
map-gas-nyseg-default:
79+
just map-gas-tariff NYSEG 00 {{tariff_map_dir_ri}}
80+
81+
map-gas-nyseg-seasonal:
82+
just map-gas-tariff NYSEG 00 {{tariff_map_dir_ri}}
83+
84+
map-gas-nyseg-class-specific-seasonal:
85+
just map-gas-tariff NYSEG 00 {{tariff_map_dir_ri}}

utils/__init__.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,35 @@
11
"""Utility helpers wrapping external packages (stub)."""
2+
3+
import os
4+
import subprocess
5+
from pathlib import Path
6+
7+
8+
def get_aws_region(default: str = "us-west-2") -> str:
9+
"""Return AWS region from env (AWS_REGION / AWS_DEFAULT_REGION) or from AWS config (~/.aws/config) via boto3."""
10+
region = os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION")
11+
if region:
12+
return region
13+
try:
14+
import boto3
15+
session = boto3.Session()
16+
if session.region_name:
17+
return session.region_name
18+
except ImportError:
19+
pass
20+
return default
21+
22+
23+
def get_project_root() -> Path:
24+
"""Return the repository root as an absolute path (via git rev-parse --show-toplevel)."""
25+
result = subprocess.run(
26+
["git", "rev-parse", "--show-toplevel"],
27+
capture_output=True,
28+
text=True,
29+
cwd=Path.cwd(),
30+
)
31+
if result.returncode != 0:
32+
raise RuntimeError(
33+
"Could not find project root (run from inside the git repository)"
34+
)
35+
return Path(result.stdout.strip()).resolve()

utils/electric_tariff_mapper.py

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,10 @@
55
import polars as pl
66
from cloudpathlib import S3Path
77

8+
from utils import get_aws_region
89
from utils.types import SBScenario, electric_utility
910

10-
# Project root (rate-design-platform); independent of cwd or caller
11-
_PROJECT_ROOT = Path(__file__).resolve().parent.parent
12-
RATE_DESIGN_DIR = _PROJECT_ROOT / "rate_design"
13-
14-
AWS_REGION = "us-west-2"
15-
16-
STORAGE_OPTIONS = {"aws_region": AWS_REGION}
11+
STORAGE_OPTIONS = {"aws_region": get_aws_region()}
1712

1813

1914
def define_electrical_tariff_key(
@@ -49,12 +44,12 @@ def generate_electrical_tariff_mapping(
4944

5045

5146
def map_electric_tariff(
52-
SB_metadata_lazy_df: pl.LazyFrame,
47+
SB_metadata_df: pl.LazyFrame,
5348
electric_utility: electric_utility,
5449
SB_scenario: SBScenario,
5550
state: str,
5651
) -> pl.LazyFrame:
57-
utility_metadata_df = SB_metadata_lazy_df.filter(
52+
utility_metadata_df = SB_metadata_df.filter(
5853
pl.col("sb.electric_utility") == electric_utility
5954
)
6055

@@ -75,7 +70,9 @@ def map_electric_tariff(
7570

7671

7772
if __name__ == "__main__":
78-
parser = argparse.ArgumentParser(description="Map electrical tariff.")
73+
parser = argparse.ArgumentParser(
74+
description="Utility to help assign electricity tariffs to utility customers."
75+
)
7976
parser.add_argument(
8077
"--metadata_path",
8178
required=True,
@@ -92,12 +89,12 @@ def map_electric_tariff(
9289
help="SB scenario type (e.g. default, seasonal, class_specific_seasonal)",
9390
)
9491
parser.add_argument(
95-
"--SB_scenario_year", required=True, help="SB scenario year (e.g. 2024)"
92+
"--SB_scenario_year", required=True, help="SB scenario year (e.g. 1 , 2, 3)"
9693
)
9794
parser.add_argument(
9895
"--output_dir",
99-
default=None,
100-
help="Optional directory for output CSV; default is rate_design/<state>/hp_rates/data/tariff_map/",
96+
required=True,
97+
help="Output directory for output CSV",
10198
)
10299
args = parser.parse_args()
103100

@@ -115,7 +112,7 @@ def map_electric_tariff(
115112
if not metadata_path.exists():
116113
raise FileNotFoundError(f"Metadata path {metadata_path} does not exist")
117114
# Polars scan_parquet needs a string path; S3Path.as_uri() gives s3:// URL
118-
SB_metadata_lazy_df = pl.scan_parquet(
115+
SB_metadata_df = pl.scan_parquet(
119116
str(metadata_path), storage_options=STORAGE_OPTIONS
120117
)
121118
except ValueError:
@@ -129,10 +126,10 @@ def map_electric_tariff(
129126
)
130127
if not metadata_path.exists():
131128
raise FileNotFoundError(f"Metadata path {metadata_path} does not exist")
132-
SB_metadata_lazy_df = pl.scan_parquet(str(metadata_path))
129+
SB_metadata_df = pl.scan_parquet(str(metadata_path))
133130

134131
# Add dummy electric utility column (deterministic by bldg_id). Later this column will be pre-existing in the SB metadata parquet.
135-
SB_metadata_lazy_df_with_electric_utility = SB_metadata_lazy_df.with_columns(
132+
SB_metadata_df_with_electric_utility = SB_metadata_df.with_columns(
136133
pl.when(pl.col("bldg_id").hash() % 3 == 0)
137134
.then(pl.lit("Coned"))
138135
.when(pl.col("bldg_id").hash() % 3 == 1)
@@ -144,35 +141,22 @@ def map_electric_tariff(
144141

145142
sb_scenario = SBScenario(args.SB_scenario_type, args.SB_scenario_year)
146143
electrical_tariff_mapping_df = map_electric_tariff(
147-
SB_metadata_lazy_df=SB_metadata_lazy_df_with_electric_utility,
144+
SB_metadata_df=SB_metadata_df_with_electric_utility,
148145
electric_utility=args.electric_utility,
149146
SB_scenario=sb_scenario,
150147
state=args.state,
151148
)
152-
if args.output_dir:
153-
try:
154-
base_path = S3Path(args.output_dir)
155-
output_path = base_path / f"{args.electric_utility}_{sb_scenario}.csv"
156-
if not output_path.parent.exists():
157-
output_path.parent.mkdir(parents=True)
158-
electrical_tariff_mapping_df.sink_csv(
159-
str(output_path), storage_options=STORAGE_OPTIONS
160-
)
161-
except ValueError:
162-
base_path = Path(args.output_dir)
163-
output_path = base_path / f"{args.electric_utility}_{sb_scenario}.csv"
164-
if not output_path.parent.exists():
165-
output_path.parent.mkdir(parents=True)
166-
electrical_tariff_mapping_df.sink_csv(str(output_path))
167-
else:
168-
output_path = (
169-
RATE_DESIGN_DIR
170-
/ args.state.lower()
171-
/ "hp_rates"
172-
/ "data"
173-
/ "tariff_map"
174-
/ f"{args.electric_utility}_{sb_scenario}.csv"
149+
try:
150+
base_path = S3Path(args.output_dir)
151+
output_path = base_path / f"{args.electric_utility}_{sb_scenario}.csv"
152+
if not output_path.parent.exists():
153+
output_path.parent.mkdir(parents=True)
154+
electrical_tariff_mapping_df.sink_csv(
155+
str(output_path), storage_options=STORAGE_OPTIONS
175156
)
157+
except ValueError:
158+
base_path = Path(args.output_dir)
159+
output_path = base_path / f"{args.electric_utility}_{sb_scenario}.csv"
176160
if not output_path.parent.exists():
177161
output_path.parent.mkdir(parents=True)
178162
electrical_tariff_mapping_df.sink_csv(str(output_path))

0 commit comments

Comments
 (0)