Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@
## [0.27.0] - UNRELEASED
### Breaking Changes
* Bumping `urllib3` to `v2.5.0`, and pulling in `zepben.auth` via the SDK.
* EAS must support unspecified `allocationLimitPerYear` and `yearRange` in the intervention config.

### New Features
* None.

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

### Fixes
* None.
Expand Down
86 changes: 48 additions & 38 deletions src/zepben/eas/client/eas_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def generator_config_to_json(self, generator_config: Optional[GeneratorConfig])
}
}

def work_package_config_to_json(self, work_package: Optional[WorkPackageConfig]) -> Optional[dict]:
def work_package_config_to_json(self, work_package: WorkPackageConfig) -> dict:
return {
"feederConfigs": {
"configs": [
Expand Down Expand Up @@ -379,44 +379,54 @@ def work_package_config_to_json(self, work_package: Optional[WorkPackageConfig])
}
}
},
"intervention": work_package.intervention and {
"baseWorkPackageId": work_package.intervention.base_work_package_id,
"yearRange": {
"maxYear": work_package.intervention.year_range.max_year,
"minYear": work_package.intervention.year_range.min_year
},
"allocationLimitPerYear": work_package.intervention.allocation_limit_per_year,
"interventionType": work_package.intervention.intervention_type.name,
"candidateGeneration": work_package.intervention.candidate_generation and {
"type": work_package.intervention.candidate_generation.type.name,
"interventionCriteriaName": work_package.intervention.candidate_generation.intervention_criteria_name,
"voltageDeltaAvgThreshold": work_package.intervention.candidate_generation.voltage_delta_avg_threshold,
"voltageUnderLimitHoursThreshold": work_package.intervention.candidate_generation.voltage_under_limit_hours_threshold,
"voltageOverLimitHoursThreshold": work_package.intervention.candidate_generation.voltage_over_limit_hours_threshold,
"tapWeightingFactorLowerThreshold": work_package.intervention.candidate_generation.tap_weighting_factor_lower_threshold,
"tapWeightingFactorUpperThreshold": work_package.intervention.candidate_generation.tap_weighting_factor_upper_threshold,
},
"allocationCriteria": work_package.intervention.allocation_criteria,
"specificAllocationInstance": work_package.intervention.specific_allocation_instance,
"phaseRebalanceProportions": work_package.intervention.phase_rebalance_proportions and {
"a": work_package.intervention.phase_rebalance_proportions.a,
"b": work_package.intervention.phase_rebalance_proportions.b,
"c": work_package.intervention.phase_rebalance_proportions.c
},
"dvms": work_package.intervention.dvms and {
"lowerLimit": work_package.intervention.dvms.lower_limit,
"upperLimit": work_package.intervention.dvms.upper_limit,
"lowerPercentile": work_package.intervention.dvms.lower_percentile,
"upperPercentile": work_package.intervention.dvms.upper_percentile,
"maxIterations": work_package.intervention.dvms.max_iterations,
"regulatorConfig": {
"puTarget": work_package.intervention.dvms.regulator_config.pu_target,
"puDeadbandPercent": work_package.intervention.dvms.regulator_config.pu_deadband_percent,
"maxTapChangePerStep": work_package.intervention.dvms.regulator_config.max_tap_change_per_step,
"allowPushToLimit": work_package.intervention.dvms.regulator_config.allow_push_to_limit
"intervention": work_package.intervention and (
{
"baseWorkPackageId": work_package.intervention.base_work_package_id,
"interventionType": work_package.intervention.intervention_type.name,
"candidateGeneration": work_package.intervention.candidate_generation and {
"type": work_package.intervention.candidate_generation.type.name,
"interventionCriteriaName": work_package.intervention.candidate_generation.intervention_criteria_name,
"voltageDeltaAvgThreshold": work_package.intervention.candidate_generation.voltage_delta_avg_threshold,
"voltageUnderLimitHoursThreshold": work_package.intervention.candidate_generation.voltage_under_limit_hours_threshold,
"voltageOverLimitHoursThreshold": work_package.intervention.candidate_generation.voltage_over_limit_hours_threshold,
"tapWeightingFactorLowerThreshold": work_package.intervention.candidate_generation.tap_weighting_factor_lower_threshold,
"tapWeightingFactorUpperThreshold": work_package.intervention.candidate_generation.tap_weighting_factor_upper_threshold,
},
"allocationCriteria": work_package.intervention.allocation_criteria,
"specificAllocationInstance": work_package.intervention.specific_allocation_instance,
"phaseRebalanceProportions": work_package.intervention.phase_rebalance_proportions and {
"a": work_package.intervention.phase_rebalance_proportions.a,
"b": work_package.intervention.phase_rebalance_proportions.b,
"c": work_package.intervention.phase_rebalance_proportions.c
},
"dvms": work_package.intervention.dvms and {
"lowerLimit": work_package.intervention.dvms.lower_limit,
"upperLimit": work_package.intervention.dvms.upper_limit,
"lowerPercentile": work_package.intervention.dvms.lower_percentile,
"upperPercentile": work_package.intervention.dvms.upper_percentile,
"maxIterations": work_package.intervention.dvms.max_iterations,
"regulatorConfig": {
"puTarget": work_package.intervention.dvms.regulator_config.pu_target,
"puDeadbandPercent": work_package.intervention.dvms.regulator_config.pu_deadband_percent,
"maxTapChangePerStep": work_package.intervention.dvms.regulator_config.max_tap_change_per_step,
"allowPushToLimit": work_package.intervention.dvms.regulator_config.allow_push_to_limit
}
}
}
}
} |
(
{ "allocationLimitPerYear": work_package.intervention.allocation_limit_per_year }
if work_package.intervention.allocation_limit_per_year is not None else {}
) |
(
{
"yearRange": {
"maxYear": work_package.intervention.year_range.max_year,
"minYear": work_package.intervention.year_range.min_year
}
}
if work_package.intervention.year_range is not None else {}
)
)
}

def run_hosting_capacity_work_package(self, work_package: WorkPackageConfig):
Expand Down
10 changes: 5 additions & 5 deletions src/zepben/eas/client/work_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -855,18 +855,18 @@ class InterventionConfig:
The new work package should process a subset of its feeders, scenarios, and years.
"""

year_range: YearRange
intervention_type: InterventionClass
"""The class of intervention to apply."""

year_range: Optional[YearRange] = None
"""
The range of years to search for and apply interventions.
All years within this range should be included in the work package.
"""

allocation_limit_per_year: int
allocation_limit_per_year: Optional[int] = None
"""The maximum number of interventions that can be applied per year."""

intervention_type: InterventionClass
"""The class of intervention to apply."""

candidate_generation: Optional[CandidateGenerationConfig] = None
"""
The method of generating candidates for the intervention.
Expand Down
66 changes: 64 additions & 2 deletions test/test_eas_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from werkzeug import Response
from zepben.ewb.auth import ZepbenTokenFetcher

from zepben.eas import EasClient, Study, SolveConfig
from zepben.eas import EasClient, Study, SolveConfig, InterventionConfig, YearRange
from zepben.eas import FeederConfig, ForecastConfig, FixedTimeLoadOverride
from zepben.eas.client.ingestor import IngestorConfigInput, IngestorRunsSortCriteriaInput, IngestorRunsFilterInput, \
IngestorRunState, IngestorRuntimeKind
Expand All @@ -26,7 +26,7 @@
Order
from zepben.eas.client.study import Result
from zepben.eas.client.work_package import FeederConfigs, TimePeriodLoadOverride, \
FixedTime, NodeLevelResultsConfig, PVVoltVARVoltWattConfig
FixedTime, NodeLevelResultsConfig, PVVoltVARVoltWattConfig, InterventionClass
from zepben.eas.client.work_package import WorkPackageConfig, TimePeriod, GeneratorConfig, ModelConfig, \
FeederScenarioAllocationStrategy, LoadPlacement, MeterPlacementConfig, SwitchMeterPlacementConfig, SwitchClass, \
SolveMode, RawResultsConfig
Expand Down Expand Up @@ -1682,3 +1682,65 @@ def test_get_ingestor_run_list_all_filters_no_verify_success(httpserver: HTTPSer
)
httpserver.check_assertions()
assert res == {"result": "success"}


def test_work_package_config_to_json_omits_server_defaulted_fields_if_unspecified(httpserver: HTTPServer):
eas_client = EasClient(
LOCALHOST,
httpserver.port,
verify_certificate=False
)

wp_config = WorkPackageConfig(
name="wp",
syf_config=FeederConfigs([]),
intervention=InterventionConfig(
base_work_package_id="abc",
intervention_type=InterventionClass.COMMUNITY_BESS
)
)
json_config = eas_client.work_package_config_to_json(wp_config)

assert json_config["intervention"] == {
"baseWorkPackageId": "abc",
"interventionType": "COMMUNITY_BESS",
"candidateGeneration": None,
"allocationCriteria": None,
"specificAllocationInstance": None,
"phaseRebalanceProportions": None,
"dvms": None
}

def test_work_package_config_to_json_includes_server_defaulted_fields_if_specified(httpserver: HTTPServer):
eas_client = EasClient(
LOCALHOST,
httpserver.port,
verify_certificate=False
)

wp_config = WorkPackageConfig(
name="wp",
syf_config=FeederConfigs([]),
intervention=InterventionConfig(
base_work_package_id="abc",
year_range=YearRange(2020, 2025),
intervention_type=InterventionClass.COMMUNITY_BESS,
allocation_limit_per_year=5
)
)
json_config = eas_client.work_package_config_to_json(wp_config)

assert json_config["intervention"] == {
"baseWorkPackageId": "abc",
"yearRange": {
"maxYear": 2025,
"minYear": 2020
},
"interventionType": "COMMUNITY_BESS",
"candidateGeneration": None,
"allocationCriteria": None,
"specificAllocationInstance": None,
"phaseRebalanceProportions": None,
"dvms": None,
"allocationLimitPerYear": 5
}