001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2016
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 * 
010 * All Rights Reserved
011 * 
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.  
014 * 
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 * 
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023 * GNU Lesser Public License for more details.
024 * 
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program.  If not, see http://www.gnu.org/licenses.
027 */
028
029package edu.wisc.ssec.mcidasv.data.hydra;
030
031import ucar.nc2.*;
032import ucar.nc2.ncml.NcMLReader;
033import ucar.ma2.*;
034
035import java.util.HashMap;
036import java.util.List;
037import java.util.ArrayList;
038import java.util.Iterator;
039import java.net.URL;
040import java.io.InputStream;
041import java.io.ByteArrayInputStream;
042
043import org.jdom2.input.SAXBuilder;
044import org.jdom2.output.XMLOutputter;
045import org.jdom2.Document;
046import org.jdom2.Element;
047
048
049public class NetCDFFile implements MultiDimensionReader {
050
051   HashMap<String, Variable> varMap = new HashMap<String, Variable>();
052   HashMap<String, String[]> varDimNames = new HashMap<String, String[]>();
053   HashMap<String, int[]> varDimLengths = new HashMap<String, int[]>();
054   HashMap<String, Class> varDataType = new HashMap<String, Class>();
055   HashMap<String, String> varUnits = new HashMap<String, String>();
056
057   NetcdfFile ncfile = null;
058
059   public static NetCDFFile makeUnion(String filename, String other) throws Exception {
060     Object obj = new Object();
061     URL url = obj.getClass().getResource("/edu/wisc/ssec/mcidasv/data/hydra/resources/union.ncml");
062     SAXBuilder builder = new SAXBuilder(false);
063     Document doc = null;
064
065     try {
066       doc = builder.build(url);
067     } catch (Exception e) {
068       e.printStackTrace();
069     }
070     Element root = doc.getRootElement();
071
072     List list = root.getChildren();
073
074     list = ((Element)list.get(1)).getChildren();
075
076     org.jdom2.Attribute attr1 = (org.jdom2.Attribute) (((Element)list.get(0)).getAttributes()).get(0);
077     attr1.setValue(filename);
078
079     org.jdom2.Attribute attr2 = (org.jdom2.Attribute) (((Element)list.get(1)).getAttributes()).get(0);
080     attr2.setValue(other);
081
082     XMLOutputter xmlOut = new XMLOutputter();
083     String newStr = xmlOut.outputString(doc);
084     ByteArrayInputStream is = new ByteArrayInputStream(newStr.getBytes());
085     return new NetCDFFile(is);
086   }
087
088   public NetCDFFile(InputStream is) throws Exception {
089     ncfile = NcMLReader.readNcML(is, null);
090     init();
091   }
092
093   public NetCDFFile(String filename) throws Exception {
094     if (filename.endsWith(".ncml")) {
095       java.io.FileReader rdr = new java.io.FileReader(filename);
096       ncfile = NcMLReader.readNcML(rdr, null);
097     }
098     else {
099       ncfile = NetcdfFile.open(filename);
100     }
101     init();
102   }
103     
104   public NetCDFFile(String filename, org.jdom2.Element root) throws Exception {
105          ncfile = NcMLReader.readNcML(filename, root, null);
106          init();
107   }
108   
109   private void init() throws Exception {
110     Iterator varIter = ncfile.getVariables().iterator();
111     while(varIter.hasNext()) {
112       Variable var = (Variable) varIter.next();
113
114       if (var instanceof Structure) {
115         analyzeStructure((Structure) var);
116         continue;
117       }
118
119       int rank = var.getRank();
120       String varName = var.getFullName();
121       varMap.put(varName, var);
122       Iterator dimIter = var.getDimensions().iterator();
123       String[] dimNames = new String[rank];
124       int[] dimLengths = new int[rank];
125       int cnt = 0;
126       while(dimIter.hasNext()) {
127         Dimension dim = (Dimension) dimIter.next();
128         String dim_name = dim.getShortName();
129         if (dim_name == null) dim_name = "dim"+cnt;
130         dimNames[cnt] = dim_name;
131         dimLengths[cnt] = dim.getLength();
132         cnt++;
133       }
134       varDimNames.put(varName, dimNames);
135       varDimLengths.put(varName, dimLengths);
136       varDataType.put(varName, var.getDataType().getPrimitiveClassType());
137       
138       Attribute attr = var.findAttribute("units");
139       if (attr != null) {
140         String unitStr = attr.getStringValue();
141         varUnits.put(varName, unitStr);
142       }
143     }
144   }
145
146   void analyzeStructure(Structure var) throws Exception {
147           if ((var.getShape()).length == 0) {
148                   return;
149           }
150           String varName = var.getFullName();
151           String[] dimNames = new String[2];
152           int[] dimLengths = new int[2];
153           int cnt = 0;
154           dimLengths[0] = (var.getShape())[0];
155           dimNames[0] = "dim" + cnt;
156
157           cnt++;
158           StructureData sData = var.readStructure(0);
159           List memList = sData.getMembers();
160           dimLengths[1] = memList.size();
161           dimNames[1] = "dim" + cnt;
162
163           varDimNames.put(varName, dimNames);
164           varDimLengths.put(varName, dimLengths);
165           varMap.put(varName, var);
166
167           StructureMembers sMembers = sData.getStructureMembers();
168           Object obj = sData.getScalarObject(sMembers.getMember(0));
169           varDataType.put(varName, obj.getClass());
170   }
171
172   public Class getArrayType(String array_name) {
173           return varDataType.get(array_name);
174   }
175
176   public String[] getDimensionNames(String array_name) {
177     return varDimNames.get(array_name);
178   }
179
180   public int[] getDimensionLengths(String array_name) {
181     return varDimLengths.get(array_name);
182   }
183
184   public String getArrayUnitString(String array_name) {
185     return varUnits.get(array_name);
186   }
187
188   public int getDimensionLength(String dimName) {
189     Dimension dim = ncfile.findDimension(dimName);
190     if (dim != null) {
191       return dim.getLength();
192     }
193     else {
194       return -1;
195     }
196   }
197
198   public float[] getFloatArray(String array_name, int[] start, int[] count, int[] stride) throws Exception {
199     return (float[]) readArray(array_name, start, count, stride);
200   }
201
202   public int[] getIntArray(String array_name, int[] start, int[] count, int[] stride) throws Exception {
203     return (int[]) readArray(array_name, start, count, stride);
204   }
205
206   public double[] getDoubleArray(String array_name, int[] start, int[] count, int[] stride) throws Exception {
207     return (double[]) readArray(array_name, start, count, stride);
208   }
209
210   public short[] getShortArray(String array_name, int[] start, int[] count, int[] stride) throws Exception {
211     return (short[]) readArray(array_name, start, count, stride);
212   }
213
214   public byte[] getByteArray(String array_name, int[] start, int[] count, int[] stride) throws Exception {
215     return (byte[]) readArray(array_name, start, count, stride);
216   }
217
218   public Object getArray(String array_name, int[] start, int[] count, int[] stride) throws Exception {
219     return readArray(array_name, start, count, stride);
220   }
221
222   protected synchronized Object readArray(String array_name, int[] start, int[] count, int[] stride) throws Exception {
223     Variable var = varMap.get(array_name);
224     if (var instanceof Structure) {
225       Array array = Array.factory(getArrayType(array_name), count);
226       Index2D idx = new Index2D(count);
227       for (int i=0; i<count[0]; i++) {
228         StructureData sData = ((Structure)var).readStructure(start[0]+i);
229         StructureMembers sMembers = sData.getStructureMembers();
230         for (int j=0; j<count[1]; j++) {
231           Object obj = sData.getScalarObject(sMembers.getMember(start[1]+j));
232           idx.set(i,j);
233           array.setObject(idx, obj);
234         }
235       }
236       return array.copyTo1DJavaArray();
237     }
238     else {
239       ArrayList rangeList = new ArrayList();
240       for (int i=0;i<start.length;i++) {
241         Range rng = new Range(start[i], start[i]+(count[i]-1)*stride[i], stride[i]);
242         rangeList.add(i, rng);
243       }
244       Array array = var.read(rangeList);
245       return array.copyTo1DJavaArray();
246     }
247   }
248
249   public HDFArray getGlobalAttribute(String attr_name) throws Exception {
250     throw new Exception("NetCDFFile.getGlobalAttributes: Unimplemented");
251   }
252
253   public HDFArray getArrayAttribute(String array_name, String attr_name) throws Exception {
254     Object array = null;
255     DataType dataType = null;
256
257     Variable var = varMap.get(array_name);
258     if (var != null) {
259        Attribute attr = var.findAttribute(attr_name);
260        if (attr != null) {
261           Array attrVals = attr.getValues();
262           dataType = attr.getDataType();
263           array = attrVals.copyTo1DJavaArray();
264        }
265     }
266
267     if (array == null) {
268        return null;
269     }
270     
271     HDFArray harray = null;
272
273     if (dataType.getPrimitiveClassType() == Float.TYPE) {
274       harray = HDFArray.make((float[])array);
275     }
276     else if (dataType.getPrimitiveClassType() == Double.TYPE) {
277       harray = HDFArray.make((double[])array);
278     }
279     else if (dataType == DataType.STRING) {
280       harray = HDFArray.make((String[])array);
281     }
282     else if (dataType.getPrimitiveClassType() == Short.TYPE) {
283       harray = HDFArray.make((short[])array);
284     }
285     else if (dataType.getPrimitiveClassType() == Integer.TYPE) {
286       harray = HDFArray.make((int[])array);
287     }
288     return harray;
289   }
290
291   public void close() throws Exception {
292     ncfile.close();
293   }
294
295   public HashMap getVarMap() {
296     return varMap;
297   }
298
299   public boolean hasArray(String name) {
300           if (varMap.get(name) == null) {
301                   return false;
302           } else {
303                   return true;
304           }
305   }
306
307   public boolean hasDimension(String name) {
308     if (ncfile.findDimension(name) != null) {
309       return true;
310     }
311     else {
312       return false;
313     }
314   }
315
316   public NetcdfFile getNetCDFFile() {
317           return ncfile;
318   }
319   
320   public static void main(String[] args) throws Exception {
321     NetCDFFile ncfile = new NetCDFFile(args[0]);
322     ncfile.close();
323   }
324}