


Export temperature and salinity forcing at the open boundary.
function write_FVCOM_tsobc(basename,time,nSiglay,in_temp,in_salt)
DESCRIPTION:
Setup an FVCOM hydrographic open boundary forcing file. Supply either
uniform values for temperature and salinity or 3D arrays (node,
sigma_layers, time).
INPUT
basename - Model case name (to find the bathymetry and open boundary
.dat files).
time - Time (Modified Julian Days)
nSiglay - Number of sigma layers
in_temp - Boundary temperature (Celsius)
in_salt - Boundary salinity (psu)
Mobj - Mesh Object with the following fields:
- nObs - number of open boundaries
- read_obc_nodes - open boundary node cell array (length = nObs)
- siglay - sigma layer definitions
- siglev - sigma level definitions
Optional keyword-argument pairs:
'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
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.
OUTPUT:
FVCOM hydrographic open boundary netCDF file
Author(s):
Geoff Cowles (University of Massachusetts Dartmouth)
Pierre Cazenave (Plymouth Marine Laboratory)
Karen Amoudry (National Oceanography Centre, Liverpool)
PWC Revision history
2012-06-15 Added support for native MATLAB NetCDF routines. Requires
MATLAB 2010a or higher.
2012-07-16 Removed hard-coded nSiglay and nSiglev and instead moved to
arguments list.
2012-10-08 Updated help to reflect the fact nSiglev is calculated as
nSiglay+1.
2012-11-09 Add new arguments to use user defined temperature and
salinity.
2013-01-09 Add support for 3D input temperature and salinity (such as
might be generated with get_POLCOMS_tsobc.m.
2016-05-25 Removed the reads of the ASCII configuration files (which
was very slow) and instead extracted the relevant information from the
supplied mesh object. As such, the requirements for the mesh object
have changed, so hopefully this won't bite too many people in the
behind. Also simplified the allocation of the arrays when uniform
values are given (i.e. when in_salt and in_temp are scalars).
KJA Revision history
Undated - Add better check for the size of the input arrays (works
with scalars).
2013-08-16 - Updated output of Itime2 to avoid rounding errors
when converting from double to single format.
==========================================================================

0001 function write_FVCOM_tsobc(basename,time,nSiglay,in_temp,in_salt,Mobj,varargin) 0002 % Export temperature and salinity forcing at the open boundary. 0003 % 0004 % function write_FVCOM_tsobc(basename,time,nSiglay,in_temp,in_salt) 0005 % 0006 % DESCRIPTION: 0007 % Setup an FVCOM hydrographic open boundary forcing file. Supply either 0008 % uniform values for temperature and salinity or 3D arrays (node, 0009 % sigma_layers, time). 0010 % 0011 % INPUT 0012 % basename - Model case name (to find the bathymetry and open boundary 0013 % .dat files). 0014 % time - Time (Modified Julian Days) 0015 % nSiglay - Number of sigma layers 0016 % in_temp - Boundary temperature (Celsius) 0017 % in_salt - Boundary salinity (psu) 0018 % Mobj - Mesh Object with the following fields: 0019 % - nObs - number of open boundaries 0020 % - read_obc_nodes - open boundary node cell array (length = nObs) 0021 % - siglay - sigma layer definitions 0022 % - siglev - sigma level definitions 0023 % Optional keyword-argument pairs: 0024 % 0025 % 'strtime' = set to true to output the 'Times' variable 0026 % 'inttime' = set to true to output the 'Itime' and 'Itime2' variables 0027 % 'floattime' = set to true to output the 'time' variable 0028 % 0029 % This script defaults to writing 'Times' only. 0030 % 0031 % FVCOM needs only one of: 0032 % 1. Times: character string of times 0033 % 2. Itime and Itime2: integer days and milliseconds since midnight 0034 % 3. time: float days. 0035 % FVCOM checks for these in the order above and this script defaults to 0036 % writing Times only. Adjust the keyword-argument pairs to your liking. 0037 % 0038 % OUTPUT: 0039 % FVCOM hydrographic open boundary netCDF file 0040 % 0041 % Author(s): 0042 % Geoff Cowles (University of Massachusetts Dartmouth) 0043 % Pierre Cazenave (Plymouth Marine Laboratory) 0044 % Karen Amoudry (National Oceanography Centre, Liverpool) 0045 % 0046 % PWC Revision history 0047 % 2012-06-15 Added support for native MATLAB NetCDF routines. Requires 0048 % MATLAB 2010a or higher. 0049 % 2012-07-16 Removed hard-coded nSiglay and nSiglev and instead moved to 0050 % arguments list. 0051 % 2012-10-08 Updated help to reflect the fact nSiglev is calculated as 0052 % nSiglay+1. 0053 % 2012-11-09 Add new arguments to use user defined temperature and 0054 % salinity. 0055 % 2013-01-09 Add support for 3D input temperature and salinity (such as 0056 % might be generated with get_POLCOMS_tsobc.m. 0057 % 2016-05-25 Removed the reads of the ASCII configuration files (which 0058 % was very slow) and instead extracted the relevant information from the 0059 % supplied mesh object. As such, the requirements for the mesh object 0060 % have changed, so hopefully this won't bite too many people in the 0061 % behind. Also simplified the allocation of the arrays when uniform 0062 % values are given (i.e. when in_salt and in_temp are scalars). 0063 % 0064 % KJA Revision history 0065 % Undated - Add better check for the size of the input arrays (works 0066 % with scalars). 0067 % 2013-08-16 - Updated output of Itime2 to avoid rounding errors 0068 % when converting from double to single format. 0069 % 0070 %========================================================================== 0071 0072 if nargin == 5 0073 warning(['Assuming uniform terrain-following sigma coordinates. ', ... 0074 'To specify different sigma coordintes, supply a MATLAB mesh ', ... 0075 'structure with fields siglay and siglev.']) 0076 end 0077 0078 [~, subname] = fileparts(mfilename('fullpath')); 0079 global ftbverbose 0080 if ftbverbose 0081 fprintf('\nbegin : %s\n', subname) 0082 end 0083 0084 % Default to string times as FVCOM looks for these first. 0085 strtime = true; 0086 inttime = false; 0087 floattime = false; 0088 for vv = 1:2:length(varargin) 0089 switch varargin{vv} 0090 case 'strtime' 0091 strtime = true; 0092 case 'inttime' 0093 inttime = true; 0094 case 'floattime' 0095 floattime = true; 0096 end 0097 end 0098 0099 tsOBCFile = [basename, '_tsobc.nc']; 0100 0101 obc_nodes = [Mobj.read_obc_nodes{:}]'; 0102 obc_h = Mobj.h(obc_nodes); 0103 siglev = Mobj.siglev(obc_nodes, :); 0104 siglay = Mobj.siglay(obc_nodes, :); 0105 0106 nTimes = length(time); 0107 nObc = length(obc_nodes); 0108 nSiglev = nSiglay + 1; 0109 0110 %-------------------------------------------------------------------------- 0111 % Generate the requisite data 0112 %-------------------------------------------------------------------------- 0113 0114 if isscalar(in_temp) && isscalar(in_salt) 0115 % Make 3D arrays from the scalar values given. 0116 temp = repmat(in_temp, [nObc, nSiglay, nTimes]); 0117 salt = repmat(in_salt, [nObc, nSiglay, nTimes]); 0118 else 0119 % We have a 3D array already. 0120 temp = in_temp; 0121 salt = in_salt; 0122 end 0123 clear in_temp in_salt 0124 0125 % We need to make sigma level and layer data resolved for each node on the 0126 % open boundary (in case we have hybrid coordinates). 0127 if isvector(siglev) 0128 siglev = repmat(siglev, [nObc, 1]); 0129 end 0130 if isvector(siglay) 0131 siglay = repmat(siglay, [nObc, 1]); 0132 end 0133 0134 % Check we've got everything the right size and shape. 0135 if nSiglev ~= size(temp, 2) + 1 || size(siglev, 2) ~= size(temp, 2) + 1 || size(siglev, 2) ~= size(salt, 2) + 1 0136 error('Specified number sigma levels does not match supplied data') 0137 end 0138 if nSiglay ~= size(temp, 2) || size(siglay, 2) ~= size(temp, 2) || size(siglay, 2) ~= size(salt, 2) 0139 error('Specified number of sigma layers does not match supplied data') 0140 end 0141 0142 0143 %-------------------------------------------------------------------------- 0144 % Set netCDF variables and dump to file 0145 %-------------------------------------------------------------------------- 0146 0147 % open boundary forcing 0148 nc = netcdf.create(tsOBCFile, 'clobber'); 0149 0150 % define global attributes 0151 netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'title','Open boundary temperature and salinity nudging') 0152 netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'type','FVCOM TIME SERIES OBC TS FILE') 0153 netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'history', sprintf('File created with %s from the MATLAB fvcom-toolbox', subname)) 0154 0155 0156 % define dimensions 0157 nobc_dimid=netcdf.defDim(nc,'nobc',nObc); 0158 datestrlen_dimid=netcdf.defDim(nc,'DateStrLen',26); 0159 time_dimid=netcdf.defDim(nc,'time',netcdf.getConstant('NC_UNLIMITED')); 0160 siglay_dimid=netcdf.defDim(nc,'siglay',nSiglay); 0161 siglev_dimid=netcdf.defDim(nc,'siglev',nSiglev); 0162 0163 % variables 0164 if strtime 0165 Times_varid=netcdf.defVar(nc,'Times','NC_CHAR',[datestrlen_dimid, time_dimid]); 0166 netcdf.putAtt(nc,Times_varid,'time_zone','UTC'); 0167 end 0168 0169 if floattime 0170 time_varid=netcdf.defVar(nc,'time','NC_FLOAT',time_dimid); 0171 netcdf.putAtt(nc,time_varid,'long_name','time'); 0172 netcdf.putAtt(nc,time_varid,'units','days since 1858-11-17 00:00:00'); 0173 netcdf.putAtt(nc,time_varid,'time_zone','UTC'); 0174 end 0175 0176 if inttime 0177 itime_varid=netcdf.defVar(nc,'Itime','NC_INT',time_dimid); 0178 netcdf.putAtt(nc,itime_varid,'units','days since 1858-11-17 00:00:00'); 0179 netcdf.putAtt(nc,itime_varid,'format','modified julian day (MJD)'); 0180 netcdf.putAtt(nc,itime_varid,'time_zone','UTC'); 0181 0182 itime2_varid=netcdf.defVar(nc,'Itime2','NC_INT',time_dimid); 0183 netcdf.putAtt(nc,itime2_varid,'units','msec since 00:00:00'); 0184 netcdf.putAtt(nc,itime2_varid,'time_zone','UTC'); 0185 end 0186 0187 nobc_varid=netcdf.defVar(nc,'obc_nodes','NC_INT',nobc_dimid); 0188 netcdf.putAtt(nc,nobc_varid,'long_name','Open Boundary Node Number'); 0189 netcdf.putAtt(nc,nobc_varid,'grid','obc_grid'); 0190 netcdf.putAtt(nc,nobc_varid,'type','data'); 0191 0192 obc_h_varid=netcdf.defVar(nc,'obc_h','NC_FLOAT',nobc_dimid); 0193 netcdf.putAtt(nc,obc_h_varid,'long_name','Open Boundary Depth'); 0194 netcdf.putAtt(nc,obc_h_varid,'units','m'); 0195 netcdf.putAtt(nc,obc_h_varid,'grid','obc_grid'); 0196 netcdf.putAtt(nc,obc_h_varid,'type','data'); 0197 0198 obc_siglev_varid=netcdf.defVar(nc,'siglev','NC_FLOAT',[nobc_dimid,siglev_dimid]); 0199 netcdf.putAtt(nc,obc_siglev_varid,'long_name','ocean_sigma/general_coordinate'); 0200 netcdf.putAtt(nc,obc_siglev_varid,'grid','obc_grid'); 0201 0202 obc_siglay_varid=netcdf.defVar(nc,'siglay','NC_FLOAT',[nobc_dimid,siglay_dimid]); 0203 netcdf.putAtt(nc,obc_siglay_varid,'long_name','ocean_sigma/general_coordinate'); 0204 netcdf.putAtt(nc,obc_siglay_varid,'grid','obc_grid'); 0205 0206 obc_temp_varid=netcdf.defVar(nc,'obc_temp','NC_FLOAT',[nobc_dimid,siglay_dimid,time_dimid]); 0207 netcdf.putAtt(nc,obc_temp_varid,'long_name','sea_water_temperature'); 0208 netcdf.putAtt(nc,obc_temp_varid,'units','Celcius'); 0209 netcdf.putAtt(nc,obc_temp_varid,'grid','obc_grid'); 0210 0211 obc_salinity_varid=netcdf.defVar(nc,'obc_salinity','NC_FLOAT',[nobc_dimid,siglay_dimid,time_dimid]); 0212 netcdf.putAtt(nc,obc_salinity_varid,'long_name','sea_water_salinity'); 0213 netcdf.putAtt(nc,obc_salinity_varid,'units','PSU'); 0214 netcdf.putAtt(nc,obc_salinity_varid,'grid','obc_grid'); 0215 0216 % end definitions 0217 netcdf.endDef(nc); 0218 0219 % write data 0220 netcdf.putVar(nc,nobc_varid,obc_nodes); 0221 netcdf.putVar(nc,obc_h_varid,obc_h); 0222 netcdf.putVar(nc,obc_siglev_varid,siglev); 0223 netcdf.putVar(nc,obc_siglay_varid,siglay); 0224 if strtime 0225 nStringOut = char(); 0226 [nYr, nMon, nDay, nHour, nMin, nSec] = mjulian2greg(time); 0227 for i=1:nTimes 0228 nDate = [nYr(i), nMon(i), nDay(i), nHour(i), nMin(i), nSec(i)]; 0229 nStringOut = [nStringOut, sprintf('%04i/%02i/%02i %02i:%02i:%09.6f', nDate)]; 0230 end 0231 netcdf.putVar(nc,Times_varid,[0, 0],[26, nTimes],nStringOut); 0232 end 0233 if floattime 0234 netcdf.putVar(nc,time_varid,0,numel(time),time); 0235 end 0236 if inttime 0237 netcdf.putVar(nc,itime_varid,floor(time)); 0238 % netcdf.putVar(nc,itime2_varid,0,numel(time),mod(time,1)*24*3600*1000); % PWC original 0239 % KJA edit: avoids rounding errors when converting from double to single 0240 % Rounds to nearest multiple of the number of msecs in an hour 0241 netcdf.putVar(nc,itime2_varid,0,numel(time),round((mod(time,1)*24*3600*1000)/(3600*1000))*(3600*1000)); 0242 end 0243 netcdf.putVar(nc,obc_temp_varid,temp); 0244 netcdf.putVar(nc,obc_salinity_varid,salt); 0245 0246 % close file 0247 netcdf.close(nc); 0248 0249 if ftbverbose 0250 fprintf('end : %s\n', subname) 0251 end