From f3bf79ff1e9509a453e9e6c691315291b7c124ed Mon Sep 17 00:00:00 2001 From: Alireza Aghamohammadi Date: Mon, 11 Dec 2023 19:41:52 +0330 Subject: [PATCH] Add docs to the project - Provide sphinx documentation for the pysolorie project. For now it just contains the module's docs. --- docs/Makefile | 20 ++++++++++ docs/conf.py | 21 ++++++++++ docs/index.rst | 22 ++++++++++ docs/make.bat | 35 ++++++++++++++++ docs/reference/modules.rst | 7 ++++ .../pysolorie.atmospheric_transmission.rst | 7 ++++ docs/reference/pysolorie.irradiance.rst | 7 ++++ docs/reference/pysolorie.model.rst | 7 ++++ .../pysolorie.numerical_integration.rst | 7 ++++ docs/reference/pysolorie.observer.rst | 7 ++++ docs/reference/pysolorie.rst | 20 ++++++++++ docs/reference/pysolorie.sun_position.rst | 7 ++++ setup.cfg | 14 +++++++ src/pysolorie/atmospheric_transmission.py | 23 +++++------ src/pysolorie/irradiance.py | 28 +++++++------ src/pysolorie/model.py | 26 +++++++----- src/pysolorie/numerical_integration.py | 40 +++++++++++-------- src/pysolorie/observer.py | 26 ++++++------ src/pysolorie/sun_position.py | 15 +++---- 19 files changed, 268 insertions(+), 71 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/make.bat create mode 100644 docs/reference/modules.rst create mode 100644 docs/reference/pysolorie.atmospheric_transmission.rst create mode 100644 docs/reference/pysolorie.irradiance.rst create mode 100644 docs/reference/pysolorie.model.rst create mode 100644 docs/reference/pysolorie.numerical_integration.rst create mode 100644 docs/reference/pysolorie.observer.rst create mode 100644 docs/reference/pysolorie.rst create mode 100644 docs/reference/pysolorie.sun_position.rst diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..3ee3024 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,21 @@ +project = "pysolorie" +copyright = "2023, Alireza Aghamohammadi" +author = "Alireza Aghamohammadi" + + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autodoc.typehints", + "sphinx.ext.viewcode", +] + + +pygments_style = "sphinx" + +templates_path = ["_templates"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] +autoclass_content = "both" + + +html_theme = "sphinx_rtd_theme" +html_static_path = ["_static"] diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..ac52444 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,22 @@ +.. pysolorie documentation master file, created by + sphinx-quickstart on Sun Dec 10 14:02:09 2023. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to pysolorie's documentation! +===================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + reference/modules + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..32bb245 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/reference/modules.rst b/docs/reference/modules.rst new file mode 100644 index 0000000..b0bc4b4 --- /dev/null +++ b/docs/reference/modules.rst @@ -0,0 +1,7 @@ +pysolorie +========= + +.. toctree:: + :maxdepth: 4 + + pysolorie diff --git a/docs/reference/pysolorie.atmospheric_transmission.rst b/docs/reference/pysolorie.atmospheric_transmission.rst new file mode 100644 index 0000000..8aa0927 --- /dev/null +++ b/docs/reference/pysolorie.atmospheric_transmission.rst @@ -0,0 +1,7 @@ +pysolorie.atmospheric\_transmission module +========================================== + +.. automodule:: pysolorie.atmospheric_transmission + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/pysolorie.irradiance.rst b/docs/reference/pysolorie.irradiance.rst new file mode 100644 index 0000000..079a24c --- /dev/null +++ b/docs/reference/pysolorie.irradiance.rst @@ -0,0 +1,7 @@ +pysolorie.irradiance module +=========================== + +.. automodule:: pysolorie.irradiance + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/pysolorie.model.rst b/docs/reference/pysolorie.model.rst new file mode 100644 index 0000000..3b3e480 --- /dev/null +++ b/docs/reference/pysolorie.model.rst @@ -0,0 +1,7 @@ +pysolorie.model module +====================== + +.. automodule:: pysolorie.model + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/pysolorie.numerical_integration.rst b/docs/reference/pysolorie.numerical_integration.rst new file mode 100644 index 0000000..6ca854c --- /dev/null +++ b/docs/reference/pysolorie.numerical_integration.rst @@ -0,0 +1,7 @@ +pysolorie.numerical\_integration module +======================================= + +.. automodule:: pysolorie.numerical_integration + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/pysolorie.observer.rst b/docs/reference/pysolorie.observer.rst new file mode 100644 index 0000000..a497b52 --- /dev/null +++ b/docs/reference/pysolorie.observer.rst @@ -0,0 +1,7 @@ +pysolorie.observer module +========================= + +.. automodule:: pysolorie.observer + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/pysolorie.rst b/docs/reference/pysolorie.rst new file mode 100644 index 0000000..fe5ce02 --- /dev/null +++ b/docs/reference/pysolorie.rst @@ -0,0 +1,20 @@ +pysolorie package +================= + +.. automodule:: pysolorie + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + pysolorie.atmospheric_transmission + pysolorie.irradiance + pysolorie.model + pysolorie.numerical_integration + pysolorie.observer + pysolorie.sun_position diff --git a/docs/reference/pysolorie.sun_position.rst b/docs/reference/pysolorie.sun_position.rst new file mode 100644 index 0000000..96416cf --- /dev/null +++ b/docs/reference/pysolorie.sun_position.rst @@ -0,0 +1,7 @@ +pysolorie.sun\_position module +============================== + +.. automodule:: pysolorie.sun_position + :members: + :undoc-members: + :show-inheritance: diff --git a/setup.cfg b/setup.cfg index 287b8ec..d49087e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -88,3 +88,17 @@ deps = flake8-bugbear commands = flake8 {posargs:src tests} + +[testenv:docs] +deps = + sphinx + sphinx-rtd-theme +commands = + sphinx-apidoc \ + --force \ + --implicit-namespaces \ + --module-first \ + --separate \ + -o docs/reference/ \ + src/pysolorie/ + sphinx-build -W -b html docs/ docs/_build/ diff --git a/src/pysolorie/atmospheric_transmission.py b/src/pysolorie/atmospheric_transmission.py index cbec258..2d4a29a 100644 --- a/src/pysolorie/atmospheric_transmission.py +++ b/src/pysolorie/atmospheric_transmission.py @@ -18,11 +18,6 @@ class AtmosphericTransmission: - """ - This class calculates the effective atmospheric transmission coefficient - of the direct beam. - """ - def __init__( self, climate_type: str, @@ -30,7 +25,9 @@ def __init__( observer_latitude: float, ): r""" - Initialize the AtmosphericTransmission class. + To instantiate the ``AtmosphericTransmission`` class, + provide the following three parameters. + :param climate_type: The type of climate. :type climate_type: str @@ -57,13 +54,14 @@ def calculate_transmittance(self, day_of_year: int, solar_time: float) -> float: is calculated using the formula: .. math:: - \tau_b = a_0 + a_1 \cdot \exp\left(-\frac{k}{\cos(\theta_z)}\right) + \tau_b = a_0 + a_1 \times \exp\left(-\frac{k}{\cos(\theta_z)}\right) - where: - \(\tau_b\) is the effective atmospheric transmission coefficient - of the direct beam, \(a_0\), \(a_1\), and \(k\) - are the components of clear-sky beam radiation transmittance, - and \(\theta_z\) is the zenith angle. + + | - :math:`\tau_b` is the effective atmospheric transmission + coefficient of the direct beam + | - :math:`a_0`, :math:`a_1`, and :math:`k` are the components + of clear-sky beam radiation transmittance + | - :math:`\theta_z` is the zenith angle :param day_of_year: The day of the year. :type day_of_year: int @@ -72,6 +70,7 @@ def calculate_transmittance(self, day_of_year: int, solar_time: float) -> float: :return: The effective atmospheric transmission coefficient of the direct beam. :rtype: float """ + zenith_angle = self.observer.calculate_zenith_angle(day_of_year, solar_time) cos_zenith_angle = math.cos(zenith_angle) EPSILON = 1e-8 # Small constant to prevent division by zero diff --git a/src/pysolorie/irradiance.py b/src/pysolorie/irradiance.py index 1b04a10..3455c6a 100644 --- a/src/pysolorie/irradiance.py +++ b/src/pysolorie/irradiance.py @@ -20,10 +20,11 @@ class SolarIrradiance: def __init__(self, sun_position: SunPosition): r""" - Initialize the SolarIrradiance class. + To instantiate the ``SolarIrradiance`` class, provide the following parameter. + :param sun_position: An instance of the SunPosition class. - :type sun_position: SunPosition + :type sun_position: pysolorie.SunPosition """ self.sun_position = sun_position @@ -38,17 +39,18 @@ def calculate_extraterrestrial_irradiance(self, day_of_year: int) -> float: The formula used is: .. math:: - - E = \text{{SOLAR\_CONSTANT}} - \times (1 + 0.33 \times \cos (2 - \times \pi \times \frac{{\text{{day\_of\_year}}}}{365})) - - where: - \(\text{{SOLAR\_CONSTANT}}\) is the average solar radiation arriving outside - of the Earth's atmosphere, which is approximately 1367 Watts per square meter. - This is also known as the solar constant.The factor 0.033 accounts - for the variation in the Earth-Sun distance - due to the Earth's elliptical orbit. + E = SC + \times (1 + 0.33 \times \cos (\frac{2\pi~n}{365})) + + + | - :math:`SC` is the average solar radiation arriving outside + of the Earth's atmosphere, + which is approximately ``1367`` Watts per square meter. + This is also known as the solar constant. + | - The factor ``0.033`` accounts + for the variation in the Earth-Sun distance + due to the Earth's elliptical orbit. + | - :math:`n` is the day of the year (i.e., ``day_of_year``) :param day\_of\_year: The day of the year, ranging from 1 to 365. :type day\_of\_year: int diff --git a/src/pysolorie/model.py b/src/pysolorie/model.py index dec37a8..a20aeb1 100644 --- a/src/pysolorie/model.py +++ b/src/pysolorie/model.py @@ -20,8 +20,8 @@ class HottelModel: Hottel Model for estimating clear-sky beam radiation transmittance based on climate type, and observer altitude. - :ivar CLIMATE_CONSTANTS: Correction factors for different climate types - (\(r_0\), \(r_1\), and \(r_k\)). + ``CLIMATE_CONSTANTS``: Correction factors for different climate types + :math:`r_0`, :math:`r_1`, and :math:`r_k`. """ CLIMATE_CONSTANTS: Dict[str, Tuple[float, float, float]] = { @@ -101,23 +101,29 @@ def calculate_transmittance_components( ) -> Tuple[float, float, float]: r""" Calculate the components of clear-sky beam radiation transmittance - (\(a_0\), \(a_1\), and \(k\)) based on climate type and observer altitude. + :math:`a_0`, :math:`a_1`, and :math:`k` + based on climate type and observer altitude. - Correction factors adjust the clear-sky beam radiation transmittance components. - The formulas used to calculate the components are: + Correction factors adjust the clear-sky beam + radiation transmittance components. According + to the following formulas: .. math:: - a_0 = r_0 \cdot a_0^* - a_1 = r_1 \cdot a_1^* - k = r_k \cdot k^* + a_0 = r_0 \times a_0^* - :param climate_type: Climate type (e.g., "TROPICAL"). + a_1 = r_1 \times a_1^* + + k = r_k \times k^* + + :param climate_type: Climate type + (i.e., ``TROPICAL``, ``MIDLATITUDE SUMMER``, + ``SUBARCTIC SUMMER``, or ``MIDLATITUDE WINTER``). :type climate_type: str :param observer_altitude: Altitude of the observer in meters. :type observer_altitude: float :return: Components of clear-sky beam radiation transmittance - (\(a_0\), \(a_1\), \(k\)). + (:math:`a_0`, :math:`a_1`, :math:`k`). :rtype: tuple of floats :raises ValueError: If an invalid climate type is provided. """ diff --git a/src/pysolorie/numerical_integration.py b/src/pysolorie/numerical_integration.py index 0ab1b55..6e0c81e 100644 --- a/src/pysolorie/numerical_integration.py +++ b/src/pysolorie/numerical_integration.py @@ -30,7 +30,8 @@ def __init__( self, climate_type: str, observer_altitude: int, observer_latitude: float ): """ - Initialize the IrradiationCalculator class. + To instantiate the ``IrradiationCalculator`` class, + provide the following three parameters. :param climate_type: The type of climate. :type climate_type: str @@ -99,24 +100,30 @@ def calculate_direct_irradiation( ) -> float: r""" Calculate the total direct irradiation - for a given solar panel orientation (beta). + for a given solar panel orientation (i.e., :math:`\beta`). - The total direct irradiation is calculated using the formula: + | The total direct irradiation is calculated using the formula: .. math:: - E_b(n,\phi) = \frac{E}{\Omega} \int_{\omega_s}^{\omega_t} - \cos(θ) H(\cos(θ)) \times \tau_b d\omega + E(n,\phi) = \frac{E}{\Omega} \int_{\omega_s}^{\omega_t} + \cos(\theta) \times H(\cos(\theta)) \times \tau_b~d\omega - where: - n is the day of year - \(\phi\) is the latitude of the observer, and - \(E\) is the amount of solar energy received - \Omega is a constant equal to 7.15 * 1e-5 - theta is incidence angle - \omega_s is the sunrise hour angle - \omega_t is the sunset hour angle - H is the heaviside step function + | - :math:`n` is the day of year (i.e., ``day_of_year``) + + | - :math:`\phi` is the latitude of the observer + + | - :math:`E` is the amount of solar energy received + + | - :math:`\Omega` is a constant equal to ``7.15 * 1e-5`` + + | - :math:`\theta` is incidence angle + + | - :math:`\omega_s` is the sunrise hour angle + + | - :math:`\omega_t` is the sunset hour angle + + | - :math:`H` is the heaviside step function :param panel_orientation: The orientation of the solar panel in radians. @@ -139,11 +146,12 @@ def calculate_direct_irradiation( def find_optimal_orientation(self, day_of_year: int) -> float: """ - Find the optimal orientation (beta) that maximizes the total direct irradiation. + Find the optimal orientation :math:`beta` that maximizes + the total direct irradiation. :param day_of_year: The day of the year. :type day_of_year: int - :return: The optimal orientation (beta) in degrees. + :return: The optimal orientation (i.e., :math:`beta`) in degrees. :rtype: float """ betas = np.arange(-math.pi / 2, math.pi / 2, 0.005) # Discretize beta diff --git a/src/pysolorie/observer.py b/src/pysolorie/observer.py index 051eb70..a93416b 100644 --- a/src/pysolorie/observer.py +++ b/src/pysolorie/observer.py @@ -25,7 +25,7 @@ def __init__( observer_longitude: Optional[float] = None, ): """ - Initialize the Observer class. + To instantiate the ``Observer`` class, provide the following parameter. :param observer_latitude: The latitude of the observer in degrees (optional). :type observer_latitude: Optional[float] @@ -47,14 +47,14 @@ def calculate_zenith_angle(self, day_of_year: int, solar_time: float) -> float: The zenith angle is calculated using the formula: .. math:: - \cos(\theta_z) = \sin(\phi) \cdot \sin(\delta) - + \cos(\phi) \cdot \cos(\delta) \cdot \cos(\omega) + \cos(\theta_z) = \sin(\phi) \times \sin(\delta) + + \cos(\phi) \times \cos(\delta) \times \cos(\omega) - where: - \(\theta_z\) is the zenith angle, - \(\phi\) is the latitude of the observer, - \(\delta\) is the solar declination, and - \(\omega\) is the hour angle. + + | - :math:`\theta_z` is the zenith angle + | - :math:`\phi` is the latitude of the observer + | - :math:`\delta` is the solar declination + | - :math:`\omega` is the hour angle. :param day_of_year: The day of the year. :type day_of_year: int @@ -81,12 +81,12 @@ def calculate_sunrise_sunset(self, day_of_year: int) -> tuple: The hour angle at sunrise and sunset is calculated using the formula: .. math:: - \cos(\omega) = -\tan(\phi) \cdot \tan(\delta) + \cos(\omega) = -\tan(\phi) \times \tan(\delta) + - where: - \(\omega\) is the hour angle, - \(\phi\) is the latitude of the observer, and - \(\delta\) is the solar declination. + | - :math:`\omega` is the hour angle + | - :math:`\phi` is the latitude of the observer + | - :math:`\delta` is the solar declination. :param day_of_year: The day of the year. :type day_of_year: int diff --git a/src/pysolorie/sun_position.py b/src/pysolorie/sun_position.py index 62af9ac..aee67e0 100644 --- a/src/pysolorie/sun_position.py +++ b/src/pysolorie/sun_position.py @@ -25,9 +25,10 @@ def solar_declination(self, day_of_year: int) -> float: The formula used to calculate the solar declination angle is: .. math:: - \delta = \sin \left( \frac{2 \pi}{365} - \times (284 + \text{{day\_of\_year}}) \right) - \times \left(\frac{23.45 \pi}{180}\right) + \delta = \frac{23.45 \pi}{180} \times + \sin \left(\frac{2\pi~(284 + n)}{365}\right) + + | :math:`n` is the day of the year (i.e., ``day_of_year``) :param day_of_year: The day of the year. :type day_of_year: int @@ -61,8 +62,8 @@ def hour_angle(self, solar_time: float) -> float: The formula used to calculate the hour angle is: .. math:: - \omega = (t - \text{{seconds\_in\_half\_day}}) - \times \frac{\pi}{\text{{seconds\_in\_half\_day}}} + \omega = (t - 12\times 60 \times 60) + \times \frac{\pi}{12\times 60 \times 60} :param solar_time: The solar time in seconds. :type solar_time: float @@ -89,8 +90,8 @@ def solar_time(self, hour_angle: float) -> float: The formula used to calculate the solar time is: .. math:: - t = \omega \times \frac{\text{{seconds\_in\_half\_day}}}{\pi} - + \text{{seconds\_in\_half\_day}} + t = \omega \times \frac{12 \times 60 \times 60}{\pi} + + 12 \times 60 \times 60 :param hour_angle: The hour angle in radians. :type hour_angle: float