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    package edu.wisc.ssec.mcidasv.data;
029    
030    
031    import edu.wisc.ssec.mcidasv.data.hydra.NetCDFFile;
032    import visad.Data;
033    import visad.Unit;
034    import visad.Gridded3DSet;
035    import visad.Gridded1DDoubleSet;
036    import visad.Gridded1DSet;
037    import visad.Set;
038    import visad.UnionSet;
039    import visad.RealTupleType;
040    import visad.RealType;
041    import visad.FlatField;
042    import visad.FieldImpl;
043    import visad.Integer1DSet;
044    import visad.FunctionType;
045    import visad.CoordinateSystem;
046    import visad.VisADException;
047    import visad.DateTime;
048    import visad.data.units.Parser;
049    import visad.data.units.ParseException;
050    
051    import java.rmi.RemoteException;
052    import java.util.Hashtable;
053    import java.util.List;
054    
055    import ucar.unidata.util.Misc;
056    import ucar.unidata.util.Range;
057    
058    import ucar.unidata.data.DataUtil;
059    import ucar.unidata.data.DataChoice;
060    import ucar.unidata.data.DataDataChoice;
061    import ucar.unidata.data.DirectDataChoice;
062    import ucar.unidata.data.DataSelection;
063    import ucar.unidata.data.DataCategory;
064    import ucar.unidata.data.DataSourceImpl;
065    import ucar.unidata.data.DataSourceDescriptor;
066    
067    
068    
069    public class NearCastTrajDataSource extends DataSourceImpl {
070    
071        private static final String DATA_DESCRIPTION = "NearCastTrajectory";
072    
073        public static String parcelDimName = "parcel";
074        public static String timeDimName = "times";
075        public static String lonName = "lon";
076        public static String latName = "lat";
077    
078        NetCDFFile ncFile = null;
079        String pressName = "pres";
080        String timeName = "times";
081    
082    
083        int[] start = new int[2];
084        int[] count = new int[2];
085        int[] stride = new int[2];
086    
087    
088        int parcelDimIdx = 0;
089        int timeDimIdx = 1;
090    
091        String[] paramList = null;
092        
093        String fileName = null;
094    
095        CoordinateSystem presToHeightCS = null;
096    
097        Unit timeUnit;
098        Set timeSet;
099    
100        int numTimes;
101        int numParcels;
102    
103        Range lonRange = new Range();
104        Range latRange = new Range();
105        Range paramRange = new Range();
106    
107        public NearCastTrajDataSource() {
108        }
109    
110        public NearCastTrajDataSource(String filename) throws VisADException {
111          this(null, Misc.newList(filename), null);
112        }
113    
114        public NearCastTrajDataSource(DataSourceDescriptor descriptor,
115                                     String fileName, Hashtable properties) throws VisADException { 
116            this(descriptor, Misc.newList(fileName), properties);
117        }
118    
119        public NearCastTrajDataSource(DataSourceDescriptor descriptor,
120                                     List newSources, Hashtable properties) throws VisADException {
121    
122           super(descriptor, DATA_DESCRIPTION, DATA_DESCRIPTION, properties);
123    
124           presToHeightCS = DataUtil.getPressureToHeightCS(DataUtil.STD_ATMOSPHERE);
125    
126           fileName = (String) newSources.get(0);
127    
128           try {
129             ncFile = new NetCDFFile(fileName);
130           }
131           catch (Exception e) {
132             e.printStackTrace();
133           }
134             
135           paramList = new String[] {"temp", "q", "the", "tp", "MS", "MQ", "MTe", "TP"};
136    
137    
138           String unitStr = ncFile.getArrayUnitString(timeName);
139           try {
140             timeUnit = Parser.parse(unitStr);
141           } 
142           catch (ParseException e) {
143             System.out.println(e);
144           }
145    
146           numTimes = ncFile.getDimensionLength(timeDimName);
147           numParcels = ncFile.getDimensionLength(parcelDimName);
148    
149           try {
150             Class type = ncFile.getArrayType(timeName);
151             if (type == Double.TYPE) {
152                double[] timeValues = ncFile.getDoubleArray(timeName, new int[] {0}, new int[] {numTimes}, new int[] {1});
153                timeSet = new Gridded1DDoubleSet(
154                           RealType.Time, new double[][] {timeValues}, numTimes, null, new Unit[] {timeUnit}, null);
155             }
156             else if (type == Float.TYPE) {
157                float[] timeValues = ncFile.getFloatArray(timeName, new int[] {0}, new int[] {numTimes}, new int[] {1});
158                timeSet = new Gridded1DSet(RealType.Time, new float[][] {timeValues}, numTimes, null, new Unit[] {timeUnit}, null);
159    
160             }
161           } 
162           catch (Exception e) {
163             e.printStackTrace();
164           }
165        }
166    
167    
168        public FlatField[] createVisADData(String paramName) {
169          return null;
170        }
171    
172        public FlatField singleTraj(String paramName, int parcelIndex, int timeStart, int timeCount, int timeStride) throws Exception {
173    
174          start[parcelDimIdx] = parcelIndex;
175          start[timeDimIdx] = timeStart;
176    
177          count[parcelDimIdx] = 1;
178          count[timeDimIdx] = timeCount;
179    
180          stride[parcelDimIdx] = 1;
181          stride[timeDimIdx] = 1;
182    
183          float[] lons = ncFile.getFloatArray(lonName, start, count, stride);
184          float[] lats = ncFile.getFloatArray(latName, start, count, stride);
185    
186          float[] minmax = minmax(lons, (float)lonRange.getMin(), (float)lonRange.getMax());
187          lonRange.setMin(minmax[0]);
188          lonRange.setMax(minmax[1]);
189          minmax = minmax(lats, (float)latRange.getMin(), (float)latRange.getMax());
190          latRange.setMin(minmax[0]);
191          latRange.setMax(minmax[1]);
192    
193          float[] pres = ncFile.getFloatArray(pressName, start, count, stride);
194          float[] param = ncFile.getFloatArray(paramName, start, count, stride);
195          minmax = minmax(param, (float)paramRange.getMin(), (float)paramRange.getMax());
196          paramRange.setMin(minmax[0]);
197          paramRange.setMax(minmax[1]);
198    
199          float[] alt = (presToHeightCS.toReference(new float[][] {pres}))[0];
200     
201          float[][] trajCoords = new float[][] {lons, lats, alt};
202    
203          Gridded3DSet domain = new Gridded3DSet(RealTupleType.SpatialEarth3DTuple, trajCoords, trajCoords[0].length);
204    
205          FunctionType fncType = new FunctionType(RealTupleType.SpatialEarth3DTuple, RealType.getRealType(paramName));
206          FlatField traj = new FlatField(fncType, domain);
207          traj.setSamples(new float[][] {param}, false);
208     
209          return traj;
210        }
211    
212        /**
213         * Make and insert the <code>DataChoice</code>-s for this
214         * <code>DataSource</code>.
215         */
216        public void doMakeDataChoices() {
217            try {
218              for (int k=0; k<paramList.length; k++) {
219                DataChoice choice = doMakeDataChoice(k);
220                if (choice != null) {
221                  addDataChoice(choice);
222                }
223              }
224            }
225            catch(Exception e) {
226              e.printStackTrace();
227            }
228        }
229    
230        private DataChoice doMakeDataChoice(int idx) throws Exception {
231            String name = paramList[idx];
232            DirectDataChoice ddc = null;
233            if (ncFile.hasArray(name)) {
234               ddc = new DirectDataChoice(this, new Integer(idx), name, name, null, new Hashtable());
235            }
236            return ddc;
237        }
238    
239        protected Data getDataInner(DataChoice dataChoice, DataCategory category,
240                                    DataSelection dataSelection,
241                                    Hashtable requestProperties)
242                throws VisADException, RemoteException {
243    
244            String paramName = dataChoice.getName();
245    
246            FieldImpl trajField = new FieldImpl(
247                          new FunctionType(RealType.Generic, new FunctionType(RealTupleType.SpatialEarth3DTuple, RealType.getRealType(paramName))), new Integer1DSet(numParcels));
248    
249            FieldImpl trajTimeField = new FieldImpl(new FunctionType(RealType.Time, trajField.getType()), timeSet); 
250    
251            lonRange.setMin(Float.MAX_VALUE);
252            lonRange.setMax(-Float.MAX_VALUE);
253            latRange.setMin(Float.MAX_VALUE);
254            latRange.setMax(-Float.MAX_VALUE);
255            paramRange.setMin(Float.MAX_VALUE);
256            paramRange.setMax(-Float.MAX_VALUE);
257    
258            try {
259              for (int t=0; t<numTimes; t++) {
260                 trajField = new FieldImpl(
261                          new FunctionType(RealType.Generic, new FunctionType(RealTupleType.SpatialEarth3DTuple, RealType.getRealType(paramName))), new Integer1DSet(numParcels));
262                for (int k=0; k<numParcels/4; k++) {
263                   FlatField fld = singleTraj(paramName, k*4, 0, t+1, 1);
264                   trajField.setSample(k, fld);
265                }
266                trajTimeField.setSample(t, trajField);
267              }
268              return trajTimeField;
269            }
270            catch (Exception e) {
271              e.printStackTrace();
272              return null;
273            }
274        }
275    
276        public static float[] minmax(float[] values, float min, float max) {
277          for (int k = 0; k < values.length; k++) {
278            float val = values[k];
279            if ((val == val) && (val < Float.POSITIVE_INFINITY) && (val > Float.NEGATIVE_INFINITY)) {
280              if (val < min) min = val;
281              if (val > max) max = val;
282            }
283          }
284          return new float[] {min, max};
285        }
286    
287       public Range getLonRange() {
288         return lonRange;
289       }
290    
291       public Range getLatRange() {
292         return latRange;
293       }
294    
295       public Range getParamRange() {
296         return paramRange;
297       }
298    
299    }