11import ast
2-
2+ import os
3+ import time
34import helics as h
45import pandas as pd
56from loguru import logger
@@ -52,6 +53,21 @@ def __init__(
5253 self .subsystem_info = []
5354 self .publications = {}
5455 self .subscriptions = {}
56+ self .load_fault = False
57+ #################################################################
58+ # add these hardcored load values for better matching
59+ self .load_power = {
60+ tid : {
61+ "transmission_loads_at_fault" : at_fault ,
62+ "transmission_loads_clear_fault" : clear_fault
63+ }
64+ for tid , at_fault , clear_fault in zip (
65+ settings .simulation .transmission_ids ,
66+ settings .simulation .transmission_loads_at_fault ,
67+ settings .simulation .transmission_loads_clear_fault
68+ )
69+ }
70+ #################################################################
5571
5672 def enter_execution_mode (self ):
5773 """Enables federate to enter execution mode"""
@@ -66,11 +82,16 @@ def enter_execution_mode(self):
6682 def create_federate (self ):
6783 """Creates a HELICS co-simulation federate"""
6884 self .fedinfo = h .helicsCreateFederateInfo ()
85+ logger .debug (f"self.fedinfo: { self .fedinfo } " )
6986 h .helicsFederateInfoSetCoreName (self .fedinfo , self .settings .helics .federate_name )
7087 h .helicsFederateInfoSetCoreTypeFromString (self .fedinfo , self .settings .helics .core_type .value )
7188 h .helicsFederateInfoSetCoreInitString (self .fedinfo , "--federates=1" )
7289 h .helicsFederateInfoSetBroker (self .fedinfo , str (self .settings .helics .broker_ip ))
7390 h .helicsFederateInfoSetBrokerPort (self .fedinfo , self .settings .helics .broker_port )
91+ IP = self .settings .helics .broker_ip
92+ Port = self .settings .helics .broker_port
93+ logger .info ("Connecting to broker @ {}" .format (f"{ IP } :{ Port } " if Port else IP ))
94+ logger .info (f"Connecting to broker @ { self .settings .helics } " )
7495
7596 if self .settings .helics .iterative_mode :
7697 h .helicsFederateInfoSetTimeProperty (
@@ -100,6 +121,7 @@ def register_publications(self, bus_subsystems: dict):
100121 self .publications = {}
101122 self .pub_struc = []
102123 for publication_dict in self .settings .helics .publications :
124+ logger .debug (f"publication_dict: { publication_dict } " )
103125 bus_subsystem_ids = publication_dict .bus_subsystems
104126 if not set (bus_subsystem_ids ).issubset (self .bus_subsystems ):
105127 msg = f"One or more invalid bus subsystem ID pass in { bus_subsystem_ids } ."
@@ -133,6 +155,7 @@ def register_publications(self, bus_subsystems: dict):
133155 self .pub_struc .append ([{elm_class : properties }, bus_cluster ])
134156 temp_res = self .sim .read_subsystems ({elm_class : properties }, bus_cluster )
135157 temp_res = self .get_restructured_results (temp_res )
158+
136159 for c_name , elm_info in temp_res .items ():
137160 for name , v_info in elm_info .items ():
138161 for p_name , val in v_info .items ():
@@ -235,11 +258,12 @@ def register_subscriptions(self):
235258 self .psse_dict [row ["bus" ]][row ["element_type" ]][element_id ] = {}
236259 if isinstance (row ["element_property" ], str ):
237260 if row ["element_property" ] not in self .psse_dict [row ["bus" ]][row ["element_type" ]][element_id ]:
238- self .psse_dict [row ["bus" ]][row ["element_type" ]][element_id ][row ["element_property" ]] = 0
261+ # FX: modify this so that multiple feeders can be connected to a Transmission Bus
262+ self .psse_dict [row ["bus" ]][row ["element_type" ]][element_id ][row ["element_property" ]] = []
239263 elif isinstance (row ["element_property" ], list ):
240264 for r in row ["element_property" ]:
241265 if r not in self .psse_dict [row ["bus" ]][row ["element_type" ]][element_id ]:
242- self .psse_dict [row ["bus" ]][row ["element_type" ]][element_id ][r ] = 0
266+ self .psse_dict [row ["bus" ]][row ["element_type" ]][element_id ][r ] = []
243267
244268 def request_time (self , _ ) -> (bool , float ):
245269 """Enables time increment of the federate ina co-simulation."
@@ -253,8 +277,10 @@ def request_time(self, _) -> (bool, float):
253277 bool: flag for iteration requrirement (rerun same time step)
254278 float: current helics time in seconds
255279 """
256-
280+
257281 r_seconds = self .sim .get_total_seconds () # - self._dss_solver.GetStepResolutionSeconds()
282+ logger .info (f"Time requested: { r_seconds } " )
283+
258284 if self .sim .get_time () not in self .all_sub_results :
259285 self .all_sub_results [self .sim .get_time ()] = {}
260286 self .all_pub_results [self .sim .get_time ()] = {}
@@ -372,20 +398,23 @@ def subscribe(self) -> dict:
372398 """
373399
374400 "Subscribes results each iteration and updates PSSE objects accordingly"
401+
375402 for sub_tag , sub_data in self .subscriptions .items ():
376403 if isinstance (sub_data ["property" ], str ):
377404 sub_data ["value" ] = h .helicsInputGetDouble (sub_data ["subscription" ])
405+ logger .debug (f"sub_data is { sub_data } " )
378406 self .psse_dict [sub_data ["bus" ]][sub_data ["element_type" ]][sub_data ["element_id" ]][
379407 sub_data ["property" ]
380- ] = ( sub_data ["value" ], sub_data ["scaler" ])
408+ ]. append (( sub_data ["value" ], sub_data ["scaler" ]) )
381409 elif isinstance (sub_data ["property" ], list ):
382410 sub_data ["value" ] = h .helicsInputGetVector (sub_data ["subscription" ])
411+ logger .debug (f"sub_data is { sub_data } " )
383412 if isinstance (sub_data ["value" ], list ) and len (sub_data ["value" ]) == len (sub_data ["property" ]):
384413 for i , p in enumerate (sub_data ["property" ]):
385- self .psse_dict [sub_data ["bus" ]][sub_data ["element_type" ]][sub_data ["element_id" ]][p ] = (
414+ self .psse_dict [sub_data ["bus" ]][sub_data ["element_type" ]][sub_data ["element_id" ]][p ]. append ( (
386415 sub_data ["value" ][i ],
387416 sub_data ["scaler" ][i ],
388- )
417+ ))
389418
390419 logger .debug ("Data received {} for tag {}" .format (sub_data ["value" ], sub_tag ))
391420 if self .settings .helics .iterative_mode :
@@ -399,31 +428,76 @@ def subscribe(self) -> dict:
399428 for i , v_dict in t_info .items ():
400429 values = {}
401430 j = 0
402- for p , v_raw in v_dict .items ():
403- if isinstance (v_raw , tuple ):
404- v , scale = v_raw
405- all_values [f"{ t } .{ b } .{ i } .{ p } " ] = v
431+ for p , v_raws in v_dict .items ():
432+ if isinstance (v_raws , list ):
406433 if isinstance (p , str ):
407434 ppty = f"realar{ PROFILE_VALIDATION [t ].index (p ) + 1 } "
408- values [ppty ] = v * scale
435+ values [ppty ] = 0
436+ for v_raw in v_raws :
437+ v , scale = v_raw
438+ if isinstance (scale , (float , int )):
439+ values [ppty ] += v * scale
440+ else :
441+ values [ppty ] += v
442+ all_values [f"{ t } .{ b } .{ i } .{ p } " ] = values [ppty ]
409443 elif isinstance (p , list ):
410444 for _ , ppt in enumerate (p ):
411445 ppty = f"realar{ PROFILE_VALIDATION [t ].index (ppt ) + 1 } "
412- values [ppty ] = v * scale
446+ values [ppty ] = 0
447+ for v_raw in v_raws :
448+ v , scale = v_raw
449+ if isinstance (scale , (float , int )):
450+ values [ppty ] += v * scale
451+ else :
452+ values [ppty ] += v
453+ all_values [f"{ t } .{ b } .{ i } .{ p } " ] = values [ppty ]
413454 j += 1
414-
415455 is_empty = [0 if not vx else 1 for vx in values .values ()]
456+ logger .debug (f"{ t } .{ b } .{ i } = { values } " )
457+ logger .debug (f"current HELICE time: { self .c_seconds } " )
458+ ######################################################
459+ ## add this for better transit matching
460+ if round (self .c_seconds , 3 ) == 0.1 and self .settings .simulation .transmission_loads_markup :
461+ logger .debug ("the moment of fault" )
462+ logger .debug (f"old { t } .{ b } .{ i } = { values } " )
463+ logger .debug (self .load_power )
464+ load_data = self .load_power [b ]['transmission_loads_at_fault' ]
465+ values ['realar1' ] = load_data [0 ]
466+ values ['realar2' ] = load_data [1 ]
467+ # os.system("PAUSE")
468+ if round (self .c_seconds , 3 ) == 0.175 and self .settings .simulation .transmission_loads_markup :
469+ logger .debug ("the moment of clearing fault" )
470+ logger .debug (f"old { t } .{ b } .{ i } = { values } " )
471+ load_data = self .load_power [b ]['transmission_loads_clear_fault' ]
472+ values ['realar1' ] = load_data [0 ]
473+ values ['realar2' ] = load_data [1 ]
474+ # os.system("PAUSE")
475+ ######################################################
416476 if (
417477 sum (is_empty ) != 0
418478 and sum (values .values ()) < VALUE_UPDATE_BOUND
419479 and sum (values .values ()) > - VALUE_UPDATE_BOUND
480+ and self .c_seconds > 0.02
420481 ):
421482 self .sim .update_object (t , b , i , values )
422483 logger .debug (f"{ t } .{ b } .{ i } = { values } " )
423484
424485 else :
425486 logger .debug ("write failed" )
487+
488+ ######################################################
489+ ## clear the result list
490+ for sub_tag , sub_data in self .subscriptions .items ():
491+ if isinstance (sub_data ["property" ], str ):
492+ self .psse_dict [sub_data ["bus" ]][sub_data ["element_type" ]][sub_data ["element_id" ]][sub_data ["property" ]] = []
493+ elif isinstance (sub_data ["property" ], list ):
494+ if isinstance (sub_data ["value" ], list ) and len (sub_data ["value" ]) == len (sub_data ["property" ]):
495+ for i , p in enumerate (sub_data ["property" ]):
496+ self .psse_dict [sub_data ["bus" ]][sub_data ["element_type" ]][sub_data ["element_id" ]][p ] = []
497+ logger .debug (f"clear self.psse_dict is { self .psse_dict } " )
498+ ######################################################
426499
500+ # os.system("PAUSE")
427501 self .c_seconds_old = self .c_seconds
428502 return all_values
429503
0 commit comments