4
4
"""Contains the benchcab application class."""
5
5
6
6
import grp
7
+ import logging
7
8
import os
8
9
import sys
9
10
from pathlib import Path
16
17
from benchcab .environment_modules import EnvironmentModules , EnvironmentModulesInterface
17
18
from benchcab .internal import get_met_forcing_file_names
18
19
from benchcab .model import Model
19
- from benchcab .utils import get_logger
20
20
from benchcab .utils .fs import mkdir , next_path
21
21
from benchcab .utils .pbs import render_job_script
22
22
from benchcab .utils .repo import create_repo
@@ -59,26 +59,37 @@ def __init__(
59
59
self ._spatial_tasks : list [spatial .SpatialTask ] = []
60
60
61
61
# Get the logger object
62
- self .logger = get_logger ()
62
+ self ._logger : Optional [ logging . Logger ] = None
63
63
self ._set_environment ()
64
64
65
+ def set_logger (self , logger : logging .Logger ):
66
+ """Set logger."""
67
+ self ._logger = logger
68
+
69
+ def _get_logger (self ) -> logging .Logger :
70
+ if self ._logger is None :
71
+ msg = "Logger uninitialised."
72
+ raise RuntimeError (msg )
73
+ return self ._logger
74
+
65
75
def _set_environment (self ):
66
76
"""Sets environment variables on current user environment."""
67
77
# Prioritize system binaries over externally set $PATHs (#220)
68
78
os .environ ["PATH" ] = f"{ ':' .join (internal .SYSTEM_PATHS )} :{ os .environ ['PATH' ]} "
69
79
70
80
def _validate_environment (self , project : str , modules : list ):
71
81
"""Performs checks on current user environment."""
82
+ logger = self ._get_logger ()
72
83
if not self .validate_env :
73
84
return
74
85
75
86
if "gadi.nci" not in internal .NODENAME :
76
- self . logger .error ("benchcab is currently implemented only on Gadi" )
87
+ logger .error ("benchcab is currently implemented only on Gadi" )
77
88
sys .exit (1 )
78
89
79
90
namelist_dir = Path (internal .NAMELIST_DIR )
80
91
if not namelist_dir .exists ():
81
- self . logger .error (
92
+ logger .error (
82
93
"Cannot find 'namelists' directory in current working directory"
83
94
)
84
95
sys .exit (1 )
@@ -101,7 +112,7 @@ def _validate_environment(self, project: str, modules: list):
101
112
102
113
for modname in modules :
103
114
if not self .modules_handler .module_is_avail (modname ):
104
- self . logger .error (f"Module ({ modname } ) is not available." )
115
+ logger .error (f"Module ({ modname } ) is not available." )
105
116
sys .exit (1 )
106
117
107
118
system_paths = os .getenv ("PATH" ).split (":" )[: len (internal .SYSTEM_PATHS )]
@@ -119,14 +130,12 @@ def _validate_environment(self, project: str, modules: list):
119
130
for site_id in all_site_ids :
120
131
paths = list (internal .MET_DIR .glob (f"{ site_id } *" ))
121
132
if not paths :
122
- self .logger .error (
123
- f"Failed to infer met file for site id '{ site_id } ' in "
124
- )
125
- self .logger .error (f"{ internal .MET_DIR } ." )
133
+ logger .error (f"Failed to infer met file for site id '{ site_id } ' in " )
134
+ logger .error (f"{ internal .MET_DIR } ." )
126
135
127
136
sys .exit (1 )
128
137
if len (paths ) > 1 :
129
- self . logger .error (
138
+ logger .error (
130
139
f"Multiple paths infered for site id: '{ site_id } ' in { internal .MET_DIR } ."
131
140
)
132
141
sys .exit (1 )
@@ -174,18 +183,17 @@ def validate_config(self, config_path: str):
174
183
175
184
def fluxsite_submit_job (self , config_path : str , skip : list [str ]) -> None :
176
185
"""Submits the PBS job script step in the fluxsite test workflow."""
186
+ logger = self ._get_logger ()
177
187
config = self ._get_config (config_path )
178
188
self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
179
189
if self .benchcab_exe_path is None :
180
190
msg = "Path to benchcab executable is undefined."
181
191
raise RuntimeError (msg )
182
192
183
193
job_script_path = Path (internal .QSUB_FNAME )
184
- self .logger .info (
185
- "Creating PBS job script to run fluxsite tasks on compute nodes"
186
- )
194
+ logger .info ("Creating PBS job script to run fluxsite tasks on compute nodes" )
187
195
188
- self . logger .info (f"job_script_path = { job_script_path } " )
196
+ logger .info (f"job_script_path = { job_script_path } " )
189
197
190
198
with job_script_path .open ("w" , encoding = "utf-8" ) as file :
191
199
contents = render_job_script (
@@ -204,92 +212,97 @@ def fluxsite_submit_job(self, config_path: str, skip: list[str]) -> None:
204
212
capture_output = True ,
205
213
)
206
214
except CalledProcessError as exc :
207
- self . logger .error ("when submitting job to NCI queue, details to follow" )
208
- self . logger .error (exc .output )
215
+ logger .error ("when submitting job to NCI queue, details to follow" )
216
+ logger .error (exc .output )
209
217
raise
210
218
211
- self . logger .info (f"PBS job submitted: { proc .stdout .strip ()} " )
212
- self . logger .info ("CABLE log file for each task is written to:" )
213
- self . logger .info (f"{ internal .FLUXSITE_DIRS ['LOG' ]} /<task_name>_log.txt" )
214
- self . logger .info ("The CABLE standard output for each task is written to:" )
215
- self . logger .info (f"{ internal .FLUXSITE_DIRS ['TASKS' ]} /<task_name>/out.txt" )
216
- self . logger .info ("The NetCDF output for each task is written to:" )
217
- self . logger .info (f"{ internal .FLUXSITE_DIRS ['OUTPUT' ]} /<task_name>_out.nc" )
219
+ logger .info (f"PBS job submitted: { proc .stdout .strip ()} " )
220
+ logger .info ("CABLE log file for each task is written to:" )
221
+ logger .info (f"{ internal .FLUXSITE_DIRS ['LOG' ]} /<task_name>_log.txt" )
222
+ logger .info ("The CABLE standard output for each task is written to:" )
223
+ logger .info (f"{ internal .FLUXSITE_DIRS ['TASKS' ]} /<task_name>/out.txt" )
224
+ logger .info ("The NetCDF output for each task is written to:" )
225
+ logger .info (f"{ internal .FLUXSITE_DIRS ['OUTPUT' ]} /<task_name>_out.nc" )
218
226
219
227
def checkout (self , config_path : str ):
220
228
"""Endpoint for `benchcab checkout`."""
229
+ logger = self ._get_logger ()
221
230
config = self ._get_config (config_path )
222
231
self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
223
232
224
233
mkdir (internal .SRC_DIR , exist_ok = True )
225
234
226
- self . logger .info ("Checking out repositories..." )
235
+ logger .info ("Checking out repositories..." )
227
236
rev_number_log = ""
228
237
229
238
for model in self ._get_models (config ):
230
239
try :
231
240
model .repo .checkout ()
232
241
except Exception :
233
242
msg = "Try using `benchcab clean realisations` first"
234
- self . logger .error (
243
+ logger .error (
235
244
"Model checkout failed, probably due to existing realisation name"
236
245
)
237
246
raise FileExistsError (msg )
238
247
rev_number_log += f"{ model .name } : { model .repo .get_revision ()} \n "
239
248
240
249
rev_number_log_path = next_path ("rev_number-*.log" )
241
- self . logger .info (f"Writing revision number info to { rev_number_log_path } " )
250
+ logger .info (f"Writing revision number info to { rev_number_log_path } " )
242
251
with rev_number_log_path .open ("w" , encoding = "utf-8" ) as file :
243
252
file .write (rev_number_log )
244
253
245
254
def build (self , config_path : str , mpi = False ):
246
255
"""Endpoint for `benchcab build`."""
256
+ logger = self ._get_logger ()
247
257
config = self ._get_config (config_path )
248
258
self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
249
259
250
260
for repo in self ._get_models (config ):
251
261
if repo .build_script :
252
262
253
- self . logger .info ("Compiling CABLE using custom build script for" )
254
- self . logger .info (f"realisation { repo .name } " )
263
+ logger .info ("Compiling CABLE using custom build script for" )
264
+ logger .info (f"realisation { repo .name } " )
255
265
repo .custom_build (modules = config ["modules" ])
256
266
257
267
else :
258
268
build_mode = "serial and MPI" if mpi else "serial"
259
- self . logger .info (
269
+ logger .info (
260
270
f"Compiling CABLE { build_mode } for realisation { repo .name } ..."
261
271
)
262
272
repo .build (modules = config ["modules" ], mpi = mpi )
263
- self . logger .info (f"Successfully compiled CABLE for realisation { repo .name } " )
273
+ logger .info (f"Successfully compiled CABLE for realisation { repo .name } " )
264
274
265
275
def fluxsite_setup_work_directory (self , config_path : str ):
266
276
"""Endpoint for `benchcab fluxsite-setup-work-dir`."""
277
+ logger = self ._get_logger ()
267
278
config = self ._get_config (config_path )
268
279
self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
269
280
270
- self . logger .info ("Setting up run directory tree for fluxsite tests..." )
281
+ logger .info ("Setting up run directory tree for fluxsite tests..." )
271
282
setup_fluxsite_directory_tree ()
272
- self . logger .info ("Setting up tasks..." )
283
+ logger .info ("Setting up tasks..." )
273
284
for task in self ._get_fluxsite_tasks (config ):
274
285
task .setup_task ()
275
- self . logger .info ("Successfully setup fluxsite tasks" )
286
+ logger .info ("Successfully setup fluxsite tasks" )
276
287
277
288
def fluxsite_run_tasks (self , config_path : str ):
278
289
"""Endpoint for `benchcab fluxsite-run-tasks`."""
290
+ logger = self ._get_logger ()
279
291
config = self ._get_config (config_path )
280
292
self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
281
293
tasks = self ._get_fluxsite_tasks (config )
282
294
283
- self . logger .info ("Running fluxsite tasks..." )
295
+ logger .info ("Running fluxsite tasks..." )
284
296
if config ["fluxsite" ]["multiprocess" ]:
285
297
ncpus = config ["fluxsite" ]["pbs" ]["ncpus" ]
286
298
fluxsite .run_tasks_in_parallel (tasks , n_processes = ncpus )
287
299
else :
288
300
fluxsite .run_tasks (tasks )
289
- self . logger .info ("Successfully ran fluxsite tasks" )
301
+ logger .info ("Successfully ran fluxsite tasks" )
290
302
291
303
def fluxsite_bitwise_cmp (self , config_path : str ):
292
304
"""Endpoint for `benchcab fluxsite-bitwise-cmp`."""
305
+ logger = self ._get_logger ()
293
306
config = self ._get_config (config_path )
294
307
self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
295
308
@@ -302,13 +315,13 @@ def fluxsite_bitwise_cmp(self, config_path: str):
302
315
self ._get_fluxsite_tasks (config )
303
316
)
304
317
305
- self . logger .info ("Running comparison tasks..." )
318
+ logger .info ("Running comparison tasks..." )
306
319
if config ["fluxsite" ]["multiprocess" ]:
307
320
ncpus = config ["fluxsite" ]["pbs" ]["ncpus" ]
308
321
run_comparisons_in_parallel (comparisons , n_processes = ncpus )
309
322
else :
310
323
run_comparisons (comparisons )
311
- self . logger .info ("Successfully ran comparison tasks" )
324
+ logger .info ("Successfully ran comparison tasks" )
312
325
313
326
def fluxsite (self , config_path : str , no_submit : bool , skip : list [str ]):
314
327
"""Endpoint for `benchcab fluxsite`."""
@@ -331,28 +344,30 @@ def clean(self, config_path: str, clean_option: str):
331
344
332
345
def spatial_setup_work_directory (self , config_path : str ):
333
346
"""Endpoint for `benchcab spatial-setup-work-dir`."""
347
+ logger = self ._get_logger ()
334
348
config = self ._get_config (config_path )
335
349
self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
336
350
337
- self . logger .info ("Setting up run directory tree for spatial tests..." )
351
+ logger .info ("Setting up run directory tree for spatial tests..." )
338
352
setup_spatial_directory_tree ()
339
- self . logger .info ("Setting up tasks..." )
353
+ logger .info ("Setting up tasks..." )
340
354
try :
341
355
payu_config = config ["spatial" ]["payu" ]["config" ]
342
356
except KeyError :
343
357
payu_config = None
344
358
for task in self ._get_spatial_tasks (config ):
345
359
task .setup_task (payu_config = payu_config )
346
- self . logger .info ("Successfully setup spatial tasks" )
360
+ logger .info ("Successfully setup spatial tasks" )
347
361
348
362
def spatial_run_tasks (self , config_path : str ):
349
363
"""Endpoint for `benchcab spatial-run-tasks`."""
364
+ logger = self ._get_logger ()
350
365
config = self ._get_config (config_path )
351
366
self ._validate_environment (project = config ["project" ], modules = config ["modules" ])
352
367
353
- self . logger .info ("Running spatial tasks..." )
368
+ logger .info ("Running spatial tasks..." )
354
369
spatial .run_tasks (tasks = self ._get_spatial_tasks (config ))
355
- self . logger .info ("Successfully dispatched payu jobs" )
370
+ logger .info ("Successfully dispatched payu jobs" )
356
371
357
372
def spatial (self , config_path : str , skip : list ):
358
373
"""Endpoint for `benchcab spatial`."""
0 commit comments