Commit 6efaecd4 authored by Sander ter Veen's avatar Sander ter Veen

Added calibrators and calculations for multiple pointings

It is now possible to specify a calibrator duration and number of calibrators. If multiple targets are selected, the data sizes and processing hours are calculated accordingly. The PDF shows all these values.
parent 55f52309
......@@ -60,11 +60,11 @@ def calculate_im_noise(n_core, n_remote, n_int, hba_mode, obs_t, n_sb):
im_noise *= 1.E6 # In uJy
return '{:0.2f}'.format(im_noise)
def calculate_raw_size(obs_t, int_time, n_baselines, n_chan, n_sb):
def calculate_raw_size(obs_t, cal_t, n_cal, int_time, n_baselines, n_chan, n_sb, n_beams):
"""Compute the datasize of a raw LOFAR measurement set given the
length of the observation, correlator integration time, number
of baselines, number of channels per subband, and number of subbands"""
n_rows = int(n_baselines * (obs_t / int_time)) - n_baselines
n_rows = int(n_baselines * ( (obs_t*n_beams + cal_t*n_cal ) / int_time)) - n_baselines
# A single row in LofarStMan format contains
# - 32-bit sequence number (4 bytes)
# - n_chan*16-bit samples for weight and sigma calculation (2*n_chan bytes)
......@@ -73,7 +73,7 @@ def calculate_raw_size(obs_t, int_time, n_baselines, n_chan, n_sb):
tot_size = sb_size * n_sb
return '{:0.2f}'.format(tot_size)
def calculate_proc_size(obs_t, int_time, n_baselines, n_chan, n_sb, pipe_type,
def calculate_proc_size(obs_t, cal_t, n_cal, int_time, n_baselines, n_chan, n_sb, n_beams, pipe_type,
t_avg, f_avg, dy_compress):
"""Compute the datasize of averaged LOFAR measurement set given the
length of the observation, integration time, number of baselines,
......@@ -86,7 +86,7 @@ def calculate_proc_size(obs_t, int_time, n_baselines, n_chan, n_sb, pipe_type,
n_chan //= f_avg
# Change integ_t to account for t_avg
int_time *= t_avg
n_rows = int(n_baselines * (obs_t / int_time)) - n_baselines
n_rows = int(n_baselines * ( (obs_t*n_beams + cal_t*n_cal ) / int_time)) - n_baselines
# What does a single row in an averaged MS contain?
sb_size = n_rows * ((7*8) + \
(4+(4*n_chan)) + \
......@@ -102,7 +102,7 @@ def calculate_proc_size(obs_t, int_time, n_baselines, n_chan, n_sb, pipe_type,
tot_size = tot_size/3.
return '{:0.2f}'.format(tot_size)
def calculate_pipe_time(obs_t, n_sb, array_mode, ateam_names, pipe_type):
def calculate_pipe_time(obs_t, cal_t, n_cal, n_sb, n_beams, array_mode, ateam_names, pipe_type):
"""Compute the pipeline processing time.
Inputs:
obs_t - Observation time in hours
......@@ -123,9 +123,9 @@ def calculate_pipe_time(obs_t, n_sb, array_mode, ateam_names, pipe_type):
if pipe_type == 'preprocessing':
if 'hba' in array_mode:
proc_time = hba_factor[n_ateams] * n_sb * obs_t
proc_time = hba_factor[n_ateams] * n_sb * ( obs_t * n_beams + cal_t * n_cal )
else:
proc_time = lba_factor[n_ateams] * n_sb * obs_t
proc_time = lba_factor[n_ateams] * n_sb * ( obs_t * n_beams + cal_t * n_cal )
# Convert to hours
proc_time /= 3600.
return proc_time
......
......@@ -33,7 +33,7 @@ app.title = 'LUCI - LOFAR Unified Calculator for Imaging'
##############################################
##############################################
# Show observational setup fields based on
# Show observational setup fields based on
# obsMode dropdown value
##############################################
@app.callback(
......@@ -41,15 +41,15 @@ app.title = 'LUCI - LOFAR Unified Calculator for Imaging'
Output('tabModeRowL', 'style'),
Output('tabModeRow', 'style'),
Output('tabModeRow', 'value'),
Output('stokesForm', 'style'),
Output('stokesRowL', 'style'),
Output('stokesRow', 'style'),
Output('nRingsForm', 'style'),
Output('nRingsRow', 'style'),
Output('nRingsRowL', 'style'),
Output('pipeTypeRow', 'options'),
Output('pipeTypeRow', 'value')
],
......@@ -78,13 +78,13 @@ def toggle_obs_mode(obs_value):
# Show TAb stokes fields based on dropdown value
################################################
@app.callback(
[Output('stokesRow', 'options'),
[Output('stokesRow', 'options'),
Output('stokesRow', 'value'),
Output('nRemoteForm', 'style'),
Output('nRemoteRow', 'style'),
Output('nRemoteRowL', 'style'),
Output('nIntForm', 'style'),
Output('nIntRow', 'style'),
Output('nIntRowL', 'style'),
......@@ -108,7 +108,7 @@ def toggle_stokes(value):
else:
return valid_stokes, 'I', \
{'display':'none'}, {'display':'none'}, {'display':'none'}, \
{'display':'none'}, {'display':'none'}, {'display':'none'},
{'display':'none'}, {'display':'none'}, {'display':'none'},
##############################################
......@@ -312,6 +312,8 @@ def on_resolve_click(n, close_msg_box, target_name, is_open):
Input('mbGenPdfClose', 'n_clicks')
],
[State('obsTimeRow', 'value'),
State('calTimeRow', 'value'),
State('nCalRow', 'value'),
State('nCoreRow', 'value'),
State('nRemoteRow', 'value'),
State('nIntRow', 'value'),
......@@ -319,6 +321,7 @@ def on_resolve_click(n, close_msg_box, target_name, is_open):
State('nSbRow', 'value'),
State('intTimeRow', 'value'),
State('hbaDualRow', 'value'),
State('coordRow', 'value'),
State('pipeTypeRow', 'value'),
State('tAvgRow', 'value'),
......@@ -338,8 +341,8 @@ def on_resolve_click(n, close_msg_box, target_name, is_open):
State('dateRow', 'date')
]
)
def on_genpdf_click(n_clicks, close_msg_box, obs_t, n_core, n_remote, n_int, n_chan,
n_sb, integ_t, ant_set, pipe_type, t_avg, f_avg, is_dysco,
def on_genpdf_click(n_clicks, close_msg_box, obs_t, cal_t, n_cal, n_core, n_remote, n_int, n_chan,
n_sb, integ_t, ant_set, coord, pipe_type, t_avg, f_avg, is_dysco,
im_noise_val, raw_size, proc_size, pipe_time, is_msg_box_open,
elevation_fig, distance_table, obs_date):
"""Function defines what to do when the generate pdf button is clicked"""
......@@ -361,8 +364,8 @@ def on_genpdf_click(n_clicks, close_msg_box, obs_t, n_core, n_remote, n_int, n_c
# Generate a relative and absolute filenames to the pdf file
rel_path = os.path.join(rel_path, 'summary_{}.pdf'.format(randnum))
abs_path = os.path.join(os.getcwd(), rel_path)
g.generate_pdf(rel_path, obs_t, n_core, n_remote, n_int, n_chan,
n_sb, integ_t, ant_set, pipe_type, t_avg, f_avg,
g.generate_pdf(rel_path, obs_t, cal_t, n_cal, n_core, n_remote, n_int, n_chan,
n_sb, integ_t, ant_set, coord, pipe_type, t_avg, f_avg,
is_dysco, im_noise_val, raw_size, proc_size, pipe_time,
elevation_fig, distance_table, obs_date)
return {'display':'block'}, '/luci/{}'.format(rel_path), False
......@@ -393,6 +396,8 @@ def serve_static(resource):
Input('msgBoxClose', 'n_clicks'),
],
[State('obsTimeRow', 'value'),
State('calTimeRow', 'value'),
State('nCalRow', 'value'),
State('nCoreRow', 'value'),
State('nRemoteRow', 'value'),
State('nIntRow', 'value'),
......@@ -412,7 +417,7 @@ def serve_static(resource):
State('demixListRow', 'value')
]
)
def on_calculate_click(n, n_clicks, obs_t, n_core, n_remote, n_int, n_chan, n_sb,
def on_calculate_click(n, n_clicks, obs_t, cal_t, n_cal, n_core, n_remote, n_int, n_chan, n_sb,
integ_t, hba_mode, pipe_type, t_avg, f_avg, dy_compress,
is_open, src_name, coord, obs_date, calib_names,
ateam_names):
......@@ -451,29 +456,33 @@ def on_calculate_click(n, n_clicks, obs_t, n_core, n_remote, n_int, n_chan, n_sb
{'display':'none'}, {}
else:
# Estimate the raw data size
if coord is not '':
coord_list = coord.split(',')
coord_input_list = coord.split(',')
n_sap=len(coord_list)
else:
n_sap=1
n_baselines = bk.compute_baselines(int(n_core), int(n_remote),
int(n_int), hba_mode)
im_noise = bk.calculate_im_noise(int(n_core), int(n_remote),
int(n_int), hba_mode, float(obs_t),
int(n_sb))
raw_size = bk.calculate_raw_size(float(obs_t), float(integ_t),
n_baselines, int(n_chan), int(n_sb))
avg_size = bk.calculate_proc_size(float(obs_t), float(integ_t),
n_baselines, int(n_chan), int(n_sb),
raw_size = bk.calculate_raw_size(float(obs_t), float(cal_t), int(n_cal), float(integ_t),
n_baselines, int(n_chan), int(n_sb), n_sap)
avg_size = bk.calculate_proc_size(float(obs_t), float(cal_t), int(n_cal), float(integ_t),
n_baselines, int(n_chan), int(n_sb), n_sap,
pipe_type, int(t_avg), int(f_avg),
dy_compress)
if pipe_type == 'none':
# No pipeline
pipe_time = None
else:
pipe_time = bk.calculate_pipe_time(float(obs_t), int(n_sb),
pipe_time = bk.calculate_pipe_time(float(obs_t), float(cal_t), int(n_cal), int(n_sb), n_sap,
hba_mode, ateam_names,
pipe_type)
# It is useful to have coord as a list from now on
if coord is not '':
coord_list = coord.split(',')
coord_input_list = coord.split(',')
# Add calibrator names to the target list so that they can be
# plotted together. Before doing that, make a copy of the input
......@@ -512,11 +521,11 @@ def on_calculate_click(n, n_clicks, obs_t, n_core, n_remote, n_int, n_chan, n_sb
# in the validate_inputs function.
# Check if the number of SAPs is less than 488
n_point = len(coord_input_list)
n_sap = n_point * int(n_sb)
max_sap = 488
if n_sap > max_sap:
n_beamlet = n_point * int(n_sb)
max_beamlet = 488
if n_beamlet > max_beamlet:
msg = 'Number of targets times number of subbands cannot ' + \
'be greater than {}.'.format(max_sap)
'be greater than {}.'.format(max_beamlet)
return '', '', '', '', msg, True, \
{'display':'none'}, {}, {'display':'none'}, {}, \
{'display':'none'}, {}
......
......@@ -71,8 +71,8 @@ def make_pdf_plot(elevation_fig, outfilename):
plt.tight_layout()
plt.savefig(outfilename, dpi=100)
def generate_pdf(pdf_file, obs_t, n_core, n_remote, n_int, n_chan, n_sb, integ_t,
antenna_set, pipe_type, t_avg, f_avg, is_dysco, im_noise_val,
def generate_pdf(pdf_file, obs_t, cal_t, n_cal, n_core, n_remote, n_int, n_chan, n_sb, integ_t,
antenna_set, coord, pipe_type, t_avg, f_avg, is_dysco, im_noise_val,
raw_size, proc_size, pipe_time, elevation_fig, distance_table,
obs_date):
"""Function to generate a pdf file summarizing the content of the calculator.
......@@ -82,6 +82,13 @@ def generate_pdf(pdf_file, obs_t, n_core, n_remote, n_int, n_chan, n_sb, integ_t
pdf.add_page()
pdf.set_font('Arial', '', 16)
if coord is not '':
coord_list = coord.split(',')
coord_input_list = coord.split(',')
n_sap=len(coord_list)
else:
n_sap=None
# Generate an html string to be written to the file
string = '<table border="0" align="left" width="80%">'
string += '<thead><tr><th width="70%" align="left">Parameter</th>'
......@@ -89,6 +96,13 @@ def generate_pdf(pdf_file, obs_t, n_core, n_remote, n_int, n_chan, n_sb, integ_t
string += '<tbody>'
string += '<tr><td>Observation time (in seconds)</td>'
string += ' <td>{}</td></tr>'.format(obs_t)
string += '<tr><td>Calibrator duration (in seconds)</td>'
string += ' <td>{}</td></tr>'.format(cal_t)
string += '<tr><td>Number of calibrators</td>'
string += ' <td>{}</td></tr>'.format(n_cal)
if n_sap:
string += '<tr><td>Number of simultaneous targets</td>'
string += ' <td>{}</td></tr>'.format(n_sap)
string += '<tr><td>No. of stations</td>'
string += ' <td>({}, {}, {})</td></tr>'.format(n_core, n_remote, n_int)
string += '<tr><td>No. of subbands</td>'
......
import dash_html_components as html
import dash_bootstrap_components as dbc
import dash_core_components as dcc
from datetime import date
from datetime import date
###############################################################################
# Define a modal to display error messages for observation time
......@@ -50,22 +50,24 @@ msgBox = dbc.Modal([
###############################################################################
defaultParams = {'obsMode':'Interferometric',
'tabMode':'Coherent',
'obsTime':'28800',
'Ncore':'24',
'obsTime':'28800',
'calTime':'600',
'Ncal': '2',
'Ncore':'24',
'Nremote':'14',
'Nint':'14',
'Nchan':'64',
'Nint':'14',
'Nchan':'64',
'Nsb':'488',
'intTime':'1',
'intTime':'1',
'hbaDual':'hbadualinner',
'Nrings':'0',
'pipeType':'none',
'tAvg':'1',
'fAvg':'4',
'pipeType':'none',
'tAvg':'1',
'fAvg':'4',
'dyCompress':'enable',
'targetName':'',
'targetName':'',
'target_coord':'',
}
......@@ -91,7 +93,7 @@ obsMode = dbc.FormGroup([
options=[
{'label':'Interferometric', 'value':'Interferometric'},
{'label':'Beamformed', 'value':'Beamformed'}
], value=defaultParams['obsMode'], searchable=False,
], value=defaultParams['obsMode'], searchable=False,
clearable=False, id='obsModeRow'
), width=dropWidth
)
......@@ -103,7 +105,7 @@ tabMode = dbc.FormGroup([
options=[
{'label':'Coherent', 'value':'Coherent'},
{'label':'Incoherent', 'value':'Incoherent'}
], value=defaultParams['tabMode'], searchable=False,
], value=defaultParams['tabMode'], searchable=False,
clearable=False, id='tabModeRow'
), width=dropWidth, id='tabModeCol'
)
......@@ -112,7 +114,7 @@ stokes = dbc.FormGroup([
dbc.Label('Stokes products to record', width=labelWidth, id='stokesRowL'),
dbc.Col(
dcc.Dropdown(
options=[], searchable=False,
options=[], searchable=False,
clearable=False, id='stokesRow'
), width=dropWidth
)
......@@ -120,16 +122,38 @@ stokes = dbc.FormGroup([
obsTime = dbc.FormGroup([
dbc.Label('Observation time (in seconds)', width=labelWidth),
dbc.Col(
dbc.Input(type='text',
id='obsTimeRow',
dbc.Input(type='text',
id='obsTimeRow',
value=defaultParams['obsTime']
), width=inpWidth
)
], row=True)
calTime = dbc.FormGroup([
dbc.Label('Calibrator duration (in seconds)', width=labelWidth),
dbc.Col(
dbc.Input(type='text',
id='calTimeRow',
value=defaultParams['calTime']
), width=inpWidth
)
], row=True)
Ncal = dbc.FormGroup([
dbc.Label('No. of calibrator observations', width=labelWidth),
dbc.Col(
dbc.Input(type='number',
id='nCalRow',
value=defaultParams['Ncal']
), width=inpWidth
)
], row=True)
Ncore = dbc.FormGroup([
dbc.Label('No. of core stations (0 - 24)', width=labelWidth),
dbc.Col(
dbc.Input(type='number',
dbc.Input(type='number',
id='nCoreRow',
value=defaultParams['Ncore']
), width=inpWidth
......@@ -140,18 +164,18 @@ Nremote = dbc.FormGroup([
id='nRemoteRowL'
),
dbc.Col(
dbc.Input(type='number',
dbc.Input(type='number',
id='nRemoteRow',
value=defaultParams['Nremote']
), width=inpWidth
)
)
], row=True, id='nRemoteForm')
Nint = dbc.FormGroup([
dbc.Label('No. of international stations (0 - 14)', width=labelWidth,
id='nIntRowL'
),
dbc.Col(
dbc.Input(type='number',
dbc.Input(type='number',
id='nIntRow',
value=defaultParams['Nint']
), width=inpWidth
......@@ -165,7 +189,7 @@ Nchan = dbc.FormGroup([
{'label':'64', 'value':'64'},
{'label':'128', 'value':'128'},
{'label':'256', 'value':'256'}
], value=defaultParams['Nchan'], searchable=False,
], value=defaultParams['Nchan'], searchable=False,
clearable=False, id='nChanRow'
), width=dropWidth
)
......@@ -173,7 +197,7 @@ Nchan = dbc.FormGroup([
Nsb = dbc.FormGroup([
dbc.Label('Number of subbands', width=labelWidth),
dbc.Col(
dbc.Input(type='number',
dbc.Input(type='number',
id='nSbRow',
value=defaultParams['Nsb']
), width=inpWidth
......@@ -182,7 +206,7 @@ Nsb = dbc.FormGroup([
intTime = dbc.FormGroup([
dbc.Label('Integration time (in seconds)', width=labelWidth),
dbc.Col(
dbc.Input(type='text',
dbc.Input(type='text',
id='intTimeRow',
value=defaultParams['intTime']
), width=inpWidth
......@@ -196,7 +220,7 @@ hbaDual = dbc.FormGroup([
{'label':'LBA Outer', 'value':'lbaouter'},
{'label':'HBA Dual', 'value':'hbadual'},
{'label':'HBA Dual Inner', 'value':'hbadualinner'}
], value=defaultParams['hbaDual'], searchable=False,
], value=defaultParams['hbaDual'], searchable=False,
clearable=False, id='hbaDualRow',
), width=dropWidth
)
......@@ -209,13 +233,14 @@ buttons = html.Div([
])
])
link = html.Div([
html.A(id='download-link',
children='Download file',
html.A(id='download-link',
children='Download file',
style={'display':'none'}
)
])
obsGUISetup = dbc.Form([obsMode, tabMode, stokes, obsTime, Ncore, Nremote, Nint, Nchan,
obsGUISetup = dbc.Form([obsMode, tabMode, stokes, obsTime, calTime, Ncal, Ncore, Nremote, Nint, Nchan,
Nsb, intTime, hbaDual, buttons, link])
obsGUIFrame = html.Div(children=[
html.H3('Observational setup'),
html.Hr(),
......@@ -229,19 +254,19 @@ pipeType = dbc.FormGroup([
dbc.Label('Pipeline', width=labelWidth-inpWidth),
dbc.Col(
dcc.Dropdown(
options=[],
value=defaultParams['pipeType'], searchable=False,
options=[],
value=defaultParams['pipeType'], searchable=False,
clearable=False, id='pipeTypeRow'
), width=dropWidth
)
], row=True)
tAvg = dbc.FormGroup([
dbc.Label('Time averaging factor', width=labelWidth-inpWidth,
dbc.Label('Time averaging factor', width=labelWidth-inpWidth,
id='tAvgRowL'
),
dbc.Col(
dbc.Input(type='number',
id='tAvgRow',
dbc.Input(type='number',
id='tAvgRow',
min=0,
value=defaultParams['tAvg']
), width=inpWidth
......@@ -284,7 +309,7 @@ dyCompress = dbc.FormGroup([
options=[
{'label':'Disable', 'value':'disable'},
{'label':'Enable', 'value':'enable'}
], value=defaultParams['dyCompress'], searchable=False,
], value=defaultParams['dyCompress'], searchable=False,
clearable=False, id='dyCompressRow'
), width=dropWidth
)
......@@ -298,13 +323,13 @@ targetToolTip = 'Multiple co-observing targets can be specified as ' + \
'comma-separated values. Note that the number of targets ' + \
'(pointings) times the number of subbands must be less than 488.'
targetName = dbc.FormGroup([
dbc.Label('Target', width=labelWidth-inpWidth,
dbc.Label('Target', width=labelWidth-inpWidth,
id='targetNameRowL'
),
dbc.Tooltip(targetToolTip, target='targetNameRowL'),
dbc.Tooltip(targetToolTip, target='targetNameRow'),
dbc.Col(
dbc.Input(id='targetNameRow', min=0),
dbc.Input(id='targetNameRow', min=0),
width=inpWidth
),
dbc.Col(
......@@ -313,21 +338,21 @@ targetName = dbc.FormGroup([
], row=True)
targetCoord = dbc.FormGroup([
dbc.Label('Coordinates', width=labelWidth-inpWidth),
dbc.Col(dbc.Input(id='coordRow'), width=inpWidth*2)
dbc.Col(dbc.Input(id='coordRow'), width=inpWidth*2)
], row=True)
Nrings = dbc.FormGroup([
dbc.Label('No. of TAB rings (0 - 8)', width=labelWidth-inpWidth,
id='nRingsRowL'),
dbc.Col(
dbc.Input(type='number',
dbc.Input(type='number',
id='nRingsRow',
value=defaultParams['Nrings']
), width=inpWidth,
), width=inpWidth,
)
], row=True, id='nRingsForm')
obsDate = dbc.FormGroup([
dbc.Label('Observation date', width=labelWidth-inpWidth),
dbc.Col(dcc.DatePickerSingle(date=date.today(),
dbc.Col(dcc.DatePickerSingle(date=date.today(),
display_format='DD/MM/YYYY',
id='dateRow')
)
......@@ -342,7 +367,7 @@ calList = dbc.FormGroup([
{'label':'3C147', 'value':'3C147'},
{'label':'3C196', 'value':'3C196'},
{'label':'3C295', 'value':'3C295'}
], searchable=True, clearable=True,
], searchable=True, clearable=True,
id='calListRow', multi=True
), width=dropWidth
)
......@@ -355,7 +380,7 @@ demixList = dbc.FormGroup([
{'label':'CasA', 'value':'CasA'},
{'label':'CygA', 'value':'CygA'},
{'label':'TauA', 'value':'TauA'}
], searchable=True, clearable=True,
], searchable=True, clearable=True,
id='demixListRow', multi=True
), width=dropWidth
)
......@@ -376,7 +401,7 @@ pipeGUIFrame = html.Div(children=[
imNoise = dbc.FormGroup([
dbc.Label('Theoretical image sensitivity (uJy/beam)', width=labelWidth),
dbc.Col(
dbc.Input(type='text', id='imNoiseRow', value='',
dbc.Input(type='text', id='imNoiseRow', value='',
disabled=True
), width=inpWidth
)
......@@ -384,7 +409,7 @@ imNoise = dbc.FormGroup([
rawSize = dbc.FormGroup([
dbc.Label('Raw data size (in GB)', width=labelWidth),
dbc.Col(
dbc.Input(type='text', id='rawSizeRow', value='',
dbc.Input(type='text', id='rawSizeRow', value='',
disabled=True
), width=inpWidth
)
......@@ -393,13 +418,13 @@ pipeSize = dbc.FormGroup([
dbc.Label('Processed data size (in GB)', width=labelWidth,
id='pipeSizeRowL'),
dbc.Col(
dbc.Input(type='text', id='pipeSizeRow', value='',
dbc.Input(type='text', id='pipeSizeRow', value='',
disabled=True
), width=inpWidth
)
], row=True)
pipeProcTime = dbc.FormGroup([
dbc.Label('Pipeline processing time (in hours)',
dbc.Label('Pipeline processing time (in hours)',
width=labelWidth, id='pipeProcTimeRowL'),
dbc.Col(
dbc.Input(type='text', id='pipeProcTimeRow', value='',
......@@ -433,8 +458,8 @@ resultGUIFrame = html.Div(children=[
graph = html.Div([
dbc.Row([
dbc.Col(
html.Div([
dcc.Graph(id='elevation-plot',
html.Div([
dcc.Graph(id='elevation-plot',
figure={'layout':{'title':'Target visibility plot'}},
style={'height':600}
)
......@@ -442,7 +467,7 @@ graph = html.Div([
),
dbc.Col(
html.Div([
dcc.Graph(id='beam-plot',
dcc.Graph(id='beam-plot',
figure={'layout':{'title':'Beam Layout'}},
style={'height':600},
config={
......@@ -474,7 +499,7 @@ layout = html.Div([dbc.Row(dbc.Col(header)),
dbc.Col(resultGUIFrame)
]),
graph,
msgBoxTAvg, msgBoxFAvg,
msgBoxResolve, msgBoxGenPdf, msgBox
])
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment