Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

centroid: implement propagated uncertainties #938

Merged
merged 4 commits into from
Jun 28, 2022

Conversation

kecnry
Copy link
Member

@kecnry kecnry commented Mar 23, 2022

  • follows same pattern as in line_flux of setting an uncertainty attribute on the returned quantity if the input Spectrum1D has assigned uncertainties.
  • implements a private uncertainty._convert_uncertainty function to convert the Spectrum1D.uncertainty to any assumed type. This is now used in line_flux as well.
  • hardcodes dispersion uncertainty to zero for now, but keeps the terms in the equations in case we want to support passing/storing dispersion uncertainties in the future. Alternatively, the equations would simplify somewhat significantly if we drop support for uncertainties on dispersion entirely.

* follows same pattern as in line_flux of setting an uncertainty attribute on the returned quantity instead of returning an extra value
* implements an private uncertainty._convert_uncertainty function to convert the Spectrum1D.uncertainty to any assumed type
* hardcodes dispersion uncertainty to zero for now, but keeps in the equations in case we want to support passing/storing dispersion uncertainties in the future.  Alternatively, the equations would simplify somewhat significantly if we drop support for uncertainties on dispersion entirely.
@kecnry kecnry marked this pull request as ready for review March 28, 2022 15:44
@kecnry

This comment was marked as resolved.

Copy link
Contributor

@rosteen rosteen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks for the addition. I made one suggestion to check the actual value of uncertainty as well as the existence of the attribute in the test. If you want to accept that I'll go ahead and approve/merge.

specutils/tests/test_analysis.py Show resolved Hide resolved
@kecnry
Copy link
Member Author

kecnry commented Apr 14, 2022

I'll also just add the same comment I did in #939 - line_flux uses (and seems to return) variance, but centroid here returns standard deviation (update: see #939 (comment)). We should probably be consistent (and document) and/or wrap the uncertainty in the StdDevUncertainty class (but then that feels even worse to be hacked on top of the quantity object)... but which do we choose?

I think at some point attaching the uncertainty to the quantity object should be revisited, as it also is easily dropped when converting units, but that's well outside the scope of these two PRs.

Copy link
Member

@eteq eteq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly some minor suggestions, overall this looks generally good.

There is one comment about the "must be 1d or 2d" that is concerning, but that might be a pre-existing limitation that shouldn't be solved in this PR (I don't know what the current behavior is in >2D!).

On the broader topic of how to encode the uncertainties: I think the ship has sailed somewhat in that line_flux is following the .uncertainty -> stddev-style uncertainties. I think that's a fine starting point, as it is infinitely better than no uncertainties and a "better" way does not yet exist.

Going forward I think we may want to encode these instead either as

  1. StdDevUncertainty objects, with a deprecation period on the "old" way of just passing stddev style uncertainties without a wrapper object, or
  2. use astropy.uncertainties. Unfrotunately that does not yet have a clean way to handle stddev/var/ivar-style uncertainties, though, so that's probably a project for the future.

Regardless, though, I think it would be good to add an uncertainty_type attribute which is set to std. That's how uncertainty objects encode it, and is sort of a soft duck-typing that might give us a fighting chance of following option 1 without a ton of pain. If you do that, though, we should also make that change in #939 and in line_flux for consistency.

@@ -186,3 +187,26 @@ def _snr_derived(spectrum, region=None):
return signal / noise
else:
return 0.0


def _convert_uncertainty(uncertainty, to_class):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should really be in astropy.nddata. And hopefully will be in 5.1 with stropy/astropy#12057 ! We should change this to use that if the version is > 5.0.x, and fall back on this implementation (or a simple copy-paste of 12057 into here?) if not. That way we won't be forced to require Astropy 5.1 which isn't even out yet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eteq I'm revisiting this now - are there good reasons to keep _convert_uncertainty rather than just bumping the astropy requirement to 5.1 in the next specutils release and using the represent_as machinery now available on the uncertainty objects?

dispersion = np.tile(dispersion, [flux.shape[0], 1])
elif len(flux.shape) > 2:
raise ValueError("spectrum must be 1D or 2D")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused on this. Shouldn't it be OK for it to be any dimension, and the centroiding is just applied only along the spectral dimension?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably, but then we need an additional argument to control which index is the spectral dimension. That is probably out of scope here... but you could also argue that the new ValueError is out of scope, so I'm happy to remove that and/or open a new ticket to support any number of dimensions.

specutils/analysis/location.py Outdated Show resolved Hide resolved
specutils/analysis/location.py Outdated Show resolved Hide resolved
specutils/analysis/location.py Outdated Show resolved Hide resolved
specutils/analysis/location.py Outdated Show resolved Hide resolved
kecnry and others added 2 commits April 22, 2022 13:49
Co-authored-by: Ricky O'Steen <39831871+rosteen@users.noreply.github.com>
Co-authored-by: Erik Tollerud <erik.tollerud@gmail.com>
Copy link
Member

@eteq eteq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As @kecnry asked, I independently derived this just to check the propagation math - if you want to check my work here it is:
20220610_144827

I made the slightly different (simpler) assumption of no uncertainty on the dispersion, but it comes to the same result, so huzzah! All is good here. I did leave one inline suggestion for a minor performance optimization, though, which you can take or leave as you wish.

Two other large-scale thoughts:

  1. this derivation is only correct if the pixel uncertainties are uncorrelated. That's fine, because the correlated case is way more complicated anyway, and I don't think we need to say we'll support that right now. But we should just note in the docs somewhere that the uncertainty propogation assumes all pixel uncertainties are un-correlated.
  2. I agree we can leave the uncertainty_type change to a follow-on PR.

So I'm approving with the proviso that @kecnry looks at my suggestion and accepts it or not as you like, and at least consider putting something in the docstrings about the uncorrelated assuption.

specutils/analysis/location.py Outdated Show resolved Hide resolved
@kecnry kecnry force-pushed the centroid-uncert branch from 8790151 to ae9a37a Compare June 10, 2022 19:03
Co-authored-by: Erik Tollerud <erik.tollerud@gmail.com>
@kecnry kecnry force-pushed the centroid-uncert branch from ae9a37a to cd7d176 Compare June 10, 2022 19:10
@rosteen
Copy link
Contributor

rosteen commented Jun 28, 2022

Dev failure is also present on main (need to take a look at that...) so I'm merging.

@eteq
Copy link
Member

eteq commented May 16, 2023

Leaving a note here since we've had some realizations that are getting implemented in #1057 : this derivation above is subtly incorrect: it hinged on an assumption about the order of summation that was incorrect. Attached is a whiteboard picture of a correct derivation (cross-checked with a few different other online sources).

centroid_unc_derivation

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants