Commit 88bed0c4 authored by Sherman Beus's avatar Sherman Beus
Browse files

Initial commit

parents
function [Jd0] = serial2doy0(serial);
%Returns the Julian day corresponding to the supplied serial date. Jan 1 = 0;
year = datestr(serial(1),10); %Returns the year of the serial date
year = datenum(str2num(year),1,1); %Converts the string returned from datestr into a number
Jd0 = serial - year;
function [Jd1] = serial2doy1(serial);
%Returns the Julian day corresponding to the supplied serial date. Jan 1 = 1;
year = datestr(serial(1),10); %Returns the year of the serial date
year = datenum(str2num(year),1,0); %Converts the string returned from datestr into a number
Jd1 = serial - year;
function [nc] = anccat (nc1, nc2)
% [NC] = ANCCAT (NC1, NC2)
%
% Combines the two input structs into a single struct. This assumes that
% the inputs are of the same data element structure, and that the time
% dimension is the last for each record field. The two structs are
% combined along the unlimited (time) dimension.
%
% $Revision: 1.10 $
% $Date: 2006/06/22 21:26:31 $
%
% See also ANCSIFT, ANCLINK, ANCSAVE, ANCGETDATA, ANCSTRUCT.
%
%-------------------------------------------------------------------
% VERSION INFORMATION:
%
% $RCSfile: anccat.m,v $
% $Revision: 1.10 $
% $Date: 2006/06/22 21:26:31 $
%
% $Log: anccat.m,v $
% Revision 1.10 2006/06/22 21:26:31 sbeus
% Updated logic pertaining to ordering of single-dimensioned fields:
% Record field: row vector (1r x nc)
% Column field: column vector (nr x 1c)
%
% Revision 1.9 2006/06/19 18:41:47 sbeus
% Added back CVS log information.
%
%
%-------------------------------------------------------------------
% Initialize output structure to first input.
nc = nc1;
% Horizontally concatenate time values.
nc.time = [nc1.time nc2.time];
[nc.time, sortinds] = sort(nc.time);
nc = timesync(nc);
varnames = fieldnames(nc1.vars);
for v = 1:length(varnames)
% Skip time fields (have already been synchronized).
if (~strcmp(varnames{v},'time') & ~strcmp(varnames{v},'base_time') & ~strcmp(varnames{v},'time_offset'))
v1 = nc1.vars.(varnames{v});
% Make sure compatible variable exists in second struct.
if (isfield(nc2.vars, varnames{v}))
v2 = nc2.vars.(varnames{v});
if (strcmp(v1.dims(length(v1.dims)), 'time'))
if (ndims(v1.data) == ndims(v2.data))
nd = ndims(v1.data);
dimdiff = (size(v1.data) == size(v2.data));
if (length(v1.dims) == 1)
dimdiff = dimdiff(2);
dimcomp = ones(1);
dimrotate = 0;
else
dimdiff = dimdiff(1:(nd-1));
dimcomp = ones(1,(nd-1));
dimrotate = (nd-1);
end
if (dimdiff == dimcomp)
% Rotate dimensions so time dim is first (necessary for vertcat).
v1.data = shiftdim(v1.data, dimrotate);
v2.data = shiftdim(v2.data, dimrotate);
% Determine subset reference struct (for sorting along time dim in first position).
S.type = '()';
S.subs = cell(0);
S.subs{1} = sortinds;
for d = 2:nd
S.subs{d} = ':';
end
% Vertically concatenate data arrays.
%disp(['Combining field: ', varnames{v}]);
nc.vars.(varnames{v}).data = subsref([v1.data;v2.data], S);
% Undo dim rotation.
nc.vars.(varnames{v}).data = shiftdim(nc.vars.(varnames{v}).data, (nd-dimrotate));
end
end
end
end
end
end
return
function [cdf,status] = anccheck (cdf)
% [cdf, status] = ANCCHECK (ancstruct)
%
% - Checks structure for required elements (dims, atts, vars)
% - Checks the data element of each field for size consistent with the dims
%
% Basically this will let you know when you've either forgotten to
% populate a field, or have made a mistake in terms of the size/shape
% of the data element.
%
% $Revision: 1.21 $
% $Date: 2006/08/18 22:41:19 $
%
% See also ANCSTRUCT, ANCLIST, ANCDIFF.
%
%-------------------------------------------------------------------
% VERSION INFORMATION:
%
% $RCSfile: anccheck.m,v $
% $Revision: 1.21 $
% $Date: 2006/08/18 22:41:19 $
%
% $Log: anccheck.m,v $
% Revision 1.21 2006/08/18 22:41:19 cflynn
% Supported logical/boolean datatype
%
% Revision 1.20 2006/06/22 21:26:31 sbeus
% Updated logic pertaining to ordering of single-dimensioned fields:
% Record field: row vector (1r x nc)
% Column field: column vector (nr x 1c)
%
% Revision 1.19 2006/06/19 18:41:47 sbeus
% Added back CVS log information.
%
%
%-------------------------------------------------------------------
status = 0;
if (nargin ~= 1)
help anccheck
return;
end
q = isquiet(cdf);
% Check for first-level elements.
elements = {'fname' 'atts' 'dims' 'recdim' 'vars'};
for e = 1:length(elements)
if ~isfield(cdf, elements{e})
if strcmp(elements{e}, 'fname')
cdf.fname = '';
else
cdf.(elements{e}) = struct;
end
dispmsg(q, 0, 'NCSTRUCT', elements{e}, 'Added');
status = status + 1;
end
end
% Check dimensions.
dims = fieldnames(cdf.dims);
cdf.dims = init_ids(cdf.dims);
elements = {'isunlim' 'length'};
for d = 1:length(dims)
dim = cdf.dims.(dims{d});
for e = 1:length(elements)
if ~isfield(dim, elements{e})
cdf.dims.(dims{d}).(elements{e}) = 0;
dispmsg(q, 1, 'DIMENSION', dims{d}, ['Added "', elements{e}, '" element']);
status = status + 1;
end
if (isempty(fieldnames(cdf.recdim)) && dim.isunlim)
cdf.recdim = dim;
cdf.recdim.name = dims{d};
dispmsg(q, 0, 'NCSTRUCT', 'recdim', 'Added details (name, id, length)');
status = status + 1;
end
end
% Check corresponding coordinate field.
if (strcmp(dims{d}, 'time'))
% Time special case is handled by 'synctime'.
continue;
end
if (isfield(cdf.vars, dims{d}))
if (length(cdf.vars.(dims{d}).dims) ~= 1)
dispwarn('COORD VAR', dims{d}, 'Is not single-dimensioned');
status = status + 1;
end
if (~strcmp(cdf.vars.(dims{d}).dims{1}, dims{d}))
dispwarn('COORD VAR', dims{d}, 'Is not appropriately dimensioned');
status = status + 1;
end
if (~isempty(cdf.vars.(dims{d}).data))
vdata = cdf.vars.(dims{d}).data;
diffs = diff(vdata);
gtzero = length(find(diffs > 0));
ltzero = length(find(diffs < 0));
if (gtzero < (dim.length-1) && ltzero < (dim.length-1))
dispwarn('COORD VAR', dims{d}, 'Is not monotonic');
status = status + 1;
end
if (~isempty(find(isnan(vdata))) || ~isempty(find(vdata == -9999)))
dispwarn('COORD VAR', dims{d}, 'Contains missing(s)');
status = status + 1;
end
else
if (dim.length > 0)
cdf.vars.(dims{d}).data = 0:(dim.length-1);
dispmsg(q, 1, 'COORD VAR', dims{d}, 'Added default data');
status = status + 1;
end
end
else
cdf.vars.(dims{d}).dims = { dims{d} };
cdf.vars.(dims{d}).data = [];
if (dim.length > 0)
cdf.vars.(dims{d}).data = 0:(dim.length-1);
end
dispmsg(q, 1, 'COORD VAR', dims{d}, 'Added');
status = status + 1;
end
end
% Check global attributes.
[cdf.atts, status] = checkatts(q, 'global', cdf.atts, status);
% Check variables.
if isfield(cdf, 'vars')
vars = fieldnames(cdf.vars);
cdf.vars = init_ids(cdf.vars);
for v = 1:length(vars)
if ~isfield(cdf.vars.(vars{v}), 'data')
cdf.vars.(vars{v}).data = 0;
dispmsg(q, 1, 'VARIABLE', vars{v}, 'Added default data');
status = status + 1;
end
if ~isfield(cdf.vars.(vars{v}), 'dims')
if any(size(cdf.vars.(vars{v}).data) == 1)
% Assume uni-dimensional fields are against the unlimited dim.
cdf.vars.(vars{v}).dims = { cdf.recdim.name };
dispmsg(q, 1, 'VARIABLE', vars{v}, ['Set default dim to unlimited ', cdf.recdim.name]);
status = status + 1;
end
end
if ~isfield(cdf.vars.(vars{v}), 'datatype')
datatype = mexnc('PARAMETER', 'NC_FLOAT');
if all(islogical(cdf.vars.(vars{v}).data))
datatype = mexnc('PARAMETER', 'NC_INT');
elseif all(cdf.vars.(vars{v}).data == floor(cdf.vars.(vars{v}).data))
datatype = mexnc('PARAMETER', 'NC_INT');
end
cdf.vars.(vars{v}).datatype = datatype;
dispmsg(q, 1, 'VARIABLE', vars{v}, ['Set default datatype to ', anctype(datatype)]);
status = status + 1;
end
if ~isfield(cdf.vars.(vars{v}), 'atts')
cdf.vars.(vars{v}).atts = struct;
dispmsg(q, 1, 'VARIABLE', vars{v}, 'Added "atts" element');
status = status + 1;
end
if ~isfield(cdf.vars.(vars{v}).atts, 'long_name')
cdf.vars.(vars{v}).atts.long_name.data = vars{v};
dispmsg(q, 2, 'ATTRIBUTE', [vars{v},':long_name'], 'Defined');
status = status + 1;
end
if ~isfield(cdf.vars.(vars{v}).atts, 'units')
cdf.vars.(vars{v}).atts.units.data = 'unitless';
dispmsg(q, 2, 'ATTRIBUTE', [vars{v},':units'], 'Defined');
status = status + 1;
end
[cdf.vars.(vars{v}).atts, status] = checkatts(q, vars{v}, cdf.vars.(vars{v}).atts, status);
end
end
% Check variable data-dimensionality consistency.
[cdf, status] = checkvardata(q, cdf, status);
% Check record dimension.
dims = fieldnames(cdf.dims);
for d = 1:length(dims)
dim = cdf.dims.(dims{d});
if dim.isunlim
cdf.recdim.name = dims{d};
cdf.recdim.id = dim.id;
cdf.recdim.length = dim.length;
break;
end
end
return
function [cdf, status] = checkvardata (q, cdf, status)
% Checks all variables for data-dimensionality consistency.
quiet = isquiet(cdf);
vars = fieldnames(cdf.vars);
for v = 1:length(vars)
variable = cdf.vars.(vars{v});
nvardims = length(variable.dims);
if (nvardims == 1)
if (isempty(variable.dims{1}))
nvardims = nvardims - 1; % scalar fields have empty string for dimension.
end
end
dsize = size(variable.data);
ddsize = dsize(dsize ~= 1); % remove unneeded dims.
% Check to see if data size agrees with dims cell array.
if (length(ddsize) ~= nvardims)
dispwarn('VARIABLE', vars{v}, 'Data size does not match dims array');
status = status + 1;
continue;
end
startstat = status;
for d = 1:(nvardims-1)
if (strcmp(variable.dims{d}, cdf.recdim.name))
dispwarn('VARIABLE', vars{v}, ['"',dims{d},'" dimension must be last in dims array']);
status = status + 1;
end
end
if (status > startstat)
continue;
end
if (nvardims == 1)
if ((strcmp(variable.dims{1},cdf.recdim.name) && dsize(2) == 1) || (~strcmp(variable.dims{1},cdf.recdim.name) && dsize(1) == 1))
cdf.vars.(vars{v}).data = cdf.vars.(vars{v}).data'; %'
variable = cdf.vars.(vars{v});
dispmsg(q, 1, 'VARIABLE', vars{v}, 'Single-dim record fields must be row vectors (non-record: column)');
status = status + 1;
end
end
% Check field dimensionality against dims cell array.
for d = 1:nvardims
if (~isfield(cdf.dims, variable.dims{d}))
% Dimension does not exist.
continue;
end
dim = cdf.dims.(variable.dims{d});
dindex = d;
if (nvardims == 1 && dim.isunlim)
% Single-dimensioned, unlimited vars are column ordered.
dindex = dindex + 1;
end
datalength = size(variable.data, dindex);
if (datalength > dim.length)
cdf.dims.(variable.dims{d}).length = datalength;
dispmsg(q, 1, 'DIMENSION', variable.dims{d}, ['Changed length to ',num2str(datalength),', to match variable: ',vars{v}]);
status = status + 1;
% Run re-check to pad all fields affected by this dimension length increase.
[cdf, status] = checkvardata(q, cdf, status);
break;
elseif (datalength < dim.length)
needlength = dim.length;
% Pad variable data with NaNs to meet dimension length.
inds = size(variable.data);
inds(dindex) = (needlength - datalength);
pad = zeros(inds)*NaN;
cdf.vars.(vars{v}).data = cat(dindex, variable.data, pad);
% Reset variable struct so recent changes will be included.
variable = cdf.vars.(vars{v});
dispmsg(q, 1, 'VARIABLE', vars{v}, ['Padded with ',num2str(needlength - datalength),' NaNs to match dimension: ',variable.dims{d}]);
status = status + 1;
end
end
end
% Handle time special case...
if isfield(cdf, 'time') & isfield(cdf.dims, 'time')
exlength = length(cdf.time);
inlength = cdf.dims.time.length;
if (exlength > inlength)
cdf.dims.time.length = exlength;
dispmsg(q, 1, 'DIMENSION', 'time', ['Changed length to ',num2str(exlength),', to match time field']);
status = status + 1;
% Run re-check to pad all fields affected by this dimension increase.
[cdf, status] = checkvardata(q, cdf, status);
elseif (exlength < inlength)
% Remove time array so timesync will update it.
cdf = rmfield(cdf, 'time');
% Synchronize time difference (so internal fields are updated e.g. base_time, time_offset).
cdf = timesync(cdf);
dispmsg(q, 0, 'NCSTRUCT', 'time', 'Synchronized with internal time variable(s)');
end
end
return
function [attstruct, status] = checkatts (q, parent, attstruct, status)
% Checks attributes.
% This function is actually deprecated but still works.
chartype = mexnc('PARAMETER', 'NC_CHAR');
atts = fieldnames(attstruct);
attstruct = init_ids(attstruct);
elements = {'data', 'datatype'};
for a = 1:length(atts)
att = attstruct.(atts{a});
for e = 1:length(elements)
if ~isfield(att, elements{e})
attstruct.(atts{a}).(elements{e}) = 0;
dispmsg(q, 2, 'ATTRIBUTE', [parent,':',atts{a}], ['Added ', elements{e}, ' element']);
status = status + 1;
end
end
att = attstruct.(atts{a});
istexttype = (att.datatype == chartype);
istext = ischar(att.data);
if (istexttype ~= istext)
attstruct.(atts{a}).datatype = chartype;
dispmsg(q, 2, 'ATTRIBUTE', [parent,':',atts{a}], 'Changed datatype to "char"');
status = status + 1;
end
end
return
function dispmsg(quiet, indent, element, name, message)
% Displays message if quiet global is not set.
spaces = ' ';
for i=0:indent
spaces = [spaces, ' '];
end
if (~quiet)
disp([spaces, '> ', upper(element), ' > ', upper(name), ': ', message]);
end
return
function dispwarn(element, name, message)
% Displays warning message.
disp(['WARNING > ', upper(element), ' > ', upper(name), ': ', message]);
return
function [quiet] = isquiet(cdf)
% Returns whether or not to suppress output messages.
quiet = false;
if (isfield(cdf,'quiet'))
quiet = cdf.quiet;
end
return
function defopts = ancdiff (nc1, nc2, options)
% NC1 = ANCDIFF (NC1, NC2)
%
% Prints differences between two input ncstructs. The optional
% options structure is composed of the following elements:
%
% OPTIONS.VERBOSE = [true|false], default: false
% OPTIONS.INCVARS = [true|false], default: true
% OPTIONS.INCDIMS = [true|false], default: true
% OPTIONS.INCATTS = [true|false], default: true
%
% $Revision: 1.2 $
% $Date: 2006/06/19 18:41:47 $
%
% See also ANCCHECK, ANCSTRUCT.
%
%-------------------------------------------------------------------
% VERSION INFORMATION:
%
% $RCSfile: ancdiff.m,v $
% $Revision: 1.2 $
% $Date: 2006/06/19 18:41:47 $
%
% $Log: ancdiff.m,v $
% Revision 1.2 2006/06/19 18:41:47 sbeus
% Added back CVS log information.
%
%
%-------------------------------------------------------------------
% Check options.
default.verbose = false;
default.incvars = true;
default.incdims = true;
default.incatts = true;
if (nargin > 2)
opts = options;
if (~isfield(opts, 'verbose'))
opts.verbose = default.verbose;
defopts = opts;
end
if (~isfield(opts, 'incvars'))
opts.incvars = default.incvars;
defopts = opts;
end
if (~isfield(opts, 'incdims'))
opts.incdims = default.incdims;
defopts = opts;
end
if (~isfield(opts, 'incatts'))
opts.incatts = default.incatts;
defopts = opts;
end
else
defopts.verbose = default.verbose;
defopts.incvars = default.incvars;
defopts.incdims = default.incdims;
defopts.incatts = default.incatts;
opts = defopts;
end
if (nargout == 1)
defopts = opts;
end
% Messages to print when a given comparison element is unmatched.
nfmsg1 = ['Not found in "', upper(inputname(1)),'"'];
nfmsg2 = ['Not found in "', upper(inputname(2)),'"'];
%===================================================================
% DIMENSIONS >
if (opts.incdims)
dims1 = fieldnames(nc1.dims);
for d = 1:length(dims1)
if (~isfield(nc2.dims, dims1{d}))
dispdiff('dim', dims1{d}, nfmsg2);
continue;
end
dim1 = nc1.dims.(dims1{d});
dim2 = nc2.dims.(dims1{d});
if (dim1.length ~= dim2.length)
dispdiff('dim', dims1{d}, 'Length mismatch', num2str(dim1.length), num2str(dim2.length), opts);
end
if (dim1.isunlim ~= dim2.isunlim)
dispdiff('dim', dims1{d}, 'Unlimited flag mismatch', num2str(dim1.isunlim), num2str(dim2.isunlim), opts);
end
end
dims2 = fieldnames(nc2.dims);
for d = 1:length(dims2)
if (~isfield(nc1.dims, dims2{d}))
dispdiff('dim', dims2{d}, nfmsg1);
continue;
end
end
end
%===================================================================
% GLOBAL ATTRIBUTES >
compatts(nfmsg1, nfmsg2, '', nc1.atts, nc2.atts, opts);
%===================================================================
% VARIABLES >
if (opts.incvars)
vars1 = fieldnames(nc1.vars);
for v = 1:length(vars1)
if (~isfield(nc2.vars, vars1{v}))
dispdiff('var', vars1{v}, nfmsg2);
continue;
end
var1 = nc1.vars.(vars1{v});
var2 = nc2.vars.(vars1{v});
if (var1.datatype ~= var2.datatype)
dispdiff('var', vars1{v}, 'Type mismatch', anctype(var1.datatype), anctype(var2.datatype), opts);
else
shape1 = size(var1.data);
shape2 = size(var2.data);
if (length(shape1) ~= length(shape2) | any(shape1 ~= shape2))