001/*
002 * $Id: NearCastTrajDataSource.java,v 1.3 2011/03/24 16:06:32 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
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 */
030package edu.wisc.ssec.mcidasv.data;
031
032
033import edu.wisc.ssec.mcidasv.data.hydra.NetCDFFile;
034import visad.Data;
035import visad.Unit;
036import visad.Gridded3DSet;
037import visad.Gridded1DDoubleSet;
038import visad.Gridded1DSet;
039import visad.Set;
040import visad.UnionSet;
041import visad.RealTupleType;
042import visad.RealType;
043import visad.FlatField;
044import visad.FieldImpl;
045import visad.Integer1DSet;
046import visad.FunctionType;
047import visad.CoordinateSystem;
048import visad.VisADException;
049import visad.DateTime;
050import visad.data.units.Parser;
051import visad.data.units.ParseException;
052
053import java.rmi.RemoteException;
054import java.util.Hashtable;
055import java.util.List;
056
057import ucar.unidata.util.Misc;
058import ucar.unidata.util.Range;
059
060import ucar.unidata.data.DataUtil;
061import ucar.unidata.data.DataChoice;
062import ucar.unidata.data.DataDataChoice;
063import ucar.unidata.data.DirectDataChoice;
064import ucar.unidata.data.DataSelection;
065import ucar.unidata.data.DataCategory;
066import ucar.unidata.data.DataSourceImpl;
067import ucar.unidata.data.DataSourceDescriptor;
068
069
070
071public 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}