Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implement a model of twilight sky brightness #84

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5d9d828
Add twilight config to desi.yaml
dkirkby Nov 23, 2017
50c5d79
Stub out new atmosphere.Twilight class
dkirkby Nov 23, 2017
98ec415
Implement twilight model ctor
dkirkby Nov 23, 2017
7b98c4b
Implement Twilight model getter/setters
dkirkby Nov 23, 2017
cbc85e3
Implement twilight model in standalone func with unit tests
dkirkby Nov 23, 2017
c232502
Allow travis test failures with astropy dev
dkirkby Nov 23, 2017
4cd8b50
Add twilight polar plot
dkirkby Nov 23, 2017
7a03996
Fix sphinx error
dkirkby Nov 23, 2017
23e72b4
Flesh out docstring
dkirkby Nov 25, 2017
54c8968
Implement optional dark subtraction from twilight model
dkirkby Nov 25, 2017
a5166c2
Scale solar spectrum for twilight prediction
dkirkby Nov 25, 2017
ee81881
Incorporate Twilight into Atmosphere
dkirkby Nov 25, 2017
77a7151
Remove obsolete sky_conditions logic
dkirkby Nov 25, 2017
e7f4f44
Update user docs to include twilight examples
dkirkby Nov 26, 2017
f4b1828
Use updated (x,y) parameterization from Sergey
dkirkby Nov 26, 2017
e748b42
Implement autoranging for twilight plot
dkirkby Nov 26, 2017
b371e5c
Use r-band fit instead of i-band for twilight model
dkirkby Nov 26, 2017
6c020fe
Add extinction to twilight model
dkirkby Nov 27, 2017
5c93325
Update documentation plots
dkirkby Nov 27, 2017
c1e3c66
Add new plot to help explain twilight model
dkirkby Nov 27, 2017
14d401f
Fix some doc typos
dkirkby Nov 27, 2017
a8877e7
Update default subtract_dark value for r-band (increases twilight norm)
dkirkby Nov 27, 2017
636ddf4
Add units to twilight r-band mag
dkirkby Dec 1, 2017
8003dd9
Add units to calculated twilight r-mag
dkirkby Dec 1, 2017
d702098
Scale dark sky emission with airmass
dkirkby Dec 1, 2017
51647d4
Fix typo
dkirkby Dec 1, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -77,10 +77,12 @@ matrix:
- os: linux
env: SETUP_CMD='build_docs -w'

# Now try Astropy dev and LTS vesions with the latest 3.x and 2.7.
# Try astropy dev version.
- os: linux
env: ASTROPY_VERSION=development
EVENT_TYPE='pull_request push cron'

# Now try Astropy LTS vesions with the latest 3.x and 2.7.
- os: linux
env: PYTHON_VERSION=2.7 ASTROPY_VERSION=lts
- os: linux
@@ -110,6 +112,13 @@ matrix:
env: MAIN_CMD='pycodestyle packagename --count' SETUP_CMD=''

allow_failures:
# Try astropy dev version. This current causes some doctests
# to fail because they produce the following unexpected output:
# Downloading http://maia.usno.navy.mil/ser7/finals2000A.all [Done]
# from `simulator = specsim.simulator.Simulator('test')``
- os: linux
env: ASTROPY_VERSION=development
EVENT_TYPE='pull_request push cron'
# Do a PEP8 test with pycodestyle
# (allow to fail unless your code completely compliant)
- os: linux
6 changes: 4 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
0.12 (unreleased)
-----------------

- No changes yet.
- Scale the dark sky spectrum with airmass.
- Implement Twilight sky brightness model and integrate with Atmosphere model.
- Remove obsolete sky_conditions parameter and only read tabulated dark sky.

0.11 (2017-10-10)
0.11 (2017-11-10)
-----------------

- Implement fast fiberloss calculator that interpolates GalSim results (#78).
Binary file modified docs/_static/desi_atmosphere.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/desi_moon_atmosphere.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/desi_moon_twilight_atmosphere.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/desi_twilight_polar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/twilight_spectrum.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 46 additions & 15 deletions docs/config.rst
Original file line number Diff line number Diff line change
@@ -117,13 +117,14 @@ multi-HDU FITS file::
In this case the HDU and columns are identified by their names in the FITS file.

Finally, some tabulated data uses different files to represent different options.
For example, sky surface brightness tables under different conditions are
For example, fiberloss tables for different source types are
specified by replacing the ``path`` node with a ``paths`` node as follows::

paths:
dark: dark-sky.csv
grey: grey-sky.csv
bright: bright-sky.csv
# Each path corresponds to a different source type.
qso: throughput/fiberloss-qso.dat
elg: throughput/fiberloss-elg.dat
lrg: throughput/fiberloss-lrg.dat

For additional examples of specifying tabular data, refer to the configurations
included with this package and described below.
@@ -182,37 +183,67 @@ The following plot summarizes the default DESI atmosphere used for simulations,
and was created using::

config = specsim.config.load_config('desi')
specsim.atmosphere.initialize(config).plot()
atm = specsim.atmosphere.initialize(config)
atm.plot()

.. image:: _static/desi_atmosphere.png
:alt: DESI default atmosphere configuration

The default atmosphere has the moon below the horizon. To simulate grey or
bright conditions, add scattered moon light by :doc:`modifying the relevant
parameters in the configuration </api>`, or else by changing attributes of the
initialized atmosphere model. For example::
The default atmosphere has the moon below the horizon. To add scattered
moonlight, :doc:`adjust the relevant parameters in the configuration </api>`,
or change attributes of the initialized atmosphere model. For example::

atm = specsim.atmosphere.initialize(config)
atm.airmass = 1.3
atm.moon.moon_zenith = 60 * u.deg
atm.moon.separation_angle = 50 * u.deg
atm.moon.moon_phase = 0.25
atm.plot()

.. image:: _static/desi_bright_atmosphere.png
:alt: DESI bright atmosphere configuration
.. image:: _static/desi_moon_atmosphere.png
:alt: DESI moon configuration

To add an additional twilight component::

atm.twilight.sun_altitude = -13 * u.deg
atm.twilight.sun_relative_azimuth = 30 * u.deg
atm.plot()

.. image:: _static/desi_moon_twilight_atmosphere.png
:alt: DESI moon plus twilight configuration

Note how total sky emission has increased significantly and is dominated by
scattered moon at the blue end. To explore the dependence of the scattered
moon brightness on the observed field, use
:func:`specsim.atmosphere.plot_lunar_brightness`. For example::
scattered moon at the blue end and twilight sun at the red end. To explore
the dependence of scattering on the observing conditions, use the
:func:`plot_lunar_brightness <specsim.atmosphere.plot_lunar_brightness>` and
:func:`plot_twlight_brightness <specsim.atmosphere.plot_twilight_brightness>`
functions. For example::

specsim.atmosphere.plot_lunar_brightness(
moon_zenith=60*u.deg, moon_azimuth=90*u.deg, moon_phase=0.25)

.. image:: _static/desi_scattered_moon.png
:alt: DESI scattered moon brightness

and::

specsim.atmosphere.plot_twilight_brightness(
sun_altitude=-13*u.deg, sun_azimuth=90*u.deg)

.. image:: _static/desi_twilight_polar.png
:alt: DESI twlight brightness

For an explanatory plot of the twilight spectrum, use::

atm.twilight.plot_spectrum()

.. image:: _static/twilight_spectrum.png
:alt: DESI twilight spectrum

Note how the twilight spectrum is significantly reddened relative to the
solar spectrum above the atmosphere (yellow) since it passes through a
large airmass (X~40) before scattering in the atmosphere above the observing
line of sight.

Instrument
^^^^^^^^^^

6 changes: 3 additions & 3 deletions docs/guide.rst
Original file line number Diff line number Diff line change
@@ -42,9 +42,9 @@ independent of its SED.
Atmosphere Model
----------------

The atmosphere adds its own emission spectrum :math:`b(\lambda)` to that of the
source and then both are attenuated by their passage through the atmosphere by
the extinction factor:
The atmosphere adds its own emission spectrum :math:`b(\lambda) X` to that of
the source and then both are attenuated by their passage through the atmosphere
by the extinction factor:

.. math::
10 changes: 2 additions & 8 deletions docs/nb/config/desi-blur-offset-scale-stochastic.yaml
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ wavelength_grid:
# The atmosphere configuration is interpreted and validated by the
# specsim.atmosphere module.
atmosphere:
# Sky emission surface brightness.
# Dark sky emission surface brightness.
sky:
table:
# The .dat extension is not automatically recognized as ascii.
@@ -42,13 +42,7 @@ atmosphere:
index: 1
# Note the factor of 1e-17 in the units!
unit: 1e-17 erg / (Angstrom arcsec2 cm2 s)
paths:
# Each path defines a possible condition.
dark: spectra/spec-sky.dat
grey: spectra/spec-sky-grey.dat
bright: spectra/spec-sky-bright.dat
# Specify the current condition.
condition: dark
path: spectra/spec-sky.dat
# Atmospheric seeing (only used when instrument.fiberloss.method = galsim)
seeing:
# The seeing is assumed to scale with wavelength as
10 changes: 2 additions & 8 deletions docs/nb/config/desi-blur-offset-scale.yaml
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ wavelength_grid:
# The atmosphere configuration is interpreted and validated by the
# specsim.atmosphere module.
atmosphere:
# Sky emission surface brightness.
# Dark sky emission surface brightness.
sky:
table:
# The .dat extension is not automatically recognized as ascii.
@@ -42,13 +42,7 @@ atmosphere:
index: 1
# Note the factor of 1e-17 in the units!
unit: 1e-17 erg / (Angstrom arcsec2 cm2 s)
paths:
# Each path defines a possible condition.
dark: spectra/spec-sky.dat
grey: spectra/spec-sky-grey.dat
bright: spectra/spec-sky-bright.dat
# Specify the current condition.
condition: dark
path: spectra/spec-sky.dat
# Atmospheric seeing (only used when instrument.fiberloss.method = galsim)
seeing:
# The seeing is assumed to scale with wavelength as
10 changes: 2 additions & 8 deletions docs/nb/config/desi-blur-offset.yaml
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ wavelength_grid:
# The atmosphere configuration is interpreted and validated by the
# specsim.atmosphere module.
atmosphere:
# Sky emission surface brightness.
# Dark sky emission surface brightness.
sky:
table:
# The .dat extension is not automatically recognized as ascii.
@@ -42,13 +42,7 @@ atmosphere:
index: 1
# Note the factor of 1e-17 in the units!
unit: 1e-17 erg / (Angstrom arcsec2 cm2 s)
paths:
# Each path defines a possible condition.
dark: spectra/spec-sky.dat
grey: spectra/spec-sky-grey.dat
bright: spectra/spec-sky-bright.dat
# Specify the current condition.
condition: dark
path: spectra/spec-sky.dat
# Atmospheric seeing (only used when instrument.fiberloss.method = galsim)
seeing:
# The seeing is assumed to scale with wavelength as
10 changes: 2 additions & 8 deletions docs/nb/config/desi-blur.yaml
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ wavelength_grid:
# The atmosphere configuration is interpreted and validated by the
# specsim.atmosphere module.
atmosphere:
# Sky emission surface brightness.
# Dark sky emission surface brightness.
sky:
table:
# The .dat extension is not automatically recognized as ascii.
@@ -42,13 +42,7 @@ atmosphere:
index: 1
# Note the factor of 1e-17 in the units!
unit: 1e-17 erg / (Angstrom arcsec2 cm2 s)
paths:
# Each path defines a possible condition.
dark: spectra/spec-sky.dat
grey: spectra/spec-sky-grey.dat
bright: spectra/spec-sky-bright.dat
# Specify the current condition.
condition: dark
path: spectra/spec-sky.dat
# Atmospheric seeing (only used when instrument.fiberloss.method = galsim)
seeing:
# The seeing is assumed to scale with wavelength as
653 changes: 564 additions & 89 deletions specsim/atmosphere.py

Large diffs are not rendered by default.

38 changes: 28 additions & 10 deletions specsim/data/config/desi.yaml
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ wavelength_grid:
# The atmosphere configuration is interpreted and validated by the
# specsim.atmosphere module.
atmosphere:
# Sky emission surface brightness.
# Dark sky emission surface brightness at airmass=1.
sky:
table:
# The .dat extension is not automatically recognized as ascii.
@@ -42,13 +42,7 @@ atmosphere:
index: 1
# Note the factor of 1e-17 in the units!
unit: 1e-17 erg / (Angstrom arcsec2 cm2 s)
paths:
# Each path defines a possible condition.
dark: spectra/spec-sky.dat
grey: spectra/spec-sky-grey.dat
bright: spectra/spec-sky-bright.dat
# Specify the current condition.
condition: dark
path: spectra/spec-sky.dat
# Atmospheric seeing (only used when instrument.fiberloss.method = galsim)
seeing:
# The seeing is assumed to scale with wavelength as
@@ -77,11 +71,35 @@ atmosphere:
constants:
# Phase of the moon from 0 (full) to 1 (new).
moon_phase: 0.5
# Zenith angles of the moon. An angle > 90 (below the horizon)
# Zenith angle of the moon. An angle > 90 (below the horizon)
# will zero the scattered moon contribution.
moon_zenith: 100 deg
# Separation angle between the observation and moon.
separation_angle: 60 deg
twilight:
# Un-normalized spectrum of scattered twilight sun.
# Use the same Wehrli 1985 extraterrestial solar spectrum for now.
table:
columns:
wavelength: { index: 1, unit: Angstrom }
flux:
index: 2
# The actual units are W / (m2 micron) but we lie here
# (by a factor of 10) since the input normalization does
# not matter and old versions of speclite.filters do
# not interpret the actual units correctly.
unit: erg / (cm2 s Angstrom)
path: sky/solarspec.txt
format: ascii.basic
constants:
# Altitude angle of the sun. The model is only valid for
# altitudes < -12 deg and altitudes < -18 deg will have no
# twilight contribution.
sun_altitude: -20 deg
# Azimuth angle of the pointing relative to the sun.
# Must be in the range [0, 180] deg, with 0 deg corresponding
# to pointing directly towards the sun.
sun_relative_azimuth: 90 deg
# Zenith extinction coefficients.
extinction:
table:
@@ -143,7 +161,7 @@ instrument:
columns:
wavelength: { index: 0, unit: Angstrom }
fiber_acceptance: { index: 1 }
# Fits file of precomputed galsim fiber acceptance
# Fits file of precomputed galsim fiber acceptance
# the fits file is created with specsim/fitgalsim.py
# the fits file is read with specsim/fastfiberacceptance.py
fast_fiber_acceptance_path: throughput/galsim-fiber-acceptance.fits
22 changes: 20 additions & 2 deletions specsim/data/config/test.yaml
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ wavelength_grid:
# The atmosphere configuration is interpreted and validated by the
# specsim.atmosphere module.
atmosphere:
# Sky emission surface brightness.
# Dark sky emission surface brightness at airmass=1.
sky:
table:
# The .ecsv extension is not automatically recognized.
@@ -29,7 +29,6 @@ atmosphere:
wavelength: { name: wavelength }
surface_brightness: { name: flux }
path: test/test_sky.ecsv
condition: default
# Atmospheric seeing (only used when instrument.fiberloss.method = galsim)
seeing:
# The seeing is assumed to scale with wavelength as
@@ -55,6 +54,25 @@ atmosphere:
moon_zenith: 70 deg
# Separation angle between the observation and moon.
separation_angle: 60 deg
twilight:
# Un-normalized spectrum of scattered twilight sun.
# Use the same Wehrli 1985 extraterrestial solar spectrum for now.
table:
# The .ecsv extension is not automatically recognized.
format: ascii.ecsv
columns:
wavelength: { name: wavelength }
flux: { name: flux }
path: test/test_solar.ecsv
constants:
# Altitude angle of the sun. The model is only valid for
# altitudes < -12 deg and altitudes < -18 deg will have no
# twilight contribution.
sun_altitude: -15 deg
# Azimuth angle of the pointing relative to the sun.
# Must be in the range [0, 180] deg, with 0 deg corresponding
# to pointing directly towards the sun.
sun_relative_azimuth: 90 deg
# Zenith extinction coefficients.
extinction:
table:
4 changes: 0 additions & 4 deletions specsim/quickspecsim.py
Original file line number Diff line number Diff line change
@@ -27,8 +27,6 @@ def main(args=None):
help='name of the simulation configuration to use')
parser.add_argument('--exposure-time', type=str, default='1000s',
help='exposure time in to use (with units)')
parser.add_argument('--sky-condition', type=str, default=None,
help='sky condition to use (uses default if not set)')
parser.add_argument('--airmass', type=float, default=1.,
help='atmosphere airmass to use.')
parser.add_argument('--moon-phase', type=float, default=None, metavar='P',
@@ -66,8 +64,6 @@ def main(args=None):
# Update configuration options from command-line options.
config.verbose = args.verbose

if args.sky_condition is not None:
config.atmosphere.sky.condition = args.sky_condition
config.atmosphere.airmass = args.airmass
if (args.moon_phase is not None or args.moon_zenith is not None or
args.moon_separation is not None):
56 changes: 51 additions & 5 deletions specsim/tests/test_atmosphere.py
Original file line number Diff line number Diff line change
@@ -26,8 +26,6 @@ def test_read_only_properties():
a = initialize(c)
with pytest.raises(AttributeError):
a.moon = None
with pytest.raises(AttributeError):
a.condition_names = None
with pytest.raises(AttributeError):
a.surface_brightness = None
with pytest.raises(AttributeError):
@@ -49,8 +47,9 @@ def test_property_updates():
m = a.moon

assert m._update_required == True
sb = 2.0464695e-17
assert np.allclose(
np.mean(a.surface_brightness.value), 1.563611e-17, atol=0.)
np.mean(a.surface_brightness.value), sb, atol=0.)
assert m.visible == True
assert np.allclose(m.obs_zenith.value, 0.)
# Evaluating the atmosphere surface_brightness updates the moon.
@@ -63,14 +62,14 @@ def test_property_updates():
assert m._update_required == True
assert np.allclose(m.obs_zenith.value, 1.20942920)
assert np.allclose(
np.mean(a.surface_brightness.value), 2.198837e-17, atol=0.)
np.mean(a.surface_brightness.value), 6.881726473e-17, atol=0.)
assert np.allclose(
np.mean(m.surface_brightness.value), 1.430046e-17, atol=0.)
assert m._update_required == False

a.airmass = 1.0
assert np.allclose(
np.mean(a.surface_brightness.value), 1.563611e-17, atol=0.)
np.mean(a.surface_brightness.value), sb, atol=0.)
assert np.allclose(
np.mean(m.surface_brightness.value), 6.370824e-18, atol=0.)
assert np.allclose(m.obs_zenith.value, 0.)
@@ -103,12 +102,59 @@ def test_seeing_none():
a.seeing_fwhm_ref = 1.5 * u.arcsec


def test_twilight_func():
def check(*args):
result = twilight_surface_brightness(*args, subtract_dark=None).value
assert np.all((result < 21.2) & (result > 18.2))
# Check limiting cases.
check(0 * u.deg, -12 * u.deg, 0 * u.deg)
check(90 * u.deg, -18 * u.deg, 1 * u.deg)
# Check broadcasting.
check(15 * u.deg, -15 * u.deg, 0 * u.rad)
check([15] * u.deg, -15 * u.deg, 0 * u.rad)
check([15] * u.deg, [-15] * u.deg, 0 * u.rad)
check([15] * u.deg, [-15] * u.deg, [0] * u.rad)
check(15 * u.deg, [-15] * u.deg, [0] * u.rad)
check(15 * u.deg, [-15] * u.deg, [0] * u.rad)
check([15] * u.deg, [-16, -15, -14] * u.deg, 0 * u.rad)
check([15, 15] * u.deg, -15 * u.deg, [0, 0] * u.rad)
check([15, 15] * u.deg, [-15, -20] * u.deg, [0, 0] * u.rad)
check([15, 15] * u.deg, -15 * u.deg, 0 * u.deg)
check([[15],[15]] * u.deg, [-16, -15, -14] * u.deg, 0 * u.rad)
# Check wraparound in azimuth.
check(15 * u.deg, -15 * u.deg, [-400, -90, 0, 90, 180, 270, 400] * u.deg)
# Verify range checks.
with pytest.raises(ValueError):
check(-1 * u.deg, -15 * u.deg, 0 * u.deg)
with pytest.raises(ValueError):
check([1, 91] * u.deg, -15 * u.deg, 0 * u.deg)
with pytest.raises(ValueError):
check(15 * u.deg, -10 * u.deg, 0 * u.deg)
with pytest.raises(ValueError):
check(15 * u.deg, [-10, -15] * u.deg, 0 * u.deg)
# Verify broadcasting checks.
with pytest.raises(ValueError):
check([15, 15] * u.deg, [-15, -15, -15] * u.deg, 0 * u.deg)
with pytest.raises(ValueError):
check([15, 15] * u.deg, -15 * u.deg, [0, 0, 0] * u.deg)
# Verify unit checking.
with pytest.raises(ValueError):
check(15, -15 * u.deg, 0 * u.deg)
with pytest.raises(ValueError):
check(15 * u.m, -15 * u.deg, 0 * u.deg)


def test_plot():
c = specsim.config.load_config('test')
a = initialize(c)
a.plot()


def test_plot_twilight():
plot_twilight_brightness(
sun_altitude=-15 * u.deg, sun_azimuth=90 * u.deg)


def test_plot_moon():
plot_lunar_brightness(
moon_zenith=60*u.deg, moon_azimuth=90*u.deg, moon_phase=0.25)