[1] | 1 | function theResult = subsref(self, theStruct) |
---|
| 2 | |
---|
| 3 | % ncvar/subsref -- Overloaded "{}", ".", and "()" operators. |
---|
| 4 | % subsref(self, theStruct) processes the subscripting |
---|
| 5 | % operator () for self, an "ncvar" object referenced on |
---|
| 6 | % the righthand side of an assignment, such as in |
---|
| 7 | % result = self(i, j, ...), where the sole operator |
---|
| 8 | % is '()'. If the syntax is result = self.theAttname |
---|
| 9 | % or result = self.theAttname(...), the named attribute |
---|
| 10 | % object of self is processed. If fewer than the full |
---|
| 11 | % number of indices are provided, the silent ones |
---|
| 12 | % default to 1, unless the last one provided is ':', |
---|
| 13 | % in which case the remainder default to ':' as well. |
---|
| 14 | % Indices beyond the full number needed are ignored. |
---|
| 15 | % ## Only a constant stride is permitted at present. |
---|
| 16 | % |
---|
| 17 | % If the "quick" flag is set, faster "vanilla-flavored" |
---|
| 18 | % processing is forced. Except for autoscaling, no |
---|
| 19 | % special treatments are performed, such as virtual |
---|
| 20 | % indexing, implicit indexing (including ":"), unsigned |
---|
| 21 | % conversions, or auto-NaNing. |
---|
| 22 | |
---|
| 23 | % Also see: ncvar/subsasgn. |
---|
| 24 | |
---|
| 25 | % Copyright (C) 1996-7 Dr. Charles R. Denham, ZYDECO. |
---|
| 26 | % All Rights Reserved. |
---|
| 27 | % Disclosure without explicit written consent from the |
---|
| 28 | % copyright owner does not constitute publication. |
---|
| 29 | |
---|
| 30 | % Version of 07-Aug-1997 15:55:19. |
---|
| 31 | % Updated 25-Mar-2003 11:35:17. |
---|
| 32 | |
---|
| 33 | if nargin < 1, help(mfilename), return, end |
---|
| 34 | |
---|
| 35 | if length(theStruct) < 1 |
---|
| 36 | result = self; |
---|
| 37 | if nargout > 0 |
---|
| 38 | theResult = result; |
---|
| 39 | else |
---|
| 40 | disp(result) |
---|
| 41 | end |
---|
| 42 | return |
---|
| 43 | end |
---|
| 44 | |
---|
| 45 | % Quick processing. |
---|
| 46 | % The NetCDF file must already be in "data" mode. |
---|
| 47 | |
---|
| 48 | isQuick = quick(self) & ... |
---|
| 49 | length(theStruct) == 1 & ... |
---|
| 50 | isequal(theStruct.type, '()'); |
---|
| 51 | |
---|
| 52 | if isQuick |
---|
| 53 | indices = theStruct.subs; |
---|
| 54 | if ~iscell(indices), indices = {indices}; end |
---|
| 55 | if (0) % Slow, but proper. |
---|
| 56 | theNCid = ncid(self); |
---|
| 57 | theVarid = varid(self); |
---|
| 58 | theSize = ncsize(self); % Slow. |
---|
| 59 | start = zeros(size(theSize)); |
---|
| 60 | count = zeros(size(theSize)); |
---|
| 61 | theAutoscaleflag = autoscale(self); |
---|
| 62 | else % Fast, but very bad manners. |
---|
| 63 | s = struct(self); |
---|
| 64 | s = s.ncitem; |
---|
| 65 | s = struct(s); |
---|
| 66 | theNCid = s.itsNCid; |
---|
| 67 | theVarid = s.itsVarid; |
---|
| 68 | start = zeros(1, length(indices)); |
---|
| 69 | count = zeros(1, length(indices)); |
---|
| 70 | theAutoscaleflag = s.itIsAutoscaling; |
---|
| 71 | end |
---|
| 72 | for i = 1:length(indices) |
---|
| 73 | k = indices{i}; |
---|
| 74 | start(i) = min(k) - 1; |
---|
| 75 | count(i) = length(k); |
---|
| 76 | end |
---|
| 77 | [result, status] = ncmex('varget', theNCid, theVarid, ... |
---|
| 78 | start, count, theAutoscaleflag); |
---|
| 79 | if status >= 0 |
---|
| 80 | result = permute(result, length(size(result)):-1:1); |
---|
| 81 | end |
---|
| 82 | if nargout > 0 |
---|
| 83 | theResult = result; |
---|
| 84 | else |
---|
| 85 | disp(result) |
---|
| 86 | end |
---|
| 87 | return |
---|
| 88 | end |
---|
| 89 | |
---|
| 90 | % Composite-variable processing. |
---|
| 91 | % We map the source-indices to the destination-indices |
---|
| 92 | % for each composite-variable participant. The indices |
---|
| 93 | % are in cells of cells, arranged in the same order as |
---|
| 94 | % the variables, which themselves are in a cell. |
---|
| 95 | |
---|
| 96 | % Can we consolidate some of this mess? |
---|
| 97 | |
---|
| 98 | theVars = var(self); % A cell. |
---|
| 99 | if ~isempty(theVars) |
---|
| 100 | [theSrcsubs, theDstsubs] = subs(self); % The mappings. |
---|
| 101 | for j = 1:length(theSrcsubs) |
---|
| 102 | siz = size(theVars{j}); |
---|
| 103 | src = theSrcsubs{j}; |
---|
| 104 | for i = 1:length(src) |
---|
| 105 | if isequal(src{i}, ':') % Convert to numbers. |
---|
| 106 | src{i} = 1:siz(i); |
---|
| 107 | end |
---|
| 108 | end |
---|
| 109 | theSrcsubs{j} = src; |
---|
| 110 | end |
---|
| 111 | theSize = zeros(size(theDstsubs)); |
---|
| 112 | for j = 1:length(theDstsubs) |
---|
| 113 | dst = theDstsubs{j}; |
---|
| 114 | for i = 1:length(dst) |
---|
| 115 | theSize(i) = max(theSize(i), max(dst{i})); |
---|
| 116 | end |
---|
| 117 | end |
---|
| 118 | theSubs = theStruct(1).subs; |
---|
| 119 | if ~iscell(theSubs), theSubs = {theSubs}; end |
---|
| 120 | isColon = isequal(theSubs{end}, ':'); |
---|
| 121 | if isColon, s = ':'; else, s = 1; end |
---|
| 122 | while length(theSubs) < length(theSize) |
---|
| 123 | theSubs{end+1} = s; |
---|
| 124 | end |
---|
| 125 | |
---|
| 126 | % Note: We compute a base-1 surrogate of theSubs, |
---|
| 127 | % in order to keep the pre-allocated "result" matrix |
---|
| 128 | % as small as possible. |
---|
| 129 | |
---|
| 130 | subsx = cell(size(theSubs)); % "subs" is a function. |
---|
| 131 | siz = zeros(size(subsx)); |
---|
| 132 | for i = 1:length(theSubs) |
---|
| 133 | if isequal(theSubs{i}, ':') |
---|
| 134 | theSubs{i} = 1:theSize(i); |
---|
| 135 | end |
---|
| 136 | subsx{i} = theSubs{i} - min(theSubs{i}) + 1; % Base-1. |
---|
| 137 | siz(i) = max(subsx{i}); |
---|
| 138 | end |
---|
| 139 | |
---|
| 140 | result = zeros(siz); % Pre-allocate. |
---|
| 141 | |
---|
| 142 | for j = 1:length(theVars) |
---|
| 143 | % [from, to] = mapsubs(theSrcsubs{j}, theDstsubs{j}, theSubs); |
---|
| 144 | [from, to] = mapsubs(theSrcsubs{j}, theDstsubs{j}, subsx); |
---|
| 145 | if ~isempty(from) & ~isempty(to) |
---|
| 146 | x = ncsubsref(theVars{j}, '()', from); |
---|
| 147 | result(to{:}) = x; |
---|
| 148 | end |
---|
| 149 | end |
---|
| 150 | |
---|
| 151 | % result = result(theSubs{:}); % Subset. |
---|
| 152 | |
---|
| 153 | result = result(subsx{:}); % Subset. |
---|
| 154 | |
---|
| 155 | if nargout > 0 |
---|
| 156 | theResult = result; |
---|
| 157 | else |
---|
| 158 | disp(result) |
---|
| 159 | end |
---|
| 160 | return |
---|
| 161 | end |
---|
| 162 | |
---|
| 163 | % Regular processing. |
---|
| 164 | |
---|
| 165 | result = []; |
---|
| 166 | if nargout > 0, theResult = result; end |
---|
| 167 | |
---|
| 168 | s = theStruct; |
---|
| 169 | theType = s(1).type; |
---|
| 170 | theSubs = s(1).subs; |
---|
| 171 | s(1) = []; |
---|
| 172 | |
---|
| 173 | nccheck(self) |
---|
| 174 | theDatatype = datatype(self); |
---|
| 175 | theFillvalue = fillval(self); |
---|
| 176 | if strcmp ( theDatatype, 'char' ) |
---|
| 177 | theAutonanflag = 0; |
---|
| 178 | theAutoscaleflag = 0; |
---|
| 179 | else |
---|
| 180 | theAutonanflag = (autonan(self) == 1) & ~isempty(theFillvalue); |
---|
| 181 | theAutoscaleflag = (autoscale(self) == 1); |
---|
| 182 | end |
---|
| 183 | theTypelen = ncmex('typelen', theDatatype); |
---|
| 184 | isUnsigned = unsigned(self); |
---|
| 185 | if theAutoscaleflag |
---|
| 186 | theScalefactor = scalefactor(self); |
---|
| 187 | theAddoffset = addoffset(self); |
---|
| 188 | end |
---|
| 189 | |
---|
| 190 | switch theType |
---|
| 191 | case '()' % Variable data by index: self(..., ...). |
---|
| 192 | indices = theSubs; |
---|
| 193 | theSize = ncsize(self); |
---|
| 194 | for i = 1:length(indices) |
---|
| 195 | if isa(indices{i}, 'double') |
---|
| 196 | if any(diff(diff(indices{i}))) |
---|
| 197 | disp(' ## Indexing strides must be positive and constant.') |
---|
| 198 | return |
---|
| 199 | end |
---|
| 200 | end |
---|
| 201 | end |
---|
| 202 | |
---|
| 203 | % Flip and permute indices before proceeding, |
---|
| 204 | % since we are using virtual indexing. |
---|
| 205 | |
---|
| 206 | theOrientation = orient(self); |
---|
| 207 | if any(theOrientation < 0) | any(diff(theOrientation) ~= 1) |
---|
| 208 | for i = 1:length(theOrientation) |
---|
| 209 | if theOrientation(i) < 0 |
---|
| 210 | if isa(indices{i}, 'double') % Slide the indices. |
---|
| 211 | indices{i} = fliplr(theSize(i) + 1 - indices{i}); |
---|
| 212 | end |
---|
| 213 | end |
---|
| 214 | end |
---|
| 215 | indices(abs(theOrientation)) = indices; |
---|
| 216 | theSize(abs(theOrientation)) = theSize; |
---|
| 217 | end |
---|
| 218 | |
---|
| 219 | if prod(theSize) > 0 |
---|
| 220 | |
---|
| 221 | % |
---|
| 222 | % Singleton variables end up with an empty "theSize". But, |
---|
| 223 | % prod(theSize) still results in 1. Yeah, that makes sense. |
---|
| 224 | % This results in [] being passed into the mex file for the |
---|
| 225 | % index. Yeah, ***THAT*** makes sense. It actually works for |
---|
| 226 | % a singleton, but causes a segmentation fault otherwise. |
---|
| 227 | % Bad state of affairs. So we need to watch for this. |
---|
| 228 | % The way out is to make sure that singletons get a start |
---|
| 229 | % index of 0. |
---|
| 230 | % |
---|
| 231 | % JGE |
---|
| 232 | if isempty(theSize) |
---|
| 233 | start = 0; |
---|
| 234 | else |
---|
| 235 | start = zeros(1, length(theSize)); |
---|
| 236 | end |
---|
| 237 | |
---|
| 238 | count = ones(1, length(theSize)); |
---|
| 239 | stride = ones(1, length(theSize)); |
---|
| 240 | for i = 1:min(length(indices), length(theSize)) |
---|
| 241 | k = indices{i}; |
---|
| 242 | if ~isstr(k) & ~strcmp(k, ':') & ~strcmp(k, '-') |
---|
| 243 | start(i) = k(1)-1; |
---|
| 244 | count(i) = length(k); |
---|
| 245 | d = 0; |
---|
| 246 | if length(k) > 1, d = diff(k); end |
---|
| 247 | stride(i) = max(d(1), 1); |
---|
| 248 | else |
---|
| 249 | count(i) = -1; |
---|
| 250 | if i == length(indices) & i < length(theSize) |
---|
| 251 | j = i+1:length(theSize); |
---|
| 252 | count(j) = -ones(1, length(j)); |
---|
| 253 | end |
---|
| 254 | end |
---|
| 255 | end |
---|
| 256 | start(start < 0) = 0; |
---|
| 257 | stride(stride < 0) = 1; |
---|
| 258 | for i = 1:length(count) |
---|
| 259 | if count(i) == -1 |
---|
| 260 | maxcount = fix((theSize(i)-start(i)+stride(i)-1) ./ stride(i)); |
---|
| 261 | count(i) = maxcount; |
---|
| 262 | end |
---|
| 263 | end |
---|
| 264 | theNetCDF = parent(self); |
---|
| 265 | theNetCDF = endef(theNetCDF); |
---|
| 266 | count(count < 0) = 0; |
---|
| 267 | if any(count == 0), error(' ## Bad count.'), end |
---|
| 268 | if all(count == 1) |
---|
| 269 | [result, status] = ncmex('varget1', ncid(self), varid(self), ... |
---|
| 270 | start, 0); |
---|
| 271 | |
---|
| 272 | elseif all(stride == 1) |
---|
| 273 | |
---|
| 274 | [result, status] = ncmex('varget', ncid(self), varid(self), ... |
---|
| 275 | start, count, 0); |
---|
| 276 | else |
---|
| 277 | imap = []; |
---|
| 278 | [result, status] = ncmex('vargetg', ncid(self), varid(self), ... |
---|
| 279 | start, count, stride, imap, ... |
---|
| 280 | 0); |
---|
| 281 | end |
---|
| 282 | if theAutonanflag & status >= 0 |
---|
| 283 | f = find(result == theFillvalue); |
---|
| 284 | if any(f), result(f) = NaN; end |
---|
| 285 | end |
---|
| 286 | if theAutoscaleflag & status >= 0 |
---|
| 287 | result = result .* theScalefactor + theAddoffset; |
---|
| 288 | end |
---|
| 289 | if isUnsigned & prod(size(result)) > 0 |
---|
| 290 | result(result < 0) = 2^(8*theTypelen) + result(result < 0); |
---|
| 291 | end |
---|
| 292 | else |
---|
| 293 | result = []; |
---|
| 294 | status = 0; |
---|
| 295 | end |
---|
| 296 | if status >= 0 & prod(size(result)) > 0 & (ndims(result)==2) & (strcmp(class(result),'char')) & any(find(size(result)==1)) |
---|
| 297 | % |
---|
| 298 | % If the read operation was successful |
---|
| 299 | % and if something was actually returned |
---|
| 300 | % and if that something has exactly two dimensions |
---|
| 301 | % and if that something was character |
---|
| 302 | % and if that character string is actually 1D (ndims never returns 1) |
---|
| 303 | % then do not permute. |
---|
| 304 | % |
---|
| 305 | % This way 1D character arrays are loaded as column vectors. |
---|
| 306 | % |
---|
| 307 | % Now if you'll excuse me, after writing this code fragment, I have to go |
---|
| 308 | % wash my hands vigorously for a few hours (get it off, get it off, get it off, unclean..) |
---|
| 309 | ; |
---|
| 310 | |
---|
| 311 | elseif status >= 0 & prod(size(result)) > 0 |
---|
| 312 | result = permute(result, length(size(result)):-1:1); |
---|
| 313 | theOrientation = orient(self); |
---|
| 314 | if any(theOrientation < 0) | any(diff(theOrientation) ~= 1) |
---|
| 315 | for i = 1:length(theOrientation) |
---|
| 316 | if theOrientation(i) < 0 |
---|
| 317 | result = flipdim(result, abs(theOrientation(i))); |
---|
| 318 | end |
---|
| 319 | end |
---|
| 320 | if length(theOrientation) < 2 |
---|
| 321 | theOrientation = [theOrientation 2]; |
---|
| 322 | end |
---|
| 323 | result = permute(result, abs(theOrientation)); |
---|
| 324 | end |
---|
| 325 | elseif status >= 0 & prod(size(result)) == 0 |
---|
| 326 | result = []; |
---|
| 327 | else |
---|
| 328 | status, prod_size_result = prod(size(result)) % *** |
---|
| 329 | warning(' ## ncvar/subsref failure.') |
---|
| 330 | end |
---|
| 331 | case '.' % Attribute: self.theAttname(...) |
---|
| 332 | theAttname = theSubs; |
---|
| 333 | while length(s) > 0 % Dotted name. |
---|
| 334 | switch s(1).type |
---|
| 335 | case '.' |
---|
| 336 | theAttname = [theAttname '.' s(1).subs]; |
---|
| 337 | s(1) = []; |
---|
| 338 | otherwise |
---|
| 339 | break |
---|
| 340 | end |
---|
| 341 | end |
---|
| 342 | result = att(self, theAttname); |
---|
| 343 | if ~isempty(result), result = subsref(result, s); end |
---|
| 344 | otherwise |
---|
| 345 | warning([' ## Illegal syntax: "' theType '"']) |
---|
| 346 | end |
---|
| 347 | |
---|
| 348 | if nargout > 0 % Always true. |
---|
| 349 | theResult = result; |
---|
| 350 | else % Is there any way to force this? |
---|
| 351 | c = ncatt('C_format', self); |
---|
| 352 | if ~isempty(c) |
---|
| 353 | c = c(:); |
---|
| 354 | s = size(result) |
---|
| 355 | result = result.'; |
---|
| 356 | result = result(:); |
---|
| 357 | step = prod(s)/s(1); |
---|
| 358 | k = 1:step; |
---|
| 359 | for i = 1:s(1) |
---|
| 360 | fprintf(c, result(k)); |
---|
| 361 | fprintf('\n'); |
---|
| 362 | k = k + step; |
---|
| 363 | end |
---|
| 364 | else |
---|
| 365 | disp(result) |
---|
| 366 | end |
---|
| 367 | end |
---|