From ec4ff0835057bfe6b6103835a301466cae08a569 Mon Sep 17 00:00:00 2001 From: Roberto Marquez Date: Thu, 27 Feb 2025 18:20:37 +1100 Subject: [PATCH 1/8] WIP Signed-off-by: Roberto Marquez --- src/zepben/eas/client/eas_client.py | 35 ++++++++++++++--- src/zepben/eas/client/work_package.py | 56 +++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/src/zepben/eas/client/eas_client.py b/src/zepben/eas/client/eas_client.py index d0bbabf..877d65e 100644 --- a/src/zepben/eas/client/eas_client.py +++ b/src/zepben/eas/client/eas_client.py @@ -258,10 +258,10 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag "energyConsumerMeterGroup": work_package.generator_config.model.meter_placement_config.energy_consumer_meter_group } if work_package.generator_config.model.meter_placement_config is not None else None, "seed": work_package.generator_config.model.seed, - "defaultLoadWatts" : work_package.generator_config.model.default_load_watts, - "defaultGenWatts" : work_package.generator_config.model.default_gen_watts, - "defaultLoadVar" : work_package.generator_config.model.default_load_var, - "defaultGenVar" : work_package.generator_config.model.default_gen_var + "defaultLoadWatts": work_package.generator_config.model.default_load_watts, + "defaultGenWatts": work_package.generator_config.model.default_gen_watts, + "defaultLoadVar": work_package.generator_config.model.default_load_var, + "defaultGenVar": work_package.generator_config.model.default_gen_var } if work_package.generator_config.model is not None else None, "solve": { "normVMinPu": work_package.generator_config.solve.norm_vmin_pu, @@ -311,7 +311,32 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag } if work_package.result_processor_config.writer_config.output_writer_config.enhanced_metrics_config is not None else None } if work_package.result_processor_config.writer_config.output_writer_config is not None else None } if work_package.result_processor_config.writer_config is not None else None - } if work_package.result_processor_config is not None else None + } if work_package.result_processor_config is not None else None, + "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, + "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 + } + } } } } diff --git a/src/zepben/eas/client/work_package.py b/src/zepben/eas/client/work_package.py index b5dc96c..35020aa 100644 --- a/src/zepben/eas/client/work_package.py +++ b/src/zepben/eas/client/work_package.py @@ -515,6 +515,60 @@ class ResultProcessorConfig: """Where results should be stored (Parquet or Postgres) and which metrics to store""" +@dataclass +class YearRange: + min_year: int + max_year: int + + +@dataclass +class InterventionClass(Enum): + TARIFF_REFORM = "TARIFF_REFORM", + CONTROLLED_LOAD_HOT_WATER = "CONTROLLED_LOAD_HOT_WATER", + COMMUNITY_BESS = "COMMUNITY_BESS", + DISTRIBUTION_TX_OLTC = "DISTRIBUTION_TX_OLTC", + LV_STATCOMS = "LV_STATCOMS", + DVMS = "DVMS", + PHASE_REBALANCING = "PHASE_REBALANCING", + DISTRIBUTION_TAP_OPTIMIZATION = "DISTRIBUTION_TAP_OPTIMIZATION", + UNKNOWN = "UNKNOWN" + + +class CandidateGenerationType(Enum): + CRITERIA = "CRITERIA", + TAP_OPTIMIZATION = "TAP_OPTIMIZATION" + + +@dataclass +class CandidateGenerationConfig: + type: CandidateGenerationType + intervention_criteria_name: Optional[str] = None + voltage_delta_avg_threshold: Optional[float] = None + voltage_under_limit_hours_threshold: Optional[int] = None + voltage_over_limit_hours_threshold: Optional[int] = None + tap_weighting_factor_lower_threshold: Optional[float] = None + tap_weighting_factor_upper_threshold: Optional[float] = None + + +@dataclass +class PhaseRebalanceProportions: + a: float + b: float + c: float + + +@dataclass +class InterventionConfig: + base_work_package_id: str + year_range: YearRange + allocation_limit_per_year: int + intervention_type: InterventionClass + candidate_generation: Optional[CandidateGenerationConfig] = None + allocation_criteria: Optional[str] = None + specific_allocation_instance: Optional[str] = None + phase_rebalance_proportions: Optional[PhaseRebalanceProportions] = None + + @dataclass class WorkPackageConfig: """ A data class representing the configuration for a hosting capacity work package """ @@ -552,6 +606,8 @@ class WorkPackageConfig: result_processor_config: Optional[ResultProcessorConfig] = None """Configuration for processing and storing results""" + intervention: Optional[InterventionConfig] = None + @dataclass class WorkPackageProgress: From 8780d709cdb90b09ee11bf73bba0c3af2165397e Mon Sep 17 00:00:00 2001 From: Marcus Koh Date: Mon, 3 Mar 2025 22:39:36 +1100 Subject: [PATCH 2/8] fix candidate generation type Signed-off-by: Marcus Koh --- src/zepben/eas/client/eas_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zepben/eas/client/eas_client.py b/src/zepben/eas/client/eas_client.py index 877d65e..16e9e33 100644 --- a/src/zepben/eas/client/eas_client.py +++ b/src/zepben/eas/client/eas_client.py @@ -321,7 +321,7 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag "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, + "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, From 4908e86b58455b5fe572d34dab2e0438405d1790 Mon Sep 17 00:00:00 2001 From: Marcus Koh Date: Mon, 3 Mar 2025 23:51:27 +1100 Subject: [PATCH 3/8] Add stuff to __all__ Signed-off-by: Marcus Koh --- src/zepben/eas/client/work_package.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/zepben/eas/client/work_package.py b/src/zepben/eas/client/work_package.py index 35020aa..3794240 100644 --- a/src/zepben/eas/client/work_package.py +++ b/src/zepben/eas/client/work_package.py @@ -11,8 +11,12 @@ __all__ = [ "SwitchClass", "SwitchMeterPlacementConfig", + "CandidateGenerationConfig", + "CandidateGenerationType", "FixedTime", "TimePeriod", + "InterventionClass", + "InterventionConfig", "LoadPlacement", "FeederScenarioAllocationStrategy", "MeterPlacementConfig", @@ -30,7 +34,8 @@ "EnhancedMetricsConfig", "WriterType", "WriterOutputConfig", - "WriterConfig" + "WriterConfig", + "YearRange", ] From f17361b542ebc8361ce2d57561410966ad509c16 Mon Sep 17 00:00:00 2001 From: Marcus Koh Date: Fri, 28 Mar 2025 15:44:02 +1100 Subject: [PATCH 4/8] add dvms Signed-off-by: Marcus Koh --- src/zepben/eas/client/eas_client.py | 13 +++++++++++++ src/zepben/eas/client/work_package.py | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/zepben/eas/client/eas_client.py b/src/zepben/eas/client/eas_client.py index 16e9e33..64047bc 100644 --- a/src/zepben/eas/client/eas_client.py +++ b/src/zepben/eas/client/eas_client.py @@ -335,6 +335,19 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag "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 + } } } } diff --git a/src/zepben/eas/client/work_package.py b/src/zepben/eas/client/work_package.py index 3794240..3b5dcbf 100644 --- a/src/zepben/eas/client/work_package.py +++ b/src/zepben/eas/client/work_package.py @@ -562,6 +562,24 @@ class PhaseRebalanceProportions: c: float +@dataclass +class RegulatorConfig: + pu_target: float + pu_deadband_percent: float + max_tap_change_per_step: int + allow_push_to_limit: bool + + +@dataclass +class DvmsConfig: + lower_limit: float + upper_limit: float + lower_percentile: float + upper_percentile: float + max_iterations: int + regulator_config: RegulatorConfig + + @dataclass class InterventionConfig: base_work_package_id: str @@ -572,6 +590,7 @@ class InterventionConfig: allocation_criteria: Optional[str] = None specific_allocation_instance: Optional[str] = None phase_rebalance_proportions: Optional[PhaseRebalanceProportions] = None + dvms: Optional[DvmsConfig] = None @dataclass From a93a296be50d86a60c3bdb006b275f0d237aecb7 Mon Sep 17 00:00:00 2001 From: Marcus Koh Date: Fri, 28 Mar 2025 16:00:33 +1100 Subject: [PATCH 5/8] add to __all__ Signed-off-by: Marcus Koh --- src/zepben/eas/client/work_package.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zepben/eas/client/work_package.py b/src/zepben/eas/client/work_package.py index 3b5dcbf..b1b265f 100644 --- a/src/zepben/eas/client/work_package.py +++ b/src/zepben/eas/client/work_package.py @@ -13,6 +13,7 @@ "SwitchMeterPlacementConfig", "CandidateGenerationConfig", "CandidateGenerationType", + "DvmsConfig", "FixedTime", "TimePeriod", "InterventionClass", @@ -27,6 +28,7 @@ "MetricsResultsConfig", "StoredResultsConfig", "GeneratorConfig", + "RegulatorConfig", "ResultProcessorConfig", "WorkPackageConfig", "WorkPackageProgress", From 8a9e571ad1990e910fc9ac3e280de51dc6336c8b Mon Sep 17 00:00:00 2001 From: Marcus Koh Date: Thu, 10 Apr 2025 12:46:58 +1000 Subject: [PATCH 6/8] Nicer serialization Signed-off-by: Marcus Koh --- src/zepben/eas/client/eas_client.py | 71 +++++++++++++++-------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/zepben/eas/client/eas_client.py b/src/zepben/eas/client/eas_client.py index 64047bc..7d3e80b 100644 --- a/src/zepben/eas/client/eas_client.py +++ b/src/zepben/eas/client/eas_client.py @@ -212,8 +212,8 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag "endTime": work_package.load_time.end_time.isoformat(), } if isinstance(work_package.load_time, TimePeriod) else None, "qualityAssuranceProcessing": work_package.quality_assurance_processing, - "generatorConfig": { - "model": { + "generatorConfig": work_package.generator_config and { + "model": work_package.generator_config.model and { "vmPu": work_package.generator_config.model.vm_pu, "vMinPu": work_package.generator_config.model.vmin_pu, "vMaxPu": work_package.generator_config.model.vmax_pu, @@ -232,7 +232,7 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag "maxLoadServiceLineRatio": work_package.generator_config.model.max_load_service_line_ratio, "maxLoadLvLineRatio": work_package.generator_config.model.max_load_lv_line_ratio, "collapseLvNetworks": work_package.generator_config.model.collapse_lv_networks, - "feederScenarioAllocationStrategy": work_package.generator_config.model.feeder_scenario_allocation_strategy.name if work_package.generator_config.model.feeder_scenario_allocation_strategy is not None else None, + "feederScenarioAllocationStrategy": work_package.generator_config.model.feeder_scenario_allocation_strategy and work_package.generator_config.model.feeder_scenario_allocation_strategy.name, "closedLoopVRegEnabled": work_package.generator_config.model.closed_loop_v_reg_enabled, "closedLoopVRegReplaceAll": work_package.generator_config.model.closed_loop_v_reg_replace_all, "closedLoopVRegSetPoint": work_package.generator_config.model.closed_loop_v_reg_set_point, @@ -245,25 +245,26 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag "splitPhaseDefaultLoadLossPercentage": work_package.generator_config.model.split_phase_default_load_loss_percentage, "splitPhaseLVKV": work_package.generator_config.model.split_phase_lv_kv, "swerVoltageToLineVoltage": work_package.generator_config.model.swer_voltage_to_line_voltage, - "loadPlacement": work_package.generator_config.model.load_placement.name if work_package.generator_config.model.load_placement is not None else None, + "loadPlacement": work_package.generator_config.model.load_placement and work_package.generator_config.model.load_placement.name, "loadIntervalLengthHours": work_package.generator_config.model.load_interval_length_hours, - "meterPlacementConfig": { + "meterPlacementConfig": work_package.generator_config.model.meter_placement_config and { "feederHead": work_package.generator_config.model.meter_placement_config.feeder_head, "distTransformers": work_package.generator_config.model.meter_placement_config.dist_transformers, - "switchMeterPlacementConfigs": [{ - "meterSwitchClass": spc.meter_switch_class.name if spc.meter_switch_class is not None else None, - "namePattern": spc.name_pattern - } for spc in - work_package.generator_config.model.meter_placement_config.switch_meter_placement_configs] if work_package.generator_config.model.meter_placement_config.switch_meter_placement_configs is not None else None, + "switchMeterPlacementConfigs": work_package.generator_config.model.meter_placement_config.switch_meter_placement_configs and [ + { + "meterSwitchClass": spc.meter_switch_class and spc.meter_switch_class.name, + "namePattern": spc.name_pattern + } for spc in work_package.generator_config.model.meter_placement_config.switch_meter_placement_configs + ], "energyConsumerMeterGroup": work_package.generator_config.model.meter_placement_config.energy_consumer_meter_group - } if work_package.generator_config.model.meter_placement_config is not None else None, + }, "seed": work_package.generator_config.model.seed, "defaultLoadWatts": work_package.generator_config.model.default_load_watts, "defaultGenWatts": work_package.generator_config.model.default_gen_watts, "defaultLoadVar": work_package.generator_config.model.default_load_var, "defaultGenVar": work_package.generator_config.model.default_gen_var - } if work_package.generator_config.model is not None else None, - "solve": { + }, + "solve": work_package.generator_config.solve and { "normVMinPu": work_package.generator_config.solve.norm_vmin_pu, "normVMaxPu": work_package.generator_config.solve.norm_vmax_pu, "emergVMinPu": work_package.generator_config.solve.emerg_vmin_pu, @@ -272,32 +273,32 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag "voltageBases": work_package.generator_config.solve.voltage_bases, "maxIter": work_package.generator_config.solve.max_iter, "maxControlIter": work_package.generator_config.solve.max_control_iter, - "mode": work_package.generator_config.solve.mode.name if work_package.generator_config.solve.mode is not None else None, + "mode": work_package.generator_config.solve.mode and work_package.generator_config.solve.mode.name, "stepSizeMinutes": work_package.generator_config.solve.step_size_minutes - } if work_package.generator_config.solve is not None else None, - "rawResults": { + }, + "rawResults": work_package.generator_config.raw_results and { "energyMeterVoltagesRaw": work_package.generator_config.raw_results.energy_meter_voltages_raw, "energyMetersRaw": work_package.generator_config.raw_results.energy_meters_raw, "resultsPerMeter": work_package.generator_config.raw_results.results_per_meter, "overloadsRaw": work_package.generator_config.raw_results.overloads_raw, "voltageExceptionsRaw": work_package.generator_config.raw_results.voltage_exceptions_raw - } if work_package.generator_config.raw_results is not None else None - } if work_package.generator_config is not None else None, + } + }, "executorConfig": {}, - "resultProcessorConfig": { - "storedResults": { + "resultProcessorConfig": work_package.result_processor_config and { + "storedResults": work_package.result_processor_config.stored_results and { "energyMeterVoltagesRaw": work_package.result_processor_config.stored_results.energy_meter_voltages_raw, "energyMetersRaw": work_package.result_processor_config.stored_results.energy_meters_raw, "overloadsRaw": work_package.result_processor_config.stored_results.overloads_raw, "voltageExceptionsRaw": work_package.result_processor_config.stored_results.voltage_exceptions_raw, - } if work_package.result_processor_config.stored_results is not None else None, - "metrics": { + }, + "metrics": work_package.result_processor_config.metrics and { "calculatePerformanceMetrics": work_package.result_processor_config.metrics.calculate_performance_metrics - } if work_package.result_processor_config.metrics is not None else None, - "writerConfig": { - "writerType": work_package.result_processor_config.writer_config.writer_type.name if work_package.result_processor_config.writer_config.writer_type is not None else None, - "outputWriterConfig": { - "enhancedMetricsConfig": { + }, + "writerConfig": work_package.result_processor_config.writer_config and { + "writerType": work_package.result_processor_config.writer_config.writer_type and work_package.result_processor_config.writer_config.writer_type.name, + "outputWriterConfig": work_package.result_processor_config.writer_config.output_writer_config and { + "enhancedMetricsConfig": work_package.result_processor_config.writer_config.output_writer_config.enhanced_metrics_config and { "populateEnhancedMetrics": work_package.result_processor_config.writer_config.output_writer_config.enhanced_metrics_config.populate_enhanced_metrics, "populateEnhancedMetricsProfile": work_package.result_processor_config.writer_config.output_writer_config.enhanced_metrics_config.populate_enhanced_metrics_profile, "populateDurationCurves": work_package.result_processor_config.writer_config.output_writer_config.enhanced_metrics_config.populate_duration_curves, @@ -308,10 +309,10 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag "calculateNormalForGenThermal": work_package.result_processor_config.writer_config.output_writer_config.enhanced_metrics_config.calculate_normal_for_gen_thermal, "calculateEmergForGenThermal": work_package.result_processor_config.writer_config.output_writer_config.enhanced_metrics_config.calculate_emerg_for_gen_thermal, "calculateCO2": work_package.result_processor_config.writer_config.output_writer_config.enhanced_metrics_config.calculate_co2 - } if work_package.result_processor_config.writer_config.output_writer_config.enhanced_metrics_config is not None else None - } if work_package.result_processor_config.writer_config.output_writer_config is not None else None - } if work_package.result_processor_config.writer_config is not None else None - } if work_package.result_processor_config is not None else None, + } + } + } + }, "intervention": work_package.intervention and { "baseWorkPackageId": work_package.intervention.base_work_package_id, "yearRange": { @@ -492,15 +493,15 @@ async def async_upload_study(self, study: Study): "styles": study.styles, "results": [{ "name": result.name, - "geoJsonOverlay": { + "geoJsonOverlay": result.geo_json_overlay and { "data": result.geo_json_overlay.data, "sourceProperties": result.geo_json_overlay.source_properties, "styles": result.geo_json_overlay.styles - } if result.geo_json_overlay else None, - "stateOverlay": { + }, + "stateOverlay": result.state_overlay and { "data": result.state_overlay.data, "styles": result.state_overlay.styles - } if result.state_overlay else None, + }, "sections": [{ "type": section.type, "name": section.name, From 308ad42c45624b8f99597cb54b5ceffddfd7cb2c Mon Sep 17 00:00:00 2001 From: Marcus Koh Date: Thu, 10 Apr 2025 13:48:03 +1000 Subject: [PATCH 7/8] Add docstrings Signed-off-by: Marcus Koh --- src/zepben/eas/client/work_package.py | 88 +++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/zepben/eas/client/work_package.py b/src/zepben/eas/client/work_package.py index b1b265f..dc8bfd1 100644 --- a/src/zepben/eas/client/work_package.py +++ b/src/zepben/eas/client/work_package.py @@ -549,12 +549,46 @@ class CandidateGenerationType(Enum): @dataclass class CandidateGenerationConfig: type: CandidateGenerationType + """The type of method for generating the intervention candidates.""" + intervention_criteria_name: Optional[str] = None + """ + The ID of the set of criteria used to select intervention candidates from enhanced metrics of the + base work package run. Only used when type is CRITERIA. + """ + voltage_delta_avg_threshold: Optional[float] = None + """ + The threshold for average deviation in voltage p.u. across the transformer. Only used when type is TAP_OPTIMIZATION. + """ + voltage_under_limit_hours_threshold: Optional[int] = None + """ + The threshold for number of hours a transformer is below the nominal voltage range. + Only used when type is TAP_OPTIMIZATION. + """ + voltage_over_limit_hours_threshold: Optional[int] = None + """ + The threshold for number of hours a transformer is above the nominal voltage range. + Only used when type is TAP_OPTIMIZATION. + """ + tap_weighting_factor_lower_threshold: Optional[float] = None + """ + The minimum threshold for the tap weighting factor, used to determine when a positive tap adjustment + (increasing voltage) is prioritized. If the tap weighting factor falls below this threshold, it indicates that + the voltage is significantly under the desired range and requires corrective action. This setting is usually + negative. Only used when type is TAP_OPTIMIZATION. + """ + tap_weighting_factor_upper_threshold: Optional[float] = None + """ + The maximum threshold for the tap weighting factor, used to determine when a negative tap adjustment + (decreasing voltage) is prioritized. If the tap weighting factor exceeds this threshold, it indicates that + the voltage is significantly over the desired range and requires corrective action. This setting is usually + positive. Only used when type is TAP_OPTIMIZATION. + """ @dataclass @@ -567,32 +601,85 @@ class PhaseRebalanceProportions: @dataclass class RegulatorConfig: pu_target: float + """Voltage p.u. to move the average customer voltage towards.""" + pu_deadband_percent: float + """Width of window of voltages considered acceptable for the average customer voltage, in %p.u.""" + max_tap_change_per_step: int + """The maximum number of tap steps to move (in either direction) for each timestep.""" + allow_push_to_limit: bool + """ + If this is true, we allow the regulator to push some number of customers outside the specified limits for DVMS, + with the limit of customers given by lowerPercentile and upperPercentile in DvmsConfig. + """ @dataclass class DvmsConfig: lower_limit: float + """The lower limit of voltage (p.u.) considered acceptable for the purposes of DVMS.""" + upper_limit: float + """The lower limit of voltage (p.u.) considered acceptable for the purposes of DVMS.""" + lower_percentile: float + """The lowest percentile of customers' voltages to consider when applying DVMS.""" + upper_percentile: float + """The highest percentile of customers' voltages to consider when applying DVMS.""" + max_iterations: int + """The number of iterations to attempt DVMS for each timestep before moving on.""" + regulator_config: RegulatorConfig + """Configures the voltage regulator to apply if the zone is already satisfactory according to the above limits.""" @dataclass class InterventionConfig: base_work_package_id: str + """ + ID of the work package that this intervention is based on. + The new work package should process a subset of its feeders, scenarios, and years. + """ + year_range: YearRange + """ + 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 + """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. + This does not need to be specified for certain interventions, e.g. PHASE_REBALANCING. + """ + allocation_criteria: Optional[str] = None + """The ID of the set of criteria used to select an intervention instance for each candidate.""" + specific_allocation_instance: Optional[str] = None + """ + The specific instance of intervention to use for every allocation. If this is unspecified, + all instances of the intervention class will be considered when choosing one for each candidate. + """ + phase_rebalance_proportions: Optional[PhaseRebalanceProportions] = None + """ + The proportions to use for phase rebalancing. + If this is unspecified and intervention_type = PHASE_REBALANCING, phases will be rebalanced to equal proportions. + """ + dvms: Optional[DvmsConfig] = None + """The config for DVMS. This must be specified if intervention_type = DVMS.""" @dataclass @@ -633,6 +720,7 @@ class WorkPackageConfig: """Configuration for processing and storing results""" intervention: Optional[InterventionConfig] = None + """Configuration for applying an intervention""" @dataclass From ff9fbb2e5567a7b4edbb6a96be208665efc40940 Mon Sep 17 00:00:00 2001 From: Marcus Koh Date: Thu, 10 Apr 2025 13:56:07 +1000 Subject: [PATCH 8/8] fix docstring Signed-off-by: Marcus Koh --- src/zepben/eas/client/work_package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zepben/eas/client/work_package.py b/src/zepben/eas/client/work_package.py index dc8bfd1..992eba9 100644 --- a/src/zepben/eas/client/work_package.py +++ b/src/zepben/eas/client/work_package.py @@ -612,7 +612,7 @@ class RegulatorConfig: allow_push_to_limit: bool """ If this is true, we allow the regulator to push some number of customers outside the specified limits for DVMS, - with the limit of customers given by lowerPercentile and upperPercentile in DvmsConfig. + with the limit of customers given by lower_percentile and upper_percentile in DvmsConfig. """