001    /*
002     * $Id: NearCastTrajDataSource.java,v 1.4 2012/02/19 17:35:44 davep Exp $
003     *
004     * This file is part of McIDAS-V
005     *
006     * Copyright 2007-2012
007     * Space Science and Engineering Center (SSEC)
008     * University of Wisconsin - Madison
009     * 1225 W. Dayton Street, Madison, WI 53706, USA
010     * https://www.ssec.wisc.edu/mcidas
011     * 
012     * All Rights Reserved
013     * 
014     * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015     * some McIDAS-V source code is based on IDV and VisAD source code.  
016     * 
017     * McIDAS-V is free software; you can redistribute it and/or modify
018     * it under the terms of the GNU Lesser Public License as published by
019     * the Free Software Foundation; either version 3 of the License, or
020     * (at your option) any later version.
021     * 
022     * McIDAS-V is distributed in the hope that it will be useful,
023     * but WITHOUT ANY WARRANTY; without even the implied warranty of
024     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
025     * GNU Lesser Public License for more details.
026     * 
027     * You should have received a copy of the GNU Lesser Public License
028     * along with this program.  If not, see http://www.gnu.org/licenses.
029     */
030    package edu.wisc.ssec.mcidasv.data;
031    
032    
033    import edu.wisc.ssec.mcidasv.data.hydra.NetCDFFile;
034    import visad.Data;
035    import visad.Unit;
036    import visad.Gridded3DSet;
037    import visad.Gridded1DDoubleSet;
038    import visad.Gridded1DSet;
039    import visad.Set;
040    import visad.UnionSet;
041    import visad.RealTupleType;
042    import visad.RealType;
043    import visad.FlatField;
044    import visad.FieldImpl;
045    import visad.Integer1DSet;
046    import visad.FunctionType;
047    import visad.CoordinateSystem;
048    import visad.VisADException;
049    import visad.DateTime;
050    import visad.data.units.Parser;
051    import visad.data.units.ParseException;
052    
053    import java.rmi.RemoteException;
054    import java.util.Hashtable;
055    import java.util.List;
056    
057    import ucar.unidata.util.Misc;
058    import ucar.unidata.util.Range;
059    
060    import ucar.unidata.data.DataUtil;
061    import ucar.unidata.data.DataChoice;
062    import ucar.unidata.data.DataDataChoice;
063    import ucar.unidata.data.DirectDataChoice;
064    import ucar.unidata.data.DataSelection;
065    import ucar.unidata.data.DataCategory;
066    import ucar.unidata.data.DataSourceImpl;
067    import ucar.unidata.data.DataSourceDescriptor;
068    
069    
070    
071    public class NearCastTrajDataSource extends DataSourceImpl {
072    
073        private static final String DATA_DESCRIPTION = "NearCastTrajectory";
074    
075        public static String parcelDimName = "parcel";
076        public static String timeDimName = "times";
077        public static String lonName = "lon";
078        public static String latName = "lat";
079    
080        NetCDFFile ncFile = null;
081        String pressName = "pres";
082        String timeName = "times";
083    
084    
085        int[] start = new int[2];
086        int[] count = new int[2];
087        int[] stride = new int[2];
088    
089    
090        int parcelDimIdx = 0;
091        int timeDimIdx = 1;
092    
093        String[] paramList = null;
094        
095        String fileName = null;
096    
097        CoordinateSystem presToHeightCS = null;
098    
099        Unit timeUnit;
100        Set timeSet;
101    
102        int numTimes;
103        int numParcels;
104    
105        Range lonRange = new Range();
106        Range latRange = new Range();
107        Range paramRange = new Range();
108    
109        public NearCastTrajDataSource() {
110        }
111    
112        public NearCastTrajDataSource(String filename) throws VisADException {
113          this(null, Misc.newList(filename), null);
114        }
115    
116        public NearCastTrajDataSource(DataSourceDescriptor descriptor,
117                                     String fileName, Hashtable properties) throws VisADException { 
118            this(descriptor, Misc.newList(fileName), properties);
119        }
120    
121        public NearCastTrajDataSource(DataSourceDescriptor descriptor,
122                                     List newSources, Hashtable properties) throws VisADException {
123    
124           super(descriptor, DATA_DESCRIPTION, DATA_DESCRIPTION, properties);
125    
126           presToHeightCS = DataUtil.getPressureToHeightCS(DataUtil.STD_ATMOSPHERE);
127    
128           fileName = (String) newSources.get(0);
129    
130           try {
131             ncFile = new NetCDFFile(fileName);
132           }
133           catch (Exception e) {
134             e.printStackTrace();
135           }
136             
137           paramList = new String[] {"temp", "q", "the", "tp", "MS", "MQ", "MTe", "TP"};
138    
139    
140           String unitStr = ncFile.getArrayUnitString(timeName);
141           try {
142             timeUnit = Parser.parse(unitStr);
143           } 
144           catch (ParseException e) {
145             System.out.println(e);
146           }
147    
148           numTimes = ncFile.getDimensionLength(timeDimName);
149           numParcels = ncFile.getDimensionLength(parcelDimName);
150    
151           try {
152             Class type = ncFile.getArrayType(timeName);
153             if (type == Double.TYPE) {
154                double[] timeValues = ncFile.getDoubleArray(timeName, new int[] {0}, new int[] {numTimes}, new int[] {1});
155                timeSet = new Gridded1DDoubleSet(
156                           RealType.Time, new double[][] {timeValues}, numTimes, null, new Unit[] {timeUnit}, null);
157             }
158             else if (type == Float.TYPE) {
159                float[] timeValues = ncFile.getFloatArray(timeName, new int[] {0}, new int[] {numTimes}, new int[] {1});
160                timeSet = new Gridded1DSet(RealType.Time, new float[][] {timeValues}, numTimes, null, new Unit[] {timeUnit}, null);
161    
162             }
163           } 
164           catch (Exception e) {
165             e.printStackTrace();
166           }
167        }
168    
169    
170        public FlatField[] createVisADData(String paramName) {
171          return null;
172        }
173    
174        public FlatField singleTraj(String paramName, int parcelIndex, int timeStart, int timeCount, int timeStride) throws Exception {
175    
176          start[parcelDimIdx] = parcelIndex;
177          start[timeDimIdx] = timeStart;
178    
179          count[parcelDimIdx] = 1;
180          count[timeDimIdx] = timeCount;
181    
182          stride[parcelDimIdx] = 1;
183          stride[timeDimIdx] = 1;
184    
185          float[] lons = ncFile.getFloatArray(lonName, start, count, stride);
186          float[] lats = ncFile.getFloatArray(latName, start, count, stride);
187    
188          float[] minmax = minmax(lons, (float)lonRange.getMin(), (float)lonRange.getMax());
189          lonRange.setMin(minmax[0]);
190          lonRange.setMax(minmax[1]);
191          minmax = minmax(lats, (float)latRange.getMin(), (float)latRange.getMax());
192          latRange.setMin(minmax[0]);
193          latRange.setMax(minmax[1]);
194    
195          float[] pres = ncFile.getFloatArray(pressName, start, count, stride);
196          float[] param = ncFile.getFloatArray(paramName, start, count, stride);
197          minmax = minmax(param, (float)paramRange.getMin(), (float)paramRange.getMax());
198          paramRange.setMin(minmax[0]);
199          paramRange.setMax(minmax[1]);
200    
201          float[] alt = (presToHeightCS.toReference(new float[][] {pres}))[0];
202     
203          float[][] trajCoords = new float[][] {lons, lats, alt};
204    
205          Gridded3DSet domain = new Gridded3DSet(RealTupleType.SpatialEarth3DTuple, trajCoords, trajCoords[0].length);
206    
207          FunctionType fncType = new FunctionType(RealTupleType.SpatialEarth3DTuple, RealType.getRealType(paramName));
208          FlatField traj = new FlatField(fncType, domain);
209          traj.setSamples(new float[][] {param}, false);
210     
211          return traj;
212        }
213    
214        /**
215         * Make and insert the <code>DataChoice</code>-s for this
216         * <code>DataSource</code>.
217         */
218        public void doMakeDataChoices() {
219            try {
220              for (int k=0; k<paramList.length; k++) {
221                DataChoice choice = doMakeDataChoice(k);
222                if (choice != null) {
223                  addDataChoice(choice);
224                }
225              }
226            }
227            catch(Exception e) {
228              e.printStackTrace();
229            }
230        }
231    
232        private DataChoice doMakeDataChoice(int idx) throws Exception {
233            String name = paramList[idx];
234            DirectDataChoice ddc = null;
235            if (ncFile.hasArray(name)) {
236               ddc = new DirectDataChoice(this, new Integer(idx), name, name, null, new Hashtable());
237            }
238            return ddc;
239        }
240    
241        protected Data getDataInner(DataChoice dataChoice, DataCategory category,
242                                    DataSelection dataSelection,
243                                    Hashtable requestProperties)
244                throws VisADException, RemoteException {
245    
246            String paramName = dataChoice.getName();
247    
248            FieldImpl trajField = new FieldImpl(
249                          new FunctionType(RealType.Generic, new FunctionType(RealTupleType.SpatialEarth3DTuple, RealType.getRealType(paramName))), new Integer1DSet(numParcels));
250    
251            FieldImpl trajTimeField = new FieldImpl(new FunctionType(RealType.Time, trajField.getType()), timeSet); 
252    
253            lonRange.setMin(Float.MAX_VALUE);
254            lonRange.setMax(-Float.MAX_VALUE);
255            latRange.setMin(Float.MAX_VALUE);
256            latRange.setMax(-Float.MAX_VALUE);
257            paramRange.setMin(Float.MAX_VALUE);
258            paramRange.setMax(-Float.MAX_VALUE);
259    
260            try {
261              for (int t=0; t<numTimes; t++) {
262                 trajField = new FieldImpl(
263                          new FunctionType(RealType.Generic, new FunctionType(RealTupleType.SpatialEarth3DTuple, RealType.getRealType(paramName))), new Integer1DSet(numParcels));
264                for (int k=0; k<numParcels/4; k++) {
265                   FlatField fld = singleTraj(paramName, k*4, 0, t+1, 1);
266                   trajField.setSample(k, fld);
267                }
268                trajTimeField.setSample(t, trajField);
269              }
270              return trajTimeField;
271            }
272            catch (Exception e) {
273              e.printStackTrace();
274              return null;
275            }
276        }
277    
278        public static float[] minmax(float[] values, float min, float max) {
279          for (int k = 0; k < values.length; k++) {
280            float val = values[k];
281            if ((val == val) && (val < Float.POSITIVE_INFINITY) && (val > Float.NEGATIVE_INFINITY)) {
282              if (val < min) min = val;
283              if (val > max) max = val;
284            }
285          }
286          return new float[] {min, max};
287        }
288    
289       public Range getLonRange() {
290         return lonRange;
291       }
292    
293       public Range getLatRange() {
294         return latRange;
295       }
296    
297       public Range getParamRange() {
298         return paramRange;
299       }
300    
301    }