FLEXPART Testing Environment CTBTO WO8
 All Classes Namespaces Files Functions Variables Pages
FlexpartCase.py
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 """
3 Created on Tue May 19 13:38:38 2015
4 
5 @author: morton
6 
7 Don Morton
8 Boreal Scientific Computing LLC, Fairbanks, Alaska, USA
9 Don.Morton@borealscicomp.com
10 http://www.borealscicomp.com/
11 
12 contributors
13 Christian Maurer
14 Delia Arnold
15 ZAMG, Vienna, Austria
16 christian.maurer@zamg.ac.at
17 delia.arnold-arias@zamg.ac.at
18 
19 """
20 
21 
22 
23 import copy
24 import filecmp
25 import logging
26 import os
27 import shutil
28 import subprocess
29 import sys
30 import time
31 
32 class FlexpartCase(object):
33 
34 
35 
36 
37  def __init__(self, src_dir=None, dest_dir=None,
38  met_dir=None, met_nest_dir=None, flexpart_exe=None):
39 
40  """Set up the class
41 
42  src_dir : a directory structure all set to run FLEXPART. Note that
43  the paths in pathnames must be all relative within this directory.
44  This directory will also need to contain the met data in directory
45  met_data
46 
47  dest_dir : location that src_dir will be copied to, and where the
48  run will be executed. dest_dir cannot already exist. We make
49  this restriction to prevent accidental overwriting of something
50  important.
51 
52  met_dir : location of met files. Assumed to have a valid
53  AVAILABLE file in it
54 
55 
56  flexpart_exe : full path to a FLEXPART executable
57  """
58 
59  # 2016-01-15 - DJM - this is something Delia and Christian introduced,
60  # but not sure why. I have modified logic so it's not needed.
61  #symlink_nest = False
62 
63  # test for a src_dir argument
64  if src_dir:
65 
66  # Test that src_dir is found
67  if os.path.isdir(src_dir):
68  self._src_dir = src_dir
69  else:
70  msg = 'src_dir not found: ' + src_dir
71  raise Exception(msg)
72  else:
73  msg = 'No src_dir argument'
74  raise Exception(msg)
75 
76  # test for a dest_dir argument
77  if dest_dir:
78  # Make sure it doesn't already exist
79  if os.path.isdir(dest_dir):
80  msg = 'dest_dir cannot already exist: ' + dest_dir
81  raise Exception(msg)
82  else:
83  self._dest_dir = dest_dir
84  else:
85  msg = 'No dest_dir argument'
86  raise Exception(msg)
87 
88  # test for a met_dir argument
89  if met_dir:
90  # Make sure it doesn't already exist
91  if os.path.isdir(met_dir):
92  self._met_dir = met_dir
93  else:
94  msg = 'met_dir not found: ' + met_dir
95  raise Exception(msg)
96  else:
97  msg = 'No met_dir argument'
98  raise Exception(msg)
99 
100  # test for a met_nest_dir argument
101  if met_nest_dir:
102  # Make sure it doesn't already exist
103  if os.path.isdir(met_nest_dir):
104  self._met_nest_dir = met_nest_dir
105  else:
106  msg = 'met_nest_dir not found: ' + met_nest_dir
107  raise Exception(msg)
108 
109  # Test that flexpart_exe exists and is executable
110  if flexpart_exe:
111  # Make sure it exists and is executable
112  if os.path.isfile(flexpart_exe) and os.access(flexpart_exe, os.X_OK):
113  self._flexpart_exe = flexpart_exe
114  else:
115  msg = 'flexpart_exe does not exist and/or is not executable'
116  raise Exception(msg)
117  else:
118  msg = 'No flexpart_exe argument'
119  raise Exception(msg)
120 
121 
122 
123  self._destdir_ok = False # This indicates if copy to destdir was ok
124  init_success = True
125  # Make sure destdir does not already exist
126  if not os.path.isdir(dest_dir):
127  # Copy the distribution from src_dir into dest_dir and validate success
128  try:
129  #print src_dir, dest_dir
130  shutil.copytree(src_dir, dest_dir)
131  logging.info('FlexpartCase: copying case dir to temp location')
132 
133  # Compare the directories. Success would be indicated
134  # by an empty list diffs.diff_files
135  diffs = filecmp.dircmp(src_dir, dest_dir)
136  if diffs.diff_files:
137  logging.warning('FlexpartCase: src and dest differ')
138  init_success = False
139 
140 
141  except:
142  init_success = False
143  logging.warning('FlexpartCase: copy failed')
144  else:
145  init_success = False
146  logging.warning('FlexpartCase: dest_dir exists')
147 
148  if init_success:
149 
150  # Check that important files are present. If not, go ahead
151  # and try to make it, raise exception if fails
152  if not os.path.isdir(dest_dir + '/output'):
153  # Try to make one
154  try:
155  os.mkdir(dest_dir + '/output', 0755)
156  except:
157  msg = 'No output dir present in case directory'
158  raise Exception(msg)
159 
160  # Make a link to the met_dir
161  try:
162  os.symlink(self._met_dir, dest_dir + '/met_data')
163  except:
164  msg = 'Unable to create met_data symlink to: ' + self._met_dir
165  raise Exception(msg)
166 
167  # Make a link to the met_nest_dir
168  if met_nest_dir:
169  try:
170  os.symlink(self._met_nest_dir, dest_dir + '/met_data_nest')
171  except:
172  msg = 'Unable to create met_data_nest symlink to: ' + \
173  self._met_nest_dir
174  raise Exception(msg)
175 
176  # Make sure there is an AVAILABLE file
177  if not os.path.isfile(dest_dir + '/met_data/AVAILABLE'):
178  msg = 'Unable to find AVAILABLE in ' + dest_dir + '/met_data'
179  raise Exception(msg)
180 
181  if met_nest_dir:
182  if not os.path.isfile(dest_dir + '/met_data_nest/AVAILABLE'):
183  msg = 'Unable to find AVAILABLE in ' + dest_dir + '/met_data_nest'
184  raise Exception(msg)
185 
186 
187 
188 
189  self._destdir_ok = True
190 
191  # Make a link to the met directory
192 
193  self._execution_time_seconds = -9999.0
194 
195 
196 
197 
198 
199  def run(self):
200  """Runs the case - assumes that the original case template was
201  in good shape and that it was copied successfully. The variable
202  self._destdir_ok provides a very simple, but incomplete check.
203 
204  This routine will launch the executable, and then wait for it to
205  complete. stdout will go to file stdout.txt at the top of the
206  dest_dir.
207  """
208 
209  stdoutFH = open(self._dest_dir + '/stdout.txt', 'w')
210 
211  start_time = time.time()
212  the_process = subprocess.Popen( self._flexpart_exe, shell=True,
213  stdout=stdoutFH,
214  cwd=self._dest_dir )
215 
216  status=the_process.wait()
217  stop_time = time.time()
218 
219  self._execution_time_seconds = stop_time - start_time
220 
221  stdoutFH.close()
222 
223  return True
224 
225  def success(self):
226  """Looks at last line of stdout and insures it contains some of the
227  expected key words. This is a very simple test and, in the future
228  should be replaced with something more robust that insures the expected
229  output files are all present
230  """
231 
232  so_far_so_good = True
233 
234  # Try to open the file for reading
235  try:
236  stdoutFH = open(self._dest_dir + '/stdout.txt', 'r')
237  except:
238  so_far_so_good = False
239 
240  if so_far_so_good:
241  # Try to get the contents of the last line and store in tokens
242  try:
243  for the_line in stdoutFH:
244  pass
245  last_line = the_line
246  stdoutFH.close()
247 
248  #print last_line
249 
250  tokens = last_line.split()
251  except:
252  so_far_so_good = False
253 
254 
255  # If no errors so far, check for several expected keywords in the
256  # tokens from the last line of the stdout file
257  if so_far_so_good and ('CONGRATULATIONS:' and \
258  'SUCCESSFULLLY' and 'COMPLETED' \
259  and 'FLEXPART' in tokens):
260  #print 'SUCCESS!!'
261  return_val = True
262  else:
263  #print 'FAILED!!'
264  return_val = False
265 
266  return return_val
267 
268 
270 
271  """Returns value of execution time in seconds"""
272 
273  return self._execution_time_seconds
274 
275