# -*- coding: utf-8 -*- ########################################################################################## # Copyright © 2013 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify, # and distribute this software and its documentation, without fee and without a signed # licensing agreement, is hereby granted, provided that the above copyright notice, this # paragraph and the following two paragraphs appear in all copies, modifications, and # distributions. # # IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, # INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF # THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE # SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". # RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, # OR MODIFICATIONS. ########################################################################################## class NetCDF #======================================================================================= # A Variable is a logical container for data. It has a dataType, a set of Dimensions # that define its array shape, and optionally a set of Attributes. The data is a # multidimensional array of primitive types, Strings, or Structures. Data access is # done through the read() methods, which return a memory resident Array. # Immutable if setImmutable() was called. #======================================================================================= class Variable < CDMNode attr_reader :attributes attr_reader :dimensions attr_reader :index_iterator #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def extra_info @netcdf_elmt.extraInfo() end #------------------------------------------------------------------------------------ # Create a new data cache, use this when you dont want to share the cache. #------------------------------------------------------------------------------------ def create_new_cache @netcdf_elmt.createNewCache() end #------------------------------------------------------------------------------------ # Finds an attribute by name #------------------------------------------------------------------------------------ def find_attribute(name, ignore_case = false) if (ignore_case) @netcdf_elmt.findAttributeIgnoreCase(name) else @netcdf_elmt.findAttribute(name) end end #------------------------------------------------------------------------------------ # Find the index of the named Dimension in this Variable. #------------------------------------------------------------------------------------ def find_dimension_index(name) @netcdf_elmt.findDimensionIndex(name) end #------------------------------------------------------------------------------------ # Returns the set of attributes for this variable. #------------------------------------------------------------------------------------ def find_attributes attributes = @netcdf_elmt.getAttributes() atts = Array.new attributes.each do |att| atts << NetCDF::Attribute.new(att) end atts end #------------------------------------------------------------------------------------ # Gets the variable data_type #------------------------------------------------------------------------------------ def get_data_type @netcdf_elmt.getDataType().toString() end #------------------------------------------------------------------------------------ # Get the description of the Variable. #------------------------------------------------------------------------------------ def get_description @netcdf_elmt.getDescription() end #------------------------------------------------------------------------------------ # Get the ith dimension. #------------------------------------------------------------------------------------ def get_dimension(index) @netcdf_elmt.getDimension(index) end #------------------------------------------------------------------------------------ # Get the list of dimensions used by this variable. #------------------------------------------------------------------------------------ def find_dimensions dimensions = @netcdf_elmt.getDimensions() dims = Array.new dimensions.each do |dim| dims << NetCDF::Dimension.new(dim) end dims end #------------------------------------------------------------------------------------ # Get the list of Dimension names, space delineated. #------------------------------------------------------------------------------------ def get_dimensions_string @netcdf_elmt.getDimensionsString() end #------------------------------------------------------------------------------------ # Get the number of bytes for one element of this Variable. #------------------------------------------------------------------------------------ def get_element_size @netcdf_elmt.getElementSize() end #------------------------------------------------------------------------------------ # Get the display name plus the dimensions, eg 'float name(dim1, dim2)' #------------------------------------------------------------------------------------ def get_name_and_dimensions @netcdf_elmt.getNameAndDimensions() end #------------------------------------------------------------------------------------ # Get the number of dimensions of the Variable. #------------------------------------------------------------------------------------ def get_rank @netcdf_elmt.getRank() end alias :rank :get_rank #------------------------------------------------------------------------------------ # Get the shape: length of Variable in each dimension. #------------------------------------------------------------------------------------ def get_shape(index = nil) if (index) @netcdf_elmt.getShape(index) else @netcdf_elmt.getShape().to_a end end alias :shape :get_shape #------------------------------------------------------------------------------------ # Get the total number of elements in the Variable. #------------------------------------------------------------------------------------ def get_size @netcdf_elmt.getSize() end alias :size :get_size #------------------------------------------------------------------------------------ # Get the Unit String for the Variable. #------------------------------------------------------------------------------------ def get_units_string @netcdf_elmt.getUnitsString() end #------------------------------------------------------------------------------------ # Has data been read and cached. #------------------------------------------------------------------------------------ def cached_data? @netcdf_elmt.hasCachedData() end #------------------------------------------------------------------------------------ # Invalidate the data cache #------------------------------------------------------------------------------------ def invalidate_cache @netcdf_elmt.invalidateCache() end #------------------------------------------------------------------------------------ # Will this Variable be cached when read. #------------------------------------------------------------------------------------ def caching? @netcdf_elmt.isCaching() end #------------------------------------------------------------------------------------ # Calculate if this is a classic coordinate variable: has same name as its first # dimension. #------------------------------------------------------------------------------------ def coordinate_variable? @netcdf_elmt.isCoordinateVariable() end #------------------------------------------------------------------------------------ # Is this Variable immutable #------------------------------------------------------------------------------------ def immutable? @netcdf_elmt.isImmutable() end #------------------------------------------------------------------------------------ # Is this variable metadata?. #------------------------------------------------------------------------------------ def metadata? @netcdf_elmt.isMetadata() end #------------------------------------------------------------------------------------ # Whether this is a scalar Variable (rank == 0). #------------------------------------------------------------------------------------ def scalar? @netcdf_elmt.isScalar() end #------------------------------------------------------------------------------------ # Can this variable's size grow?. #------------------------------------------------------------------------------------ def unlimited? @netcdf_elmt.isUnlimited() end #------------------------------------------------------------------------------------ # Is this Variable unsigned?. #------------------------------------------------------------------------------------ def unsigned? @netcdf_elmt.isUnsigned() end #------------------------------------------------------------------------------------ # Does this variable have a variable length dimension? If so, it has as one of its # mensions Dimension.VLEN. #------------------------------------------------------------------------------------ def variable_length? @netcdf_elmt.isVariableLength() end #------------------------------------------------------------------------------------ # Reads data for this Variable and sets the variable @data to the memory resident # array. # :origin int array with the origin of data to be read # :shape int array with the shape of the data to be read. If origin or #------------------------------------------------------------------------------------ def read(*args) opts = Map.options(args) spec = opts.getopt(:spec) origin = opts.getopt(:origin) shape = opts.getopt(:shape) if (origin || shape) MDArray.build_from_nc_array(nil, @netcdf_elmt.read(origin.to_java(:int), shape.to_java(:int))) elsif (spec) MDArray.build_from_nc_array(nil, @netcdf_elmt.read(spec)) else MDArray.build_from_nc_array(nil, @netcdf_elmt.read()) end end #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def read_scalar(type = nil) if (!type) type = get_data_type end case type when "double" @netcdf_elmt.readScalarDouble() when "float" @netcdf_elmt.readScalarFloat() when "long" @netcdf_elmt.readScalarLong() when "int" @netcdf_elmt.readScalarInt() when "short" @netcdf_elmt.readScalarShort() when "byte" @netcdf_elmt.readScalarByte() when "string" @netcdf_elmt.readScalarString() else raise "Unknown type: #{type}" end end #------------------------------------------------------------------------------------ # Set the data cache #------------------------------------------------------------------------------------ def set_cached_data(array, metadata = nil) @netcdf_elmt.setCachedData(array.nc_array, metadata) end #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def caching=(boolean) @netcdf_elmt.setCaching(boolean) end #------------------------------------------------------------------------------------ # Create a new Variable that is a logical subsection of this Variable. The # subsection can be specified passing the following arguments: # shape # origin # size # stride # range # section # spec #------------------------------------------------------------------------------------ def section(*args) sec = MDArray::Section.build(*args) NetCDF::Variable.new(@netcdf_elmt.section(sec.netcdf_elmt)) end #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def set_cached_data(array, metadata) @netcdf_elmt.setCachedData(array.nc_array, metadata) end #------------------------------------------------------------------------------------ # Prints the content of the current data slice #------------------------------------------------------------------------------------ def to_string @netcdf_elmt.toString() end alias :to_s :to_string #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def to_string_debug @netcdf_elmt.toSringDebug() end #------------------------------------------------------------------------------------ # Prints the content of the current data slice #------------------------------------------------------------------------------------ def print p to_string end end # Variable #======================================================================================= # #======================================================================================= class VariableWriter < Variable #------------------------------------------------------------------------------------ # Remove an Attribute : uses the attribute hashCode to find it. #------------------------------------------------------------------------------------ def remove_attribute(attribute, ignore_case = false) if (attribute.is_a? String) if (ignore_case) @netcdf_elmt.removeAttributeIgnoreCase(attribute) else @netcdf_elmt.removeAttribute(attribute) end elsif (attribute.is_a? NetCDF::Attribute) @netcdf_elmt.remove(attribute.netcdf_elmt) else raise "Given parameter is not an attribute: #{attribute}" end end #------------------------------------------------------------------------------------ # Reset the dimension array. #------------------------------------------------------------------------------------ def reset_dimensions @netcdf_elmt.resetDimensions() end #------------------------------------------------------------------------------------ # Use when dimensions have changed, to recalculate the shape. #------------------------------------------------------------------------------------ def reset_shape @netcdf_elmt.resetShape() end #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ end # VariableWriter #======================================================================================= # #======================================================================================= class TimeVariable < Variable include_package "ucar.nc2.time" attr_reader :calendar attr_reader :units attr_reader :base_date #------------------------------------------------------------------------------------ # Initializes the Variable by giving a java netcdf_variable #------------------------------------------------------------------------------------ def initialize(netcdf_variable) super(netcdf_variable) @calendar = @netcdf_elmt.findAttribute("calendar").getStringValue() @units = @netcdf_elmt.findAttribute("units").getStringValue() date_unit = CalendarDateUnit.of(@calendar, @units) @base_date = date_unit.getBaseCalendarDate() end #------------------------------------------------------------------------------------ # Returns the number of milliseconds elapsed from the base_date to the given date. # The given date should be in iso_format. #------------------------------------------------------------------------------------ def to_msec(iso_date) date = CalendarDate.parseISOformat(@calendar, iso_date) date.getDifferenceInMsecs(@base_date) end #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def next millisec_date = super @base_date.add(millisec_date, CalendarPeriod.fromUnitString("Millisec")).toString() end end # TimeVariable end # NetCDFInterface