1717 build_simulation_configs ,
1818 comparison_signature_for ,
1919 label_signature_for ,
20+ normalize_comparison_mode ,
21+ normalize_two_sim_target ,
2022)
2123from e3sm_compareview .components import doc , drawers , file_browser , toolbars
2224from e3sm_compareview .pipeline import EAMVisSource
@@ -65,7 +67,10 @@ def __init__(self, server=None):
6567 # Simulation comparison selection
6668 "simulation_configs" : [],
6769 "control_simulation_file" : "" ,
68- "comparison_mode" : "diff" ,
70+ "two_sim_test_simulation_file" : "" ,
71+ "comparison_mode" : "multi-sim" ,
72+ "comparison_type" : "diff" ,
73+ "selected_columns" : ["ctrl" , "test" , "diff" , "comp1" , "comp2" ],
6974 "dragged_simulation_path" : "" ,
7075 }
7176 )
@@ -257,9 +262,24 @@ def selected_variable_names(self):
257262 @property
258263 def active_simulation_configs (self ):
259264 return active_simulation_configs (
260- self .state .simulation_configs , self .state .control_simulation_file
265+ self .state .simulation_configs ,
266+ self .state .control_simulation_file ,
267+ self .state .comparison_mode ,
268+ self .state .two_sim_test_simulation_file ,
261269 )
262270
271+ def _ensure_two_sim_target (self ):
272+ if self .state .comparison_mode != "two-sim" :
273+ return
274+
275+ target_path = normalize_two_sim_target (
276+ self .state .simulation_configs ,
277+ self .state .control_simulation_file ,
278+ self .state .two_sim_test_simulation_file ,
279+ )
280+ if target_path != self .state .two_sim_test_simulation_file :
281+ self .state .two_sim_test_simulation_file = target_path
282+
263283 def _selected_variables_to_show (self ):
264284 vars_to_show = self .selected_variables
265285 return vars_to_show if any (vars_to_show .values ()) else None
@@ -338,7 +358,10 @@ def download_state(self):
338358 }
339359 state_content ["comparisons" ] = {
340360 "control" : self .state .control_simulation_file ,
361+ "target" : self .state .two_sim_test_simulation_file ,
341362 "mode" : self .state .comparison_mode ,
363+ "type" : self .state .comparison_type ,
364+ "columns" : self .state .selected_columns ,
342365 "simulations" : self .state .simulation_configs ,
343366 }
344367 state_content ["variables-selection" ] = self .state .variables_selected
@@ -364,7 +387,10 @@ def download_state(self):
364387 for view_type , var_names in active_variables .items ():
365388 for var_name in var_names :
366389 for view_spec in self .source .get_view_specs (
367- var_name , self .state .comparison_mode
390+ var_name ,
391+ self .state .comparison_mode ,
392+ self .state .comparison_type ,
393+ self .state .selected_columns ,
368394 ):
369395 config = self .view_manager .get_view (view_spec , view_type ).config
370396 views_to_export .append (
@@ -430,7 +456,28 @@ async def _import_state(self, state_content):
430456 self .state .control_simulation_file = comparisons .get (
431457 "control" , self .state .control_simulation_file
432458 )
433- self .state .comparison_mode = comparisons .get ("mode" , "diff" )
459+ self .state .two_sim_test_simulation_file = comparisons .get (
460+ "target" , self .state .two_sim_test_simulation_file
461+ )
462+ raw_mode = comparisons .get ("mode" )
463+ if raw_mode in ("two-sim" , "multi-sim" ):
464+ self .state .comparison_mode = raw_mode
465+ else :
466+ self .state .comparison_mode = comparisons .get (
467+ "strategy" , self .state .comparison_mode
468+ )
469+
470+ raw_type = comparisons .get ("type" )
471+ if raw_type in ("diff" , "comp1" , "comp2" ):
472+ self .state .comparison_type = raw_type
473+ else :
474+ legacy_type = comparisons .get ("mode" )
475+ if legacy_type in ("diff" , "comp1" , "comp2" ):
476+ self .state .comparison_type = legacy_type
477+ self .state .selected_columns = comparisons .get (
478+ "columns" , self .state .selected_columns
479+ )
480+ self ._ensure_two_sim_target ()
434481
435482 # Load variables
436483 self .state .variables_selected = state_content ["variables-selection" ]
@@ -477,6 +524,7 @@ async def data_loading_open(self, simulation_files, connectivity):
477524 )
478525 self .state .simulation_configs = simulation_configs
479526 self .state .control_simulation_file = control_file
527+ self ._ensure_two_sim_target ()
480528
481529 await asyncio .sleep (0.1 )
482530 # Use the selected simulations from the UI state.
@@ -584,21 +632,52 @@ async def _data_load_variables(self):
584632 def _on_layout_change (self , ** _ ):
585633 self ._rebuild_active_layout ()
586634
635+ @change ("comparison_type" )
636+ def _on_comparison_type_change (self , ** _ ):
637+ if (
638+ self .state .comparison_mode != "multi-sim"
639+ or not self .state .variables_loaded
640+ ):
641+ return
642+
643+ self ._rebuild_active_layout (update_color = True )
644+
587645 @change ("comparison_mode" )
588- def _on_comparison_mode_change (self , ** _ ):
589- if not self .state .variables_loaded :
646+ def _on_comparison_mode_change (self , comparison_mode , ** _ ):
647+ normalized = normalize_comparison_mode (comparison_mode )
648+ if normalized != comparison_mode :
649+ self .state .comparison_mode = normalized
590650 return
591651
652+ self .state .variables_selected = []
653+ self .state .variables_loaded = False
654+
655+ @change ("selected_columns" )
656+ def _on_selected_columns_change (self , ** _ ):
657+ if (
658+ self .state .comparison_mode != "two-sim"
659+ or not self .state .variables_loaded
660+ ):
661+ return
592662 self ._rebuild_active_layout (update_color = True )
593663
594- @change ("simulation_configs" , "control_simulation_file" )
664+ @change (
665+ "simulation_configs" ,
666+ "control_simulation_file" ,
667+ "comparison_mode" ,
668+ "two_sim_test_simulation_file" ,
669+ )
595670 def _on_simulation_selection_change (self , simulation_configs , ** _ ):
596671 if simulation_configs :
597672 valid_paths = {entry ["path" ] for entry in simulation_configs }
598673 if self .state .control_simulation_file not in valid_paths :
599674 self .state .control_simulation_file = simulation_configs [0 ]["path" ]
675+ self ._ensure_two_sim_target ()
600676 comparison_signature = comparison_signature_for (
601- simulation_configs , self .state .control_simulation_file
677+ simulation_configs ,
678+ self .state .control_simulation_file ,
679+ self .state .comparison_mode ,
680+ self .state .two_sim_test_simulation_file ,
602681 )
603682 label_signature = label_signature_for (simulation_configs )
604683
@@ -610,6 +689,7 @@ def _on_simulation_selection_change(self, simulation_configs, **_):
610689
611690 if comparison_changed :
612691 self ._refresh_source_simulations ()
692+ self .view_manager .reset_view_orders (self .selected_variables )
613693 if self .state .variables_loaded and self ._rebuild_active_layout (update_color = True ):
614694 return
615695 self .state .variables_loaded = False
0 commit comments