1010from subprocess import CalledProcessError
1111from typing import Optional
1212
13- from benchcab import internal
13+ from benchcab import fluxsite , internal , spatial
1414from benchcab .comparison import run_comparisons , run_comparisons_in_parallel
1515from benchcab .config import read_config
1616from benchcab .environment_modules import EnvironmentModules , EnvironmentModulesInterface
17- from benchcab .fluxsite import (
18- Task ,
19- get_fluxsite_comparisons ,
20- get_fluxsite_tasks ,
21- run_tasks ,
22- run_tasks_in_parallel ,
23- )
2417from benchcab .internal import get_met_forcing_file_names
2518from benchcab .model import Model
2619from benchcab .utils import get_logger
2720from benchcab .utils .fs import mkdir , next_path
2821from benchcab .utils .pbs import render_job_script
2922from benchcab .utils .repo import create_repo
3023from benchcab .utils .subprocess import SubprocessWrapper , SubprocessWrapperInterface
31- from benchcab .workdir import setup_fluxsite_directory_tree
24+ from benchcab .workdir import (
25+ setup_fluxsite_directory_tree ,
26+ setup_spatial_directory_tree ,
27+ )
3228
3329
3430class Benchcab :
@@ -57,7 +53,8 @@ def __init__(
5753
5854 self ._config : Optional [dict ] = None
5955 self ._models : list [Model ] = []
60- self .tasks : list [Task ] = [] # initialise fluxsite tasks lazily
56+ self ._fluxsite_tasks : list [fluxsite .FluxsiteTask ] = []
57+ self ._spatial_tasks : list [spatial .SpatialTask ] = []
6158
6259 # Get the logger object
6360 self .logger = get_logger ()
@@ -148,16 +145,26 @@ def _get_models(self, config: dict) -> list[Model]:
148145 self ._models .append (Model (repo = repo , model_id = id , ** sub_config ))
149146 return self ._models
150147
151- def _initialise_tasks (self , config : dict ) -> list [Task ]:
152- """A helper method that initialises and returns the `tasks` attribute."""
153- self .tasks = get_fluxsite_tasks (
154- models = self ._get_models (config ),
155- science_configurations = config ["science_configurations" ],
156- fluxsite_forcing_file_names = get_met_forcing_file_names (
157- config ["fluxsite" ]["experiment" ]
158- ),
159- )
160- return self .tasks
148+ def _get_fluxsite_tasks (self , config : dict ) -> list [fluxsite .FluxsiteTask ]:
149+ if not self ._fluxsite_tasks :
150+ self ._fluxsite_tasks = fluxsite .get_fluxsite_tasks (
151+ models = self ._get_models (config ),
152+ science_configurations = config ["science_configurations" ],
153+ fluxsite_forcing_file_names = get_met_forcing_file_names (
154+ config ["fluxsite" ]["experiment" ]
155+ ),
156+ )
157+ return self ._fluxsite_tasks
158+
159+ def _get_spatial_tasks (self , config ) -> list [spatial .SpatialTask ]:
160+ if not self ._spatial_tasks :
161+ self ._spatial_tasks = spatial .get_spatial_tasks (
162+ models = self ._get_models (config ),
163+ met_forcings = config ["spatial" ]["met_forcings" ],
164+ science_configurations = config ["science_configurations" ],
165+ payu_args = config ["spatial" ]["payu" ]["args" ],
166+ )
167+ return self ._spatial_tasks
161168
162169 def validate_config (self , config_path : str ):
163170 """Endpoint for `benchcab validate_config`."""
@@ -226,7 +233,7 @@ def checkout(self, config_path: str):
226233 with rev_number_log_path .open ("w" , encoding = "utf-8" ) as file :
227234 file .write (rev_number_log )
228235
229- def build (self , config_path : str ):
236+ def build (self , config_path : str , mpi = False ):
230237 """Endpoint for `benchcab build`."""
231238 config = self ._get_config (config_path )
232239 self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
@@ -239,40 +246,39 @@ def build(self, config_path: str):
239246 repo .custom_build (modules = config ["modules" ])
240247
241248 else :
242- build_mode = "with MPI" if internal . MPI else "serially"
249+ build_mode = "with MPI" if mpi else "serially"
243250 self .logger .info (
244251 f"Compiling CABLE { build_mode } for realisation { repo .name } ..."
245252 )
246- repo .pre_build ()
247- repo .run_build (modules = config ["modules" ])
248- repo .post_build ()
253+ repo .pre_build (mpi = mpi )
254+ repo .run_build (modules = config ["modules" ], mpi = mpi )
255+ repo .post_build (mpi = mpi )
249256 self .logger .info (f"Successfully compiled CABLE for realisation { repo .name } " )
250257
251258 def fluxsite_setup_work_directory (self , config_path : str ):
252259 """Endpoint for `benchcab fluxsite-setup-work-dir`."""
253260 config = self ._get_config (config_path )
254261 self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
255262
256- tasks = self .tasks if self .tasks else self ._initialise_tasks (config )
257263 self .logger .info ("Setting up run directory tree for fluxsite tests..." )
258264 setup_fluxsite_directory_tree ()
259265 self .logger .info ("Setting up tasks..." )
260- for task in tasks :
266+ for task in self . _get_fluxsite_tasks ( config ) :
261267 task .setup_task ()
262268 self .logger .info ("Successfully setup fluxsite tasks" )
263269
264270 def fluxsite_run_tasks (self , config_path : str ):
265271 """Endpoint for `benchcab fluxsite-run-tasks`."""
266272 config = self ._get_config (config_path )
267273 self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
274+ tasks = self ._get_fluxsite_tasks (config )
268275
269- tasks = self .tasks if self .tasks else self ._initialise_tasks (config )
270276 self .logger .info ("Running fluxsite tasks..." )
271277 if config ["fluxsite" ]["multiprocess" ]:
272278 ncpus = config ["fluxsite" ]["pbs" ]["ncpus" ]
273- run_tasks_in_parallel (tasks , n_processes = ncpus )
279+ fluxsite . run_tasks_in_parallel (tasks , n_processes = ncpus )
274280 else :
275- run_tasks (tasks )
281+ fluxsite . run_tasks (tasks )
276282 self .logger .info ("Successfully ran fluxsite tasks" )
277283
278284 def fluxsite_bitwise_cmp (self , config_path : str ):
@@ -285,8 +291,9 @@ def fluxsite_bitwise_cmp(self, config_path: str):
285291 "nccmp/1.8.5.0"
286292 ) # use `nccmp -df` for bitwise comparisons
287293
288- tasks = self .tasks if self .tasks else self ._initialise_tasks (config )
289- comparisons = get_fluxsite_comparisons (tasks )
294+ comparisons = fluxsite .get_fluxsite_comparisons (
295+ self ._get_fluxsite_tasks (config )
296+ )
290297
291298 self .logger .info ("Running comparison tasks..." )
292299 if config ["fluxsite" ]["multiprocess" ]:
@@ -308,10 +315,44 @@ def fluxsite(self, config_path: str, no_submit: bool, skip: list[str]):
308315 else :
309316 self .fluxsite_submit_job (config_path , skip )
310317
311- def spatial (self , config_path : str ):
318+ def spatial_setup_work_directory (self , config_path : str ):
319+ """Endpoint for `benchcab spatial-setup-work-dir`."""
320+ config = self ._get_config (config_path )
321+ self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
322+
323+ self .logger .info ("Setting up run directory tree for spatial tests..." )
324+ setup_spatial_directory_tree ()
325+ self .logger .info ("Setting up tasks..." )
326+ try :
327+ payu_config = config ["spatial" ]["payu" ]["config" ]
328+ except KeyError :
329+ payu_config = None
330+ for task in self ._get_spatial_tasks (config ):
331+ task .setup_task (payu_config = payu_config )
332+ self .logger .info ("Successfully setup spatial tasks" )
333+
334+ def spatial_run_tasks (self , config_path : str ):
335+ """Endpoint for `benchcab spatial-run-tasks`."""
336+ config = self ._get_config (config_path )
337+ self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
338+
339+ self .logger .info ("Running spatial tasks..." )
340+ spatial .run_tasks (tasks = self ._get_spatial_tasks (config ))
341+ self .logger .info ("Successfully dispatched payu jobs" )
342+
343+ def spatial (self , config_path : str , skip : list ):
312344 """Endpoint for `benchcab spatial`."""
345+ self .checkout (config_path )
346+ self .build (config_path , mpi = True )
347+ self .spatial_setup_work_directory (config_path )
348+ self .spatial_run_tasks (config_path )
313349
314- def run (self , config_path : str , no_submit : bool , skip : list [str ]):
350+ def run (self , config_path : str , skip : list [str ]):
315351 """Endpoint for `benchcab run`."""
316- self .fluxsite (config_path , no_submit , skip )
317- self .spatial (config_path )
352+ self .checkout (config_path )
353+ self .build (config_path )
354+ self .build (config_path , mpi = True )
355+ self .fluxsite_setup_work_directory (config_path )
356+ self .spatial_setup_work_directory (config_path )
357+ self .fluxsite_submit_job (config_path , skip )
358+ self .spatial_run_tasks (config_path )
0 commit comments