Visitar URL original
Add cutoff blackbody model class by cgobat · Pull Request #20560 · astropy/astropy · GitHub
Skip to content

Add cutoff blackbody model class - #20560

Open
cgobat wants to merge 19 commits into
astropy:mainfrom
cgobat:cutoff-blackbody
Open

cgobat wants to merge 19 commits into
astropy:mainfrom
cgobat:cutoff-blackbody

Conversation

@cgobat

@cgobat cgobat commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Description

This pull request add a new Fittable1DModel class called CutoffBlackBody that implements a blackbody emission spectrum, with power-law suppression below a cutoff wavelength.

Mathematically, the model is:

$$ B_{\lambda}^{\mathrm{cut}}(T) = A\ B_{\lambda}(T) \begin{cases} (\lambda / \lambda_{\mathrm{cut}})^{\beta}, & \lambda < \lambda_{\mathrm{cut}} \\ 1, & \lambda \geq \lambda_{\mathrm{cut}} \end{cases} $$

where $B_\lambda(T)$ is the Planck function for temperature $T$, $A$ is a dimensionless scale factor, and $\beta$ is the index of the power-law suppression.

I am opening this as a draft PR at first because, as you may notice, I have left the bolometric flux implementation mostly blank. The integral of this function is significantly messier1 than that of a normal blackbody, and I think the cleanest way to compute it would probably be numerically with scipy. However I am not sure if it is acceptable to add a scipy dependency/import to this file/module. The calculation should also be doable with numpy alone, but it will not be as clean, so please let me know which way to go on this.

The bolometric flux method uses scipy.integrate.quad for the integral, but I am open to changing this if desired.

AI Disclosure

GPT-5.6 was used to generate the documentation updates and unit tests, and it helped with the implementation of the bolometric flux integral as well.

  • I certify that I am human and that I take full responsibility for this pull request including all interactions with reviewers.

Merge method

  • By checking this box, the PR author has requested that maintainers do NOT use the "Squash and Merge" button. Maintainers should respect this when possible; however, the final decision is at the discretion of the maintainer that merges the PR.

Footnotes

  1. For arbitrary values of β, the bolometric integral does not reduce to a finite closed-form expression and must be evaluated/approximated numerically anyway, since the solution involves an infinite sum (of gamma functions, no less!) ↩

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for rebase and squash.
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

@cgobat cgobat changed the title Cutoff blackbody Add cutoff blackbody model class Oct 7, 2026
@pllim pllim added this to the v8.1.0 milestone Oct 7, 2026
@pllim

pllim commented Oct 7, 2026

Copy link
Copy Markdown
Member

Hello and thanks.

scipy vs numpy

Is there any performance boost either way? I think that might be the main factor. Otherwise, if scipy is preferred, I think it would be acceptable to use but you will have to be more careful in handling "what if scipy is not installed" scenario.

@cgobat

cgobat commented Oct 7, 2026 •

Copy link
Copy Markdown
Member Author

I'd like to avoid hardcoding a discretized grid for this integration, which means that scipy vs. numpy implementations are going to be different and thus not directly comparable. Scipy makes it really easy with scipy.integrate.quad which just takes the function itself and internally chooses the evaluation points adaptively. With numpy I think the way to do it would be to use Legendre-Gauss quadrature via np.polynomial.legendre.leggauss for the nodes/weights. This does still require choosing a quadrature order (i.e., number of nodes), but we don't have to define the actual physical grid spacing or an arbitrary upper integration bound.

In practice, the two methods agree to within very small tolerances (max rel. error of ~1e-9 (1e-14 typ.) for N=64 nodes and ~1e-10 (1e-15 typ.) for N=128 nodes). The Gauss-Legendre (numpy) way is faster by a fair margin for both N=64 and N=128. Does that make it your preference, at the cost of probably slightly less obvious code/implementation?

@pllim

pllim commented Oct 7, 2026

Copy link
Copy Markdown
Member

I vaguely remember @karllark being passionate about our blackbody modeling, so maybe he has opinions. Also cc @astropy/modeling

@karllark

karllark commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

I do not have an opinion on how the integral is computed. Thanks for thinking of me though.

@cgobat

cgobat commented Oct 8, 2026

Copy link
Copy Markdown
Member Author

Here's a scipy implementation for review. My thinking is that this is less obscure (thus easier to maintain), and wringing every ounce of performance out of this method isn't critical since it's not called at all during fitting or anything like that.

@cgobat
cgobat marked this pull request as ready for review October 8, 2026 21:09
@cgobat
cgobat requested a review from a team as a code owner October 8, 2026 21:09
@cgobat

cgobat commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

Sorry for the CI churn. I think this should basically be good to go now.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants