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 |
---|