# -*- 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 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 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