From 4abb31205818d3c431a04a297fa89b05a66c1312 Mon Sep 17 00:00:00 2001 From: poorva1209 Date: Thu, 18 Jun 2026 11:11:37 -0700 Subject: [PATCH 1/3] Add publish_period and interval to SimulationArgs --- gridappsd-python-lib/gridappsd/simulation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gridappsd-python-lib/gridappsd/simulation.py b/gridappsd-python-lib/gridappsd/simulation.py index c1b77bf..de24330 100644 --- a/gridappsd-python-lib/gridappsd/simulation.py +++ b/gridappsd-python-lib/gridappsd/simulation.py @@ -58,8 +58,8 @@ class ModelCreationConfig(ConfigBase): class SimulationArgs(ConfigBase): start_time: str = field(default="1655321830") duration: str = field(default="300") - timestep_frequency: str = field(default="1000") - timestep_increment: str = field(default="1000") + publish_period: str = field(default="60") + interval: str = field(default="60") run_realtime: bool = field(default=True) pause_after_measurements: bool = field(default=False) simulation_name: str = field(default="ieee13nodeckt") From 5fdd911963ea4a7e8e361a302773079516323a6f Mon Sep 17 00:00:00 2001 From: Andrew R Fisher Date: Thu, 18 Jun 2026 13:29:20 -0700 Subject: [PATCH 2/3] adding conditional defaults for publish_period and interval. --- gridappsd-python-lib/gridappsd/simulation.py | 15 ++- gridappsd-python-lib/tests/test_simulation.py | 95 ++++++++++--------- 2 files changed, 64 insertions(+), 46 deletions(-) diff --git a/gridappsd-python-lib/gridappsd/simulation.py b/gridappsd-python-lib/gridappsd/simulation.py index de24330..aa91bbd 100644 --- a/gridappsd-python-lib/gridappsd/simulation.py +++ b/gridappsd-python-lib/gridappsd/simulation.py @@ -58,12 +58,23 @@ class ModelCreationConfig(ConfigBase): class SimulationArgs(ConfigBase): start_time: str = field(default="1655321830") duration: str = field(default="300") - publish_period: str = field(default="60") - interval: str = field(default="60") + publish_period: str = field(default=None) + interval: str = field(default=None) run_realtime: bool = field(default=True) pause_after_measurements: bool = field(default=False) simulation_name: str = field(default="ieee13nodeckt") + def __post_init_(self): + if self.run_realtime: + self.interval = "1" + if not self.publish_period: + self.publish_period = "3" + else: + if not self.interval: + self.interval = "60" + if not self.publish_period: + self.publish_period = "60" + @dataclass class SimulatorArgs(ConfigBase): diff --git a/gridappsd-python-lib/tests/test_simulation.py b/gridappsd-python-lib/tests/test_simulation.py index 47dcceb..76dd8e2 100644 --- a/gridappsd-python-lib/tests/test_simulation.py +++ b/gridappsd-python-lib/tests/test_simulation.py @@ -16,50 +16,57 @@ @pytest.fixture def createGadObject(): - gad_user = os.environ.get('GRIDAPPSD_USER') - if gad_user is None: - os.environ['GRIDAPPSD_USER'] = 'system' - gad_password = os.environ.get('GRIDAPPSD_PASSWORD') - if gad_password is None: - os.environ['GRIDAPPSD_PASSWORD'] = 'manager' - return GridAPPSD() + gad_user = os.environ.get('GRIDAPPSD_USER') + if gad_user is None: + os.environ['GRIDAPPSD_USER'] = 'system' + gad_password = os.environ.get('GRIDAPPSD_PASSWORD') + if gad_password is None: + os.environ['GRIDAPPSD_PASSWORD'] = 'manager' + return GridAPPSD() @pytest.mark.integration def test_createSimulations(createGadObject): - gadObj = createGadObject - response = gadObj.query_model_info() - models = response.get("data", {}).get("models", {}) - start_time = int(datetime(year=2025, month=1, day=1, hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc).timestamp()) - simulationArgs = SimulationArgs(start_time=f"{start_time}", - duration="120", - run_realtime=False, - pause_after_measurements=False) - sim_config = SimulationConfig(simulation_config=simulationArgs) - modelsToRun = [ - "49AD8E07-3BF9-A4E2-CB8F-C3722F837B62", # IEEE 13 Node Test Feeder - "C1C3E687-6FFD-C753-582B-632A27E28507" # IEEE 123 Node Test Feeder - ] - for m in models: - if m.get("modelId") not in modelsToRun: - continue - line_name = m.get("modelId") - subregion_name = m.get("subRegionId") - region_name = m.get("regionId") - psc = PowerSystemConfig(Line_name=line_name, - SubGeographicalRegion_name=subregion_name, - GeographicalRegion_name=region_name) - sim_config.power_system_configs.append(psc) - sim_obj = Simulation(gapps=gadObj, run_config=sim_config) - def on_measurement(sim, ts, m): - global measurements_received - measurements_received += 1 - def on_simulation_complete(sim): - global simulation_is_complete - simulation_is_complete = True - sim_obj.add_onmeasurement_callback(on_measurement) - sim_obj.add_oncomplete_callback(on_simulation_complete) - sim_obj.start_simulation() - while not simulation_is_complete: - time.sleep(1) - assert measurements_received == 1 - gadObj.disconnect() + gadObj = createGadObject + response = gadObj.query_model_info() + models = response.get("data", {}).get("models", {}) + start_time = int(datetime(year=2025, + month=1, + day=1, + hour=0, + minute=0, + second=0, + microsecond=0, + tzinfo=timezone.utc).timestamp()) + simulationArgs = SimulationArgs(start_time=f"{start_time}", + duration="120", + run_realtime=False, + pause_after_measurements=False) + sim_config = SimulationConfig(simulation_config=simulationArgs) + modelsToRun = [ + "49AD8E07-3BF9-A4E2-CB8F-C3722F837B62", # IEEE 13 Node Test Feeder + "C1C3E687-6FFD-C753-582B-632A27E28507" # IEEE 123 Node Test Feeder + ] + for m in models: + if m.get("modelId") not in modelsToRun: + continue + line_name = m.get("modelId") + subregion_name = m.get("subRegionId") + region_name = m.get("regionId") + psc = PowerSystemConfig(Line_name=line_name, + SubGeographicalRegion_name=subregion_name, + GeographicalRegion_name=region_name) + sim_config.power_system_configs.append(psc) + sim_obj = Simulation(gapps=gadObj, run_config=sim_config) + def on_measurement(sim, ts, m): + global measurements_received + measurements_received += 1 + def on_simulation_complete(sim): + global simulation_is_complete + simulation_is_complete = True + sim_obj.add_onmeasurement_callback(on_measurement) + sim_obj.add_oncomplete_callback(on_simulation_complete) + sim_obj.start_simulation() + while not simulation_is_complete: + time.sleep(1) + assert measurements_received == 1 + gadObj.disconnect() From 26697a35ca50759c903938f6e7a7be0cb82cb519 Mon Sep 17 00:00:00 2001 From: Andrew R Fisher Date: Thu, 18 Jun 2026 14:05:31 -0700 Subject: [PATCH 3/3] added correct base types to simulation dataclass members, did a little error checking on some attributes to detect user errors. --- gridappsd-python-lib/gridappsd/simulation.py | 27 +++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/gridappsd-python-lib/gridappsd/simulation.py b/gridappsd-python-lib/gridappsd/simulation.py index aa91bbd..9a65592 100644 --- a/gridappsd-python-lib/gridappsd/simulation.py +++ b/gridappsd-python-lib/gridappsd/simulation.py @@ -42,11 +42,11 @@ def asdict(self): @dataclass class ModelCreationConfig(ConfigBase): - load_scaling_factor: str = field(default="1") + load_scaling_factor: float = field(default=1) schedule_name: str = field(default="ieeezipload") - z_fraction: str = field(default="0") - i_fraction: str = field(default="1") - p_fraction: str = field(default="0") + z_fraction: float = field(default=0) + i_fraction: float = field(default=1) + p_fraction: float = field(default=0) randomize_zipload_fractions: bool = field(default=False) use_houses: bool = field(default=False) @@ -56,24 +56,27 @@ class ModelCreationConfig(ConfigBase): @dataclass class SimulationArgs(ConfigBase): - start_time: str = field(default="1655321830") - duration: str = field(default="300") - publish_period: str = field(default=None) - interval: str = field(default=None) + start_time: int = field(default=1655321830) + duration: int = field(default=300) + publish_period: int = field(default=None) + interval: int = field(default=None) run_realtime: bool = field(default=True) pause_after_measurements: bool = field(default=False) simulation_name: str = field(default="ieee13nodeckt") def __post_init_(self): if self.run_realtime: - self.interval = "1" + self.interval = 1 if not self.publish_period: - self.publish_period = "3" + self.publish_period = 3 else: if not self.interval: - self.interval = "60" + self.interval = 60 if not self.publish_period: - self.publish_period = "60" + self.publish_period = 60 + if self.publish_period < self.interval: + raise RuntimeError("A simulation's publishing_period cannot be less than the simulation's timestep " + f"interval. please make the publishing_period >= interval!") @dataclass