Home > fvcom_prepro > write_FVCOM_tsobcERSEM.m

write_FVCOM_tsobcERSEM

PURPOSE ^

Export temperature and salinity forcing at the open boundary.

SYNOPSIS ^

function write_FVCOM_tsobcERSEM(tsOBCFile,FileExists,time,nSiglay,Mobj,ERSEMdata,varargin)

DESCRIPTION ^

 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
    tsOBCFile - Filename to use as output
    FileExists - True if tsOBCFile already exists and we only want to add
    ERSEM variables to it.
    time - Time (Modified Julian Days)
    nSiglay - Number of sigma layers
    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
    ERSEMdata - struct with information to output to Netcdf File

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function write_FVCOM_tsobcERSEM(tsOBCFile,FileExists,time,nSiglay,Mobj,ERSEMdata,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 %    tsOBCFile - Filename to use as output
0013 %    FileExists - True if tsOBCFile already exists and we only want to add
0014 %    ERSEM variables to it.
0015 %    time - Time (Modified Julian Days)
0016 %    nSiglay - Number of sigma layers
0017 %    Mobj - Mesh Object with the following fields:
0018 %       - nObs - number of open boundaries
0019 %       - read_obc_nodes - open boundary node cell array (length = nObs)
0020 %       - siglay - sigma layer definitions
0021 %       - siglev - sigma level definitions
0022 %    ERSEMdata - struct with information to output to Netcdf File
0023 
0024 %    Optional keyword-argument pairs:
0025 %
0026 %    'strtime' = set to true to output the 'Times' variable
0027 %    'inttime' = set to true to output the 'Itime' and 'Itime2' variables
0028 %    'floattime' = set to true to output the 'time' variable
0029 %
0030 %    This script defaults to writing 'Times' only.
0031 %
0032 %    FVCOM needs only one of:
0033 %        1. Times: character string of times
0034 %        2. Itime and Itime2: integer days and milliseconds since midnight
0035 %        3. time: float days.
0036 %    FVCOM checks for these in the order above and this script defaults to
0037 %    writing Times only. Adjust the keyword-argument pairs to your liking.
0038 %
0039 % OUTPUT:
0040 %    FVCOM hydrographic open boundary netCDF file
0041 %
0042 % Author(s):
0043 %    Geoff Cowles (University of Massachusetts Dartmouth)
0044 %    Pierre Cazenave (Plymouth Marine Laboratory)
0045 %    Karen Amoudry (National Oceanography Centre, Liverpool)
0046 %    Ricardo Torres (Plymouth Marine Laboratory)
0047 % PWC Revision history
0048 %    2012-06-15 Added support for native MATLAB NetCDF routines. Requires
0049 %    MATLAB 2010a or higher.
0050 %    2012-07-16 Removed hard-coded nSiglay and nSiglev and instead moved to
0051 %    arguments list.
0052 %    2012-10-08 Updated help to reflect the fact nSiglev is calculated as
0053 %    nSiglay+1.
0054 %    2012-11-09 Add new arguments to use user defined temperature and
0055 %    salinity.
0056 %    2013-01-09 Add support for 3D input temperature and salinity (such as
0057 %    might be generated with get_POLCOMS_tsobc.m.
0058 %    2016-05-25 Removed the reads of the ASCII configuration files (which
0059 %    was very slow) and instead extracted the relevant information from the
0060 %    supplied mesh object. As such, the requirements for the mesh object
0061 %    have changed, so hopefully this won't bite too many people in the
0062 %    behind. Also simplified the allocation of the arrays when uniform
0063 %    values are given (i.e. when in_salt and in_temp are scalars).
0064 %
0065 % KJA Revision history
0066 %    Undated - Add better check for the size of the input arrays (works
0067 %    with scalars).
0068 %    2013-08-16 - Updated output of Itime2 to avoid rounding errors
0069 %    when converting from double to single format.
0070 % RJT Revision history
0071 %    2013-12-05 Added functionality to output ERSEM nutrients
0072 %    2017-04-10 Option to write to an existing file... i.e. a Nesting file
0073 %==============================================================================
0074 
0075 [~, subname] = fileparts(mfilename('fullpath'));
0076 global ftbverbose
0077 if ftbverbose
0078     fprintf('\nbegin : %s\n', subname)
0079 end
0080 NNuts=length(ERSEMdata);
0081 % Default to string times as FVCOM looks for these first.
0082 strtime = true;
0083 inttime = false;
0084 floattime = false;
0085 for vv = 1:2:length(varargin)
0086     switch varargin{vv}
0087         case 'strtime'
0088             strtime = true;
0089         case 'inttime'
0090             inttime = true;
0091         case 'floattime'
0092             floattime = true;
0093     end
0094 end
0095 
0096 obc_nodes = [Mobj.read_obc_nodes{:}]';
0097 obc_h = Mobj.h(obc_nodes);
0098 siglev = Mobj.siglev(obc_nodes, :);
0099 siglay = Mobj.siglay(obc_nodes, :);
0100 
0101 nTimes = length(time);
0102 nObc = length(obc_nodes);
0103 nSiglev = nSiglay + 1;
0104 
0105 if ftbverbose; fprintf('obc reading complete\n'); end
0106 
0107 %--------------------------------------------------------------------------
0108 % Generate the requisite data
0109 %--------------------------------------------------------------------------
0110 
0111 
0112 % We need to make sigma level and layer data resolved for each node on the
0113 % open boundary (in case we have hybrid coordinates).
0114 if isvector(siglev)
0115     siglev = repmat(siglev, [nObc, 1]);
0116 end
0117 if isvector(siglay)
0118     siglay = repmat(siglay, [nObc, 1]);
0119 end
0120 
0121 % Check we've got everything the right size and shape.
0122 if nSiglev ~= size(Mobj.(ERSEMdata(1).name), 2) + 1 || size(siglev, 2) ~= size(Mobj.(ERSEMdata(1).name), 2) + 1 || size(siglev, 2) ~= size(Mobj.(ERSEMdata(2).name), 2) + 1
0123     error('Specified number sigma levels does not match supplied data')
0124 end
0125 if nSiglay ~= size(Mobj.(ERSEMdata(1).name), 2) || size(siglay, 2) ~= size(Mobj.(ERSEMdata(1).name), 2) || size(siglay, 2) ~= size(Mobj.(ERSEMdata(2).name), 2)
0126     error('Specified number of sigma layers does not match supplied data')
0127 end
0128 
0129 
0130 %--------------------------------------------------------------------------
0131 % Set netCDF variables and dump to file
0132 %--------------------------------------------------------------------------
0133 if FileExists
0134     % open boundary forcing
0135     nc = netcdf.open(tsOBCFile, 'WRITE');
0136     % read dimensions from the
0137     % define dimensions
0138     dimids = netcdf.inqDimIDs(nc);
0139     for dd =1:length(dimids)
0140         dimidname=netcdf.inqDim(nc,dimids(dd));
0141         switch dimidname
0142             case{'node'}
0143 
0144                 nobc_dimid=netcdf.inqDimID(nc,dimidname);
0145             case{'DateStrLen'}
0146                 datestrlen_dimid=netcdf.inqDimID(nc,dimidname);
0147             case{'time'}
0148 
0149                 time_dimid=netcdf.inqDimID(nc,dimidname);
0150                 % read time in case is different from data in file
0151                 file_times = netcdf.getVar(nc,netcdf.inqVarID(nc,'Times'))';
0152                 file_timem = datenum(file_times,'yyyy-mm-dd HH:MM:SS.FFF');
0153             case{'siglay'}
0154 
0155                 siglay_dimid=netcdf.inqDimID(nc,dimidname);
0156             case{'siglev'}
0157                 siglev_dimid=netcdf.inqDimID(nc,dimidname);
0158         end
0159     end
0160     netcdf.reDef(nc)
0161 else
0162     % open boundary forcing
0163     nc = netcdf.create(tsOBCFile, 'clobber');
0164 
0165     % define global attributes
0166     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'title','Open boundary ERSEM nudging')
0167     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'type','FVCOM TIME SERIES OBC FABM FILE')
0168     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'history', sprintf('File created with %s from the MATLAB fvcom-toolbox', subname))
0169 
0170 
0171     % define dimensions
0172     nobc_dimid=netcdf.defDim(nc,'nobc',nObc);
0173     datestrlen_dimid=netcdf.defDim(nc,'DateStrLen',26);
0174     time_dimid=netcdf.defDim(nc,'time',netcdf.getConstant('NC_UNLIMITED'));
0175     siglay_dimid=netcdf.defDim(nc,'siglay',nSiglay);
0176     siglev_dimid=netcdf.defDim(nc,'siglev',nSiglev);
0177 
0178     % variables
0179     if strtime
0180         Times_varid=netcdf.defVar(nc,'Times','NC_CHAR',[datestrlen_dimid, time_dimid]);
0181         netcdf.putAtt(nc,Times_varid,'time_zone','UTC');
0182     end
0183 
0184     if floattime
0185         time_varid=netcdf.defVar(nc,'time','NC_FLOAT',time_dimid);
0186         netcdf.putAtt(nc,time_varid,'long_name','time');
0187         netcdf.putAtt(nc,time_varid,'units','days since 1858-11-17 00:00:00');
0188         netcdf.putAtt(nc,time_varid,'time_zone','UTC');
0189     end
0190 
0191     if inttime
0192         itime_varid=netcdf.defVar(nc,'Itime','NC_INT',time_dimid);
0193         netcdf.putAtt(nc,itime_varid,'units','days since 1858-11-17 00:00:00');
0194         netcdf.putAtt(nc,itime_varid,'format','modified julian day (MJD)');
0195         netcdf.putAtt(nc,itime_varid,'time_zone','UTC');
0196 
0197         itime2_varid=netcdf.defVar(nc,'Itime2','NC_INT',time_dimid);
0198         netcdf.putAtt(nc,itime2_varid,'units','msec since 00:00:00');
0199         netcdf.putAtt(nc,itime2_varid,'time_zone','UTC');
0200     end
0201 
0202     nobc_varid=netcdf.defVar(nc,'obc_nodes','NC_INT',nobc_dimid);
0203     netcdf.putAtt(nc,nobc_varid,'long_name','Open Boundary Node Number');
0204     netcdf.putAtt(nc,nobc_varid,'grid','obc_grid');
0205     netcdf.putAtt(nc,nobc_varid,'type','data');
0206 
0207     obc_h_varid=netcdf.defVar(nc,'obc_h','NC_FLOAT',nobc_dimid);
0208     netcdf.putAtt(nc,obc_h_varid,'long_name','Open Boundary Depth');
0209     netcdf.putAtt(nc,obc_h_varid,'units','m');
0210     netcdf.putAtt(nc,obc_h_varid,'grid','obc_grid');
0211     netcdf.putAtt(nc,obc_h_varid,'type','data');
0212 
0213     obc_siglev_varid=netcdf.defVar(nc,'siglev','NC_FLOAT',[nobc_dimid,siglev_dimid]);
0214     netcdf.putAtt(nc,obc_siglev_varid,'long_name','ocean_sigma/general_coordinate');
0215     netcdf.putAtt(nc,obc_siglev_varid,'grid','obc_grid');
0216 
0217     obc_siglay_varid=netcdf.defVar(nc,'siglay','NC_FLOAT',[nobc_dimid,siglay_dimid]);
0218     netcdf.putAtt(nc,obc_siglay_varid,'long_name','ocean_sigma/general_coordinate');
0219     netcdf.putAtt(nc,obc_siglay_varid,'grid','obc_grid');
0220 end
0221 
0222 
0223 % nutrients here
0224 for nuts=1:NNuts
0225     varidN{nuts}=['obc_',ERSEMdata(nuts).name,'_varid'];
0226     eval([varidN{nuts},'=netcdf.defVar(nc,''',ERSEMdata(nuts).name,''',''NC_FLOAT'',[nobc_dimid,siglay_dimid,time_dimid]);'])
0227     eval(['netcdf.putAtt(nc,',varidN{nuts},',''long_name'',''',ERSEMdata(nuts).long_name,''');'])
0228     eval(['netcdf.putAtt(nc,',varidN{nuts},',''units'',''',ERSEMdata(nuts).units,''');'])
0229     eval(['netcdf.putAtt(nc,',varidN{nuts},',''grid'',''obc_grid'');'])
0230 % enable compression on the big variables.
0231     eval(['netcdf.defVarDeflate(nc, ',varidN{nuts},', true, true, 7);'])
0232 
0233     % obc_salinity_varid=netcdf.defVar(nc,'obc_salinity','NC_FLOAT',[nobc_dimid,siglay_dimid,time_dimid]);
0234     % netcdf.putAtt(nc,obc_salinity_varid,'long_name','sea_water_salinity');
0235     % netcdf.putAtt(nc,obc_salinity_varid,'units','PSU');
0236     % netcdf.putAtt(nc,obc_salinity_varid,'grid','obc_grid');
0237 end
0238 
0239 
0240 
0241 
0242 
0243 % end definitions
0244 netcdf.endDef(nc);
0245 
0246 if ~FileExists
0247     % grid and time information already exist in file...
0248     % write data
0249     netcdf.putVar(nc,nobc_varid,obc_nodes);
0250     netcdf.putVar(nc,obc_h_varid,obc_h);
0251     netcdf.putVar(nc,obc_siglev_varid,siglev);
0252     netcdf.putVar(nc,obc_siglay_varid,siglay);
0253     if strtime
0254         nStringOut = char();
0255         [nYr, nMon, nDay, nHour, nMin, nSec] = mjulian2greg(time);
0256         for i=1:nTimes
0257             nDate = [nYr(i), nMon(i), nDay(i), nHour(i), nMin(i), nSec(i)];
0258             nStringOut = [nStringOut, sprintf('%04i/%02i/%02i %02i:%02i:%09.6f', nDate)];
0259         end
0260         netcdf.putVar(nc,Times_varid,[0, 0],[26, nTimes],nStringOut);
0261     end
0262     if floattime
0263         netcdf.putVar(nc,time_varid,0,numel(time),time);
0264     end
0265     if inttime
0266         netcdf.putVar(nc,itime_varid,floor(time));
0267         % netcdf.putVar(nc,itime2_varid,0,numel(time),mod(time,1)*24*3600*1000); % PWC original
0268         % KJA edit: avoids rounding errors when converting from double to single
0269         % Rounds to nearest multiple of the number of msecs in an hour
0270         netcdf.putVar(nc,itime2_varid,0,numel(time),round((mod(time,1)*24*3600*1000)/(3600*1000))*(3600*1000));
0271     end
0272     for nuts=1:NNuts
0273         eval(['netcdf.putVar(nc,',varidN{nuts},',Mobj.(ERSEMdata(nuts).name));'])
0274             disp(['Finished with variable, ',ERSEMdata(nuts).name])
0275      end
0276 
0277 else % file exist and time could be different... check and interpolate if necessary
0278     if length(time) < length(file_timem)
0279         for nuts=1:NNuts
0280             data= Mobj.(ERSEMdata(nuts).name);
0281             dataint = nan(size(data, 1),size(data, 2),length(file_timem));
0282             for nn=1:size(data, 1)
0283                 [X1,Y1]=meshgrid(file_timem- 678942,siglay(nn,:));
0284                 [X,Y]=meshgrid(time,siglay(nn,:));
0285                 % interpolate ERSEMdata...
0286                 dataint(nn,:,:) = interp2(X,Y,squeeze(data(nn,:,:)),X1,Y1);
0287             end
0288             Nut_id= netcdf.inqVarID(nc,ERSEMdata(nuts).name);
0289 
0290             netcdf.putVar(nc,Nut_id,dataint);
0291             disp(['Finished with variable, ',ERSEMdata(nuts).name])
0292         end
0293     else
0294         % everything is in the same time frequency
0295         for nuts=1:NNuts
0296             eval(['netcdf.putVar(nc,',varidN{nuts},',Mobj.(ERSEMdata(nuts).name));'])
0297             disp(['We have reversed the Z dimension of variable , ',ERSEMdata(nuts).name])
0298             disp(['Finished with variable, ',ERSEMdata(nuts).name])
0299          end
0300 
0301     end
0302 end
0303 % close file
0304 netcdf.close(nc);
0305 
0306 if ftbverbose
0307     fprintf('end   : %s\n', subname)
0308 end

Generated on Wed 20-Feb-2019 16:06:01 by m2html © 2005