Home > fvcom_prepro > write_FVCOM_forcing.m

write_FVCOM_forcing

PURPOSE ^

Write data out to FVCOM netCDF forcing file.

SYNOPSIS ^

function write_FVCOM_forcing(Mobj, fileprefix, data, infos, fver, varargin)

DESCRIPTION ^

 Write data out to FVCOM netCDF forcing file.

 write_FVCOM_forcing(Mobj, fvcom_forcing_file, data, infos, fver)

 DESCRIPTION:
   Takes the given interpolated data (e.g. from grid2fvcom) and writes out
   to a netCDF file.

 INPUT:
   Mobj - MATLAB mesh object containing fields:
       tri - triangulation table for the unstructured grid
       nVerts - number of grid vertices (nodes)
       nElems - number of grid elements
       nativeCoords - model coordinate type ('cartesian' or 'spherical')
       x, y or lon, lat - node positions (depending on nativeCoords value)
   fileprefix - Output netCDF file prefix (plus path) will be
       fileprefix_{wnd,hfx,evap}.nc if fver is '3.1.0', otherwise output
       files will be fileprefix_wnd.nc.
   data - Struct of the data to be written out.
   infos - Additional remarks to be written to the "infos" netCDF variable
   fver - Output for version 3.1.0 or 3.1.6. The latter means all the
       forcing can go in a single file, the former needs separate files
       for specific forcing data (wind, heating and precipitation).
   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

 The fields in data may be called any of:
     - 'u10', 'v10' or 'uwnd', 'vwnd' - wind components
     - 'Et' or 'evap'      - evaporation
     - 'prate' or 'P_E'    - precipitation
     - 'nlwrs'             - net longwave radiation*,**
     - 'nswrs'             - net shortwave radiation*,**,***
     - 'shtfl'             - sensible heat net flux*,**
     - 'lhtfl'             - latent heat net flux*,**
     - 'slp' or 'pres'     - mean sea level pressure***
     - 'dswrf'             - downward shortwave flux
     - 'dlwrf'             - downward longwave flux***
     - 'rhum'              - relative humidity***
     - 'air'               - air temperature***
     - 'lon'               - longitude (vector)
     - 'lat'               - latitude (vector)
     - 'x'                 - eastings (vector)
     - 'y'                 - northings (vector)
     - 'nshf'              - pre-computed net surface heat flux**
     - 'lcc'               - low cloud cover

 Fields marked with an * are combined to form the "surface net heat flux"
 (nshf) as follows:

   nshf = nlwrs + nswrs - lhtfl - shtfl;

 ** Alternatively, a new field 'nshf' (net surface heat flux) can be
 supplied, in which case shtfl and lhtfl are not necessary as their only
 function is in the calculation of net surface heat flux. This approach
 eliminates the need to interpolate so many variables onto the FVCOM grid,
 thus decreasing the time needed to generate the FVCOM input files.

 *** These fields are required for HEATING_CALCULATED model input files.

 OUTPUT:
   FVCOM forcing netCDF file(s)

 EXAMPLE USAGE:
   windBase = '/path/to/output/casename_wnd.nc';
   write_FVCOM_forcing(Mobj, windBase, data, ...
       'FVCOM atmospheric forcing data', '3.1.6');

 Author(s):
   Pierre Cazenave (Plymouth Marine Laboratory)
   Karen Amoudry (National Oceanography Centre, Liverpool)
   Rory O'Hara Murray (Marine Scotland Science)

 PWC Revision history:
   2012-11-01 - First version based on the parts of grid2fvcom_U10V10.m
   which dealt with writing the netCDF file. This version now dynamically
   deals with varying numbers of forcing data.
   2012-11-09 - Add the correct calculation for the net surface heat flux.
   2013-02-14 - Fix the surface net heat flux sign convention, include the
   longwave radiation variable and add support for a new field in the
   input struct ('nshf') which contains the pre-computed net surface heat
   flux.
   2013-05-13 - Fix the evaporation to use the correct variable from NCEP
   (pevpr rather than P_E which is actually the precipitation minus the
   evaporation in Et). The data in Et are calcaulated from lhtfl whereas
   pevpr comes directly from NCEP and to me it seems more sensible to use
   that to maintain consistency.
   2013-05-14 - Add example usage to the help and specify which fields are
   required in Mobj.
   2013-06-21 - Remove support for pevpr (pevpr is in W/m^{2} from the
   NCEP Reanalysis 2 data (FVCOM wants evaporation in m/s). Update the
   help accordingly.
   2013-10-24 - Add support for writing all the variables needed for a
   HEATING_CALCULATED model run. This essentially makes
   write_FVCOM_heating redundant, but I'll leave it in as it's a bit
   simpler to understand what's going on there. Also update the way the
   net surface heat flux is calculated (sum long and short, subtract
   latent and sensible).
   2014-01-08 - Fix the way the wind variables are handled so that both
   the U10/V10 and uwind_speed/vwind_speed netCDF variables are written if
   only one of data.u10/data.v10 or data.uwnd/data.vwnd is given.
   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'.

 KJA Revision history:
   2013-01-16 - Added support for output of sea level pressure.
   2013-08-16 - 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.
   2013-09-26 - Added support for output of low cloud cover and specific
   humidity.

 ROM Revision History:
   2013-12-02 Change the output of tri' to tri, as tri was being written
   the wrong way around.

==========================================================================

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function write_FVCOM_forcing(Mobj, fileprefix, data, infos, fver, varargin)
0002 % Write data out to FVCOM netCDF forcing file.
0003 %
0004 % write_FVCOM_forcing(Mobj, fvcom_forcing_file, data, infos, fver)
0005 %
0006 % DESCRIPTION:
0007 %   Takes the given interpolated data (e.g. from grid2fvcom) and writes out
0008 %   to a netCDF file.
0009 %
0010 % INPUT:
0011 %   Mobj - MATLAB mesh object containing fields:
0012 %       tri - triangulation table for the unstructured grid
0013 %       nVerts - number of grid vertices (nodes)
0014 %       nElems - number of grid elements
0015 %       nativeCoords - model coordinate type ('cartesian' or 'spherical')
0016 %       x, y or lon, lat - node positions (depending on nativeCoords value)
0017 %   fileprefix - Output netCDF file prefix (plus path) will be
0018 %       fileprefix_{wnd,hfx,evap}.nc if fver is '3.1.0', otherwise output
0019 %       files will be fileprefix_wnd.nc.
0020 %   data - Struct of the data to be written out.
0021 %   infos - Additional remarks to be written to the "infos" netCDF variable
0022 %   fver - Output for version 3.1.0 or 3.1.6. The latter means all the
0023 %       forcing can go in a single file, the former needs separate files
0024 %       for specific forcing data (wind, heating and precipitation).
0025 %   Optional keyword-argument pairs. These control the time variables. This
0026 %   script defaults to writing 'Times' only.
0027 %   FVCOM needs only one of:
0028 %       1. Times: character string of times
0029 %       2. Itime and Itime2: integer days and milliseconds since midnight
0030 %       3. time: float days.
0031 %   FVCOM checks for these in the order above and this script defaults to
0032 %   writing Times only. Adjust the keyword-argument pairs to your liking:
0033 %
0034 %   'strtime' = set to true to output the 'Times' variable
0035 %   'inttime' = set to true to output the 'Itime' and 'Itime2' variables
0036 %   'floattime' = set to true to output the 'time' variable
0037 %
0038 % The fields in data may be called any of:
0039 %     - 'u10', 'v10' or 'uwnd', 'vwnd' - wind components
0040 %     - 'Et' or 'evap'      - evaporation
0041 %     - 'prate' or 'P_E'    - precipitation
0042 %     - 'nlwrs'             - net longwave radiation*,**
0043 %     - 'nswrs'             - net shortwave radiation*,**,***
0044 %     - 'shtfl'             - sensible heat net flux*,**
0045 %     - 'lhtfl'             - latent heat net flux*,**
0046 %     - 'slp' or 'pres'     - mean sea level pressure***
0047 %     - 'dswrf'             - downward shortwave flux
0048 %     - 'dlwrf'             - downward longwave flux***
0049 %     - 'rhum'              - relative humidity***
0050 %     - 'air'               - air temperature***
0051 %     - 'lon'               - longitude (vector)
0052 %     - 'lat'               - latitude (vector)
0053 %     - 'x'                 - eastings (vector)
0054 %     - 'y'                 - northings (vector)
0055 %     - 'nshf'              - pre-computed net surface heat flux**
0056 %     - 'lcc'               - low cloud cover
0057 %
0058 % Fields marked with an * are combined to form the "surface net heat flux"
0059 % (nshf) as follows:
0060 %
0061 %   nshf = nlwrs + nswrs - lhtfl - shtfl;
0062 %
0063 % ** Alternatively, a new field 'nshf' (net surface heat flux) can be
0064 % supplied, in which case shtfl and lhtfl are not necessary as their only
0065 % function is in the calculation of net surface heat flux. This approach
0066 % eliminates the need to interpolate so many variables onto the FVCOM grid,
0067 % thus decreasing the time needed to generate the FVCOM input files.
0068 %
0069 % *** These fields are required for HEATING_CALCULATED model input files.
0070 %
0071 % OUTPUT:
0072 %   FVCOM forcing netCDF file(s)
0073 %
0074 % EXAMPLE USAGE:
0075 %   windBase = '/path/to/output/casename_wnd.nc';
0076 %   write_FVCOM_forcing(Mobj, windBase, data, ...
0077 %       'FVCOM atmospheric forcing data', '3.1.6');
0078 %
0079 % Author(s):
0080 %   Pierre Cazenave (Plymouth Marine Laboratory)
0081 %   Karen Amoudry (National Oceanography Centre, Liverpool)
0082 %   Rory O'Hara Murray (Marine Scotland Science)
0083 %
0084 % PWC Revision history:
0085 %   2012-11-01 - First version based on the parts of grid2fvcom_U10V10.m
0086 %   which dealt with writing the netCDF file. This version now dynamically
0087 %   deals with varying numbers of forcing data.
0088 %   2012-11-09 - Add the correct calculation for the net surface heat flux.
0089 %   2013-02-14 - Fix the surface net heat flux sign convention, include the
0090 %   longwave radiation variable and add support for a new field in the
0091 %   input struct ('nshf') which contains the pre-computed net surface heat
0092 %   flux.
0093 %   2013-05-13 - Fix the evaporation to use the correct variable from NCEP
0094 %   (pevpr rather than P_E which is actually the precipitation minus the
0095 %   evaporation in Et). The data in Et are calcaulated from lhtfl whereas
0096 %   pevpr comes directly from NCEP and to me it seems more sensible to use
0097 %   that to maintain consistency.
0098 %   2013-05-14 - Add example usage to the help and specify which fields are
0099 %   required in Mobj.
0100 %   2013-06-21 - Remove support for pevpr (pevpr is in W/m^{2} from the
0101 %   NCEP Reanalysis 2 data (FVCOM wants evaporation in m/s). Update the
0102 %   help accordingly.
0103 %   2013-10-24 - Add support for writing all the variables needed for a
0104 %   HEATING_CALCULATED model run. This essentially makes
0105 %   write_FVCOM_heating redundant, but I'll leave it in as it's a bit
0106 %   simpler to understand what's going on there. Also update the way the
0107 %   net surface heat flux is calculated (sum long and short, subtract
0108 %   latent and sensible).
0109 %   2014-01-08 - Fix the way the wind variables are handled so that both
0110 %   the U10/V10 and uwind_speed/vwind_speed netCDF variables are written if
0111 %   only one of data.u10/data.v10 or data.uwnd/data.vwnd is given.
0112 %   2014-08-11 - (PWC) Add new flags to control which time variables to
0113 %   use. FVCOM reads the 'Times' variable first if present, then falls back
0114 %   to 'Itime' and 'Itime2' and finally 'time'.
0115 %
0116 % KJA Revision history:
0117 %   2013-01-16 - Added support for output of sea level pressure.
0118 %   2013-08-16 - Updated output of Itime2 to avoid rounding errors
0119 %   when converting from double to single format.
0120 %   2013-09-03 - Removed PWC's fix for timestrings. Issue was due to
0121 %   rounding errors caused by mjulian2greg.m, which have now been fixed.
0122 %   2013-09-26 - Added support for output of low cloud cover and specific
0123 %   humidity.
0124 %
0125 % ROM Revision History:
0126 %   2013-12-02 Change the output of tri' to tri, as tri was being written
0127 %   the wrong way around.
0128 %
0129 %==========================================================================
0130 
0131 multi_out = false; % default to 3.1.6, single output file
0132 if (nargin < 4 || nargin > 5) && isempty(varargin)
0133     error('Incorrect number of arguments')
0134 elseif nargin == 5
0135     if strcmpi(fver, '3.1.0')
0136         multi_out = true;
0137     end
0138 end
0139 
0140 subname = 'write_FVCOM_forcing';
0141 
0142 global ftbverbose;
0143 if ftbverbose
0144     fprintf('\nbegin : %s \n', subname)
0145 end
0146 
0147 % Default to string times as FVCOM looks for these first.
0148 strtime = true;
0149 inttime = false;
0150 floattime = false;
0151 for vv = 1:2:length(varargin)
0152     switch varargin{vv}
0153         case 'strtime'
0154             strtime = true;
0155         case 'inttime'
0156             inttime = true;
0157         case 'floattime'
0158             floattime = true;
0159     end
0160 end
0161 
0162 tri = Mobj.tri;
0163 nNodes = Mobj.nVerts;
0164 nElems = Mobj.nElems;
0165 ntimes = numel(data.time);
0166 
0167 if strcmpi(Mobj.nativeCoords, 'cartesian')
0168     x = Mobj.x;
0169     y = Mobj.y;
0170 else
0171     x = Mobj.lon;
0172     y = Mobj.lat;
0173 end
0174 % Create a string for each variable's coordinate attribute
0175 coordString = sprintf('FVCOM %s coordinates', Mobj.nativeCoords);
0176 
0177 % Create element vertices positions
0178 xc = nodes2elems(x, Mobj);
0179 yc = nodes2elems(y, Mobj);
0180 
0181 %--------------------------------------------------------------------------
0182 % Create the netCDF header for the FVCOM forcing file
0183 %--------------------------------------------------------------------------
0184 
0185 if multi_out
0186     suffixes = {'_wnd', '_hfx', '_evap', '_air_press'};
0187 else
0188     suffixes = {'_wnd'};
0189 end
0190 
0191 % We use this variable to indicate whether we were given precalculated net
0192 % surface heat flux.
0193 nshf = 0;
0194 
0195 for i=1:length(suffixes)
0196     nc = netcdf.create([fileprefix, suffixes{i}, '.nc'], 'clobber');
0197 
0198 %     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'type','FVCOM Forcing File')
0199     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'title','FVCOM Forcing File')
0200     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'institution','Plymouth Marine Laboratory')
0201     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'source','FVCOM grid (unstructured) surface forcing')
0202     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'history', sprintf('File created with %s from the MATLAB fvcom-toolbox', subname))
0203     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'references','http://fvcom.smast.umassd.edu, http://codfish.smast.umassd.edu')
0204     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'Conventions','CF-1.0')
0205 %     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'infos',infos)
0206     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'CoordinateSystem',Mobj.nativeCoords)
0207     netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'CoordinateProjection','init=epsg:4326') % WGS84?
0208 
0209     % Dimensions
0210     nele_dimid=netcdf.defDim(nc,'nele',nElems);
0211     node_dimid=netcdf.defDim(nc,'node',nNodes);
0212     three_dimid=netcdf.defDim(nc,'three',3);
0213     time_dimid=netcdf.defDim(nc,'time',netcdf.getConstant('NC_UNLIMITED'));
0214     datestrlen_dimid=netcdf.defDim(nc,'DateStrLen',26);
0215 
0216     % Space variables
0217     x_varid=netcdf.defVar(nc,'x','NC_FLOAT',node_dimid);
0218     netcdf.putAtt(nc,x_varid,'long_name','nodal x-coordinate');
0219     netcdf.putAtt(nc,x_varid,'units','meters');
0220 
0221     y_varid=netcdf.defVar(nc,'y','NC_FLOAT',node_dimid);
0222     netcdf.putAtt(nc,y_varid,'long_name','nodal y-coordinate');
0223     netcdf.putAtt(nc,y_varid,'units','meters');
0224 
0225     xc_varid=netcdf.defVar(nc,'xc','NC_FLOAT',nele_dimid);
0226     netcdf.putAtt(nc,xc_varid,'long_name','zonal x-coordinate');
0227     netcdf.putAtt(nc,xc_varid,'units','meters');
0228 
0229     yc_varid=netcdf.defVar(nc,'yc','NC_FLOAT',nele_dimid);
0230     netcdf.putAtt(nc,yc_varid,'long_name','zonal y-coordinate');
0231     netcdf.putAtt(nc,yc_varid,'units','meters');
0232 
0233     nv_varid=netcdf.defVar(nc,'nv','NC_INT',[nele_dimid, three_dimid]);
0234     netcdf.putAtt(nc,nv_varid,'long_name','nodes surrounding element');
0235 
0236     % Time variables
0237     if floattime
0238         time_varid=netcdf.defVar(nc,'time','NC_FLOAT',time_dimid);
0239         netcdf.putAtt(nc,time_varid,'long_name','time');
0240         netcdf.putAtt(nc,time_varid,'units','days since 1858-11-17 00:00:00');
0241         netcdf.putAtt(nc,time_varid,'format','modified julian day (MJD)');
0242         netcdf.putAtt(nc,time_varid,'time_zone','UTC');
0243     end
0244 
0245     if inttime
0246         itime_varid=netcdf.defVar(nc,'Itime','NC_INT',time_dimid);
0247         netcdf.putAtt(nc,itime_varid,'units','days since 1858-11-17 00:00:00');
0248         netcdf.putAtt(nc,itime_varid,'format','modified julian day (MJD)');
0249         netcdf.putAtt(nc,itime_varid,'time_zone','UTC');
0250 
0251         itime2_varid=netcdf.defVar(nc,'Itime2','NC_INT',time_dimid);
0252         netcdf.putAtt(nc,itime2_varid,'units','msec since 00:00:00');
0253         netcdf.putAtt(nc,itime2_varid,'time_zone','UTC');
0254         netcdf.putAtt(nc,itime2_varid,'long_name','time');
0255     end
0256 
0257     if strtime
0258         times_varid=netcdf.defVar(nc,'Times','NC_CHAR',[datestrlen_dimid,time_dimid]);
0259         netcdf.putAtt(nc,times_varid,'long_name','Calendar Date');
0260         netcdf.putAtt(nc,times_varid,'format','String: Calendar Time');
0261         netcdf.putAtt(nc,times_varid,'time_zone','UTC');
0262     end
0263 
0264     % Since we have a dynamic number of variables in the struct, try to be
0265     % a bit clever about how to create the output variables.
0266     fnames = fieldnames(data);
0267     used_varids = cell(0);
0268     used_fnames = cell(0);
0269     used_dims = cell(0); % exclude time (assume all variables vary in time)
0270 
0271     for vv=1:length(fnames)
0272         % Need to check both whether we have the data but also whether
0273         % we're outputting to several netCDF files. If so, we drop some
0274         % variables if we're in the wrong file loop.
0275         switch fnames{vv}
0276             case {'uwnd', 'u10'}
0277                 if strcmpi(suffixes{i}, '_wnd') || ~multi_out
0278                     % wind components (assume we have v if we have u)
0279 
0280                     % On the elements
0281                     u10_varid=netcdf.defVar(nc,'U10','NC_FLOAT',[nele_dimid, time_dimid]);
0282                     netcdf.putAtt(nc,u10_varid,'long_name','Eastward Wind Speed');
0283                     netcdf.putAtt(nc,u10_varid,'units','m/s');
0284                     netcdf.putAtt(nc,u10_varid,'grid','fvcom_grid');
0285                     netcdf.putAtt(nc,u10_varid,'coordinates',coordString);
0286                     netcdf.putAtt(nc,u10_varid,'type','data');
0287 
0288                     v10_varid=netcdf.defVar(nc,'V10','NC_FLOAT',[nele_dimid, time_dimid]);
0289                     netcdf.putAtt(nc,v10_varid,'long_name','Northward Wind Speed');
0290                     netcdf.putAtt(nc,v10_varid,'units','m/s');
0291                     netcdf.putAtt(nc,v10_varid,'grid','fvcom_grid');
0292                     netcdf.putAtt(nc,v10_varid,'coordinates',coordString);
0293                     netcdf.putAtt(nc,v10_varid,'type','data');
0294 
0295                     uwind_varid=netcdf.defVar(nc,'uwind_speed','NC_FLOAT',[nele_dimid, time_dimid]);
0296                     netcdf.putAtt(nc,uwind_varid,'long_name','Eastward Wind Speed');
0297                     netcdf.putAtt(nc,uwind_varid,'standard_name','Wind Speed');
0298                     netcdf.putAtt(nc,uwind_varid,'units','m/s');
0299                     netcdf.putAtt(nc,uwind_varid,'grid','fvcom_grid');
0300                     netcdf.putAtt(nc,uwind_varid,'type','data');
0301 
0302                     vwind_varid=netcdf.defVar(nc,'vwind_speed','NC_FLOAT',[nele_dimid, time_dimid]);
0303                     netcdf.putAtt(nc,vwind_varid,'long_name','Northward Wind Speed');
0304                     netcdf.putAtt(nc,vwind_varid,'standard_name','Wind Speed');
0305                     netcdf.putAtt(nc,vwind_varid,'units','m/s');
0306                     netcdf.putAtt(nc,vwind_varid,'grid','fvcom_grid');
0307                     netcdf.putAtt(nc,vwind_varid,'type','data');
0308 
0309                     % Only on the elements (both U10/V10 and uwind_speed
0310                     % and vwind_speed).
0311                     used_varids = [used_varids, {'u10_varid', 'v10_varid', 'uwind_varid', 'vwind_varid'}];
0312                     % We should only have one of {u,v}wnd or {u,v}10 as the
0313                     % field name and used_fnames needs to reflect that.
0314                     if isfield(data, 'uwnd') && ~isfield(data, 'u10')
0315                         % We have uwnd and vwnd variants (no u10/v10).
0316                         used_fnames = [used_fnames, {'uwnd', 'vwnd', 'uwnd', 'vwnd'}];
0317                     elseif isfield(data, 'u10') && ~isfield(data, 'uwnd')
0318                         % We have only u10 and v10 variants (no uwnd/vwnd)
0319                         used_fnames = [used_fnames, {'u10', 'v10', 'u10', 'v10'}];
0320                     elseif isfield(data, 'u10') && isfield(data, 'uwnd')
0321                         error('Supply only one set of wind fields: ''uwnd'' and ''vwnd'' or ''u10'' and ''v10''.')
0322                     else
0323                         error('Unrecognised wind field names.')
0324                     end
0325                     used_dims = [used_dims, {'nElems', 'nElems', 'nElems', 'nElems'}];
0326                 end
0327 
0328             case {'vwnd', 'v10'}
0329                 % We dealt with these in the u component section above, so
0330                 % just pass silently.
0331                 true;
0332 
0333             case {'slp', 'pres'}
0334                 if strcmpi(suffixes{i}, '_air_press') || ~multi_out
0335                     % Sea level pressure
0336                     slp_varid=netcdf.defVar(nc,'air_pressure','NC_FLOAT',[node_dimid, time_dimid]);
0337                     netcdf.putAtt(nc,slp_varid,'long_name','Surface air pressure');
0338                     netcdf.putAtt(nc,slp_varid,'units','Pa');
0339                     netcdf.putAtt(nc,slp_varid,'grid','fvcom_grid');
0340                     netcdf.putAtt(nc,slp_varid,'coordinates',coordString);
0341                     netcdf.putAtt(nc,slp_varid,'type','data');
0342 
0343                     used_varids = [used_varids, 'slp_varid'];
0344                     used_fnames = [used_fnames, fnames{vv}];
0345                     used_dims = [used_dims, 'nNodes'];
0346                 end
0347 
0348             case 'lcc'
0349                 if strcmpi(suffixes{i}, '_low_cloud_cover') || ~multi_out
0350                     % Low cloud cover
0351                     slp_varid=netcdf.defVar(nc,'low_cloud_cover','NC_FLOAT',[node_dimid, time_dimid]);
0352                     netcdf.putAtt(nc,slp_varid,'long_name','Low cloud cover');
0353                     netcdf.putAtt(nc,slp_varid,'units','Fraction');
0354                     netcdf.putAtt(nc,slp_varid,'grid','fvcom_grid');
0355                     netcdf.putAtt(nc,slp_varid,'coordinates',coordString);
0356                     netcdf.putAtt(nc,slp_varid,'type','data');
0357 
0358                     used_varids = [used_varids, 'lcc_varid'];
0359                     used_fnames = [used_fnames, fnames{vv}];
0360                     used_dims = [used_dims, 'nNodes'];
0361                 end
0362 
0363             case 'shum'
0364                 if strcmpi(suffixes{i}, '_specific_humidity') || ~multi_out
0365                     % Specific humidity
0366                     slp_varid=netcdf.defVar(nc,'specific_humidity','NC_FLOAT',[node_dimid, time_dimid]);
0367                     netcdf.putAtt(nc,slp_varid,'long_name','Specific humidity');
0368                     netcdf.putAtt(nc,slp_varid,'units','Kg kg^-1');
0369                     netcdf.putAtt(nc,slp_varid,'grid','fvcom_grid');
0370                     netcdf.putAtt(nc,slp_varid,'coordinates',coordString);
0371                     netcdf.putAtt(nc,slp_varid,'type','data');
0372 
0373                     used_varids = [used_varids, 'shum_varid'];
0374                     used_fnames = [used_fnames, fnames{vv}];
0375                     used_dims = [used_dims, 'nNodes'];
0376                 end
0377 
0378             case {'Et', 'evap'}
0379                 if strcmpi(suffixes{i}, '_evap') || ~multi_out
0380                     % Evaporation
0381                     pevpr_varid=netcdf.defVar(nc,'evap','NC_FLOAT',[node_dimid, time_dimid]);
0382                     netcdf.putAtt(nc,pevpr_varid,'long_name','Evaporation');
0383                     netcdf.putAtt(nc,pevpr_varid,'description','Evaporation, ocean lose water is negative');
0384                     netcdf.putAtt(nc,pevpr_varid,'units','m s-1');
0385                     netcdf.putAtt(nc,pevpr_varid,'grid','fvcom_grid');
0386                     netcdf.putAtt(nc,pevpr_varid,'coordinates',coordString);
0387                     netcdf.putAtt(nc,pevpr_varid,'type','data');
0388 
0389                     used_varids = [used_varids, 'pevpr_varid'];
0390                     used_fnames = [used_fnames, fnames{vv}];
0391                     used_dims = [used_dims, 'nNodes'];
0392                 end
0393 
0394             case {'prate', 'P_E'}
0395                 if strcmpi(suffixes{i}, '_evap') || ~multi_out
0396                     % Precipitation (or precipitation - evaporation)
0397                     prate_varid=netcdf.defVar(nc,'precip','NC_FLOAT',[node_dimid, time_dimid]);
0398                     netcdf.putAtt(nc,prate_varid,'long_name','Precipitation');
0399                     netcdf.putAtt(nc,prate_varid,'description','Precipitation, ocean lose water is negative');
0400                     netcdf.putAtt(nc,prate_varid,'units','m s-1');
0401                     netcdf.putAtt(nc,prate_varid,'grid','fvcom_grid');
0402                     netcdf.putAtt(nc,prate_varid,'coordinates',coordString);
0403                     netcdf.putAtt(nc,prate_varid,'type','data');
0404 
0405                     used_varids = [used_varids, 'prate_varid'];
0406                     used_fnames = [used_fnames, fnames{vv}];
0407                     used_dims = [used_dims, 'nNodes'];
0408                 end
0409 
0410             case 'nswrs'
0411                 if strcmpi(suffixes{i}, '_hfx') || ~multi_out
0412                     % Net shortwave radiation
0413                     nswrs_varid=netcdf.defVar(nc,'short_wave','NC_FLOAT',[node_dimid, time_dimid]);
0414                     netcdf.putAtt(nc,nswrs_varid,'long_name','Short Wave Radiation');
0415                     netcdf.putAtt(nc,nswrs_varid,'units','W m-2');
0416                     netcdf.putAtt(nc,nswrs_varid,'grid','fvcom_grid');
0417                     netcdf.putAtt(nc,nswrs_varid,'coordinates',coordString);
0418                     netcdf.putAtt(nc,nswrs_varid,'type','data');
0419 
0420                     used_varids = [used_varids, 'nswrs_varid'];
0421                     used_fnames = [used_fnames, fnames{vv}];
0422                     used_dims = [used_dims, 'nNodes'];
0423                 end
0424 
0425             case 'nlwrs'
0426                 if strcmpi(suffixes{i}, '_hfx') || ~multi_out
0427                     % Net longwave radiation
0428                     nlwrs_varid=netcdf.defVar(nc,'long_wave','NC_FLOAT',[node_dimid, time_dimid]);
0429                     netcdf.putAtt(nc,nlwrs_varid,'long_name','Long Wave Radiation');
0430                     netcdf.putAtt(nc,nlwrs_varid,'units','W m-2');
0431                     netcdf.putAtt(nc,nlwrs_varid,'grid','fvcom_grid');
0432                     netcdf.putAtt(nc,nlwrs_varid,'coordinates',coordString);
0433                     netcdf.putAtt(nc,nlwrs_varid,'type','data');
0434 
0435                     used_varids = [used_varids, 'nlwrs_varid'];
0436                     used_fnames = [used_fnames, fnames{vv}];
0437                     used_dims = [used_dims, 'nNodes'];
0438                 end
0439 
0440             case 'air'
0441                 if strcmpi(suffixes{i}, '_hfx') || ~multi_out
0442                     % Air temperature.
0443                     airt_varid = netcdf.defVar(nc, 'air_temperature', 'NC_FLOAT', [node_dimid, time_dimid]);
0444                     netcdf.putAtt(nc, airt_varid, 'long_name', 'Surface air temperature');
0445                     netcdf.putAtt(nc, airt_varid, 'units', 'Celsius Degree');
0446                     netcdf.putAtt(nc, airt_varid, 'grid', 'fvcom_grid');
0447                     netcdf.putAtt(nc, airt_varid, 'coordinates', coordString);
0448                     netcdf.putAtt(nc, airt_varid, 'type', 'data');
0449                     used_varids = [used_varids, 'airt_varid'];
0450                     used_fnames = [used_fnames, fnames{vv}];
0451                     used_dims = [used_dims, 'nNodes'];
0452                 end
0453 
0454             case 'rhum'
0455                 if strcmpi(suffixes{i}, '_hfx') || ~multi_out
0456                     % Relative humidity
0457 
0458                     rhum_varid = netcdf.defVar(nc, 'relative_humidity', 'NC_FLOAT', [node_dimid, time_dimid]);
0459                     netcdf.putAtt(nc, rhum_varid, 'long_name', 'surface air relative humidity');
0460                     netcdf.putAtt(nc, rhum_varid, 'units', 'percentage');
0461                     netcdf.putAtt(nc, rhum_varid, 'grid', 'fvcom_grid');
0462                     netcdf.putAtt(nc, rhum_varid, 'coordinates', coordString);
0463                     netcdf.putAtt(nc, rhum_varid, 'type', 'data');
0464 
0465                     used_varids = [used_varids, 'rhum_varid'];
0466                     used_fnames = [used_fnames, fnames{vv}];
0467                     used_dims = [used_dims, 'nNodes'];
0468                 end
0469 
0470             case 'dswrf'
0471                 if strcmpi(suffixes{i}, '_hfx') || ~multi_out
0472                     % Downward shortwave radiation
0473 
0474                     dswrf_varid = netcdf.defVar(nc, 'short_wave', 'NC_FLOAT', [node_dimid, time_dimid]);
0475                     netcdf.putAtt(nc, dswrf_varid, 'long_name', 'Downward solar shortwave radiation flux');
0476                     netcdf.putAtt(nc, dswrf_varid, 'units', 'Watts meter-2');
0477                     netcdf.putAtt(nc, dswrf_varid, 'grid', 'fvcom_grid');
0478                     netcdf.putAtt(nc, dswrf_varid, 'coordinates', coordString);
0479                     netcdf.putAtt(nc, dswrf_varid, 'type', 'data');
0480 
0481                     used_varids = [used_varids, 'dswrf_varid'];
0482                     used_fnames = [used_fnames, fnames{vv}];
0483                     used_dims = [used_dims, 'nNodes'];
0484                 end
0485 
0486             case 'dlwrf'
0487                 if strcmpi(suffixes{i}, '_hfx') || ~multi_out
0488                     % Downward longwave radiation
0489 
0490                     dlwrf_varid = netcdf.defVar(nc, 'long_wave', 'NC_FLOAT', [node_dimid, time_dimid]);
0491                     netcdf.putAtt(nc, dlwrf_varid, 'long_name', 'Downward solar longwave radiation flux');
0492                     netcdf.putAtt(nc, dlwrf_varid, 'units', 'Watts meter-2');
0493                     netcdf.putAtt(nc, dlwrf_varid, 'grid', 'fvcom_grid');
0494                     netcdf.putAtt(nc, dlwrf_varid, 'coordinates', coordString);
0495                     netcdf.putAtt(nc, dlwrf_varid, 'type', 'data');
0496 
0497                     used_varids = [used_varids, 'dlwrf_varid'];
0498                     used_fnames = [used_fnames, fnames{vv}];
0499                     used_dims = [used_dims, 'nNodes'];
0500                 end
0501 
0502             case {'shtfl', 'lhtfl', 'nshf'} % , 'nlwrs', 'nswrs'}
0503                 % We can't trigger on nlwrs and nswrs here because they're
0504                 % the triggers for the net longwave and shortwave variables
0505                 % above. Instead, we need to use the latent heat flux
0506                 % variables as the triggers for the net heat flux.
0507                 % We also need to check for the existence of the "net
0508                 % surface heat flux ('nshf')" field which can be created
0509                 % before calling grid2fvcom. This approach means there's
0510                 % fewer calls to the (expensive) interpolation as the net
0511                 % surface heat flux is calculated before being interpolated
0512                 % onto the FVCOM grid. Set the nshf variable accordingly.
0513                 if strcmpi(fnames{vv}, 'nshf')
0514                     nshf = 1;
0515                 end
0516                 try
0517                     % We might have already made this attribute, so fail
0518                     % elegantly if we do. This is because we need to put
0519                     % all four of shtfl, lhtfl, nlwrs and nswrs to make
0520                     % Surface Net Heat Flux.
0521                     if strcmpi(suffixes{i}, '_hfx') || ~multi_out
0522                         % Surface net heat flux
0523                         nhf_varid=netcdf.defVar(nc,'net_heat_flux','NC_FLOAT',[node_dimid, time_dimid]);
0524                         netcdf.putAtt(nc,nhf_varid,'long_name','Surface Net Heat Flux');
0525                         netcdf.putAtt(nc,nhf_varid,'units','W m-2');
0526                         netcdf.putAtt(nc,nhf_varid,'grid','fvcom_grid');
0527                         netcdf.putAtt(nc,nhf_varid,'coordinates',coordString);
0528                         netcdf.putAtt(nc,nhf_varid,'type','data');
0529                     end
0530                 end
0531                 %if strcmpi(suffixes{i}, '_hfx') || ~multi_out
0532                 if ~multi_out % write out only if we're doing a single file
0533                     % We need to save the current variable name even if
0534                     % we've already made its attribute.
0535                     used_varids = [used_varids, 'nhf_varid'];
0536                     used_fnames = [used_fnames, fnames{vv}];
0537                     used_dims = [used_dims, 'nNodes'];
0538                 end
0539 
0540             case {'time', 'lon', 'lat', 'x', 'y'}
0541                 continue
0542 
0543             otherwise
0544                 if ftbverbose
0545                     warning('Unknown or possibly unused input data type: %s', fnames{vv})
0546                 end
0547         end
0548     end
0549 
0550     % End definitions
0551     netcdf.endDef(nc);
0552 
0553     % Put the easy ones in first.
0554     netcdf.putVar(nc, nv_varid, tri);
0555     netcdf.putVar(nc,x_varid,x);
0556     netcdf.putVar(nc,y_varid,y);
0557     netcdf.putVar(nc,xc_varid,xc);
0558     netcdf.putVar(nc,yc_varid,yc);
0559     % Do the times.
0560     if floattime
0561         netcdf.putVar(nc,time_varid,0,ntimes,data.time);
0562     end
0563     if inttime
0564         netcdf.putVar(nc,itime_varid,0,ntimes,floor(data.time));
0565     %     netcdf.putVar(nc,itime2_varid,0,ntimes,mod(data.time,1)*24*3600*1000); % PWC original
0566         % KJA edit: avoids rounding errors when converting from double to single
0567         % Rounds to nearest multiple of the number of msecs in an hour
0568         netcdf.putVar(nc,itime2_varid,0,ntimes,round((mod(data.time,1)*24*3600*1000)/(3600*1000))*(3600*1000));
0569     end
0570 
0571     if strtime
0572         nStringOut = char();
0573         [nYr, nMon, nDay, nHour, nMin, nSec] = mjulian2greg(data.time);
0574         for i=1:ntimes
0575             nDate = [nYr(i), nMon(i), nDay(i), nHour(i), nMin(i), nSec(i)];
0576             nStringOut = [nStringOut, sprintf('%04i/%02i/%02i %02i:%02i:%09.6f', nDate)];
0577         end
0578         netcdf.putVar(nc,times_varid,[0, 0], [26, ntimes], nStringOut);
0579     end
0580 
0581     % Now do the dynamic ones. Set the heat flux to not done (hf_done = 0)
0582     % until we hit one of the holy quad (shtfl, lhtfl, nlwrs and nswrs).
0583     % Also make sure we have wind data, either as u10/v10 or uwnd/vwnd.
0584     hf_done = 0;
0585     wnd_done = 0;
0586     for ff = 1:length(used_fnames)
0587         if ftbverbose
0588             fprintf('write : %s... ', used_fnames{ff})
0589         end
0590         if strcmpi(used_fnames{ff}, 'shtfl') || strcmpi(used_fnames{ff}, 'lhtfl') || strcmpi(used_fnames{ff}, 'nlwrs') || strcmpi(used_fnames{ff}, 'nswrs')
0591 
0592             hf_done = hf_done + 1;
0593 
0594             if hf_done == 4 && nshf == 0
0595                 if ftbverbose
0596                     fprintf('combining heat flux ... ')
0597                 end
0598                 % We've got all four heat parameters, so dump them into the
0599                 % file.
0600                 %hf = -(data.shtfl.node + data.lhtfl.node + ...
0601                 %    data.nlwrs.node + data.nswrs.node);
0602                 hf = data.nlwrs.node + data.nswrs.node - ...
0603                     data.shtfl.node - data.lhtfl.node;
0604                 netcdf.putVar(nc,nhf_varid,[0,0],[nNodes,ntimes],hf)
0605             elseif strcmpi(used_fnames{ff}, 'nswrs') || strcmpi(used_fnames{ff}, 'nlwrs')
0606                 % We've already done the net surface heat flux but we're on
0607                 % either of the other fluxes (short/long wave) which we
0608                 % need to dump. Do that here.
0609                 if strcmpi(used_dims{ff}, 'nNodes')
0610                     eval(['netcdf.putVar(nc,',used_varids{ff},',[0,0],[',used_dims{ff},',ntimes],data.',used_fnames{ff},'.node);'])
0611                 else
0612                     eval(['netcdf.putVar(nc,',used_varids{ff},',[0,0],[',used_dims{ff},',ntimes],data.',used_fnames{ff},'.data);'])
0613                 end
0614             else
0615                 % We haven't got the precomputed net surface heat flux but
0616                 % we haven't yet got enough of the parameters to export the
0617                 % heat flux from the short + long + latent + sensible.
0618                 % Essentially this loop just does hf_done = hf_done + 1.
0619             end
0620         elseif strcmpi(used_fnames{ff}, 'nshf') && nshf == 1
0621             if ftbverbose
0622                 fprintf('existing combined heat flux ... ')
0623             end
0624             % We have pre-computed net surface heat flux, in which case set
0625             % hf_done to 4 and put the data into the netCDF. Also set the
0626             % nshf variable 1 to stop the net surface heat flux variable
0627             % being overwritten above.
0628             hf_done = 4;
0629             netcdf.putVar(nc, nhf_varid, [0, 0], [nNodes, ntimes], data.nshf.node)
0630         else
0631             % One of the other data sets for which we can simply dump the
0632             % existing array without waiting for other data.
0633             if strcmpi(used_dims{ff}, 'nNodes')
0634                 eval(['netcdf.putVar(nc,',used_varids{ff},',[0,0],[',used_dims{ff},',ntimes],data.',used_fnames{ff},'.node);'])
0635             else
0636                 try
0637                     eval(['netcdf.putVar(nc,',used_varids{ff},',[0,0],[',used_dims{ff},',ntimes],data.',used_fnames{ff},'.data);'])
0638                     wnd_done = wnd_done + 1;
0639                 catch err
0640                     fprintf('%s', err.message)
0641                 end
0642             end
0643         end
0644         if ftbverbose
0645             fprintf('done.\n')
0646         end
0647     end
0648     if hf_done < 4 && nshf == 1
0649         % hf_done might be higher than four, but unless it is at least
0650         % four, we haven't got everything we need. Only trigger this
0651         % warning if we've been given any of the net heat flux components.
0652         warning('Did not have all the required heat flux parameters for HEATING_ON. Need ''shtfl'', ''lhtfl'', ''nlwrs'' and ''nwsrs''.')
0653     end
0654 
0655     if wnd_done < 2;
0656         warning('No wind data was provided (or one component was missing). Expected fields u10 and v10 or uwnd and vwnd.')
0657     end
0658 
0659     % Close the netCDF file(s)
0660     netcdf.close(nc);
0661 end
0662 
0663 if ftbverbose
0664     fprintf('end   : %s \n', subname)
0665 end

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