Commit f3d36844 authored by Pierre Cazenave's avatar Pierre Cazenave

Merge branch 'dev'

Bring in the changes from the dev branch into the master branch. These include:

- Support for converting POLCOMS flow, index and grid files into the necessary files to write FVCOM river input files (NetCDF and nml files). The existing river functions have been updated to reflect the changes needed in the latest versions of FVCOM (3.1.x). write_FVCOM_river.m now uses the native MATLAB NetCDF routines to export to NetCDF.
- Preliminary support for mean flow at the open boundaries. At the moment, the mean flow is interpolated from POLCOMS daily mean flow values. The necessary tools to write out the FVCOM ASCII mean flow files have been created, but I have not yet managed to successfully run a model with mean flow. Consider it a work in progress.
- The NCEP surface forcing is now able to use either the MATLAB native support or otherwise (for older versions) the third-party OPeNDAP toolbox (http://www.opendap.org/pub/contributed/source/ml-toolbox/). It is still dependent on the air-sea toolbox (http://woodshole.er.usgs.gov/operations/sea-mat/air_sea-html/index.html). The surface forcing has had the sign convention fixed (see get_NCEP_forcing.m).
- Vertical temperature and salinity profiles from POLCOMS model outputs are scaled to the FVCOM depth rather than truncating. Hopefully this means the full structure of the water column is preserved if POLCOMS and FVCOM differ in their depths (see get_POLCOMS_tsobc.m).
- Export of the surface forcing can now use a precomputed surface heat flux rather than having to interpolate the four components only to merge them (see write_FVCOM_forcing.m).
- Some of the older functions have been made more consistent in terms of the coding style (e.g. warnings are now turned on, or not turned off, for all functions). Similarly, the history global variable in any FVCOM NetCDF file now includes the name of the function from which it was generated.
- The routine to replace variables within an FVCOM restart file now includes the ability to adjust the times for which the restart file is applicable. This is useful if you have a restart file for a model domain, but wish to use it for a different time.
- A new function to reorganise open boundary elements to have an edge approximately normal to the open boundary has been added (fix_inside_boundary.m). The routine is somewhat brute force, and can result in invalid unstructured grids. As such, any changes should be reviewed in SMS prior to being used in a model run.
- Additional tools (write_SMS_2dm.m and write_SMS_cst.m) provide functionality to export data from MATLAB to formats compatible with SMS.
parents af0f43f7 2be99d82
function [Mobj] = add_river_nodes(Mobj,Nlist,RiverName)
function [Mobj] = add_river_nodes_list(Mobj,Nlist,RiverName)
% Add a set of river nodes comprising a single river to Mesh structure
% Using a set of user-defined nodes
%
% [Mobj] = add_river_nodes(Mobj)
% [Mobj] = add_river_nodes(Mobj,Nlist,RiverName)
%
% DESCRIPTION:
% Select using ginput the set of nodes comprising a river
......@@ -16,7 +16,7 @@ function [Mobj] = add_river_nodes(Mobj,Nlist,RiverName)
% Mobj = Matlab mesh object with an additional river nodelist
%
% EXAMPLE USAGE
% Mobj = add_river_nodes(Mobj,'Potomac')
% Mobj = add_river_nodes(Mobj, [146, 3004], 'Potomac')
%
% Author(s):
% Geoff Cowles (University of Massachusetts Dartmouth)
......@@ -27,54 +27,54 @@ function [Mobj] = add_river_nodes(Mobj,Nlist,RiverName)
%
% Revision history
%
%==============================================================================
subname = 'add_river_nodes';
%==========================================================================
subname = 'add_river_nodes_list';
global ftbverbose
if(ftbverbose)
fprintf('\n')
fprintf(['begin : ' subname '\n'])
end;
if ftbverbose
fprintf('\n')
fprintf(['begin : ' subname '\n'])
end
%------------------------------------------------------------------------------
%--------------------------------------------------------------------------
% Get a unique list and make sure they are in the range of node numbers
%------------------------------------------------------------------------------
%--------------------------------------------------------------------------
Nlist = unique(Nlist);
if(max(Nlist) > Mobj.nVerts);
fprintf('your river node number(s) exceed the total number of nodes in the domain\n');
fprintf('stop screwing around\n');
error('stopping...\n')
end;
if max(Nlist) > Mobj.nVerts
fprintf('your river node number(s) exceed the total number of nodes in the domain\n');
fprintf('stop screwing around\n');
error('stopping...\n')
end
%------------------------------------------------------------------------------
%--------------------------------------------------------------------------
% Plot the mesh
%------------------------------------------------------------------------------
%--------------------------------------------------------------------------
if(lower(Mobj.nativeCoords(1:3)) == 'car')
x = Mobj.x;
y = Mobj.y;
if strcmpi(Mobj.nativeCoords(1:3), 'car')
x = Mobj.x;
y = Mobj.y;
else
x = Mobj.lon;
y = Mobj.lat;
end;
x = Mobj.lon;
y = Mobj.lat;
end
figure
patch('Vertices',[x,y],'Faces',Mobj.tri,...
'Cdata',Mobj.h,'edgecolor','k','facecolor','interp');
hold on;
patch('Vertices', [x,y], 'Faces', Mobj.tri,...
'Cdata', Mobj.h, 'edgecolor', 'k', 'facecolor', 'interp');
hold on
plot(x(Nlist),y(Nlist),'ro');
title('river nodes');
plot(x(Nlist), y(Nlist), 'ro')
title('river nodes')
% add to mesh object
npts = numel(Nlist);
Mobj.nRivers = Mobj.nRivers + 1;
Mobj.nRivNodes(Mobj.nRivers) = npts;
Mobj.riv_nodes(Mobj.nRivers,1:npts) = Nlist;
Mobj.riv_nodes(Mobj.nRivers, 1:npts) = Nlist;
Mobj.riv_name{Mobj.nRivers} = RiverName;
if(ftbverbose)
fprintf(['end : ' subname '\n'])
end;
if ftbverbose
fprintf(['end : ' subname '\n'])
end
......@@ -84,7 +84,7 @@ Mobj.sponge_nodes(Mobj.nSponge,1:npts) = SpongeList;
Mobj.sponge_name{Mobj.nSponge} = SpongeName;
Mobj.sponge_fac(Mobj.nSponge) = SpongeCoeff;
if max(size(SpongeRadius))==1 % if you have a constant sponge radius
if numel(unique(SpongeRadius)) == 1 % if you have a constant sponge radius
Mobj.sponge_rad(Mobj.nSponge) = SpongeRadius;
else % if you have a variable sponge radius
Mobj.sponge_rad(Mobj.nSponge,1:npts) = SpongeRadius;
......
......@@ -90,4 +90,11 @@ for s=1:nPos
inc = inc + 1;
end
Mobj.stations = out;
if ~isempty(out)
Mobj.stations = out;
else
Mobj.stations = [];
if ftbverbose
fprintf('No stations found within the model domain.\n')
end
end
......@@ -31,7 +31,7 @@ function add_var_FVCOM_river(RiverFile,VarName,VarLongName,VarUnits,VarData)
%
%==============================================================================
warning off
%warning off
subname = 'add_var_FVCOM_river';
global ftbverbose;
......
......@@ -27,7 +27,7 @@ function example_FVCOM_tsobc(basename,time,nSiglay)
%
%==============================================================================
warning off;
%warning off;
subname = 'example_FVCOM_tsobc';
......@@ -127,7 +127,7 @@ nc = netcdf.create(tsOBCFile, 'clobber');
netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'type','FVCOM RIVER FORCING FILE')
netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'title','simple open boundary hydrography test')
netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'type','FVCOM TIME SERIES OBC TS FILE')
netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'history','generated using the fvcom-toolbox')
netcdf.putAtt(nc,netcdf.getConstant('NC_GLOBAL'),'history','File generated using example_FVCOM_tsobc.m from the MATLAB fvcom-toolbox')
% define dimensions
......
......@@ -24,7 +24,7 @@ function example_FVCOM_wind_ts
% Revision history
%
%==============================================================================
warning off
%warning off
subname = 'example_FVCOM_wind_ts';
global ftbverbose;
if(ftbverbose);
......
......@@ -24,7 +24,7 @@ function example_FVCOM_wind_ts_speed
% Revision history
%
%==============================================================================
warning off
%warning off
subname = 'example_FVCOM_wind_ts';
fprintf('\n')
fprintf(['begin : ' subname '\n'])
......
......@@ -9,7 +9,7 @@ clear all; close all;
% Revision history
%
%==============================================================================
warning off
%warning off
type = 2;
% set mesh/bathymetry files
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -62,12 +62,13 @@ end
for ii = 1:todo
if iscell(files)
ftn = files{ii};
else
ftn = files;
end
if ftbverbose
if iscell(files)
ftn = files{ii};
else
ftn = files;
end
% Strip path from filename for the verbose output.
[~, basename, ext] = fileparts(ftn);
tmp_fn = [basename, ext];
......
function Mobj = get_POLCOMS_rivers(Mobj, polcoms_file, polcoms_ij, polcoms_grid, dist_thresh)
% Parse the POLCOMS rivers data file.
%
% get_POLCOMS_rivers(Mobj, polcoms_file, polcoms_ij, polcoms_grid, dist_thresh)
%
% DESCRIPTION:
% Takes an existing POLCOMS formatted river discharge file and extracts
% the data which fall within the model domain specified in Mobj.
%
% INPUT:
% Mobj - MATLAB mesh object containing:
% * lon, lat - positions for the unstructured grid.
% polcoms_file - flow data file(s) from POLCOMS. For multiple files, give
% in chronological order as a cell array of file names.
% polcoms_ij - indices in the POLCOMS grid at which each river is
% located.
% polcoms_grid - NetCDF file of the POLCOMS grid.
% dist_thresh - [optional] Maximum distance away from a POLCOMS river
% node beyond which the search for an FVCOM node is abandoned. Units
% in degrees.
%
% OUTPUT:
% Mobj.river_flux - volume flux at the nodes within the model domain.
% Mobj.river_nodes - node IDs for the rivers. At the moment, these are
% point sources only. Eventually, some rivers may have to be split
% over several nodes.
% Mobj.river_time - time series for the river discharge data
%
% EXAMPLE USAGE:
% Mobj = get_POLCOMS_rivers(Mobj, 'polcoms.flw', 'polcoms.index', ...
% 'polcoms.nc', 0.025)
%
% Author(s):
% Pierre Cazenave (Plymouth Marine Laboratory)
%
% Revision history:
% 2013-03-21 - First version.
%
%==========================================================================
subname = 'get_POLCOMS_rivers';
global ftbverbose;
if ftbverbose
fprintf(['\nbegin : ' subname '\n'])
end
% Check inputs
if exist(polcoms_grid, 'file') ~= 2
error('file: %s does not exist or is not readable.', polcoms_grid)
end
if exist(polcoms_ij, 'file') ~= 2
error('file: %s does not exist or is not readable.', polcoms_ij)
end
if exist(polcoms_file, 'file') ~= 2
error('file: %s does not exist or is not readable.', polcoms_file)
end
if nargin < 4
% No distance threshold
dist_thresh = -1;
end
if ~Mobj.have_lonlat
error('Require unstructured grid positions in lon/lat format to compare against POLCOMS positions.')
end
% The POLCOMS river file has a pretty straightforward format of a 2D array
% of river along x and time along y. Since it's a simple text file with no
% weird format, we'll just read it in with load.
if iscell(polcoms_file)
pc_riv = [];
for rr = 1:length(polcoms_file)
pc_riv = [pc_riv; load(polcoms_file{rr})];
end
clear rr
else
pc_riv = load(polcoms_file);
end
[pc_nt, pc_nr] = size(pc_riv);
% Get the positions for each river from the NetCDF grid and the index file.
% Format is:
%
% n
% id1 i j Name1
% id2 i j Name2
% ...
% idn i j Namen
fidx = fopen(polcoms_ij, 'r');
if fidx < 0
error('file: %s does not exist', polcoms_ij);
end
% Output arrays
pc_idx = nan(pc_nr, 3);
pc_name = cell(pc_nr, 1);
c = 0; % line counter
while ~feof(fidx)
line = fgetl(fidx);
if isempty(line) || ~ischar(line)
continue
else
c = c + 1;
end
if c == 1
% First (valid) line should be number of rivers
nridx = str2double(strtrim(line));
if nridx ~= pc_nr
warning('Number of rivers in the index file\n\n\t%s\n\ndoes not match the number of rivers in the data file\n\n\t%s\n', polcoms_ij, polcoms_file)
warning('Resizing the arrays to match the index file.')
pc_idx = nan(nridx, 3);
pc_name = cell(nridx, 1);
pc_nr = nridx; % reset number of rivers value
end
else
% We're in the data
S = regexpi(strtrim(line), ' +', 'split');
pc_idx(c - 1, :) = [str2double(S{1}), str2double(S{2}), str2double(S{3})];
pc_name{c - 1} = S{end};
end
end
clear S line c
fclose(fidx);
% Now read in the NetCDF file and grab the real coordinates of those
% positions.
nc = netcdf.open(polcoms_grid, 'NOWRITE');
[~, numvars, ~, ~] = netcdf.inq(nc);
for ii = 1:numvars
[varname, ~, ~, ~] = netcdf.inqVar(nc, ii - 1);
varid = netcdf.inqVarID(nc, varname);
if ftbverbose
fprintf('\tvariable %s... ', varname)
end
switch varname
case 'lon'
pc_lon = netcdf.getVar(nc, varid);
case 'lat'
pc_lat = netcdf.getVar(nc, varid);
end
if ftbverbose
fprintf('done.\n')
end
end
clear numdims numvars dimnames
netcdf.close(nc)
% Use the indices from the polcoms_ij file to get the real positions of the
% river nodes.
pc_riv_lonlat = [pc_lon(pc_idx(:, 2), 1), pc_lat(1, pc_idx(:, 3))'];
% Now we have the positions of the rivers, we need to find the most
% appropriate node in the FVCOM grid open boundaries. This will probably
% not work completely because POLCOMS' grid resolution is lower than
% FVCOM's is likely to be, and so the nearest open boundary node might be a
% long way down an estuary, for example. So, we'll do this automatically
% here, but then you'll probably have to move the positions yourself after
% this has finished. Short of some complex searches along the open
% boundaries and some angle-based criteria (sharpest angle = river mouth),
% this is probably the most sensible approach.
vc = 0; % valid FVCOM boundary node counter
% We need to find the coastline nodes and exclude the open boundary nodes
% from them. This will be our list of potential candidates for the river
% nodes.
[~, ~, ~, bnd] = connectivity([Mobj.lon, Mobj.lat], Mobj.tri);
boundary_nodes = 1:Mobj.nVerts;
boundary_nodes = boundary_nodes(bnd);
coast_nodes = boundary_nodes(~ismember(boundary_nodes, [Mobj.read_obc_nodes{:}]));
fv_obc = nan;
fv_names = cell(0);
fv_riv_idx = nan;
for pp = 1:pc_nr
% Find the open boundary node closest to this river
fv_dist = sqrt( ...
(pc_riv_lonlat(pp, 1) - Mobj.lon(coast_nodes)).^2 + ...
(pc_riv_lonlat(pp, 2) - Mobj.lat(coast_nodes)).^2);
[c, idx] = min(fv_dist);
if c > dist_thresh && dist_thresh ~= -1 % -1 is for no check
if ftbverbose
fprintf('\tskipping river %s (%f, %f)\n', pc_name{pp}, pc_riv_lonlat(pp, 1), pc_riv_lonlat(pp, 2))
end
continue
else
if ftbverbose
fprintf('candidate river %s found (%f, %f)... ', pc_name{pp}, pc_riv_lonlat(pp, 1), pc_riv_lonlat(pp, 2))
end
end
% Don't have duplicate river nodes. Is this wise? Probably not because
% the order in which we stumble upon rivers is arbitrary (alphabetical)
% and so we might end up with the wrong discharge values. I can't
% see a more sensible approach than this, though.
if ~ismember(coast_nodes(idx), fv_obc)
vc = vc + 1;
fv_obc(vc) = coast_nodes(idx);
fv_names{vc} = pc_name{pp};
fv_riv_idx(vc) = pp;
if ftbverbose
fprintf('added.\n')
end
else
if ftbverbose
fprintf('skipped.\n')
end
end
end
% Add to the Mobj.
Mobj.river_nodes = fv_obc;
% Add the relevant time series of river discharge.
Mobj.river_flux = pc_riv(:, fv_riv_idx);
% Time's a bit more interesting because we have approximately daily values
% (the number of rows in pc_riv is approximately number of days in a year,
% plus a few extras). Since the input file name gives us the year, we
% should be able to reconstruct something approaching a date for the
% current time series. As ever, hacking around with input file names is
% bound to break at some point in the future, so warn as such.
warning('Extracting year from the input file name. This might break if your file name doesn''t match what is expected.')
if iscell(polcoms_file)
[~, fn, ~] = fileparts(polcoms_file{1}); % use the first file name
else
[~, fn, ~] = fileparts(polcoms_file);
end
% Assume last four characters are the year.
ryear = str2double(fn(end-3:end));
% Create a Modified Julian Day time series starting at January 1st, ryear.
rtimes = datevec(datenum([ryear, 1, 1, 0, 0, 0]):datenum([ryear, 1, 1, 0, 0, 0]) + pc_nt - 1);
Mobj.river_time = nan(pc_nt, 1);
for tt = 1:pc_nt
Mobj.river_time(tt) = greg2mjulian( ...
rtimes(tt, 1), rtimes(tt, 2), rtimes(tt, 3), ...
rtimes(tt, 4), rtimes(tt, 5), rtimes(tt, 6) ...
);
end
Mobj.river_names = fv_names;
% Figure to check what's going on with identifying river nodes
% figure
% plot(pc_riv_lonlat(:,1), pc_riv_lonlat(:,2), 'o', 'MarkerFaceColor', 'b')
% hold on
% plot(Mobj.lon(bnd), Mobj.lat(bnd), 'go', 'MarkerFaceColor', 'g')
% axis('equal', 'tight')
% plot(Mobj.lon(coast_nodes), Mobj.lat(coast_nodes), 'ro')
% plot(Mobj.lon(fv_obc), Mobj.lat(fv_obc), 'ko', 'MarkerFaceColor', 'k')
% axis([min(Mobj.lon), max(Mobj.lon), min(Mobj.lat), max(Mobj.lat)])
% legend('POLCOMS nodes', 'Grid boundary', 'Land nodes', 'Selected nodes', 'Location', 'NorthOutside', 'Orientation', 'Horizontal')
% legend('BoxOff')
if ftbverbose
fprintf(['end : ' subname '\n'])
end
......@@ -33,19 +33,25 @@ function Mobj = get_POLCOMS_tsobc(Mobj, ts)
%
% OUTPUT:
% Mobj = MATLAB structure in which three new fields (called temperature,
% salinity and ts_time). temperature and salinity have sizes
% salinity and ts_times). temperature and salinity have sizes
% (sum(Mobj.nObcNodes), sigma, time). The time dimension is
% determined based on the input NetCDF file. The ts_time variable
% is just the input file times in Modified Julian Day.
%
% EXAMPLE USAGE
% Mobj = get_POLCOMS_tsobc(Mobj, ts, depth)
% Mobj = get_POLCOMS_tsobc(Mobj, ts)
%
% Author(s):
% Pierre Cazenave (Plymouth Marine Laboratory)
%
% Revision history
% 2013-02-07 First version based on get_POLCOMS_tsobc.m.
% 2013-02-07 First version.
% 2013-02-27 Change the vertical interpolation to be scaled within the
% POLCOMS-ERSEM depth range for the current node. The net result is that
% the vertical profiles are squashed or stretched to fit within the
% FVCOM depths. This means the full profile structure is maintained in
% the resulting FVCOM boundary input despite the differing depths at the
% FVCOM boundary node.
%
%==========================================================================
......@@ -85,6 +91,9 @@ if ftbverbose
tic
end
for t = 1:nt
if ftbverbose
fprintf('%s : %i of %i timesteps... ', subname, t, nt)
end
% Get the current 3D array of PML POLCOMS-ERSEM results.
pctemp3 = pc.ETWD.data(:, :, :, t);
pcsalt3 = pc.x1XD.data(:, :, :, t);
......@@ -175,35 +184,47 @@ for t = 1:nt
% Now we've interpolated in space, we can interpolate the z-values
% to the sigma depths.
oNodes = Mobj.obc_nodes(Mobj.obc_nodes ~= 0);
for zi = 1:fz
% Preallocate the output arrays
fvtempz = nan(nf, fz);
fvsalz = nan(nf, fz);
for pp = 1:nf
% Get the FVCOM depths at this node
tfz = Mobj.siglayz(oNodes(pp), :);
% Now get the interpolated PML POLCOMS-ERSEM depth at this node
tpz = idepthz(pp, :);
% Get the temperature and salinity values for this node and
% interpolate down the water column (from PML POLCOMS-ERSEM to
% FVCOM). I had originally planned to use csaps for the
% vertical interplation/subsampling at each location. However,
% the demo of csaps in the MATLAB documentation makes the
% interpolation look horrible (shaving off extremes). interp1
% provides a range of interpolation schemes, of which pchip
% seems to do a decent job of the interpolation (at least
% qualitatively).
if ~isnan(tpz)
fvtempz(pp, :) = interp1(tpz, itempz(pp, :), tfz, 'linear', 'extrap');
fvsalz(pp, :) = interp1(tpz, isalz(pp, :), tfz, 'linear', 'extrap');
else
warning('Should never see this... ') % because we test for NaNs when fetching the values.
warning('FVCOM boundary node at %f, %f is outside the PML POLCOMS-ERSEM domain. Skipping.', fvlon(pp), fvlat(pp))
continue
end
% Preallocate the output arrays
fvtempz = nan(nf, fz);
fvsalz = nan(nf, fz);
for pp = 1:nf
% Get the FVCOM depths at this node
tfz = Mobj.siglayz(oNodes(pp), :);
% Now get the interpolated PML POLCOMS-ERSEM depth at this node
tpz = idepthz(pp, :);
% To ensure we get the full vertical expression of the vertical
% profiles, we need to normalise the POLCOMS-ERSEM and FVCOM
% depths to the same range. This is because in instances where
% FVCOM depths are shallower (e.g. in coastal regions), if we
% don't normalise the depths, we end up truncating the vertical
% profile. This approach ensures we always use the full
% vertical profile, but we're potentially squeezing it into a
% smaller depth.
A = max(tpz);
B = min(tpz);
C = max(tfz);
D = min(tfz);
norm_tpz = (((D - C) * (tpz - A)) / (B - A)) + C;
% Get the temperature and salinity values for this node and
% interpolate down the water column (from PML POLCOMS-ERSEM to
% FVCOM). I had originally planned to use csaps for the
% vertical interplation/subsampling at each location. However,
% the demo of csaps in the MATLAB documentation makes the
% interpolation look horrible (shaving off extremes). interp1
% provides a range of interpolation schemes, of which pchip
% seems to do a decent job of the interpolation (at least
% qualitatively).
if ~isnan(tpz)
fvtempz(pp, :) = interp1(norm_tpz, itempz(pp, :), tfz, 'linear', 'extrap');
fvsalz(pp, :) = interp1(norm_tpz, isalz(pp, :), tfz, 'linear', 'extrap');
else
warning('Should never see this... ') % because we test for NaNs when fetching the values.
warning('FVCOM boundary node at %f, %f is outside the PML POLCOMS-ERSEM domain. Skipping.', fvlon(pp), fvlat(pp))
continue
end
end
......@@ -211,6 +232,10 @@ for t = 1:nt
% FVCOM results array.
fvtemp(:, :, t) = fvtempz;
fvsal(:, :, t) = fvsalz;
if ftbverbose
fprintf('done.\n')
end
end
if ftbverbose
toc
......
function [fieldout] = nodes2elems(fieldin,Mobj)
function [fieldout] = nodes2elems(fieldin,Mobj)
% Transfer a field from vertices to elements
%
% function [fieldout] = nodes2elems(fieldin,Mobj)
% function [fieldout] = nodes2elems(fieldin, Mobj)
%
% DESCRIPTION:
% Smooth a vertex based field
% Transfer a field from vertices (nodes) to elements
%
% INPUT
% Mobj = Matlab mesh object
......@@ -15,36 +14,36 @@ function [fieldout] = nodes2elems(fieldin,Mobj)
% fieldout = element-based field
%
% EXAMPLE USAGE
% f = smoothfield(fv,Mobj)
% f = smoothfield(fv, Mobj)
%
% Author(s):
% Geoff Cowles (University of Massachusetts Dartmouth)
%
% Revision history
%
%==============================================================================
%==========================================================================
subname = 'nodes2elems';
global ftbverbose;
if(ftbverbose);
fprintf('\n')
fprintf(['begin : ' subname '\n'])
end;
if ftbverbose;
fprintf('\n')
fprintf(['begin : ' subname '\n'])
end
%------------------------------------------------------------------------------
%--------------------------------------------------------------------------
% Parse input
%------------------------------------------------------------------------------
%--------------------------------------------------------------------------
if(exist('fieldin')*exist('Mobj') == 0)
if exist('fieldin', 'var') ~= 1 || exist('Mobj', 'var') ~= 1
error('arguments to nodes2elems are missing')
end;
end
if(length(fieldin) ~= Mobj.nVerts)
if length(fieldin) ~= Mobj.nVerts