Skip to content

Commit

Permalink
Merge branch 'geospatial_decorator_namespace' into pre-release
Browse files Browse the repository at this point in the history
  • Loading branch information
tobin-ford committed Feb 7, 2025
2 parents 38e06fd + 6e442b0 commit 3bad5ce
Show file tree
Hide file tree
Showing 17 changed files with 163 additions and 101 deletions.
2 changes: 1 addition & 1 deletion docs/source/user_guide/geospatial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Previously, ``pvdeg.geospatial`` provided minimal templates and forced users to
But many pvdeg functions do not require a template for geospatial analysis.

Auto-templating: allows users to skip creating templates for most ``pvdeg`` functions.
It is integrated into ``geospatial.analysis``. If a function is defined with the ``@geospatial_quick_shape`` decorator in the source code, we can call ``geospatial.analysis`` without providing a template.
It is integrated into ``geospatial.analysis``. If a function is defined with the ``@decorators.geospatial_quick_shape`` decorator in the source code, we can call ``geospatial.analysis`` without providing a template.
The function responsible for this is called ``geospatial.auto_template`` and is exposed publicly to create templates outside of ``geospatial.analysis``.

If a function cannot be auto-templated, both ``geospatial.analysis`` and ``geospatial.auto_template`` will raise the following error.
Expand Down
2 changes: 1 addition & 1 deletion docs/source/whatsnew/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ What's New
==========
PVDegradationTools (pvdeg) change log:

.. include:: releases/v0.4.4.rst
.. include:: releases/v0.5.0.rst
.. include:: releases/v0.4.3.rst
.. include:: releases/v0.4.2.rst
.. include:: releases/v0.4.1.rst
Expand Down
59 changes: 38 additions & 21 deletions docs/source/whatsnew/releases/v0.4.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,68 @@ v0.4.0 (2024-07-29)
=======================

Enhancements
---------
----------------

Scenarios

* Unified Cell and Module Temperature function. See: ``temperature.temperature``
* Added support for pvlib temperature models. ``see pvlib docs <https://pvlib-python.readthedocs.io/en/stable/reference/pv_modeling/temperature.html>``
* Overhauled scenario class for pv system analysis. Scenario object for single point analysis and GeospatialScenario object for geospatial analysis. See: ``scenario.Scenario`` and ``scenario.GeospatialScenario``
* Created Scenario tutorials to showcase new scenario functionality.
* Added a number of geospatial downselection functions. Find coordinates near mountains, rivers, coastlines and lakes from NSRDB data. See: ``geospatial.identify_mountains_weights``, ``geospatial.identify_mountains_radii``, ``geospatial.feature_downselect``
* Added geospatial bounding box support. Clip unwanted data with rectangular bounding boxes. See: ``geospatial.apply_bounding_box``
* Added stochastic non-uniform density downselection function to preferentially select for mountains (higher point density with changes in elevation, lower density when flatter.) See: ``geospatial.elevation_stochastic_downselection``
* Updated non-uniform downselection with thresholding and non-linear normalization (support for logarithmic and exponential normalization) See: ``geospatial.identify_mountains_weights``
* Added Scenario and GeospatialScenario methods for quick plotting and downselection. See: ``GeospatialScenario.plot_coords``, ``GeospatialScenario.plot_meta_classification``, ``GeospatialScenario.plot_USA``, ``Scenario.extract``, ``Scenario.plot``, ``GeospatialScenario.classify_mountain_weights``, ``GeospatialScenario.classify_mountain_radii``, ``GeospatialScenario.downselect_elevation_stochastic``.
- Unified Cell and Module Temperature function. See:
- ``temperature.temperature``
- Added support for pvlib temperature models. See pvlib docs:
- `https://pvlib-python.readthedocs.io/en/stable/reference/pv_modeling/temperature.html`_
- Overhauled scenario class for pv system analysis. Scenario object for single point analysis and GeospatialScenario object for geospatial analysis. See: ``scenario.Scenario`` and ``scenario.GeospatialScenario``
- Created Scenario tutorials to showcase new scenario functionality.
- Added a number of geospatial downselection functions. Find coordinates near mountains, rivers, coastlines and lakes from NSRDB data. See:
- ``geospatial.identify_mountains_weights``
- ``geospatial.identify_mountains_radii``
- ``geospatial.feature_downselect``
* Added geospatial bounding box support. Clip unwanted data with rectangular bounding boxes. See:
- ``geospatial.apply_bounding_box``
* Added stochastic non-uniform density downselection function to preferentially select for mountains (higher point density with changes in elevation, lower density when flatter.) See:
- ``geospatial.elevation_stochastic_downselection``
* Updated non-uniform downselection with thresholding and non-linear normalization (support for logarithmic and exponential normalization) See:
- ``geospatial.identify_mountains_weights``
* Added Scenario and GeospatialScenario methods for quick plotting and downselection. See:
- ``GeospatialScenario.plot_coords``
- ``GeospatialScenario.plot_meta_classification``
- ``GeospatialScenario.plot_USA``
- ``Scenario.extract``
- ``Scenario.plot``
- ``GeospatialScenario.classify_mountain_weights``
- ``GeospatialScenario.classify_mountain_radii``
- ``GeospatialScenario.downselect_elevation_stochastic``
* Added a convenience method ``GepspatialScenario.geospatial_data`` to quickly pull the geospatial weather and metadata from a scenario. Matches the API for ``pvdeg.weather.get``.

Geospatial Improvements

* Autotemplating system for geospatial analysis using `pvdeg.geospatial.autotemplate`.
* New module `pvdeg.decorators` that contains `pvdeg` specific decorator functions.
* Implemented `geospatial_result_type` decorator to update functions and preform runtime introspection to determine if a function is autotemplate-able.
* `Geospatial Templates.ipynb` notebook to showcase new and old templating functionality for users.
* Autotemplating system for geospatial analysis using ``pvdeg.geospatial.autotemplate``.
* New module ``pvdeg.decorators`` that contains ``pvdeg`` specific decorator functions.
* Implemented ``geospatial_result_type`` decorator to update functions and preform runtime introspection to determine if a function is autotemplate-able.
* ``Geospatial Templates.ipynb`` notebook to showcase new and old templating functionality for users.
* Implemented testing for geospatial analysis.
* Added chunked and unchunked testing.

Symbolic Evaluation

* symbolic equation solver for simple models.
* notebook tutorial `Custom-Functions-Nopython.ipynb`
* notebook tutorial ``Custom-Functions-Nopython.ipynb``

IEC-63126 Tool

* Added `GeospatialScenario` to standoff tool for regional analyses.
* Added ``GeospatialScenario`` to standoff tool for regional analyses.
* Increased plotting functionality within tool.

Bug Fixes
---------
* Added type hinting to many `pvdeg` functions
* Fixed broken keywords in many `pvdeg.standards` function calls
* Replaced deprecated numba `jit(nopython=True)` calls with `njit`
* Fix incorrect keyword arguments in `pvdeg.standards.T98_estimate`
* Added type hinting to many ``pvdeg`` functions
* Fixed broken keywords in many ``pvdeg.standards`` function calls
* Replaced deprecated numba ``jit(nopython=True)`` calls with ``njit``
* Fix incorrect keyword arguments in ``pvdeg.standards.T98_estimate``
* Fixed ``pvdeg.temperature.module`` and ``pvdeg.temperature.cell`` docstring return type. Correct return type ``pd.Series``
* Fixed broken Geospatial Analysis, when using chunked (dask) xarrays for weather data

Dependencies
------------
* `sympy` package required for `pvdeg.symbolic` functions and notebook. Not added to dependency list.
* ``sympy`` package required for ``pvdeg.symbolic`` functions and notebook. Not added to dependency list.
* Restrict the following dependencies to fix unit testing
* ``numpy==1.26.4``
* ``pvlib==0.10.3``
Expand Down
18 changes: 0 additions & 18 deletions docs/source/whatsnew/releases/v0.4.4.rst

This file was deleted.

52 changes: 52 additions & 0 deletions docs/source/whatsnew/releases/v0.5.0.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
v0.5.0 (2025-2-7)
===================

Enhancements
--------------
- New Logo!🎉🎉🎉
- Created utilities for parallelized downloads of ``PVGIS`` and ``NSRDB`` so users can download geospatial data for at home simulations. This will interface nicely with the soon to be released ``GeoGridStore``, allowing users to grow stores of geospatial data overtime as their needs grow for at-home, large-scale analyses.
- Documenation overhaul. Significant ``User Guide`` improvements. Added geospatial information with visual aids, added meteorological data page and materials access page.
- Suite of utility functions to facilitate accessing material parameter json files.
- Moved ``GeospatialScenario`` class definition to ``geospatialscenario.py``
- Remove kdtree as required argument from ``GeospatialScenario`` downselection methods, kdtree objects are now generated on the fly when required and saved to scenario object for future use.
- ``decorators.geospatial_quick_shape`` arguments modified. ``numeric_or_timeseries``, now takes a string ``('numeric', 'timeseries')`` to determine type of outputs rather than a ``Bool`` or ``Int``
- previously, ``0`` or ``False`` represented a numeric/scalar result, now this is represented by ``'numeric'``
- previosuly, ``1`` or ``True`` represented a timeseries result, now this is represented by ``'timeseries'``
- ``decorators.py`` namespace changed to default ``pvdeg`` namespace. now this can be directly accessed via ``pvdeg.decorators``. This reduces the need for an extra import.
- ``geospatial_quick_shape`` decorator namespace changed to defualt pvdeg namespace

Previously,

.. code-block:: Python
import pvdeg
from pvdeg.decorator import geospatial_quick_shape
@geospatial_quick_shape(0, ...)
def myfunc(...):
....
Now, either of the following options work.

.. code-block:: Python
import pvdeg
# now takes string instead of integer or boolean value
@pvdeg.decorators.geospatial_quick_shape('numeric', ...)
def myfunc(...):
....
.. code-block:: Python
# this is the style used in the PVDeg package implementations
import pvdeg.decorators
@decorators.geospatial_quick_shape('numeric', ...)
def myfunc(...):
....
Contributors
-----------
- Tobin Ford (:ghuser:`tobin-ford`)
1 change: 1 addition & 0 deletions pvdeg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

# from . import cli
from . import collection
from . import decorators
from . import degradation
from . import design
from . import fatigue
Expand Down
10 changes: 6 additions & 4 deletions pvdeg/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@
import inspect
import warnings

def geospatial_quick_shape(numeric_or_timeseries: bool, shape_names: list[str]) -> None:
def geospatial_quick_shape(numeric_or_timeseries: str, shape_names: list[str]) -> None:
"""
Add an attribute to the functions that can be run with geospatial analysis.
Strict typing is not enough for this purpose so we can view this attribute
at runtime to create a template for the function.
For single numeric results, includes tabular numeric data
>>> value = False (0)
>>> value = 'numeric'
Example if a function returns a dataframe with 1 row of numerics (not timeseries)
`pvdeg.standards.standoff` does this.
For timeseries results
>>> value = True (1)
>>> value = 'timeseries'
Example, `pvdeg.temperature.temperature`
Expand All @@ -35,7 +35,9 @@ def geospatial_quick_shape(numeric_or_timeseries: bool, shape_names: list[str])
>>> func.shape_names = ["T98", "x_eff"] # function attribute names
* Note: we cannot autotemplate functions with ambiguous return types that depend on runtime input,
the function will need strictly return a timeseries or numeric but not one or the other.
the function will need strictly return a timeseries or numeric.
* Note: this is accessed through the ``decorators.geospatial_quick_shape`` namespace
Parameters:
-----------
Expand Down
13 changes: 7 additions & 6 deletions pvdeg/degradation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
from concurrent.futures import ProcessPoolExecutor, as_completed
from typing import Union

from . import temperature
from . import spectral
from . import weather

from pvdeg.decorators import geospatial_quick_shape
from . import (
temperature,
spectral,
weather,
decorators,
)

# TODO: Clean up all those functions and add gaps functionality

Expand Down Expand Up @@ -236,7 +237,7 @@ def _to_eq_vantHoff(temp, Tf=1.41):
return Toeq


@geospatial_quick_shape(0, ["Iwa"])
@decorators.geospatial_quick_shape('numeric', ["Iwa"])
def IwaVantHoff(
weather_df,
meta,
Expand Down
9 changes: 6 additions & 3 deletions pvdeg/design.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
"""Collection of functions for PV module design considertations."""

from . import humidity
from pvdeg.decorators import geospatial_quick_shape
from . import (
humidity,
decorators
)

import pandas as pd


Expand Down Expand Up @@ -42,7 +45,7 @@ def edge_seal_ingress_rate(avg_psat):
return k


@geospatial_quick_shape(0, ["width"])
@decorators.geospatial_quick_shape('numeric', ["width"])
def edge_seal_width(
weather_df: pd.DataFrame,
meta: dict,
Expand Down
8 changes: 5 additions & 3 deletions pvdeg/fatigue.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import numpy as np
import pandas as pd
from scipy.constants import convert_temperature
from pvdeg import temperature
from pvdeg.decorators import geospatial_quick_shape

from pvdeg import (
temperature,
decorators
)

def _avg_daily_temp_change(time_range, temp_cell):
"""
Expand Down Expand Up @@ -98,7 +100,7 @@ def _times_over_reversal_number(temp_cell, reversal_temp):
return num_changes_temp_hist


@geospatial_quick_shape(0, ["damage"])
@decorators.geospatial_quick_shape('numeric', ["damage"])
def solder_fatigue(
weather_df: pd.DataFrame,
meta: dict,
Expand Down
10 changes: 4 additions & 6 deletions pvdeg/geospatial.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,15 +509,13 @@ def auto_template(func: Callable, ds_gids: xr.Dataset) -> xr.Dataset:
"""

can_auto_template(func=func)
# if not (hasattr(func, "numeric_or_timeseries") and hasattr(func, "shape_names")):
# raise ValueError(
# f"{func.__name__} cannot be autotemplated. create a template manually"
# )

if func.numeric_or_timeseries == 0:
if func.numeric_or_timeseries == 'numeric':
shapes = {datavar: ("gid",) for datavar in func.shape_names}
elif func.numeric_or_timeseries == 1:
elif func.numeric_or_timeseries == 'timeseries':
shapes = {datavar: ("gid", "time") for datavar in func.shape_names}
else:
raise ValueError(f"{func.__name__} 'numeric_or_timseries' attribute invalid. is {func.numeric_or_timeseries} should be 'numeric' or 'timeseries'")

template = output_template(ds_gids=ds_gids, shapes=shapes) # zeros_template?

Expand Down
9 changes: 4 additions & 5 deletions pvdeg/humidity.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
from pathlib import Path
from concurrent.futures import ProcessPoolExecutor, as_completed

from . import (
from pvdeg import (
temperature,
spectral,
weather
weather,
decorators
)

from pvdeg.decorators import geospatial_quick_shape


def _ambient(weather_df):
"""
Expand Down Expand Up @@ -654,7 +653,7 @@ def backsheet(
return backsheet


@geospatial_quick_shape(1, ["RH_surface_outside", "RH_front_encap", "RH_back_encap", "RH_backsheet"])
@decorators.geospatial_quick_shape('timeseries', ["RH_surface_outside", "RH_front_encap", "RH_back_encap", "RH_backsheet"])
def module(
weather_df,
meta,
Expand Down
13 changes: 9 additions & 4 deletions pvdeg/letid.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@
import pvlib


from pvdeg import collection, utilities, standards, DATA_DIR
from pvdeg.decorators import geospatial_quick_shape
from pvdeg import (
collection,
utilities,
standards,
decorators,
DATA_DIR,
)


def tau_now(tau_0, tau_deg, n_b):
Expand Down Expand Up @@ -872,8 +877,8 @@ def calc_injection_outdoors(results):
return injection


@geospatial_quick_shape(
1,
@decorators.geospatial_quick_shape(
'timeseries',
[
"Temperature",
"Injection",
Expand Down
11 changes: 5 additions & 6 deletions pvdeg/spectral.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@

import pvlib
import pandas as pd
from pvdeg.decorators import geospatial_quick_shape
from pvdeg import decorators


@geospatial_quick_shape(
1,
@decorators.geospatial_quick_shape(
'timeseries',
[
"apparent_zenith",
"zenith",
Expand Down Expand Up @@ -54,8 +53,8 @@ def solar_position(weather_df: pd.DataFrame, meta: dict) -> pd.DataFrame:
return solar_position


@geospatial_quick_shape(
1,
@decorators.geospatial_quick_shape(
'timeseries',
[
"poa_global",
"poa_direct",
Expand Down
Loading

0 comments on commit 3bad5ce

Please sign in to comment.