function theResult = subsref(self, theStruct) % ncvar/subsref -- Overloaded "{}", ".", and "()" operators. % subsref(self, theStruct) processes the subscripting % operator () for self, an "ncvar" object referenced on % the righthand side of an assignment, such as in % result = self(i, j, ...), where the sole operator % is '()'. If the syntax is result = self.theAttname % or result = self.theAttname(...), the named attribute % object of self is processed. If fewer than the full % number of indices are provided, the silent ones % default to 1, unless the last one provided is ':', % in which case the remainder default to ':' as well. % Indices beyond the full number needed are ignored. % ## Only a constant stride is permitted at present. % % If the "quick" flag is set, faster "vanilla-flavored" % processing is forced. Except for autoscaling, no % special treatments are performed, such as virtual % indexing, implicit indexing (including ":"), unsigned % conversions, or auto-NaNing. % Also see: ncvar/subsasgn. % Copyright (C) 1996-7 Dr. Charles R. Denham, ZYDECO. % All Rights Reserved. % Disclosure without explicit written consent from the % copyright owner does not constitute publication. % Version of 07-Aug-1997 15:55:19. % Updated 25-Mar-2003 11:35:17. if nargin < 1, help(mfilename), return, end if length(theStruct) < 1 result = self; if nargout > 0 theResult = result; else disp(result) end return end % Quick processing. % The NetCDF file must already be in "data" mode. isQuick = quick(self) & ... length(theStruct) == 1 & ... isequal(theStruct.type, '()'); if isQuick indices = theStruct.subs; if ~iscell(indices), indices = {indices}; end if (0) % Slow, but proper. theNCid = ncid(self); theVarid = varid(self); theSize = ncsize(self); % Slow. start = zeros(size(theSize)); count = zeros(size(theSize)); theAutoscaleflag = autoscale(self); else % Fast, but very bad manners. s = struct(self); s = s.ncitem; s = struct(s); theNCid = s.itsNCid; theVarid = s.itsVarid; start = zeros(1, length(indices)); count = zeros(1, length(indices)); theAutoscaleflag = s.itIsAutoscaling; end for i = 1:length(indices) k = indices{i}; start(i) = min(k) - 1; count(i) = length(k); end [result, status] = ncmex('varget', theNCid, theVarid, ... start, count, theAutoscaleflag); if status >= 0 result = permute(result, length(size(result)):-1:1); end if nargout > 0 theResult = result; else disp(result) end return end % Composite-variable processing. % We map the source-indices to the destination-indices % for each composite-variable participant. The indices % are in cells of cells, arranged in the same order as % the variables, which themselves are in a cell. % Can we consolidate some of this mess? theVars = var(self); % A cell. if ~isempty(theVars) [theSrcsubs, theDstsubs] = subs(self); % The mappings. for j = 1:length(theSrcsubs) siz = size(theVars{j}); src = theSrcsubs{j}; for i = 1:length(src) if isequal(src{i}, ':') % Convert to numbers. src{i} = 1:siz(i); end end theSrcsubs{j} = src; end theSize = zeros(size(theDstsubs)); for j = 1:length(theDstsubs) dst = theDstsubs{j}; for i = 1:length(dst) theSize(i) = max(theSize(i), max(dst{i})); end end theSubs = theStruct(1).subs; if ~iscell(theSubs), theSubs = {theSubs}; end isColon = isequal(theSubs{end}, ':'); if isColon, s = ':'; else, s = 1; end while length(theSubs) < length(theSize) theSubs{end+1} = s; end % Note: We compute a base-1 surrogate of theSubs, % in order to keep the pre-allocated "result" matrix % as small as possible. subsx = cell(size(theSubs)); % "subs" is a function. siz = zeros(size(subsx)); for i = 1:length(theSubs) if isequal(theSubs{i}, ':') theSubs{i} = 1:theSize(i); end subsx{i} = theSubs{i} - min(theSubs{i}) + 1; % Base-1. siz(i) = max(subsx{i}); end result = zeros(siz); % Pre-allocate. for j = 1:length(theVars) % [from, to] = mapsubs(theSrcsubs{j}, theDstsubs{j}, theSubs); [from, to] = mapsubs(theSrcsubs{j}, theDstsubs{j}, subsx); if ~isempty(from) & ~isempty(to) x = ncsubsref(theVars{j}, '()', from); result(to{:}) = x; end end % result = result(theSubs{:}); % Subset. result = result(subsx{:}); % Subset. if nargout > 0 theResult = result; else disp(result) end return end % Regular processing. result = []; if nargout > 0, theResult = result; end s = theStruct; theType = s(1).type; theSubs = s(1).subs; s(1) = []; nccheck(self) theDatatype = datatype(self); theFillvalue = fillval(self); if strcmp ( theDatatype, 'char' ) theAutonanflag = 0; theAutoscaleflag = 0; else theAutonanflag = (autonan(self) == 1) & ~isempty(theFillvalue); theAutoscaleflag = (autoscale(self) == 1); end theTypelen = ncmex('typelen', theDatatype); isUnsigned = unsigned(self); if theAutoscaleflag theScalefactor = scalefactor(self); theAddoffset = addoffset(self); end switch theType case '()' % Variable data by index: self(..., ...). indices = theSubs; theSize = ncsize(self); for i = 1:length(indices) if isa(indices{i}, 'double') if any(diff(diff(indices{i}))) disp(' ## Indexing strides must be positive and constant.') return end end end % Flip and permute indices before proceeding, % since we are using virtual indexing. theOrientation = orient(self); if any(theOrientation < 0) | any(diff(theOrientation) ~= 1) for i = 1:length(theOrientation) if theOrientation(i) < 0 if isa(indices{i}, 'double') % Slide the indices. indices{i} = fliplr(theSize(i) + 1 - indices{i}); end end end indices(abs(theOrientation)) = indices; theSize(abs(theOrientation)) = theSize; end if prod(theSize) > 0 % % Singleton variables end up with an empty "theSize". But, % prod(theSize) still results in 1. Yeah, that makes sense. % This results in [] being passed into the mex file for the % index. Yeah, ***THAT*** makes sense. It actually works for % a singleton, but causes a segmentation fault otherwise. % Bad state of affairs. So we need to watch for this. % The way out is to make sure that singletons get a start % index of 0. % % JGE if isempty(theSize) start = 0; else start = zeros(1, length(theSize)); end count = ones(1, length(theSize)); stride = ones(1, length(theSize)); for i = 1:min(length(indices), length(theSize)) k = indices{i}; if ~isstr(k) & ~strcmp(k, ':') & ~strcmp(k, '-') start(i) = k(1)-1; count(i) = length(k); d = 0; if length(k) > 1, d = diff(k); end stride(i) = max(d(1), 1); else count(i) = -1; if i == length(indices) & i < length(theSize) j = i+1:length(theSize); count(j) = -ones(1, length(j)); end end end start(start < 0) = 0; stride(stride < 0) = 1; for i = 1:length(count) if count(i) == -1 maxcount = fix((theSize(i)-start(i)+stride(i)-1) ./ stride(i)); count(i) = maxcount; end end theNetCDF = parent(self); theNetCDF = endef(theNetCDF); count(count < 0) = 0; if any(count == 0), error(' ## Bad count.'), end if all(count == 1) [result, status] = ncmex('varget1', ncid(self), varid(self), ... start, 0); elseif all(stride == 1) [result, status] = ncmex('varget', ncid(self), varid(self), ... start, count, 0); else imap = []; [result, status] = ncmex('vargetg', ncid(self), varid(self), ... start, count, stride, imap, ... 0); end if theAutonanflag & status >= 0 f = find(result == theFillvalue); if any(f), result(f) = NaN; end end if theAutoscaleflag & status >= 0 result = result .* theScalefactor + theAddoffset; end if isUnsigned & prod(size(result)) > 0 result(result < 0) = 2^(8*theTypelen) + result(result < 0); end else result = []; status = 0; end if status >= 0 & prod(size(result)) > 0 & (ndims(result)==2) & (strcmp(class(result),'char')) & any(find(size(result)==1)) % % If the read operation was successful % and if something was actually returned % and if that something has exactly two dimensions % and if that something was character % and if that character string is actually 1D (ndims never returns 1) % then do not permute. % % This way 1D character arrays are loaded as column vectors. % % Now if you'll excuse me, after writing this code fragment, I have to go % wash my hands vigorously for a few hours (get it off, get it off, get it off, unclean..) ; elseif status >= 0 & prod(size(result)) > 0 result = permute(result, length(size(result)):-1:1); theOrientation = orient(self); if any(theOrientation < 0) | any(diff(theOrientation) ~= 1) for i = 1:length(theOrientation) if theOrientation(i) < 0 result = flipdim(result, abs(theOrientation(i))); end end if length(theOrientation) < 2 theOrientation = [theOrientation 2]; end result = permute(result, abs(theOrientation)); end elseif status >= 0 & prod(size(result)) == 0 result = []; else status, prod_size_result = prod(size(result)) % *** warning(' ## ncvar/subsref failure.') end case '.' % Attribute: self.theAttname(...) theAttname = theSubs; while length(s) > 0 % Dotted name. switch s(1).type case '.' theAttname = [theAttname '.' s(1).subs]; s(1) = []; otherwise break end end result = att(self, theAttname); if ~isempty(result), result = subsref(result, s); end otherwise warning([' ## Illegal syntax: "' theType '"']) end if nargout > 0 % Always true. theResult = result; else % Is there any way to force this? c = ncatt('C_format', self); if ~isempty(c) c = c(:); s = size(result) result = result.'; result = result(:); step = prod(s)/s(1); k = 1:step; for i = 1:s(1) fprintf(c, result(k)); fprintf('\n'); k = k + step; end else disp(result) end end