@@ -24,8 +24,13 @@ def __init__(self, *args, **kwargs):
2424 to pass to the resource manager
2525 """
2626 super (AMWG , self ).__init__ (* args , ** kwargs )
27+ if not os .environ .get ('NCARG_ROOT' ):
28+ msg = 'ERROR: NCL doesnt appear to be installed in your environment, unable to run AMWG'
29+ print_line (msg , status = 'err' )
30+ self ._status = JobStatus .FAILED
31+
2732 self ._job_type = 'amwg'
28- self ._requires = 'climo'
33+ self ._requires = [ 'climo' ]
2934 self ._data_required = ['climo_regrid' ]
3035
3136 config = kwargs .get ('config' )
@@ -77,6 +82,7 @@ def __init__(self, *args, **kwargs):
7782 self ._host_path = ''
7883 self ._output_path = ''
7984
85+ self .setup_job_args (config )
8086 # -----------------------------------------------
8187
8288 def setup_data (self , config , filemanager , case ):
@@ -92,7 +98,7 @@ def _dep_filter(self, job):
9298 find the climo job we're waiting for, assuming there's only
9399 one climo job in this case with the same start and end years
94100 """
95- if job .job_type != self ._requires :
101+ if job .job_type not in self ._requires :
96102 return False
97103 if job .start_year != self .start_year :
98104 return False
@@ -131,14 +137,13 @@ def setup_dependencies(self, *args, **kwargs):
131137 self .depends_on .append (self_climo .id )
132138 # -----------------------------------------------
133139
134- def execute (self , config , event_list , custom_args = None , dryrun = False ):
140+ def execute (self , config , * args , custom_args = None , dryrun = False , ** kwargs ):
135141 """
136142 Execute the AMWG job
137143
138144 Parameters
139145 ----------
140146 config (dict): the global config object
141- event_list (EventList): an EventList to push notifications into
142147 dryrun (bool): if true this job will generate all scripts,
143148 setup data, and exit without submitting the job
144149 Returns
@@ -210,12 +215,11 @@ def execute(self, config, event_list, custom_args=None, dryrun=False):
210215 output_path = csh_template_out )
211216
212217 # create the run command and submit it
213- self ._has_been_executed = True
214218 cmd = ['csh' , csh_template_out ]
215- return self ._submit_cmd_to_manager (config , cmd , event_list )
219+ return self ._submit_cmd_to_manager (config , cmd )
216220 # -----------------------------------------------
217221
218- def postvalidate (self , config , event_list , * args , ** kwargs ):
222+ def postvalidate (self , config , * args , ** kwargs ):
219223 """
220224 Validates that the job ran correctly
221225
@@ -261,7 +265,6 @@ def postvalidate(self, config, event_list, *args, **kwargs):
261265 return self ._check_tar (
262266 img_source_tar ,
263267 img_source ,
264- event_list ,
265268 config ,
266269 expected_files ) == 0
267270 else :
@@ -307,45 +310,43 @@ def postvalidate(self, config, event_list, *args, **kwargs):
307310 number_missing = 0
308311 if os .path .exists (img_source_tar ):
309312 number_missing = self ._check_tar (
310- img_source_tar , img_source , event_list , config , expected_files )
313+ img_source_tar , img_source , config , expected_files )
311314
312315 if number_missing == 0 :
313316 msg = '{prefix}: all expected output images found' .format (
314317 prefix = self .msg_prefix ())
315- print_line (msg , event_list )
318+ print_line (msg )
316319 logging .info (msg )
317320 self ._check_links (config , img_source )
318321 return True
319322 elif number_missing > 0 and number_missing <= 2 :
320323 msg = '{prefix}: this job was found to be missing plots, please check the console output for additional information' .format (
321324 prefix = self .msg_prefix ())
322- print_line (msg , event_list )
325+ print_line (msg )
323326 self ._check_links (config , img_source )
324327 return True
325328 else :
326329 return False
327330 # -----------------------------------------------
328331
329- def handle_completion (self , filemanager , event_list , config , * args , ** kwargs ):
332+ def handle_completion (self , filemanager , config , * args , ** kwargs ):
330333 """
331334 Sets up variables needed to web hosting
332335
333336 Parameters
334337 ----------
335- event_list (EventList): an EventList to push user notifications into
338+ filemanager: the global filemanager instance
336339 config (dict): the global config object
337340 """
338- if self .status == JobStatus .COMPLETED :
339- msg = '{prefix}: Job complete' .format (
340- prefix = self .msg_prefix ())
341- else :
342- msg = '{prefix}: Job failed' .format (
343- prefix = self .msg_prefix ())
344- print_line (msg , event_list )
345- logging .info (msg )
341+ if self .status != JobStatus .COMPLETED :
342+ msg = f'{ self .msg_prefix ()} : Job failed, not running completion handler'
343+ print_line (msg , status = 'error' )
344+ return
346345
347346 # if hosting is turned off, simply return
348347 if not config ['global' ].get ('host' ):
348+ msg = f'{ self .msg_prefix ()} : Job completion handler done\n '
349+ print_line (msg )
349350 return
350351
351352 img_source = os .path .join (
@@ -361,16 +362,18 @@ def handle_completion(self, filemanager, event_list, config, *args, **kwargs):
361362 else :
362363 msg = '{prefix}: Unable to find output directory or tar archive' .format (
363364 prefix = self .msg_prefix ())
364- print_line (msg , event_list )
365+ print_line (msg )
365366 self .status = JobStatus .FAILED
366367 logging .info (msg )
367368 return
368369
369370 self .setup_hosting (
370371 always_copy = config ['global' ]['always_copy' ],
371372 img_source = img_source ,
372- host_path = self ._host_path ,
373- event_list = event_list )
373+ host_path = self ._host_path )
374+
375+ msg = f'{ self .msg_prefix ()} : Job completion handler done\n '
376+ print_line (msg )
374377
375378 # -----------------------------------------------
376379
@@ -475,11 +478,11 @@ def _change_input_file_names(self):
475478 os .rename (input_file , new_name )
476479 # -----------------------------------------------
477480
478- def _check_tar (self , img_source_tar , img_source , event_list , config , expected_files ):
481+ def _check_tar (self , img_source_tar , img_source , config , expected_files ):
479482 number_missing = 0
480483 msg = '{prefix}: extracting images from tar archive' .format (
481484 prefix = self .msg_prefix ())
482- print_line (msg , event_list )
485+ print_line (msg )
483486 call (['tar' , '-xf' , img_source_tar ,
484487 '--directory' , self ._output_path ])
485488 passed = True
@@ -497,7 +500,7 @@ def _check_tar(self, img_source_tar, img_source, event_list, config, expected_fi
497500 prefix = self .msg_prefix (),
498501 dir = setpath )
499502 logging .error (msg )
500- print_line (msg , event_list )
503+ print_line (msg )
501504 else :
502505 count = len (os .listdir (setpath ))
503506 if count < expected_files [setname ]:
@@ -507,6 +510,71 @@ def _check_tar(self, img_source_tar, img_source, event_list, config, expected_fi
507510 numProduced = count ,
508511 numExpected = expected_files [setname ])
509512 logging .error (msg )
510- print_line (msg , event_list )
513+ print_line (msg )
511514 number_missing += 1
512515 return number_missing
516+
517+ def validate (self , config ):
518+ messages = []
519+ if 'job_options' in config .keys ():
520+ amwg_global_config = config ['job_options' ].get ('amwg' )
521+ if amwg_global_config :
522+ if 'diag_home' not in amwg_global_config .keys ():
523+ msg = "Global job_options does not contain the amwg code path"
524+ messages .append (msg )
525+ if not amwg_global_config .get ('frequency' ):
526+ config ['job_options' ]['amwg' ]['frequency' ] = set ()
527+ if not isinstance (amwg_global_config ['frequency' ], set ):
528+ amwg_global_config ['frequency' ] = set (amwg_global_config ['frequency' ])
529+ amwg_sets = amwg_global_config .get ('plot_sets' )
530+ if amwg_sets :
531+ if not isinstance (amwg_sets , set ):
532+ amwg_sets = set (amwg_sets )
533+ allowed_sets = set ([str (x ) for x in range (1 , 17 )] + ['all' , '4a' ])
534+ for s in amwg_sets :
535+ if s not in allowed_sets :
536+ msg = "{} is not an allowed AMWG set" .format (s )
537+ messages .append (msg )
538+
539+ for case in config ['simulations' ]:
540+ if "amwg" not in case ['jobs' ]:
541+ continue
542+ case_options = case ['jobs' ]['amwg' ]
543+
544+ freqs = case_options .get ('frequency' )
545+ if freqs :
546+ if not isinstance (freqs , set ):
547+ freqs = set (freqs )
548+ freqs .update (amwg_global_config ['frequency' ])
549+
550+ case_sets = case_options .get ('plot_sets' )
551+ if case_sets :
552+ if not isinstance (case_sets , set ):
553+ case_sets = set (case_sets )
554+ allowed_sets = set ([str (x ) for x in range (1 , 17 )] + ['all' , '4a' ])
555+ for s in case_sets :
556+ if s not in allowed_sets :
557+ msg = "case {case} contains invalid AMWG set {set}" .format (
558+ case = case_options ['shortname' ], set = s )
559+ messages .append (msg )
560+ case_sets .update (amwg_sets )
561+
562+ if not amwg_global_config .get ('output_grid_name' ) and not case_options .get ('output_grid_name' ):
563+ msg = 'Please specify a name for the climo output_grid_name in either the global job_options under amwg, or under the job entry in each simulation\' s config'
564+ messages .append (msg )
565+ else :
566+ if not case_options .get ('output_grid_name' ):
567+ case_options ['output_grid_name' ] = amwg_global_config .get ('output_grid_name' )
568+ if not amwg_global_config .get ('atm_map_path' ) and not case_options .get ('atm_map_path' ):
569+ msg = 'Please specify a atm_map_path in either the global job_options under amwg, or under the job entry in each simulation\' s config'
570+ messages .append (msg )
571+ else :
572+ if not case_options .get ('atm_map_path' ):
573+ case_options ['atm_map_path' ] = amwg_global_config .get ('atm_map_path' )
574+
575+ if messages :
576+ return messages
577+ return None
578+
579+
580+
0 commit comments