# -*- coding: utf-8 -*-
"""
Functions to simplify the interrogation of NetCDF4 files.
"""
#Generic base data format class structures for building loaders for specific
#data set.
#
#:Dependencies [External]: os, numpy, netCDF4
#:Dependencies [Internal]:
# ----------------------------------------------------------------------------
# IMPORTS
# ----------------------------------------------------------------------------
# Standard Python Dependencies
import os
# Non-Standard Python Dependencies
import numpy as np
from netCDF4 import Dataset as ncdata
from netCDF4 import date2num, num2date
# Local Module Dependencies
from ocmw.core.timeFuncs import datetime, stdTimeUnits
from ocmw.core.geometry import spatialCoverage
# Other Dependencies
# ----------------------------------------------------------------------------
# GLOBAL VARIABLES
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# CLASS DEFINITIONS
# ----------------------------------------------------------------------------
# ============ Generic netCDF Reader ====================================
[docs]
class netcdfGeneric:
"""
Base class for loading and interogating netCDF4 data files.
"""
def __init__(self, fileName):
self.file = {}
if os.path.isfile(fileName):
self.file.update({'name': fileName})
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
self.file.update({'attribs': nc.ncattrs()})
dimNames = []
for key in nc.dimensions.keys():
dimNames.append(nc.dimensions[key].name)
self.file.update({'dims': dimNames})
self.file.update({'vars': list(nc.variables)})
else:
self.file.update({'name': ''})
self.file.update({'attribs': []})
self.file.update({'vars': []})
print('WARNING: File '+fileName+' does not exist.')
[docs]
def listGlobalAttr(self):
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
attrList = nc.ncattrs()
return attrList
[docs]
def hasGlobalAttr(self, attrName):
return attrName in self.file['attribs']
[docs]
def getGlobalAttr(self, attrName):
if self.hasGlobalAttr(attrName):
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
attrib = nc.__getattr__(attrName)
else:
print('WARNING: Global Attribute '+attrName+' does not exist.')
print('Available global attributes:')
print(list(self.file['attribs']))
attrib = None
return attrib
[docs]
def listDims(self):
dimsList = []
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
for key in nc.dimensions.keys():
dimsList.append(nc.dimensions[key].name)
return dimsList
[docs]
def hasDim(self, dimName):
return dimName in self.file['dims']
[docs]
def getDim(self, dimName):
if self.hasDim(dimName):
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
dimSize = nc.dimensions[dimName].size
else:
print('WARNING: Dimension '+dimName+' does not exist.')
print('Available dimensions:')
print(list(self.file['dims']))
dimSize = None
return dimSize
[docs]
def listVars(self):
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
varList = list(nc.variables)
return varList
[docs]
def hasVar(self, varName):
return varName in self.file['vars']
[docs]
def listVarAttrs(self, varName):
if self.hasVar(varName):
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
attrList = nc.variables[varName].ncattrs()
else:
print('WARNING: Variable '+varName+' does not exist.')
print('Available variables:')
print(list(self.file['vars']))
attrList = []
return attrList
[docs]
def hasVarAttr(self, varName, attrName):
attrList = self.listVarAttrs(varName)
return attrName in attrList
[docs]
def getVarAttr(self, varName, attrName):
if varName in self.file['vars']:
if self.hasVarAttr(varName, attrName):
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
attr = nc.variables[varName].getncattr(attrName)
else:
print('WARNING: Attribute '+attrName+' does not exist.')
print('Available attributes:')
print(list(self.listVarAttrs(varName)))
attr = None
else:
print('WARNING: Variable '+varName+' does not exist.')
print('Available variables:')
print(list(self.file['vars']))
attr = None
return attr
[docs]
def getVarDimNames(self, varName):
if self.hasVar(varName):
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
dimNames = list(nc.variables[varName].dimensions)
else:
print('WARNING: Variable '+varName+' does not exist.')
print('Available variables:')
print(list(self.file['vars']))
dimNames = None
return dimNames
[docs]
def getVarDimSizes(self, varName):
if self.hasVar(varName):
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
dimSizes = list(nc.variables[varName].shape)
else:
print('WARNING: Variable '+varName+' does not exist.')
print('Available variables:')
print(list(self.file['vars']))
dimSizes = None
return dimSizes
[docs]
def getVar(self, varName):
if self.hasVar(varName):
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
if np.ma.isMaskedArray(nc.variables[varName][:]):
var = np.ma.getdata(nc.variables[varName][:])
else:
var = nc.variables[varName][:]
if var.dtype == '|S1':
var = (b''.join(list(var))).decode('utf-8')
else:
print('WARNING: Variable '+varName+' does not exist.')
print('Available variables:')
print(list(self.file['vars']))
var = None
return var
[docs]
def updateVar(self, varName, vals):
if varName in self.file['vars']:
nc = ncdata(self.file['name'], 'r+')
nc.variables[varName][:] = vals
nc.close()
else:
print('WARNING: Variable '+varName+' does not exist.')
print('Available variables:')
print(list(self.file['vars']))
return
[docs]
def updateVarAttr(self, varName, varAttr, vals):
if self.hasVarAttr(varName,varAttr):
nc = ncdata(self.file['name'], 'r+')
nc.variables[varName].setncattr(varName,vals)
nc.close()
else:
print('WARNING: Variable '+varName+' does not have attribute '+varAttr+'.')
print('Available variables:')
print(list(self.listVarAttr(varName)))
return
[docs]
def updateGlobalAttr(self, attrName, val):
if self.hasGlobalAttr(attrName):
nc = ncdata(self.file['name'], 'r+')
nc.__getattr__(attrName,val)
nc.close()
else:
print('WARNING: Global attribure '+attrName+' does not exist.')
print('Available attributes:')
print(list(self.listGlobalAttr))
return
# ============ 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.hasVarAttr(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.hasVarAttr(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
# ==================== OceanSites Moored Buoy Data ======================
[docs]
class wavebuoy(netcdfGeneric):
"""
Class structure for reading the CMEMS formatted wavebuoy netCDF files.
"""
def __init__(self, fileName):
netcdfGeneric.__init__(self, fileName)
if self.file['name'] != '':
if 'platform_code' in self.file['attribs']:
self.platform = ncdata(fileName).platform_code
if 'time_coverage_start' in self.file['attribs']:
tstr = ncdata(fileName).time_coverage_start
self.time_start = tstr.replace('T', ' ').replace('Z', '')
if 'time_coverage_end' in self.file['attribs']:
tstr = ncdata(fileName).time_coverage_end
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.nanmedian(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.nanmedian(self.getVar('LONGITUDE'))
self.lon = int(lon*100000.0)/100000.0
if 'TIME' in self.file['vars']:
t = self.getVar('TIME')
p = np.median(np.diff(t))*24.0
self.sample_period = round(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')
time, mask = get_nc_var(nc, 'TIME')
var = date2num(num2date(time, timeUnits), stdTimeUnits)
var[mask] = np.nan
else:
var, mask = get_nc_var(nc, varName)
if mask is not None:
var[mask] = np.nan
if self.hasVarAttr(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]
def getQCVar(self, varName):
if varName in self.file['vars']:
if varName == 'TIME':
timeUnits = self.getVarAttr('TIME', 'units')
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
times, t_mask = get_nc_var(nc, 'TIME')
tqc, tqc_mask = get_nc_var(nc, 'TIME_QC')
var = date2num(num2date(times, timeUnits), stdTimeUnits)
t_unique, indx, cnts = np.unique(times,
return_index=True,
return_counts=True)
umask = np.ones(tqc.shape, dtype=bool)
umask[np.sort(indx[cnts == 1])] = False
tmask = tqc_mask
mask = tmask | umask
else:
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
var, v_mask = get_nc_var(nc, varName)
vqc, vqc_mask = get_nc_var(nc, varName+'_QC')
vqc, vqc_mask = get_nc_var(nc, varName+'_QC')
var[v_mask] = np.nan
var[vqc != 1] = np.nan
mask = np.zeros(vqc.shape, dtype=bool)
mask[np.isnan(var)] = True
else:
print('WARNING: Variable '+varName+' does not exist.')
print('Available variables:')
print(list(self.file['vars']))
var = mask = None
return var, mask
[docs]
def getQCTimeseries(self, varName, varIndex):
t, tmsk = self.getQCVar('TIME')
v, vmsk = self.getQCVar(varName)
msk = tmsk | vmsk[:, varIndex]
times = t[~msk].copy()
values = v[:, varIndex].copy()
values = values[~msk]
return times, values
[docs]
def gapFillTimeseries(self, times, values):
return times, values
# ==================== EMEC Moored Buoy Data SeaDataNet ======================
[docs]
class emecwb(netcdfGeneric):
"""
Class structure for reading the EMEC formatted wavebuoy netCDF files.
"""
def __init__(self, fileName):
netcdfGeneric.__init__(self, fileName)
if self.file['name'] != '':
if 'SDN_STATION' in self.file['vars']:
self.platform = str(self.getVar('SDN_STATION'))
else:
self.platform = 'unknown'
if 'LATITUDE' in self.file['vars']:
self.lat_min = np.nanmin(self.getVar('LATITUDE'))
self.lat_max = np.nanmax(self.getVar('LATITUDE'))
lat = np.nanmedian(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.nanmedian(self.getVar('LONGITUDE'))
self.lon = int(lon*100000.0)/100000.0
if 'TIME' in self.file['vars']:
t = self.getVar('TIME').squeeze()
p = np.median(np.diff(t))*24.0
self.sample_period = round(p*3600.0)/3600.0
self.time_start = num2date(t[0], stdTimeUnits).strftime()
self.time_end = num2date(t[-1], stdTimeUnits).strftime()
[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')
time, mask = get_nc_var(nc, 'TIME')
var = date2num(num2date(time, timeUnits), stdTimeUnits)
var[mask] = np.nan
else:
var, mask = get_nc_var(nc, varName)
if mask is not None:
var[mask] = np.nan
if self.hasVarAttr(varName,'_FillValue'):
fv = self.getVarAttr(varName,'_FillValue')
var[var==fv] = np.NaN
if var.dtype == '|S1':
var = (b''.join(list(var))).decode('utf-8')
var = np.squeeze(var)
else:
print('WARNING: Variable '+varName+' does not exist.')
print('Available variables:')
print(list(self.file['vars']))
var = None
return var
[docs]
def getQCVar(self, varName):
if varName in self.file['vars']:
if varName == 'TIME':
timeUnits = self.getVarAttr('TIME', 'units')
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
times, t_mask = get_nc_var(nc, 'TIME')
tqc, tqc_mask = get_nc_var(nc, 'TIME_SEADATANET_QC')
var = date2num(num2date(times, timeUnits), stdTimeUnits)
t_unique, indx, cnts = np.unique(times,
return_index=True,
return_counts=True)
umask = np.ones(tqc.shape, dtype=bool)
umask[np.sort(indx[cnts == 1])] = False
tmask = tqc_mask
mask = tmask | umask
var = np.squeeze(var)
mask = np.squeeze(mask)
else:
with ncdata(self.file['name'], 'r', format='NETCDF4') as nc:
var, v_mask = get_nc_var(nc, varName)
vqc, vqc_mask = get_nc_var(nc, varName+'_SEADATANET_QC')
#vqc, vqc_mask = get_nc_var(nc, varName+'_SEADATANET_QC')
var[v_mask] = np.nan
var[vqc > 49] = np.nan
mask = np.zeros(vqc.shape, dtype=bool)
mask[np.isnan(var)] = True
var = np.squeeze(var)
mask = np.squeeze(mask)
else:
print('WARNING: Variable '+varName+' does not exist.')
print('Available variables:')
print(list(self.file['vars']))
var = mask = None
return var, mask
[docs]
def getQCTimeseries(self, varName, varIndex):
t, tmsk = self.getQCVar('TIME')
v, vmsk = self.getQCVar(varName)
msk = tmsk | vmsk
times = t[~msk].copy()
values = v.copy()
values = values[~msk]
return times, values
[docs]
def gapFillTimeseries(self, times, values):
return times, values
# ====================== OceanSites Drifter Data ======================
[docs]
class drifter(netcdfGeneric):
"""
Class structure for reading the CMEMS formatted drifter netCDF files.
"""
def __init__(self, fileName):
netcdfGeneric.__init__(self, fileName)
if self.file['name'] != '':
if 'platform_code' in self.file['attribs']:
self.platform = ncdata(fileName).platform_code
if 'time_coverage_start' in self.file['attribs']:
tstr = ncdata(fileName).time_coverage_start
self.time_start = tstr.replace('T', ' ').replace('Z', '')
if 'time_coverage_end' in self.file['attribs']:
tstr = ncdata(fileName).time_coverage_end
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.nanmedian(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.nanmedian(self.getVar('LONGITUDE'))
self.lon = int(lon*100000.0)/100000.0
if 'TIME' in self.file['vars']:
t = self.getVar('TIME')
p = np.median(np.diff(t))*24.0
self.sample_period = round(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][:]
var = nc.variables[varName][:]
if self.hasVarAttr(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]
def getTrackCoverage(self):
coverage = spatialCoverage()
if (self.hasVar('LATITUDE') & self.hasVar('LONGITUDE')):
coverage.lat_range[0] = np.nanmin(self.getVar('LATITUDE'))
coverage.lat_range[1] = np.nanmax(self.getVar('LATITUDE'))
coverage.lon_range[0] = np.nanmin(self.getVar('LONGITUDE'))
coverage.lon_range[1] = np.nanmax(self.getVar('LONGITUDE'))
return coverage
[docs]
def crossesDomain(self, domain: spatialCoverage):
# this belongs in a separate match module...
crosses = False
return crosses
# ----------------------------------------------------------------------------
# FUNCTION DEFINITIONS
# ----------------------------------------------------------------------------
[docs]
def is_masked(data):
masked = type(data) == np.ma.core.MaskedArray
return masked
[docs]
def get_nc_var(ncHnd, varName):
try:
if (ncHnd[varName].valid_min == ' ') or (ncHnd[varName].valid_max == ' '):
ncHnd.set_auto_mask(False)
except:
ncHnd.set_auto_mask(True)
var = ncHnd.variables[varName][:].copy()
if is_masked(var):
data = np.ma.getdata(var)
mask = np.ma.getmask(var)
if mask.size == 1:
mskval = mask
mask = np.zeros(data.shape, dtype='bool')
mask[:] = mskval
else:
data = var
mask = None
return data, mask
[docs]
def ncread(filename, varname):
with ncdata(filename,'r') as nc:
if varname in list(nc.variables):
if np.ma.isMaskedArray(nc.variables[varname]):
var = np.ma.getdata(nc.variables[varname][:])
else:
var = nc.variables[varname][:]
else:
var = None
return var
[docs]
def ncwrite(filename, varname, var):
with ncdata(filename,'a') as nc:
if varname in list(nc.variables):
nc.variables[varname][:] = var
return var
#--------------------------------------------------------------------------
# MAIN PROCESS
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
# INTERFACE
#--------------------------------------------------------------------------