Changeset 954


Ignore:
Timestamp:
02/01/12 12:36:42 (4 months ago)
Author:
guygriffiths
Message:

Merged changes from Kyle Wilcox

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/java/uk/ac/rdg/resc/edal/cdm/CdmUtils.java

    r943 r954  
    11/* 
    2  * Copyright (c) 2010 The University of Reading 
    3  * All rights reserved. 
    4  * 
    5  * Redistribution and use in source and binary forms, with or without 
    6  * modification, are permitted provided that the following conditions 
    7  * are met: 
    8  * 1. Redistributions of source code must retain the above copyright 
    9  *    notice, this list of conditions and the following disclaimer. 
    10  * 2. Redistributions in binary form must reproduce the above copyright 
    11  *    notice, this list of conditions and the following disclaimer in the 
    12  *    documentation and/or other materials provided with the distribution. 
    13  * 3. Neither the name of the University of Reading, nor the names of the 
    14  *    authors or contributors may be used to endorse or promote products 
    15  *    derived from this software without specific prior written permission. 
    16  * 
    17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
    18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
    19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
    20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
    21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
    22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
    23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
    24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
    26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
    27  */ 
     2* Copyright (c) 2010 The University of Reading 
     3* All rights reserved. 
     4* 
     5* Redistribution and use in source and binary forms, with or without 
     6* modification, are permitted provided that the following conditions 
     7* are met: 
     8* 1. Redistributions of source code must retain the above copyright 
     9* notice, this list of conditions and the following disclaimer. 
     10* 2. Redistributions in binary form must reproduce the above copyright 
     11* notice, this list of conditions and the following disclaimer in the 
     12* documentation and/or other materials provided with the distribution. 
     13* 3. Neither the name of the University of Reading, nor the names of the 
     14* authors or contributors may be used to endorse or promote products 
     15* derived from this software without specific prior written permission. 
     16* 
     17* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
     18* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
     19* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
     20* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
     21* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
     22* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
     23* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
     24* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
     25* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
     26* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     27*/ 
    2828 
    2929package uk.ac.rdg.resc.edal.cdm; 
     
    3636import java.util.Collections; 
    3737import java.util.Date; 
     38import java.util.Formatter; 
    3839import java.util.List; 
    3940import java.util.Map; 
     
    6364import ucar.nc2.dt.GridDataset.Gridset; 
    6465import ucar.nc2.dt.GridDatatype; 
    65 import ucar.nc2.dt.TypedDatasetFactory; 
     66import ucar.nc2.ft.FeatureDatasetFactoryManager; 
    6667import ucar.unidata.geoloc.LatLonPoint; 
    6768import ucar.unidata.geoloc.LatLonRect; 
     
    6970import uk.ac.rdg.resc.edal.coverage.domain.Domain; 
    7071import uk.ac.rdg.resc.edal.coverage.grid.HorizontalGrid; 
     72import uk.ac.rdg.resc.edal.coverage.grid.RectilinearGrid; 
    7173import uk.ac.rdg.resc.edal.coverage.grid.ReferenceableAxis; 
    7274import uk.ac.rdg.resc.edal.coverage.grid.RegularAxis; 
     75import uk.ac.rdg.resc.edal.coverage.grid.RegularGrid; 
    7376import uk.ac.rdg.resc.edal.coverage.grid.impl.RectilinearGridImpl; 
    7477import uk.ac.rdg.resc.edal.coverage.grid.impl.ReferenceableAxisImpl; 
     
    289292    public static GridDataset getGridDataset(NetcdfDataset nc) throws IOException 
    290293    { 
    291         return (GridDataset)TypedDatasetFactory.open(FeatureType.GRID, 
    292             nc, null, null); 
     294        return (GridDataset)FeatureDatasetFactoryManager.open(FeatureType.GRID, nc.getLocation(), null, new Formatter()); 
    293295    } 
    294296 
    295297    /** 
    296298     * Estimates the optimum {@link DataReadingStrategy} from the given 
    297      * NetcdfDataset.  Essentially, if the amount of data to be read is very 
    298      * large, {@link DataReadingStrategy#SCANLINE} will be returned.  Otherwise, 
     299     * NetcdfDataset. Essentially, if the amount of data to be read is very 
     300     * large, {@link DataReadingStrategy#SCANLINE} will be returned. Otherwise, 
    299301     * if the data are remote remote (e.g. OPeNDAP) or 
    300302     * compressed, this will return {@link DataReadingStrategy#BOUNDING_BOX}, 
    301      * which makes a single i/o call, minimizing the overhead.  If the data 
     303     * which makes a single i/o call, minimizing the overhead. If the data 
    302304     * are local and uncompressed this will return {@link DataReadingStrategy#SCANLINE}, 
    303305     * which reduces the amount of data read. 
     
    313315            return DataReadingStrategy.SCANLINE; 
    314316        } 
     317        return getOptimumDataReadingStrategy(nc); 
     318    } 
     319     
     320    public static DataReadingStrategy getOptimumDataReadingStrategy(NetcdfDataset nc) 
     321    { 
    315322        String fileType = nc.getFileTypeId(); 
    316323        return "netCDF".equals(fileType) || "HDF4".equals(fileType) 
     
    321328    /** 
    322329     * Converts the given LatLonRect to a GeographicBoundingBox. 
    323      * @todo Should probably be an Extent or a BoundingBox (I think Extent 
    324      * is more accurate - see the GeoAPI spec document.  Extents do not cross 
    325      * the anti-meridian).  Also do we need to return a more precise CRS? 
    326      * GeographicBoundingBox is deliberately approximate so doesn't use a CRS. 
     330     *  
     331     * @todo Should probably be an Extent or a BoundingBox (I think Extent is 
     332     *       more accurate - see the GeoAPI spec document. Extents do not cross 
     333     *       the anti-meridian). Also do we need to return a more precise CRS? 
     334     *       GeographicBoundingBox is deliberately approximate so doesn't use a 
     335     *       CRS. 
    327336     */ 
    328337    public static GeographicBoundingBox getBbox(LatLonRect latLonRect) 
     
    357366 
    358367    /** 
    359      * Gets List of DateTimes representing the timesteps of the given coordinate system, 
    360      * in an appropriate {@link Chronology}. (Chronologies represent the 
     368     * Gets List of DateTimes representing the timesteps of the given coordinate 
     369     * system, in an appropriate {@link Chronology}. (Chronologies represent the 
    361370     * calendar system.) 
    362      * @param coordSys The coordinate system containing the time information 
     371     *  
     372     * @param coordSys 
     373     *            The coordinate system containing the time information 
    363374     * @return List of TimestepInfo objects, or an empty list if the coordinate 
    364      * system has no time axis 
    365      * @throws IllegalArgumentException if the calendar system of the time axis 
    366      * cannot be handled. 
     375     *         system has no time axis 
     376     * @throws IllegalArgumentException 
     377     *             if the calendar system of the time axis cannot be handled. 
    367378     */ 
    368379    public static List<DateTime> getTimesteps(CoordinateAxis1DTime timeAxis) 
     
    394405 
    395406    /** 
    396      * Creates a list of DateTimes in a non-standard calendar system.  All of the 
     407     * Creates a list of DateTimes in a non-standard calendar system. All of the 
    397408     * DateTimes will have a zero time zone offset (i.e. UTC). 
    398409     */ 
     
    424435    /** 
    425436     * Reads a set of points at a given time and elevation from the given 
    426      * GridDatatype.  This method will internally create a {@link HorizontalGrid} 
    427      * object with each invocation; if you expect to call this method multiple times, 
    428      * greater efficiency may be gained by creating the HorizontalGrid once and 
    429      * calling {@link #readHorizontalPoints(ucar.nc2.dataset.NetcdfDataset, 
    430      * java.lang.String, uk.ac.rdg.resc.edal.coverage.grid.HorizontalGrid, int, 
    431      * int, uk.ac.rdg.resc.edal.coverage.domain.Domain)}. 
    432      * @param nc The (already-opened) NetcdfDataset from which we'll read data 
    433      * @param varId The ID of the variable from which we will read data 
    434      * @param tIndex The time index, ignored if the grid has no time axis 
    435      * @param zIndex The elevation index, ignored if the grid has no elevation axis 
    436      * @param targetDomain The list of horizontal points for which we need data 
     437     * GridDatatype. This method will internally create a {@link HorizontalGrid} 
     438     * object with each invocation; if you expect to call this method multiple 
     439     * times, greater efficiency may be gained by creating the HorizontalGrid 
     440     * once and calling 
     441     * {@link #readHorizontalPoints(ucar.nc2.dataset.NetcdfDataset, java.lang.String, uk.ac.rdg.resc.edal.coverage.grid.HorizontalGrid, int, int, uk.ac.rdg.resc.edal.coverage.domain.Domain)} 
     442     * . 
     443     *  
     444     * @param nc 
     445     *            The (already-opened) NetcdfDataset from which we'll read data 
     446     * @param varId 
     447     *            The ID of the variable from which we will read data 
     448     * @param tIndex 
     449     *            The time index, ignored if the grid has no time axis 
     450     * @param zIndex 
     451     *            The elevation index, ignored if the grid has no elevation axis 
     452     * @param targetDomain 
     453     *            The list of horizontal points for which we need data 
    437454     * @return a List of floating point numbers, one for each point in the 
    438      * {@code targetDomain}, in the same order.  Missing values (e.g. land pixels 
    439      * in oceanography data} are represented as nulls. 
    440      * @throws IllegalArgumentException if there is no variable in the dataset 
    441      * with the id {@code varId}. 
    442      * @throws IOException if there was an error reading data from the data source 
     455     *         {@code targetDomain}, in the same order. Missing values (e.g. 
     456     *         land pixels in oceanography data} are represented as nulls. 
     457     * @throws IllegalArgumentException 
     458     *             if there is no variable in the dataset with the id 
     459     *             {@code varId}. 
     460     * @throws IOException 
     461     *             if there was an error reading data from the data source 
    443462     */ 
    444463    public static List<Float> readHorizontalPoints(NetcdfDataset nc, String varId, 
     
    455474     * Reads a set of points at a given time from the given GridDatatype at a 
    456475     * number of elevations. 
    457      * @param nc The (already-opened) NetcdfDataset from which we'll read data 
    458      * @param varId The ID of the variable from which we will read data 
    459      * @param sourceGrid object that maps between real-world and grid coordinates 
    460      * in the source data grid 
    461      * @param tIndex The time index, ignored if the grid has no time axis 
    462      * @param zIndices The elevation indices, ignored if the grid has no elevation axis 
    463      * @param targetDomain The list of horizontal points for which we need data 
     476     *  
     477     * @param nc 
     478     *            The (already-opened) NetcdfDataset from which we'll read data 
     479     * @param varId 
     480     *            The ID of the variable from which we will read data 
     481     * @param sourceGrid 
     482     *            object that maps between real-world and grid coordinates in 
     483     *            the source data grid 
     484     * @param tIndex 
     485     *            The time index, ignored if the grid has no time axis 
     486     * @param zIndices 
     487     *            The elevation indices, ignored if the grid has no elevation 
     488     *            axis 
     489     * @param targetDomain 
     490     *            The list of horizontal points for which we need data 
    464491     * @return a List of floating point numbers for each elevation; each list 
    465      * contains a value for each point in the {@code targetDomain}, in the same 
    466      * order.  Missing values (e.g. land pixels in oceanography data} are 
    467      * represented as nulls. 
    468      * @throws IllegalArgumentException if there is no variable in the dataset 
    469      * with the id {@code varId}. 
    470      * @throws IOException if there was an error reading data from the data source 
     492     *         contains a value for each point in the {@code targetDomain}, in 
     493     *         the same order. Missing values (e.g. land pixels in oceanography 
     494     *         data} are represented as nulls. 
     495     * @throws IllegalArgumentException 
     496     *             if there is no variable in the dataset with the id 
     497     *             {@code varId}. 
     498     * @throws IOException 
     499     *             if there was an error reading data from the data source 
    471500     */ 
    472501    public static List<List<Float>> readVerticalSection(NetcdfDataset nc, String varId, 
     
    479508        // We create the pixelMap only once 
    480509        PixelMap pixelMap = new PixelMap(sourceGrid, targetDomain); 
    481  
     510        DataReadingStrategy strategy = getOptimumDataReadingStrategy(pixelMap, nc); 
     511         
     512        return readVerticalSection(nc, grid, tIndex, zIndices, pixelMap, strategy, (int)targetDomain.size()); 
     513    } 
     514     
     515    public static List<List<Float>> readVerticalSection(NetcdfDataset nc, GridDatatype grid, 
     516            int tIndex, List<Integer> zIndices, PixelMap pixelMap, DataReadingStrategy strategy, 
     517            int targetDomainSize) 
     518            throws IOException 
     519    { 
    482520        // Defend against null values 
    483521        if (zIndices == null) zIndices = Arrays.asList(-1); 
     
    486524            // It's very unlikely that the target domain will be bigger than 
    487525            // Integer.MAX_VALUE 
    488             data.add(readHorizontalPoints(nc, grid, tIndex, zIndex, pixelMap, (int)targetDomain.size())); 
     526            data.add(readHorizontalPoints(nc, grid, tIndex, zIndex, pixelMap, strategy, targetDomainSize)); 
    489527        } 
    490528        return data; 
    491529    } 
    492530     
     531     
    493532    /** 
    494533     * Reads a set of points at a given time and elevation from the given 
    495      * GridDatatype.  Use this method if you already have a {@link HorizontalGrid} 
    496      * object created for the variable in question, otherwise use 
    497      * {@link #readHorizontalPoints(ucar.nc2.dataset.NetcdfDataset, java.lang.String, 
    498      * int, int, uk.ac.rdg.resc.edal.coverage.domain.Domain)}. 
    499      * @param nc The (already-opened) NetcdfDataset from which we'll read data 
    500      * @param varId The ID of the variable from which we will read data 
    501      * @param sourceGrid object that maps between real-world and grid coordinates 
    502      * in the source data grid 
    503      * @param tIndex The time index, ignored if the grid has no time axis 
    504      * @param zIndex The elevation index, ignored if the grid has no elevation axis 
    505      * @param targetDomain The list of horizontal points for which we need data 
     534     * GridDatatype. Use this method if you already have a 
     535     * {@link HorizontalGrid} object created for the variable in question, 
     536     * otherwise use 
     537     * {@link #readHorizontalPoints(ucar.nc2.dataset.NetcdfDataset, java.lang.String, int, int, uk.ac.rdg.resc.edal.coverage.domain.Domain)} 
     538     * . 
     539     *  
     540     * @param nc 
     541     *            The (already-opened) NetcdfDataset from which we'll read data 
     542     * @param varId 
     543     *            The ID of the variable from which we will read data 
     544     * @param sourceGrid 
     545     *            object that maps between real-world and grid coordinates in 
     546     *            the source data grid 
     547     * @param tIndex 
     548     *            The time index, ignored if the grid has no time axis 
     549     * @param zIndex 
     550     *            The elevation index, ignored if the grid has no elevation axis 
     551     * @param targetDomain 
     552     *            The list of horizontal points for which we need data 
    506553     * @return a List of floating point numbers, one for each point in the 
    507      * {@code targetDomain}, in the same order.  Missing values (e.g. land pixels 
    508      * in oceanography data} are represented as nulls. 
    509      * @throws IllegalArgumentException if there is no variable in the dataset 
    510      * with the id {@code varId}. 
    511      * @throws IOException if there was an error reading data from the data source 
     554     *         {@code targetDomain}, in the same order. Missing values (e.g. 
     555     *         land pixels in oceanography data} are represented as nulls. 
     556     * @throws IllegalArgumentException 
     557     *             if there is no variable in the dataset with the id 
     558     *             {@code varId}. 
     559     * @throws IOException 
     560     *             if there was an error reading data from the data source 
    512561     */ 
    513562    public static List<Float> readHorizontalPoints(NetcdfDataset nc, String varId, 
     
    522571    /** 
    523572     * Reads a set of points at a given time and elevation from the given 
    524      * GridDatatype.  Use this method if you already have a {@link HorizontalGrid} 
    525      * object created for the variable in question, otherwise use 
    526      * {@link #readHorizontalPoints(ucar.nc2.dataset.NetcdfDataset, java.lang.String, 
    527      * int, int, uk.ac.rdg.resc.edal.coverage.domain.Domain)}. 
    528      * @param nc The (already-opened) NetcdfDataset from which we'll read data 
    529      * @param grid The GridDatatype object representing the data to be read 
    530      * @param sourceGrid object that maps between real-world and grid coordinates 
    531      * in the source data grid 
    532      * @param tIndex The time index, ignored if the grid has no time axis 
    533      * @param zIndex The elevation index, ignored if the grid has no elevation axis 
    534      * @param targetDomain The list of horizontal points for which we need data 
     573     * GridDatatype. Use this method if you already have a 
     574     * {@link HorizontalGrid} object created for the variable in question, 
     575     * otherwise use 
     576     * {@link #readHorizontalPoints(ucar.nc2.dataset.NetcdfDataset, java.lang.String, int, int, uk.ac.rdg.resc.edal.coverage.domain.Domain)} 
     577     * . 
     578     *  
     579     * @param nc 
     580     *            The (already-opened) NetcdfDataset from which we'll read data 
     581     * @param grid 
     582     *            The GridDatatype object representing the data to be read 
     583     * @param sourceGrid 
     584     *            object that maps between real-world and grid coordinates in 
     585     *            the source data grid 
     586     * @param tIndex 
     587     *            The time index, ignored if the grid has no time axis 
     588     * @param zIndex 
     589     *            The elevation index, ignored if the grid has no elevation axis 
     590     * @param targetDomain 
     591     *            The list of horizontal points for which we need data 
    535592     * @return a List of floating point numbers, one for each point in the 
    536      * {@code targetDomain}, in the same order.  Missing values (e.g. land pixels 
    537      * in oceanography data} are represented as nulls. 
    538      * @throws IllegalArgumentException if there is no variable in the dataset 
    539      * with the id {@code varId}. 
    540      * @throws IOException if there was an error reading data from the data source 
     593     *         {@code targetDomain}, in the same order. Missing values (e.g. 
     594     *         land pixels in oceanography data} are represented as nulls. 
     595     * @throws IllegalArgumentException 
     596     *             if there is no variable in the dataset with the id 
     597     *             {@code varId}. 
     598     * @throws IOException 
     599     *             if there was an error reading data from the data source 
    541600     */ 
    542601    public static List<Float> readHorizontalPoints(NetcdfDataset nc, GridDatatype grid, 
     
    573632    } 
    574633 
    575     static List<Float> readHorizontalPoints(NetcdfDataset nc, GridDatatype grid, 
     634    public static List<Float> readHorizontalPoints(NetcdfDataset nc, GridDatatype grid, 
    576635            int tIndex, int zIndex, PixelMap pixelMap, DataReadingStrategy strategy, 
    577636            int targetDomainSize) 
     
    594653    /** 
    595654     * Returns an immutable List of the given size in which all values are null. 
    596      * @todo we could cache instances of this object for some typical sizes (e.g. 256x256) 
     655     *  
     656     * @todo we could cache instances of this object for some typical sizes 
     657     *       (e.g. 256x256) 
    597658     */ 
    598659    private static List<Float> nullList(final int size) 
     
    610671 
    611672    /** 
    612      * Wraps a float array as an immutable List.  NaNs in the passed array will 
     673     * Wraps a float array as an immutable List. NaNs in the passed array will 
    613674     * be returned as null values. 
    614675     */ 
     
    647708     * Reads a timeseries of points from the given GridDatatype at a given 
    648709     * elevation and xy location 
    649      * @param nc The (already-opened) NetcdfDataset from which we'll read data 
    650      * @param varId The ID of the variable from which we will read data 
    651      * @param horizGrid object that maps between real-world and grid coordinates 
    652      * in the source data grid 
    653      * @param tIndices The list of indices along the time axis 
    654      * @param zIndex The elevation index, ignored if the grid has no elevation axis 
    655      * @param xy The horizontal location of the required timeseries 
    656      * @return a list of floating-point numbers, one for each of the time indices. 
    657      * Missing values (e.g. land pixels in oceanography data} are represented as nulls. 
    658      * @throws IOException if there was an error reading data from the data source 
     710     *  
     711     * @param nc 
     712     *            The (already-opened) NetcdfDataset from which we'll read data 
     713     * @param varId 
     714     *            The ID of the variable from which we will read data 
     715     * @param horizGrid 
     716     *            object that maps between real-world and grid coordinates in 
     717     *            the source data grid 
     718     * @param tIndices 
     719     *            The list of indices along the time axis 
     720     * @param zIndex 
     721     *            The elevation index, ignored if the grid has no elevation axis 
     722     * @param xy 
     723     *            The horizontal location of the required timeseries 
     724     * @return a list of floating-point numbers, one for each of the time 
     725     *         indices. Missing values (e.g. land pixels in oceanography data} 
     726     *         are represented as nulls. 
     727     * @throws IOException 
     728     *             if there was an error reading data from the data source 
    659729     */ 
    660730    public static List<Float> readTimeseries(NetcdfDataset nc, String varId, 
     
    709779 
    710780    /** 
    711      * @return the value of the standard_name attribute of the variable, 
    712      * or the long_name if it does not exist, or the unique id if neither of 
    713      * these attributes exist. 
     781     * @return the value of the standard_name attribute of the variable, or the 
     782     *         long_name if it does not exist, or the unique id if neither of 
     783     *         these attributes exist. 
    714784     */ 
    715785    public static String getVariableTitle(Variable var) 
Note: See TracChangeset for help on using the changeset viewer.