Changeset 954
- Timestamp:
- 02/01/12 12:36:42 (4 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/java/uk/ac/rdg/resc/edal/cdm/CdmUtils.java
r943 r954 1 1 /* 2 * Copyright (c) 2010 The University of Reading3 * All rights reserved.4 *5 * Redistribution and use in source and binary forms, with or without6 * modification, are permitted provided that the following conditions7 * are met:8 * 1. Redistributions of source code must retain the above copyright9 *notice, this list of conditions and the following disclaimer.10 * 2. Redistributions in binary form must reproduce the above copyright11 *notice, this list of conditions and the following disclaimer in the12 *documentation and/or other materials provided with the distribution.13 * 3. Neither the name of the University of Reading, nor the names of the14 *authors or contributors may be used to endorse or promote products15 *derived from this software without specific prior written permission.16 *17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES19 * 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, BUT22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF26 * 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 */ 28 28 29 29 package uk.ac.rdg.resc.edal.cdm; … … 36 36 import java.util.Collections; 37 37 import java.util.Date; 38 import java.util.Formatter; 38 39 import java.util.List; 39 40 import java.util.Map; … … 63 64 import ucar.nc2.dt.GridDataset.Gridset; 64 65 import ucar.nc2.dt.GridDatatype; 65 import ucar.nc2. dt.TypedDatasetFactory;66 import ucar.nc2.ft.FeatureDatasetFactoryManager; 66 67 import ucar.unidata.geoloc.LatLonPoint; 67 68 import ucar.unidata.geoloc.LatLonRect; … … 69 70 import uk.ac.rdg.resc.edal.coverage.domain.Domain; 70 71 import uk.ac.rdg.resc.edal.coverage.grid.HorizontalGrid; 72 import uk.ac.rdg.resc.edal.coverage.grid.RectilinearGrid; 71 73 import uk.ac.rdg.resc.edal.coverage.grid.ReferenceableAxis; 72 74 import uk.ac.rdg.resc.edal.coverage.grid.RegularAxis; 75 import uk.ac.rdg.resc.edal.coverage.grid.RegularGrid; 73 76 import uk.ac.rdg.resc.edal.coverage.grid.impl.RectilinearGridImpl; 74 77 import uk.ac.rdg.resc.edal.coverage.grid.impl.ReferenceableAxisImpl; … … 289 292 public static GridDataset getGridDataset(NetcdfDataset nc) throws IOException 290 293 { 291 return (GridDataset)TypedDatasetFactory.open(FeatureType.GRID, 292 nc, null, null); 294 return (GridDataset)FeatureDatasetFactoryManager.open(FeatureType.GRID, nc.getLocation(), null, new Formatter()); 293 295 } 294 296 295 297 /** 296 298 * Estimates the optimum {@link DataReadingStrategy} from the given 297 * NetcdfDataset. Essentially, if the amount of data to be read is very298 * 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, 299 301 * if the data are remote remote (e.g. OPeNDAP) or 300 302 * compressed, this will return {@link DataReadingStrategy#BOUNDING_BOX}, 301 * which makes a single i/o call, minimizing the overhead. If the data303 * which makes a single i/o call, minimizing the overhead. If the data 302 304 * are local and uncompressed this will return {@link DataReadingStrategy#SCANLINE}, 303 305 * which reduces the amount of data read. … … 313 315 return DataReadingStrategy.SCANLINE; 314 316 } 317 return getOptimumDataReadingStrategy(nc); 318 } 319 320 public static DataReadingStrategy getOptimumDataReadingStrategy(NetcdfDataset nc) 321 { 315 322 String fileType = nc.getFileTypeId(); 316 323 return "netCDF".equals(fileType) || "HDF4".equals(fileType) … … 321 328 /** 322 329 * 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. 327 336 */ 328 337 public static GeographicBoundingBox getBbox(LatLonRect latLonRect) … … 357 366 358 367 /** 359 * Gets List of DateTimes representing the timesteps of the given coordinate system,360 * in an appropriate {@link Chronology}.(Chronologies represent the368 * Gets List of DateTimes representing the timesteps of the given coordinate 369 * system, in an appropriate {@link Chronology}. (Chronologies represent the 361 370 * calendar system.) 362 * @param coordSys The coordinate system containing the time information 371 * 372 * @param coordSys 373 * The coordinate system containing the time information 363 374 * @return List of TimestepInfo objects, or an empty list if the coordinate 364 * system has no time axis365 * @throws IllegalArgumentException if the calendar system of the time axis366 * cannot be handled.375 * system has no time axis 376 * @throws IllegalArgumentException 377 * if the calendar system of the time axis cannot be handled. 367 378 */ 368 379 public static List<DateTime> getTimesteps(CoordinateAxis1DTime timeAxis) … … 394 405 395 406 /** 396 * Creates a list of DateTimes in a non-standard calendar system. All of the407 * Creates a list of DateTimes in a non-standard calendar system. All of the 397 408 * DateTimes will have a zero time zone offset (i.e. UTC). 398 409 */ … … 424 435 /** 425 436 * 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 437 454 * @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 443 462 */ 444 463 public static List<Float> readHorizontalPoints(NetcdfDataset nc, String varId, … … 455 474 * Reads a set of points at a given time from the given GridDatatype at a 456 475 * 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 464 491 * @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 471 500 */ 472 501 public static List<List<Float>> readVerticalSection(NetcdfDataset nc, String varId, … … 479 508 // We create the pixelMap only once 480 509 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 { 482 520 // Defend against null values 483 521 if (zIndices == null) zIndices = Arrays.asList(-1); … … 486 524 // It's very unlikely that the target domain will be bigger than 487 525 // 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)); 489 527 } 490 528 return data; 491 529 } 492 530 531 493 532 /** 494 533 * 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 506 553 * @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 512 561 */ 513 562 public static List<Float> readHorizontalPoints(NetcdfDataset nc, String varId, … … 522 571 /** 523 572 * 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 535 592 * @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 541 600 */ 542 601 public static List<Float> readHorizontalPoints(NetcdfDataset nc, GridDatatype grid, … … 573 632 } 574 633 575 static List<Float> readHorizontalPoints(NetcdfDataset nc, GridDatatype grid,634 public static List<Float> readHorizontalPoints(NetcdfDataset nc, GridDatatype grid, 576 635 int tIndex, int zIndex, PixelMap pixelMap, DataReadingStrategy strategy, 577 636 int targetDomainSize) … … 594 653 /** 595 654 * 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) 597 658 */ 598 659 private static List<Float> nullList(final int size) … … 610 671 611 672 /** 612 * Wraps a float array as an immutable List. NaNs in the passed array will673 * Wraps a float array as an immutable List. NaNs in the passed array will 613 674 * be returned as null values. 614 675 */ … … 647 708 * Reads a timeseries of points from the given GridDatatype at a given 648 709 * 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 659 729 */ 660 730 public static List<Float> readTimeseries(NetcdfDataset nc, String varId, … … 709 779 710 780 /** 711 * @return the value of the standard_name attribute of the variable, 712 * or thelong_name if it does not exist, or the unique id if neither of713 * 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. 714 784 */ 715 785 public static String getVariableTitle(Variable var)
Note: See TracChangeset
for help on using the changeset viewer.
