001    /*
002     * This file is part of McIDAS-V
003     *
004     * Copyright 2007-2013
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    
029    package edu.wisc.ssec.mcidasv.data.hydra;
030    
031    import ucar.nc2.*;
032    import ucar.nc2.ncml.NcMLReader;
033    import ucar.ma2.*;
034    
035    import java.util.HashMap;
036    import java.util.List;
037    import java.util.ArrayList;
038    import java.util.Iterator;
039    import java.net.URL;
040    import java.io.InputStream;
041    import java.io.ByteArrayInputStream;
042    
043    import org.jdom2.input.SAXBuilder;
044    import org.jdom2.output.XMLOutputter;
045    import org.jdom2.Document;
046    import org.jdom2.Element;
047    
048    
049    public 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    }