001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2025 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 https://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, DataType> varDataType = new HashMap<>(); 059 private final Map<String, String> varUnits = new HashMap<>(); 060 061 NetcdfFile ncfile = null; 062 063 public static NetCDFFile makeUnion(String filename, String other) throws Exception { 064 Object obj = new Object(); 065 URL url = obj.getClass().getResource("/edu/wisc/ssec/mcidasv/data/hydra/resources/union.ncml"); 066 SAXBuilder builder = new SAXBuilder(false); 067 Document doc = null; 068 069 try { 070 doc = builder.build(url); 071 } catch (Exception e) { 072 logger.error("Problem creating SAXBuilder", e); 073 } 074 Element root = doc.getRootElement(); 075 076 List list = root.getChildren(); 077 078 list = ((Element)list.get(1)).getChildren(); 079 080 org.jdom2.Attribute attr1 = (((Element)list.get(0)).getAttributes()).get(0); 081 attr1.setValue(filename); 082 083 org.jdom2.Attribute attr2 = (((Element)list.get(1)).getAttributes()).get(0); 084 attr2.setValue(other); 085 086 XMLOutputter xmlOut = new XMLOutputter(); 087 String newStr = xmlOut.outputString(doc); 088 logger.trace("union string:\n{}", newStr); 089 ByteArrayInputStream is = new ByteArrayInputStream(newStr.getBytes()); 090 return new NetCDFFile(is); 091 } 092 093 public NetCDFFile(InputStream is) throws Exception { 094 ncfile = NcMLReader.readNcML(is, null); 095 init(); 096 } 097 098 public NetCDFFile(String filename) throws Exception { 099 if (filename.endsWith(".ncml")) { 100 java.io.FileReader rdr = new java.io.FileReader(filename); 101 ncfile = NcMLReader.readNcML(rdr, null); 102 } 103 else { 104 ncfile = NetcdfFile.open(filename); 105 } 106 init(); 107 } 108 109 public NetCDFFile(String filename, org.jdom2.Element root) throws Exception { 110 ncfile = NcMLReader.readNcML(filename, root, null); 111 init(); 112 } 113 114 private void init() throws Exception { 115 Iterator varIter = ncfile.getVariables().iterator(); 116 while(varIter.hasNext()) { 117 Variable var = (Variable) varIter.next(); 118 119 if (var instanceof Structure) { 120 analyzeStructure((Structure) var); 121 continue; 122 } 123 124 int rank = var.getRank(); 125 String varName = var.getFullName(); 126 varMap.put(varName, var); 127 Iterator dimIter = var.getDimensions().iterator(); 128 String[] dimNames = new String[rank]; 129 int[] dimLengths = new int[rank]; 130 int cnt = 0; 131 while(dimIter.hasNext()) { 132 Dimension dim = (Dimension) dimIter.next(); 133 String dim_name = dim.getShortName(); 134 if (dim_name == null) dim_name = "dim"+cnt; 135 dimNames[cnt] = dim_name; 136 dimLengths[cnt] = dim.getLength(); 137 cnt++; 138 } 139 varDimNames.put(varName, dimNames); 140 varDimLengths.put(varName, dimLengths); 141// varDataType.put(varName, var.getDataType().getPrimitiveClassType()); 142 varDataType.put(varName, var.getDataType()); 143 144 Attribute attr = var.findAttribute("units"); 145 if (attr != null) { 146 String unitStr = attr.getStringValue(); 147 varUnits.put(varName, unitStr); 148 } 149 } 150 } 151 152 void analyzeStructure(Structure var) throws Exception { 153 if ((var.getShape()).length == 0) { 154 return; 155 } 156 String varName = var.getFullName(); 157 String[] dimNames = new String[2]; 158 int[] dimLengths = new int[2]; 159 int cnt = 0; 160 dimLengths[0] = (var.getShape())[0]; 161 dimNames[0] = "dim" + cnt; 162 163 cnt++; 164 StructureData sData = var.readStructure(0); 165 List memList = sData.getMembers(); 166 dimLengths[1] = memList.size(); 167 dimNames[1] = "dim" + cnt; 168 169 varDimNames.put(varName, dimNames); 170 varDimLengths.put(varName, dimLengths); 171 varMap.put(varName, var); 172 173 StructureMembers sMembers = sData.getStructureMembers(); 174 Object obj = sData.getScalarObject(sMembers.getMember(0)); 175 176// varDataType.put(varName, obj.getClass()); 177 varDataType.put(varName, var.getDataType()); 178 } 179 180// public Class getArrayType(String array_name) { 181// return varDataType.get(array_name); 182// } 183 public DataType getArrayType(String array_name) { 184 return varDataType.get(array_name); 185 } 186 187 public String[] getDimensionNames(String array_name) { 188 return varDimNames.get(array_name); 189 } 190 191 public int[] getDimensionLengths(String array_name) { 192 return varDimLengths.get(array_name); 193 } 194 195 public String getArrayUnitString(String array_name) { 196 return varUnits.get(array_name); 197 } 198 199 public int getDimensionLength(String dimName) { 200 Dimension dim = ncfile.findDimension(dimName); 201 return (dim != null) ? dim.getLength() : -1; 202 } 203 204 public float[] getFloatArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 205 Variable var = varMap.get(array_name); 206 if (var instanceof Structure) { 207 Array array = Array.factory(getArrayType(array_name), count); 208 Index2D idx = new Index2D(count); 209 for (int i=0; i<count[0]; i++) { 210 StructureData sData = ((Structure)var).readStructure(start[0]+i); 211 StructureMembers sMembers = sData.getStructureMembers(); 212 for (int j=0; j<count[1]; j++) { 213 Object obj = sData.getScalarObject(sMembers.getMember(start[1]+j)); 214 idx.set(i,j); 215 array.setObject(idx, obj); 216 } 217 } 218 return (float[]) array.get1DJavaArray(DataType.FLOAT); 219 } 220 else { 221 List<Range> rangeList = new ArrayList<>(start.length); 222 for (int i=0;i<start.length;i++) { 223 Range rng = new Range(start[i], start[i]+(count[i]-1)*stride[i], stride[i]); 224 rangeList.add(i, rng); 225 } 226 Array array = var.read(rangeList); 227 return (float[]) array.get1DJavaArray(DataType.FLOAT); 228 } 229 } 230 231 public int[] getIntArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 232 Variable var = varMap.get(array_name); 233 if (var instanceof Structure) { 234 Array array = Array.factory(getArrayType(array_name), count); 235 Index2D idx = new Index2D(count); 236 for (int i=0; i<count[0]; i++) { 237 StructureData sData = ((Structure)var).readStructure(start[0]+i); 238 StructureMembers sMembers = sData.getStructureMembers(); 239 for (int j=0; j<count[1]; j++) { 240 Object obj = sData.getScalarObject(sMembers.getMember(start[1]+j)); 241 idx.set(i,j); 242 array.setObject(idx, obj); 243 } 244 } 245 return (int[]) array.get1DJavaArray(DataType.INT); 246 } 247 else { 248 List<Range> rangeList = new ArrayList<>(start.length); 249 for (int i=0;i<start.length;i++) { 250 Range rng = new Range(start[i], start[i]+(count[i]-1)*stride[i], stride[i]); 251 rangeList.add(i, rng); 252 } 253 Array array = var.read(rangeList); 254 return (int[]) array.get1DJavaArray(DataType.INT); 255 } 256 } 257 258 public double[] getDoubleArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 259 Variable var = varMap.get(array_name); 260 if (var instanceof Structure) { 261 Array array = Array.factory(getArrayType(array_name), count); 262 Index2D idx = new Index2D(count); 263 for (int i=0; i<count[0]; i++) { 264 StructureData sData = ((Structure)var).readStructure(start[0]+i); 265 StructureMembers sMembers = sData.getStructureMembers(); 266 for (int j=0; j<count[1]; j++) { 267 Object obj = sData.getScalarObject(sMembers.getMember(start[1]+j)); 268 idx.set(i,j); 269 array.setObject(idx, obj); 270 } 271 } 272 return (double[]) array.get1DJavaArray(DataType.DOUBLE); 273 } 274 else { 275 List<Range> rangeList = new ArrayList<>(start.length); 276 for (int i=0;i<start.length;i++) { 277 Range rng = new Range(start[i], start[i]+(count[i]-1)*stride[i], stride[i]); 278 rangeList.add(i, rng); 279 } 280 Array array = var.read(rangeList); 281 return (double[]) array.get1DJavaArray(DataType.DOUBLE); 282 } 283 } 284 285 public short[] getShortArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 286 Variable var = varMap.get(array_name); 287 if (var instanceof Structure) { 288 Array array = Array.factory(getArrayType(array_name), count); 289 Index2D idx = new Index2D(count); 290 for (int i=0; i<count[0]; i++) { 291 StructureData sData = ((Structure)var).readStructure(start[0]+i); 292 StructureMembers sMembers = sData.getStructureMembers(); 293 for (int j=0; j<count[1]; j++) { 294 Object obj = sData.getScalarObject(sMembers.getMember(start[1]+j)); 295 idx.set(i,j); 296 array.setObject(idx, obj); 297 } 298 } 299 return (short[]) array.get1DJavaArray(DataType.SHORT); 300 } 301 else { 302 List<Range> rangeList = new ArrayList<>(start.length); 303 for (int i=0;i<start.length;i++) { 304 Range rng = new Range(start[i], start[i]+(count[i]-1)*stride[i], stride[i]); 305 rangeList.add(i, rng); 306 } 307 Array array = var.read(rangeList); 308 return (short[]) array.get1DJavaArray(DataType.SHORT); 309 } 310 } 311 312 public byte[] getByteArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 313 Variable var = varMap.get(array_name); 314 if (var instanceof Structure) { 315 Array array = Array.factory(getArrayType(array_name), count); 316 Index2D idx = new Index2D(count); 317 for (int i=0; i<count[0]; i++) { 318 StructureData sData = ((Structure)var).readStructure(start[0]+i); 319 StructureMembers sMembers = sData.getStructureMembers(); 320 for (int j=0; j<count[1]; j++) { 321 Object obj = sData.getScalarObject(sMembers.getMember(start[1]+j)); 322 idx.set(i,j); 323 array.setObject(idx, obj); 324 } 325 } 326 return (byte[]) array.get1DJavaArray(DataType.BYTE); 327 } 328 else { 329 List<Range> rangeList = new ArrayList<>(start.length); 330 for (int i=0;i<start.length;i++) { 331 Range rng = new Range(start[i], start[i]+(count[i]-1)*stride[i], stride[i]); 332 rangeList.add(i, rng); 333 } 334 Array array = var.read(rangeList); 335 return (byte[]) array.get1DJavaArray(DataType.BYTE); 336 } 337 } 338 339 public Object getArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 340 return readArray(array_name, start, count, stride); 341 } 342 343 protected synchronized Object readArray(String array_name, int[] start, int[] count, int[] stride) throws Exception { 344 Variable var = varMap.get(array_name); 345 if (var instanceof Structure) { 346 Array array = Array.factory(getArrayType(array_name), count); 347 Index2D idx = new Index2D(count); 348 for (int i=0; i<count[0]; i++) { 349 StructureData sData = ((Structure)var).readStructure(start[0]+i); 350 StructureMembers sMembers = sData.getStructureMembers(); 351 for (int j=0; j<count[1]; j++) { 352 Object obj = sData.getScalarObject(sMembers.getMember(start[1]+j)); 353 idx.set(i,j); 354 array.setObject(idx, obj); 355 } 356 } 357 return array.copyTo1DJavaArray(); 358 } 359 else { 360 List<Range> rangeList = new ArrayList<>(start.length); 361 for (int i=0;i<start.length;i++) { 362 Range rng = new Range(start[i], start[i]+(count[i]-1)*stride[i], stride[i]); 363 rangeList.add(i, rng); 364 } 365 Array array = var.read(rangeList); 366 return array.copyTo1DJavaArray(); 367 } 368 } 369 370 public HDFArray getGlobalAttribute(String attr_name) throws Exception { 371 throw new Exception("NetCDFFile.getGlobalAttributes: Unimplemented"); 372 } 373 374 public HDFArray getArrayAttribute(String array_name, String attr_name) throws Exception { 375 Object array = null; 376 DataType dataType = null; 377 378 Variable var = varMap.get(array_name); 379 if (var != null) { 380 Attribute attr = var.findAttribute(attr_name); 381 if (attr != null) { 382 Array attrVals = attr.getValues(); 383 dataType = attr.getDataType(); 384 array = attrVals.copyTo1DJavaArray(); 385 } 386 } 387 388 if (array == null) { 389 return null; 390 } 391 392 HDFArray harray = null; 393 394 if (dataType.getPrimitiveClassType() == Float.TYPE) { 395 harray = HDFArray.make((float[])array); 396 } 397 else if (dataType.getPrimitiveClassType() == Double.TYPE) { 398 harray = HDFArray.make((double[])array); 399 } 400 else if (dataType == DataType.STRING) { 401 harray = HDFArray.make((String[])array); 402 } 403 else if (dataType.getPrimitiveClassType() == Short.TYPE) { 404 harray = HDFArray.make((short[])array); 405 } 406 else if (dataType.getPrimitiveClassType() == Integer.TYPE) { 407 harray = HDFArray.make((int[])array); 408 } 409 return harray; 410 } 411 412 public void close() throws Exception { 413 ncfile.close(); 414 } 415 416 public Map<String, Variable> getVarMap() { 417 return varMap; 418 } 419 420 public boolean hasArray(String name) { 421 return varMap.get(name) != null; 422 } 423 424 public boolean hasDimension(String name) { 425 return ncfile.findDimension(name) != null; 426 } 427 428 public NetcdfFile getNetCDFFile() { 429 return ncfile; 430 } 431 432 public static void main(String[] args) throws Exception { 433 NetCDFFile ncfile = new NetCDFFile(args[0]); 434 ncfile.close(); 435 } 436}