Source code for ModelData

# -*- coding: utf-8 -*-
"""
Class structures and functions for loading numerical model output data in 
netCDF formats.

:Dependencies [External]: os, numpy, datetime
:Dependencies [Internal]: waveval.DataFormats. waveval.TimeFunc, waveval.Geometry

"""
# ----------------------------------------------------------------------------
#   IMPORTS
# ----------------------------------------------------------------------------
# Standard Python Dependencies
import os
from datetime import datetime
# Non-Standard Python Dependencies
import numpy as np
# Local Module Dependencies
from waveval.DataFormats import ncdata, netcdfGeneric
from waveval.TimeFuncs import num2date, date2num
from waveval.TimeFuncs import stdTimeUnits
from waveval.Geometry import spatialCoverage
# Other Dependencies

# ----------------------------------------------------------------------------
#   GLOBAL VARIABLES
# ----------------------------------------------------------------------------


# ----------------------------------------------------------------------------
#   CLASS DEFINITIONS
# ----------------------------------------------------------------------------
# ============ ResourceCode WW3 Model Output Files ======================
[docs]class ww3(netcdfGeneric): """ Class structure for reading the ResourceCode WW3 model output netCDF files. """ def __init__(self, fileName): netcdfGeneric.__init__(self, fileName) if self.file['name'] != '': if 'station_name' in self.file['vars']: self.platform = \ "".join([s.decode('utf-8') for s in (self.getVar('station_name')[0])]) if 'start_date' in self.file['attribs']: tstr = ncdata(fileName).start_date self.time_start = tstr.replace('T', ' ').replace('Z', '') if 'stop_date' in self.file['attribs']: tstr = ncdata(fileName).stop_date self.time_end = tstr.replace('T', ' ').replace('Z', '') if 'latitude' in self.file['vars']: self.lat_min = np.nanmin(self.getVar('latitude')) self.lat_max = np.nanmax(self.getVar('latitude')) lat = np.nanmean(self.getVar('latitude')) self.lat = int(lat*100000.0)/100000.0 if 'longitude' in self.file['vars']: self.lon_min = np.nanmin(self.getVar('longitude')) self.lon_max = np.nanmax(self.getVar('longitude')) lon = np.nanmean(self.getVar('longitude')) self.lon = int(lon*100000.0)/100000.0 if 'time' in self.file['vars']: t = self.getVar('time') p = np.mean(np.diff(t))*24.0 self.sample_period = int(p*3600.0)/3600.0
[docs] def getMetaData(self): path, file = os.path.split(self.file['name']) dtFmt = '%Y-%m-%d %H:%M:%S' year = datetime.strptime(self.time_start, dtFmt).year month = datetime.strptime(self.time_start, dtFmt).month meta = [self.platform, path, file, self.lat, self.lon, self.time_start, self.time_end, year, month, self.sample_period] return meta
[docs] def getVar(self, varName): if varName in self.file['vars']: with ncdata(self.file['name'], 'r', format='NETCDF4') as nc: if varName == 'time': timeUnits = self.getVarAttr('time', 'units') if np.ma.isMaskedArray(nc.variables[varName][:]): time = np.ma.getdata(nc.variables[varName][:]) else: time = nc.variables[varName][:] var = date2num(num2date(time, timeUnits), stdTimeUnits) else: if np.ma.isMaskedArray(nc.variables[varName][:]): var = np.ma.getdata(nc.variables[varName][:]) else: var = nc.variables[varName][:] if self.hasAttr(varName,'_FillValue'): fv = self.getVarAttr(varName,'_FillValue') var[var==fv] = np.NaN else: print('WARNING: Variable '+varName+' does not exist.') print('Available variables:') print(list(self.file['vars'])) var = None return var
[docs]class ww3Mesh: """ Class structure for extracting the model mesh data from the a ResourceCode WW3 model output netCDF files that contains the mesh definition. """ def __init__(self, meshFile): try: mesh = ww3(meshFile) lon = mesh.getVar('longitude') lat = mesh.getVar('latitude') elems = mesh.getVar('tri') bathy = mesh.getVar('dpt') self.domain = spatialCoverage(np.nanmin(lat), np.nanmax(lat), np.nanmin(lon), np.nanmax(lon)) self.X = lon self.Y = lat self.elems = elems self.bathy = bathy except: print('WARNING: An error occurred while extracting mesh.') self.domain = None self.X = None self.Y = None self.elems = None self.bathy = None
# ============ Marine Scotland SSW Model Output Files ===================
[docs]class ssw_rs(netcdfGeneric): """ Class structure for reading the Marine Scotland SSW model output netCDF files. """ def __init__(self, fileName): netcdfGeneric.__init__(self, fileName) if self.file['name'] != '': # set metadata platform self.platform = None # set metadata start date t = self.getVar('time')[0] units = self.getVarAttr('time','units') self.time_start = num2date(t,units).strftime() # set metadata stop date t = self.getVar('time')[-1] units = self.getVarAttr('time','units') self.time_end = num2date(t,units).strftime() if 'lat' in self.file['vars']: self.lat_min = np.nanmin(self.getVar('lat')) self.lat_max = np.nanmax(self.getVar('lat')) lat = np.nanmean(self.getVar('lat')) self.lat = int(lat*100000.0)/100000.0 if 'lon' in self.file['vars']: self.lon_min = np.nanmin(self.getVar('lon')) self.lon_max = np.nanmax(self.getVar('lon')) lon = np.nanmean(self.getVar('lon')) self.lon = int(lon*100000.0)/100000.0 if 'time' in self.file['vars']: t = self.getVar('time') p = np.mean(np.diff(t))*24.0 self.sample_period = int(p*3600.0)/3600.0
[docs] def getMetaData(self): path, file = os.path.split(self.file['name']) dtFmt = '%Y-%m-%d %H:%M:%S' year = datetime.strptime(self.time_start, dtFmt).year month = datetime.strptime(self.time_start, dtFmt).month meta = [self.platform, path, file, self.lat, self.lon, self.time_start, self.time_end, year, month, self.sample_period] return meta
[docs] def getVar(self, varName): if varName in self.file['vars']: with ncdata(self.file['name'], 'r', format='NETCDF4') as nc: if varName == 'time': timeUnits = self.getVarAttr('time', 'units') if np.ma.isMaskedArray(nc.variables[varName][:]): time = np.ma.getdata(nc.variables[varName][:]) else: time = nc.variables[varName][:] var = date2num(num2date(time, timeUnits), stdTimeUnits) elif varName in ['lon','lonc']: if np.ma.isMaskedArray(nc.variables[varName][:]): var = np.ma.getdata(nc.variables[varName][:]) else: var = nc.variables[varName][:] var[var > 180.0] = var[var > 180.0] -360.0 else: if np.ma.isMaskedArray(nc.variables[varName][:]): var = np.ma.getdata(nc.variables[varName][:]) else: var = nc.variables[varName][:] if self.hasAttr(varName,'_FillValue'): fv = self.getVarAttr(varName,'_FillValue') var[var==fv] = np.NaN else: print('WARNING: Variable '+varName+' does not exist.') print('Available variables:') print(list(self.file['vars'])) var = None return var
[docs]class sswMesh: """ Class structure for extracting the model mesh data from the a Marine Scotland SSW model output netCDF files that contains the mesh definition. """ def __init__(self, sswFile): try: ssw = ssw_rs(sswFile) lon = ssw.getVar('lon') lat = ssw.getVar('lat') elems = np.transpose(ssw.getVar('nv')) self.domain = spatialCoverage(np.nanmin(lat), np.nanmax(lat), np.nanmin(lon), np.nanmax(lon)) self.X = lon self.Y = lat self.elems = elems self.Xc = ssw.getVar('lonc') self.Yc = ssw.getVar('latc') self.bathy = ssw.getVar('h') self.bathyc = ssw.getVar('h_center') except: print('WARNING: An error occurred while extracting mesh.') self.domain = None self.X = None self.Y = None self.elems = None self.Xc = None self.Yc = None self.bathy = None self.bathyc = None
# ---------------------------------------------------------------------------- # FUNCTION DEFINITIONS # ----------------------------------------------------------------------------
[docs]def mesh2sms2dm(outpath,outfile,mesh): """ Convert mesh data to SMS2DM mesh format. """ f = open(os.path.join(outpath,outfile),'w') f.write('MESH2D\n') elems = mesh.getVar('tri') X = mesh.getVar('longitude') Y = mesh.getVar('latitude') bathy = mesh.getVar('bathy') nelems = len(elems) for el in range(nelems): s = ['E3T',str(el+1), str(elems[el,0]), str(elems[el,1]), str(elems[el,2]),'\n'] aline = ' '.join(s) f.write(aline) nnodes = len(X) for nd in range(nnodes): s = ['ND',str(nd+1),str(X[nd]),str(Y[nd]),str(bathy[nd]),'\n'] aline = ' '.join(s) f.write(aline) f.close() return