Skip to content

Commit 5e72b92

Browse files
committed
Start work on sun altitude interpolator
1 parent 0e8b170 commit 5e72b92

File tree

1 file changed

+86
-6
lines changed

1 file changed

+86
-6
lines changed

py/desisurvey/ephemerides.py

+86-6
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,16 @@ def __init__(self, start_date=None, stop_date=None, num_obj_steps=25,
169169
# tabulating the (ra,dec) of objects to avoid.
170170
t_obj = np.linspace(0., 1., num_obj_steps)
171171

172+
# Lookup sun altitude thresholds.
173+
bright_max_alt = (
174+
config.programs.BRIGHT.max_sun_altitude().to(u.rad).value)
175+
dark_max_alt = (
176+
config.programs.DARK.max_sun_altitude().to(u.rad).value)
177+
178+
rng = np.rad2deg(bright_max_alt - dark_max_alt)
179+
print('limits', rng)
180+
max_err = 0.
181+
172182
# Calculate ephmerides for each night.
173183
for day_offset in range(num_nights):
174184
day = self.start + day_offset * u.day
@@ -177,19 +187,34 @@ def __init__(self, start_date=None, stop_date=None, num_obj_steps=25,
177187
# Store local noon for this day.
178188
row['noon'] = day.mjd
179189
# Calculate bright twilight.
180-
mayall.horizon = (
181-
config.programs.BRIGHT.max_sun_altitude().to(u.rad).value)
190+
mayall.horizon = bright_max_alt
182191
row['brightdusk'] = mayall.next_setting(
183192
ephem.Sun(), use_center=True) + mjd0
184193
row['brightdawn'] = mayall.next_rising(
185194
ephem.Sun(), use_center=True) + mjd0
186195
# Calculate dark / gray twilight.
187-
mayall.horizon = (
188-
config.programs.DARK.max_sun_altitude().to(u.rad).value)
196+
mayall.horizon = dark_max_alt
189197
row['dusk'] = mayall.next_setting(
190198
ephem.Sun(), use_center=True) + mjd0
191199
row['dawn'] = mayall.next_rising(
192200
ephem.Sun(), use_center=True) + mjd0
201+
# Calculate the midpoint between BRIGHT/DARK twilight.
202+
mayall.horizon = 0.5 * (
203+
config.programs.BRIGHT.max_sun_altitude().to(u.rad).value +
204+
config.programs.DARK.max_sun_altitude().to(u.rad).value)
205+
middusk = mayall.next_setting(
206+
ephem.Sun(), use_center=True) + mjd0
207+
middawn = mayall.next_rising(
208+
ephem.Sun(), use_center=True) + mjd0
209+
# Compare with linear extrapolations.
210+
middusk_pred = 0.5 * (row['brightdusk'] + row['dusk'])
211+
middawn_pred = 0.5 * (row['brightdawn'] + row['dawn'])
212+
dawn = (row['brightdawn'] - row['dawn'])
213+
dusk = (row['dusk'] - row['brightdusk'])
214+
dusk_err = (middusk_pred - middusk) / dusk * rng
215+
dawn_err = (middusk_pred - middusk) / dawn * rng
216+
#print('dawn/dusk (arcsec)', dusk_err * 3600, dawn_err * 360)
217+
max_err = max(max_err, abs(dusk_err), abs(dawn_err))
193218
# Calculate the moonrise/set for any moon visible tonight.
194219
m0 = ephem.Moon()
195220
mayall.horizon = '-0:34' # the value that the USNO uses.
@@ -212,6 +237,8 @@ def __init__(self, start_date=None, stop_date=None, num_obj_steps=25,
212237
row[name + '_ra'][i] = math.degrees(float(model.ra))
213238
row[name + '_dec'][i] = math.degrees(float(model.dec))
214239

240+
print('max_err', max_err * 3600, 'arcsec')
241+
215242
# Initialize a grid covering each night with 15sec resolution
216243
# for tabulating the night program.
217244
t_grid = get_grid(step_size=15 * u.s)
@@ -291,8 +318,7 @@ def get_moon_illuminated_fraction(self, mjd):
291318
Parameters
292319
----------
293320
mjd : float or array
294-
MJD values during a single night where the program should be
295-
tabulated.
321+
MJD values where the illuminated fraction should be tabulated.
296322
297323
Returns
298324
-------
@@ -423,6 +449,60 @@ def is_full_moon(self, night, num_nights=None):
423449
return index - lo in sort_order[-num_nights:]
424450

425451

452+
def get_sun_altitude(row, mjd):
453+
"""Return the sun altitude at the specified time for twilight modeling.
454+
455+
This function only returns values in the range [-10, -20] deg
456+
since values outside this range are either never used for observing
457+
or else considered completely dark.
458+
459+
The calculation uses linear interpolation of the tabulated times when the
460+
sun passes through the bright and dark maximum altitudes, nominally -13
461+
and -15 deg, which provides an altitude accurate to better than 30"
462+
between these limits.
463+
464+
Parameters
465+
----------
466+
row : astropy.table.Row
467+
A single row from the ephemerides astropy Table corresponding to the
468+
night in question.
469+
mjd : float
470+
MJD value(s) during a single night where the sun altitude should be
471+
calculated.
472+
473+
Returns
474+
-------
475+
astropy.units.Quantity
476+
Sun altitude(s) in degrees at each input mjd value, clipped to
477+
the range [-10, -20].
478+
"""
479+
# Lookup the bright, dark threshold altitudes.
480+
config = desisurvey.config.Configuration()
481+
bright_max_alt = config.programs.BRIGHT.max_sun_altitude()
482+
dark_max_alt = config.programs.DARK.max_sun_altitude()
483+
484+
# Validate input timestamp(s)
485+
mjd = np.asarray(mjd)
486+
scalar = mjd.ndim == 0
487+
mjd = np.atleast1d(mjd)
488+
midnight = 0.5 * (row['dusk'] + row['dawn'])
489+
if np.any(np.abs(mjd - midnight) > 0.5):
490+
raise ValueError('mjd is not associated with the specified night')
491+
492+
# Use linear interpolation on the dusk timestamps for times before midnight.
493+
sun_alt = np.empty_like(mjd)
494+
at_dusk = mjd < midnight
495+
sun_alt[at_dusk] = bright_max_alt + (bright_max_alt - dark_max_alt) * (
496+
mjd[at_dusk] - row['brightdusk']) / (row['dusk'] - row['brightdusk'])
497+
498+
# Use linear interpolation on the dawn timestamps after midnight.
499+
at_dawn = ~at_dusk
500+
sun_alt[at_dawn] = bright_max_alt + (bright_max_alt - dark_max_alt) * (
501+
mjd[at_dawn] - row['brightdawn']) / (row['dusk'] - row['brightdusk'])
502+
503+
return sun_alt
504+
505+
426506
def get_object_interpolator(row, object_name, altaz=False):
427507
"""Build an interpolator for object location during one night.
428508

0 commit comments

Comments
 (0)