Skip to content

Diffuse components with Klucher #2794

Closed

Description

@cbcrespo

Is your feature request related to a problem? Please describe.
As part of my GSoC 2026 project, I am adding support for return_components to all diffuse transposition models in pvlib, which currently is supported by some models (e.g. perez) but not others (e.g. klucher). While some models provide separable components, klucher does not, because its component terms are multiplicatively coupled.

Describe the solution you'd like
Separating the transposed diffuse irradiance into sky diffuse, circumsolar and horizon brightening components under a proportional allocation assumption (detailed below) which, of course, should be clearly documented.

Describe alternatives you've considered
Not supporting diffuse components for this model, and having return_components=True return a dictionary (in order to keep consistency with other models) returning a single value, the total diffuse irradiance.

Additional context
The following is the expression for total diffuse irradiance via klucher:
$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 consider (as identified by Loutzenhiser et al.):

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

Then we can simplify the full expression into:
$I (1+h) (1+c) = I (1+c+h+hc)$

That $hc$ term is problematic if we want to separate components. @adriesse proposed a solution here which was to distribute this $hc$ term between $h$ and $c$ proportionally. We would get:
$c' = c + \frac{c}{h+c} hc$
$h' = h + \frac{h}{h+c} hc$

And the full expression then becomes:
$I_d = I(1 + c' + h')$

Thus enabling the separation of components.

I would like feedback on whether this decomposition is acceptable for inclusion in pvlib, or whether klucher should instead not expose component breakdowns at all (i.e., return_components is still used to maintain consistency with other models, but returns a dict with only total irradiance for this model).

Activity

  1. cwhanse commented on Jun 23, 2026

    @cwhanse
    Member

    I'm moderately opposed to altering the klucher function to return circumsolar and horizon components not described in the reference:
    #2527 (comment)

    If we want a version of klucher that returns these components, the proportional approach seems as good as any. But that's essentially a new diffuse component model and should have its own reference and name.

  2. adriesse commented on Jun 23, 2026

    @adriesse
    Member

    I think if we're on a path to allowing a variable number of components there is less motivation to do this split in the code. It could be described in the Notes section or demonstrated in an example, or indeed it could be considered as a new model.

  3. cbcrespo commented on Jun 26, 2026

    @cbcrespo
    ContributorAuthor

    To add to the discussion: I did a small sensitivity analysis of the size of this $hc$ term when compared to the total diffuse irradiance, and to the circumsolar and horizon components. Here the components are calculated via the proportional split. This is for a location near Lisbon and two systems: 30º south, and vertical west-facing.

    Image
  4. adriesse commented on Jun 29, 2026

    @adriesse
    Member

    That's an interesting perspective, @cbcrespo . I am not sure these fractions tell the whole story though. I guess the first question is, what do we want to show (and maybe to whom)? Perhaps a comparison of the components between this and one or more other models that produce the same components give some confidence that the values don't go haywire. You could probably turn it into a poster for PVSEC, if you want.

  5. cbcrespo commented on Jun 30, 2026

    @cbcrespo
    ContributorAuthor

    I agree that it doesn't tell the whole story @adriesse. I also wanted to share the following plot (same location, tilted system):

    Image

    My takeaway from these two is that the $hc$ term isn't necessarily the problem. This term will be small most of the time (although maybe a bit more relevant for the vertical system) and therefore however we choose to split it may not be of great importance. But the fact that the scale of the circumsolar component differs significantly from the other models to me hints that maybe this forced separation of components indeed doesn't hold a clear physical meaning. But I'm curious to hear everyone's thoughts on this.

  6. AdamRJensen commented on Jul 1, 2026

    @AdamRJensen
    Member

    I'm moderately opposed to altering the klucher function to return circumsolar and horizon components not described in the reference: #2527 (comment)

    If we want a version of klucher that returns these components, the proportional approach seems as good as any. But that's essentially a new diffuse component model and should have its own reference and name.

    @kandersolar and @wholmgren Could you weigh in on this.

  7. adriesse commented on Jul 1, 2026

    @adriesse
    Member

    @cbcrespo It is interesting to see how small the horizon brightening contribution is. I suspect that one of the reasons for the difference it the datasets that the various authors had available to develop their models.

    The partitioning was proposed as a way to have all models return the same set of components, but this is no longer the goal. As I said before, it could be described in the Notes section or demonstrated in an example, or indeed it could be considered as a new model.

    If the partitioning is not done for Klucher, we just need to find a suitable name for the combined anisotropic component, like maybe "poa_anisotropic".

  8. ramaroesilva commented on Jul 1, 2026

    @ramaroesilva
    Contributor

    hi all, really nice discussion here.

    my two cents on the general situation:

    • I don't think that the weight of the components in a model is a good indicator on whether the splitting should be enabled or not, I would instead think have support materials that can help users to make their own choice (for example, a small white paper from @cbcrespo studying this for a few climates by the end of her GSoC)
    • at the same time, I believe this issue is starting to fall out of scope of @cbcrespo GSoC project (i.e., to uniform diffuse transposition outputs, as a means to allow diffuse-specific IAM losses in the ModelChain framework). this is particularly relevant considering that her GSoC will consist of several PRs, with strong inter-dependence and, thus, highly prone to being slowed down by PR review timings.

    since klucher is not that much of a default option for transposing (#goperez), the number of potential modellers wanting this splitting is modest when compared to the target users who are using modelchain without diffuse IAM.

    this doesn't mean we shouldn't keep discussing this and eventually reach to a consensus and resulting PR, but for now I would:

    • have this klucher thing running in parallel to the main GSoC tasks
    • keep klucher as the only non-splittable algorithm for now, which would allow @cbcrespo to have a real example to make sure that her modifications are compatible with such cases
    • once a common consensus is reached, I would merge the resulting PR by the end of the GSoC, to minimize entropy but also also as an example of adding a new transposition algo within pvlib's new modelchain framework (allowing to ID potential modifications in how models are added compared to before)
  9. ramaroesilva commented on Jul 1, 2026

    @ramaroesilva
    Contributor

    If the partitioning is not done for Klucher, we just need to find a suitable name for the combined anisotropic component, like maybe "poa_anisotropic".

    about @adriesse suggestion of isotropic/anisotropic components, since for now klucher is the only "problematic" case, I would first do a mapping for algorithms not yet implemented in pvlib before proposing a solution (to avoid ad-hoc). this would also require some reflection on the advantages IAM-wise, since this anisotropic component would still have to consider isotropic/horizon/circumsolar optical losses.

  10. cbcrespo commented on Jul 1, 2026

    @cbcrespo
    ContributorAuthor

    If the partitioning is not done for Klucher, we just need to find a suitable name for the combined anisotropic component, like maybe "poa_anisotropic".

    @adriesse as @ramaroesilva mentioned, I'm not sure how one would address an anisotropic component in terms of IAM calculations - which is part of the next step of my GSoC project, but also one of the main motivations behind diffuse components support.

    Regardless, I am in favour of leaving this on standby for now. Ultimately I think I am leaning towards not having klucher return diffuse components at all, which would either mean that return_components is not supported, or that it returns a dictionary with only the total diffuse - which, in my opinion, is an argument against removing the total diffuse from the output dict, as has been suggested by some.

  11. markcampanelli commented on Jul 1, 2026

    @markcampanelli
    Contributor

    @cbcrespo As an aside, I am curious how often the "total sky diffuse" of Klucher well matches that of Perez?

  12. wholmgren commented on Jul 2, 2026

    @wholmgren
    Member

    @AdamRJensen in this case I think we're proposing too large of a deviation from the source material for klucher. I am fine with a new function klucher_proportional_components and this issue as the reference, though I am sure that'll be rejected.

  13. AdamRJensen commented on Jul 3, 2026

    @AdamRJensen
    Member

    @cbcrespo I think this is outside the scope of your GSoC project. I suggest that you do not support Klucher in your further work and close the PR and this discussion.

    Great work though 🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    GSoCContributions related to Google Summer of Code.enhancement

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions