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