Coverage for tests/test_fixed_plant_adjustments.py: 100%
38 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-16 23:05 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-16 23:05 +0000
1"""Tests for fixed plant seasonal adjustment helpers."""
3import pandas as pd
4import pytest
5from prepare_times_nz.stage_4.electricity.fixed_plant_adjustments import (
6 extract_season_from_timeslice,
7 format_fixed_plant_adjustment_output,
8 join_fixed_plants_to_renewable_availability,
9 prepare_renewable_availability_for_join,
10)
13def test_extract_season_from_timeslice_handles_full_and_parent_slices():
14 """
15 TIMES time slices should map cleanly onto the seasonal join key.
16 """
18 assert extract_season_from_timeslice("WIN-WK-P") == "WIN"
19 assert extract_season_from_timeslice("SPR-") == "SPR"
22def test_prepare_renewable_availability_for_join_adds_season_and_drops_year_zero():
23 """
24 Join prep should ignore interpolation rows and retain concrete curve years.
25 """
27 renewable = pd.DataFrame(
28 {
29 "TimeSlice": ["WIN-WK-P", "WIN-WE-N"],
30 "LimType": ["UP", "UP"],
31 "Attribute": ["NCAP_AF", "NCAP_AF"],
32 "NI": [0.6, 0.5],
33 "SI": [0.4, 0.3],
34 "Pset_PN": ["ELC_HydRR_*", "ELC_HydRR_*"],
35 "Year": [0, 2024],
36 }
37 )
39 result = prepare_renewable_availability_for_join(renewable)
41 assert result["Season"].tolist() == ["WIN"]
42 assert "Year" not in result.columns
45def test_join_fixed_plants_to_renewable_availability_matches_on_pset_and_season():
46 """
47 Fixed-plant season rows should expand to all matching renewable timeslices.
48 """
50 fixed_plants = pd.DataFrame(
51 {
52 "TechName": ["Hydro A", "Hydro A", "Hydro B"],
53 "TechCode": ["HydRR", "HydRR", "HydRR"],
54 "Pset_PN": ["ELC_HydRR_*", "ELC_HydRR_*", "ELC_HydRR_*"],
55 "Year": [2030, 2030, 2030],
56 "Region": ["NI", "NI", "SI"],
57 "Season": ["WIN", "SPR", "WIN"],
58 "Share": [1.0, 0.5, 1.0],
59 }
60 )
61 renewable = pd.DataFrame(
62 {
63 "TimeSlice": ["WIN-WK-P", "WIN-WE-N", "SPR-WK-D", "SPR-"],
64 "LimType": ["UP", "UP", "UP", "UP"],
65 "Attribute": ["NCAP_AF", "NCAP_AF", "NCAP_AF", "NCAP_AFS"],
66 "NI": [0.6, 0.5, 0.7, 0.8],
67 "SI": [0.4, 0.3, 0.6, 0.75],
68 "Pset_PN": ["ELC_HydRR_*"] * 4,
69 "Year": [2024, 2024, 2024, 2024],
70 }
71 )
73 result = join_fixed_plants_to_renewable_availability(fixed_plants, renewable)
75 assert result["TimeSlice"].tolist() == [
76 "SPR-",
77 "SPR-WK-D",
78 "WIN-WE-N",
79 "WIN-WK-P",
80 "WIN-WE-N",
81 "WIN-WK-P",
82 ]
83 assert result["Season"].tolist() == ["SPR", "SPR", "WIN", "WIN", "WIN", "WIN"]
84 assert result["Year"].tolist() == [2030, 2030, 2030, 2030, 2030, 2030]
85 assert result["NI"].tolist() == [0.8, 0.7, 0.5, 0.6, 0.5, 0.6]
86 assert result["SI"].tolist() == [0.75, 0.6, 0.3, 0.4, 0.3, 0.4]
89def test_format_fixed_plant_adjustment_output_creates_value_and_drops_helper_columns():
90 """
91 Downstream formatting should emit a reduced commissioning year and an
92 unmodified following year, then trim join-only fields.
93 """
95 joined = pd.DataFrame(
96 {
97 "TechName": ["Hydro A", "Hydro B"],
98 "TechCode": ["HydRR", "HydRR"],
99 "Pset_PN": ["ELC_HydRR_*", "ELC_HydRR_*"],
100 "Year": [2030, 2030],
101 "Region": ["NI", "SI"],
102 "Season": ["WIN", "WIN"],
103 "Share": [0.5, 0.25],
104 "TimeSlice": ["WIN-WK-P", "WIN-WK-P"],
105 "LimType": ["UP", "UP"],
106 "Attribute": ["NCAP_AF", "NCAP_AF"],
107 "NI": [0.6, 0.6],
108 "SI": [0.4, 0.4],
109 }
110 )
112 result = format_fixed_plant_adjustment_output(joined)
114 assert result["TechName"].tolist() == ["Hydro A", "Hydro A", "Hydro B", "Hydro B"]
115 assert result["Year"].tolist() == [2030, 2031, 2030, 2031]
116 assert result["Region"].tolist() == ["NI", "NI", "SI", "SI"]
117 assert result["Value"].tolist() == [0.3, 0.6, 0.1, 0.4]
118 assert "NI" not in result.columns
119 assert "SI" not in result.columns
120 assert "Pset_PN" not in result.columns
121 assert "TechCode" not in result.columns
122 assert "Season" not in result.columns
123 assert "Share" not in result.columns
126def test_join_fixed_plants_to_renewable_availability_raises_on_missing_match():
127 """
128 A missing seasonal renewable curve should fail loudly.
129 """
131 fixed_plants = pd.DataFrame(
132 {
133 "TechName": ["Solar A"],
134 "TechCode": ["SolarTrack"],
135 "Pset_PN": ["ELC_SolarTrack_*"],
136 "Year": [2030],
137 "Region": ["NI"],
138 "Season": ["SUM"],
139 "Share": [1.0],
140 }
141 )
142 renewable = pd.DataFrame(
143 {
144 "TimeSlice": ["WIN-WK-P"],
145 "LimType": ["FX"],
146 "Attribute": ["NCAP_AF"],
147 "NI": [0.9],
148 "SI": [0.8],
149 "Pset_PN": ["ELC_SolarTrack_*"],
150 "Year": [2024],
151 }
152 )
154 with pytest.raises(ValueError, match="could not be matched"):
155 join_fixed_plants_to_renewable_availability(fixed_plants, renewable)