from netCDF4 import Dataset, date2num
import numpy as np
[docs]
class FVCOMWriter(object):
""" Create an FVCOM netCDF input file. """
def __init__(self, filename, dimensions, global_attributes=None, **kwargs):
""" Create a netCDF file.
Parameters
----------
filename : str, pathlib.Path
Output netCDF path.
dimensions : dict
Dictionary of dimension names and sizes.
global_attributes : dict, optional
Global attributes to add to the netCDF file.
Remaining arguments are passed to netCDF4.Dataset.
"""
self.nc = Dataset(str(filename), 'w', **kwargs)
for dimension in dimensions:
self.nc.createDimension(dimension, dimensions[dimension])
if global_attributes:
for attribute in global_attributes:
setattr(self.nc, attribute, global_attributes[attribute])
[docs]
def add_variable(self, name, data, dimensions, attributes=None, format='f4', ncopts={}):
"""
Create a `name' variable with the given `attributes' and `data'.
Parameters
----------
name : str
Variable name to add.
data : np.ndararay, list, float, str
Data to add to the netCDF file object.
dimensions : list, tuple
List of dimension names to apply to the new variable.
attributes : dict, optional
Attributes to add to the netCDF variable object.
format : str, optional
Data format for the new variable. Defaults to 'f4' (float32).
ncopts : dict
Dictionary of options to use when creating the netCDF variables.
"""
var = self.nc.createVariable(name, format, dimensions, **ncopts)
if attributes:
for attribute in attributes:
setattr(var, attribute, attributes[attribute])
var[:] = data
setattr(self, name, var)
[docs]
def write_fvcom_time(self, time, **kwargs):
"""
Write the four standard FVCOM time variables (time, Times, Itime, Itime2) for the given time series.
Parameters
----------
time : np.ndarray, list, tuple
Times as datetime objects.
"""
mjd = date2num(time, units='days since 1858-11-17 00:00:00')
Itime = np.floor(mjd) # integer Modified Julian Days
Itime2 = (mjd - Itime) * 24 * 60 * 60 * 1000 # milliseconds since midnight
Times = [t.strftime('%Y-%m-%dT%H:%M:%S.%f') for t in time]
# time
atts = {'units': 'days since 1858-11-17 00:00:00',
'format': 'modified julian day (MJD)',
'long_name': 'time',
'time_zone': 'UTC'}
self.add_variable('time', mjd, ['time'], attributes=atts, **kwargs)
# Itime
atts = {'units': 'days since 1858-11-17 00:00:00',
'format': 'modified julian day (MJD)',
'time_zone': 'UTC'}
self.add_variable('Itime', Itime, ['time'], attributes=atts, format='i', **kwargs)
# Itime2
atts = {'units': 'msec since 00:00:00', 'time_zone': 'UTC'}
self.add_variable('Itime2', Itime2, ['time'], attributes=atts, format='i', **kwargs)
# Times
atts = {'long_name': 'Calendar Date', 'format': 'String: Calendar Time', 'time_zone': 'UTC'}
self.add_variable('Times', Times, ['time', 'DateStrLen'], format='c', attributes=atts, **kwargs)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
""" Tidy up the netCDF file handle. """
self.nc.close()