


Write an FVCOM surface elevation time series forcing file
write_FVCOM_elevtide(Mobj, MJD, ElevationFile, MyTitle)
DESCRIPTION:
Write an FVCOM netCDF surface elevation forcing file
INPUT:
Mobj = Matlab mesh object with fields:
obc_nodes - array of boundary node IDs.
surfaceElevation - array of surface elevation values (shaped [space,
time]).
MJD = list of modified Modified Julian Dates of size [times] (defined
as unlimited in the netCDF file).
ElevationFile = name of netCDF file.
MyTitle = casename title, written as global attribute of netCDF file.
Optional keyword-argument pairs. These control the time variables. This
script defaults to writing 'Times' only.
FVCOM needs only one of:
1. Times: character string of times
2. Itime and Itime2: integer days and milliseconds since midnight
3. time: float days.
FVCOM checks for these in the order above and this script defaults to
writing Times only. Adjust the keyword-argument pairs to your liking:
'strtime' = set to true to output the 'Times' variable
'inttime' = set to true to output the 'Itime' and 'Itime2' variables
'floattime' = set to true to output the 'time' variable
OUTPUT:
ElevationFile, A netCDF FVCOM surface elevations tide forcing file
EXAMPLE USAGE
With default settings:
write_FVCOM_elevtide(Mobj, MJD, '/tmp/elevtide.nc, 'Shelf tides')
Enable the 'time' variable in the netCDF.
write_FVCOM_elevtide(Mobj, MJD, '/tmp/elevtide.nc, ...
'Shelf tides', 'floattime', true)
Author(s):
Pierre Cazenave (Plymouth Marine Laboratory)
Karen Amoudry (National Oceanography Centre Liverpool)
Revision history
2012-08-08 (PWC) First version.
2012-11-14 (PWC) Updated to expect Modified Julian Day rather than
doing the conversion in here. Also put the pieces in set_elevtide in
here to simplify the process of writing out an elevation input file.
2012-12-04 (KJA) Updated to use surface elevation and open boundary
nodes from Mobj.
2013-08-16 (KJA) Updated output of Itime2 to avoid rounding errors when
converting from double to single format.
2013-09-03 - Removed PWC's fix for timestrings. Issue was due to
rounding errors caused by mjulian2greg.m, which have now been fixed.
2014-01-27 - (PWC) Simplify the ftbverbose/report stuff.
2014-08-11 - (PWC) Add new flags to control which time variables to
use. FVCOM reads the 'Times' variable first if present, then falls back
to 'Itime' and 'Itime2' and finally 'time'. Also reinstate the original
version of the calculation of Itime2 as the rounding effect was
smoothing out the data too much, affecting its precision.
==========================================================================

0001 function write_FVCOM_elevtide(Mobj,MJD,ElevationFile,MyTitle,varargin) 0002 % Write an FVCOM surface elevation time series forcing file 0003 % 0004 % write_FVCOM_elevtide(Mobj, MJD, ElevationFile, MyTitle) 0005 % 0006 % DESCRIPTION: 0007 % Write an FVCOM netCDF surface elevation forcing file 0008 % 0009 % INPUT: 0010 % Mobj = Matlab mesh object with fields: 0011 % obc_nodes - array of boundary node IDs. 0012 % surfaceElevation - array of surface elevation values (shaped [space, 0013 % time]). 0014 % MJD = list of modified Modified Julian Dates of size [times] (defined 0015 % as unlimited in the netCDF file). 0016 % ElevationFile = name of netCDF file. 0017 % MyTitle = casename title, written as global attribute of netCDF file. 0018 % Optional keyword-argument pairs. These control the time variables. This 0019 % script defaults to writing 'Times' only. 0020 % FVCOM needs only one of: 0021 % 1. Times: character string of times 0022 % 2. Itime and Itime2: integer days and milliseconds since midnight 0023 % 3. time: float days. 0024 % FVCOM checks for these in the order above and this script defaults to 0025 % writing Times only. Adjust the keyword-argument pairs to your liking: 0026 % 0027 % 'strtime' = set to true to output the 'Times' variable 0028 % 'inttime' = set to true to output the 'Itime' and 'Itime2' variables 0029 % 'floattime' = set to true to output the 'time' variable 0030 % 0031 % OUTPUT: 0032 % ElevationFile, A netCDF FVCOM surface elevations tide forcing file 0033 % 0034 % EXAMPLE USAGE 0035 % With default settings: 0036 % write_FVCOM_elevtide(Mobj, MJD, '/tmp/elevtide.nc, 'Shelf tides') 0037 % Enable the 'time' variable in the netCDF. 0038 % write_FVCOM_elevtide(Mobj, MJD, '/tmp/elevtide.nc, ... 0039 % 'Shelf tides', 'floattime', true) 0040 % 0041 % Author(s): 0042 % Pierre Cazenave (Plymouth Marine Laboratory) 0043 % Karen Amoudry (National Oceanography Centre Liverpool) 0044 % 0045 % Revision history 0046 % 2012-08-08 (PWC) First version. 0047 % 2012-11-14 (PWC) Updated to expect Modified Julian Day rather than 0048 % doing the conversion in here. Also put the pieces in set_elevtide in 0049 % here to simplify the process of writing out an elevation input file. 0050 % 2012-12-04 (KJA) Updated to use surface elevation and open boundary 0051 % nodes from Mobj. 0052 % 2013-08-16 (KJA) Updated output of Itime2 to avoid rounding errors when 0053 % converting from double to single format. 0054 % 2013-09-03 - Removed PWC's fix for timestrings. Issue was due to 0055 % rounding errors caused by mjulian2greg.m, which have now been fixed. 0056 % 2014-01-27 - (PWC) Simplify the ftbverbose/report stuff. 0057 % 2014-08-11 - (PWC) Add new flags to control which time variables to 0058 % use. FVCOM reads the 'Times' variable first if present, then falls back 0059 % to 'Itime' and 'Itime2' and finally 'time'. Also reinstate the original 0060 % version of the calculation of Itime2 as the rounding effect was 0061 % smoothing out the data too much, affecting its precision. 0062 % 0063 %========================================================================== 0064 0065 global ftbverbose 0066 0067 subname = 'write_FVCOM_elevtide'; 0068 if ftbverbose; fprintf('\nbegin : %s \n', subname); end 0069 0070 % Default to string times as FVCOM looks for these first. 0071 strtime = true; 0072 inttime = false; 0073 floattime = false; 0074 for vv = 1:2:length(varargin) 0075 switch varargin{vv} 0076 case 'strtime' 0077 strtime = true; 0078 case 'inttime' 0079 inttime = true; 0080 case 'floattime' 0081 floattime = true; 0082 end 0083 end 0084 0085 % Get a list of the open boundary nodes. Transpose Mobj.obc_nodes so the 0086 % order of the boundary nodes is preserved. 0087 tmpObcNodes = Mobj.obc_nodes'; 0088 % Flip it back so it's the same shape as it would have been using the old 0089 % code. 0090 ObcNodes = tmpObcNodes(tmpObcNodes~=0)'; 0091 0092 %-------------------------------------------------------------------------- 0093 % Sanity check on input and dimensions 0094 %-------------------------------------------------------------------------- 0095 if ischar(MJD(1)) 0096 nTimes = size(MJD, 1); 0097 else 0098 nTimes = numel(MJD); 0099 end 0100 if ftbverbose; fprintf('Number of time steps %d\n',nTimes); end 0101 0102 nObcs = numel(ObcNodes); 0103 if ftbverbose; fprintf('Number of Open Boundary Nodes %d\n',nObcs); end 0104 0105 [chk1, chk2] = size(Mobj.surfaceElevation); 0106 if nObcs ~= chk1 || nTimes ~= chk2 0107 fprintf('Surface elevation dimensions do not match time series and number of boundary nodes.\n') 0108 fprintf('Surface elevation nodes and time sizes: (%d, %d)\n', chk1, chk2) 0109 fprintf('Boundary nodes size: %d\n', nObcs) 0110 fprintf('Times size: %d\n', nTimes) 0111 error('Input data sizes do not match. Check and try again.'); 0112 end 0113 0114 %% 0115 %-------------------------------------------------------------------------- 0116 % Dump the file 0117 %-------------------------------------------------------------------------- 0118 0119 nc=netcdf.create(ElevationFile,'clobber'); 0120 0121 % define global attributes 0122 netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'type','FVCOM TIME SERIES ELEVATION FORCING FILE') 0123 netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'title',MyTitle) 0124 netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'history', sprintf('File created with %s from the MATLAB fvcom-toolbox', subname)) 0125 0126 % define dimensions 0127 nobc_dimid=netcdf.defDim(nc,'nobc',nObcs); 0128 time_dimid=netcdf.defDim(nc,'time',netcdf.getConstant('NC_UNLIMITED')); 0129 date_str_len_dimid=netcdf.defDim(nc,'DateStrLen',26); 0130 0131 % define variables and attributes 0132 nobc_varid=netcdf.defVar(nc,'obc_nodes','NC_INT',nobc_dimid); 0133 netcdf.putAtt(nc,nobc_varid,'long_name','Open Boundary Node Number'); 0134 netcdf.putAtt(nc,nobc_varid,'grid','obc_grid'); 0135 0136 iint_varid=netcdf.defVar(nc,'iint','NC_INT',time_dimid); 0137 netcdf.putAtt(nc,iint_varid,'long_name','internal mode iteration number'); 0138 0139 if floattime 0140 time_varid=netcdf.defVar(nc,'time','NC_FLOAT',time_dimid); 0141 netcdf.putAtt(nc,time_varid,'long_name','time'); 0142 netcdf.putAtt(nc,time_varid,'units','days since 1858-11-17 00:00:00'); 0143 netcdf.putAtt(nc,time_varid,'format','modified julian day (MJD)'); 0144 netcdf.putAtt(nc,time_varid,'time_zone','UTC'); 0145 end 0146 0147 if inttime 0148 itime_varid=netcdf.defVar(nc,'Itime','NC_INT',time_dimid); 0149 netcdf.putAtt(nc,itime_varid,'units','days since 1858-11-17 00:00:00'); 0150 netcdf.putAtt(nc,itime_varid,'format','modified julian day (MJD)'); 0151 netcdf.putAtt(nc,itime_varid,'time_zone','UTC'); 0152 0153 itime2_varid=netcdf.defVar(nc,'Itime2','NC_INT',time_dimid); 0154 netcdf.putAtt(nc,itime2_varid,'units','msec since 00:00:00'); 0155 netcdf.putAtt(nc,itime2_varid,'time_zone','UTC'); 0156 end 0157 0158 if strtime 0159 Times_varid=netcdf.defVar(nc,'Times','NC_CHAR',[date_str_len_dimid, time_dimid]); 0160 netcdf.putAtt(nc,Times_varid,'time_zone','UTC'); 0161 end 0162 0163 elevation_varid=netcdf.defVar(nc,'elevation','NC_FLOAT',[nobc_dimid, time_dimid]); 0164 netcdf.putAtt(nc,elevation_varid,'long_name','Open Boundary Elevation'); 0165 netcdf.putAtt(nc,elevation_varid,'units','meters'); 0166 0167 % end definitions 0168 netcdf.endDef(nc); 0169 0170 % write data 0171 netcdf.putVar(nc,nobc_varid,ObcNodes); 0172 netcdf.putVar(nc,iint_varid,0,nTimes,1:nTimes); 0173 if strtime 0174 % If out MJD data is characters, assume we've already got a suitable 0175 % array of Time strings. Use those to create an MJD array to write to 0176 % netCDF. This is sometimes preferable to having MJD as an array of 0177 % floats in the case where we've read in a 'time' variable from a 0178 % netCDF file and its precision is insufficient to actually store the 0179 % times properly. netCDF, otherwise, create one assuming we've actually 0180 % got Modified Julian Days. If we've been given an array of floats, 0181 % then just dump those to netCDF as before. 0182 if ischar(MJD(1)) 0183 nStringOut = MJD'; 0184 MJD = datenum(nStringOut', 'YYYY-mm-dd HH:MM:SS.FFF') - 678942; 0185 else 0186 nStringOut = char(); 0187 [nYr, nMon, nDay, nHour, nMin, nSec] = mjulian2greg(MJD); 0188 for i=1:nTimes 0189 nDate = [nYr(i), nMon(i), nDay(i), nHour(i), nMin(i), nSec(i)]; 0190 nStringOut = [nStringOut, sprintf('%04i/%02i/%02i %02i:%02i:%09.6f', nDate)]; 0191 end 0192 end 0193 netcdf.putVar(nc,Times_varid,nStringOut); 0194 end 0195 if floattime 0196 netcdf.putVar(nc,time_varid,0,nTimes,MJD); 0197 end 0198 if inttime 0199 netcdf.putVar(nc,itime_varid,floor(MJD)); 0200 netcdf.putVar(nc,itime2_varid,0,nTimes,round(mod(MJD,1) * 24 * 60 * 60 * 1000)); 0201 end 0202 netcdf.putVar(nc,elevation_varid,Mobj.surfaceElevation); 0203 0204 % close file 0205 netcdf.close(nc); 0206 0207 if ftbverbose; fprintf('end : %s \n', subname); end 0208