001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2024
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 ucar.ma2.DataType;
032import visad.FlatField;
033import visad.VisADException;
034import visad.RealType;
035import visad.SetType;
036import visad.FunctionType;
037import visad.Set;
038import java.rmi.RemoteException;
039import java.util.HashMap;
040import java.util.Iterator;
041import java.util.Map;
042
043public abstract class MultiDimensionAdapter {
044
045   MultiDimensionReader reader = null;
046   Map<String, Object> metadata = null;
047   String arrayName = null;
048   String[] array_dim_names = null;
049   int[] array_dim_lengths  = null;
050   int array_rank;
051//   Class arrayType;
052    DataType arrayType;
053
054   Map<String, String> dimNameMap = new HashMap<>();
055
056   RealType rangeType;
057
058   RangeProcessor rangeProcessor = null;
059
060   public MultiDimensionAdapter() {
061   }
062
063   public MultiDimensionAdapter(MultiDimensionReader reader, Map<String, Object> metadata) {
064     this.reader = reader;
065     this.metadata = metadata;
066     this.init();
067   }
068
069   public abstract Map<String, double[]> getDefaultSubset();
070
071   public abstract Set makeDomain(Map<String, double[]> subset) throws Exception;
072
073   private void init() {
074     this.arrayName = (String) metadata.get("array_name");
075
076     String[] suppliedDimNames = (String[]) metadata.get("array_dimension_names");
077     if (suppliedDimNames != null) {
078       array_dim_names = suppliedDimNames;
079     }
080     else {
081       array_dim_names = reader.getDimensionNames(arrayName);
082     }
083
084     array_dim_lengths = reader.getDimensionLengths(arrayName);
085     array_rank = array_dim_lengths.length;
086     arrayType = reader.getArrayType(arrayName);
087
088     for (int i=0; i<array_rank; i++) {
089       dimNameMap.put(array_dim_names[i], array_dim_names[i]);
090     }
091
092     Iterator<String> iter = metadata.keySet().iterator();
093     while (iter.hasNext()) {
094       String key = iter.next();
095       Object val = metadata.get(key);
096       if (!(val instanceof String)) continue;
097       String name = (String) val; 
098       for (int kk=0; kk<array_rank; kk++) {
099         if (array_dim_names[kk].equals(name)) {
100           dimNameMap.put(array_dim_names[kk], key);
101         }
102       }
103     }
104
105   }
106
107   public Subset getIndexes(Map<String, double[]> select) {
108     Subset subset = new Subset(array_rank);
109     int[] start = subset.getStart();
110     int[] count = subset.getCount();
111     int[] stride = subset.getStride();
112
113     Iterator<String> iter = select.keySet().iterator();
114     while (iter.hasNext()) {
115       String key = iter.next();
116       String name = (String) metadata.get(key);
117
118       if (name == null) name = key;
119
120       for (int kk=0; kk<array_rank; kk++) {
121         if (array_dim_names[kk].equals(name)) {
122           double[] coords = select.get(key);
123
124           if (array_dim_lengths[kk] == 1) {
125             start[kk] = 0;
126             count[kk] = 1;
127             stride[kk] = 1;
128           }
129           else {
130             start[kk] = (int) coords[0];
131             count[kk] = (int) ((coords[1] - coords[0])/coords[2] + 1f);
132             stride[kk] = (int) coords[2];
133           }
134
135         }
136       }
137     }
138     return subset;
139   }
140
141   public FlatField getData(Map<String, double[]> subset) throws Exception {
142     Set domainSet = makeDomain(subset);
143     return makeFlatField(domainSet, subset);
144   }
145
146   private FlatField makeFlatField(Set domainSet, float[][] range) throws VisADException, RemoteException {
147     FlatField f_field = makeFlatField(domainSet);
148     f_field.setSamples(range, false);
149     return f_field;
150   }
151
152   private FlatField makeFlatField(Set domainSet, double[][] range) throws VisADException, RemoteException {
153     FlatField f_field = makeFlatField(domainSet);
154     f_field.setSamples(range, false);
155     return f_field;
156   }
157
158   private FlatField makeFlatField(Set domainSet) throws VisADException, RemoteException {
159     FlatField f_field = new FlatField(new FunctionType(((SetType)domainSet.getType()).getDomain(), rangeType), domainSet);
160     return f_field;
161   }
162
163   public FlatField makeFlatField(Set domainSet, Map<String, double[]> subset) throws Exception {
164     FlatField f_field = null;
165
166     Object range = readArray(subset);
167
168     if (range instanceof float[]) {
169       float[] new_range = processRange((float[]) range, subset);
170       f_field = makeFlatField(domainSet, new float[][] {new_range});
171     }
172     else if (range instanceof double[]) {
173       double[] new_range = processRange((double[]) range, subset);
174       f_field = makeFlatField(domainSet, new double[][] {new_range});
175     }
176     else if (range instanceof short[]) {
177       float[] float_range = processRange((short[])range, subset);
178       f_field = makeFlatField(domainSet, new float[][] {float_range});
179     }
180     else if (range instanceof byte[]) {
181       float[] float_range = processRange((byte[])range, subset);
182       f_field = makeFlatField(domainSet, new float[][] {float_range});
183     }
184
185     return f_field;
186   }
187
188   public RangeProcessor getRangeProcessor() {
189     return rangeProcessor;
190   }
191
192   public void setRangeProcessor(RangeProcessor rangeProcessor) {
193     this.rangeProcessor = rangeProcessor;
194   }
195
196   public float[] processRange(short[] range, Map<String, double[]> subset) {
197     if (rangeProcessor == null) {
198       float[] f_range = new float[range.length];
199       for (int i=0; i<range.length;i++) f_range[i] = (float) range[i]; 
200       return f_range;
201     }
202     else { 
203       return rangeProcessor.processRange(range, subset);
204     }
205   }
206
207   public float[] processRange(byte[] range, Map<String, double[]> subset) {
208     if (rangeProcessor == null) {
209       float[] f_range = new float[range.length];
210       for (int i=0; i<range.length;i++) f_range[i] = (float) range[i];
211       return f_range;
212     }
213     else {
214       return rangeProcessor.processRange(range, subset);
215     }
216   }
217
218   public float[] processRange(float[] range, Map<String, double[]> subset) {
219     if (rangeProcessor == null) {
220       return range;
221     }
222     else {
223       return rangeProcessor.processRange(range, subset);
224     }
225   }
226
227   public double[] processRange(double[] range, Map<String, double[]> subset) {
228     if (rangeProcessor == null) {
229       return range;
230     }
231     else {
232       return rangeProcessor.processRange(range, subset);
233     }
234   }
235
236
237   public Object readArray(Map<String, double[]> subset) throws Exception {
238     Subset select = getIndexes(subset);
239     int[] start = select.getStart();
240     int[] count = select.getCount();
241     int[] stride = select.getStride();
242
243     return reader.getArray(arrayName, start, count, stride);
244   }
245
246   public MultiDimensionReader getReader() {
247     return reader;
248   }
249
250   public Map<String, Object> getMetadata() {
251     return metadata;
252   }
253
254   String getArrayName() {
255     return arrayName;
256   }
257
258   public RealType getRangeType() {
259     return rangeType;
260   }
261   
262   public Map<String, double[]> getSubsetFromLonLatRect(Map<String, double[]> subset, double minLat, double maxLat,
263                                      double minLon, double maxLon) {
264     return subset;
265   }
266
267   public Map<String, double[]> getSubsetFromLonLatRect(double minLat, double maxLat,
268                                          double minLon, double maxLon) {
269     return null;
270   }
271
272   public Map<String, double[]> getSubsetFromLonLatRect(double minLat, double maxLat,
273                                          double minLon, double maxLon,
274                                          int xStride, int yStride, int zStride) {
275     return null;
276   }
277
278}