Skip to content

Commit b57fa5d

Browse files
committed
add SAT scheduler run page
1 parent c9f4660 commit b57fa5d

File tree

1 file changed

+217
-0
lines changed

1 file changed

+217
-0
lines changed

src/pages/6_SAT_Scheduler.py

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
import os
2+
import yaml
3+
4+
import argparse
5+
import datetime as dt
6+
from schedlib import utils as u
7+
from schedlib.quality_assurance import SunCrawler
8+
9+
import streamlit as st
10+
from matplotlib.backends.backend_agg import RendererAgg
11+
from threading import RLock
12+
13+
logger = u.init_logger(__name__)
14+
15+
_lock = RLock()
16+
17+
schedule_base_dir = os.environ.get("SCHEDULE_BASE_DIR", 'master_schedules/')
18+
# dictionary goes dict[elevation][sun_keepout]
19+
schedule_files = {
20+
50 : {
21+
45: os.path.join(schedule_base_dir, '20250411_d-40,-10_e50_s0.5,0.8_a45_j2025-02-15T12:00+00:00_n365.txt'),
22+
49: os.path.join(schedule_base_dir, '20250411_d-40,-10_e50_s0.5,0.8_a49_j2025-02-15T12:00+00:00_n365.txt'),
23+
},
24+
60 : {
25+
45: os.path.join(schedule_base_dir, '20250411_d-40,-10_e60_s0.5,0.8_a45_j2025-02-15T12:00+00:00_n365.txt'),
26+
49: os.path.join(schedule_base_dir, '20250411_d-40,-10_e60_s0.5,0.8_a49_j2025-02-15T12:00+00:00_n365.txt'),
27+
}
28+
}
29+
30+
cal_files = {
31+
50 : {
32+
45: os.path.join(schedule_base_dir, '20250411_d-40,-10_e50_s0.5,0.8_a45_j2025-02-15T12:00+00_:00_n365_planets.txt'),
33+
49: os.path.join(schedule_base_dir, '20250411_d-40,-10_e50_s0.5,0.8_a45_j2025-02-15T12:00+00:00_n365_planets.txt'),
34+
},
35+
60 : {
36+
45: os.path.join(schedule_base_dir, '20250411_d-40,-10_e60_s0.5,0.8_a45_j2025-02-15T12:00+00:00_n365_planets.txt'),
37+
49: os.path.join(schedule_base_dir, '20250411_d-40,-10_e60_s0.5,0.8_a49_j2025-02-15T12:00+00:00_n365_planets.txt'),
38+
}
39+
}
40+
41+
wiregrid_files = {
42+
50 : {
43+
45: os.path.join(schedule_base_dir, '20250411_d-40,-10_e50_s0.5,0.8_a45_j2025-02-15T12:00+00:00_n365_wiregrid.txt'),
44+
49: os.path.join(schedule_base_dir, '20250411_d-40,-10_e50_s0.5,0.8_a45_j2025-02-15T12:00+00:00_n365_wiregrid.txt'),
45+
},
46+
60 : {
47+
45: os.path.join(schedule_base_dir, '20250411_d-40,-10_e60_s0.5,0.8_a45_j2025-02-15T12:00+00:00_n365_wiregrid.txt'),
48+
49: os.path.join(schedule_base_dir, '20250411_d-40,-10_e60_s0.5,0.8_a49_j2025-02-15T12:00+00:00_n365_wiregrid.txt'),
49+
}
50+
}
51+
52+
left_column, right_column = st.columns(2)
53+
init_end_date = dt.date.today() + dt.timedelta(days=1)
54+
55+
with left_column:
56+
start_date = st.date_input("Start date", value=dt.date.today(), key='start_date')
57+
end_date = st.date_input("End date", value=init_end_date, key='end_date')
58+
59+
platform = st.selectbox("Platform:", options=["satp1", "satp2", "satp3"])
60+
elevation = st.selectbox("CMB Scan Elevation:", options=[50, 60], index=1)
61+
62+
use_cal_file = st.checkbox("Use Calibration File", value=False)
63+
use_wiregrid_file = st.checkbox("Use Wiregrid File", value=False)
64+
65+
boresight = st.number_input("Boresight (deg)", value=0.0)
66+
# cal_targets = st.text_input("Calibration Targets (comma-separated)")
67+
68+
no_cmb = st.checkbox("No CMB", value=False)
69+
az_speed = st.number_input("Azimuth Speed (deg/s)", value=0.5)
70+
az_accel = st.number_input("Azimuth Acceleration (deg/s²)", value=0.25)
71+
az_offset = st.number_input("Azimuth Offset (deg)", value=0.0)
72+
el_offset = st.number_input("Elevation Offset (deg)", value=0.0)
73+
xi_offset = st.number_input("Xi Offset (deg)", value=0.0)
74+
eta_offset = st.number_input("Eta Offset (deg)", value=0.0)
75+
iv_cadence = st.number_input("IV Cadence (seconds)", value=14400)
76+
bias_step_cadence = st.number_input("Bias Step Cadence (seconds)", value=1800)
77+
min_hwp_el = st.number_input("Min HWP Elevation (deg)", value=48.0)
78+
max_cmb_scan_duration = st.number_input("Max CMB Scan Duration (seconds)", value=3600)
79+
80+
with right_column:
81+
start_time = st.time_input("Start time (UTC)", value=dt.datetime.utcnow().time(), key='start_time')
82+
end_time = st.time_input("End time (UTC)", value=dt.datetime.utcnow().time(), key='end_time')
83+
84+
hwp_override = st.checkbox("HWP Override", value=False)
85+
az_motion_override = st.checkbox("Az Motion Override", value=False)
86+
home_at_end = st.checkbox("Home at End", value=False)
87+
relock_cadence = st.number_input("Relock Cadence (seconds)", value=86400)
88+
disable_hwp = st.checkbox("Disable HWP", value=False)
89+
if platform in ['satp1', 'satp2']:
90+
brake_default = True
91+
bore_rot = True
92+
elif platform in ['satp3']:
93+
brake_default = False
94+
bore_rot = False
95+
brake_hwp = st.checkbox("Brake HWP", value=brake_default)
96+
apply_boresight_rotation = st.checkbox("Apply Boresight Rotation", value=bore_rot)
97+
az_branch_override = st.number_input("Az Branch Override (deg)", value=180.0)
98+
allow_partial_override = st.checkbox("Allow Partial Override", value=False)
99+
drift_override = st.checkbox("Drift Override", value=True)
100+
wiregrid_az = st.number_input("Wiregrid Azimuth (deg)", value=180.0)
101+
wiregrid_el = st.number_input("Wiregrid Elevation (deg)", value=48.0)
102+
# outfile = st.text_input("Output Filename")
103+
# cal_anchor_time = st.text_input("Calibration Anchor Time")
104+
105+
if st.button('Generate Schedule'):
106+
t0 = dt.datetime.combine(
107+
start_date, start_time, tzinfo=dt.timezone.utc
108+
)
109+
t1 = dt.datetime.combine(
110+
end_date, end_time, tzinfo=dt.timezone.utc
111+
)
112+
113+
cal_targets = []
114+
t0_state_file = None
115+
cal_anchor_time = None
116+
117+
match platform:
118+
case "satp1":
119+
from schedlib.policies.satp1 import SATP1Policy as Policy
120+
case "satp2":
121+
from schedlib.policies.satp2 import SATP2Policy as Policy
122+
case "satp3":
123+
from schedlib.policies.satp3 import SATP3Policy as Policy
124+
125+
if no_cmb:
126+
sfile = os.path.join(schedule_base_dir, "empty_cmb.txt")
127+
else:
128+
sfile = schedule_files[int(elevation)]
129+
if use_cal_file:
130+
cfile = cal_files[int(elevation)]
131+
else:
132+
cfile = None
133+
if use_wiregrid_file:
134+
wgfile = wiregrid_files[int(elevation)]
135+
else:
136+
wgfile = None
137+
if platform == 'satp1':
138+
sfile = sfile[45] # absorptive baffle runs 45 degree keepout
139+
if use_cal_file:
140+
cfile = cfile[45]
141+
if use_wiregrid_file:
142+
wgfile = wgfile[45]
143+
elif platform in ['satp2', 'satp3']:
144+
sfile = sfile[49] # reflective baffle runs 49 degree keepout
145+
if use_cal_file:
146+
cfile = cfile[49]
147+
if use_wiregrid_file:
148+
wgfile = wgfile[49]
149+
if not os.path.exists(sfile):
150+
raise ValueError(f"Schedule file {sfile} does not exist")
151+
if use_cal_file and not os.path.exists(cfile):
152+
raise ValueError(f"Cal file {sfile} does not exist")
153+
154+
if (not t0_state_file is None) and (not os.path.exists(t0_state_file)):
155+
print(f"Not using state file {t0_state_file} because it doesn't exist")
156+
t0_state_file = None
157+
158+
if relock_cadence == "None":
159+
relock_cadence = None
160+
cfg = {
161+
'az_speed': az_speed,
162+
'az_accel': az_accel,
163+
'az_offset': az_offset,
164+
'el_offset': el_offset,
165+
'xi_offset': xi_offset,
166+
'eta_offset': eta_offset,
167+
'iv_cadence': iv_cadence,
168+
'bias_step_cadence': bias_step_cadence,
169+
'min_hwp_el': min_hwp_el,
170+
'max_cmb_scan_duration': max_cmb_scan_duration,
171+
'disable_hwp': disable_hwp,
172+
'brake_hwp': brake_hwp,
173+
'apply_boresight_rot': apply_boresight_rotation,
174+
'boresight_override': boresight,
175+
'hwp_override': hwp_override,
176+
'az_motion_override': az_motion_override,
177+
'home_at_end': home_at_end,
178+
'relock_cadence': relock_cadence,
179+
'az_branch_override': az_branch_override,
180+
'allow_partial_override': allow_partial_override,
181+
'drift_override': drift_override,
182+
'wiregrid_az': wiregrid_az,
183+
'wiregrid_el': wiregrid_el,
184+
}
185+
186+
policy = Policy.from_defaults(
187+
master_file=sfile,
188+
state_file = t0_state_file,
189+
**cfg
190+
)
191+
192+
policy.cal_targets = []
193+
for target in cal_targets:
194+
tb = target.get('boresight', None)
195+
if tb is None:
196+
target['boresight'] = boresight
197+
policy.add_cal_target(**target)
198+
199+
seq = policy.init_cmb_seqs(t0, t1)
200+
seq = policy.init_cal_seqs(cfile, wgfile, seq, t0, t1, cal_anchor_time)
201+
seq = policy.apply(seq)
202+
cmds, state = policy.seq2cmd(seq, t0, t1, return_state=True)
203+
schedule = policy.cmd2txt(cmds, t0, t1)
204+
205+
sun_safe = False
206+
try:
207+
## check sun safety
208+
sc = SunCrawler(platform, cmd_txt=schedule, az_offset=az_offset, el_offset=el_offset)
209+
sc.step_thru_schedule()
210+
except Exception as e:
211+
print("SCHEDULE NOT SUN SAFE")
212+
sun_safe=False
213+
214+
if not sun_safe:
215+
st.error("SunCrawer found the schedule is not Sun Safe")
216+
217+
st.code(schedule, language="text")

0 commit comments

Comments
 (0)