001    /**
002     * 
003     */
004    package org.wdssii.dualpol;
005    
006    import java.io.File;
007    import java.io.IOException;
008    import java.text.ParsePosition;
009    import java.text.SimpleDateFormat;
010    import java.util.Date;
011    import java.util.List;
012    
013    import org.apache.commons.logging.Log;
014    import org.apache.commons.logging.LogFactory;
015    import org.wdssii.core.DataEncoder;
016    import org.wdssii.core.DataType;
017    import org.wdssii.core.DataUnavailableException;
018    import org.wdssii.core.LatLonGrid;
019    import org.wdssii.core.Location;
020    
021    import ucar.ma2.Array;
022    import ucar.ma2.Index;
023    import ucar.nc2.NetcdfFile;
024    import ucar.nc2.Variable;
025    
026    /**
027     * Reads IDL-generated 3D grids
028     * 
029     * @author lakshman
030     * 
031     */
032    public class IDLNetcdfGridReader {
033            private static Log log = LogFactory.getLog(IDLNetcdfGridReader.class);
034    
035            public IDLNetcdfGridReader() {
036            }
037    
038            @SuppressWarnings("serial")
039            private static class FormatException extends DataUnavailableException {
040                    public FormatException(String msg) {
041                            super(msg);
042                    }
043            }
044    
045            @SuppressWarnings("unchecked")
046            /**
047             * @return an array of LatLonGrid where the first dimension is the gridType
048             *         (DZ, DR, etc.) and the second dimension is the height
049             */
050            public LatLonGrid[][] fromNetcdfFile(File path) {
051                    NetcdfFile ncfile = null;
052    
053                    try {
054                            Date time = getTimeFromFileName(path.getName());
055                            ncfile = NetcdfFile.open(path.getAbsolutePath());
056                            
057                            IDLGridProperties idl = new IDLGridProperties(
058                                            ncfile.findGlobalAttribute("radarlat"),
059                                            ncfile.findGlobalAttribute("radarlon"),
060                                            ncfile.findGlobalAttribute("ident"),
061                                            ncfile.findGlobalAttribute("xdelta"),
062                                            ncfile.findGlobalAttribute("ydelta"),
063                                            ncfile.findGlobalAttribute("zdelta"));
064    
065                            List<Variable> variables = ncfile.getVariables();
066                            int numVariables = variables.size();
067                            int numHt = -1;
068                            LatLonGrid[][] grids = new LatLonGrid[numVariables][];
069                            for (int i = 0; i < numVariables; ++i) {
070                                    String variableName = variables.get(i).getName();
071                                    float[][][] values = readData3D(ncfile, variableName);
072                                    numHt = values.length;
073                                    int numLat = values[0].length;
074                                    int numLon = values[0][0].length;
075                                    grids[i] = new LatLonGrid[numHt];
076                                    for (int ht = 0; ht < numHt; ++ht) {
077                                            Location nwCorner = new Location(idl.getRadarLat() + 0.5
078                                                            * numLat * idl.getDeltaLat(), idl.getRadarLon() - 0.5
079                                                            * numLon * idl.getDeltaLon(), idl.getRadarHtKms() + ht
080                                                            * idl.getDeltaHeightKms());
081                                            grids[i][ht] = new LatLonGrid(nwCorner, time, idl.getTypeName(variableName),
082                                                            idl.getDeltaLat(), idl.getDeltaLon(), values[ht]);
083                                    }
084                            }
085                            
086                            // Threshold based on RhoHV
087                            int rhohv = -1;
088                            for (int i=0; i < numVariables; ++i){
089                                    if ( numHt > 0 && grids[i][0].getTypeName().equals("RhoHV") ){
090                                            rhohv = i;
091                                    }
092                            }
093                            if (rhohv >= 0){
094                                    for (int ht=0; ht < numHt; ++ht){
095                                            for (int i=0; i < numVariables; ++i){
096                                                    if ( i != rhohv ){
097                                                            threshold( grids[i][ht], grids[rhohv][ht] , 0.5f );
098                                                    }
099                                            }
100                                    }
101                            }
102                            
103                            return grids;
104                    } catch (Exception e) {
105                            log.warn(e);
106                    } finally {
107                            try {
108                                    if (ncfile != null)
109                                            ncfile.close();
110                            } catch (Exception e) {
111                            }
112                    }
113                    return null;
114            }
115    
116            private void threshold(LatLonGrid grid, LatLonGrid rhohv, float thresh) {
117                    int numLat = grid.getNumLat();
118                    int numLon = grid.getNumLon();
119                    float[][] values = grid.getValues();
120                    float[][] corr = rhohv.getValues();
121                    int numRemoved = 0;
122                    for (int i=0; i < numLat; ++i){
123                            for (int j=0; j < numLon; ++j){
124                                    if ( corr[i][j] < thresh ){
125                                            values[i][j] = DataType.MissingData;
126                                            ++numRemoved;
127                                    }
128                            }
129                    }
130                    log.info("Thresholding based on RhoHV removed " + numRemoved + " pixels from " + 
131                                    grid.getTypeName() + " at ht=" + grid.getLocation().getHeightKms());
132            }
133    
134            private Variable getVariable(NetcdfFile ncfile, String name)
135                            throws FormatException {
136                    Variable data = ncfile.findVariable(name);
137                    if (data == null) {
138                            throw new FormatException("missing variable " + name);
139                    }
140                    return data;
141            }
142    
143    
144            private boolean isValid(float value){
145                    if ( Math.abs(value-999) < 0.001 || Math.abs(value+999) < 0.001 ){
146                            return false;
147                    }
148                    return true;
149            }
150            
151            private float[][][] readData3D(NetcdfFile ncfile, String typeName)
152                            throws IOException {
153                    Variable data = getVariable(ncfile, typeName);
154                    Array values = data.read();
155                    int numz = data.getDimension(0).getLength();
156                    int numy = data.getDimension(1).getLength();
157                    int numx = data.getDimension(2).getLength();
158    
159                    float[][][] result = new float[numz][numy][numx];
160                    Index index = values.getIndex();
161                    for (int z = 0; z < numz; ++z) {
162                            for (int y = 0; y < numy; ++y) {
163                                    for (int x = 0; x < numx; ++x) {
164                                            index.set(z, y, x);
165                                            float value = values.getFloat(index);
166                                            if ( !isValid(value) ) {
167                                                    value = DataType.MissingData;
168                                            }
169                                            result[z][numy-y-1][x] = value;
170                                    }
171                            }
172                    }
173                    return result;
174            }
175    
176            public static Date getTimeFromFileName(String path) {
177                    SimpleDateFormat sdf = new SimpleDateFormat(IDLGridProperties.getFileNameDateFormat());
178                    Date result = sdf.parse(path, new ParsePosition(5));
179                    if (result == null) {
180                            throw new FormatException(
181                                            "The name of the file: "
182                                                            + path
183                                                            + " has to be of the form KOUN_031505_172326_anything.nc.gz");
184                    } else {
185                            return result;
186                    }
187            }
188    
189            /**
190             * Simple program that reads IDL-generated files and writes out WDSS-II
191             * netcdf files
192             */
193            public static void main(String[] args) {
194                    if (args.length < 2) {
195                            System.out.println("Usage: java "
196                                            + IDLNetcdfGridReader.class.getCanonicalName()
197                                            + " icingInDir icingOutDir");
198                            return;
199                    }
200                    IDLNetcdfGridReader reader = new IDLNetcdfGridReader();
201                    String outputDir = args[1];
202                    new File(outputDir).mkdirs();
203                    File[] inFiles = new File(args[0]).listFiles();
204                    for (File file : inFiles) {
205                            if (file.getName().contains(".nc")
206                                            || file.getName().contains(".netcdf")) {
207                                    log.info("Reading " + file);
208                                    LatLonGrid[][] grids = reader.fromNetcdfFile(file);
209                                    for (LatLonGrid[] gridarray : grids) {
210                                            for (LatLonGrid grid : gridarray) {
211                                                    DataEncoder.writeDataAndNotify(grid, outputDir);
212                                            }
213                                    }
214                            } else {
215                                    System.out.println("Ignoring " + file
216                                                    + " since it does not have .nc in name");
217                            }
218                    }
219            }
220    }