Skip to content

Commit a2349fb

Browse files
authored
[DEV-6652] allow leaving allocation_limit_per_year and year_range unspecified (#52)
--------- Signed-off-by: Marcus Koh <marcus.koh@zepben.com>
1 parent 3ad1370 commit a2349fb

File tree

4 files changed

+122
-46
lines changed

4 files changed

+122
-46
lines changed

changelog.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22
## [0.27.0] - UNRELEASED
33
### Breaking Changes
44
* Bumping `urllib3` to `v2.5.0`, and pulling in `zepben.auth` via the SDK.
5+
* EAS must support unspecified `allocationLimitPerYear` and `yearRange` in the intervention config.
56

67
### New Features
78
* None.
89

910
### Enhancements
10-
* None.
11+
* To reduce confusion when running certain classes of intervention, the following fields are no longe required in `InterventionConfig`,
12+
and are defaulted to sensible values server-side:
13+
* `yearRange`
14+
* `allocation_limit_per_year`
1115

1216
### Fixes
1317
* None.

src/zepben/eas/client/eas_client.py

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ def generator_config_to_json(self, generator_config: Optional[GeneratorConfig])
282282
}
283283
}
284284

285-
def work_package_config_to_json(self, work_package: Optional[WorkPackageConfig]) -> Optional[dict]:
285+
def work_package_config_to_json(self, work_package: WorkPackageConfig) -> dict:
286286
return {
287287
"feederConfigs": {
288288
"configs": [
@@ -379,44 +379,54 @@ def work_package_config_to_json(self, work_package: Optional[WorkPackageConfig])
379379
}
380380
}
381381
},
382-
"intervention": work_package.intervention and {
383-
"baseWorkPackageId": work_package.intervention.base_work_package_id,
384-
"yearRange": {
385-
"maxYear": work_package.intervention.year_range.max_year,
386-
"minYear": work_package.intervention.year_range.min_year
387-
},
388-
"allocationLimitPerYear": work_package.intervention.allocation_limit_per_year,
389-
"interventionType": work_package.intervention.intervention_type.name,
390-
"candidateGeneration": work_package.intervention.candidate_generation and {
391-
"type": work_package.intervention.candidate_generation.type.name,
392-
"interventionCriteriaName": work_package.intervention.candidate_generation.intervention_criteria_name,
393-
"voltageDeltaAvgThreshold": work_package.intervention.candidate_generation.voltage_delta_avg_threshold,
394-
"voltageUnderLimitHoursThreshold": work_package.intervention.candidate_generation.voltage_under_limit_hours_threshold,
395-
"voltageOverLimitHoursThreshold": work_package.intervention.candidate_generation.voltage_over_limit_hours_threshold,
396-
"tapWeightingFactorLowerThreshold": work_package.intervention.candidate_generation.tap_weighting_factor_lower_threshold,
397-
"tapWeightingFactorUpperThreshold": work_package.intervention.candidate_generation.tap_weighting_factor_upper_threshold,
398-
},
399-
"allocationCriteria": work_package.intervention.allocation_criteria,
400-
"specificAllocationInstance": work_package.intervention.specific_allocation_instance,
401-
"phaseRebalanceProportions": work_package.intervention.phase_rebalance_proportions and {
402-
"a": work_package.intervention.phase_rebalance_proportions.a,
403-
"b": work_package.intervention.phase_rebalance_proportions.b,
404-
"c": work_package.intervention.phase_rebalance_proportions.c
405-
},
406-
"dvms": work_package.intervention.dvms and {
407-
"lowerLimit": work_package.intervention.dvms.lower_limit,
408-
"upperLimit": work_package.intervention.dvms.upper_limit,
409-
"lowerPercentile": work_package.intervention.dvms.lower_percentile,
410-
"upperPercentile": work_package.intervention.dvms.upper_percentile,
411-
"maxIterations": work_package.intervention.dvms.max_iterations,
412-
"regulatorConfig": {
413-
"puTarget": work_package.intervention.dvms.regulator_config.pu_target,
414-
"puDeadbandPercent": work_package.intervention.dvms.regulator_config.pu_deadband_percent,
415-
"maxTapChangePerStep": work_package.intervention.dvms.regulator_config.max_tap_change_per_step,
416-
"allowPushToLimit": work_package.intervention.dvms.regulator_config.allow_push_to_limit
382+
"intervention": work_package.intervention and (
383+
{
384+
"baseWorkPackageId": work_package.intervention.base_work_package_id,
385+
"interventionType": work_package.intervention.intervention_type.name,
386+
"candidateGeneration": work_package.intervention.candidate_generation and {
387+
"type": work_package.intervention.candidate_generation.type.name,
388+
"interventionCriteriaName": work_package.intervention.candidate_generation.intervention_criteria_name,
389+
"voltageDeltaAvgThreshold": work_package.intervention.candidate_generation.voltage_delta_avg_threshold,
390+
"voltageUnderLimitHoursThreshold": work_package.intervention.candidate_generation.voltage_under_limit_hours_threshold,
391+
"voltageOverLimitHoursThreshold": work_package.intervention.candidate_generation.voltage_over_limit_hours_threshold,
392+
"tapWeightingFactorLowerThreshold": work_package.intervention.candidate_generation.tap_weighting_factor_lower_threshold,
393+
"tapWeightingFactorUpperThreshold": work_package.intervention.candidate_generation.tap_weighting_factor_upper_threshold,
394+
},
395+
"allocationCriteria": work_package.intervention.allocation_criteria,
396+
"specificAllocationInstance": work_package.intervention.specific_allocation_instance,
397+
"phaseRebalanceProportions": work_package.intervention.phase_rebalance_proportions and {
398+
"a": work_package.intervention.phase_rebalance_proportions.a,
399+
"b": work_package.intervention.phase_rebalance_proportions.b,
400+
"c": work_package.intervention.phase_rebalance_proportions.c
401+
},
402+
"dvms": work_package.intervention.dvms and {
403+
"lowerLimit": work_package.intervention.dvms.lower_limit,
404+
"upperLimit": work_package.intervention.dvms.upper_limit,
405+
"lowerPercentile": work_package.intervention.dvms.lower_percentile,
406+
"upperPercentile": work_package.intervention.dvms.upper_percentile,
407+
"maxIterations": work_package.intervention.dvms.max_iterations,
408+
"regulatorConfig": {
409+
"puTarget": work_package.intervention.dvms.regulator_config.pu_target,
410+
"puDeadbandPercent": work_package.intervention.dvms.regulator_config.pu_deadband_percent,
411+
"maxTapChangePerStep": work_package.intervention.dvms.regulator_config.max_tap_change_per_step,
412+
"allowPushToLimit": work_package.intervention.dvms.regulator_config.allow_push_to_limit
413+
}
417414
}
418-
}
419-
}
415+
} |
416+
(
417+
{ "allocationLimitPerYear": work_package.intervention.allocation_limit_per_year }
418+
if work_package.intervention.allocation_limit_per_year is not None else {}
419+
) |
420+
(
421+
{
422+
"yearRange": {
423+
"maxYear": work_package.intervention.year_range.max_year,
424+
"minYear": work_package.intervention.year_range.min_year
425+
}
426+
}
427+
if work_package.intervention.year_range is not None else {}
428+
)
429+
)
420430
}
421431

422432
def run_hosting_capacity_work_package(self, work_package: WorkPackageConfig):

src/zepben/eas/client/work_package.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -855,18 +855,18 @@ class InterventionConfig:
855855
The new work package should process a subset of its feeders, scenarios, and years.
856856
"""
857857

858-
year_range: YearRange
858+
intervention_type: InterventionClass
859+
"""The class of intervention to apply."""
860+
861+
year_range: Optional[YearRange] = None
859862
"""
860863
The range of years to search for and apply interventions.
861864
All years within this range should be included in the work package.
862865
"""
863866

864-
allocation_limit_per_year: int
867+
allocation_limit_per_year: Optional[int] = None
865868
"""The maximum number of interventions that can be applied per year."""
866869

867-
intervention_type: InterventionClass
868-
"""The class of intervention to apply."""
869-
870870
candidate_generation: Optional[CandidateGenerationConfig] = None
871871
"""
872872
The method of generating candidates for the intervention.

test/test_eas_client.py

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from werkzeug import Response
1818
from zepben.ewb.auth import ZepbenTokenFetcher
1919

20-
from zepben.eas import EasClient, Study, SolveConfig
20+
from zepben.eas import EasClient, Study, SolveConfig, InterventionConfig, YearRange
2121
from zepben.eas import FeederConfig, ForecastConfig, FixedTimeLoadOverride
2222
from zepben.eas.client.ingestor import IngestorConfigInput, IngestorRunsSortCriteriaInput, IngestorRunsFilterInput, \
2323
IngestorRunState, IngestorRuntimeKind
@@ -26,7 +26,7 @@
2626
Order
2727
from zepben.eas.client.study import Result
2828
from zepben.eas.client.work_package import FeederConfigs, TimePeriodLoadOverride, \
29-
FixedTime, NodeLevelResultsConfig, PVVoltVARVoltWattConfig
29+
FixedTime, NodeLevelResultsConfig, PVVoltVARVoltWattConfig, InterventionClass
3030
from zepben.eas.client.work_package import WorkPackageConfig, TimePeriod, GeneratorConfig, ModelConfig, \
3131
FeederScenarioAllocationStrategy, LoadPlacement, MeterPlacementConfig, SwitchMeterPlacementConfig, SwitchClass, \
3232
SolveMode, RawResultsConfig
@@ -1682,3 +1682,65 @@ def test_get_ingestor_run_list_all_filters_no_verify_success(httpserver: HTTPSer
16821682
)
16831683
httpserver.check_assertions()
16841684
assert res == {"result": "success"}
1685+
1686+
1687+
def test_work_package_config_to_json_omits_server_defaulted_fields_if_unspecified(httpserver: HTTPServer):
1688+
eas_client = EasClient(
1689+
LOCALHOST,
1690+
httpserver.port,
1691+
verify_certificate=False
1692+
)
1693+
1694+
wp_config = WorkPackageConfig(
1695+
name="wp",
1696+
syf_config=FeederConfigs([]),
1697+
intervention=InterventionConfig(
1698+
base_work_package_id="abc",
1699+
intervention_type=InterventionClass.COMMUNITY_BESS
1700+
)
1701+
)
1702+
json_config = eas_client.work_package_config_to_json(wp_config)
1703+
1704+
assert json_config["intervention"] == {
1705+
"baseWorkPackageId": "abc",
1706+
"interventionType": "COMMUNITY_BESS",
1707+
"candidateGeneration": None,
1708+
"allocationCriteria": None,
1709+
"specificAllocationInstance": None,
1710+
"phaseRebalanceProportions": None,
1711+
"dvms": None
1712+
}
1713+
1714+
def test_work_package_config_to_json_includes_server_defaulted_fields_if_specified(httpserver: HTTPServer):
1715+
eas_client = EasClient(
1716+
LOCALHOST,
1717+
httpserver.port,
1718+
verify_certificate=False
1719+
)
1720+
1721+
wp_config = WorkPackageConfig(
1722+
name="wp",
1723+
syf_config=FeederConfigs([]),
1724+
intervention=InterventionConfig(
1725+
base_work_package_id="abc",
1726+
year_range=YearRange(2020, 2025),
1727+
intervention_type=InterventionClass.COMMUNITY_BESS,
1728+
allocation_limit_per_year=5
1729+
)
1730+
)
1731+
json_config = eas_client.work_package_config_to_json(wp_config)
1732+
1733+
assert json_config["intervention"] == {
1734+
"baseWorkPackageId": "abc",
1735+
"yearRange": {
1736+
"maxYear": 2025,
1737+
"minYear": 2020
1738+
},
1739+
"interventionType": "COMMUNITY_BESS",
1740+
"candidateGeneration": None,
1741+
"allocationCriteria": None,
1742+
"specificAllocationInstance": None,
1743+
"phaseRebalanceProportions": None,
1744+
"dvms": None,
1745+
"allocationLimitPerYear": 5
1746+
}

0 commit comments

Comments
 (0)