@@ -153,10 +153,10 @@ class Simulation:
153153 get attributes and access to intermediate evaluation stages
154154 logger : logging.Logger
155155 global simulation logger
156- _blocks_dyn : set [Block]
157- blocks with internal ´Solver´ instances (stateful)
158- _blocks_evt : set [Block]
159- blocks with internal events (discrete time, eventful)
156+ _blocks_dyn : list [Block]
157+ blocks with internal ´Solver´ instances (stateful)
158+ _blocks_evt : list [Block]
159+ blocks with internal events (discrete time, eventful)
160160 _active : bool
161161 flag for setting the simulation as active, used for interrupts
162162 """
@@ -176,10 +176,13 @@ def __init__(
176176 ** solver_kwargs
177177 ):
178178
179- #system definition
180- self .blocks = set ()
181- self .connections = set ()
182- self .events = set ()
179+ #system definition (ordered lists with shadow sets for O(1) lookup)
180+ self .blocks = []
181+ self ._block_set = set ()
182+ self .connections = []
183+ self ._conn_set = set ()
184+ self .events = []
185+ self ._event_set = set ()
183186
184187 #simulation timestep and bounds
185188 self .dt = dt
@@ -215,10 +218,12 @@ def __init__(
215218 self .time = 0.0
216219
217220 #collection of blocks with internal ODE solvers
218- self ._blocks_dyn = set ()
221+ self ._blocks_dyn = []
222+ self ._blocks_dyn_set = set ()
219223
220224 #collection of blocks with internal events
221- self ._blocks_evt = set ()
225+ self ._blocks_evt = []
226+ self ._blocks_evt_set = set ()
222227
223228 #flag for setting the simulation active
224229 self ._active = True
@@ -269,9 +274,9 @@ def __contains__(self, other):
269274 bool
270275 """
271276 return (
272- other in self .blocks or
273- other in self .connections or
274- other in self .events
277+ other in self ._block_set or
278+ other in self ._conn_set or
279+ other in self ._event_set
275280 )
276281
277282
@@ -480,7 +485,7 @@ def add_block(self, block):
480485 """
481486
482487 #check if block already in block list
483- if block in self .blocks :
488+ if block in self ._block_set :
484489 _msg = f"block { block } already part of simulation"
485490 self .logger .error (_msg )
486491 raise ValueError (_msg )
@@ -490,14 +495,17 @@ def add_block(self, block):
490495
491496 #add to dynamic list if solver was initialized
492497 if block .engine :
493- self ._blocks_dyn .add (block )
498+ self ._blocks_dyn .append (block )
499+ self ._blocks_dyn_set .add (block )
494500
495501 #add to eventful list if internal events
496502 if block .events :
497- self ._blocks_evt .add (block )
503+ self ._blocks_evt .append (block )
504+ self ._blocks_evt_set .add (block )
498505
499506 #add block to global blocklist
500- self .blocks .add (block )
507+ self .blocks .append (block )
508+ self ._block_set .add (block )
501509
502510 #mark graph for rebuild
503511 if self .graph :
@@ -517,19 +525,24 @@ def remove_block(self, block):
517525 """
518526
519527 #check if block is in block list
520- if block not in self .blocks :
528+ if block not in self ._block_set :
521529 _msg = f"block { block } not part of simulation"
522530 self .logger .error (_msg )
523531 raise ValueError (_msg )
524532
525533 #remove from global blocklist
526- self .blocks .discard (block )
534+ self .blocks .remove (block )
535+ self ._block_set .discard (block )
527536
528537 #remove from dynamic list
529- self ._blocks_dyn .discard (block )
538+ if block in self ._blocks_dyn_set :
539+ self ._blocks_dyn .remove (block )
540+ self ._blocks_dyn_set .discard (block )
530541
531542 #remove from eventful list
532- self ._blocks_evt .discard (block )
543+ if block in self ._blocks_evt_set :
544+ self ._blocks_evt .remove (block )
545+ self ._blocks_evt_set .discard (block )
533546
534547 #mark graph for rebuild
535548 if self .graph :
@@ -549,13 +562,14 @@ def add_connection(self, connection):
549562 """
550563
551564 #check if connection already in connection list
552- if connection in self .connections :
565+ if connection in self ._conn_set :
553566 _msg = f"{ connection } already part of simulation"
554567 self .logger .error (_msg )
555568 raise ValueError (_msg )
556569
557570 #add connection to global connection list
558- self .connections .add (connection )
571+ self .connections .append (connection )
572+ self ._conn_set .add (connection )
559573
560574 #mark graph for rebuild
561575 if self .graph :
@@ -575,13 +589,14 @@ def remove_connection(self, connection):
575589 """
576590
577591 #check if connection is in connection list
578- if connection not in self .connections :
592+ if connection not in self ._conn_set :
579593 _msg = f"{ connection } not part of simulation"
580594 self .logger .error (_msg )
581595 raise ValueError (_msg )
582596
583597 #remove from global connection list
584- self .connections .discard (connection )
598+ self .connections .remove (connection )
599+ self ._conn_set .discard (connection )
585600
586601 #mark graph for rebuild
587602 if self .graph :
@@ -600,13 +615,14 @@ def add_event(self, event):
600615 """
601616
602617 #check if event already in event list
603- if event in self .events :
618+ if event in self ._event_set :
604619 _msg = f"{ event } already part of simulation"
605620 self .logger .error (_msg )
606621 raise ValueError (_msg )
607622
608623 #add event to global event list
609- self .events .add (event )
624+ self .events .append (event )
625+ self ._event_set .add (event )
610626
611627
612628 def remove_event (self , event ):
@@ -621,13 +637,14 @@ def remove_event(self, event):
621637 """
622638
623639 #check if event is in event list
624- if event not in self .events :
640+ if event not in self ._event_set :
625641 _msg = f"{ event } not part of simulation"
626642 self .logger .error (_msg )
627643 raise ValueError (_msg )
628644
629645 #remove from global event list
630- self .events .discard (event )
646+ self .events .remove (event )
647+ self ._event_set .discard (event )
631648
632649
633650 # system assembly -------------------------------------------------------------
@@ -685,10 +702,11 @@ def _check_blocks_are_managed(self):
685702 conn_blocks .update (conn .get_blocks ())
686703
687704 # Check subset actively managed
688- if not conn_blocks .issubset (self .blocks ):
689- self .logger .warning (
690- f"{ blk } in 'connections' but not in 'blocks'!"
691- )
705+ for blk in conn_blocks :
706+ if blk not in self ._block_set :
707+ self .logger .warning (
708+ f"{ blk } in 'connections' but not in 'blocks'!"
709+ )
692710
693711
694712 # solver management -----------------------------------------------------------
@@ -719,13 +737,15 @@ def _set_solver(self, Solver=None, **solver_kwargs):
719737 self .engine = self .Solver ()
720738
721739 #iterate all blocks and set integration engines with tolerances
722- self ._blocks_dyn = set ()
740+ self ._blocks_dyn = []
741+ self ._blocks_dyn_set = set ()
723742 for block in self .blocks :
724743 block .set_solver (self .Solver , self .engine , ** self .solver_kwargs )
725-
744+
726745 #add dynamic blocks to list
727746 if block .engine :
728- self ._blocks_dyn .add (block )
747+ self ._blocks_dyn .append (block )
748+ self ._blocks_dyn_set .add (block )
729749
730750 #logging message
731751 self .logger .info (
0 commit comments