Home > utilities > fvcom2grid.m

fvcom2grid

PURPOSE ^

Interpolate FVCOM onto regular grid

SYNOPSIS ^

function fvcom = fvcom2grid(Mobj, vars, data)

DESCRIPTION ^

 Interpolate FVCOM onto regular grid
 grid.

 fvcom2grid(Mobj,vars,data)

 DESCRIPTION:

 INPUT:
   Mobj - MATLAB mesh object with the following fields:
       x, y, lon, lat - cartesian and spherical node coordinates. These
       are transferred to the NetCDF file only and are not used in the
       interpolation at all.
       nVerts - number of vertices (nodes) in the unstructured grid.
       nElems - number of elements in the unstructured grid.
   vars - a cell array of the variable names to be interpolated on the
       FVCOM grid in Mobj (e.g. uwnd, U10, vwnd, V10 etc.).
   data - a struct which contains the following arrays:
       x - x data (probably best in cartesian for the interpolation)
       y - y data (probably best in cartesian for the interpolation)
       The struct must also contain all the variables defined in vars.
       time - time vector (in Modified Julian Days). If you're using some
       of the NCEP surface products (e.g. relative humitidy, sea level
       pressure), you need to supply x and y coordinates for their grids
       as .xalt and .yalt).

 OUTPUT:

 EXAMPLE USAGE:
   interpfields = {'uwnd', 'vwnd', 'slp', 'nshf', 'nlwrs', 'nswrs', ...
       'P_E', 'Et', 'time', 'lon', 'lat', 'x', 'y'};
   forcing_interp = grid2fvcom(Mobj, interpfields, forcing);

 NOTE:

 Author(s):
   Pierre Cazenave (Plymouth Marine Laboratory)

 Revision history:
   2014-03-21 First version based on grid2fvcom.m in the
   fvcom-toolbox.

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

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function fvcom = fvcom2grid(Mobj, vars, data)
0002 % Interpolate FVCOM onto regular grid
0003 % grid.
0004 %
0005 % fvcom2grid(Mobj,vars,data)
0006 %
0007 % DESCRIPTION:
0008 %
0009 % INPUT:
0010 %   Mobj - MATLAB mesh object with the following fields:
0011 %       x, y, lon, lat - cartesian and spherical node coordinates. These
0012 %       are transferred to the NetCDF file only and are not used in the
0013 %       interpolation at all.
0014 %       nVerts - number of vertices (nodes) in the unstructured grid.
0015 %       nElems - number of elements in the unstructured grid.
0016 %   vars - a cell array of the variable names to be interpolated on the
0017 %       FVCOM grid in Mobj (e.g. uwnd, U10, vwnd, V10 etc.).
0018 %   data - a struct which contains the following arrays:
0019 %       x - x data (probably best in cartesian for the interpolation)
0020 %       y - y data (probably best in cartesian for the interpolation)
0021 %       The struct must also contain all the variables defined in vars.
0022 %       time - time vector (in Modified Julian Days). If you're using some
0023 %       of the NCEP surface products (e.g. relative humitidy, sea level
0024 %       pressure), you need to supply x and y coordinates for their grids
0025 %       as .xalt and .yalt).
0026 %
0027 % OUTPUT:
0028 %
0029 % EXAMPLE USAGE:
0030 %   interpfields = {'uwnd', 'vwnd', 'slp', 'nshf', 'nlwrs', 'nswrs', ...
0031 %       'P_E', 'Et', 'time', 'lon', 'lat', 'x', 'y'};
0032 %   forcing_interp = grid2fvcom(Mobj, interpfields, forcing);
0033 %
0034 % NOTE:
0035 %
0036 % Author(s):
0037 %   Pierre Cazenave (Plymouth Marine Laboratory)
0038 %
0039 % Revision history:
0040 %   2014-03-21 First version based on grid2fvcom.m in the
0041 %   fvcom-toolbox.
0042 %
0043 %==========================================================================
0044 
0045 if nargin ~= 3
0046     error('Incorrect number of arguments')
0047 end
0048 
0049 subname = 'grid2fvcom';
0050 
0051 global ftbverbose;
0052 if ftbverbose
0053     fprintf('\nbegin : %s \n', subname)
0054 end
0055 
0056 % Before we go too far into this, check we have all the fields in the input
0057 % data that are being requested.
0058 for ff = 1:length(vars)
0059     assert(isfield(data, vars{ff}), ...
0060         'Missing field %s in the input data struct.', vars{ff})
0061 end
0062 
0063 % Run jobs on multiple workers if we have that functionality. Not sure if
0064 % it's necessary, but check we have the Parallel Toolbox first.
0065 % wasOpened = false;
0066 if license('test', 'Distrib_Computing_Toolbox')
0067     % We have the Parallel Computing Toolbox, so launch a bunch of workers.
0068     if matlabpool('size') == 0
0069         % Force pool to be local in case we have remote pools available.
0070         matlabpool open local
0071 %         wasOpened = true;
0072     end
0073 end
0074 
0075 %--------------------------------------------------------------------------
0076 % Get the relevant bits from the FVCOM mesh object
0077 %--------------------------------------------------------------------------
0078 x = Mobj.x;
0079 y = Mobj.y;
0080 nVerts = Mobj.nVerts;
0081 nElems = Mobj.nElems;
0082 if ftbverbose
0083     fprintf('info for FVCOM domain\n');
0084     fprintf('number of nodes: %d\n', nVerts);
0085     fprintf('number of elems: %d\n', nElems);
0086 end
0087 
0088 xc = nodes2elems(x, Mobj);
0089 yc = nodes2elems(y, Mobj);
0090 
0091 try
0092     ntimes = numel(data.time);
0093 catch
0094     ntimes = numel(data.(vars{1}).time);
0095 end
0096 
0097 % Interpolate supplied regularly gridded data to FVCOM mesh. Use
0098 % TriScatteredInterp to do the interpolation instead of griddata (should be
0099 % faster).
0100 for vv = 1:length(vars)
0101     switch vars{vv}
0102         case 'time'
0103             fprintf('transferring variable %s as is\n', vars{vv})
0104             fvcom.(vars{vv}) = data.(vars{vv});
0105             continue
0106 
0107         case {'lat', 'lon', 'x', 'y'}
0108             fprintf('reassigning variable %s from unstructured grid\n', vars{vv})
0109             fvcom.(vars{vv}) = Mobj.(vars{vv});
0110 
0111         case {'xalt', 'yalt'}
0112             % Only exist for the interpolation of some data on an
0113             % alternative grid.
0114             fprintf('skipping %s\n', vars{vv})
0115 
0116         otherwise
0117             % Preallocate the output arrays.
0118             % Serial version:
0119             % fvcom.(vars{vv}).data = zeros(nElems, ntimes);
0120             % fvcom.(vars{vv}).node = zeros(nVerts, ntimes);
0121             % Also create temporary arrays for the inner loop to be
0122             % parallelisable (is that a word?):
0123             tmp_fvcom_data = zeros(nElems, ntimes);
0124             tmp_fvcom_node = zeros(nVerts, ntimes);
0125             try
0126                 tmp_data_data = data.(vars{vv}).data; % input to the interpolation
0127             catch msg
0128                 fprintf('Trying for alternative data structure. (%s) ', ...
0129                     msg.message)
0130                 tmp_data_data = data.(vars{vv}); % input to the interpolation
0131                 fprintf('success!\n')
0132             end
0133 
0134             xx = data.x(:);
0135             yy = data.y(:);
0136             % Sometimes the parfor loop will fail if xxalt and yyalt
0137             % aren't defined at all. So, make them empty here. This
0138             % shouldn't impact data where we need those alternative arrays
0139             % because if the data.xalt and data.yalt arrays exist, then
0140             % these values will be overwritten with them. It does ensure
0141             % that xxalt and yyalt always exist though.
0142             xxalt = [];
0143             yyalt = [];
0144 
0145             % Check the shapes of the input data match those of the
0146             % position arrays.
0147             [fvx, fvy] = size(data.x);
0148             [ncx, ncy, ~] = size(tmp_data_data);
0149 
0150             if isfield(data, 'xalt')
0151                 [fvxalt, fvyalt] = size(data.xalt);
0152                 xxalt = data.xalt(:);
0153                 yyalt = data.yalt(:);
0154                 if (ncx ~= fvx || ncy ~= fvy) || (ncx ~= fvxalt || ncy ~= fvyalt)
0155                     % Flipping the input array so it hopefully matches the
0156                     % position arrays.
0157                     tmp_data_data = permute(tmp_data_data, [2, 1, 3]);
0158                     warning('Transposed ''%s'' input data to match position array dimensions', vars{vv})
0159                 end
0160                 if isfield(data, 'lsmalt')
0161                     % If we have a land mask, mask off the coastal and land
0162                     % points in the coordinates arrays with the alternative
0163                     % mask.
0164                     xxalt(data.lsmalt ~= 0) = [];
0165                     yyalt(data.lsmalt ~= 0) = [];
0166                 end
0167             else
0168                 if (ncx ~= fvx || ncy ~= fvy)
0169                     % Flipping the input array so it hopefully matches the
0170                     % position arrays.
0171                     tmp_data_data = permute(tmp_data_data, [2, 1, 3]);
0172                     warning('Transposed ''%s'' input data to match position array dimensions', vars{vv})
0173                 end
0174                 % If we have a land mask, mask off the coastal and land points
0175                 % in the coordinates arrays.
0176                 if isfield(data, 'lsm')
0177                     xx(data.lsm ~= 0) = [];
0178                     yy(data.lsm ~= 0) = [];
0179                 end
0180             end
0181 
0182             % Use a parallel loop for the number of time steps we're
0183             % interpolating.
0184             varname = vars{vv};
0185             parfor i = 1:ntimes
0186                 if ftbverbose
0187                     fprintf('interpolating %s, frame %d of %d\n', varname, i, ntimes);
0188                 end
0189 
0190                 % Serial version:
0191                 % currvar = data.(vars{vv}).data(:, :, i);
0192                 % Parallel version:
0193                 currvar = tmp_data_data(:, :, i);
0194 
0195                 % griddata way (cubic interpolation)
0196                 %fvcom.(vars{vv}).node(:,i) = griddata(wind.x,wind.y,currvar,x,y,'cubic');
0197                 %fvcom.(vars{vv}).data(:,i) = griddata(wind.x,wind.y,currvar,xc,yc,'cubic');
0198 
0199                 % TriScatteredInterp way (with natural neighbour
0200                 % interpolation). Instead of the quite crude try/catch that
0201                 % was here, count the number of elements in the coordinate
0202                 % (xx and yy) and data (currvar) arrays: if they differ,
0203                 % try the same thing with the xxalt and xyalt coordinate
0204                 % arrays. If they still differ, then error out. The reason
0205                 % for this different approach is that the parfor sometimes
0206                 % failed for me when using non-NCEP data as the source for
0207                 % the interpolation.
0208                 ndata = numel(currvar(~isnan(currvar)));
0209                 nxx = numel(xx);
0210                 nyy = numel(yy);
0211                 assert(nxx == nyy, 'Inconsistent coordinate array sizes.')
0212                 if nxx == ndata
0213                     ftsin = TriScatteredInterp(...
0214                         xx, ...
0215                         yy, ...
0216                         currvar(~isnan(currvar(:))), ...
0217                         'natural');
0218                 elseif exist('xxalt', 'var') && numel(xxalt) == ndata
0219                     ftsin = TriScatteredInterp(...
0220                         xxalt, ...
0221                         yyalt, ...
0222                         currvar(~isnan(currvar(:))), ...
0223                         'natural');
0224                 else
0225                     error('Can''t interpolate the data: non-matching coordinate array sizes.')
0226                 end
0227 %                 try
0228 %                     ftsin = TriScatteredInterp(...
0229 %                         xx, ...
0230 %                         yy, ...
0231 %                         currvar(~isnan(currvar(:))), ...
0232 %                         'natural');
0233 %                 catch err
0234 %                     % In my experience, the matlabpool size - 1 is the
0235 %                     % first iteration that actually gets printed to the
0236 %                     % display.
0237 %                     if i == matlabpool('size') - 1
0238 %                         % Only print the warning on the "first" iteration.
0239 %                         warning([err.identifier, ': Some NCEP data are projected' ...
0240 %                             ' onto a different grid. Check you have specified' ...
0241 %                             ' data.xalt and data.yalt arrays which are on the' ...
0242 %                             ' same grid as the data to be interpolated.'])
0243 %                     end
0244 %                     ftsin = TriScatteredInterp(xxalt, yyalt, ...
0245 %                         currvar(~isnan(currvar(:))), 'natural');
0246 %                 end
0247 
0248                 % Serial version:
0249                 % fvcom.(vars{vv}).node(:,i) = ftsin(x,y);
0250                 % fvcom.(vars{vv}).data(:,i) = ftsin(xc,yc);
0251                 % nnans(1) = sum(isnan(fvcom.(vars{vv}).node(:,i)));
0252                 % nnans(2) = sum(isnan(fvcom.(vars{vv}).data(:,i)));
0253                 % Parallel version:
0254                 tmp_fvcom_node(:, i) = ftsin(x, y);
0255                 tmp_fvcom_data(:, i) = ftsin(xc, yc);
0256                 nnans1 = sum(isnan(tmp_fvcom_node(:, i)));
0257                 nnans2 = sum(isnan(tmp_fvcom_data(:, i)));
0258                 if  nnans1 > 0
0259                     warning('%i NaNs in the interpolated node data. This won''t work with FVCOM.', nnans1)
0260                 end
0261                 if nnans2 > 0
0262                     warning('%i NaNs in the interpolated element data. This won''t work with FVCOM.', nnans2)
0263                 end
0264             end
0265             % Transfer the temporary arrays back to the relevant struct and
0266             % clear out the temporary arrays.
0267             fvcom.(vars{vv}).node = tmp_fvcom_node;
0268             fvcom.(vars{vv}).data = tmp_fvcom_data;
0269             clear nnans* tmp_*
0270 
0271             if ftbverbose
0272                 fprintf('interpolation of %s complete\n', vars{vv});
0273             end
0274     end
0275 end
0276 
0277 % if wasOpened
0278 %     matlabpool close
0279 % end
0280 
0281 % Better way of closing the pool after each invocation (though this might
0282 % incur some overhead due to the time it takes to spin up/close down a
0283 % MATLAB pool of workers).
0284 cleaner = onCleanup(@() matlabpool('close'));
0285 
0286 if ftbverbose
0287     fprintf('end   : %s \n', subname)
0288 end
0289 
0290 %% Debugging figure to check the interpolation makes sense.
0291 
0292 % close all
0293 %
0294 % figure
0295 %
0296 % vartoplot = 'nswrf';
0297 % tidx = 12; % time index
0298 %
0299 % subplot(2, 1, 1)
0300 % try
0301 %     pcolor(data.lon, data.lat, data.(vartoplot).data(:, :, tidx)')
0302 % catch
0303 %     pcolor(data.lon, data.lat, data.(vartoplot)(:, :, tidx)')
0304 % end
0305 % shading flat
0306 % axis('equal', 'tight')
0307 % title([vartoplot, ' (regularly gridded)'])
0308 % colorbar
0309 % try
0310 %     caxis([min(fvcom.(vartoplot).data(:, tidx)), max(fvcom.(vartoplot).data(:, tidx))])
0311 % catch
0312 %     caxis([min(fvcom.(vartoplot)(:, tidx)), max(fvcom.(vartoplot)(:, tidx))])
0313 % end
0314 % axis([min(Mobj.lon), max(Mobj.lon), min(Mobj.lat), max(Mobj.lat)])
0315 %
0316 % subplot(2, 1, 2)
0317 % try
0318 %     patch('Vertices', [Mobj.lon, Mobj.lat], 'Faces', Mobj.tri, 'cData', fvcom.(vartoplot).data(:, tidx));
0319 % catch
0320 %     patch('Vertices', [Mobj.lon, Mobj.lat], 'Faces', Mobj.tri, 'cData', fvcom.(vartoplot)(:, tidx));
0321 % end
0322 % shading flat
0323 % axis('equal')
0324 % axis([min(data.lon(:)), max(data.lon(:)), min(data.lat(:)), max(data.lat(:))])
0325 % title([vartoplot, ' (interpolated)'])
0326 % colorbar
0327 % try
0328 %     caxis([min(fvcom.(vartoplot).data(:, tidx)), max(fvcom.(vartoplot).data(:, tidx))])
0329 % catch
0330 %     caxis([min(fvcom.(vartoplot)(:, tidx)), max(fvcom.(vartoplot)(:, tidx))])
0331 % end
0332 % axis([min(Mobj.lon), max(Mobj.lon), min(Mobj.lat), max(Mobj.lat)])
0333

Generated on Tue 29-Jul-2014 15:11:16 by m2html © 2005