From d51b86e7b13b7cb916b8e584ca3fb39571514c39 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 5 Feb 2026 16:19:52 -0500 Subject: [PATCH 1/7] first draft --- docs/sphinx/source/user_guide/index.rst | 1 + .../source/user_guide/modeling_topics/iam.rst | 87 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 docs/sphinx/source/user_guide/modeling_topics/iam.rst diff --git a/docs/sphinx/source/user_guide/index.rst b/docs/sphinx/source/user_guide/index.rst index f8da3b6b44..af2a4cbb92 100644 --- a/docs/sphinx/source/user_guide/index.rst +++ b/docs/sphinx/source/user_guide/index.rst @@ -27,6 +27,7 @@ This user guide is an overview and explains some of the key features of pvlib. modeling_topics/weather_data modeling_topics/singlediode modeling_topics/temperature + modeling_topics/iam .. toctree:: :maxdepth: 2 diff --git a/docs/sphinx/source/user_guide/modeling_topics/iam.rst b/docs/sphinx/source/user_guide/modeling_topics/iam.rst new file mode 100644 index 0000000000..0d89b14964 --- /dev/null +++ b/docs/sphinx/source/user_guide/modeling_topics/iam.rst @@ -0,0 +1,87 @@ +.. _iam: + + +Incidence angle modifier +======================== + +Some fraction of the light incident on a PV module surface is reflected away or +absorbed before it reaches the PV cell. This irradiance reduction depends +on the angle at which the light strikes the module (the angle of incidence, +:term:`aoi`) and the optical properties of the module. + +Some reduction occurs at all angles of incidence, even normal incidence. +However, because PV module testing is performed at normal incidence, +the reduction at normal incidence is implicit in the PV module's power rating +and does not need to be accounted for separately in a performance model. +Therefore, only the extra reduction at non-normal incidence should be modeled. + +This is done using incidence angle modififer (:term:`IAM`) models. IAM is +the fraction of incident light that is transmitted to the PV cell, normalized +to the value at normal incidence: + +.. math:: + + IAM(\theta) = \frac{T(\theta)}{T(0)}, + +where $T(\theta)$ represents the transmitted light fraction at AOI $\theta$. +IAM equals (by definition) 1.0 when AOI is zero and typically approaches zero +as AOI approaches 90 degrees. The shape of the IAM profile at intermediate AOI +is nonlinear and depends on the module's optical properties. + +In pvlib, IAM is a unitless quantity (values from 0–1) and IAM functions take +input angles in degrees. + + +Types of models +--------------- + +IAM is sometimes applied only to the beam component of in-plane irradiance, as +the beam component is often the largest contributor to total in-plane +irradiance and has a highly variable AOI across the day and year. However, +in principle IAM should be applied to diffuse irradiance as well. Modeling IAM +for diffuse irradiance is complicated by the light coming from a range +of angles. IAM for direct irradiance is comparatively straightforward +because the entire component has a single angle of incidence. + +The IAM models currently available in pvlib are summarized in the +following table: + ++-------------------------------------------+---------+-------------------------------------------+ +| Model | Type | Notes | ++===========================================+=========+===========================================+ +| :py:func:`~pvlib.iam.ashrae` | direct | Once common, now less used | ++-------------------------------------------+---------+-------------------------------------------+ +| :py:func:`~pvlib.iam.martin_ruiz` | direct | Used in the IEC 61853 standard | ++-------------------------------------------+---------+-------------------------------------------+ +| :py:func:`~pvlib.iam.martin_ruiz_diffuse` | diffuse | Used in the IEC 61853 standard | ++-------------------------------------------+---------+-------------------------------------------+ +| :py:func:`~pvlib.iam.physical` | direct | Physics-based; optional AR coating | ++-------------------------------------------+---------+-------------------------------------------+ +| :py:func:`~pvlib.iam.sapm` | direct | Can exhibit "wiggles" in the curve | ++-------------------------------------------+---------+-------------------------------------------+ +| :py:func:`~pvlib.iam.schlick` | direct | Does not take module-specific parameters | ++-------------------------------------------+---------+-------------------------------------------+ +| :py:func:`~pvlib.iam.schlick_diffuse` | diffuse | Does not take module-specific parmaeters | ++-------------------------------------------+---------+-------------------------------------------+ + +In addition to the core models above, pvlib provides several other functions +for IAM modeling: + +- :py:func:`~pvlib.iam.interp`: interpolate between points on a measured IAM profile +- :py:func:`~pvlib.iam.marion_diffuse` and :py:func:`~pvlib.iam.marion_integrate`: + numerically integrate any IAM model across AOI to compute sky, horizon, and ground IAMs + + +Model parameters +---------------- + +Some IAM model functions provide default values for their parameters. +However, these generic values may not be suitable for all modules. +It should be noted that using the default parameter values for each +model generally leads to different IAM profiles. + +Module-specific values can be obtained via testing. For example, IEC 61853-2 +testing produces measured IAM values across the range of AOI and a corresponding +parameter value for the Martin-Ruiz model. Parameters for other models can +be determined using :py:func:`pvlib.iam.fit`. Parameters can be (approximately) +converted between models using :py:func:`pvlib.iam.convert`. From 9c6a0cd76c2389c2a6f33e55c23281e7b1c4fbd6 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Thu, 5 Feb 2026 16:32:59 -0500 Subject: [PATCH 2/7] tweaks --- docs/sphinx/source/user_guide/modeling_topics/iam.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sphinx/source/user_guide/modeling_topics/iam.rst b/docs/sphinx/source/user_guide/modeling_topics/iam.rst index 0d89b14964..a55a3f351b 100644 --- a/docs/sphinx/source/user_guide/modeling_topics/iam.rst +++ b/docs/sphinx/source/user_guide/modeling_topics/iam.rst @@ -23,7 +23,7 @@ to the value at normal incidence: IAM(\theta) = \frac{T(\theta)}{T(0)}, -where $T(\theta)$ represents the transmitted light fraction at AOI $\theta$. +where :math:`T(\theta)` represents the transmitted light fraction at AOI :math:`\theta`. IAM equals (by definition) 1.0 when AOI is zero and typically approaches zero as AOI approaches 90 degrees. The shape of the IAM profile at intermediate AOI is nonlinear and depends on the module's optical properties. @@ -82,6 +82,6 @@ model generally leads to different IAM profiles. Module-specific values can be obtained via testing. For example, IEC 61853-2 testing produces measured IAM values across the range of AOI and a corresponding -parameter value for the Martin-Ruiz model. Parameters for other models can -be determined using :py:func:`pvlib.iam.fit`. Parameters can be (approximately) +parameter value for the Martin-Ruiz model. Parameter values for other models can +be determined using :py:func:`pvlib.iam.fit`. Parameter values can also be (approximately) converted between models using :py:func:`pvlib.iam.convert`. From 6f09542435e568a6b1c155296d18c0d2e69920d1 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Tue, 10 Feb 2026 09:26:49 -0500 Subject: [PATCH 3/7] Apply suggestions from code review Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> Co-authored-by: Cliff Hansen Co-authored-by: Rajiv Daxini <143435106+RDaxini@users.noreply.github.com> Co-authored-by: Anton Driesse --- docs/sphinx/source/user_guide/modeling_topics/iam.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/sphinx/source/user_guide/modeling_topics/iam.rst b/docs/sphinx/source/user_guide/modeling_topics/iam.rst index a55a3f351b..974885a272 100644 --- a/docs/sphinx/source/user_guide/modeling_topics/iam.rst +++ b/docs/sphinx/source/user_guide/modeling_topics/iam.rst @@ -7,10 +7,10 @@ Incidence angle modifier Some fraction of the light incident on a PV module surface is reflected away or absorbed before it reaches the PV cell. This irradiance reduction depends on the angle at which the light strikes the module (the angle of incidence, -:term:`aoi`) and the optical properties of the module. +:term:`AOI `) and the optical properties of the module. Some reduction occurs at all angles of incidence, even normal incidence. -However, because PV module testing is performed at normal incidence, +However, because PV modules are rated with irradiance at normal incidence, the reduction at normal incidence is implicit in the PV module's power rating and does not need to be accounted for separately in a performance model. Therefore, only the extra reduction at non-normal incidence should be modeled. @@ -25,7 +25,7 @@ to the value at normal incidence: where :math:`T(\theta)` represents the transmitted light fraction at AOI :math:`\theta`. IAM equals (by definition) 1.0 when AOI is zero and typically approaches zero -as AOI approaches 90 degrees. The shape of the IAM profile at intermediate AOI +as AOI approaches 90°. The shape of the IAM profile at intermediate AOI is nonlinear and depends on the module's optical properties. In pvlib, IAM is a unitless quantity (values from 0–1) and IAM functions take @@ -76,12 +76,12 @@ Model parameters ---------------- Some IAM model functions provide default values for their parameters. -However, these generic values may not be suitable for all modules. +However, these generic values may not be suitable for all PV modules. It should be noted that using the default parameter values for each model generally leads to different IAM profiles. Module-specific values can be obtained via testing. For example, IEC 61853-2 testing produces measured IAM values across the range of AOI and a corresponding parameter value for the Martin-Ruiz model. Parameter values for other models can -be determined using :py:func:`pvlib.iam.fit`. Parameter values can also be (approximately) +be determined using :py:func:`pvlib.iam.fit`. Parameter values can also be approximately converted between models using :py:func:`pvlib.iam.convert`. From cf10fc894a98c53380917b8f0ab0975e6234dbb8 Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Tue, 10 Feb 2026 10:04:06 -0500 Subject: [PATCH 4/7] Further edits from review --- .../source/user_guide/modeling_topics/iam.rst | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/docs/sphinx/source/user_guide/modeling_topics/iam.rst b/docs/sphinx/source/user_guide/modeling_topics/iam.rst index 974885a272..2c820aaa60 100644 --- a/docs/sphinx/source/user_guide/modeling_topics/iam.rst +++ b/docs/sphinx/source/user_guide/modeling_topics/iam.rst @@ -15,9 +15,9 @@ the reduction at normal incidence is implicit in the PV module's power rating and does not need to be accounted for separately in a performance model. Therefore, only the extra reduction at non-normal incidence should be modeled. -This is done using incidence angle modififer (:term:`IAM`) models. IAM is -the fraction of incident light that is transmitted to the PV cell, normalized -to the value at normal incidence: +This is done using incidence angle modififer (:term:`IAM`) models. +Conceptually, IAM is the fraction of incident light that is +transmitted to the PV cell, normalized to the value at normal incidence: .. math:: @@ -28,6 +28,10 @@ IAM equals (by definition) 1.0 when AOI is zero and typically approaches zero as AOI approaches 90°. The shape of the IAM profile at intermediate AOI is nonlinear and depends on the module's optical properties. +IAM may also depend on the wavelength of the light, the polarization of the light, +and which side of the module the light comes from. However, IAM models usually +neglect these minor effects. + In pvlib, IAM is a unitless quantity (values from 0–1) and IAM functions take input angles in degrees. @@ -35,13 +39,22 @@ input angles in degrees. Types of models --------------- -IAM is sometimes applied only to the beam component of in-plane irradiance, as -the beam component is often the largest contributor to total in-plane -irradiance and has a highly variable AOI across the day and year. However, -in principle IAM should be applied to diffuse irradiance as well. Modeling IAM -for diffuse irradiance is complicated by the light coming from a range -of angles. IAM for direct irradiance is comparatively straightforward -because the entire component has a single angle of incidence. +Because total in-plane irradiance is the combination of light from many +directions, IAM values are computed for each component separately: + +- *direct IAM*: IAM computed for the AOI of direct irradiance +- *circumsolar IAM*: typically approximated as equal to the direct IAM +- *diffuse IAM*: IAM integrated across the ranges of AOI spanning the sky and/or + ground surfaces + +Because diffuse light can be thought of as a field of many small beams of +direct light, diffuse IAM can then be understood as the IAM averaged across +those individual beams. This averaging can be done explicitly or empirically. + +In principle, IAM should be applied to all components of incident irradiance. +In practice, IAM is sometimes applied only to the direct component of in-plane +irradiance, as the direct component is often the largest contributor to total +in-plane irradiance and has a highly variable AOI across the day and year. The IAM models currently available in pvlib are summarized in the following table: @@ -57,7 +70,7 @@ following table: +-------------------------------------------+---------+-------------------------------------------+ | :py:func:`~pvlib.iam.physical` | direct | Physics-based; optional AR coating | +-------------------------------------------+---------+-------------------------------------------+ -| :py:func:`~pvlib.iam.sapm` | direct | Can exhibit "wiggles" in the curve | +| :py:func:`~pvlib.iam.sapm` | direct | Can be non-monotonic and exceed 1.0 | +-------------------------------------------+---------+-------------------------------------------+ | :py:func:`~pvlib.iam.schlick` | direct | Does not take module-specific parameters | +-------------------------------------------+---------+-------------------------------------------+ From ddd6b754434ca674b84380864abe8618747612ea Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Tue, 10 Feb 2026 10:08:31 -0500 Subject: [PATCH 5/7] whatsnew --- docs/sphinx/source/whatsnew/v0.15.1.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/sphinx/source/whatsnew/v0.15.1.rst b/docs/sphinx/source/whatsnew/v0.15.1.rst index 5cd4131c85..48e714acc6 100644 --- a/docs/sphinx/source/whatsnew/v0.15.1.rst +++ b/docs/sphinx/source/whatsnew/v0.15.1.rst @@ -24,6 +24,7 @@ Enhancements Documentation ~~~~~~~~~~~~~ +* Provide an overview of IAM modeling functionality in :ref:`iam`. (GH2565) Testing @@ -45,4 +46,9 @@ Maintenance Contributors ~~~~~~~~~~~~ * Aman Srivastava (:ghuser:`aman-coder03`) +* Rajiv Daxini (:ghuser:`RDaxini`) +* Echedey Luis (:ghuser:`echedey-ls`) +* Cliff Hansen (:ghuser:`cwhanse`) +* Anton Driesse (:ghuser:`adriesse`) +* Kevin Anderson (:ghuser:`kandersolar`) From 3a107d57de8a833889cdda7b91cfc3e3cabf8f5d Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Tue, 10 Feb 2026 10:11:43 -0500 Subject: [PATCH 6/7] fix PR number in whatsnew --- docs/sphinx/source/whatsnew/v0.15.1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/whatsnew/v0.15.1.rst b/docs/sphinx/source/whatsnew/v0.15.1.rst index 48e714acc6..9955df7473 100644 --- a/docs/sphinx/source/whatsnew/v0.15.1.rst +++ b/docs/sphinx/source/whatsnew/v0.15.1.rst @@ -24,7 +24,7 @@ Enhancements Documentation ~~~~~~~~~~~~~ -* Provide an overview of IAM modeling functionality in :ref:`iam`. (GH2565) +* Provide an overview of IAM modeling functionality in :ref:`iam`. (:pull:`2683`) Testing From 1fa81472fbf0c8e87556c80d6fc0b260e920618c Mon Sep 17 00:00:00 2001 From: Kevin Anderson Date: Tue, 10 Feb 2026 14:34:02 -0500 Subject: [PATCH 7/7] Apply suggestions from code review Co-authored-by: Anton Driesse --- docs/sphinx/source/user_guide/modeling_topics/iam.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sphinx/source/user_guide/modeling_topics/iam.rst b/docs/sphinx/source/user_guide/modeling_topics/iam.rst index 2c820aaa60..ecd591133e 100644 --- a/docs/sphinx/source/user_guide/modeling_topics/iam.rst +++ b/docs/sphinx/source/user_guide/modeling_topics/iam.rst @@ -17,7 +17,7 @@ Therefore, only the extra reduction at non-normal incidence should be modeled. This is done using incidence angle modififer (:term:`IAM`) models. Conceptually, IAM is the fraction of incident light that is -transmitted to the PV cell, normalized to the value at normal incidence: +transmitted to the PV cell, normalized to the fraction transmitted at normal incidence: .. math:: @@ -32,8 +32,8 @@ IAM may also depend on the wavelength of the light, the polarization of the ligh and which side of the module the light comes from. However, IAM models usually neglect these minor effects. -In pvlib, IAM is a unitless quantity (values from 0–1) and IAM functions take -input angles in degrees. +IAM functions in pvlib take an input angle in degrees and return a unitless ratio +in the range 0–1. Types of models