API Reference
=============


.. module:: epr
   :synopsis: Python bindings for ENVISAT Product Reader C API

PyEPR_ provides Python_ bindings for the ENVISAT Product Reader C API
(`EPR API`_) for reading satellite data from ENVISAT_ ESA_ (European
Space Agency) mission.

PyEPR_ is fully object oriented and, as well as the `EPR API`_ for C,
supports ENVISAT_ MERIS, AATSR Level 1B and Level 2 and also ASAR data
products. It provides access to the data either on a geophysical
(decoded, ready-to-use pixel samples) or on a raw data layer.
The raw data access makes it possible to read any data field contained
in a product file.

.. _PyEPR: https://github.com/avalentino/pyepr
.. _Python: http://www.python.org
.. _`EPR API`: https://github.com/bcdev/epr-api
.. _ENVISAT: http://envisat.esa.int
.. _ESA: http://earth.esa.int


.. currentmodule:: epr


Classes
-------

Product
~~~~~~~

.. class:: Product

   ENVISAT product

   The Product class provides methods and properties to get information
   about an ENVISAT product file.

   .. seealso:: :func:`open`


   .. attribute:: file_path

      The file's path including the file name


   .. attribute:: id_string

      The product identifier string obtained from the MPH parameter 'PRODUCT'

      The first 10 characters of this string identify the product type,
      e.g. "MER_1P__FR" for a MERIS Level 1b full resolution product.
      The rest of the string decodes product instance properties.


   .. attribute:: meris_iodd_version

      For MERIS L1b and RR and FR to provide backward compatibility


   .. attribute:: tot_size

      The total size in bytes of the product file


   .. method:: get_band(name)

      Gets the band corresponding to the specified name.

      :param name:
            the name of the band
      :returns:
            the requested :class:`Band` instance, or raises a
            :class:`EPRValueError` if not found


   .. method:: get_band_at(index)

      Gets the band at the specified position within the product

      :param index:
            the index identifying the position of the band, starting
            with 0, must not be negative
      :returns:
            the requested :class:`Band` instance, or raises a
            :class:`EPRValueError` if not found


   .. method:: get_dataset(name)

      Gets the dataset corresponding to the specified dataset name

      :param name:
            the dataset name
      :returns:
            the requested :class:`Dataset` instance


   .. method:: get_dataset_at(index)

      Gets the dataset at the specified position within the product

      :param index:
            the index identifying the position of the dataset, starting
            with 0, must not be negative
      :returns:
            the requested :class:`Dataset`


   .. method:: get_dsd_at(index)

      Gets the DSD at the specified position

      Gets the DSD (dataset descriptor) at the specified position
      within the product.

      :param index:
            the index identifying the position of the DSD, starting
            with 0, must not be negative
      :returns:
            the requested :class:`DSD` instance


   .. method:: get_num_bands

      Gets the number of all bands contained in a product


   .. method:: get_num_datasets

      Gets the number of all datasets contained in a product


   .. method:: get_num_dsds

      Gets the number of all DSDs (dataset descriptors) contained
      in the product


   .. method:: get_scene_height

      Gets the product's scene height in pixels


   .. method:: get_scene_width

      Gets the product's scene width in pixels


   .. method:: get_mph

      The :class:`Record` representing the main product header (MPH)


   .. method:: get_sph

      The :class:`Record` representing the specific product header (SPH)

   .. method:: get_dataset_names

      Return the list of names of the datasets in the product

      .. note:: this method has no correspondent in the C API


   .. method:: read_bitmask_raster

      Calculates a bit-mask raster

      Calculates a bit-mask, composed of flags of the given product
      and combined as described in the given bit-mask expression, for
      the a certain dimension and sub-sampling as defined in the
      given raster.

      :param bm_expr:
            a string holding the logical expression for the definition
            of the bit-mask. In a bit-mask expression, any number of
            the flag-names (found in the DDDB) can be composed with
            "(", ")", "NOT", "AND", "OR". Valid bit-mask expression are
            for example ``flags.LAND OR flags.CLOUD`` or
            ``NOT flags.WATER AND flags.TURBID_S``

      :param xoffset:
            across-track co-ordinate in pixel co-ordinates (zero-based)
            of the upper right corner of the source-region
      :param yoffset:
            along-track co-ordinate in pixel co-ordinates (zero-based)
            of the upper right corner of the source-region
      :param raster:
            the raster for the bit-mask. The data type of the raster
            must be either :data:`E_TID_UCHAR` or :data:`E_TID_CHAR`
      :returns:
            zero for success, an error code otherwise

      .. seealso:: :func:`create_bitmask_raster`


   .. method:: get_band_names

      Return the list of names of the bands in the product

      .. note:: this method has no correspondent in the C API


   .. method:: datasets

      Return the list of dataset in the product

      .. note:: this method has no correspondent in the C API


   .. method:: bands

      Return the list of bands in the product

      .. note:: this method has no correspondent in the C API


   .. rubric:: Implemented special methods

   * __repr__
   * __str__


Dataset
~~~~~~~

.. class:: Dataset

   ENVISAT dataset

   The Dataset class contains information about a dataset within an
   ENVISAT product file which has been opened with the :func:`open`
   function.

   A new Dataset instance can be obtained with the
   :meth:`Product.get_dataset` or :meth:`Product.get_dataset_at` methods.


   .. attribute:: description

      A short description of the band's contents


   .. attribute:: product

      The :class:`Product` instance to which this dataset belongs to


   .. method:: get_name

      Gets the name of the dataset


   .. method:: get_dsd

      Gets the dataset descriptor (DSD)


   .. method:: get_dsd_name

      Gets the name of the DSD (dataset descriptor)


   .. method:: get_num_records

      Gets the number of records of the dataset


   .. method:: create_record

      Creates a new record

      Creates a new, empty record with a structure compatible with
      the dataset. Such a record is typically used in subsequent
      calls to :meth:`Dataset.read_record`.

      :returns:
            the new record instance


   .. method:: read_record(index[, record])

      Reads specified record of the dataset

      The record is identified through the given zero-based record
      index. In order to reduce memory reallocation, a record
      (pre-)created by the method :meth:`Dataset.create_record` can
      be passed to this method.
      Data is then read into this given record.

      If no record (``None``) is given, the method initiates a new
      one.

      In both cases, the record in which the data is read into will
      be  returned.

      :param index:
            the zero-based record index
      :param record:
            a pre-created record to reduce memory reallocation, can be
            ``None`` (default) to let the function allocate a new
            record
      :returns:
            the record in which the data has been read into or raises
            an exception (:class:`EPRValueError`) if an error occurred


   .. method:: records

      Return the list of records contained in the dataset

      .. note:: this method has no correspondent in the C API


   .. rubric:: Implemented special methods

   * __repr__
   * __str__
   * __iter__


Record
~~~~~~

.. class:: Record

   Represents a record read from an ENVISAT dataset

   A record is composed of multiple fields.

   .. seealso:: :class:`Field`


   .. method:: get_field(name)

      Gets a field specified by name

      The field is here identified through the given name.
      It contains the field info and all corresponding values.

      :param name:
            the the name of required field
      :returns:
            the specified :class:`Field` or raises an exception
            (:class:`EPRValueError`) if an error occurred


   .. method:: get_field_at(index)

      Gets a field at the specified position within the record

      :param index:
            the zero-based index (position within record) of the field
      :returns:
            the field or raises and exception (:class:`EPRValueError`)
            if an error occurred


   .. method:: get_num_fields

      Gets the number of fields contained in the record


   .. method:: print_([ostream])

      Write the record to specified file (default: :data:`sys.stdout`)

      This method writes formatted contents of the record to
      specified *ostream* text file or (default) the ASCII output
      is be printed to standard output (:data:`sys.stdout`)

      :param ostream:
            the (opened) output file object

      .. note:: the *ostream* parameter have to be a *real* file not
                a generic stream object like :class:`StringIO` instances


   .. method:: print_element(field_index, element_index[, ostream])

      Write the specified field element to file (default: :data:`sys.stdout`)

      This method writes formatted contents of the specified field
      element to the *ostream* text file or (default) the ASCII output
      will be printed to standard output (:data:`sys.stdout`)

      :param field_index:
            the index of field in the record
      :param element_index:
            the index of element in the specified field
      :param ostream:
            the (opened) output file object

      .. note:: the *ostream* parameter have to be a *real* file not
                a generic stream object like :class:`StringIO` instances


   .. method:: get_field_names

      Return the list of names of the fields in the product

      .. note:: this method has no correspondent in the C API


   .. method:: fields

      Return the list of fields contained in the record

      .. note:: this method has no correspondent in the C API


   .. rubric:: Implemented special methods

   * __repr__
   * __str__
   * __iter__


Field
~~~~~

.. class:: Field

   Represents a field within a record

   A field is composed of one or more data elements of one of the
   types defined in the internal ``field_info`` structure.

   .. seealso:: :class:`Record`


   .. method:: get_description

      Gets the description of the field


   .. method:: get_name

      Gets the name of the field


   .. method:: get_num_elems

      Gets the number of elements of the field


   .. method:: get_type

      Gets the type of the field


   .. method:: get_unit

      Gets the unit of the field


   .. method:: get_elem([index])

      Field single element access

      This function is for getting the elements of a field.

      :param index:
            the zero-based index of element to be returned, must not be
            negative. Default: 0.
      :returns:
            the typed value from given field


   .. method:: get_elems

      Field array element access

      This function is for getting an array of field elements of the
      field.

      :returns:
            the data array (:class:`numpy.ndarray`) having the type of
            the field


   .. method:: print_([ostream])

      Write the field to specified file (default: :data:`sys.stdout`)

      This method writes formatted contents of the field to
      specified *ostream* text file or (default) the ASCII output
      is be printed to standard output (:data:`sys.stdout`)

      :param ostream:
            the (opened) output file object

      .. note:: the *ostream* parameter have to be a *real* file not
                a generic stream object like :class:`StringIO` instances


   .. rubric:: Implemented special methods

   * __repr__
   * __str__
   * __eq__
   * __ne__
   * __len__ [#]_

.. rubric:: Footnotes

.. [#] if the field is a :data:`E_TID_STRING` field then the
       :meth:`__len__` method returns the string length, otherwise the
       number of elements of the field is returned (same as
       :meth:`Field.get_num_elems`)


DSD
~~~

.. class:: DSD

   Dataset descriptor

   The DSD class contains information about the properties of a
   dataset and its location within an ENVISAT product file


   .. attribute:: ds_name

      The dataset name


   .. attribute:: ds_offset

      The offset of dataset-information the product file


   .. attribute:: ds_size

      The size of dataset-information in dataset product file


   .. attribute:: ds_type

      The dataset type descriptor


   .. attribute:: dsr_size

      The size of dataset record for the given dataset name


   .. attribute:: filename

      The filename in the DDDB with the description of this dataset


   .. attribute:: index

      The index of this DSD (zero-based)


   .. attribute:: num_dsr

      The number of dataset records for the given dataset name


   .. rubric:: Implemented special methods

   * __repr__
   * __eq__
   * __ne__


Band
~~~~

.. class:: Band

   The band of an ENVISAT product

   The Band class contains information about a band within an ENVISAT
   product file which has been opened with the :func:`open` function.

   A new Band instance can be obtained with the :meth:`Product.get_band`
   method.


   .. attribute:: bm_expr

      A bit-mask expression used to filter valid pixels

      All others are set to zero


   .. attribute:: data_type

      The data type of the band's pixels

      Possible values are:

      * ``*``         --> the datatype remains unchanged.
      * ``uint8_t``   --> 8-bit unsigned integer
      * ``uint32_t``  --> 32-bit unsigned integer
      * ``Float``     --> 32-bit IEEE floating point


   .. attribute:: description

      A short description of the band's contents


   .. attribute:: lines_mirrored

      Mirrored lines flag

      If true (=1) lines will be mirrored (flipped) after read into a
      raster in order to ensure a pixel ordering in raster X direction
      from WEST to EAST.


   .. attribute:: product

      The :class:`Product` instance to which this band belongs to


   .. attribute:: sample_model

      The sample model operation

      The sample model operation applied to the source dataset for
      getting the correct samples from the MDS (for example MERIS L2).

      Possible values are:

      * ``*``     --> no operation (direct copy)
      * ``1OF2``  --> first byte of 2-byte interleaved MDS
      * ``2OF2``  --> second byte of 2-byte interleaved MDS
      * ``0123``  --> combine 3-bytes interleaved to 4-byte integer


   .. attribute:: scaling_factor

      The scaling factor

      Possible values are:

      * ``*`` --> no factor provided (implies scaling_method=*)
      * ``const`` --> a floating point constant
      * ``GADS.field[.field2]`` --> value is provided in global
        annotation dataset with name `GADS` in field `field``.
        Optionally a second element index for multiple-element fields
        can be given too


   .. attribute:: scaling_method

      The scaling method which must be applied to the raw source data
      in order to get the 'real' pixel values in geo-physical units.

      Possible values are:

      * ``*``            --> no scaling applied
      * ``Linear_Scale`` --> linear scaling applied::

            y = offset + scale * x

      * ``Log_Scale``    --> logarithmic scaling applied::

            y = log10(offset + scale * x)


   .. attribute:: scaling_offset

      Possible values are:

      * ``*`` --> no offset provided (implies scaling_method=*)
      * ``const`` --> a floating point constant
      * ``GADS.field[.field2]` --> value is provided in global
        annotation dataset with name ``GADS`` in field ``field``.
        Optionally a second element index for multiple-element fields
        can be given too


   .. attribute:: spectr_band_index

      The (zero-based) spectral band index

       -1 if this is not a spectral band


   .. attribute:: unit

      The geophysical unit for the band's pixel values


   .. method:: get_name

      Gets the name of the band


   .. method:: create_compatible_raster(src_width, src_height[, xstep, ystep])

      Creates a raster which is compatible with the data type of the band

      The created raster is used to read the data in it (see
      :meth:`Band.read_raster`).

      The raster is defined on the grid of the product, from which the
      data are read. Spatial subsets and under-sampling are possible)
      through the parameter of the method.

      A raster is an object that allows direct access to data of a
      certain portion of the ENVISAT product that are read into the it.
      Such a portion is called the source. The complete ENVISAT product
      can be much greater than the source. One can move the raster over
      the complete ENVISAT product and read in turn different parts
      (always of the size of the source) of it into the raster.
      The source is specified by the parameters *height* and *width*.

      A typical example is a processing in blocks. Lets say, a block
      has 64x32 pixel. Then, my source has a width of 64 pixel and a
      height of 32 pixel.

      Another example is a processing of complete image lines. Then,
      my source has a widths of the complete product (for example 1121
      for a MERIS RR product), and a height of 1). One can loop over
      all blocks read into the raster and process it.

      In addition, it is possible to defined a sub-sampling step for
      a raster. This means, that the source is not read 1:1 into the
      raster, but that only every 2nd or 3rd pixel is read. This step
      can be set differently for the across track (source_step_x) and
      along track (source_step_y) directions.

      :param src_width:
            the width (across track dimension) of the source to be read
            into the raster
      :param src_height:
            the height (along track dimension) of the source to be read
            into the raster
      :param xstep:
            the sub-sampling step across track of the source when reading
            into the raster. Default 1.
      :param ystep:
            the sub-sampling step along track of the source when reading
            into the raster. Default 1.
      :returns:
            the new raster instance or raises an exception
            (:class:`EPRValueError`) if an error occurred


   .. method:: read_raster([xoffset, yoffset, raster])

      Reads (geo-)physical values of the band of the specified
      source-region

      The source-region is a defined part of the whole ENVISAT product
      image, which shall be read into a raster.
      In this routine the co-ordinates are specified, where the
      source-region to be read starts.
      The dimension of the region and the sub-sampling are attributes
      of the raster into which the data are read.

      :param xoffset:
            across-track source co-ordinate in pixel co-ordinates
            (zero-based) of the upper right corner of the source-region.
            Default 0.
      :param yoffset:
            along-track source co-ordinate in pixel co-ordinates
            (zero-based) of the upper right corner of the source-region.
            Default 0.
      :param raster:
            :class:`Raster` instance set with appropriate parameters to
            read into. If not provided a new :class:`Raster` is instantiated
      :returns:
            the :class:`Raster` instance in which data are read

      This method raises an instance of the appropriate :class:`EPRError`
      sub-class if case of errors

      .. seealso:: :meth:`Band.create_compatible_raster` and
                   :func:`create_raster`


   .. method:: read_as_array([width, height, xoffset, yoffset, xstep, ystep])

      Reads the specified source region as an :class:`numpy.ndarray`

      The source-region is a defined part of the whole ENVISAT product
      image, which shall be read into a raster.
      In this routine the co-ordinates are specified, where the
      source-region to be read starts.
      The dimension of the region and the sub-sampling are attributes
      of the raster into which the data are read.

      :param src_width:
            the width (across track dimension) of the source to be read
            into the raster. If not provided reads as much as possible
      :param src_height:
            the height (along track dimension) of the source to be read
            into the raster, If not provided reads as much as possible
      :param xoffset:
            across-track source co-ordinate in pixel co-ordinates
            (zero-based) of the upper right corner of the source-region.
            Default 0.
      :param yoffset:
            along-track source co-ordinate in pixel co-ordinates
            (zero-based) of the upper right corner of the source-region.
            Default 0.
      :param xstep:
            the sub-sampling step across track of the source when reading
            into the raster. Default 1
      :param ystep:
            the sub-sampling step along track of the source when reading
            into the raster. Default 1
      :returns:
            the :class:`numpy.ndarray` instance in which data are read

      This method raises an instance of the appropriate :class:`EPRError`
      sub-class if case of errors

      .. note:: this method has no correspondent in the C API
      .. seealso:: :meth:`Band.create_compatible_raster`,
                   :func:`create_raster` and :meth:`Band.read_raster`


   .. rubric:: Implemented special methods

   * __repr__


Raster
~~~~~~

.. class:: Raster

   Represents a raster in which data will be stored

   All 'size' parameter are in PIXEL.


   .. attribute:: data_type

      The data type of the band's pixels

      All ``E_TID_*`` types are possible


   .. attribute:: source_height

      The height of the source


   .. attribute:: source_width

      The width of the source


   .. attribute:: source_step_x

      The sub-sampling for the across-track direction in pixel


   .. attribute:: source_step_y

      The sub-sampling for the along-track direction in pixel


   .. attribute:: data

      Raster data exposed as :class:`numpy.ndarray` object

      .. note:: this property shares the data buffer with the
                :class:`Raster` object so any change in its contents
                is also reflected to the :class:`Raster` object

      .. note:: this property has no correspondent in the C API


   .. method:: get_pixel(x, y)

      Single pixel access

      This function is for getting the values of the elements of a
      raster (i.e. pixel)

      :param x:
            the (zero-based) X coordinate of the pixel
      :param y:
            the (zero-based) Y coordinate of the pixel
      :returns:
            the typed value at the given co-ordinate


   .. method:: get_elem_size

      The size in byte of a single element (sample) of this raster's
      buffer


   .. method:: get_height

      Gets the raster's height in pixels


   .. method:: get_width

      Gets the raster's width in pixels


   .. rubric:: Implemented special methods

   * __repr__


EPRTime
~~~~~~~

.. class:: EPRTime

   Convenience class for time data exchange.

   EPRTime is a :class:`collections.namedtuple` with the following fields:

   .. attribute:: days
   .. attribute:: seconds
   .. attribute:: microseconds


Functions
---------

.. function:: open(filename)

   Opens the ENVISAT product

   Opens the ENVISAT product file with the given file path, reads MPH,
   SPH and all DSDs, organized the table with parameter of line length
   and tie points number.

   :param product_file_path:
        the path to the ENVISAT product file
   :returns:
        the :class:`Product` instance representing the specified
        product. An exception (:class:`ValueError`) is raised if the
        file could not be opened.

   .. seealso :class:`Product`


.. function:: data_type_id_to_str

   Gets the 'C' data type string for the given data type


.. function:: get_data_type_size

   Gets the size in bytes for an element of the given data type


.. function:: get_sample_model_name

   Return the name of the specified sample model


.. function:: get_scaling_method_name

   Return the name of the specified scaling method


.. function:: create_raster(data_type, src_width, src_height[, xstep, ystep])

   Creates a raster of the specified data type

   This function can be used to create any type of raster, e.g. for
   later use as a bit-mask.

   :param data_type:
        the type of the data to stored in the raster, must be one of
        E_TID_*.

        .. seealso:: `Data type Identifiers`_

   :param src_width:
        the width (across track dimension) of the source to be read
        into the raster.
        See description of :meth:`Band.create_compatible_raster`
   :param src_height:
        the height (along track dimension) of the source to be read
        into the raster.
        See description of :meth:`Band.create_compatible_raster`
   :param xstep:
        the sub-sampling step across track of the source when reading
        into the raster. Default 1.
   :param ystep:
        the sub-sampling step along track of the source when reading
        into the raster. Default 1.
   :returns:
        the new :class:`Raster` instance

   .. seealso:: description of :meth:`Band.create_compatible_raster`


.. function:: create_bitmask_raster(src_width, src_height[, xstep, ystep])

   Creates a raster to be used for reading bitmasks

   The raster returned always is of type ``byte``.

   :param src_width:
        the width (across track dimension) of the source to be read
        into the raster
   :param src_height:
        the height (along track dimension) of the source to be read
        into the raster
   :param xstep:
        the sub-sampling step across track of the source when reading
        into the raster. Default 1.
   :param ystep:
        the sub-sampling step along track of the source when reading
        into the raster. Default 1.
   :returns:
        the new raster instance or raises an exception
        (:class:`EPRValueError`) if an error occurred

   .. seealso:: the description of :meth:`Band.create_compatible_raster`


Exceptions
----------

EPRError
~~~~~~~~

.. exception:: EPRError

   EPR API error

   .. attribute:: code

      EPR API error code


   .. method:: __init__([message[, code, *args, **kwargs]])

      Initializer

      :param message:
            error message
      :pram code:
            EPR error code


EPRValueError
~~~~~~~~~~~~~

.. exception:: EPRValueError

   Inherits both :class:`EPRError` and standard :class:`ValueError`


Data
----

.. data:: EPR_C_API_VERSION

   Version string of the wrapped `EPR API`_ C library


Data type identifiers
~~~~~~~~~~~~~~~~~~~~~

.. data:: E_TID_UNKNOWN
.. data:: E_TID_UCHAR
.. data:: E_TID_CHAR
.. data:: E_TID_USHORT
.. data:: E_TID_SHORT
.. data:: E_TID_UINT
.. data:: E_TID_INT
.. data:: E_TID_FLOAT
.. data:: E_TID_DOUBLE
.. data:: E_TID_STRING
.. data:: E_TID_SPARE
.. data:: E_TID_TIME


Sample Models
~~~~~~~~~~~~~

.. data:: E_SMOD_1OF1
.. data:: E_SMOD_1OF2
.. data:: E_SMOD_2OF2
.. data:: E_SMOD_3TOI
.. data:: E_SMOD_2TOF


Scaling Methods
~~~~~~~~~~~~~~~

.. data:: E_SMID_NON

   No scaling


.. data:: E_SMID_LIN

   Linear pixel scaling


.. data:: E_SMID_LOG

   Logarithmic pixel scaling
