1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package au.csiro.netcdf.util;
21
22 import java.io.BufferedReader;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.util.ArrayList;
27 import java.util.List;
28
29 import ucar.ma2.Array;
30 import ucar.ma2.DataType;
31 import ucar.nc2.Attribute;
32 import ucar.nc2.Dimension;
33 import ucar.nc2.NetcdfFile;
34 import ucar.nc2.Variable;
35
36
37
38
39
40
41
42
43
44
45 public class NetCDFUtils
46 {
47
48 public static final int NOT_FOUND = -1;
49
50 public static final String NULL_VALUE = "null";
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public static int lookupIndex(NetcdfFile file, Dimension dimension, String value) throws IOException
66 {
67 int index;
68 Variable coordVar = file.findVariable(dimension.getName());
69 if (coordVar != null && coordVar.isCoordinateVariable())
70 {
71 Array cvData = coordVar.read();
72 if (coordVar.getDataType().isIntegral())
73 {
74 Long target = Long.valueOf(value);
75 index = NetCDFUtils.searchIntegralArray(cvData, target);
76 if (index < 0)
77 {
78 for (int i = 0; i < cvData.getSize(); i++)
79 {
80 if (target == cvData.getLong(i))
81 {
82 index = i;
83 break;
84 }
85 }
86 }
87 }
88 else if (coordVar.getDataType().isNumeric())
89 {
90 final double floatingPointTolerance = 0.00001d;
91 Double target = Double.valueOf(value);
92 index = NetCDFUtils.searchFloatingPointArray(cvData, target,
93 floatingPointTolerance);
94 if (index < 0)
95 {
96 for (int i = 0; i < cvData.getSize(); i++)
97 {
98 Double cellVal = cvData.getDouble(i);
99 if (Math.abs(target - cellVal) < floatingPointTolerance)
100 {
101 index = i;
102 break;
103 }
104 }
105 }
106 }
107 else if (coordVar.getDataType().isString())
108 {
109 Character target = Character.valueOf(value.charAt(0));
110 index = NetCDFUtils.searchCharArray(cvData, target);
111 if (index < 0)
112 {
113 for (int i = 0; i < cvData.getSize(); i++)
114 {
115 if (target == cvData.getChar(i))
116 {
117 index = i;
118 break;
119 }
120 }
121 }
122 }
123 else
124 {
125 throw new IllegalArgumentException("Unable to search dimension '" + dimension.getName()
126 + "' of type " + coordVar.getDataType().toString());
127 }
128 }
129 else
130 {
131 throw new IllegalArgumentException("No coordinate variable defined for dimension '"
132 + dimension.getName() + "'. Unable to process range of lookup(" + value + ")");
133 }
134 return index;
135 }
136
137
138
139
140
141
142
143
144
145 public static int searchIntegralArray(Array source, long value)
146 {
147 long low = 0;
148 long high = source.getSize() - 1;
149 int mid;
150
151 while( low <= high )
152 {
153 mid = (int) (( low + high ) / 2);
154
155 if (source.getLong(mid) < value)
156 {
157 low = mid + 1;
158 }
159 else if (source.getLong(mid) > value)
160 {
161 high = mid - 1;
162 }
163 else
164 {
165 return mid;
166 }
167 }
168
169 return NOT_FOUND;
170 }
171
172
173
174
175
176
177
178
179
180
181
182 public static int searchFloatingPointArray(Array source, double value, double tolerance)
183 {
184 long low = 0;
185 long high = source.getSize() - 1;
186 int mid;
187
188 while( low <= high )
189 {
190 mid = (int) (( low + high ) / 2);
191
192 if( value - source.getDouble(mid) > tolerance )
193 {
194 low = mid + 1;
195 }
196 else if( source.getDouble(mid) - value > tolerance )
197 {
198 high = mid - 1;
199 }
200 else
201 {
202 return mid;
203 }
204 }
205
206 return NOT_FOUND;
207 }
208
209
210
211
212
213
214
215
216
217
218 public static int searchCharArray(Array source, Character value)
219 {
220 long low = 0;
221 long high = source.getSize() - 1;
222 int mid;
223
224 while( low <= high )
225 {
226 mid = (int) (( low + high ) / 2);
227
228 Character midValue = (Character) source.getObject(mid);
229 if( value.compareTo(midValue) > 0 )
230 {
231 low = mid + 1;
232 }
233 else if( value.compareTo(midValue) < 0 )
234 {
235 high = mid - 1;
236 }
237 else
238 {
239 return mid;
240 }
241 }
242
243 return NOT_FOUND;
244 }
245
246
247
248
249
250
251
252
253
254
255 public static List<Attribute> mapStringToAttributeValueList(String commaSeparatedAttributeValueString)
256 throws IllegalArgumentException
257 {
258 return mapStringToAttributeValueList(commaSeparatedAttributeValueString, DataType.STRING);
259 }
260
261
262
263
264
265
266
267
268
269
270
271 public static List<Attribute> mapStringToAttributeValueList(String commaSeparatedAttributeValueString, DataType dataType)
272 throws IllegalArgumentException
273 {
274 List<Attribute> attributeValues = new ArrayList<Attribute>();
275
276 List<String> attributePairs = Util.tokeniseCommaSeparatedString(commaSeparatedAttributeValueString);
277 for (String attributePair : attributePairs)
278 {
279 String[] keyValuePair = Util.splitOnNonBackslashedCharacter(attributePair, "=");
280
281
282 if (keyValuePair.length == 2 && !keyValuePair[0].isEmpty() && !keyValuePair[1].isEmpty())
283 {
284 String key = keyValuePair[0].replaceAll("\\\\,", ",").replaceAll("\\\\=", "=");
285 key = key.trim();
286 String strVal = keyValuePair[1].replaceAll("\\\\,", ",").replaceAll("\\\\=", "=");
287 Attribute attrib;
288
289 if (NULL_VALUE.equals(strVal) || dataType == DataType.STRING || dataType == DataType.CHAR)
290 {
291 attrib = new Attribute(key, strVal);
292 }
293 else if (dataType == DataType.FLOAT)
294 {
295 Float value;
296 try
297 {
298 value = Float.parseFloat(strVal);
299 }
300 catch (NumberFormatException e)
301 {
302 throw new IllegalArgumentException("Invalid float value '" + strVal + "' for key "
303 + key + ".");
304 }
305 attrib = new Attribute(key, value);
306 }
307 else if (dataType == DataType.DOUBLE)
308 {
309 Double value;
310 try
311 {
312 value = Double.parseDouble(strVal);
313 }
314 catch (NumberFormatException e)
315 {
316 throw new IllegalArgumentException("Invalid double value '" + strVal + "' for key "
317 + key + ".");
318 }
319 attrib = new Attribute(key, value);
320 }
321 else if (dataType == DataType.INT)
322 {
323 Integer value;
324 try
325 {
326 value = Integer.parseInt(strVal);
327 }
328 catch (NumberFormatException e)
329 {
330 throw new IllegalArgumentException("Invalid integer value '" + strVal + "' for key "
331 + key + ".");
332 }
333 attrib = new Attribute(key, value);
334 }
335 else if (dataType == DataType.SHORT)
336 {
337 Short value;
338 try
339 {
340 value = Short.parseShort(strVal);
341 }
342 catch (NumberFormatException e)
343 {
344 throw new IllegalArgumentException("Invalid short value '" + strVal + "' for key "
345 + key + ".");
346 }
347 attrib = new Attribute(key, value);
348 }
349 else if (dataType == DataType.BYTE)
350 {
351 Byte value;
352 try
353 {
354 value = Byte.parseByte(strVal);
355 }
356 catch (NumberFormatException e)
357 {
358 throw new IllegalArgumentException("Invalid byte value '" + strVal + "' for key "
359 + key + ".");
360 }
361 attrib = new Attribute(key, value);
362 }
363 else
364 {
365 throw new IllegalArgumentException(
366 "Unexpected datatype of " + dataType + " supplied to mapStringToAttributeValueList.");
367 }
368 attributeValues.add(attrib);
369 }
370 else
371 {
372 throw new IllegalArgumentException(
373 "The following String could not be converted into a list of Attributes: "
374 + commaSeparatedAttributeValueString);
375 }
376 }
377
378 return attributeValues;
379 }
380
381
382
383
384
385
386
387
388
389 public static List<Attribute> readAttributesFromStream(InputStream input) throws IOException
390 {
391 List<Attribute> attributes = new ArrayList<Attribute>();
392
393 try
394 {
395
396 if (input != null)
397 {
398
399 BufferedReader dataIn = new BufferedReader(new InputStreamReader(input));
400
401
402 StringBuffer strBuf = new StringBuffer();
403 char cbuf[] = new char[2048];
404 @SuppressWarnings("unused")
405 int n;
406 while (dataIn.ready() && (n = dataIn.read(cbuf)) != -1)
407 {
408 strBuf.append(cbuf);
409 cbuf = new char[2048];
410 }
411
412
413
414 try
415 {
416 attributes = NetCDFUtils.mapStringToAttributeValueList(strBuf.toString().trim());
417 }
418 catch (IllegalArgumentException iae)
419 {
420 throw new IllegalArgumentException(
421 "input file or standard input does not contain a comma separated String of attribute-value pairs: "
422 + strBuf.toString().trim());
423 }
424 }
425 }
426 finally
427 {
428 if (input != null)
429 {
430 input.close();
431 }
432 }
433
434 return attributes;
435 }
436 }