reskit.util
===========

.. py:module:: reskit.util


Submodules
----------

.. toctree::
   :maxdepth: 1

   /_readthedocs/reskit/util/air_density/index
   /_readthedocs/reskit/util/economic/index
   /_readthedocs/reskit/util/errors/index
   /_readthedocs/reskit/util/leap_day/index
   /_readthedocs/reskit/util/loss_factors/index
   /_readthedocs/reskit/util/relative_humidity/index
   /_readthedocs/reskit/util/specific_humidity/index
   /_readthedocs/reskit/util/topography/index
   /_readthedocs/reskit/util/weather_tile/index
   /_readthedocs/reskit/util/wet_bulb_temperature/index


Exceptions
----------

.. autoapisummary::

   reskit.util.ResError
   reskit.util.RESKitDeprecationError


Functions
---------

.. autoapisummary::

   reskit.util.compute_air_density
   reskit.util.levelized_cost_of_electricity
   reskit.util.levelized_cost_of_electricity_simplified
   reskit.util.remove_leap_day
   reskit.util.low_generation_loss
   reskit.util.visibility_from_topography
   reskit.util.get_dataframe_with_weather_tilepaths


Package Contents
----------------

.. py:function:: compute_air_density(temperature=20, pressure=101325, relative_humidity=0, dew_temperature=None)

   Computes air density, following the approach of "Revised formula for the density of moist air (CIPM-2007)" by A Picard, R S Davis, M Glaser and K Fujii


.. py:function:: levelized_cost_of_electricity(expenditures, productions, discount_rate=0.08)

   Compute the LCOE of a producer using explicitly given production and
   expeditures for each year in the economic lifetime

   Uses the equation:
   .. math::
       \mathrm{LCOE} = \sum{\frac{exp_y}{(1+r)^y}} / \sum{\frac{prod_y}{(1+r)^y}}

   where:
     * $exp_y$ -> The expenditures in year $y$ [Euro]
     * $prod_y$ -> The production in year $y$ [kWh]
     * $r$ -> The discount rate

   :param expenditures: All expenditures for each year in the lifetime
   :type expenditures: array_like
   :param productions: Annual production for each year in the lifetime
   :type productions: array_like
   :param discount_rate:
                         The discount rate
                           * If a numeric is given, the discount rate is applied to all years
                           * If an array is given, a discount rate for each year must by provided
   :type discount_rate: numeric or array_like

   :rtype: numeric or array_like


.. py:function:: levelized_cost_of_electricity_simplified(capex, mean_production, opex_per_capex=0.02, lifetime=20, discount_rate=0.08)

   Compute the LCOE of a producer using the simple method

   Uses the equation:
   .. math::
       \mathrm{LCOE} = C * \frac{ (r/(1-(1+r)^{-N})) + O_c }{P_{mean}}

   where:
     * $C$ -> CAPEX [euros]
     * $O_c$ -> Fixed OPEX as a factor of CAPEX
     * $P_{mean}$ -> The average production in each year [kWh]
     * $r$ -> The discount rate
     * $N$ -> The economic lifetime [years]


   :param capex: The capital expenditures
   :type capex: numeric or array_like
   :param mean_production: The average annual production
   :type mean_production: numeric or array_like
   :param opex_per_capex: The operational expenditures given as a factor or the capex
   :type opex_per_capex: numeric
   :param lifetime: The economic lifetime in years
   :type lifetime: numeric
   :param discount_rate: The discount rate
   :type discount_rate: numeric

   :rtype: numeric or array_like


.. py:exception:: ResError

   Bases: :py:obj:`Exception`


   Common base class for all non-exit exceptions.

   Initialize self.  See help(type(self)) for accurate signature.


.. py:exception:: RESKitDeprecationError(commit_hash)

   Bases: :py:obj:`Exception`


   Custom exception for deprecation errors.

   Raises an error stating that the method is deprecated and suggests
   a commit to check out when function is needed for backward
   compatibility.

   commit_hash : str
       The has to the commit with the last working version
       of the deprecated method.


.. py:function:: remove_leap_day(timeseries)

   Removes leap days from a given timeseries

   :param timeseries:
                      The time series data to remove leap days from
                        * If something array_like is given, the length must be 8784
                        * If a pandas DataFrame or Series is given, time indexes will be used
                          directly
   :type timeseries: array_like

   :rtype: Array


.. py:function:: low_generation_loss(capacity_factor, base=0, sharpness=5)

   Generate capacity-factor-dependent loss factors

   Follows the equation:
       (1-base) * ( 1 - exp[-sharpness * capacity_factor] )


.. py:function:: visibility_from_topography(lon, lat, elevation_raster, base_elevation=None, eye_level=2, max_degree=0.1, degree_step=0.003, theta_step=3, _interpolation='cubic')

   Determine visibility around a given point based on topography. Also
   gives planar angle, planar elevation, and planar distance of multiple
   sample points surroudning the specified latitude and longitude


   Params:
   ======
   lon : longitude point to consider
   lat : latitude point to consider
   elevation_raster : The raster to extract elevation values from
   eye_level : The height to measure visibility from (in meters) above the elevation at the center point
   base_elevation : The total height to measure visibility from (in meters)
       - If given, 'eye_level' is ignored
   max_degree : The maximum distance to consider (in degrees)
   degree_step : approximate radial degree discretization
   theta_step : theta discretization

   Return:
   ======
   dict
       - All items are pandas DataFrames
           * Columns match to theta direction (in radians)
       - Items include:
           * latitude : the latitude at each sample point
           * longitude : the longitude at each sample point
           * planar_angle : the angle between the view point and the sample point
           * planar_dist : the planar distance between the view point and the sample point
           * planar_elev : the planar elevation of the sample point
           * visibility : indicates if the sample point should be visible from the view point

   Note:
   =====
   * This algorithm will likely fail if used too near to the poles
   * It is also important to choose an appropriate degree_step for the
     given elevation raster file. If the step size is too small,
     artifacts will begin to appear in leading to reduced visibility
     - Todo: investigate this further?? (It has something to do with
       the interpolation
     - For now, choose a value which is slightly higher than the raster's
       pixel resolution

   * You can plot the outputs nicely with:
      >>> fig = plt.figure()
      >>> ax = (
      ...     fig.add_subplot(
      ...         111,
      ...         polar=True,
      ...     )
      ... )
      >>> h = ax.pcolormesh(a['visibility'].columns,
      >>>                   a['visibility'].index,
      >>>                   a['visibility'])
      >>> plt.colorbar(h)
      >>> plt.show()


.. py:function:: get_dataframe_with_weather_tilepaths(placements, weather_path, zoom)

   This method will generate a dataframe from a list of input placements
   and add the link to the corresponding weather data tile in a new dataframe
   column 'source'.

   placements : pd.DataFrame with 'geom' column and osgeo.ogr.Geometry point
   objects in EPSG:4326 or 'lat' and 'lon' columns with degrees in EPSG:4326.
   weather_path : The path to the tilepath or a dummy path containing '<X-TILE>'
   and '<Y-TILE>', optionally also <ZOOM> as spacers. These will be replaced by
   the actual tile ID in x and y direction, plus zoom value if applicable.
   weather_path can also be None only if 'source' is an existing attribute of the
   placements dataframe, the column values will be assumed as existing filepaths
   of weather data tiles then.
   in placements dataframe or if no '<ZOOM>' spacer in weather_path.


