2 The main file with the class definitions
7 This file contains all of the classes for the module. It has the base MITgcm_Simulation class, and all of the subclasses for different types of fields. Each class has methods for taking derivatives and doing useful manipulations. It also has some functions that might be of use.
15 import matplotlib.pyplot
as plt
21 """!The simulation class is the main class of this package, and an instance of this class is a model object. All fields are associated with the model object - either directly (it is a dict), or indirectly through one of its subobjects (which are also dicts).
24 def __init__(self,output_dir,grid_netcdf_filename,EOS_type='linear',g=9.81,
25 ntiles_x=1,ntiles_y=1,grid_type=
'cartesian'):
26 """!Instantiate an MITgcm model instance.
31 * output_dir - the location in which the grid netcdf file is, and the rest of the data can be found
32 * grid_netcdf_filename - name of the grid file
33 * EOS_type - the equation of state used. 'linear' is the only supported equation of state at the moment
35 * ntiles_x - number of tiles in the x direction (nPx in MITgcm speak)
36 * ntiles_y - number of tiles in the y direction (nPy in MITgcm speak)
37 * grid_type - cartesian or polar. Fancy grids like cubed sphere aren't supported at the moment.
41 self[
'output_dir'] = output_dir
44 self.
grid[
'grid_type'] = grid_type
48 self[
'EOS_type'] = EOS_type
49 if EOS_type !=
'linear':
50 raise NotImplementedError(
'Only linear equation of state is currently supported')
52 self[
'ntiles_x'] = ntiles_x
53 self[
'ntiles_y'] = ntiles_y
55 def load_field(self,model_instance, netcdf_filename,variable,time_level=-1,
56 field_name=
None,grid_loc=
'T',single_file=
False):
57 """!Load a model field from NetCDF output. This function associates the field with the object it is called on.
59 time_level can be an integer or an array of integers. If it's an array, then multiple time levels will be returned as a higher dimensional array.
61 netcdf_filename can be a string with shell wildcards - they'll be expanded and all of the files loaded. BUT, this is intended as a way to take a quick look at the model. I would *strongly* recommend using something like "gluemncbig" to join the multiple tiles into one file before doing proper analysis."""
62 if field_name ==
None:
65 file_list = glob.glob(netcdf_filename)
68 self[field_name] = self.
load_from_file(model_instance,file_list,variable,time_level,grid_loc,single_file)
71 def load_from_file(self,model_instance, file_list,variable,time_level,grid_loc,single_file):
72 """!Internal function to pull the data from the file(s). It is called by "load_field", and probably shouldn't be used independently."""
87 elif grid_loc ==
'Zeta':
91 print "grid_loc variable not set correctly"
95 if len(file_list) != model_instance[
'ntiles_x']*model_instance[
'ntiles_y']:
96 raise RuntimeError(
"The number of tiles found (" + str(len(file_list)) +
") isn't equal to ntiles_x*ntiles_y (" + str(model_instance[
'ntiles_x']*model_instance[
'ntiles_y']) +
"). You should check this. \n Aborting import of " + variable)
101 if time_level ==
'All':
102 print 'Loading all available time levels in ' + str(variable) +
'. This could take a while.'
104 for files
in file_list:
105 netcdf_file = netCDF4.Dataset(files)
106 index = files.find(
'.t')
107 tile = files[index+2:-3]
108 if variable
in netcdf_file.variables.keys():
109 data[tile] = netcdf_file.variables[variable][:]
112 raise KeyError(variable,
'not in', files,
'- aborting import')
118 for files
in file_list:
119 netcdf_file = netCDF4.Dataset(files)
120 index = files.find(
'.t')
121 tile = files[index+2:-3]
122 if variable
in netcdf_file.variables.keys():
123 data[tile] = netcdf_file.variables[variable][time_level,...]
126 raise KeyError(variable,
'not in', files,
'- aborting import')
131 if len(file_list) == 1:
132 loaded_field = data[tile]
135 data2 = collections.OrderedDict(sorted(data.items(), key=
lambda t: t[0]))
144 if model_instance[
'ntiles_x'] > 1:
146 for i
in xrange(0,model_instance[
'ntiles_y']):
147 strip_x[i] = np.concatenate([data2[tiles[n]][...,:clip_x]
148 for n
in xrange(i*model_instance[
'ntiles_x'],
149 (i+1)*model_instance[
'ntiles_x'] - 1) ],axis=-1)
151 strip_x[i] = np.concatenate((strip_x[i],data2[tiles[n+1]][...,:,:]),axis=-1)
155 strip_x_keys = strip_x.keys()
157 if model_instance[
'ntiles_y'] > 1:
159 loaded_field = np.concatenate([strip_x[strip_x_keys[n]][...,:clip_y,:]
160 for n
in xrange(0,len(strip_x_keys)-1)],axis=-2)
162 loaded_field = np.concatenate((loaded_field,strip_x[strip_x_keys[n+1]][...]),axis=-2)
164 loaded_field = strip_x[strip_x_keys[0]]
171 """!A method that allows model objects to be added together. It does element wise addition for each of the fields."""
172 me = copy.deepcopy(self)
173 for key, value
in me.__dict__.iteritems():
174 for key1, value1
in other.__dict__.iteritems():
176 setattr(me, key, value + value1)
180 """!A method that allows model objects to be divided by floating point numbers. Each field is divided by a floating point number."""
181 me = copy.deepcopy(self)
182 for key, value
in me.__dict__.iteritems():
183 setattr(me, key, value/float(other))
187 """! A method that allows model objects to be multiplied by floating point numbers. Each field is multiplied by a floating point number."""
188 me = copy.deepcopy(self)
189 for key, value
in me.__dict__.iteritems():
190 setattr(me, key, value * float(other))
194 """! A method that allows model objects to be multiplied by floating point numbers. Each field is multiplied by a floating point number."""
195 me = copy.deepcopy(self)
196 for key, value
in me.__dict__.iteritems():
197 setattr(me, key, value * float(other))
201 """! This is the class for all fields on zonal velocity points."""
203 def __init__(self,model_instance,netcdf_filename,variable,time_level=-1,empty=False,field_name=None,single_file=False):
207 self.
load_field(model_instance,netcdf_filename,variable,time_level,field_name,grid_loc=
'U',single_file=False)
211 def load_field(self,model_instance, netcdf_filename,variable,time_level=-1,field_name=None,grid_loc='U',single_file=False):
212 """!Load a model field from NetCDF output. This function associates the field with the object it is called on.
214 time_level can be an integer or an array of integers. If it's an array, then multiple time levels will be returned as a higher dimensional array.
216 netcdf_filename can be a string with shell wildcards - they'll be expanded and all of the files loaded. BUT, this is intended as a way to take a quick look at the model. I would *strongly* recommend using something like "gluemncbig" to join the multiple tiles into one file before doing proper analysis."""
217 if field_name ==
None:
218 field_name = variable
220 file_list = glob.glob(netcdf_filename)
222 self[field_name] = self.
load_from_file(model_instance,file_list,variable,time_level,grid_loc,single_file)
226 def take_d_dx(self,model_instance,input_field = 'UVEL',output_field='dU_dx'):
227 """! Take the x derivative of the field given on u-points, using the spacings in grid object.
229 Performs centred second-order differencing everywhere except next to boundaries. First order is
230 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
233 if input_field
in self:
234 np.seterr(divide=
'ignore')
235 UVEL = self[input_field]
236 dU_dx = np.zeros((UVEL.shape))
238 for i
in xrange(1,UVEL.shape[2]-2):
239 dU_dx[:,:,i] = np.nan_to_num(model_instance.grid[
'wet_mask_U'][:,:,i]*
240 (model_instance.grid[
'wet_mask_U'][:,:,i+1]*UVEL[:,:,i+1] +
241 (1 - model_instance.grid[
'wet_mask_U'][:,:,i+1])*UVEL[:,:,i] -
242 (1 - model_instance.grid[
'wet_mask_U'][:,:,i-1])*UVEL[:,:,i] -
243 model_instance.grid[
'wet_mask_U'][:,:,i-1]*UVEL[:,:,i-1])/(
244 model_instance.grid[
'wet_mask_U'][:,:,i-1]*model_instance.grid[
'dxF'][:,i-1] +
245 model_instance.grid[
'wet_mask_U'][:,:,i+1]*model_instance.grid[
'dxF'][:,i]))
247 dU_dx[:,:,i] = (UVEL[:,:,i+1] - UVEL[:,:,i])/(model_instance.grid[
'dxF'][:,i])
249 dU_dx[:,:,i] = (UVEL[:,:,i] - UVEL[:,:,i-1])/(model_instance.grid[
'dxF'][:,i-1])
251 self[output_field] = dU_dx
253 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
260 def take_d_dy(self,model_instance,input_field = 'UVEL',output_field='dU_dy'):
261 """! Take the y derivative of the field on u points, using the spacings provided.
264 Performs centred second-order differencing everywhere except next to boundaries. First order is
265 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
268 if input_field
in self:
269 np.seterr(divide=
'ignore')
270 UVEL = self[input_field]
271 dU_dy = np.zeros((UVEL.shape))
273 for j
in xrange(1,UVEL.shape[1]-1):
274 dU_dy[:,j,1:] = (model_instance.grid[
'wet_mask_U'][:,j,1:]*
275 (model_instance.grid[
'wet_mask_U'][:,j+1,1:]*UVEL[:,j+1,1:] +
276 (1 - model_instance.grid[
'wet_mask_U'][:,j+1,1:])*UVEL[:,j,1:] -
279 (1 - model_instance.grid[
'wet_mask_U'][:,j-1,1:])*UVEL[:,j,1:] -
280 model_instance.grid[
'wet_mask_U'][:,j-1,1:]*UVEL[:,j-1,1:])/(
281 model_instance.grid[
'wet_mask_U'][:,j-1,1:]*model_instance.grid[
'dyC'][j,:] +
282 model_instance.grid[
'wet_mask_U'][:,j+1,1:]*model_instance.grid[
'dyC'][j+1,:]))
285 dU_dy[:,j,1:] = (model_instance.grid[
'wet_mask_U'][:,j,1:]*(UVEL[:,j+1,1:] -
286 UVEL[:,j,1:])/(model_instance.grid[
'dyC'][j+1,:]))
288 dU_dy[:,j,1:] = (model_instance.grid[
'wet_mask_U'][:,j,1:]*(UVEL[:,j,1:] -
289 UVEL[:,j-1,1:])/(model_instance.grid[
'dyC'][j,:]))
291 self[output_field] = np.nan_to_num(dU_dy)
293 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
299 def take_d_dz(self,model_instance,input_field = 'UVEL',output_field='dU_dz'):
300 """! Take the z derivative of the field given on u-points, using the spacings in grid object.
302 Performs centred second-order differencing everywhere except next to boundaries. First order is
303 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
306 if input_field
in self:
307 np.seterr(divide=
'ignore')
308 UVEL = self[input_field]
309 d_dz = np.zeros((UVEL.shape))
311 for k
in xrange(1,UVEL.shape[0]-1):
313 d_dz[k,:,:] = np.nan_to_num(model_instance.grid[
'wet_mask_U'][k,:,:]*(UVEL[k-1,:,:] -
314 (1-model_instance.grid[
'wet_mask_U'][k+1,:,:])*UVEL[k,:,:]-
315 model_instance.grid[
'wet_mask_U'][k+1,:,:]*UVEL[k+1,:,:])/(model_instance.grid[
'drC'][k] +
316 model_instance.grid[
'wet_mask_U'][k+1,:,:]*model_instance.grid[
'drC'][k+1]))
319 d_dz[k,:,:] = (UVEL[k,:,:] - UVEL[k+1,:,:])/(model_instance.grid[
'drC'][k+1])
321 d_dz[k,:,:] = (UVEL[k-1,:,:] - UVEL[k,:,:])/(model_instance.grid[
'drC'][k])
323 self[output_field] = d_dz
325 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
329 """! Shift the array on to the corresponding tracer point."""
330 shifted = (self[field_name][...,0:-1] + self[field_name][...,1:])/2
335 """! This is the class for all fields on meridional velocity points."""
337 def __init__(self,model_instance,netcdf_filename,variable,time_level=-1,empty=False,field_name=None,single_file=False):
338 """!Instantiate a field on the meridional velocity points."""
342 self.
load_field(model_instance,netcdf_filename,variable,time_level,field_name,grid_loc=
'V',single_file=
False)
346 def load_field(self,model_instance, netcdf_filename,variable,time_level=-1,field_name=None,grid_loc='V',single_file=False):
347 """!Load a model field from NetCDF output. This function associates the field with the object it is called on.
349 time_level can be an integer or an array of integers. If it's an array, then multiple time levels will be returned as a higher dimensional array.
351 netcdf_filename can be a string with shell wildcards - they'll be expanded and all of the files loaded. BUT, this is intended as a way to take a quick look at the model. I would *strongly* recommend using something like "gluemncbig" to join the multiple tiles into one file before doing proper analysis."""
352 if field_name ==
None:
353 field_name = variable
355 file_list = glob.glob(netcdf_filename)
357 self[field_name] = self.
load_from_file(model_instance,file_list,variable,time_level,grid_loc,single_file)
361 def take_d_dx(self,model_instance,input_field = 'VVEL',output_field='dV_dx'):
362 """!Take the x derivative of the field on v points using the spacings in model_instance.grid object.
364 This function can be daisy-chained to get higher order derivatives.
366 Performs centred second-order differencing everywhere except next to boundaries. First order is
367 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
370 if input_field
in self:
371 np.seterr(divide=
'ignore')
372 VVEL = self[input_field]
373 dV_dx = np.zeros((VVEL.shape))
375 for i
in xrange(1,VVEL.shape[2]-1):
376 dV_dx[:,1:,i] = np.nan_to_num(model_instance.grid[
'wet_mask_V'][:,1:,i]*
377 (model_instance.grid[
'wet_mask_V'][:,1:,i+1]*VVEL[:,1:,i+1] +
378 (1 - model_instance.grid[
'wet_mask_V'][:,1:,i+1])*VVEL[:,1:,i] -
379 (1 - model_instance.grid[
'wet_mask_V'][:,1:,i-1])*VVEL[:,1:,i] -
380 model_instance.grid[
'wet_mask_V'][:,1:,i-1]*VVEL[:,1:,i-1])/(
381 model_instance.grid[
'wet_mask_V'][:,1:,i-1]*model_instance.grid[
'dxC'][:,i] +
382 model_instance.grid[
'wet_mask_V'][:,1:,i+1]*model_instance.grid[
'dxC'][:,i+1]))
384 dV_dx[:,1:,i] = (VVEL[:,1:,i+1] - VVEL[:,1:,i])/(model_instance.grid[
'dxC'][:,i+1])
386 dV_dx[:,1:,i] = (VVEL[:,1:,i] - VVEL[:,1:,i-1])/(model_instance.grid[
'dxC'][:,i])
388 self[output_field] = dV_dx
390 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
393 def take_d_dy(self,model_instance,input_field = 'VVEL',output_field='dV_dy'):
394 """! Take the y derivative of the field given on v-points, using the spacings in grid object.
396 Performs centred second-order differencing everywhere except next to boundaries. First order is
397 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
400 if input_field
in self:
401 np.seterr(divide=
'ignore')
402 VVEL = self[input_field]
403 dV_dy = np.zeros((VVEL.shape))
405 for j
in xrange(1,VVEL.shape[1]-2):
406 dV_dy[:,j,:] = np.nan_to_num(model_instance.grid[
'wet_mask_V'][:,j,:]*(
407 model_instance.grid[
'wet_mask_V'][:,j+1,:]*VVEL[:,j+1,:] +
408 (1 - model_instance.grid[
'wet_mask_V'][:,j+1,:])*VVEL[:,j,:] -
409 (1 - model_instance.grid[
'wet_mask_V'][:,j-1,:])*VVEL[:,j,:] -
410 model_instance.grid[
'wet_mask_V'][:,j-1,:]*VVEL[:,j-1,:])/(
411 model_instance.grid[
'wet_mask_V'][:,j-1,:]*model_instance.grid[
'dyF'][j-1,:] +
412 model_instance.grid[
'wet_mask_V'][:,j+1,:]*model_instance.grid[
'dyF'][j,:]))
414 dV_dy[:,j,:] = (VVEL[:,j+1,:] - VVEL[:,j,:])/(model_instance.grid[
'dyF'][j,:])
416 dV_dy[:,j,:] = (VVEL[:,j,:] - VVEL[:,j-1,:])/(model_instance.grid[
'dyF'][j-1,:])
418 self[output_field] = dV_dy
420 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
424 def take_d_dz(self,model_instance,input_field = 'VVEL',output_field='dV_dz'):
425 """! Take the z derivative of the field given on v-points, using the spacings in grid object.
427 Performs centred second-order differencing everywhere except next to boundaries. First order is
428 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
431 if input_field
in self:
432 np.seterr(divide=
'ignore')
433 VVEL = self[input_field]
434 d_dz = np.zeros((VVEL.shape))
436 for k
in xrange(1,VVEL.shape[0]-1):
438 d_dz[k,:,:] = np.nan_to_num(model_instance.grid[
'wet_mask_V'][k,:,:]*(VVEL[k-1,:,:] -
439 (1-model_instance.grid[
'wet_mask_V'][k+1,:,:])*VVEL[k,:,:]-
440 model_instance.grid[
'wet_mask_V'][k+1,:,:]*VVEL[k+1,:,:])/(model_instance.grid[
'drC'][k] +
441 model_instance.grid[
'wet_mask_V'][k+1,:,:]*model_instance.grid[
'drC'][k+1]))
444 d_dz[k,:,:] = (VVEL[k,:,:] - VVEL[k+1,:,:])/(model_instance.grid[
'drC'][k+1])
446 d_dz[k,:,:] = (VVEL[k-1,:,:] - VVEL[k,:,:])/(model_instance.grid[
'drC'][k])
448 self[output_field] = d_dz
450 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
454 """! Shift the array on to the corresponding tracer point."""
455 shifted = (self[field_name][...,0:-1,:] + self[field_name][...,1:,:])/2
460 """! This is the class for all fields on vertical velocity points."""
462 def __init__(self,model_instance,netcdf_filename,variable,time_level=-1,empty=False,field_name=None,single_file=False):
466 self.
load_field(model_instance,netcdf_filename,variable,time_level,field_name,grid_loc=
'W',single_file=
False)
470 def load_field(self,model_instance, netcdf_filename,variable,time_level=-1,field_name=None,grid_loc='W',single_file=False):
471 """!Load a model field from NetCDF output. This function associates the field with the object it is called on.
473 time_level can be an integer or an array of integers. If it's an array, then multiple time levels will be returned as a higher dimensional array."""
474 if field_name ==
None:
475 field_name = variable
478 file_list = glob.glob(netcdf_filename)
481 loaded_field = self.
load_from_file(model_instance,file_list,variable,time_level,grid_loc,single_file)
484 if len(loaded_field.shape) == 4:
485 self[field_name] = np.append(loaded_field,np.zeros((loaded_field.shape[0],1,loaded_field.shape[-2],loaded_field.shape[-1])),axis=1)
487 self[field_name] = np.append(loaded_field,np.zeros((1,loaded_field.shape[-2],loaded_field.shape[-1])),axis=0)
493 def take_d_dx(self,model_instance,input_field = 'WVEL',output_field='dW_dx'):
494 """!Take the x derivative of the field on w points, using spacings in grid object.
496 Performs centred second-order differencing everywhere except next to boundaries. First order is
497 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
500 if input_field
in self:
501 np.seterr(divide=
'ignore')
502 WVEL = self[input_field]
503 d_dx = np.zeros((WVEL.shape))
505 for i
in xrange(1,WVEL.shape[2]-1):
506 d_dx[:,:,i] = np.nan_to_num(model_instance.grid[
'wet_mask_W'][:,:,i]*
507 (model_instance.grid[
'wet_mask_W'][:,:,i+1]*WVEL[:,:,i+1] +
508 (1 - model_instance.grid[
'wet_mask_W'][:,:,i+1])*WVEL[:,:,i] -
509 (1 - model_instance.grid[
'wet_mask_W'][:,:,i-1])*WVEL[:,:,i] -
510 model_instance.grid[
'wet_mask_W'][:,:,i-1]*WVEL[:,:,i-1])/(
511 model_instance.grid[
'wet_mask_W'][:,:,i-1]*model_instance.grid[
'dxC'][:,i] +
512 model_instance.grid[
'wet_mask_W'][:,:,i+1]*model_instance.grid[
'dxC'][:,i+1]))
514 d_dx[:,:,i] = (WVEL[:,:,i+1] - WVEL[:,:,i])/(model_instance.grid[
'dxC'][:,i+1])
516 d_dx[:,:,i] = (WVEL[:,:,i] - WVEL[:,:,i-1])/(model_instance.grid[
'dxC'][:,i])
518 self[output_field] = d_dx
521 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
525 def take_d_dy(self,model_instance,input_field = 'WVEL',output_field='dW_dy'):
526 """!Take the y derivative of the field on w points, using spacings in grid object.
528 Performs centred second-order differencing everywhere except next to boundaries. First order is
529 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
532 if input_field
in self:
533 np.seterr(divide=
'ignore')
534 WVEL = self[input_field]
535 dW_dy = np.zeros((WVEL.shape))
537 for j
in xrange(1,WVEL.shape[2]-1):
538 dW_dy[:,j,:] = np.nan_to_num(model_instance.grid[
'wet_mask_W'][:,j,:]*
539 (model_instance.grid[
'wet_mask_W'][:,j+1,:]*WVEL[:,j+1,:] +
540 (1 - model_instance.grid[
'wet_mask_W'][:,j+1,:])*WVEL[:,j,:] -
541 (1 - model_instance.grid[
'wet_mask_W'][:,j-1,:])*WVEL[:,j,:] -
542 model_instance.grid[
'wet_mask_W'][:,j-1,:]*WVEL[:,j-1,:])/(
543 model_instance.grid[
'wet_mask_W'][:,j-1,:]*model_instance.grid[
'dyC'][j,:] +
544 model_instance.grid[
'wet_mask_W'][:,j+1,:]*model_instance.grid[
'dyC'][j+1,:]))
546 dW_dy[:,j,:] = (WVEL[:,j+1,:] - WVEL[:,j,:])/(model_instance.grid[
'dyC'][j+1,:])
548 dW_dy[:,j,:] = (WVEL[:,j,:] - WVEL[:,j-1,:])/(model_instance.grid[
'dyC'][j,:])
550 self[output_field] = dW_dy
553 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
556 def take_d_dz(self,model_instance,input_field = 'WVEL',output_field='dW_dz'):
557 """! Take the z derivative of the field given on w-points, using the spacings in grid object.
559 Performs centred second-order differencing everywhere except next to boundaries. First order is
560 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
563 if input_field
in self:
564 np.seterr(divide=
'ignore')
565 WVEL = self[input_field]
566 dWVEL_dz = np.zeros((WVEL.shape))
568 for k
in xrange(1,WVEL.shape[0]-2):
569 dWVEL_dz[k,:,:] = np.nan_to_num(model_instance.grid[
'wet_mask_TH'][k,:,:]*(WVEL[k-1,:,:] -
570 (1-model_instance.grid[
'wet_mask_TH'][k+1,:,:])*WVEL[k,:,:]-
571 model_instance.grid[
'wet_mask_TH'][k+1,:,:]*WVEL[k+1,:,:])/
572 (model_instance.grid[
'drF'][k-1]+
573 model_instance.grid[
'wet_mask_TH'][k+1,:,:]*model_instance.grid[
'drF'][k]))
576 dWVEL_dz[k,:,:] = (WVEL[k,:,:] - WVEL[k+1,:,:])/(model_instance.grid[
'drF'][k])
578 dWVEL_dz[k,:,:] = (WVEL[k-1,:,:] - WVEL[k,:,:])/(model_instance.grid[
'drF'][k-1])
580 dWVEL_dz[k,:,:] = (WVEL[k-1,:,:] - WVEL[k,:,:])/(model_instance.grid[
'drF'][k-1])
582 self[output_field] = dWVEL_dz
584 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
588 """! Shift the array on to the corresponding tracer point."""
589 shifted = (self[field_name][...,0:-1,:,:] + self[field_name][...,1:,:,:])/2
594 """!This is the base class for all model fields on the tracer points. It includes definitions for taking derivatives."""
595 def __init__(self,model_instance,netcdf_filename,variable,time_level=-1,empty=False,field_name=None,single_file=False):
599 self.
load_field(model_instance,netcdf_filename,variable,time_level,field_name,grid_loc=
'T',single_file=
False)
603 def load_field(self,model_instance, netcdf_filename,variable,time_level=-1,field_name=None,grid_loc='T',single_file=False):
604 """!Load a model field from NetCDF output. This function associates the field with the object it is called on.
606 time_level can be an integer or an array of integers. If it's an array, then multiple time levels will be returned as a higher dimensional array.
608 netcdf_filename can be a string with shell wildcards - they'll be expanded and all of the files loaded. BUT, this is intended as a way to take a quick look at the model. I would *strongly* recommend using something like "gluemncbig" to join the multiple tiles into one file before doing proper analysis."""
609 if field_name ==
None:
610 field_name = variable
612 file_list = glob.glob(netcdf_filename)
614 self[field_name] = self.
load_from_file(model_instance,file_list,variable,time_level,grid_loc,single_file)
618 def take_d_dx(self,model_instance,input_field = 'RHO',output_field='dRHO_dx'):
619 """!Take the x derivative of the field on tracer points, using spacings in grid object.
621 Performs centred second-order differencing everywhere except next to boundaries. First order is
622 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
625 if input_field
in self:
626 np.seterr(divide=
'ignore')
627 rho = self[input_field]
630 model_instance.grid[
'dxC'][:],))
631 self[output_field] = np.nan_to_num(d_dx)
633 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
638 d_dx = np.zeros((rho.shape))
641 d_dx[:,:,i] = (rho[:,:,i+1] - rho[:,:,i])/(dxC[:,i+1])
643 d_dx[:,:,i] = (rho[:,:,i] - rho[:,:,i-1])/(dxC[:,i])
645 for i
in xrange(1,rho.shape[2]-1):
646 d_dx[:,:,i] = (wet_mask_TH[:,:,i]*
647 (wet_mask_TH[:,:,i+1]*rho[:,:,i+1] +
648 (1 - wet_mask_TH[:,:,i+1])*rho[:,:,i] -
649 (1 - wet_mask_TH[:,:,i-1])*rho[:,:,i] -
650 wet_mask_TH[:,:,i-1]*rho[:,:,i-1])/(
651 wet_mask_TH[:,:,i-1]*dxC[:,i] +
652 wet_mask_TH[:,:,i+1]*dxC[:,i+1]))
656 def take_d_dy(self,model_instance,input_field = 'RHO',output_field='dRHO_dy'):
657 """!Take the y derivative of the field on tracer points, using spacings in grid object.
659 Performs centred second-order differencing everywhere except next to boundaries. First order is
660 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
663 if input_field
in self:
667 model_instance.grid[
'wet_mask_TH'][:],model_instance.grid[
'dyC'][:]))
669 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
673 """!The numerical bit of taking the y derivative. This has been separated out so that it can be accelerated with numba, but that isn't working yet."""
675 d_dy = np.zeros((rho.shape))
678 d_dy[:,j,:] = (rho[:,j+1,:] - rho[:,j,:])/(dyC[j+1,:])
680 d_dy[:,j,:] = (rho[:,j,:] - rho[:,j-1,:])/(dyC[j,:])
682 for j
in xrange(1,rho.shape[1]-1):
683 d_dy[:,j,:] = (wet_mask_TH[:,j,:]*
684 (wet_mask_TH[:,j+1,:]*rho[:,j+1,:] +
685 (1 - wet_mask_TH[:,j+1,:])*rho[:,j,:] -
686 (1 - wet_mask_TH[:,j-1,:])*rho[:,j,:] -
687 wet_mask_TH[:,j-1,:]*rho[:,j-1,:])/(
688 wet_mask_TH[:,j-1,:]*dyC[j,:] +
689 wet_mask_TH[:,j+1,:]*dyC[j+1,:]))
693 def take_d_dz(self,model_instance,input_field = 'RHO',output_field='dRHO_dz'):
694 """! Take the z derivative of the field given on tracer-points, using the spacings in grid object.
696 Performs centred second-order differencing everywhere except next to boundaries. First order is
697 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
700 if input_field
in self:
701 np.seterr(divide=
'ignore')
702 rho = self[input_field]
703 d_dz = np.zeros((rho.shape))
705 for k
in xrange(1,rho.shape[0]-1):
707 d_dz[k,:,:] = (model_instance.grid[
'wet_mask_TH'][k,:,:]*(rho[k-1,:,:] -
708 (1-model_instance.grid[
'wet_mask_TH'][k+1,:,:])*rho[k,:,:]-
709 model_instance.grid[
'wet_mask_TH'][k+1,:,:]*rho[k+1,:,:])/(model_instance.grid[
'drC'][k] +
710 model_instance.grid[
'wet_mask_TH'][k+1,:,:]*model_instance.grid[
'drC'][k+1]))
713 d_dz[k,:,:] = (rho[k,:,:] - rho[k+1,:,:])/(model_instance.grid[
'drC'][k+1])
715 d_dz[k,:,:] = (rho[k-1,:,:] - rho[k,:,:])/(model_instance.grid[
'drC'][k])
717 self[output_field] = np.nan_to_num(d_dz)
719 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
725 """!A class for fields on vorticity points."""
726 def __init__(self,model_instance,netcdf_filename,variable,time_level=-1,empty=False,field_name=None,single_file=False):
730 self.
load_field(model_instance,netcdf_filename,variable,time_level,field_name,grid_loc=
'Zeta',single_file=
False)
734 def load_field(self,model_instance, netcdf_filename,variable,time_level=-1,field_name=None,grid_loc='Zeta',single_file=False):
735 """!Load a model field from NetCDF output. This function associates the field with the object it is called on.
737 time_level can be an integer or an array of integers. If it's an array, then multiple time levels will be returned as a higher dimensional array.
739 netcdf_filename can be a string with shell wildcards - they'll be expanded and all of the files loaded. BUT, this is intended as a way to take a quick look at the model. I would *strongly* recommend using something like "gluemncbig" to join the multiple tiles into one file before doing proper analysis."""
740 if field_name ==
None:
741 field_name = variable
743 file_list = glob.glob(netcdf_filename)
745 self[field_name] = self.
load_from_file(model_instance,file_list,variable,time_level,grid_loc,single_file)
749 def take_d_dx(self,model_instance,input_field = 'momVort3',output_field='dmomVort3_dx'):
750 """! Take the x derivative of the field given on vorticity-points, using the spacings in grid object.
752 Performs centred second-order differencing everywhere except next to boundaries. First order is
753 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
756 if input_field
in self:
757 np.seterr(divide=
'ignore')
758 momVort3 = self[input_field]
759 dmomVort3_dx = np.zeros((momVort3.shape))
761 for i
in xrange(1,momVort3.shape[2]-2):
762 dmomVort3_dx[:,:,i] = np.nan_to_num(model_instance.grid[
'wet_mask_U'][:,:,i]*
763 (model_instance.grid[
'wet_mask_U'][:,:,i+1]*momVort3[:,:,i+1] +
764 (1 - model_instance.grid[
'wet_mask_U'][:,:,i+1])*momVort3[:,:,i] -
765 (1 - model_instance.grid[
'wet_mask_U'][:,:,i-1])*momVort3[:,:,i] -
766 model_instance.grid[
'wet_mask_U'][:,:,i-1]*momVort3[:,:,i-1])/(
767 model_instance.grid[
'wet_mask_U'][:,:,i-1]*model_instance.grid[
'dxF'][:,i-1] +
768 model_instance.grid[
'wet_mask_U'][:,:,i+1]*model_instance.grid[
'dxF'][:,i]))
770 dmomVort3_dx[:,:,i] = (momVort3[:,:,i+1] - momVort3[:,:,i])/(model_instance.grid[
'dxF'][:,i])
771 i = momVort3.shape[2]-1
772 dmomVort3_dx[:,:,i] = (momVort3[:,:,i] - momVort3[:,:,i-1])/(model_instance.grid[
'dxF'][:,i-1])
774 self[output_field] = dmomVort3_dx
776 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
780 def take_d_dy(self,model_instance,input_field = 'momVort3',output_field='dmomVort3_dy'):
781 """! Take the y derivative of the field given on vorticity-points, using the spacings in grid object.
783 Performs centred second-order differencing everywhere except next to boundaries. First order is
784 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
787 if input_field
in self:
788 np.seterr(divide=
'ignore')
789 momVort3 = self[input_field]
790 dmomVort3_dy = np.zeros((momVort3.shape))
792 for j
in xrange(1,momVort3.shape[1]-2):
793 dmomVort3_dy[:,j,:] = np.nan_to_num(model_instance.grid[
'wet_mask_V'][:,j,:]*(
794 model_instance.grid[
'wet_mask_V'][:,j+1,:]*momVort3[:,j+1,:] +
795 (1 - model_instance.grid[
'wet_mask_V'][:,j+1,:])*momVort3[:,j,:] -
796 (1 - model_instance.grid[
'wet_mask_V'][:,j-1,:])*momVort3[:,j,:] -
797 model_instance.grid[
'wet_mask_V'][:,j-1,:]*momVort3[:,j-1,:])/(
798 model_instance.grid[
'wet_mask_V'][:,j-1,:]*model_instance.grid[
'dyF'][j-1,:] +
799 model_instance.grid[
'wet_mask_V'][:,j+1,:]*model_instance.grid[
'dyF'][j,:]))
801 dmomVort3_dy[:,j,:] = (momVort3[:,j+1,:] - momVort3[:,j,:])/(model_instance.grid[
'dyF'][j,:])
802 j = momVort3.shape[1]-1
803 dmomVort3_dy[:,j,:] = (momVort3[:,j,:] - momVort3[:,j-1,:])/(model_instance.grid[
'dyF'][j-1,:])
805 self[output_field] = dmomVort3_dy
807 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
810 def take_d_dz(self,model_instance,input_field = 'momVort3',output_field='dmomVort3_dz'):
811 """! Take the z derivative of the field given on vorticity-points, using the spacings in grid object.
813 Performs centred second-order differencing everywhere except next to boundaries. First order is
814 used there (meaning the gradients at the boundary are evaluated half a grid point away from where
817 if input_field
in self:
818 np.seterr(divide=
'ignore')
819 momVort3 = self[input_field]
820 d_dz = np.zeros((momVort3.shape))
822 for k
in xrange(1,momVort3.shape[0]-1):
824 d_dz[k,:,:] = np.nan_to_num(model_instance.grid[
'wet_mask_TH'][k,:,:]*(momVort3[k-1,:,:] -
825 (1-model_instance.grid[
'wet_mask_TH'][k+1,:,:])*momVort3[k,:,:]-
826 model_instance.grid[
'wet_mask_TH'][k+1,:,:]*momVort3[k+1,:,:])/(model_instance.grid[
'drC'][k] +
827 model_instance.grid[
'wet_mask_TH'][k+1,:,:]*model_instance.grid[
'drC'][k+1]))
830 d_dz[k,:,:] = (momVort3[k,:,:] - momVort3[k+1,:,:])/(model_instance.grid[
'drC'][k+1])
831 k = momVort3.shape[0]-1
832 d_dz[k,:,:] = (momVort3[k-1,:,:] - momVort3[k,:,:])/(model_instance.grid[
'drC'][k])
834 self[output_field] = d_dz
836 raise KeyError(
'Chosen input array ' + str(input_field) +
' is not defined')
841 """! Shift the array on to the corresponding tracer point."""
842 shifted = (self[field_name][...,0:-1] + self[field_name][...,1:])/2
843 shifted = (shifted[...,0:-1,:] + shifted[...,1:,:])/2
849 """!This defines the class for the grid object.
851 Currently requires a single grid file.
853 This object holds all the information about the grid on which the simulation was run. It also holds masks for selecting only the boundary values of fields on the tracer points.
857 """!Define a single object that has all of the grid variables tucked away in it.
858 Each of the variables pulled directly from the netcdf file still has the
859 original description attached to it. The 2D and 3D arrays do not.
861 Variables imported are:
862 * rAw: r-face area at U point
863 * rAs: r-face area at V point
864 * rA: r-face area at cell center
865 * HFacW: vertical fraction of open cell at West face
866 * HFacS: vertical fraction of open cell at South face
867 * HFacC: vertical fraction of open cell at cell center
868 * X: longitude of cell center
869 * Xp1: longitude of cell corner
870 * dxF: x cell face separation
871 * dxC: x cell center separation
872 * dxV: x v-velocity separation
873 * Y: latitude of cell center
874 * Yp1: latitude of cell corner
875 * dyU: y u-velocity separation
876 * dyC: y cell center separation
877 * dyF: y cell face separation
878 * Z: vertical coordinate of cell center
879 * Zl: vertical coordinate of upper cell interface
880 * Zu: vertical coordinate of lower cell interface
881 * drC: r cell center separation
882 * drF: r cell face separation
883 * fCoriG: Coriolis f at cell corner
884 * fCori: Coriolis f at cell center
886 Variables computed and stored are:
887 * wet_mask_V : a 3d array that is one if the point is in the fluid, zero otherwise.
892 **Cell volumes can be calculated and stored with the compute_cell_volume function**
895 **These boundary masks can be computed with the compute_boundary_masks function**
896 * west_mask : a 3d array that is one if the point has a boundary to the west
903 Notes: uses glob to expand wildcards in the file name. BUT, it will only use the first file that matches.
913 grid_netcdf_file_list = glob.glob(grid_netcdf_filename)
915 if not grid_netcdf_file_list:
916 raise RuntimeError(
'Grid file not found.')
919 grid_netcdf_file = netCDF4.Dataset(grid_netcdf_file_list[0])
921 self[
'rAw'] = grid_netcdf_file.variables[
'rAw']
922 self[
'rAs'] = grid_netcdf_file.variables[
'rAs']
923 self[
'rA'] = grid_netcdf_file.variables[
'rA']
924 self[
'HFacW'] = grid_netcdf_file.variables[
'HFacW']
925 self[
'HFacS'] = grid_netcdf_file.variables[
'HFacS']
926 self[
'HFacC'] = grid_netcdf_file.variables[
'HFacC']
927 self[
'X']= grid_netcdf_file.variables[
'X']
928 self[
'Xp1'] = grid_netcdf_file.variables[
'Xp1']
929 self[
'dxF'] = grid_netcdf_file.variables[
'dxF']
930 self[
'dxC'] = grid_netcdf_file.variables[
'dxC']
931 self[
'dxV'] = grid_netcdf_file.variables[
'dxV']
932 self[
'Y'] = grid_netcdf_file.variables[
'Y']
933 self[
'Yp1'] = grid_netcdf_file.variables[
'Yp1']
934 self[
'dyU'] = grid_netcdf_file.variables[
'dyU']
935 self[
'dyC'] = grid_netcdf_file.variables[
'dyC']
936 self[
'dyF'] = grid_netcdf_file.variables[
'dyF']
937 self[
'Z'] = grid_netcdf_file.variables[
'Z']
938 self[
'Zl'] = grid_netcdf_file.variables[
'Zl']
939 self[
'Zu'] = grid_netcdf_file.variables[
'Zu']
940 self[
'drC'] = grid_netcdf_file.variables[
'drC']
941 self[
'drF'] = grid_netcdf_file.variables[
'drF']
942 self[
'fCoriG'] = grid_netcdf_file.variables[
'fCoriG']
943 self[
'fCori'] = grid_netcdf_file.variables[
'fCori']
952 self[
'wet_mask_V'] = np.ones((np.shape(self[
'HFacS'][:])))
953 self[
'wet_mask_V'][self[
'HFacS'][:] == 0.] = 0.
954 self[
'wet_mask_U'] = np.ones((np.shape(self[
'HFacW'][:])))
955 self[
'wet_mask_U'][self[
'HFacW'][:] == 0.] = 0.
956 self[
'wet_mask_TH'] = np.ones((np.shape(self[
'HFacC'][:])))
957 self[
'wet_mask_TH'][self[
'HFacC'][:] == 0.] = 0.
958 self[
'wet_mask_W'] = np.append(self[
'wet_mask_TH'],np.ones((1,len(self[
'Y'][:]),len(self[
'X'][:]))),axis=0)
969 """!This function does the computationally heavy job of looping through each dimension and creating masks that are one if the boundary is next to the grid point in the specified direction. This function is accelerated by numba, making it about 100 times faster."""
971 wet_mask_TH = self[
'wet_mask_TH'][:]
973 west_mask = np.zeros((wet_mask_TH.shape))
974 east_mask = np.zeros((wet_mask_TH.shape))
975 south_mask = np.zeros((wet_mask_TH.shape))
976 north_mask = np.zeros((wet_mask_TH.shape))
977 bottom_mask = np.zeros((wet_mask_TH.shape))
980 for k
in xrange(0,wet_mask_TH.shape[0]):
981 for j
in xrange(0,wet_mask_TH.shape[1]):
982 for i
in xrange(0,wet_mask_TH.shape[2]):
984 if wet_mask_TH[k,j,i] - wet_mask_TH[k,j,i-1] == 1:
989 if wet_mask_TH[k,j,i-1] - wet_mask_TH[k,j,i] == 1:
990 east_mask[k,j,i-1] = 1
994 if wet_mask_TH[k,j,i] - wet_mask_TH[k,j-1,i] == 1:
995 south_mask[k,j,i] = 1
999 if wet_mask_TH[k,j-1,i] - wet_mask_TH[k,j,i] == 1:
1000 north_mask[k,j,i-1] = 1
1004 if wet_mask_TH[k-1,j,i] - wet_mask_TH[k,j,i] == 1:
1005 bottom_mask[k-1,j,i] = 1
1007 self[
'west_mask'] = west_mask
1008 self[
'east_mask'] = east_mask
1009 self[
'south_mask'] = south_mask
1010 self[
'north_mask'] = north_mask
1011 self[
'bottom_mask'] = bottom_mask
1015 """Compute a 3D array that contains the volume of each cell."""
1017 self[
'U_cell_volume'] = copy.deepcopy(self[
'rAw'][:].reshape((1,self[
'rAw'][:].shape[0],self[
'rAw'][:].shape[1]))*
1018 self[
'drF'][:].reshape((self[
'drF'][:].shape[0],1,1)))
1020 self[
'V_cell_volume'] = copy.deepcopy(self[
'rAs'][:].reshape((1,self[
'rAs'][:].shape[0],self[
'rAs'][:].shape[1]))*
1021 self[
'drF'][:].reshape((self[
'drF'][:].shape[0],1,1)))
1023 self[
'T_cell_volume'] = copy.deepcopy(self[
'dxF'][:]*self[
'dyF'][:]*
1024 self[
'drF'][:].reshape((len(self[
'drF'][:]),1,1)))
1029 """!A tracer point field that contains methods for density fields. Only linear equation of state with temperature variations is supported at the moment.
1031 The linear equation of state is given by
1034 \rho = \rho_{nil} (-\alpha_{T} (\theta - \theta_{0}) + \beta_{S} (S - S_{0})) + \rho_{nil}
1036 where \f$ \rho_{nil} \f$ is the reference density, \f$ \alpha_{T} \f$ is the thermal expansion coefficient, \f$ \beta_{S} \f$ is the haline contraction coefficient, \f$ \theta \f$ and \f$ \beta \f$ are the temperature and salinity fields, and subscript zeros denote reference values.
1039 def __init__(self,model_instance,Talpha=2e-4,Sbeta=0,RhoNil=1035,cp=4000,
1040 temp_field=
'THETA',salt_field=
'S',density_field=
'RHO',
1041 Tref=20,Sref=30,empty=
False):
1046 self[
'Talpha'] = Talpha
1047 self[
'Sbeta'] = Sbeta
1048 self[
'RhoNil'] = RhoNil
1050 temp_field,salt_field,density_field,Tref,Sref)
1053 def calculate_density(self,model_instance,Talpha=2e-4,Sbeta=0,RhoNil=1035,cp=4000,
1054 temp_field=
'THETA',salt_field=
'S',density_field=
'RHO',Tref=20,Sref=30):
1055 """!Cacluate Density field given temperature and salinity fields, using the linear equation of state."""
1056 if model_instance[
'EOS_type'] ==
'linear':
1058 self[density_field] = (RhoNil*( -Talpha*(model_instance.temperature[temp_field] - Tref))
1061 self[density_field] = (RhoNil*( Sbeta*(model_instance.salinity[salt_field] - Sref) - Talpha*(model_instance.temperature[temp_field] - Tref))
1063 print 'Warning: Linear equation of state with salinity is currently untested. Proceed with caution.'
1065 raise NotImplementedError(
'Only linear EOS supported at the moment. Sorry.')
1068 """!Calculate time rate of change of the Density field from the temperature tendency and the linear equation of state. Returned as 'TotRhoTend' associated with the density object.
1070 Differentiating the linear equation of state with respect to temperature, and assuming \f$ \beta_{S} \f$ equals zero, gives
1072 \frac{\partial \rho}{\partial t} = - \rho_{nil} \alpha_{T} \frac{\partial \theta}{\partial t}
1075 if model_instance[
'EOS_type'] ==
'linear':
1076 if self[
'Sbeta'] == 0:
1077 self[
'TotRhoTend'] = (-self[
'RhoNil']*self[
'Talpha']*model_instance.temperature[
'TOTTTEND'])
1079 raise NotImplementedError(
'This function only supports temperature variations at the moment. Sorry.')
1081 raise NotImplementedError(
'Only liner EOS supported at the moment.')
1086 """!The Bernoulli field, evaluated from velocity, Pressure and Density.
1088 BP = \frac{P}{\rho_{0}} + g z + \frac{u^{2} + v^{2}}{2}
1091 def __init__(self,model_instance,density_field='RHO',UVEL_field='UVEL',VVEL_field='VVEL'):
1092 BP_pressure = ((model_instance.pressure[
'P'][:,:,:]/model_instance.density[
'RhoNil'] +
1093 model_instance.grid[
'Z'][:].reshape((len(model_instance.grid[
'Z'][:]),1,1))*model_instance[
'g']))
1095 BP_u = (model_instance.zonal_velocity[UVEL_field][:,:,1:]*model_instance.zonal_velocity[UVEL_field][:,:,1:] +
1096 model_instance.zonal_velocity[UVEL_field][:,:,:-1]*model_instance.zonal_velocity[UVEL_field][:,:,:-1])/2
1098 BP_v = (model_instance.meridional_velocity[VVEL_field][:,1:,:]*model_instance.meridional_velocity[VVEL_field][:,1:,:] +
1099 model_instance.meridional_velocity[VVEL_field][:,:-1,:]*model_instance.meridional_velocity[VVEL_field][:,:-1,:])/2
1101 self[
'BP'] = BP_pressure + (BP_u + BP_v)/2
1105 """!Calculates the pressure field from the density field using the hydrostatic approximation."""
1106 def __init__(self,model_instance,density_field='RHO',ETAN_field='ETAN',empty=False):
1112 delta_P = np.zeros((np.shape(model_instance.density[density_field])))
1113 delta_P[:,:,:] = (model_instance[
'g']*model_instance.density[density_field][:,:,:]*
1114 model_instance.grid[
'drF'][:].reshape(len(model_instance.grid[
'drF'][:]),1,1))
1118 delta_P[0,:,:] = (delta_P[0,:,:] +
1119 model_instance.free_surface[ETAN_field]*model_instance[
'g']*model_instance.density[density_field][0,:,:])
1121 self[
'delta_P'] = delta_P
1122 self[
'P'] = np.cumsum(delta_P,0)
1129 """!Evaluate the potential vorticity on the tracer points."""
1130 def __init__(self,model_instance,density_field='RhoNil',density_deriv_field='dRHO_dz',vort_field='omega_a'):
1131 self[
'Q'] = -model_instance.vorticity[vort_field]*model_instance.density[density_deriv_field]/model_instance.density[density_field]
def __div__(self, other)
A method that allows model objects to be divided by floating point numbers.
def take_d_dy
Take the y derivative of the field given on vorticity-points, using the spacings in grid object...
Calculates the pressure field from the density field using the hydrostatic approximation.
def take_d_dx
Take the x derivative of the field on w points, using spacings in grid object.
def load_field
Load a model field from NetCDF output.
The simulation class is the main class of this package, and an instance of this class is a model obje...
def shift_to_tracer(self, field_name)
Shift the array on to the corresponding tracer point.
def numerics_take_d_dy(self, rho, wet_mask_TH, dyC)
The numerical bit of taking the y derivative.
def compute_cell_volume(self)
def load_field
Load a model field from NetCDF output.
The Bernoulli field, evaluated from velocity, Pressure and Density.
def load_field
Load a model field from NetCDF output.
def take_d_dx
Derivatives of model fields.
def take_d_dy
Take the y derivative of the field on w points, using spacings in grid object.
def compute_boundary_masks(self)
This function does the computationally heavy job of looping through each dimension and creating masks...
This defines the class for the grid object.
This is the class for all fields on meridional velocity points.
def shift_to_tracer(self, field_name)
Shift the array on to the corresponding tracer point.
def take_d_dy
Take the y derivative of the field on u points, using the spacings provided.
A tracer point field that contains methods for density fields.
def numerics_take_d_dx(self, rho, wet_mask_TH, dxC)
def take_d_dx
Take the x derivative of the field on tracer points, using spacings in grid object.
def take_d_dz
Take the z derivative of the field given on v-points, using the spacings in grid object.
def take_d_dx
Take the x derivative of the field on v points using the spacings in model_instance.grid object.
def load_from_file(self, model_instance, file_list, variable, time_level, grid_loc, single_file)
Internal function to pull the data from the file(s).
This is the class for all fields on vertical velocity points.
def take_d_dz
Take the z derivative of the field given on u-points, using the spacings in grid object.
def __mul__(self, other)
A method that allows model objects to be multiplied by floating point numbers.
def shift_to_tracer(self, field_name)
Shift the array on to the corresponding tracer point.
def take_d_dz
Take the z derivative of the field given on tracer-points, using the spacings in grid object...
def __init__
Instantiate an MITgcm model instance.
def take_d_dy
Take the y derivative of the field on tracer points, using spacings in grid object.
def load_field
Load a model field from NetCDF output.
This is the base class for all model fields on the tracer points.
def __init__
Instantiate a field on the meridional velocity points.
def __init__(self, grid_netcdf_filename)
Define a single object that has all of the grid variables tucked away in it.
Evaluate the potential vorticity on the tracer points.
def calculate_TotRhoTend(self, model_instance)
Calculate time rate of change of the Density field from the temperature tendency and the linear equat...
def take_d_dz
Take the z derivative of the field given on w-points, using the spacings in grid object.
def calculate_density
Cacluate Density field given temperature and salinity fields, using the linear equation of state...
def __rmul__(self, other)
A method that allows model objects to be multiplied by floating point numbers.
def load_field
Load a model field from NetCDF output.
def load_field
Load a model field from NetCDF output.
This is the class for all fields on zonal velocity points.
def shift_to_tracer(self, field_name)
Shift the array on to the corresponding tracer point.
def take_d_dz
Take the z derivative of the field given on vorticity-points, using the spacings in grid object...
def take_d_dy
Take the y derivative of the field given on v-points, using the spacings in grid object.
A class for fields on vorticity points.
def take_d_dx
Take the x derivative of the field given on vorticity-points, using the spacings in grid object...
def __add__(self, other)
A method that allows model objects to be added together.