From 0353269717c6a1815a4950d217176d36fd4bcdfd Mon Sep 17 00:00:00 2001 From: Jimmy Tung Date: Tue, 8 Jul 2025 10:18:50 +1000 Subject: [PATCH 1/6] Added support for load/gen vMinPu and vMaxPu values, and ctPrimScalingFactor. Signed-off-by: Jimmy Tung --- changelog.md | 4 ++- src/zepben/eas/client/eas_client.py | 45 ++++++++++++++------------- src/zepben/eas/client/work_package.py | 31 ++++++++++++------ test/test_eas_client.py | 9 ++++-- 4 files changed, 55 insertions(+), 34 deletions(-) diff --git a/changelog.md b/changelog.md index 55761c5..a286b31 100644 --- a/changelog.md +++ b/changelog.md @@ -4,7 +4,9 @@ * None. ### New Features -* None. +* Modification to `ModelConfig` to allow more customization for model generation + * Added support for separate `vMinPu` and `vMaxPu` with load and generators. + * Added support for `ctPrimScalingFactor` which is required when calculating new `ctPrim` value when feeder proxy loads are not in use. ### Enhancements * None. diff --git a/src/zepben/eas/client/eas_client.py b/src/zepben/eas/client/eas_client.py index 02d2bca..645f908 100644 --- a/src/zepben/eas/client/eas_client.py +++ b/src/zepben/eas/client/eas_client.py @@ -234,7 +234,7 @@ async def async_get_work_package_cost_estimation(self, work_package: WorkPackage ] } if isinstance(config.load_time, TimePeriod) else None, "fixedTime": config.load_time and { - "loadTime": config.load_time.time.isoformat(), + "loadTime": config.load_time.load_time.isoformat(), "overrides": config.load_time.load_overrides and [ { "loadId": key, @@ -260,7 +260,7 @@ async def async_get_work_package_cost_estimation(self, work_package: WorkPackage for key, value in work_package.syf_config.load_time.load_overrides.items()} } if isinstance(work_package.syf_config.load_time, TimePeriod) else None, "fixedTime": work_package.syf_config.load_time and { - "loadTime": work_package.syf_config.load_time.fetch_load_time.isoformat(), + "loadTime": work_package.syf_config.load_time.load_time.isoformat(), "overrides": work_package.syf_config.load_time.load_overrides and { key: value.__dict__ for key, value in work_package.syf_config.load_time.load_overrides.items()} @@ -270,8 +270,10 @@ async def async_get_work_package_cost_estimation(self, work_package: WorkPackage "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, + "loadVMinPu": work_package.generator_config.model.load_vmin_pu, + "loadVMaxPu": work_package.generator_config.model.load_vmax_pu, + "genVMinPu": work_package.generator_config.model.gen_vmin_pu, + "genVMaxPu": work_package.generator_config.model.gen_vmax_pu, "loadModel": work_package.generator_config.model.load_model, "collapseSWER": work_package.generator_config.model.collapse_swer, "calibration": work_package.generator_config.model.calibration, @@ -320,6 +322,7 @@ async def async_get_work_package_cost_estimation(self, work_package: WorkPackage "defaultLoadVar": work_package.generator_config.model.default_load_var, "defaultGenVar": work_package.generator_config.model.default_gen_var, "transformerTapSettings": work_package.generator_config.model.transformer_tap_settings, + "ctPrimScalingFactor": work_package.generator_config.model.ct_prim_scaling_factor, }, "solve": work_package.generator_config.solve and { "normVMinPu": work_package.generator_config.solve.norm_vmin_pu, @@ -465,7 +468,7 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag ] } if isinstance(config.load_time, TimePeriod) else None, "fixedTime": config.load_time and { - "loadTime": config.load_time.time.isoformat(), + "loadTime": config.load_time.load_time.isoformat(), "overrides": config.load_time.load_overrides and [ { "loadId": key, @@ -491,7 +494,7 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag for key, value in work_package.syf_config.load_time.load_overrides.items()} } if isinstance(work_package.syf_config.load_time, TimePeriod) else None, "fixedTime": work_package.syf_config.load_time and { - "loadTime": work_package.syf_config.load_time.time.isoformat(), + "loadTime": work_package.syf_config.load_time.load_time.isoformat(), "overrides": work_package.syf_config.load_time.load_overrides and { key: value.__dict__ for key, value in work_package.syf_config.load_time.load_overrides.items()} @@ -501,8 +504,8 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag "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, + "vMinPu": work_package.generator_config.model.load_vmin_pu, + "vMaxPu": work_package.generator_config.model.load_vmax_pu, "loadModel": work_package.generator_config.model.load_model, "collapseSWER": work_package.generator_config.model.collapse_swer, "calibration": work_package.generator_config.model.calibration, @@ -1045,17 +1048,17 @@ async def async_run_opendss_export(self, config: OpenDssConfig): }, "modulesConfiguration": { "common": { - **({"fixedTime": {"loadTime": config.load_time.time.isoformat(), - "overrides": config.load_time.load_overrides and [ - { - "loadId": key, - "loadWattsOverride": value.load_watts, - "genWattsOverride": value.gen_watts, - "loadVarOverride": value.load_var, - "genVarOverride": value.gen_var, - } for key, value in config.load_time.load_overrides.items() - ] - }} if isinstance(config.load_time, FixedTime) else {}), + **({"fixedTime": {"loadTime": config.load_time.load_time.isoformat(), + "overrides": config.load_time.load_overrides and [ + { + "loadId": key, + "loadWattsOverride": value.load_watts, + "genWattsOverride": value.gen_watts, + "loadVarOverride": value.load_var, + "genVarOverride": value.gen_var, + } for key, value in config.load_time.load_overrides.items() + ] + }} if isinstance(config.load_time, FixedTime) else {}), **({"timePeriod": { "startTime": config.load_time.start_time.isoformat(), "endTime": config.load_time.end_time.isoformat(), @@ -1073,8 +1076,8 @@ async def async_run_opendss_export(self, config: OpenDssConfig): **({"generator": { **({"model": { "vmPu": config.generator_config.model.vm_pu, - "vMinPu": config.generator_config.model.vmin_pu, - "vMaxPu": config.generator_config.model.vmax_pu, + "vMinPu": config.generator_config.model.load_vmin_pu, + "vMaxPu": config.generator_config.model.load_vmax_pu, "loadModel": config.generator_config.model.load_model, "collapseSWER": config.generator_config.model.collapse_swer, "calibration": config.generator_config.model.calibration, diff --git a/src/zepben/eas/client/work_package.py b/src/zepben/eas/client/work_package.py index 66ec675..0668fda 100644 --- a/src/zepben/eas/client/work_package.py +++ b/src/zepben/eas/client/work_package.py @@ -145,8 +145,8 @@ class FixedTime: present for the provided time in the load database for accurate results. """ - def __init__(self, time: datetime, load_overrides: Optional[Dict[str, FixedTimeLoadOverride]] = None): - self.time = time.replace(tzinfo=None) + def __init__(self, load_time: datetime, load_overrides: Optional[Dict[str, FixedTimeLoadOverride]] = None): + self.load_time = load_time.replace(tzinfo=None) self.load_overrides = load_overrides @@ -212,17 +212,25 @@ class ModelConfig: vm_pu: Optional[float] = None """Voltage per-unit of voltage source.""" - vmin_pu: Optional[float] = None + load_vmin_pu: Optional[float] = None """ - Minimum per unit voltage for which the load model selected and generator model is assumed to apply. Below this value, the load/gen model reverts to a - constant impedance model. For generator model used, this is used to determine the upper current limit. For example, if Vminpu is 0.90 then the current - limit is (1/0.90) = 111%. + Minimum per unit voltage for which the load model selected is assumed to apply. Below this value, the load model reverts to a constant impedance model. """ - vmax_pu: Optional[float] = None + load_vmax_pu: Optional[float] = None """ - Maximum per unit voltage for which the load model selected and generator model is assumed to apply. Above this value, the load/gen model reverts to a - constant impedance model. + Maximum per unit voltage for which the load model selected is assumed to apply. Above this value, the load model reverts to a constant impedance model. + """ + + gen_vmin_pu: Optional[float] = None + """ + Minimum per unit voltage for which the generator model is assumed to apply. Below this value, the gen model reverts to a constant impedance model. + For generator model used, this is used to determine the upper current limit. For example, if Vminpu is 0.90 then the current limit is (1/0.90) = 111%. + """ + + gen_vmax_pu: Optional[float] = None + """ + Maximum per unit voltage for which the generator model is assumed to apply. Above this value, the gen model reverts to a constant impedance model. """ load_model: Optional[int] = None @@ -438,6 +446,11 @@ class ModelConfig: The name of the set of distribution transformer tap settings to be applied to the model from an external source. """ + ct_prim_scaling_factor: Optional[float] = None + """ + Optional setting for scaling factor of calculated CTPrim for zone sub transformers. + """ + class SolveMode(Enum): YEARLY = "YEARLY" diff --git a/test/test_eas_client.py b/test/test_eas_client.py index 148a843..e22bfcf 100644 --- a/test/test_eas_client.py +++ b/test/test_eas_client.py @@ -904,8 +904,10 @@ def run_opendss_export_request_handler(request): generator_config=GeneratorConfig( ModelConfig( vm_pu=1.0, - vmin_pu=0.80, - vmax_pu=1.15, + load_vmin_pu=0.80, + load_vmax_pu=1.15, + gen_vmin_pu=0.50, + gen_vmax_pu=2.00, load_model=1, collapse_swer=False, calibration=False, @@ -954,7 +956,8 @@ def run_opendss_export_request_handler(request): default_gen_watts=[50.0, 150.0, 250.0], default_load_var=[10.0, 20.0, 30.0], default_gen_var=[5.0, 15.0, 25.0], - transformer_tap_settings="tap-3" + transformer_tap_settings="tap-3", + ct_prim_scaling_factor= 2.0 ), SolveConfig( norm_vmin_pu=0.9, From 3aab950576595a5309f90d9bbd3727616072b44a Mon Sep 17 00:00:00 2001 From: Jimmy Tung Date: Tue, 8 Jul 2025 10:40:16 +1000 Subject: [PATCH 2/6] Move changelog to proper section Signed-off-by: Jimmy Tung --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index a286b31..dc84a02 100644 --- a/changelog.md +++ b/changelog.md @@ -1,7 +1,7 @@ # EAS Python client ## [0.20.0] - UNRELEASED ### Breaking Changes -* None. +* `FixedTimeLoadOverride` now takes in optional list of floats instead of optional float for its variable. ### New Features * Modification to `ModelConfig` to allow more customization for model generation From 976b2eddff4136d346b943439efede6ad508189b Mon Sep 17 00:00:00 2001 From: Jimmy Tung Date: Wed, 30 Jul 2025 11:48:26 +1000 Subject: [PATCH 3/6] Rebase and fix missing variable in config for parts of eas_client.py Signed-off-by: Jimmy Tung --- src/zepben/eas/client/eas_client.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/zepben/eas/client/eas_client.py b/src/zepben/eas/client/eas_client.py index 645f908..c6945dc 100644 --- a/src/zepben/eas/client/eas_client.py +++ b/src/zepben/eas/client/eas_client.py @@ -504,8 +504,10 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag "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.load_vmin_pu, - "vMaxPu": work_package.generator_config.model.load_vmax_pu, + "loadVMinPu": work_package.generator_config.model.load_vmin_pu, + "loadVMaxPu": work_package.generator_config.model.load_vmax_pu, + "genVMinPu": work_package.generator_config.model.gen_vmin_pu, + "genVMaxPu": work_package.generator_config.model.gen_vmax_pu, "loadModel": work_package.generator_config.model.load_model, "collapseSWER": work_package.generator_config.model.collapse_swer, "calibration": work_package.generator_config.model.calibration, @@ -1076,8 +1078,10 @@ async def async_run_opendss_export(self, config: OpenDssConfig): **({"generator": { **({"model": { "vmPu": config.generator_config.model.vm_pu, - "vMinPu": config.generator_config.model.load_vmin_pu, - "vMaxPu": config.generator_config.model.load_vmax_pu, + "loadVMinPu": config.generator_config.model.load_vmin_pu, + "loadVMaxPu": config.generator_config.model.load_vmax_pu, + "genVMinPu": config.generator_config.model.gen_vmin_pu, + "genVMaxPu": config.generator_config.model.gen_vmax_pu, "loadModel": config.generator_config.model.load_model, "collapseSWER": config.generator_config.model.collapse_swer, "calibration": config.generator_config.model.calibration, From df2a3d16dc443b9ce560f580eec072cacdee2bdf Mon Sep 17 00:00:00 2001 From: Jimmy Tung Date: Wed, 30 Jul 2025 12:03:34 +1000 Subject: [PATCH 4/6] fix async get paged opendss models and tests Signed-off-by: Jimmy Tung --- src/zepben/eas/client/eas_client.py | 6 ++++-- test/test_eas_client.py | 12 ++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/zepben/eas/client/eas_client.py b/src/zepben/eas/client/eas_client.py index c6945dc..3d1a4af 100644 --- a/src/zepben/eas/client/eas_client.py +++ b/src/zepben/eas/client/eas_client.py @@ -1253,8 +1253,10 @@ async def async_get_paged_opendss_models( generator { model { vmPu - vMinPu - vMaxPu + loadVMinPu + loadVMaxPu + genVMinPu + genVMaxPu loadModel collapseSWER calibration diff --git a/test/test_eas_client.py b/test/test_eas_client.py index e22bfcf..be9437e 100644 --- a/test/test_eas_client.py +++ b/test/test_eas_client.py @@ -805,8 +805,10 @@ def run_opendss_export_request_handler(request): "generator": { "model": { "vmPu": 1.0, - "vMinPu": 0.80, - "vMaxPu": 1.15, + "loadVMinPu": 0.80, + "loadVMaxPu": 1.15, + "genVMinPu": 0.50, + "genVMaxPu": 2.00, "loadModel": 1, "collapseSWER": False, "calibration": False, @@ -1073,8 +1075,10 @@ def test_run_opendss_export_valid_certificate_success(ca: trustme.CA, httpserver generator { model { vmPu - vMinPu - vMaxPu + loadVMinPu + loadVMaxPu + genVMinPu + genVMaxPu loadModel collapseSWER calibration From a2ab9fdbdae7084ca8598f939fe69840ffbdb6c5 Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 30 Jul 2025 15:31:06 +1000 Subject: [PATCH 5/6] add to other queries Signed-off-by: vince --- src/zepben/eas/client/eas_client.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/zepben/eas/client/eas_client.py b/src/zepben/eas/client/eas_client.py index 3d1a4af..45dd344 100644 --- a/src/zepben/eas/client/eas_client.py +++ b/src/zepben/eas/client/eas_client.py @@ -555,7 +555,8 @@ async def async_run_hosting_capacity_work_package(self, work_package: WorkPackag "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, - "transformerTapSettings": work_package.generator_config.model.transformer_tap_settings + "transformerTapSettings": work_package.generator_config.model.transformer_tap_settings, + "ctPrimScalingFactor": work_package.generator_config.model.ct_prim_scaling_factor, }, "solve": work_package.generator_config.solve and { "normVMinPu": work_package.generator_config.solve.norm_vmin_pu, @@ -1129,7 +1130,8 @@ async def async_run_opendss_export(self, config: OpenDssConfig): "defaultGenWatts": config.generator_config.model.default_gen_watts, "defaultLoadVar": config.generator_config.model.default_load_var, "defaultGenVar": config.generator_config.model.default_gen_var, - "transformerTapSettings": config.generator_config.model.transformer_tap_settings + "transformerTapSettings": config.generator_config.model.transformer_tap_settings, + "ctPrimScalingFactor": work_package.generator_config.model.ct_prim_scaling_factor, }} if config.generator_config.model else {}), **({"solve": { "normVMinPu": config.generator_config.solve.norm_vmin_pu, @@ -1301,7 +1303,8 @@ async def async_get_paged_opendss_models( defaultGenWatts defaultLoadVar defaultGenVar - transformerTapSettings + transformerTapSettings, + ctPrimScalingFactor } solve { normVMinPu From 3859f117a23660e0969b4f884c2cccaa9fe14a5f Mon Sep 17 00:00:00 2001 From: vince Date: Wed, 30 Jul 2025 15:39:01 +1000 Subject: [PATCH 6/6] fix test Signed-off-by: vince --- src/zepben/eas/client/eas_client.py | 4 ++-- test/test_eas_client.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/zepben/eas/client/eas_client.py b/src/zepben/eas/client/eas_client.py index 45dd344..029b08d 100644 --- a/src/zepben/eas/client/eas_client.py +++ b/src/zepben/eas/client/eas_client.py @@ -1131,7 +1131,7 @@ async def async_run_opendss_export(self, config: OpenDssConfig): "defaultLoadVar": config.generator_config.model.default_load_var, "defaultGenVar": config.generator_config.model.default_gen_var, "transformerTapSettings": config.generator_config.model.transformer_tap_settings, - "ctPrimScalingFactor": work_package.generator_config.model.ct_prim_scaling_factor, + "ctPrimScalingFactor": config.generator_config.model.ct_prim_scaling_factor, }} if config.generator_config.model else {}), **({"solve": { "normVMinPu": config.generator_config.solve.norm_vmin_pu, @@ -1303,7 +1303,7 @@ async def async_get_paged_opendss_models( defaultGenWatts defaultLoadVar defaultGenVar - transformerTapSettings, + transformerTapSettings ctPrimScalingFactor } solve { diff --git a/test/test_eas_client.py b/test/test_eas_client.py index be9437e..9ad38e5 100644 --- a/test/test_eas_client.py +++ b/test/test_eas_client.py @@ -863,7 +863,8 @@ def run_opendss_export_request_handler(request): "defaultGenWatts": [50.0, 150.0, 250.0], "defaultLoadVar": [10.0, 20.0, 30.0], "defaultGenVar": [5.0, 15.0, 25.0], - "transformerTapSettings": "tap-3" + "transformerTapSettings": "tap-3", + "ctPrimScalingFactor": 2.0 }, "solve": { "normVMinPu": 0.9, @@ -959,7 +960,7 @@ def run_opendss_export_request_handler(request): default_load_var=[10.0, 20.0, 30.0], default_gen_var=[5.0, 15.0, 25.0], transformer_tap_settings="tap-3", - ct_prim_scaling_factor= 2.0 + ct_prim_scaling_factor=2.0 ), SolveConfig( norm_vmin_pu=0.9, @@ -1124,6 +1125,7 @@ def test_run_opendss_export_valid_certificate_success(ca: trustme.CA, httpserver defaultLoadVar defaultGenVar transformerTapSettings + ctPrimScalingFactor } solve { normVMinPu