Most of the work on Phase 1 of the project is now complete, with only a few final loose ends remaining before I fully transition to Phase 2. Over the past few weeks, the focus has been on standardizing support for diffuse irradiance components across pvlib’s transposition models and ensuring that this information can be propagated through the higher-level irradiance APIs.

Recently merged work

A couple of smaller pull requests have already been merged:

  • Updating existing transposition models (perez and perez_driesse) to use standard dictionaries instead of OrderedDicts when return_components=True.
  • Removing the horizon component from haydavies, which was always zero. All sky diffuse functions will return only the components supported by their respective model.

The Klucher Question

The most interesting discussion during this phase ended up revolving around the Klucher transposition model.

Unlike the other models, Klucher’s formulation is built around isotropic, horizon brightening, and circumsolar effects, but these contributions are not naturally separable because the correction terms are multiplied together:

$I_d = \mathrm{DHI} \frac{1 + \cos\beta}{2} \left(1 + F’ \sin^3\left(\frac{\beta}{2}\right)\right)\left(1 + F’ \cos^2\theta \sin^3\theta_z\right)$

If we define:

  • Isotropic component: $I = \frac{1 + \cos\beta}{2}$
  • Horizon brightening term: $h = F’ \sin^3\left(\frac{\beta}{2}\right)$
  • Circumsolar term: $c = F’ \cos^2\theta \sin^3\theta_z$

then the expression becomes:

$I (1+h) (1+c) = I (1+c+h+hc)$

The challenge is the $hc$ term. Separating the irradiance into individual components would require deciding how to allocate this interaction term between the horizon and circumsolar contributions.

One possible approach would be to distribute it proportionally between the two components. However, doing so would introduce an assumption that is not present in the original formulation. Although this interaction term generally represents only a small fraction of the total irradiance (see plot below), it would still constitute a meaningful departure from the source material.

image

After discussion, the decision was made not to pursue this approach.

An additional observation was that Klucher’s decomposition differs substantially from the behavior of the other transposition models in terms of the proportions between different components. The isotropic component alone is equal to the full isotropic model irradiance, with the other effects added on top. This suggests that even a simple isotropic + anisotropic decomposition may be less straightforward than initially expected.

image

As a result, klucher will not support component decomposition through return_components.

Should Total Diffuse Irradiance Be Returned?

Another discussion that (re)emerged during this phase concerns the behavior of return_components across all functions.

Currently, when return_components=True, the returned dictionary includes both the individual diffuse components and the total diffuse irradiance. An open question is whether the total diffuse value is actually necessary, since it can be reconstructed by summing the components.

This remains an active topic of discussion. For now, the existing behavior has been preserved for all newly updated functions in order to maintain consistency with the models that already supported return_components. Since this is largely independent from the broader project, it is something that can be revisited later if necessary without affecting other implemented features.

Extending the Irradiance Wrappers

The final task in Phase 1 is extending support for return_components to the higher-level wrapper functions in pvlib.irradiance:

  • get_sky_diffuse
  • poa_components
  • get_total_irradiance

Adding this support will make component information available without requiring users to call the transposition models directly. It also lays the groundwork for Phase 2, where these diffuse components will need to be propagated through the ModelChain workflow.

There is currently an open PR implementing these changes, although it will remain pending until the earlier PRs are fully resolved.

Looking Ahead

With most of the diffuse components work now complete, I’m currently getting started on Phase 2 of the project: integrating diffuse irradiance components into ModelChain and enabling component-specific optical loss calculations.

More on that soon!


<
Previous Post
Two Weeks In: Progress on Diffuse Component Standardization
>
Blog Archive
Archive of all previous blog posts