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
3 changes: 2 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
* `rating_threshold`
* `simplify_plsi_threshold`
* `emerg_amp_scaling`
* Added optional field `inverterControlConfig` to `ModelConfig`. This `PVVoltVARVoltWattConfig` allows the configuration of advanced inverter control profiles.

### Enhancements
* None.

### Fixes
* None.
* `TimePeriod` no longer truncates the `start_time` and `end_time` to midnight(`00:00:00`). `TimePeriod` will now preserve arbitrary start and end times to minute precision.

### Notes
* None.
Expand Down
12 changes: 11 additions & 1 deletion src/zepben/eas/client/eas_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,12 @@ def generator_config_to_json(self, generator_config: Optional[GeneratorConfig])
"useSpanLevelThreshold": generator_config.model.use_span_level_threshold,
"ratingThreshold": generator_config.model.rating_threshold,
"simplifyPLSIThreshold": generator_config.model.simplify_plsi_threshold,
"emergAmpScaling": generator_config.model.emerg_amp_scaling
"emergAmpScaling": generator_config.model.emerg_amp_scaling,
"inverterControlConfig": generator_config.model.inverter_control_config and {
"cutOffDate": generator_config.model.inverter_control_config.cut_off_date and generator_config.model.inverter_control_config.cut_off_date.isoformat(),
"beforeCutOffProfile": generator_config.model.inverter_control_config.beforeCutOffProfile,
"afterCutOffProfile": generator_config.model.inverter_control_config.afterCutOffProfile
}
},
"solve": generator_config.solve and {
"normVMinPu": generator_config.solve.norm_vmin_pu,
Expand Down Expand Up @@ -1330,6 +1335,11 @@ async def async_get_paged_opendss_models(
ratingThreshold
simplifyPLSIThreshold
emergAmpScaling
inverterControlConfig {
cutOffDate
beforeCutOffProfile
afterCutOffProfile
}
}
solve {
normVMinPu
Expand Down
28 changes: 25 additions & 3 deletions src/zepben/eas/client/work_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"LoadPlacement",
"FeederScenarioAllocationStrategy",
"MeterPlacementConfig",
"PVVoltVARVoltWattConfig",
"ModelConfig",
"SolveMode",
"SolveConfig",
Expand Down Expand Up @@ -147,7 +148,7 @@ class FixedTime:
"""

def __init__(self, load_time: datetime, load_overrides: Optional[Dict[str, FixedTimeLoadOverride]] = None):
self.load_time = load_time.replace(tzinfo=None)
self.load_time = load_time.replace(second=0, microsecond=0, tzinfo=None)
self.load_overrides = load_overrides


Expand All @@ -165,8 +166,8 @@ def __init__(
load_overrides: Optional[Dict[str, TimePeriodLoadOverride]] = None
):
self._validate(start_time, end_time)
self.start_time = start_time.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=None)
self.end_time = end_time.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=None)
self.start_time = start_time.replace(second=0, microsecond=0, tzinfo=None)
self.end_time = end_time.replace(second=0, microsecond=0, tzinfo=None)
self.load_overrides = load_overrides

@staticmethod
Expand Down Expand Up @@ -208,6 +209,22 @@ class MeterPlacementConfig:
"""The ID of the meter group to use for populating EnergyMeters at EnergyConsumers."""


@dataclass
class PVVoltVARVoltWattConfig:
cut_off_date: Optional[datetime] = None
"""Optional cut-off date to determine which profile to apply to equipment during translation to the OpenDss model.
If supplied, the "commissionedDate" of the equipment is compared against this date, equipment that do not have a
"commissionedDate" will receive the [beforeCutOffProfile]. If null, the [afterCutOffProfile] profile is applied to all equipment."""

beforeCutOffProfile: Optional[str] = None
"""Optional name of the profile to apply to equipment with a "commissionDate" before [cutOffDate].
If null the equipment will be translated into a regular Generator the rather a PVSystem."""

afterCutOffProfile: Optional[str] = None
"""Optional name of the profile to apply to equipment with a "commissionDate" after [cutOffDate].
If null the equipment will be translated into a regular Generator the rather a PVSystem."""


@dataclass
class ModelConfig:
vm_pu: Optional[float] = None
Expand Down Expand Up @@ -492,6 +509,11 @@ class ModelConfig:
Set as a factor value, i.e put as 1.5 if scaling is 150%
"""

inverter_control_config: Optional[PVVoltVARVoltWattConfig] = None
"""
Optional configuration object to enable modelling generation equipment as PVSystems controlled by InvControls rather than Generators.
"""


class SolveMode(Enum):
YEARLY = "YEARLY"
Expand Down
36 changes: 27 additions & 9 deletions test/test_eas_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
Order
from zepben.eas.client.study import Result
from zepben.eas.client.work_package import FeederConfigs, TimePeriodLoadOverride, \
FixedTime, NodeLevelResultsConfig
FixedTime, NodeLevelResultsConfig, PVVoltVARVoltWattConfig
from zepben.eas.client.work_package import WorkPackageConfig, TimePeriod, GeneratorConfig, ModelConfig, \
FeederScenarioAllocationStrategy, LoadPlacement, MeterPlacementConfig, SwitchMeterPlacementConfig, SwitchClass, \
SolveMode, RawResultsConfig
Expand Down Expand Up @@ -195,8 +195,8 @@ def test_get_work_package_cost_estimation_no_verify_success(httpserver: HTTPServ
[1],
["scenario"],
TimePeriod(
datetime(2022, 1, 1),
datetime(2022, 1, 2),
datetime(2022, 1, 1, 10),
datetime(2022, 1, 2, 12),
None
)
)
Expand Down Expand Up @@ -753,6 +753,7 @@ def hosting_capacity_run_calibration_with_calibration_time_request_handler(reque
'fixUndersizedServiceLines': None,
'genVMaxPu': None,
'genVMinPu': None,
'inverterControlConfig': None,
'loadIntervalLengthHours': None,
'loadModel': None,
'loadPlacement': None,
Expand Down Expand Up @@ -860,6 +861,7 @@ def hosting_capacity_run_calibration_with_generator_config_request_handler(reque
'fixUndersizedServiceLines': None,
'genVMaxPu': None,
'genVMinPu': None,
'inverterControlConfig': None,
'loadIntervalLengthHours': None,
'loadModel': None,
'loadPlacement': None,
Expand Down Expand Up @@ -961,6 +963,7 @@ def hosting_capacity_run_calibration_with_partial_model_config_request_handler(r
'fixUndersizedServiceLines': None,
'genVMaxPu': None,
'genVMinPu': None,
'inverterControlConfig': None,
'loadIntervalLengthHours': None,
'loadModel': None,
'loadPlacement': None,
Expand Down Expand Up @@ -1089,8 +1092,8 @@ def run_opendss_export_request_handler(request):
}]
}} if isinstance(OPENDSS_CONFIG.load_time, FixedTime) else
{"timePeriod": {
"startTime": "2022-04-01T00:00:00",
"endTime": "2023-04-01T00:00:00",
"startTime": "2022-04-01T10:13:00",
"endTime": "2023-04-01T12:14:00",
"overrides": [{
'loadId': 'meter1',
'loadWattsOverride': [1.0],
Expand Down Expand Up @@ -1169,7 +1172,12 @@ def run_opendss_export_request_handler(request):
"useSpanLevelThreshold": True,
"ratingThreshold": 20.0,
"simplifyPLSIThreshold": 20.0,
"emergAmpScaling": 1.8
"emergAmpScaling": 1.8,
'inverterControlConfig': {
'afterCutOffProfile': 'afterProfile',
'beforeCutOffProfile': 'beforeProfile',
'cutOffDate': '2024-04-12T11:42:00'
},
},
"solve": {
"normVMinPu": 0.9,
Expand Down Expand Up @@ -1214,8 +1222,8 @@ def run_opendss_export_request_handler(request):
year=2024,
feeder="feeder1",
load_time=TimePeriod(
datetime(2022, 4, 1),
datetime(2023, 4, 1),
datetime(2022, 4, 1, 10, 13),
datetime(2023, 4, 1, 12, 14),
{"meter1": TimePeriodLoadOverride([1.0], [2.0], [3.0], [4.0])}
),
model_name="TEST OPENDSS MODEL 1",
Expand Down Expand Up @@ -1282,7 +1290,12 @@ def run_opendss_export_request_handler(request):
use_span_level_threshold=True,
rating_threshold=20.0,
simplify_plsi_threshold=20.0,
emerg_amp_scaling= 1.8
emerg_amp_scaling=1.8,
inverter_control_config=PVVoltVARVoltWattConfig(
cut_off_date=datetime(2024, 4, 12, 11, 42),
beforeCutOffProfile="beforeProfile",
afterCutOffProfile="afterProfile"
)
),
SolveConfig(
norm_vmin_pu=0.9,
Expand Down Expand Up @@ -1464,6 +1477,11 @@ def test_run_opendss_export_valid_certificate_success(ca: trustme.CA, httpserver
ratingThreshold
simplifyPLSIThreshold
emergAmpScaling
inverterControlConfig {
cutOffDate
beforeCutOffProfile
afterCutOffProfile
}
}
solve {
normVMinPu
Expand Down