Skip to content

Commit 4a0e24f

Browse files
committed
Add calculate_observing_night
1 parent dc04700 commit 4a0e24f

File tree

3 files changed

+126
-0
lines changed

3 files changed

+126
-0
lines changed

src/adam_core/observers/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# flake8: noqa: F401
22
from .observers import Observers
33
from .state import get_observer_state
4+
from .utils import calculate_observing_night
45

56
__all__ = ["Observers", "get_observer_state"]
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import pyarrow as pa
2+
import pyarrow.compute as pc
3+
4+
from ...time import Timestamp
5+
from ..utils import calculate_observing_night
6+
7+
8+
def test_calculate_observing_night() -> None:
9+
# Rubin Observatory is UTC-7
10+
# Reasonable observating times would be +- 12 hours from local midnight
11+
# or 7:00 to 17:00 UTC
12+
13+
# ZTF is UTC-8
14+
# Reasonable observating times would be +- 12 hours from local midnight
15+
# or 8:00 to 16:00 UTC
16+
17+
# M22 is UTC+2
18+
# Reasonable observating times would be +- 12 hours from local midnight
19+
# or 22:00 to 10:00 UTC
20+
21+
# 000 is UTC
22+
# Reasonable observating times would be +- 12 hours from local midnight
23+
# or 0:00 to 12:00 UTC
24+
25+
codes = pa.array([
26+
"X05", "X05", "X05", "X05", "X05",
27+
"I41", "I41", "I41", "I41", "I41",
28+
"M22", "M22", "M22", "M22", "M22",
29+
"000", "000", "000", "000", "000",
30+
])
31+
times_utc = Timestamp.from_mjd(
32+
[
33+
# Rubin Observatory
34+
59000 + 7 / 24 - 12 / 24,
35+
59000 + 7 / 24 - 6 / 24,
36+
59000 + 7 / 24,
37+
59000 + 7 / 24 + 6 / 24,
38+
59000 + 7 / 24 + 12 / 24,
39+
# ZTF
40+
59000 + 8 / 24 - 12 / 24,
41+
59000 + 8 / 24 - 4 / 24,
42+
59000 + 8 / 24,
43+
59000 + 8 / 24 + 4 / 24,
44+
59000 + 8 / 24 + 12 / 24,
45+
# M22
46+
59000 - 2 / 24 - 12 / 24,
47+
59000 - 2 / 24 - 6 / 24,
48+
59000 - 2 / 24,
49+
59000 - 2 / 24 + 6 / 24,
50+
59000 - 2 / 24 + 12 / 24,
51+
# 000
52+
59000 - 12 / 24,
53+
59000 - 6 / 24,
54+
59000,
55+
59000 + 6 / 24,
56+
59000 + 12 / 24,
57+
],
58+
scale="utc",
59+
)
60+
61+
observing_night = calculate_observing_night(codes, times_utc)
62+
desired = pa.array([
63+
58999, 58999, 58999, 58999, 59000,
64+
58999, 58999, 58999, 58999, 59000,
65+
58999, 58999, 58999, 58999, 59000,
66+
58999, 58999, 58999, 58999, 59000,
67+
])
68+
assert pc.all(pc.equal(observing_night, desired)).as_py()

src/adam_core/observers/utils.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from datetime import timedelta
2+
from zoneinfo import ZoneInfo
3+
4+
import numpy as np
5+
import pyarrow as pa
6+
import pyarrow.compute as pc
7+
from astropy.time import Time
8+
9+
from ..time import Timestamp
10+
from .observers import OBSERVATORY_PARALLAX_COEFFICIENTS
11+
12+
13+
def calculate_observing_night(codes: pa.Array, times: Timestamp) -> pa.Array:
14+
"""
15+
Compute the observing night for a given set of observatory codes and times. An observing night is defined as the night
16+
during which the observation is made, in the local time of the observatory +- 12 hours. The observing night is defined
17+
as the integer MJD of the night in the local time of the observatory.
18+
19+
Parameters
20+
----------
21+
codes : pyarrow.Array (N)
22+
An array of observatory codes.
23+
times : Timestamp (N)
24+
An array of times.
25+
26+
Returns
27+
-------
28+
observing_night : pyarrow.Array (N)
29+
An array of observing nights.
30+
"""
31+
half_day = timedelta(hours=12)
32+
observing_night = np.empty(len(times), dtype=np.int64)
33+
34+
for code in pc.unique(codes):
35+
36+
parallax_coefficients = OBSERVATORY_PARALLAX_COEFFICIENTS.select("code", code)
37+
if len(parallax_coefficients) == 0:
38+
raise ValueError(f"Unknown observatory code: {code}")
39+
40+
tz = ZoneInfo(parallax_coefficients.timezone()[0])
41+
42+
mask = pc.equal(codes, code)
43+
times_code = times.apply_mask(mask)
44+
45+
observing_night_code = Time(
46+
[
47+
time + time.astimezone(tz).utcoffset() - half_day
48+
for time in times_code.to_astropy().datetime
49+
],
50+
format="datetime",
51+
scale="utc",
52+
)
53+
observing_night_code = observing_night_code.mjd.astype(int)
54+
55+
observing_night[mask.to_numpy(zero_copy_only=False)] = observing_night_code
56+
57+
return pa.array(observing_night)

0 commit comments

Comments
 (0)