1+ import os
2+ from experiment_manager_tool .git_manager .git_manager import payu_clone_from_commit_hash
3+ from experiment_manager_tool .utils .util_functions import update_diag_table
4+ from experiment_manager_tool .configuration_updater .f90nml_updater import f90nmlUpdater
5+ from experiment_manager_tool .configuration_updater .nuopc_runconfig_updater import NuopcRunConfigUpdater
6+ from experiment_manager_tool .configuration_updater .nuopc_runseq_updater import NuopcRunSeqUpdater
7+ from experiment_manager_tool .configuration_updater .config_updater import ConfigUpdater
8+ from experiment_manager_tool .configuration_updater .mom6_updater import MOM6Updater
9+ from experiment_manager_tool .mixins .mixins import FullPathMixin
10+ from experiment_manager_tool .pbs_job_manager .pbs_job_manager import PBSJobManager
11+ from experiment_manager_tool .utils .base_manager import BaseManager
12+
13+ class ControlExperiment (BaseManager , FullPathMixin ):
14+ def __init__ (self , yamlfile : str ) -> None :
15+ super ().__init__ (yamlfile )
16+
17+ # YAML inputs for control experiment
18+ self .base_url = self .indata .get ("base_url" )
19+ self .base_commit = self .indata .get ("base_commit" )
20+ self .base_branch_name = self .indata .get ("base_branch_name" )
21+ self .base_path = self .full_path ("base_dir_name" )
22+
23+ # diag_table updates
24+ self .diag_ctrl = self .indata .get ("diag_ctrl" , False )
25+ self .diag_path = self .full_path ("diag_dir_name" )
26+
27+ # configuration updaters
28+ self .f90nmlupdater = f90nmlUpdater ()
29+ self .configupdater = ConfigUpdater ()
30+ self .nuopcrunsequpdater = NuopcRunSeqUpdater ()
31+ self .nuopcrunconfigupdater = NuopcRunConfigUpdater (yamlfile )
32+ self .mom6updater = MOM6Updater (yamlfile )
33+
34+ # PBS job manager and control runs
35+ self .check_duplicate_jobs = self .indata .get ("check_duplicate_jobs" , True )
36+ ctrl_nruns = self .indata .get ("ctrl_nruns" , 0 )
37+ self .pbsjobmanager = PBSJobManager (self .dir_manager , self .check_duplicate_jobs , ctrl_nruns )
38+
39+ def manage_experiment (self ) -> None :
40+ print (f"-- Setting up control experiment at { self .base_path } " )
41+
42+ if os .path .exists (self .base_path ):
43+ print (f"-- Control experiment { self .base_path } already exists, hence skipping cloning." )
44+ print (f" However, control experiment can still be updated based on the YAML inputs." )
45+ else :
46+ payu_clone_from_commit_hash (
47+ self .base_url ,
48+ self .base_commit ,
49+ self .base_branch_name ,
50+ self .base_path ,
51+ )
52+
53+ # update diag_table if enabled
54+ update_diag_table (self .base_path ,
55+ self .diag_path ,
56+ self .diag_ctrl ,
57+ self .model ,
58+ )
59+
60+ # setup control experiment
61+ self ._setup_control_expt ()
62+
63+ # run control experiment
64+ self .pbsjobmanager .pbs_job_runs (self .base_path )
65+
66+ def _setup_control_expt (self ) -> None :
67+ """
68+ Modifies parameters based on the input YAML configuration for the control experiment.
69+
70+ Updates configuration files:
71+ 1. config.yaml,
72+ 2. f90 namelist files (.in, .nml),
73+ 3. nuopc.runconfig,
74+ 4. MOM_input,
75+ 5. nuopc.runseq,
76+ for the control experiment if needed.
77+ """
78+ for curr_dir , sub_dirs , files_curr_dir in os .walk (self .base_path ):
79+ sub_dirs [:] = [tmp_d for tmp_d in sub_dirs if ".git" not in tmp_d ]
80+ for f in files_curr_dir :
81+ if ".git" in f :
82+ continue
83+
84+ target_file = os .path .relpath (os .path .join (curr_dir , f ), self .base_path )
85+ yaml_data = self .indata .get (target_file )
86+
87+ if yaml_data :
88+ # Updates config entries from f90nml files
89+ if target_file .endswith ("_in" ) or target_file .endswith (".nml" ):
90+ self .f90nmlupdater .update_nml_params (self .base_path , yaml_data , target_file )
91+
92+ # Updates config entries from `nuopc.runconfig`
93+ if target_file == "nuopc.runconfig" :
94+ self .nuopcrunconfigupdater .update_runconfig_params (self .base_path , yaml_data , target_file )
95+
96+ # Updates config entries from `config_yaml`
97+ if target_file == "config.yaml" :
98+ self .configupdater .update_config_params (self .base_path , yaml_data , target_file )
99+
100+ # Updates config entries from `MOM_input`
101+ if target_file == "MOM_input" :
102+ self .mom6updater .update_mom6_params (self .base_path , yaml_data , target_file )
103+
104+ # Update only coupling timestep from `nuopc.runseq`
105+ if target_file == "nuopc.runseq" :
106+ self .nuopcrunsequpdater .update_cpl_dt_params (self .base_path , yaml_data , target_file )
0 commit comments