001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2023 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 org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033import ucar.nc2.*; 034import ucar.nc2.ncml.NcMLReader; 035import ucar.ma2.*; 036 037import java.util.HashMap; 038import java.util.List; 039import java.util.ArrayList; 040import java.util.Iterator; 041import java.net.URL; 042import java.io.InputStream; 043import java.io.ByteArrayInputStream; 044import java.util.Map; 045 046import org.jdom2.input.SAXBuilder; 047import org.jdom2.output.XMLOutputter; 048import org.jdom2.Document; 049import org.jdom2.Element; 050 051 052public class NetCDFFile implements MultiDimensionReader { 053 private static final Logger logger = LoggerFactory.getLogger(NetCDFFile.class); 054 private final Map<String, Variable> varMap = new HashMap<>(); 055 private final Map<String, String[]> varDimNames = new HashMap<>(); 056 private final Map<String, int[]> varDimLengths = new HashMap<>(); 057 private final Map<String, Class> varDataType = new HashMap<>(); 058 private final Map<String, String> varUnits = new HashMap<>(); 059 060 NetcdfFile ncfile = null; 061 062 public static NetCDFFile makeUnion(String filename, String other) throws Exception { 063 Object obj = new Object(); 064 URL url = obj.getClass().getResource("/edu/wisc/ssec/mcidasv/data/hydra/resources/union.ncml"); 065 SAXBuilder builder = new SAXBuilder(false); 066 Document doc = null; 067 068 try { 069 doc = builder.build(url); 070 } catch (Exception e) { 071 logger.error("Problem creating SAXBuilder", e); 072 } 073 Element root = doc.getRootElement(); 074 075 List list = root.getChildren(); 076 077 list = ((Element)list.get(1)).getChildren(); 078 079 org.jdom2.Attribute attr1 = (((Element)list.get(0)).getAttributes()).get(0); 080 attr1.setValue(filename); 081 082 org.jdom2.Attribute attr2 = (((Element)list.get(1)).getAttributes()).get(0); 083 attr2.setValue(other); 084 085 XMLOutputter xmlOut = new XMLOutputter(); 086 String newStr = xmlOut.outputString(doc); 087 logger.trace("union string:\n{}", newStr); 088 ByteArrayInputStream is = new ByteArrayInputStream(newStr.getBytes()); 089 return new NetCDFFile(is); 090 } 091 092 public NetCDFFile(InputStream is) throws Exception { 093 ncfile = NcMLReader.readNcML(is, null); 094 init(); 095 } 096 097 public NetCDFFile(String filename) throws Exception { 098 if (filename.endsWith(".ncml")) { 099 java.io.FileReader rdr = new java.io.FileReader(filename); 100 ncfile = NcMLReader.readNcML(rdr, null); 101 } 102 else { 103 ncfile = NetcdfFile.open(filename); 104 } 105 init(); 106 } 107 108 public NetCDFFile(String filename, org.jdom2.Element root) throws Exception { 109 ncfile = NcMLReader.readNcML(filename, root, null); 110 init(); 111 } 112 113 private void init() throws Exception { 114 Iterator varIter = ncfile.getVariables().iterator(); 115 while(varIter.hasNext()) { 116 Variable var = (Variable) varIter.next(); 117 118 if (var instanceof Structure) { 119 analyzeStructure((Structure) var); 120 continue; 121 } 122 123 int rank = var.getRank(); 124 String varName = var.getFullName(); 125 varMap.put(varName, var); 126 Iterator dimIter = var.getDimensions().iterator(); 127 String[] dimNames = new String[rank]; 128 int[] dimLengths = new int[rank]; 129 int cnt = 0; 130 while(dimIter.hasNext()) { 131 Dimension dim = (Dimension) dimIter.next(); 132 String dim_name = dim.getShortName(); 133 if (dim_name == null) dim_name = "dim"+cnt; 134 dimNames[cnt] = dim_name; 135 dimLengths[cnt] = dim.getLength(); 136 cnt++; 137 } 138 varDimNames.put(varName, dimNames); 139 varDimLengths.put(varName, dimLengths); 140 varDataType.put(varName, var.getDataType().getPrimitiveClassType()); 141 142 Attribute attr = var.findAttribute("units"); 143 if (attr != null) { 144 String unitStr = attr.getStringValue(); 145 varUnits.put(varName, unitStr); 146 } 147 } 148 } 149 150 void analyzeStructure(Structure var) throws Exception { 151 if ((var.getShape()).length == 0) { 152 return; 153 } 154 String varName = var.getFullName(); 155 String[] dimNames = new String[2]; 156 int[] dimLengths = new int[2]; 157 int cnt = 0; 158 dimLengths[0] = (var.getShape())[0]; 159 dimNames[0] = "dim" + cnt; 160 161 cnt++; 162 StructureData sData = var.readStructure(0); 163 List memList = sData.getMembers(); 164 dimLengths[1] = memList.size(); 165 dimNames[1] = "dim" + cnt; 166 167 varDimNames.put(varName, dimNames); 168 varDimLengths.put(varName, dimLengths); 169 varMap.put(varName, var); 170 171 StructureMembers sMembers = sData.getStructureMembers(); 172 Object obj = sData.getScalarObject(sMembers.getMember(0)); 173 varDataType.put(varName, obj.getClass()); 174 } 175 176 public Class getArrayType(String array_name) { 177 return varDataType.get(array_name); 178 } 179 180 public String[] getDimensionNames(String array_name) { 181 return varDimNames.get(array_name); 182 } 183 184 public int[] getDimensionLengths(String array_name) { 185 return varDimLengths.get(array_name); 186 } 187 188 public String getArrayUnitString(String array_name) { 189 return varUnits.get(array_name); 190 } 191 192 public int getDimensionLength(String dimName) { 193 Dimension dim = ncfile.findDimension(dimName); 194 return (dim != null) ? dim.getLength() : -1; 195 } 196 197 public float[] getFloatArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 198 return (float[]) readArray(array_name, start, count, stride); 199 } 200 201 public int[] getIntArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 202 return (int[]) readArray(array_name, start, count, stride); 203 } 204 205 public double[] getDoubleArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 206 return (double[]) readArray(array_name, start, count, stride); 207 } 208 209 public short[] getShortArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 210 return (short[]) readArray(array_name, start, count, stride); 211 } 212 213 public byte[] getByteArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 214 return (byte[]) readArray(array_name, start, count, stride); 215 } 216 217 public Object getArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 218 return readArray(array_name, start, count, stride); 219 } 220 221 protected synchronized Object readArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 222 Variable var = varMap.get(array_name); 223 if (var instanceof Structure) { 224 Array array = Array.factory(getArrayType(array_name), count); 225 Index2D idx = new Index2D(count); 226 for (int i=0; i<count[0]; i++) { 227 StructureData sData = ((Structure)var).readStructure(start[0]+i); 228 StructureMembers sMembers = sData.getStructureMembers(); 229 for (int j=0; j<count[1]; j++) { 230 Object obj = sData.getScalarObject(sMembers.getMember(start[1]+j)); 231 idx.set(i,j); 232 array.setObject(idx, obj); 233 } 234 } 235 return array.copyTo1DJavaArray(); 236 } 237 else { 238 List<Range> rangeList = new ArrayList<>(start.length); 239 for (int i=0;i<start.length;i++) { 240 Range rng = new Range(start[i], start[i]+(count[i]-1)*stride[i], stride[i]); 241 rangeList.add(i, rng); 242 } 243 Array array = var.read(rangeList); 244 return array.copyTo1DJavaArray(); 245 } 246 } 247 248 public HDFArray getGlobalAttribute(String attr_name) throws Exception { 249 throw new Exception("NetCDFFile.getGlobalAttributes: Unimplemented"); 250 } 251 252 public HDFArray getArrayAttribute(String array_name, String attr_name) throws Exception { 253 Object array = null; 254 DataType dataType = null; 255 256 Variable var = varMap.get(array_name); 257 if (var != null) { 258 Attribute attr = var.findAttribute(attr_name); 259 if (attr != null) { 260 Array attrVals = attr.getValues(); 261 dataType = attr.getDataType(); 262 array = attrVals.copyTo1DJavaArray(); 263 } 264 } 265 266 if (array == null) { 267 return null; 268 } 269 270 HDFArray harray = null; 271 272 if (dataType.getPrimitiveClassType() == Float.TYPE) { 273 harray = HDFArray.make((float[])array); 274 } 275 else if (dataType.getPrimitiveClassType() == Double.TYPE) { 276 harray = HDFArray.make((double[])array); 277 } 278 else if (dataType == DataType.STRING) { 279 harray = HDFArray.make((String[])array); 280 } 281 else if (dataType.getPrimitiveClassType() == Short.TYPE) { 282 harray = HDFArray.make((short[])array); 283 } 284 else if (dataType.getPrimitiveClassType() == Integer.TYPE) { 285 harray = HDFArray.make((int[])array); 286 } 287 return harray; 288 } 289 290 public void close() throws Exception { 291 ncfile.close(); 292 } 293 294 public Map<String, Variable> getVarMap() { 295 return varMap; 296 } 297 298 public boolean hasArray(String name) { 299 return varMap.get(name) != null; 300 } 301 302 public boolean hasDimension(String name) { 303 return ncfile.findDimension(name) != null; 304 } 305 306 public NetcdfFile getNetCDFFile() { 307 return ncfile; 308 } 309 310 public static void main(String[] args) throws Exception { 311 NetCDFFile ncfile = new NetCDFFile(args[0]); 312 ncfile.close(); 313 } 314}