|
|
|
@ -314,7 +314,7 @@ def skip_intro_choices(clicks_wizard, clicks_expert, clicks_pickband, clicks_pic
@@ -314,7 +314,7 @@ def skip_intro_choices(clicks_wizard, clicks_expert, clicks_pickband, clicks_pic
|
|
|
|
|
clicks_continuum, clicks_line, |
|
|
|
|
a_wavelength, a_array, time_selection, starttime, starthour, obs_duration): |
|
|
|
|
if clicks_expert is not None: |
|
|
|
|
return main_page(None) |
|
|
|
|
return main_page() |
|
|
|
|
elif clicks_wizard is not None: |
|
|
|
|
return initial_page('band') |
|
|
|
|
elif clicks_pickband is not None: |
|
|
|
@ -325,10 +325,9 @@ def skip_intro_choices(clicks_wizard, clicks_expert, clicks_pickband, clicks_pic
@@ -325,10 +325,9 @@ def skip_intro_choices(clicks_wizard, clicks_expert, clicks_pickband, clicks_pic
|
|
|
|
|
#TODO: if dates are provided, all date/time/dur must be provided |
|
|
|
|
return initial_page('mode') |
|
|
|
|
elif clicks_continuum is not None: |
|
|
|
|
return compute_observation(n_clicks, band, starttime, starthour, duration, source, onsourcetime, |
|
|
|
|
datarate, subbands, channels, pols, inttime, guest_time, selected_tab, *ants) |
|
|
|
|
return initial_page('final') |
|
|
|
|
elif clicks_line is not None: |
|
|
|
|
return dash.no_update |
|
|
|
|
return initial_page('final') |
|
|
|
|
else: |
|
|
|
|
return dash.no_update |
|
|
|
|
|
|
|
|
@ -339,14 +338,14 @@ def initial_page(choice_card):
@@ -339,14 +338,14 @@ def initial_page(choice_card):
|
|
|
|
|
return [ |
|
|
|
|
html.Div(className='row justify-content-center', |
|
|
|
|
children=html.Div(className='col-sm-6 justify-content-center', |
|
|
|
|
children=[html.Div(className='justify-content-center', |
|
|
|
|
children=[#html.H3("Welcome!"), |
|
|
|
|
html.P(["The EVN Observation Planner allows you to plan observations with the ", |
|
|
|
|
html.A(href="https://www.evlbi.org", children="European VLBI Network"), |
|
|
|
|
" (EVN) and other Very Long Baseline Interferometry (VLBI) networks. " |
|
|
|
|
"The EVN Observation Planner helps you to determine when your source " |
|
|
|
|
"can be observed by the different antennas, and provides the expected " |
|
|
|
|
"outcome of these observations, like the expected sensitivity or resolution."]), |
|
|
|
|
children=[html.Div(className='justify-content-center', |
|
|
|
|
children=[#html.H3("Welcome!"), |
|
|
|
|
html.P(["The EVN Observation Planner allows you to plan observations with the ", |
|
|
|
|
html.A(href="https://www.evlbi.org", children="European VLBI Network"), |
|
|
|
|
" (EVN) and other Very Long Baseline Interferometry (VLBI) networks. " |
|
|
|
|
"The EVN Observation Planner helps you to determine when your source " |
|
|
|
|
"can be observed by the different antennas, and provides the expected " |
|
|
|
|
"outcome of these observations, like the expected sensitivity or resolution."]), |
|
|
|
|
html.Br(), |
|
|
|
|
*[ |
|
|
|
|
html.Div(hidden=False if choice_card == 'choice' else True, |
|
|
|
@ -359,6 +358,8 @@ def initial_page(choice_card):
@@ -359,6 +358,8 @@ def initial_page(choice_card):
|
|
|
|
|
children=ge.initial_window_pick_time()), |
|
|
|
|
html.Div(hidden=False if choice_card == 'mode' else True, |
|
|
|
|
children=ge.initial_window_pick_mode(app)), |
|
|
|
|
html.Div(hidden=False if choice_card == 'final' else True, |
|
|
|
|
children=ge.initial_window_final()), |
|
|
|
|
], |
|
|
|
|
], style={'text:align': 'justify !important'}) |
|
|
|
|
]) |
|
|
|
@ -366,10 +367,32 @@ def initial_page(choice_card):
@@ -366,10 +367,32 @@ def initial_page(choice_card):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main_page(a_wavelength): |
|
|
|
|
a_band = tuple(fs.bands)[a_wavelength] if a_wavelength is not None else None |
|
|
|
|
def final_guess_window(): |
|
|
|
|
return [ |
|
|
|
|
# First row containing all buttons/options, list of telescopes, and button with text output |
|
|
|
|
html.Div(), |
|
|
|
|
html.Div(className='row justify-content-center', children=[ |
|
|
|
|
html.H3('You are know ready'), |
|
|
|
|
html.P(["Press compute to produce the summary for your observation. " |
|
|
|
|
"You would then see different tabs with the information. " |
|
|
|
|
"You will also be able to change the setup and re-compute it."]), |
|
|
|
|
html.Br(), |
|
|
|
|
]), |
|
|
|
|
html.Span(style={'height': '2rem'}), |
|
|
|
|
html.Div(className='row justify-content-center', |
|
|
|
|
children=html.Button('Compute', id='antenna-selection-button', |
|
|
|
|
className='btn btn-primary btn-lg')), |
|
|
|
|
html.Div(className='col-9 text-center justify-content-center', children=[ |
|
|
|
|
dcc.Loading(id="loading", children=[html.Div(id="loading-output")], |
|
|
|
|
type="dot"), |
|
|
|
|
dcc.Loading(id="loading2", children=[html.Div(id="loading-output2")], |
|
|
|
|
type="dot") |
|
|
|
|
]) |
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main_page(results_visible=False): |
|
|
|
|
return [# First row containing all buttons/options, list of telescopes, and button with text output |
|
|
|
|
dcc.ConfirmDialog(id='global-error', message=''), |
|
|
|
|
# Elements in second column (checkboxes with all stations) |
|
|
|
|
html.Div(className='container-fluid', children=[ |
|
|
|
@ -380,49 +403,75 @@ def main_page(a_wavelength):
@@ -380,49 +403,75 @@ def main_page(a_wavelength):
|
|
|
|
|
html.Div('', style={'height': '70px'}), |
|
|
|
|
dcc.Loading(id="loading2", children=[html.Div(id="loading-output2")], |
|
|
|
|
type="dot"), |
|
|
|
|
html.Div(id='div-antenna-selection-button2', children=[]), |
|
|
|
|
html.Label('Your observing Band'), |
|
|
|
|
*ge.tooltip(idname='popover-band', |
|
|
|
|
html.Button('Compute observation', id='antenna-selection-button', |
|
|
|
|
className='btn btn-primary btn-lg', |
|
|
|
|
style={'width': '100%', 'margin-bottom': '1rem'}), |
|
|
|
|
]), |
|
|
|
|
html.Br(), |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
html.H6(['Your observing Band', |
|
|
|
|
*ge.tooltip(idname='popover-band', |
|
|
|
|
message="This will update the " |
|
|
|
|
"antenna list showing the ones that can observe " |
|
|
|
|
"at that given frequency."), |
|
|
|
|
dcc.Dropdown(id='band', persistence=True, value=a_band, |
|
|
|
|
"at that given frequency.") |
|
|
|
|
]), |
|
|
|
|
dcc.Dropdown(id='band', persistence=True, value=None, |
|
|
|
|
options=[{'label': fs.bands[b], 'value': b} for b \ |
|
|
|
|
# in fs.bands], value='18cm'), |
|
|
|
|
in fs.bands], placeholder='Select observing band...') |
|
|
|
|
|
|
|
|
|
in fs.bands], placeholder='Select observing band...'), |
|
|
|
|
]), |
|
|
|
|
html.Div(className='input-group-prepend', children=[ |
|
|
|
|
html.Br(), |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
html.H6(['Real-time correlation?', |
|
|
|
|
*ge.tooltip(idname='popover-eevn', |
|
|
|
|
message="Only available for the EVN: real-time correlation mode." |
|
|
|
|
"The data are transferred and correlated in real-time, but " |
|
|
|
|
"not all telescopes are capable for this and the bandwidth " |
|
|
|
|
"may be limited. Observations during the e-EVN epochs.") |
|
|
|
|
]), |
|
|
|
|
dbc.Checklist(id='e-EVN', className='checkbox', persistence=True, |
|
|
|
|
options=[{'label': ' e-EVN (real-time) mode', |
|
|
|
|
options=[{'label': ' e-EVN mode', |
|
|
|
|
'value': 'e-EVN'}], value=[]), |
|
|
|
|
*ge.tooltip(idname='popover-eevn', |
|
|
|
|
message="Only available for the EVN: real-time correlation mode.") |
|
|
|
|
]), |
|
|
|
|
html.Br(), |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
html.Label('Source (name or coordinates)'), |
|
|
|
|
*ge.tooltip(idname='popover-target', |
|
|
|
|
html.H6(['Source (name or coordinates)', |
|
|
|
|
*ge.tooltip(idname='popover-target', |
|
|
|
|
message="Source name or coordinates. " \ |
|
|
|
|
"You may see an error if the given name is not properly resolved. " |
|
|
|
|
"J2000 coordinates are assumed in both forms: 00:00:00 00:00:00 or " \ |
|
|
|
|
"00h00m00s 00d00m00s."), |
|
|
|
|
# dcc.Input(id='source', value='12:29:06.7 +02:03:08.6', type='text', |
|
|
|
|
"00h00m00s 00d00m00s.") |
|
|
|
|
]), |
|
|
|
|
dcc.Input(id='source', value=None, type='text', |
|
|
|
|
className='form-control', placeholder="hh:mm:ss dd:mm:ss", |
|
|
|
|
persistence=True), |
|
|
|
|
html.Small(id='error_source', style={'color': '#999999'}, |
|
|
|
|
className='form-text'), |
|
|
|
|
]), |
|
|
|
|
dbc.Tabs(children=[ |
|
|
|
|
dbc.Tab(label='Pick Epoch', id='tab-pick-epoch', tabClassName='tab-for-card', children=[ |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
dbc.Card(className='card-no-left-border', children=dbc.CardBody([ |
|
|
|
|
html.Br(), |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
html.H6('Epoch for observation'), |
|
|
|
|
dbc.FormGroup([ |
|
|
|
|
dbc.RadioItems(options=[{"label": "I don't have a preferred epoch", "value": False}, |
|
|
|
|
{"label": "I know the observing epoch", "value": True}], |
|
|
|
|
value=False, id="initial-timeselection", inline=True, persistence=True), |
|
|
|
|
], inline=True), |
|
|
|
|
html.Div(children=[ |
|
|
|
|
html.Div(id='initial-timeselection-div-guess', className='row justify-content-center', |
|
|
|
|
children=[ |
|
|
|
|
html.Small("Choose the first option to find out when your source " |
|
|
|
|
"may be visible (by >3 telescopes).", style={'color': '#999999'}), |
|
|
|
|
html.Small("Note that this option may not provide the best (expected) " |
|
|
|
|
"results in case of combining different networks very far apart " |
|
|
|
|
"(e.g. LBA and EVN).", style={'color': '#999999'}) |
|
|
|
|
]), |
|
|
|
|
html.Div(id='initial-timeselection-div-epoch', children=[ |
|
|
|
|
html.Label('Start of observation (UTC)'), |
|
|
|
|
*ge.tooltip(idname='popover-startime', message="Select the date and " |
|
|
|
|
"time of the start of the observation (Universal, UTC, " |
|
|
|
|
"time). You will also see the day of the year (DOY) in " |
|
|
|
|
"brackets once the date is selected."), |
|
|
|
|
html.Br(), |
|
|
|
|
dcc.DatePickerSingle(id='starttime', date=None, min_date_allowed=dt(1900, 1, 1), |
|
|
|
|
max_date_allowed=dt(2100, 1, 1), |
|
|
|
|
display_format='DD-MM-YYYY (DDD)', |
|
|
|
@ -431,54 +480,41 @@ def main_page(a_wavelength):
@@ -431,54 +480,41 @@ def main_page(a_wavelength):
|
|
|
|
|
initial_visible_month=dt.today(), |
|
|
|
|
persistence=True, |
|
|
|
|
className='form-picker'), |
|
|
|
|
dcc.Dropdown(id='starthour', placeholder="Start time", value=None, |
|
|
|
|
dcc.Dropdown(id='starthour', placeholder="Start time (UTC)", value=None, |
|
|
|
|
options=[{'label': f"{hm//60:02n}:{hm % 60:02n}", \ |
|
|
|
|
'value': f"{hm//60:02n}:{hm % 60:02n}"} \ |
|
|
|
|
for hm in range(0, 24*60, 15)], |
|
|
|
|
persistence=True, className='form-hour'), |
|
|
|
|
html.Small(id='error_starttime', style={'color': 'red'}, |
|
|
|
|
className='form-text text-muted'), |
|
|
|
|
html.Label('Duration of the observation (in hours)'), |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
html.Label('Duration of the observation (hours)'), |
|
|
|
|
*ge.tooltip(idname='popover-duration', message="Select the total duration of the " |
|
|
|
|
"observation (provided in hours)."), |
|
|
|
|
dcc.Input(id='duration', value=None, type='number', className='form-control', |
|
|
|
|
placeholder="In hours", persistence=True, inputMode='numeric'), |
|
|
|
|
html.Small(id='error_duration', style={'color': 'red'}, className='form-text text-muted') |
|
|
|
|
])])) |
|
|
|
|
]), |
|
|
|
|
placeholder="Duration in hours", persistence=True, inputMode='numeric'), |
|
|
|
|
html.Small(id='error_duration', style={'color': 'red'}, |
|
|
|
|
className='form-text text-muted') |
|
|
|
|
]) |
|
|
|
|
]) |
|
|
|
|
]), |
|
|
|
|
dbc.Tab(label='Guess Times', id='tab-guess-times', tabClassName='tab-for-card', children=[ |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
dbc.Card(className='card-no-left-border', children=dbc.CardBody([ |
|
|
|
|
html.P("Choose this option if you just want to find out when your source " |
|
|
|
|
"will be visible. It will pick the time range when more than 3 antennas " |
|
|
|
|
"can observe."), |
|
|
|
|
dbc.Checklist(id='guest-times', className='checkbox', persistence=True, |
|
|
|
|
options=[{'label': " I don't have preferred times", |
|
|
|
|
'value': 'guest-times'}], value=[]), |
|
|
|
|
html.Small("Note that this option may not provide the wished results if " |
|
|
|
|
"different networks far apart (e.g. LBA + EVN) are selected.", |
|
|
|
|
style={'color': '#999999'}) |
|
|
|
|
]) |
|
|
|
|
)]) |
|
|
|
|
]) |
|
|
|
|
]), |
|
|
|
|
html.Br(), |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
html.Label(id='onsourcetime-label', |
|
|
|
|
children='% of on-target time'), |
|
|
|
|
*ge.tooltip(idname='popover-ontarget', |
|
|
|
|
html.H6(['% of on-target time', |
|
|
|
|
*ge.tooltip(idname='popover-ontarget', |
|
|
|
|
message="Assumes that you will only spend this amount of the total " \ |
|
|
|
|
"observing time on the given target source. It affects the " \ |
|
|
|
|
"expected sensitivity."), |
|
|
|
|
]), |
|
|
|
|
dcc.Slider(id='onsourcetime', min=20, max=100, step=5, value=70, |
|
|
|
|
marks= {i: str(i) for i in range(20, 101, 10)}, |
|
|
|
|
persistence=True), |
|
|
|
|
html.Label(id='onsourcetime-label', style={'color': '#999999'}, |
|
|
|
|
children='70% of the observation.'), |
|
|
|
|
]), |
|
|
|
|
html.H4("Advanced setup"), |
|
|
|
|
html.Br(), |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
html.Label('Datarate per station'), |
|
|
|
|
*ge.tooltip(idname='popover-datarate', |
|
|
|
|
html.H6(['Datarate per station', |
|
|
|
|
*ge.tooltip(idname='popover-datarate', |
|
|
|
|
message=["Expected datarate for each station, assuming all " \ |
|
|
|
|
"of them run at the same rate.", |
|
|
|
|
html.Ul([ |
|
|
|
@ -487,46 +523,55 @@ def main_page(a_wavelength):
@@ -487,46 +523,55 @@ def main_page(a_wavelength):
|
|
|
|
|
html.Li("The VLBA can now observe up to 4 Gbps."), |
|
|
|
|
html.Li("The LBA typically runs at 512 Mbps but can reach up to 1 Gbps."), |
|
|
|
|
html.Li("Check the documentation from other networks to be " \ |
|
|
|
|
"sure about their capabilities.")])]), |
|
|
|
|
"sure about their capabilities.")])]) |
|
|
|
|
]), |
|
|
|
|
dcc.Dropdown(id='datarate', |
|
|
|
|
placeholder="Select the data rate...", |
|
|
|
|
options=[{'label': fs.data_rates[dr], 'value': dr} \ |
|
|
|
|
for dr in fs.data_rates], value=2048, persistence=True), |
|
|
|
|
html.Label(id='bandwidth-label', style={'color': '#999999'}, children='') |
|
|
|
|
]), |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
html.Label('Number of subbands'), |
|
|
|
|
*ge.tooltip(idname='popover-subbands', |
|
|
|
|
html.H6(['Number of subbands', |
|
|
|
|
*ge.tooltip(idname='popover-subbands', |
|
|
|
|
message="Number of subbands to split the total observed bandwidth " |
|
|
|
|
" during correlation (IFs in AIPS)."), |
|
|
|
|
" during correlation (IFs in AIPS).") |
|
|
|
|
]), |
|
|
|
|
dcc.Dropdown(id='subbands', placeholder="Select no. subbands...", |
|
|
|
|
options=[{'label': fs.subbands[sb], 'value': sb} \ |
|
|
|
|
for sb in fs.subbands], value=8, persistence=True), |
|
|
|
|
]), |
|
|
|
|
html.Br(), |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
html.Label('Number of spectral channels'), |
|
|
|
|
*ge.tooltip(idname='popover-channels', |
|
|
|
|
html.H6(['Number of spectral channels', |
|
|
|
|
*ge.tooltip(idname='popover-channels', |
|
|
|
|
message="How many channels per subband will be produced " |
|
|
|
|
"during correlation."), |
|
|
|
|
dcc.Dropdown(id='channels', placeholder="Select no. channels...", |
|
|
|
|
options=[{'label': fs.channels[ch], |
|
|
|
|
'value': ch} \ |
|
|
|
|
for ch in fs.channels], value=32, persistence=True), |
|
|
|
|
"during correlation.") |
|
|
|
|
]), |
|
|
|
|
dcc.Dropdown(id='channels', placeholder="Select no. channels...", |
|
|
|
|
options=[{'label': fs.channels[ch], |
|
|
|
|
'value': ch} \ |
|
|
|
|
for ch in fs.channels], value=32, persistence=True), |
|
|
|
|
]), |
|
|
|
|
html.Br(), |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
html.Label('Number of polarizations'), |
|
|
|
|
*ge.tooltip(idname='popover-pols', |
|
|
|
|
html.H6(['Number of polarizations', |
|
|
|
|
*ge.tooltip(idname='popover-pols', |
|
|
|
|
message="Number of polarizations to correlate. Note that VLBI uses circular " \ |
|
|
|
|
"polarizations. Full polarization implies the four stokes: RR, LL, RL, LR; " \ |
|
|
|
|
"while dual polarization implies RR and LL only."), |
|
|
|
|
"while dual polarization implies RR and LL only.") |
|
|
|
|
]), |
|
|
|
|
dcc.Dropdown(id='pols', placeholder="Select polarizations...", |
|
|
|
|
options=[{'label': fs.polarizations[p], 'value': p} \ |
|
|
|
|
for p in fs.polarizations], value=4, persistence=True), |
|
|
|
|
]), |
|
|
|
|
html.Br(), |
|
|
|
|
html.Div(className='form-group', children=[ |
|
|
|
|
html.Label('Integration time (s)'), |
|
|
|
|
*ge.tooltip(idname='popover-inttime', |
|
|
|
|
html.H6(['Integration time', |
|
|
|
|
*ge.tooltip(idname='popover-inttime', |
|
|
|
|
message="Integration time to compute each visibility. Note that for continuum " \ |
|
|
|
|
"observations values of 1-2 seconds are typical."), |
|
|
|
|
"observations values of 1-2 seconds are typical.") |
|
|
|
|
]), |
|
|
|
|
dcc.Dropdown(id='inttime', placeholder="Select integration time...", |
|
|
|
|
options=[{'label': fs.inttimes[it], 'value': it} \ |
|
|
|
|
for it in fs.inttimes], value=2, persistence=True), |
|
|
|
@ -540,35 +585,29 @@ def main_page(a_wavelength):
@@ -540,35 +585,29 @@ def main_page(a_wavelength):
|
|
|
|
|
html.Div(className='row justify-content-center', children=[ |
|
|
|
|
html.Div(className='col-9', children=[ |
|
|
|
|
html.Div(id='first-advise', className='col-sm-9', children=[ |
|
|
|
|
html.P(["Here you can set up your observation.", html.Br(), |
|
|
|
|
"Please select which network (or networks) you want to use in your " |
|
|
|
|
"observations, or select a customized array of antennas. " |
|
|
|
|
"On the left panel you can set the basic information from your observations: " |
|
|
|
|
"times of the observations and target source to observe. ", html.Br(), |
|
|
|
|
"Optionally, you can customize the configuration and correlation parameters " |
|
|
|
|
"under 'advance setup'. Otherwise, default values based on your selection " |
|
|
|
|
"will be used.", html.Br(), |
|
|
|
|
"Once you are ready, press the big red ", html.B("'compute observation'"), |
|
|
|
|
" button. You will get a detailed " |
|
|
|
|
"summary of the planned observation and expected outcomes in the different " |
|
|
|
|
html.H4("Customize your observation"), |
|
|
|
|
html.P(["Select which VLBI network(s) you want to use in your " |
|
|
|
|
"observation, or select an ad-hoc array of antennas. ", html.Br(), |
|
|
|
|
"Set the basic information from your observations: " |
|
|
|
|
"observing band, target source, epoch, and observing setup. ", html.Br(), |
|
|
|
|
"Finally, press the blue ", html.B("'compute observation'"), |
|
|
|
|
" button. ", html.Br(), |
|
|
|
|
"You will get a detailed " |
|
|
|
|
"summary of the planned observation and expected outcome in the different " |
|
|
|
|
"tabs."]), |
|
|
|
|
html.P(["Note that only antennas that can observe at the selected band " |
|
|
|
|
"will be clickable."]) |
|
|
|
|
html.P(html.Em(["Note that only antennas that can observe at the selected band " |
|
|
|
|
"will be clickable."])) |
|
|
|
|
], style={'margin-top': '2rem', 'margin-bottom': '2rem'}), |
|
|
|
|
html.Div(className='col-9 form-group row align-items-end', children=[ |
|
|
|
|
html.Div(className='col-md-6', children=[ |
|
|
|
|
html.Label('Select default VLBI Network(s)', |
|
|
|
|
style={'color': '#a01d26'}), |
|
|
|
|
html.Label('Select default VLBI Network(s)'), |
|
|
|
|
# style={'color': '#a01d26'}), |
|
|
|
|
*ge.tooltip(idname='popover-network', message="Automatically selects " |
|
|
|
|
"the default participating antennas for the selected VLBI network(s)."), |
|
|
|
|
dcc.Dropdown(id='array', options=[{'label': n, 'value': n} \ |
|
|
|
|
for n in default_arrays if n != 'e-EVN'], value=[], |
|
|
|
|
persistence=True, multi=True), |
|
|
|
|
]), |
|
|
|
|
html.Div(id='div-antenna-selection-button', className='col-sm-3', children=[ |
|
|
|
|
html.Button('Compute Observation', id='antenna-selection-button', |
|
|
|
|
className='btn btn-primary btn-lg'), |
|
|
|
|
]) |
|
|
|
|
]), |
|
|
|
|
html.Div(className='col-9 text-center justify-content-center', children=[ |
|
|
|
|
dcc.Loading(id="loading", children=[html.Div(id="loading-output")], |
|
|
|
@ -590,9 +629,8 @@ def main_page(a_wavelength):
@@ -590,9 +629,8 @@ def main_page(a_wavelength):
|
|
|
|
|
disabled=not s.has_band(selected_band)), |
|
|
|
|
dbc.Label(s.name, html_for=f"check_{s.codename}", |
|
|
|
|
id=f"_input_{s.codename}", |
|
|
|
|
className='custom-control-label form-check-label') |
|
|
|
|
], check=True, inline=True, className="form-check-input " |
|
|
|
|
"custom-checkbox custom-control custom-control-inline") |
|
|
|
|
className='custom-control-label') |
|
|
|
|
], check=True, inline=True, className="custom-checkbox custom-control custom-control-inline") |
|
|
|
|
for s in all_antennas if s.network == an_array |
|
|
|
|
]) |
|
|
|
|
]) for an_array in sorted_networks |
|
|
|
@ -690,43 +728,36 @@ def main_page(a_wavelength):
@@ -690,43 +728,36 @@ def main_page(a_wavelength):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.callback([Output('tab-pick-epoch', 'label'), |
|
|
|
|
Output('tab-guess-times', 'label')], |
|
|
|
|
[Input('guest-times', 'value')]) |
|
|
|
|
def update_tab_time_labels(guest_time): |
|
|
|
|
"""Updates the labels in the tabs where the user can either pick a specific observing |
|
|
|
|
time or let the app to guest the correct times. |
|
|
|
|
It will add a green tick or red cross to the option that is currently selected. |
|
|
|
|
@app.callback(Output('onsourcetime-label', 'children'), |
|
|
|
|
[Input('onsourcetime', 'value'), |
|
|
|
|
Input('duration', 'value'), |
|
|
|
|
Input('initial-timeselection', 'value')]) |
|
|
|
|
def update_onsourcetime_label(onsourcetime, total_duration, defined_epoch): |
|
|
|
|
"""Keeps the on-source time label updated with the value selected by the user. |
|
|
|
|
""" |
|
|
|
|
if guest_time: |
|
|
|
|
return "Pick Epoch ", "Guest Times ✔️" |
|
|
|
|
else: |
|
|
|
|
return "Pick Epoch ✔️", "Guest Times ❌" |
|
|
|
|
if (total_duration is not None) and defined_epoch: |
|
|
|
|
print(total_duration) |
|
|
|
|
return f"{onsourcetime}% of the total time ({ge.optimal_units(total_duration*u.h*onsourcetime/100, [u.h, u.min, u.s]):.03n})." |
|
|
|
|
|
|
|
|
|
return f"{onsourcetime}% of the total observation." |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.callback([Output('div-antenna-selection-button', 'children'), |
|
|
|
|
Output('div-antenna-selection-button2', 'children')], |
|
|
|
|
[Input('tabs', 'value')]) |
|
|
|
|
def move_compute_button(selected_tab): |
|
|
|
|
"""Depending on which tab is selected, it will show the button to compute the observation |
|
|
|
|
in one place or another, so it is always visible and clickable. |
|
|
|
|
@app.callback(Output('bandwidth-label', 'children'), |
|
|
|
|
[Input('datarate', 'value'), |
|
|
|
|
Input('pols', 'value')]) |
|
|
|
|
def update_bandwidth_label(datarate, npols): |
|
|
|
|
"""Updates the total bandwidth label as a function of the selected datarate and number of |
|
|
|
|
polarizations. Returns a string with the value and units. |
|
|
|
|
""" |
|
|
|
|
if selected_tab == 'tab-setup' or selected_tab == 'tab-doc': |
|
|
|
|
return html.Button('Compute Observation', id='antenna-selection-button', |
|
|
|
|
className='btn btn-primary btn-lg'), html.Div('', style={'height': '2.3rem'}) |
|
|
|
|
else: |
|
|
|
|
return html.Div('', style={'height': '2.3rem'}), html.Button('Compute again', |
|
|
|
|
id='antenna-selection-button', className='btn btn-primary btn-lg', |
|
|
|
|
style={'width': '100%', 'margin-bottom': '1rem'}), |
|
|
|
|
if (None not in (datarate, npols)) and (datarate != -1): |
|
|
|
|
# Either 1 or 2 pols per station: |
|
|
|
|
temp = npols % 3 + npols // 3 |
|
|
|
|
return [f"The total bandwidth is {ge.optimal_units(datarate*u.MHz/(temp*2*2), [u.GHz, u.MHz, u.kHz] )}.", |
|
|
|
|
html.Br(), html.Br()] |
|
|
|
|
|
|
|
|
|
return '' |
|
|
|
|
|
|
|
|
|
@app.callback(Output('onsourcetime-label', 'children'), |
|
|
|
|
[Input('onsourcetime', 'value')]) |
|
|
|
|
def update_onsourcetime_label(onsourcetime): |
|
|
|
|
"""Keeps the on-source time label updated with the value selected by the user. |
|
|
|
|
""" |
|
|
|
|
return f"% of on-target time ({onsourcetime}%)" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.callback([Output(f"check_{s.codename}", 'checked') for s in all_antennas] + \ |
|
|
|
@ -828,11 +859,11 @@ def get_source(source_coord):
@@ -828,11 +859,11 @@ def get_source(source_coord):
|
|
|
|
|
State('channels', 'value'), |
|
|
|
|
State('pols', 'value'), |
|
|
|
|
State('inttime', 'value'), |
|
|
|
|
State('guest-times', 'value'), |
|
|
|
|
State('initial-timeselection', 'value'), |
|
|
|
|
State('tabs', 'value')] + \ |
|
|
|
|
[State(f"check_{s.codename}", 'checked') for s in all_antennas]) |
|
|
|
|
def compute_observation(n_clicks, band, starttime, starthour, duration, source, onsourcetime, |
|
|
|
|
datarate, subbands, channels, pols, inttime, guest_time, selected_tab, *ants): |
|
|
|
|
datarate, subbands, channels, pols, inttime, epoch_selected, selected_tab, *ants): |
|
|
|
|
"""Computes all products to be shown concerning the set observation. |
|
|
|
|
""" |
|
|
|
|
# To decide where to put the output message |
|
|
|
@ -841,7 +872,7 @@ def compute_observation(n_clicks, band, starttime, starthour, duration, source,
@@ -841,7 +872,7 @@ def compute_observation(n_clicks, band, starttime, starthour, duration, source,
|
|
|
|
|
return '', '', dash.no_update, dash.no_update, dash.no_update, \ |
|
|
|
|
dash.no_update, dash.no_update |
|
|
|
|
|
|
|
|
|
if not guest_time: |
|
|
|
|
if epoch_selected: |
|
|
|
|
# All options must be completed |
|
|
|
|
if None in (band, starttime, starthour, duration, source, datarate, subbands, channels, pols, inttime) \ |
|
|
|
|
or source == "": |
|
|
|
@ -889,7 +920,7 @@ def compute_observation(n_clicks, band, starttime, starthour, duration, source,
@@ -889,7 +920,7 @@ def compute_observation(n_clicks, band, starttime, starthour, duration, source,
|
|
|
|
|
"First, set correctly an observation in the previous tab.", ''] |
|
|
|
|
return *[temp if out_center else temp[::-1]][0], \ |
|
|
|
|
dash.no_update, dash.no_update, dash.no_update, dash.no_update, dash.no_update |
|
|
|
|
if guest_time: |
|
|
|
|
if not epoch_selected: |
|
|
|
|
try: |
|
|
|
|
if starttime is not None: |
|
|
|
|
utc_times, _ = observation.Observation.guest_times_for_source(target_source, |
|
|
|
@ -955,7 +986,7 @@ def compute_observation(n_clicks, band, starttime, starthour, duration, source,
@@ -955,7 +986,7 @@ def compute_observation(n_clicks, band, starttime, starthour, duration, source,
|
|
|
|
|
|
|
|
|
|
# TODO: parallelize all these fig functions |
|
|
|
|
if out_center: |
|
|
|
|
if guest_time: |
|
|
|
|
if not epoch_selected: |
|
|
|
|
return [html.Br(), dbc.Alert("You can check now the results in the different tabs", color='info', \ |
|
|
|
|
dismissable=True), |
|
|
|
|
*alert_message("Note that you have selected the 'guest time' option. " |
|
|
|
@ -1104,3 +1135,4 @@ if __name__ == '__main__':
@@ -1104,3 +1135,4 @@ if __name__ == '__main__':
|
|
|
|
|
app.run_server(host='0.0.0.0', debug=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|