Skip to content

Commit

Permalink
LsstErrorModel and LsstErrorParams are smarter aliases, including doc…
Browse files Browse the repository at this point in the history
…string inheritance. Parameter docstrings now included in the model dosctrings. Some documentation improvements, and cleaning up the parameter validation method. (#17)
  • Loading branch information
jfcrenshaw authored Mar 5, 2024
1 parent b6382aa commit 07a9db0
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 73 deletions.
44 changes: 21 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,16 @@ errModel.getLimitingMags(nSigma=1, coadded=False) # single-image point-source 1-
# Tweaking the error model

There are many parameters you can tweak to fine tune the error model.
To see all available parameters, you can either call help on the error model's `params` object,
To see all available parameters, check the docstring of either the error model or parameters object.
For example,

```python
help(errModel.params)
```

or look at the docstring of the corresponding parameters object,

```python
from photerr import LsstErrorParams
help(LsstErrorParams)
from photerr import LsstErrorModel
help(LsstErrorModel)
```

All model parameters can be overridden using keyword arguments to the error model constructor.
Below, we explain a few of the more commonly tweaked parameters.
Below, we explain in detail a few of the more commonly tweaked parameters.

### *Changing the observing duration*

Expand All @@ -74,8 +69,8 @@ errModel = LsstErrorModel(nYrObs=1)
### *Changing the band names*

Another parameter you might want to tweak is the name of the bands.
By default, the `LsstErrorModel` assumes that the LSST bands are named `u`, `g`, etc.
If instead, the bands in your catalog are named `lsst_u`, `lsst_g`, etc., then you can instantiate the error model with a rename dictionary:
By default, the `LsstErrorModel` assumes the LSST bands are named `u`, `g`, `r`, etc.
If instead, the bands in your catalog are named `lsst_u`, `lsst_g`, `lsst_r`, etc., you can instantiate the error model with a rename dictionary:

```python
errModel = LsstErrorModel(renameDict={"u": "lsst_u", "g": "lsst_g", ...})
Expand All @@ -89,43 +84,44 @@ If you are changing other dictionary-parameters at the same time (e.g. `nVisYr`,
By default, PhotErr tries to use the provided information to calculate limiting magnitudes for you.
If you would like to directly supply your own $5\sigma$ limits, you can do so using the `m5` parameter.
Note PhotErr assumes these are single-visit point-source limiting magnitudes.
If you want to supply coadded depths, you should also set `nYrObs=1` and `nVisYr=1`, so that the calculated coadded depths are equal to those you provided.
If you want to supply coadded depths, you should also set `nYrObs=1` and `nVisYr=1`, so the calculated coadded depths are equal to those you provided.

### *Handling non-detections*

The other big thing you may want to change is how the error model identifies and handles non-detections.

The error model has a parameter named `sigLim`, which sets the limit for non-detections.
By default, `sigLim=0`, which means that only negative fluxes count as non-detections, however if you set `sigLim=1`, then any magnitudes beyond the 1-sigma limit in each band will count as a non-detection.
By default `sigLim=0`, which means only negative fluxes count as non-detections, however if you set `sigLim=1`, any magnitudes beyond the 1-sigma limit in each band will count as a non-detection.
You can set `sigLim` to any non-negative float.

The `ndMode` parameter tells the error model how to handle the non-detections.
By default, `ndMode="flag"`, which means that the model will flag non-detections with the value set by `ndFlag`, which defaults to `np.inf`.
By default `ndMode="flag"`, which means the model will flag non-detections with the value set by `ndFlag`, which defaults to `np.inf`.
However, you can also set `ndMode="sigLim"`, in which case the model will set all non-detections to the n-sigma limits set by the `sigLim` parameter described in the previous paragraph.
Remember that `sigLim` also sets the detection threshold, so in effect, any galaxy magnitudes beyond the detection threshold will be set equal to the detection threshold.

One other option is provided by the `absFlux` parameter.
If `absFlux=True`, then the absolute value of all fluxes are taken before converting back to magnitudes.
If `absFlux=True`, the absolute value of all fluxes are taken before converting back to magnitudes.
If combined with `sigLim=0`, this means every galaxy will have an observed flux in every band.
This is useful if you do not want to worry about non-detections, but it results in a non-Gaussian error distribution for low-SNR sources.
This is useful if you do not want to worry about non-detections, but it results in a non-Gaussian error distribution for the flux of low-SNR sources.

### Errors for extended sources
### *Errors for extended sources*

PhotErr can be used to calculate errors for extended sources as well.
You just have to pass `extendedType="auto"` or `extendedType="gaap"` to the constructor (see explanation below for the differences in these models).
PhotErr will then look for columns in the input DataFrame that correspond to the semi-major and -minor axes of the objects, corresponding to half-light radii in arcseconds.
By default, it looks for these in columns titled "major" and "minor", but you can change the names of these columns using the `majorCol` and `minorCol` keywords.
By default it looks for these in columns titled "major" and "minor", but you can change the names of these columns using the `majorCol` and `minorCol` keywords.

You can also calculate limiting magnitudes for apertures of a given size by passing the `aperture` keyword to `errModel.getLimitingMags()`

### Scaling the errors
### *Scaling the errors*

If you want to scale up or scale down the errors in any band(s), you can use the keyword `scale`.
For example, `LsstErrorModel(scale={"u": 2, "y": 2})` will have all the same properties of the default error model, except the errors in the `u` and `y` bands will be doubled.
This allows you to answer questions like "what happens to my science if the `u` band errors are doubled."

Note this only scales the band-specific error.
The band-independent systematic error floor, `sigmaSys` is still the same, and so at high-SNR near the systematic floor, the errors won't scale as you expect.
Note it is the flux error that is doubled.
This also only scales the band-specific error.
The band-independent systematic error floor, `sigmaSys` is still the same, and so at high-SNR near the systematic floor the errors won't scale as you expect.

### *Other error models*

Expand All @@ -134,7 +130,9 @@ Each of these models also have corresponding parameter objects: `EuclidErrorPara

You can also start with the base error model, `ErrorModel`, which is not defaulted for any specific survey.
To instantiate `ErrorModel`, there are several required arguments that you must supply.
To see a list and explanation of these arguments, see the docstring for `ErrorParams`.
To see a list and explanation of these arguments, see the docstring for `ErrorModel`.
However, the easiest way to create a new model is to supply `nYrObs`, `nVisYr`, `gamma`, and `m5`.
You might need to fit `gamma` to match the expected errors, however a good default guess is `0.04`.

# Explanation of the error model

Expand Down
12 changes: 4 additions & 8 deletions photerr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@

from .euclid import EuclidErrorModel, EuclidErrorParams
from .lsstV1 import LsstErrorModelV1, LsstErrorParamsV1
from .lsstV2 import LsstErrorModelV2, LsstErrorParamsV2
from .lsstV2 import LsstErrorModelV2
from .lsstV2 import LsstErrorModelV2 as LsstErrorModel
from .lsstV2 import LsstErrorParamsV2
from .lsstV2 import LsstErrorParamsV2 as LsstErrorParams
from .model import ErrorModel
from .params import ErrorParams
from .roman import RomanErrorModel, RomanErrorParams

# set the version number
__version__ = metadata.version(__package__)
del metadata


# alias the latest LSST error model
class LsstErrorParams(LsstErrorParamsV2): ...


class LsstErrorModel(LsstErrorModelV2): ...
9 changes: 7 additions & 2 deletions photerr/euclid.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class EuclidErrorParams(ErrorParams):
"""Parameters for the Euclid photometric error model.
gamma and limiting magnitudes taken from page 4 of Graham 2020.
nYrObs and nVisYr set = 1, assuming that Roman is point-and-stare.
nYrObs and nVisYr set = 1, assuming that Euclid is point-and-stare.
"""

__doc__ += param_docstring
Expand All @@ -32,7 +32,12 @@ class EuclidErrorParams(ErrorParams):


class EuclidErrorModel(ErrorModel):
"""Photometric error model for Euclid."""
"""Photometric error model for Euclid.
Below is the parameter docstring:
"""

__doc__ += EuclidErrorParams.__doc__

def __init__(self, **kwargs: Any) -> None:
"""Create a Euclid error model.
Expand Down
7 changes: 6 additions & 1 deletion photerr/lsstV1.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,12 @@ class LsstErrorParamsV1(ErrorParams):


class LsstErrorModelV1(ErrorModel):
"""Photometric error model for LSST, version 1."""
"""Photometric error model for LSST, version 1.
Below is the parameter docstring:
"""

__doc__ += LsstErrorParamsV1.__doc__

def __init__(self, **kwargs: Any) -> None:
"""Create an LSST error model.
Expand Down
7 changes: 6 additions & 1 deletion photerr/lsstV2.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,12 @@ class LsstErrorParamsV2(ErrorParams):


class LsstErrorModelV2(ErrorModel):
"""Photometric error model for LSST, version 2."""
"""Photometric error model for LSST, version 2.
Below is the parameter docstring:
"""

__doc__ += LsstErrorParamsV2.__doc__

def __init__(self, **kwargs: Any) -> None:
"""Create an LSST error model.
Expand Down
8 changes: 3 additions & 5 deletions photerr/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@
class ErrorModel:
"""Base error model from Ivezic 2019.
References
----------
Ivezic 2019 - https://arxiv.org/abs/0805.2366
van den Busch 2020 - http://arxiv.org/abs/2007.01846
Kuijken 2019 - https://arxiv.org/abs/1902.11265
Below is the parameter docstring:
"""

__doc__ += ErrorParams.__doc__

def __init__(self, *args: ErrorParams, **kwargs: Any) -> None:
"""Create an error model using the passed ErrorParams or keyword overrides.
Expand Down
61 changes: 30 additions & 31 deletions photerr/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import numpy as np

param_docstring = """
Note for all the dictionary parameters below, you can pass a float
instead and that value will be used for all bands. However at least
one of these parameters must be a dictionary so that the model can
Expand Down Expand Up @@ -164,42 +163,42 @@
# this dictionary defines the allowed types and values for every parameter
# we will use it for parameter validation during ErrorParams instantiation
_val_dict = {
# param: [ is dict?, [allowed types], [allowed values], negative allowed? ]
"nYrObs": [False, [int, float], [], False],
"nVisYr": [True, [int, float], [], False],
"gamma": [True, [int, float], [], False],
"m5": [True, [int, float], [], True],
"tvis": [True, [int, float], [], False],
"airmass": [True, [int, float], [], False],
"Cm": [True, [int, float], [], True],
"dCmInf": [True, [int, float], [], True],
"msky": [True, [int, float], [], True],
"mskyDark": [True, [int, float], [], True],
"theta": [True, [int, float], [], False],
"km": [True, [int, float], [], False],
"tvisRef": [False, [int, float, type(None)], [], False],
"sigmaSys": [False, [int, float], [], False],
"sigLim": [False, [int, float], [], False],
"ndMode": [False, [str], ["flag", "sigLim"], None],
"ndFlag": [False, [int, float], [], True],
"absFlux": [False, [bool], [], None],
"extendedType": [False, [str], ["point", "auto", "gaap"], None],
"aMin": [False, [int, float], [], False],
"aMax": [False, [int, float], [], False],
"majorCol": [False, [str], [], None],
"minorCol": [False, [str], [], None],
"decorrelate": [False, [bool], [], None],
"highSNR": [False, [bool], [], None],
"scale": [True, [int, float], [], None],
"errLoc": [False, [str], ["after", "end", "alone"], None],
# param: ( is dict?, (allowed types), (allowed values), negative allowed? )
"nYrObs": (False, (int, float), (), False),
"nVisYr": (True, (int, float), (), False),
"gamma": (True, (int, float), (), False),
"m5": (True, (int, float), (), True),
"tvis": (True, (int, float), (), False),
"airmass": (True, (int, float), (), False),
"Cm": (True, (int, float), (), True),
"dCmInf": (True, (int, float), (), True),
"msky": (True, (int, float), (), True),
"mskyDark": (True, (int, float), (), True),
"theta": (True, (int, float), (), False),
"km": (True, (int, float), (), False),
"tvisRef": (False, (int, float, type(None)), (), False),
"sigmaSys": (False, (int, float), (), False),
"sigLim": (False, (int, float), (), False),
"ndMode": (False, (str,), ("flag", "sigLim"), None),
"ndFlag": (False, (int, float), (), True),
"absFlux": (False, (bool,), (), None),
"extendedType": (False, (str,), ("point", "auto", "gaap"), None),
"aMin": (False, (int, float), (), False),
"aMax": (False, (int, float), (), False),
"majorCol": (False, (str,), (), None),
"minorCol": (False, (str,), (), None),
"decorrelate": (False, (bool,), (), None),
"highSNR": (False, (bool,), (), None),
"scale": (True, (int, float), (), None),
"errLoc": (False, (str,), ("after", "end", "alone"), None),
}


@dataclass
class ErrorParams:
"""Parameters for the photometric error models."""

__doc__ += param_docstring
__doc__ += "\n" + param_docstring

nYrObs: float
nVisYr: dict[str, float]
Expand Down Expand Up @@ -437,7 +436,7 @@ def _check_single_param(
"""Check that this single parameter has the correct type/value."""
name = key if subkey is None else f"{key}.{subkey}"

if not any([isinstance(param, t) for t in allowed_types]):
if not isinstance(param, allowed_types):
raise TypeError(
f"{name} is of type {type(param).__name__}, but should be "
f"of type {', '.join(t.__name__ for t in allowed_types)}."
Expand Down
7 changes: 6 additions & 1 deletion photerr/roman.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ class RomanErrorParams(ErrorParams):


class RomanErrorModel(ErrorModel):
"""Photometric error model for Roman."""
"""Photometric error model for Roman.
Below is the parameter docstring:
"""

__doc__ += RomanErrorParams.__doc__

def __init__(self, **kwargs: Any) -> None:
"""Create a Roman error model.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "photerr"
version = "1.2.2"
version = "1.2.3"
description = "Photometric error model for astronomical imaging surveys"
authors = ["John Franklin Crenshaw <[email protected]>"]
readme = "README.md"
Expand Down
1 change: 1 addition & 0 deletions tests/test_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,5 @@ def test_all_dicts_are_floats() -> None:


def test_validate_params_with_numpy_float() -> None:
"""Test that numpy floats don't fail validation for primitive floats."""
LsstErrorParams(m5={"u": np.array([23.0])[0]})

0 comments on commit 07a9db0

Please sign in to comment.