Repository: LSSTDESC/surveycodex (language: python)

Issue:
Add reference for psf_fwhm and exposure time in LSST
I was checking the `psf_fwhm` for [LSST](https://github.com/aboucaud/galcheat/blob/main/galcheat/data/LSST.yaml) that are currently the ones directly taken from BTK. These come from `zenith_psf_fwhm` in WeakLensingDeblending (in turn taken from this [paper](https://arxiv.org/pdf/0805.2366v4.pdf)) multiplied by `airmass**0.6` (see equation [here](https://github.com/LSSTDESC/WeakLensingDeblending/blob/228c6655d63de9edd9bf2c8530f99199ee47fc5e/descwl/survey.py#L53))

Added the reference in the corresponding yaml file. 

So I think the only reference missing is `exposure_time`, WLD says that they are found in the same paper I linked above but I couldn't find them. Does anyone know how to find them? @aboucaud @mpaillassa @thuiop

Closes #25 


Discussion / hints:
So it is not written plainly but I guess we can approximate it.

You read on section 2.1.5

> The total number of visits of any given area of sky, when accounting for all filters, should be of the order of 1,000

and

> The adopted time allocation (see Table 1) includes a slight preference to the r and i bands because of their dominant role in star/galaxy separation and weak lensing measurements.

On Table 1 you find the `mean number of visits`
| u | g | r | i | z | y |
| - | - | - | - | - | - |
| 56 | 80 | 184 | 184 | 160 | 160 | 

These account for 824 visits < 1,000 cited above. _Is this normal ?_

The first approximation that comes to mind would be to use that number directly and multiply it by the single exposure time : 15sec, or since they are done by pairs 30 sec.

Otherwise we use the table to compute the ratio between bands 
| u | g | r | i | z | y |
| - | - | - | - | - | - |
| 0.068 | 0.097 | 0.223 | 0.223 | 0.194 | 0.194 | 

and try to find the "mean_visit_full_exposure_time" that we can multiply these ratio with.


Hello @ismael-mendoza, thanks for looking into it. In fact I did not make the PR related to #25 yet so the LSST survey is not complete yet and misses references for:
* `pixel_size`, which may be the lone link between `zeropoint_airmass` and `zeropoint`, or the Table 1 in [the paper](https://arxiv.org/pdf/0805.2366v4.pdf) you mentioned.
* `sky_brightness`, which may be Table 2 in the [the paper](https://arxiv.org/pdf/0805.2366v4.pdf) as current (WLD) values are the same.
* `exposure_time`, which may be Table 1. As @aboucaud mentioned, we may approximate them using the number of visits. Considering visits of 30s, we can effectively find back the current (WLD) values.
* `psf_fwhm` before you started looking into it. I think it is ok now !

We may also use [the paper ](https://arxiv.org/pdf/0805.2366v4.pdf) you mention for the `obscuration` reference instead of citing WLD like currently done. From the 6.5m effective diameter given in the paper, `obscuration` is `1-(6.5*6.5)/(8.34*8.34)` giving 0.39257227.


Just want to mention here the PR #97 in which I have completely changed the way references are written in the YAML files.
Thanks @aboucaud and @mpaillassa I'm looking into this PR again now and will take #97 into account. 
My bad, I accidentally closed this branch. I'm still learning the ropes of working from forks. Will open a new PR soon.

Fix patch:
diff --git a/galcheat/data/LSST.yaml b/galcheat/data/LSST.yaml
index 0f3f1c9..d6d5452 100644
--- a/galcheat/data/LSST.yaml
+++ b/galcheat/data/LSST.yaml
@@ -3,55 +3,55 @@ description: "Legacy Survey of Space and Time (LSST) done with the Simonyi surve
 pixel_scale: 0.2
 gain: 1.0
 mirror_diameter: 8.36
-obscuration: 0.40974106
+obscuration: 0.39257227
 zeropoint_airmass: 1.2
 filters:
   u:
     name: "u"
-    sky_brightness: 22.9
+    sky_brightness: 22.99
     exposure_time: 1680
     zeropoint: 26.40
-    psf_fwhm: 0.859
+    psf_fwhm: 0.90
     effective_wavelength: 368.141
   g:
     name: "g"
-    sky_brightness: 22.3
+    sky_brightness: 22.26
     exposure_time: 2400
     zeropoint: 28.26
-    psf_fwhm: 0.814
+    psf_fwhm: 0.86
     effective_wavelength: 486.412
   r:
     name: "r"
-    sky_brightness: 21.2
+    sky_brightness: 21.20
     exposure_time: 5520
     zeropoint: 28.10
-    psf_fwhm: 0.781
+    psf_fwhm: 0.81
     effective_wavelength: 624.976
   i:
     name: "i"
-    sky_brightness: 20.5
+    sky_brightness: 20.48
     exposure_time: 5520
     zeropoint: 27.78
-    psf_fwhm: 0.748
+    psf_fwhm: 0.79
     effective_wavelength: 756.469
   z:
     name: "z"
-    sky_brightness: 19.6
+    sky_brightness: 19.60
     exposure_time: 4800
     zeropoint: 27.39
-    psf_fwhm: 0.725
+    psf_fwhm: 0.77
     effective_wavelength: 870.164
   y:
     name: "y"
-    sky_brightness: 18.6
+    sky_brightness: 18.61
     exposure_time: 4800
     zeropoint: 26.56
-    psf_fwhm: 0.703
+    psf_fwhm: 0.76
     effective_wavelength: 972.202
 references:
   pixel_scale:
     link: "https://www.lsst.org/about/camera/features"
-    comment: "See Technical details"
+    comment: "See Technical details."
   gain:
     link: "https://github.com/LSSTDESC/imSim/blob/main/imsim/stamp.py#L416"
     comment: ""
@@ -59,23 +59,23 @@ references:
     link: "https://www.lsst.org/about/tel-site/optical_design"
     comment: ""
   obscuration:
-    link: "https://arxiv.org/abs/0805.2366"
-    comment: "See https://github.com/aboucaud/galcheat/issues/38 for discussions"
+    link: "https://arxiv.org/abs/0805.2366.pdf"
+    comment: "(v5) The paper mentions an effective diameter of ~6.5m. See https://github.com/aboucaud/galcheat/issues/38 for discussions on how to calculate obscuration from effective diameter."
   zeropoint_airmass:
     link: "https://speclite.readthedocs.io/en/latest/filters.html#lsst-filters"
     comment: ""
   sky_brightness:
-    link: "https://www.lsst.org/about/camera/features"
-    comment: ""
+    link: "https://arxiv.org/abs/0805.2366"
+    comment: "(v5) See Table 2, first row."
   exposure_time:
-    link: "https://www.lsst.org/about/camera/features"
-    comment: "See Technical details"
+    link: "https://arxiv.org/abs/0805.2366"
+    comment: "(v5) See Table 1 'Mean number of visits' and in the paper it is mentioned that the visit exposure time is 30s (section 2.2.2). So, for example, for u band 56 * 30 = 1680."
   zeropoint:
     link: "https://speclite.readthedocs.io/en/latest/filters.html#lsst-filters"
-    comment: "computed with speclite – see scripts/check_zeropoints.py"
+    comment: "Computed with speclite – see scripts/check_zeropoints.py"
   psf_fwhm:
-    link: ""
-    comment: ""
+    link: "https://arxiv.org/pdf/0805.2366.pdf"
+    comment: "(v5) Computed from second row of Table 2 by multiplying times airmass**0.6 where  airmass=1.2 (used throughout paper in e.g. Figure 4)"
   effective_wavelength:
     link: "https://speclite.readthedocs.io/en/latest/filters.html#lsst-filters"
     comment: "computed with speclite – see scripts/check_effective_wavelength.py"


Test patch:
diff --git a/tests/test_utilities.py b/tests/test_utilities.py
index a9dd24d..a14623a 100644
--- a/tests/test_utilities.py
+++ b/tests/test_utilities.py
@@ -1,24 +1,25 @@
+import numpy as np
 import pytest
 
 from galcheat.helpers import get_survey
 from galcheat.utilities import mag2counts, mean_sky_level
 
-BTK_COUNTS_MAG24 = {
-    "LSST_u": 15321.782101179268,
-    "LSST_g": 121397.91888074754,
-    "LSST_r": 240956.73939657194,
-    "LSST_i": 179448.18815675998,
-    "LSST_z": 108953.51289042353,
-    "LSST_y": 50727.240442255556,
+WLD_COUNTS_MAG24 = {
+    "LSST_u": 15388.800000000001,
+    "LSST_g": 121680.0,
+    "LSST_r": 241224.00000000003,
+    "LSST_i": 178627.19999999998,
+    "LSST_z": 108864.0,
+    "LSST_y": 50784.0,
 }
 
-BTK_MEAN_SKY_LEVEL = {
-    "LSST_u": 1687.9876819744386,
-    "LSST_g": 23241.878848667337,
-    "LSST_r": 127057.1381640446,
-    "LSST_i": 180301.3875959776,
-    "LSST_z": 250784.8105213134,
-    "LSST_y": 293292.6831817095,
+WLD_SKY_LEVEL = {
+    "LSST_u": 1695.370986797218,
+    "LSST_g": 23295.88385352744,
+    "LSST_r": 127198.06540061244,
+    "LSST_i": 179476.4959914193,
+    "LSST_z": 250578.77335308882,
+    "LSST_y": 293620.8532702446,
 }
 
 
@@ -27,7 +28,7 @@
 )
 def lsst_btk_counts(request):
     survey, filt = request.param
-    expected = int(BTK_COUNTS_MAG24[f"{survey}_{filt}"])
+    expected = int(WLD_COUNTS_MAG24[f"{survey}_{filt}"])
     return survey, filt, expected
 
 
@@ -36,39 +37,43 @@ def lsst_btk_counts(request):
 )
 def lsst_btk_sky_level(request):
     survey, filt = request.param
-    expected = int(BTK_MEAN_SKY_LEVEL[f"{survey}_{filt}"])
+    expected = WLD_SKY_LEVEL[f"{survey}_{filt}"]
     return survey, filt, expected
 
 
 def test_mag2counts_str(lsst_btk_counts):
     survey, filt, expected = lsst_btk_counts
-    assert mag2counts(24, survey, filt).value == expected
+    np.testing.assert_allclose(mag2counts(24, survey, filt).value, expected, rtol=1e-1)
 
 
 def test_mag2counts_filter_str(lsst_btk_counts):
     survey, filt, expected = lsst_btk_counts
     survey_inst = get_survey(survey)
-    assert mag2counts(24, survey_inst, filt).value == expected
+    np.testing.assert_allclose(
+        mag2counts(24, survey_inst, filt).value, expected, rtol=1e-1
+    )
 
 
 def test_mag2counts_filter_instance(lsst_btk_counts):
     survey, filt, expected = lsst_btk_counts
     survey_inst = get_survey(survey)
     filt_inst = survey_inst.get_filter(filt)
-    assert mag2counts(24, survey_inst, filt_inst).value == expected
+    np.testing.assert_allclose(
+        mag2counts(24, survey, filt_inst).value, expected, rtol=1e-1
+    )
 
 
 def test_mean_sky_level_str(lsst_btk_sky_level):
     survey, filt, expected = lsst_btk_sky_level
     sky_level = mean_sky_level(survey, filt).value
-    assert int(sky_level) == expected
+    np.testing.assert_allclose(sky_level, expected, rtol=1e-1)
 
 
 def test_mean_sky_level_filter_str(lsst_btk_sky_level):
     survey, filt, expected = lsst_btk_sky_level
     survey_inst = get_survey(survey)
     sky_level = mean_sky_level(survey_inst, filt).value
-    assert int(sky_level) == expected
+    np.testing.assert_allclose(sky_level, expected, rtol=1e-1)
 
 
 def test_mean_sky_level_filter_instance(lsst_btk_sky_level):
@@ -76,4 +81,4 @@ def test_mean_sky_level_filter_instance(lsst_btk_sky_level):
     survey_inst = get_survey(survey)
     filt_inst = survey_inst.get_filter(filt)
     sky_level = mean_sky_level(survey_inst, filt_inst).value
-    assert int(sky_level) == expected
+    np.testing.assert_allclose(sky_level, expected, rtol=1e-1)