Skip to content
Snippets Groups Projects
Select Git revision
  • fc5e5428b6863ddba44cf4ba16812cebdf6f1158
  • 2022 default
  • 2021
  • master protected
  • 2021
5 results

hello_mpi.c

Blame
  • dashboard.py 65.54 KiB
    from email.mime import image
    import json
    import pandas as pd
    import dash
    from dash import html, Output, Input, State, ctx, Dash, dcc, dash_table, no_update, callback
    import dash_bootstrap_components as dbc
    import sqlite3
    import datetime as dt
    from PIL import Image
    from pathlib import Path
    import eurad.info as info
    import numpy as np
    from eurad_plot import get_euradim_plot, get_timeseries_plot
    from eurad.eurad_netcdf import EURAD_netCDF
    import os
    import zipfile
    from cryptography.fernet import Fernet
    import pyunicore.client as uc_client
    import pyunicore.credentials as uc_credentials
    from string import ascii_lowercase, digits
    from random import choice
    from time import sleep
    from deployment_settings import (
            KEY,
            UNICORE_BASE, UFTP_BASE,
            UNICORE_USER, UNICORE_PASSWORD
            )
    from utils import transfer_results_from_HPC
    from mlair.time_series import plot as plot_ml_time_series
    import pages.dashboard_translations as guitr
    import pages.dashboard_constants as guiconst
    
    # the following should be done with static files!
    APP_HOME = Path.cwd()
    IMAGE_PATH = APP_HOME.joinpath("static", "images")
    DATA_PATH = APP_HOME.joinpath("static", "data")
    ASSETS_PATH = APP_HOME.joinpath("assets", "generated_plots")
    
    dash.register_page(__name__, title="DestinE Air Quality Use Case", path="/")
    
    # to be put to correct source code file!
    metrics_info_tmp = pd.read_csv(DATA_PATH.joinpath("mlair_metrics.csv"), delimiter=';')
    len_met = len(metrics_info_tmp)
    metrics_info = [metrics_info_tmp.iloc[:int(len_met/2),:],
                 metrics_info_tmp.iloc[int(len_met/2):,:].reset_index(drop=True).rename(columns={" Description": " Beschreibung"})]
    emis_info_tmp = pd.read_csv(DATA_PATH.joinpath("eurad_emission_scenarios.csv"), delimiter=';')
    len_em = len(emis_info_tmp)
    emis_info = [emis_info_tmp.iloc[:int(len_em/2),:],
                 emis_info_tmp.iloc[int(len_em/2):,:].reset_index(drop=True).rename(columns={" Description": " Beschreibung"})]
    
    
    def get_random_string(length):
        # choose from all lowercase letter
        allowed_char = ascii_lowercase + digits
        return ''.join(choice(allowed_char) for i in range(length))
    
    
    def create_db_job_entry(user_id, job_dict):
        creation_date = dt.datetime.now().strftime('%Y-%m-%d %H:%M')
        conn = sqlite3.connect(DATA_PATH.joinpath('destine_de370c_users.db'))
        conn.execute("INSERT INTO jobs (id, user_id, application, status, start_date, forecast_length, region, species, metric, emis_scen, creation_date) \
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
            (job_dict['id'],
             user_id,
             job_dict['application'],
             job_dict['status'],
             job_dict['start_date'],
             job_dict['forecast_length'],
             job_dict['region'],
             job_dict['species'],
             job_dict['metric'],
             job_dict['emis_scen'],
             creation_date))
        conn.commit()
        conn.close()
    
    
    def get_db_job_entry(jobid):
        conn = sqlite3.connect(DATA_PATH.joinpath('destine_de370c_users.db'))
        cur = conn.cursor()
        cur.execute(f"SELECT application, status, start_date, forecast_length, region, species, metric, emis_scen FROM jobs \
                       WHERE id = '{jobid}'")
        jobs = cur.fetchall()
        conn.close()
        job_dict = {}
        for job in jobs:
            application, status, start_date, forecast_length, region, species, metric, emis_scen = job
            job_dict['id'] = jobid
            job_dict['application'] = application
            job_dict['status'] = status
            job_dict['start_date'] = start_date
            job_dict['forecast_length'] = forecast_length
            job_dict['region'] = region
            job_dict['species'] = species
            job_dict['metric'] = metric
            job_dict['emis_scen'] = emis_scen
        return job_dict
    
    
    def create_login_button(title="login"):
        return html.Div([
            html.Span(style={"flex": "1"}),
            html.Span([
                dbc.Button(f"{title}", id="login_button", class_name="fzj_style_btn"),
                dbc.Modal([
                    dbc.ModalHeader("Login"),
                    dbc.ModalBody([
                        dbc.Row([
                            dbc.Col(dbc.Label("Name:"), width=3),
                            dbc.Col(dbc.Input(id='login_name', type="text"))
                            ]),
                        dbc.Row([
                            dbc.Col(dbc.Label("Password:"), width=3),
                            dbc.Col(dbc.Input(id='login_password', type="password"))
                            ])
                    ]),
                    html.Div(id="alert_nouser", children=[]),
                    dbc.ModalFooter(
                        [dbc.Button("login", id="login_close", class_name="fzj_style_btn", n_clicks=0),
                        dbc.Button("register", id="register_open", class_name="fzj_style_btn", n_clicks=0)]),
                ],
                    id="login_modal",
                    is_open=False,
                    size="lg")
            ]),
            html.Span(style={"flex": "1"}),
        ], id="login")
    
    # TODO: take language ids from the controlled vocabulary!
    register_modal = html.Div(
        [
            dbc.Modal(
                [
                    dbc.ModalHeader("Register for Destination Earch Use Case for Air Quality"),
                    dbc.ModalBody(
                        [
                            dbc.Row([
                            dbc.Col(dbc.Label("Name:"), width=3),
                            dbc.Col(dbc.Input(id='register_name', type="text"))
                            ]),
                            dcc.Dropdown(
                                id='language_dropdown',
                                options=[
                                    {'label': 'English', 'value': 0},
                                    {'label': 'Deutsch', 'value': 1}
                                ],
                                value=0
                            )
                        ]
                    ),
                    dbc.ModalFooter(
                        [
                            dbc.Button("OK", id="register_ok_button", class_name="fzj_style_btn"),
                            dbc.Button("Close", id="register_close_button", class_name="fzj_style_btn"),
                        ]
                    ),
                ],
                id="register_modal",
            ),
        ]
    )
    
    aai_login = dbc.Row([
        create_login_button()
    ], id="login-background", style={"height": "70px"})
    
    
    def generate_ml_fcast_body(language_id=0):
        return [
        dbc.Row([
            dbc.Col(dbc.Label(guitr.state_label[language_id]), width=3),
            dbc.Col(
                dcc.Dropdown(value=0,
                             options=[{'label': guitr.region_text[language_id][i],
                                       'value': i,
                                       'disabled': True if i > 1 else False
                                      } for i in range(len(guitr.region_text[language_id]))],
                             id="ml_fcast_body_region"), width=6
            ),
        ], class_name="row mt-3"),
        dbc.Row([
            dbc.Col(dbc.Label(guitr.date_label[language_id]), width=3),
            dbc.Col(dcc.DatePickerSingle(date=dt.date(2018, 7, 18),
                                         display_format=guitr.date_format[language_id],
                                         first_day_of_week=guitr.first_day_of_week[language_id],
                                         min_date_allowed=dt.date(2018, 7, 18),
                                         max_date_allowed=dt.date(2018, 7, 31),
                                         initial_visible_month=dt.date(2018, 7, 1),
                                         id="ml_fcast_body_startdate")),
            dbc.Col(dbc.Label(f"{guitr.forecast_length_label[language_id]}:")),
            dbc.Col(dcc.Dropdown(value=guitr.forecast_length_options[language_id][0], options=guitr.forecast_length_options[language_id],
                                 id="ml_fcast_body_forecast_length"))
        ], class_name="row mt-3"),
        dbc.Row([
            dbc.Col(dbc.Label(f"{guitr.species_label[language_id]}:"), width=3),
            dbc.Col(
                dcc.Dropdown(value=0,
                             options=[{'label': guitr.species_options[language_id][i],
                                       'value': i,
                                       'disabled': True
                                      } for i in range(len(guitr.species_options[language_id]))],
                             id="ml_fcast_body_species"), width=6
            )
        ], class_name="row mt-3"),
        dbc.Row([
            dbc.Col(dbc.Label(f"{guitr.output_metrics_label[language_id]}:"), width=3),
            dbc.Col(dcc.Dropdown(value=0,
                                 options=[{'label': metrics_info[language_id][' Name'][i],
                                           'value': i,
                                           'disabled': True
                                          } for i in range(len(metrics_info[language_id][' Name']))],
                                 id="ml_fcast_body_metrics")),
            dbc.Col(dbc.Button(f"{guitr.help_metrics_label[language_id]}", id="help_metrics_open", class_name="fzj_style_btn"), width=3),
            dbc.Modal([
                dbc.ModalHeader(f"{guitr.help_metrics_label[language_id]}"),
                dbc.ModalBody(dash_table.DataTable(metrics_info[language_id].to_dict('records'),
                                                   [{"name": i, "id": i} for i in metrics_info[language_id].columns],
                                                   style_table={"width": "100%"},
                                                   style_cell={"textAlign": "left",
                                                               "whiteSpace": "pre-line"})),
                dbc.ModalFooter([dbc.Button(f"{guitr.close_label[language_id]}", id=f"help_metrics_close", class_name="fzj_style_btn", n_clicks=0)]),
                ],
                id="help_metrics_modal",
                is_open=False,
                size="lg")
        ], class_name="row mt-3")
    ]
    
    def generate_ml_fcast_output_body(language_id, jobnr):
        stations_list = info.get_available_stations(infile="mlair_stations.csv")
    #   stations_list = sorted(stations_list)
        if jobnr and (jobnr != 'bla'):
            job_props = get_db_job_entry(jobnr)
            start_date = job_props['start_date']
            ireg = job_props['region']
            region = guitr.region_text[language_id][ireg]
            ispec = job_props['species']
            species = guitr.species_options[language_id][ispec]
            imetric = job_props['metric']
            metric = guitr.metrics_options[language_id][imetric]
            fc_length =  job_props['forecast_length']
            fc_length_str = "{} {}{}".format(fc_length, guitr.day_label[language_id], guitr.day_plural_label[language_id] if fc_length > 1 else "")
        else:
            start_date = "2018-07-18"
            region = "X"
            species = "X"
            metric = "X"
            fc_length_str = "X"
        return [
        dbc.Row(dbc.Label(f"""{guitr.region_label[language_id]}: {region},
                              {guitr.species_label[language_id]}: {species},
                              {guitr.output_metrics_label[language_id]}: {metric},
                              {guitr.start_date_label[language_id]}: {start_date},
                              {guitr.forecast_length_label[language_id]}: {fc_length_str}""")),
        dbc.Row([
            dbc.Col(dbc.Label(f"{guitr.station_label[language_id]}:"), width=3),
            dbc.Col(
                dcc.Dropdown(id="station-dropdown-ml-output",
                             value=stations_list[0],
                             options= [{'label': stations_list[i],
                                        'value': stations_list[i],
                                        'disabled': True
                                       } for i in range(len(stations_list))],
                             ), width=6
            ),
            dbc.Col(dbc.Button(f"{guitr.map_select_label[language_id]}", disabled=True, class_name="fzj_style_btn"), width=2)
        ], class_name="row mt-3"),
        dbc.Row([
            dbc.Col([html.Div(id='image-container-ml-output'),
                     html.Div([dbc.Button(f"{guitr.download_label[language_id]}", id="mlair_download",
                                class_name="fzj_style_btn"),
                              dcc.Download(id="mlair_download_result")]),
                     dbc.Col(html.Br()),
                     html.Div([dbc.Button(f"{guitr.im_download_label[language_id]}", id="mlair_plot_download",
                                class_name="fzj_style_btn"),
                              dcc.Download(id="mlair_download_plot")])], width=12),
        ], class_name="row mt-3"),
    ]
    
    @callback(
        [Output('image-container-ml-output', 'children'),
         Output("plot-info", "data", allow_duplicate=True)],
         Input('station-dropdown-ml-output', 'value'),
        [State("user-info", "data"),
         State("job-info", "data")],
        prevent_initial_call=True
    )
    def update_mlair_image(selected_station, users_dict, job_dict):
        jobid = json.loads(job_dict)["jobnr"]
        if jobid != "bla":
            try:
                language_id = json.loads(users_dict)["language_id"]
            except:
                language_id = 0
    
            job_props = get_db_job_entry(jobid)
            station_code, station_label = selected_station.split(',')
            station_code = station_code.strip()
            plotinfo_dict = {}
            plotinfo_dict["station"] = station_code
            ispec = job_props['species']
            species = guitr.species_options[0][ispec]
            ml_species = guiconst.ml_names[species]
            plotinfo_dict["species"] = ml_species
            plotinfo_dict["start_date"] = job_props['start_date'][0:10]
            forecast_length = job_props['forecast_length']
            fc_length_str = "{}{}{}".format(forecast_length, guitr.day_label[language_id], guitr.day_plural_label[language_id] if forecast_length > 1 else "")
            plotinfo_dict["fc_length"] = fc_length_str
            plotinfo_json = json.dumps(plotinfo_dict)
    
            image_path = plot_ml_time_series(selected_station, language_id,
                                             ispec=job_props['species'],
                                             start_date=job_props['start_date'],
                                             forecast_length=job_props['forecast_length'])
            image = html.Img(src=image_path, className='image-fit-container')
            return image, plotinfo_json
        else:
            return None, None
    
    
    def generate_ml_fcast_output_modal(jobnr=None, lisopen=False, language_id=0):
        return html.Div([
            dbc.Modal(
                        [
                            dbc.ModalTitle(f"{guitr.run2_label[language_id]} {jobnr}", style={"fontSize": 15}),
                            dbc.ModalHeader(dbc.ModalTitle(guitr.application_text[language_id][1])),
                            dbc.ModalBody(generate_ml_fcast_output_body(language_id, jobnr)),
                            dbc.ModalFooter([dbc.Button(f"{guitr.close_label[language_id]}", id="ml_fcast_output_close",
                                                        class_name="fzj_style_btn", n_clicks=0)
                                             ]),
                        ],
                        id="ml_fcast_output_modal",
                        is_open=lisopen,
                        size="lg"
                        )
        ], id="ml_fcast_output_modal_container")
    
    
    def generate_ml_fcast_result_modal(jobnr=None, lisopen=False, language_id=0):
        return dbc.Modal(
                        [
                            dbc.ModalTitle(f"{guitr.run2_label[language_id]} {jobnr}", style={"fontSize": 15}),
                            dbc.ModalHeader(dbc.ModalTitle(guitr.application_text[language_id][1])),
                            dbc.ModalBody(generate_ml_fcast_output_body(language_id, jobnr)),
                            dbc.ModalFooter(dbc.Button(f"{guitr.close_label[language_id]}", id="ml_fcast_result_close",
                                                       class_name="fzj_style_btn", n_clicks=0)),
                        ],
                        id="ml_fcast_result_modal",
                        is_open=lisopen,
                        size="lg"
                    )
    
    
    ml_fcast_result_modal = html.Div([
                generate_ml_fcast_result_modal()
            ], id="ml_fcast_result_modal_container")
    
    def generate_eurad_im_body(language_id=0):
        disabled_days = [ dt.datetime.strptime('2017-01-27','%Y-%m-%d') + dt.timedelta(days=i) for i in range(14) ]
        disabled_days += [ dt.datetime.strptime('2017-02-16','%Y-%m-%d') + dt.timedelta(days=i) for i in range(523) ]
        return [
        dbc.Row([
            dbc.Col(dbc.Label(f"{guitr.date_label[language_id]}:"), width=3),
            dbc.Col(dcc.DatePickerSingle(id="eurad_im_start_date",
                                         date=guiconst.min_date_allowed,
                                         display_format=guitr.date_format[language_id],
                                         first_day_of_week=guitr.first_day_of_week[language_id],
                                         min_date_allowed=guiconst.min_date_allowed,
                                         max_date_allowed=guiconst.max_date_allowed,
                                         disabled_days=disabled_days,
                                         initial_visible_month=guiconst.initial_visible_month)),
            dbc.Col(dbc.Label(f"{guitr.forecast_length_label[language_id]}:")),
            dbc.Col(dcc.Dropdown(value=guitr.forecast_length_options[language_id][-1],
                                 options=[{'label': guitr.forecast_length_options[language_id][i],
                                           'value': guitr.forecast_length_options[language_id][i],
                                           } for i in range(len(guitr.forecast_length_options[language_id]))],
                                 id="eurad_im_forecast_length"))
        ], class_name="row mt-3"),
        dbc.Row([
            dbc.Col(dbc.Label(f"{guitr.region_label[language_id]}:"), width=3),
            dbc.Col(dcc.RadioItems(options={
                                         0: guitr.region_text[language_id][0],
                                         1: guitr.region_text[language_id][1]},
                                         value=0, id="eurad_im_region_choice")),
        ], class_name="row mt-3"),
    ]
    
    
    @callback(
        [Output('image-container-output', 'children'),
         Output('image-container-timeseries-output', 'children'),
         Output("plot-info", "data", allow_duplicate=True)],
        [Input('time-step-dropdown-output', 'value'),
         Input('variable-dropdown-output', 'value'),
         Input('station-dropdown-output', 'value'),
         Input('eurad_im_target', 'value'),
         Input('eurad_scen_diff', 'value')],
        [State("user-info", "data"),
         State("job-info", "data")],
        prevent_initial_call=True
    )
    def update_image(selected_time_step, selected_variable, selected_station, ltarget, ldiff, users_dict, jobs_dict):
        plotinfo_dict = {}
        if selected_time_step and selected_variable and selected_variable != 'NoneAvailable':
          
            jobnr = json.loads(jobs_dict)["jobnr"]
            try:
                language_id = json.loads(users_dict)["language_id"]
            except:
                language_id = 0
    
            job_props = get_db_job_entry(jobnr)
            application = job_props['application']
            lltarget = True if ((application == 0) and ltarget) else False
            lldiff = True if ((application == 2) and ldiff) else False
    
            image_path = get_euradim_plot(language_id, jobnr, selected_time_step, selected_variable, selected_station, lldiff, lltarget)
            timeseries_image_path = get_timeseries_plot(language_id, jobnr, selected_station, selected_variable, selected_time_step)
    
            first_image = html.Img(src=image_path, className='image-fit-container')
            second_image = html.Img(src=timeseries_image_path, className='image-fit-container')
      
            plotinfo_dict["time_step"] = selected_time_step
            plotinfo_dict["variable"] = selected_variable
            plotinfo_dict["station"] = selected_station.split(',')[0]
            plotinfo_dict["language_id"] = language_id
            plotinfo_dict["ldiff"] = lldiff
            plotinfo_dict["ltarget"] = lltarget
            plotinfo_json = json.dumps(plotinfo_dict)
    
            return first_image, second_image, plotinfo_json
    
        plotinfo_json = json.dumps(plotinfo_dict)
        return None, None, plotinfo_json
    
    
    
    def generate_eurad_im_output_body(language_id, context, jobnr):
        if jobnr and (jobnr != 'bla'):
            infile = str(DATA_PATH.joinpath(f'{jobnr}.nc'))
            job_props = get_db_job_entry(jobnr)
            start_date = job_props['start_date']
            region = job_props['region']
            fc_length =  job_props['forecast_length']
    
            if not os.path.isfile(infile):
                filenames = transfer_results_from_HPC(jobnr, start_date, 0, fc_length, DATA_PATH)
                os.symlink(filenames['download_filename'], infile)
    
            nc_file = EURAD_netCDF(infile)
            timestep_list = nc_file.get_time_stamps()
            timestep_strings = [np.datetime_as_string(ts)[:16] for ts in timestep_list['time'].values]
    
            start_date = pd.to_datetime(timestep_strings[0]).strftime(guitr.date_format3[language_id])
            fc_length_str = "{} {}{}".format(fc_length, guitr.day_label[language_id], guitr.day_plural_label[language_id] if fc_length > 1 else "")
    
            variables_list = info.get_available_variables(infile)
            # for unit conversion, PRS and TEM were added
            variables_list.remove('PRS')
            variables_list.remove('TEM')
    
            stations_list = info.get_available_stations()
            stations_list = sorted(stations_list)
        else:
            start_date = '2018-07-19T00:00'
            region = 0
            timestep_strings = [ '2018-07-19 00:00' ]
            fc_length_str = '1'
            variables_list = [ 'NoneAvailable' ]
            stations_list = [ "XX, XX" ]
        return [
        dbc.Row([dbc.Label(f"""{guitr.region_label[language_id]}: {guitr.region_text[language_id][region]}, 
                               {guitr.start_date_label[language_id]}: {start_date},
                               {guitr.forecast_length_label[language_id]}: {fc_length_str}""")]),
        dbc.Row([
            dbc.Col(dbc.Label(f"{guitr.time_step_label[language_id]}:"), width=3),
            dbc.Col(dcc.Dropdown(value=timestep_strings[0], options=timestep_strings, id='time-step-dropdown-{}'.format(context)), width=3)
        ], class_name="row mt-3"),
        dbc.Row([
            dbc.Col(dbc.Label("Variable:"), width=3),
            dbc.Col(dcc.Dropdown(value=variables_list[0], options=variables_list, id='variable-dropdown-{}'.format(context)), width=3),
            dbc.Col(dbc.Label(f"{guitr.location_label[language_id]}:"), width=1),
            dbc.Col(dcc.Dropdown(value=stations_list[0], options=stations_list, id='station-dropdown-{}'.format(context)), width=5)
        ], class_name="row mt-3"),
        dbc.Row([
            dbc.Col(html.Div(id='image-container-{}'.format(context)), width=6),
            dbc.Col([html.Div(id='image-container-timeseries-{}'.format(context)),
                     html.Div([dbc.Button(f"{guitr.download_label[language_id]}", id="eurad_im_output_download",
                                class_name="fzj_style_btn"),
                              dcc.Download(id="eurad_im_download_result")]),
                     dbc.Col(html.Br()),
                     html.Div([dbc.Button(f"{guitr.im_download_label[language_id]}", id="eurad_im_plots_download",
                                class_name="fzj_style_btn"),
                              dcc.Download(id="eurad_im_download_plots")])], width=6),
        ], class_name="row mt-3"),
        dbc.Row([
            dbc.Col(html.Br(), width=12),
            dbc.Col([
                dbc.Checkbox(id="eurad_im_target", label=f"{guitr.show_target_plot_label[language_id]}", value=False)
            ], width=12),
            dbc.Col([
                dbc.Checkbox(id="eurad_im_downscaling", label=f"{guitr.show_downscaling_label[language_id]}", value=0, disabled=True)
            ], width=12)
        ], class_name="row mt-3f"),
        dbc.Row([
            dbc.Col(html.Br(), width=12),
            dbc.Col([
                dbc.Button(f"{guitr.ml_download_label[language_id]}", id="ml_downscaling_data_download",
                           n_clicks=0, class_name="fzj_style_btn"),
            ], width=12),
            dbc.Col([
                dbc.Label(f"{guitr.ml_download_explanation[language_id]}", id="ml_download_explanation",
                          style={'font-size': '12px'}),
            ], width=12)
        ], class_name="row mt-3f"),
    ]
    
    @callback(
        Output('ml_downscaling_data_download', 'disabled'),
        [Input('variable-dropdown-output', 'value')]
    )
    def update_button_disabled(selected_option):
        if selected_option == 'O3' or selected_option == 'NO2':
            return False
        else:
            return True
    
    
    def generate_eurad_im_output_modal(jobnr=None, lisopen=False, language_id=0):
        return html.Div([
            dbc.Modal(
                    [
                        dbc.ModalTitle(f"{guitr.run2_label[language_id]} {jobnr}", style={"fontSize": 15}, id="eurad_im_output_modal_title"),
                        dbc.ModalHeader(dbc.ModalTitle(guitr.application_text[language_id][0])),
                        dbc.ModalBody(generate_eurad_im_output_body(language_id, "output", jobnr)),
                        dbc.ModalFooter([dbc.Button(f"{guitr.close_label[language_id]}", id="eurad_im_output_close",
                                                    class_name="fzj_style_btn", n_clicks=0)
                                         ]),
                    ],
                    id="eurad_im_output_modal",
                    is_open=lisopen,
                    size="xl"
                )
            ], id="eurad_im_output_modal_container")
    
    
    def generate_eurad_im_result_modal(jobnr=None, lisopen=False, language_id=0):
        return dbc.Modal(
                        [
                            dbc.ModalTitle(f"{guitr.run2_label[language_id]} {jobnr}", style={"fontSize": 15}),
                            dbc.ModalHeader(dbc.ModalTitle(guitr.application_text[language_id][0])),
                            dbc.ModalBody(generate_eurad_im_output_body(language_id, "result", jobnr)),
                            dbc.ModalFooter(dbc.Button(f"{guitr.close_label[language_id]}", id="eurad_im_result_close",
                                                       class_name="fzj_style_btn", n_clicks=0)),
                        ],
                        id="eurad_im_result_modal",
                        is_open=lisopen,
                        size="xl"
                    )
    
    
    eurad_im_result_modal = html.Div([
                generate_eurad_im_result_modal()
            ], id="eurad_im_result_modal_container")
    
    def generate_eurad_scen_output_body(language_id, context, jobnr):
    
        if jobnr and (jobnr != 'bla'):
            infile = str(DATA_PATH.joinpath(f'{jobnr}.nc'))
            basefile = str(DATA_PATH.joinpath(f'base_{jobnr}.nc'))
            job_props = get_db_job_entry(jobnr)
            start_date = job_props['start_date']
            iscen = job_props['emis_scen']
            ireg = job_props['region']
            region = guitr.region_text[language_id][ireg]
            fc_length = job_props['forecast_length']
    
            if not os.path.isfile(infile):
                filenames = transfer_results_from_HPC(jobnr, start_date, iscen, fc_length, DATA_PATH)
                os.symlink(filenames['download_filename'], infile)
                os.symlink(filenames['base_download_filename'], basefile)
    
            nc_file = EURAD_netCDF(infile)
            timestep_list = nc_file.get_time_stamps()
            timestep_strings = [np.datetime_as_string(ts)[:16] for ts in timestep_list['time'].values]
    
            start_date = pd.to_datetime(timestep_strings[0]).strftime(guitr.date_format3[language_id])
            fc_length_str = "{} {}{}".format(fc_length, guitr.day_label[language_id], guitr.day_plural_label[language_id] if fc_length > 1 else "")
    
            variables_list = info.get_available_variables(infile)
            # for unit conversion, PRS and TEM were added
            variables_list.remove('PRS')
            variables_list.remove('TEM')
    
            stations_list = info.get_available_stations()
            stations_list = sorted(stations_list)
        else:
            start_date = '2018-07-19T00:00'
            timestep_strings = [ '2018-07-19 00:00' ]
            fc_length_str = '1'
            variables_list = [ 'NoneAvailable' ]
            stations_list = [ "XX, XX" ]
            iscen = 0
            region = "X"
        return [
            dbc.Row([dbc.Label(f"""{guitr.region_label[language_id]}: {region}, 
                                   {guitr.start_date_label[language_id]}: {start_date},
                                   {guitr.forecast_length_label[language_id]}: {fc_length_str},
                                   {guitr.emis_scen_label[language_id]}: {emis_info[language_id][' Name'][iscen]}""")]),
            dbc.Row([
                dbc.Col(dbc.Label(f"{guitr.time_step_label[language_id]}:"), width=3),
                dbc.Col(dcc.Dropdown(value=timestep_strings[0], options=timestep_strings, id='time-step-dropdown-{}'.format(context)), width=3)
            ], class_name="row mt-3"),
            dbc.Row([
                dbc.Col(dbc.Label("Variable:"), width=3),
                dbc.Col(dcc.Dropdown(value=variables_list[0], options=variables_list, id='variable-dropdown-{}'.format(context)), width=3),
                dbc.Col(dbc.Label(f"{guitr.location_label[language_id]}:"), width=1),
                dbc.Col(dcc.Dropdown(value=stations_list[0], options=stations_list, id='station-dropdown-{}'.format(context)), width=5)
            ], class_name="row mt-3"),
            dbc.Row([
                dbc.Col(html.Div(id='image-container-{}'.format(context)), width=6),
                dbc.Col([html.Div(id='image-container-timeseries-{}'.format(context)),
                         html.Div([dbc.Button(f"{guitr.download_label[language_id]}", id="eurad_scen_output_download",
                                    class_name="fzj_style_btn"),
                                  dcc.Download(id="eurad_scen_download_result")]),
                         dbc.Col(html.Br()),
                         html.Div([dbc.Button(f"{guitr.im_download_label[language_id]}", id="eurad_im_plots_download",
                                    class_name="fzj_style_btn"),
                                  dcc.Download(id="eurad_im_download_plots")])], width=6),
            ], class_name="row mt-3"),
            dbc.Row([
                dbc.Col(html.Br(), width=12),
                dbc.Col([
                    dbc.Checkbox(id="eurad_scen_diff", label=f"{guitr.show_diff_plot_label[language_id]}", value=False)
                ], width=12),
                dbc.Col([
                    dbc.Checkbox(id="eurad_scen_downscaling", label=f"{guitr.show_downscaling_label[language_id]}", value=0, disabled=True)
                ], style={"display": "flex"}),
            ], class_name="row mt-3f"),
        ]
    
    
    def generate_eurad_scen_body(language_id):
        disabled_days = [ dt.datetime.strptime('2017-01-27','%Y-%m-%d') + dt.timedelta(days=i) for i in range(14) ]
        disabled_days += [ dt.datetime.strptime('2017-02-16','%Y-%m-%d') + dt.timedelta(days=i) for i in range(523) ]
        return [
        dbc.Row([
            dbc.Col(dbc.Label(f"{guitr.date_label[language_id]}:"), width=3),
            dbc.Col(dcc.DatePickerSingle(id="eurad_scen_start_date",
                                         date=guiconst.min_date_allowed,
                                         display_format=guitr.date_format[language_id],
                                         first_day_of_week=guitr.first_day_of_week[language_id],
                                         min_date_allowed=guiconst.min_date_allowed,
                                         max_date_allowed=guiconst.max_date_allowed,
                                         disabled_days=disabled_days,
                                         initial_visible_month=guiconst.initial_visible_month)),
            dbc.Col(dbc.Label(f"{guitr.forecast_length_label[language_id]}:")),
            dbc.Col(dcc.Dropdown(value=guitr.forecast_length_options[language_id][-1],
                                 options=[{'label': guitr.forecast_length_options[language_id][i],
                                           'value': guitr.forecast_length_options[language_id][i],
                                           } for i in range(len(guitr.forecast_length_options[language_id]))],
                                 id="eurad_scen_forecast_length"))
        ], class_name="row mt-3"),
        dbc.Row([
            dbc.Col(dbc.Label(f"{guitr.region_label[language_id]}:"), width=3),
            dbc.Col(dcc.RadioItems(options={
                                         0: guitr.region_text[language_id][0],
                                         1: guitr.region_text[language_id][1]},
                                         value=0, id="eurad_scen_region_choice")),
        ], class_name="row mt-3"),
        dbc.Row([
            dbc.Col(dbc.Label(f"{guitr.emis_scen_label[language_id]}:"), width=3),
            dbc.Col(
                dcc.Dropdown(value=0,
                             options=[{'label': emis_info[language_id][" Name"][i],
                                       'value': i,
                                       'disabled': True if i == len(emis_info[language_id][" Name"])-1 else False
                                      } for i in range(len(emis_info[language_id][" Name"]))],
                             id="eurad_scen_emi"), width=6
            ),
            dbc.Col(dbc.Button(f"{guitr.help_emissions_label[language_id]}", id="help_emis_open", class_name="fzj_style_btn"), width=3),
            dbc.Modal([
                dbc.ModalHeader(f"{guitr.help_emissions_label[language_id]}"),
                dbc.ModalBody(dash_table.DataTable(emis_info[language_id].to_dict('records'),
                                                   [{"name": i, "id": i} for i in emis_info[language_id].columns],
                                                   style_table={"width": "100%"},
                                                   style_cell={"textAlign": "left",
                                                               "whiteSpace": "pre-line"
                                                               })),
                dbc.ModalFooter([dbc.Button(f"{guitr.close_label[language_id]}", id=f"help_emis_close", class_name="fzj_style_btn", n_clicks=0)]),
                ],
                id="help_emis_modal",
                is_open=False,
                size="lg")
        ], class_name="row mt-3"),
    ]
    
    
    def generate_eurad_scen_output_modal(container_id="eurad_scen_output_modal_container",
                                  jobnr=None, lisopen=False, language_id=0):
        return html.Div([
                dbc.Modal(
                        [
                            dbc.ModalTitle(f"{guitr.run2_label[language_id]} {jobnr}", style={"fontSize": 15}),
                            dbc.ModalHeader(dbc.ModalTitle(guitr.application_text[language_id][2])),
                            dbc.ModalBody(generate_eurad_scen_output_body(language_id, "output", jobnr)),
                            dbc.ModalFooter([dbc.Button(f"{guitr.close_label[language_id]}", id="eurad_scen_output_close",
                                                        class_name="fzj_style_btn", n_clicks=0)
                                             ]),
                        ],
                        id=container_id[:-10],
                        is_open=lisopen,
                        size="lg"
                        )
            ], id=container_id)
    
    def generate_eurad_scen_result_modal(container_id="eurad_scen_result_modal_container",
                                  jobnr=None, lisopen=False, language_id=0):
        return html.Div([
                dbc.Modal(
                        [
                            dbc.ModalTitle(f"{guitr.run2_label[language_id]} {jobnr}", style={"fontSize": 15}),
                            dbc.ModalHeader(dbc.ModalTitle(guitr.application_text[language_id][2])),
                            dbc.ModalBody(generate_eurad_scen_output_body(language_id, "result", jobnr)),
                            dbc.ModalFooter([dbc.Button(f"{guitr.close_label[language_id]}", id="eurad_scen_result_modal_close",
                                                        class_name="fzj_style_btn", n_clicks=0)
                                             ]),
                        ],
                        id=container_id[:-10],
                        is_open=lisopen,
                        size="lg"
                        )
            ], id=container_id)
    
    
    def create_jobs_tab(language_id=0):
        modal_list = [
            {"name": guitr.application_text[language_id][0], "id": "eurad_im", "body": generate_eurad_im_body(language_id),
             "description": guitr.description_text[language_id][0], "icon": "Icon1_FieldForecasting_small.png"},
            {"name": guitr.application_text[language_id][1], "id": "ml_fcast", "body": generate_ml_fcast_body(language_id),
             "description": guitr.description_text[language_id][1], "icon": "Icon2_PointForecasting_small.png"},
            {"name": guitr.application_text[language_id][2], "id": "eurad_scen", "body": generate_eurad_scen_body(language_id),
             "description": guitr.description_text[language_id][2], "icon": "Icon3_EmissionScenarios_small.png"},
        ]
    
        return html.Div([
            html.P([]),
            html.Div([
                html.Div(
                    [
                        html.Div([
                            dbc.Tooltip(modal["description"], target=f"{modal['id']}_open",
                                        style={"opacity": 1.0}),
                            dbc.Button([
                                #html.Div(html.H1(modal["name"],style={"line-height": "500px", "color": "black", "bgcolor": "white"}), style={"align-self": "center",
                                #                                      "width": "760px",
                                #                                      "height": "500px",
                                #                                      "background-image": f"url(../static/logos/{modal['icon']})"})
                                html.Div(html.H1(modal["name"],style={"line-height": "1100px", "vertical-align": "bottom"}), style={"align-self": "center",
                                                                      "width": "760px",
                                                                      "height": "600px",
                                                                      "background-image": f"url(static/logos/{modal['icon']})",
                                                                      "background-repeat": "no-repeat"})
                                                                      
                            ], id=f"{modal['id']}_open", style={"flex": "auto"}, class_name="fzj_style_btn")                                        
                        ], className="modal_button")
                        for modal in modal_list
                    ], className="button_row"
                ),
                html.Div([
                    dbc.Modal(
                        [
                            dbc.ModalHeader(dbc.ModalTitle(modal["name"])),
                            dbc.ModalBody(
                                modal["body"]
                            ),
                            dbc.ModalFooter([
                                dbc.Button(
                                    f"{guitr.run_label[language_id]}", id=f"{modal['id']}_run", class_name="fzj_style_btn", n_clicks=0
                                ),
                                dbc.Button(
                                    f"{guitr.close_label[language_id]}", id=f"{modal['id']}_close", class_name="fzj_style_btn", n_clicks=0
                                )
                            ]),
                        ],
                        id=f"{modal['id']}_modal",
                        is_open=False,
                        size="lg"
                    )
                    for modal in modal_list
                ]),
                html.P([
    
                ], id="outp_id"),
            ])
        ], id="create_jobs")
    
    
    # Define the layout of the first tab
    def create_description_content(language_id):
        return dbc.Card(
            dbc.CardBody(
                guitr.description[language_id]
            ),
            class_name="mt-3",
        )
    
    
    def get_job_status(jobid, application, convoc_status_dict):
        application_settings = { 0 : { "ecf_host": "jrlogin05.jureca",
                                       "ecf_port":  4960 },
                                 1 : { "ecf_host": "jrlogin09.jureca",
                                       "ecf_port": 20932 }, 
                                 2 : { "ecf_host": "jrlogin05.jureca",
                                       "ecf_port":  4960 } }
    
        base_url = f"{UNICORE_BASE}JURECA/rest/core"
    
        # Authentification/Authorization
        credentials = uc_credentials.UsernamePassword(UNICORE_USER, UNICORE_PASSWORD)
        client = uc_client.Client(credentials, base_url)
    
        # query status of ecflow jobs
    
        executable = "ecflow_client"
        environment = [ "PYTHONPATH=$PYTHONPATH:/p/project/cjicg21/jicg2126/ecflow/ecFlow-5.11.0-Source/lib/python3.8/site-packages/ecflow",
                        "PATH=$PATH:/p/project/cjicg21/jicg2126/ecflow/ecFlow-5.11.0-Source/bin/",
                        "ECFLOW_DIR=/p/project/cjicg21/jicg2126/ecflow/ecFlow-5.11.0-Source",
                        f"ECF_HOST={application_settings[application]['ecf_host']}",
                        f"ECF_PORT={application_settings[application]['ecf_port']}" ]
    
        arguments = [ f"--query dstate /{jobid}" ]
        job_description = {"Executable": executable,
                           "Job type": "ON_LOGIN_NODE",
                           "Environment": environment,
                           "Arguments": arguments, }
    
        job = client.new_job(job_description)
        # job.poll() takes up to one minute! Let's try after 2 seconds
        sleep(3)
    
        try:
            working_dir = job.working_dir
            stdout_content = working_dir.stat("stdout").raw().readlines()
            new_status = stdout_content[0].decode('utf-8').strip()
        except:
            new_status = 'queued'
    
        # translate response from UNICORE to controlled vocabulary
        if new_status == 'complete':
            new_status_code = convoc_status_dict['finished']
        elif new_status == 'active':
            new_status_code = convoc_status_dict['active']
        elif new_status == 'queued':
            new_status_code = convoc_status_dict['waiting']
        elif new_status == 'aborted' or new_status == 'suspended':
            new_status_code = convoc_status_dict['aborted']
        else:
            new_status_code = -1
    
        return new_status_code
    
    
    def change_status_of_job(jobid, new_status):
        conn = sqlite3.connect(DATA_PATH.joinpath('destine_de370c_users.db'))
        cur = conn.cursor()
        cur.execute(f"UPDATE jobs SET status={new_status} WHERE id='{jobid}'")
        conn.commit()
        conn.close()
    
    
    def get_my_jobs_from_db(user_id=None, language_id=0):
        data_from_db = []
        if user_id:
            conn = sqlite3.connect(DATA_PATH.joinpath('destine_de370c_users.db'))
            cur = conn.cursor()
            cmd = f"SELECT {', '.join(guiconst.job_fields)} FROM jobs WHERE user_id={user_id}"
            cur.execute(cmd)
            data_rows_from_db = cur.fetchall()
            cur.execute("SELECT job_status, id FROM convoc_status")
            convoc_status_from_db = cur.fetchall()
            conn.close()
    
            convoc_status_dict = dict(convoc_status_from_db)
    
            # if status != 'finished':
            # use /p/project/cjicg21/schroeder5/Destine_AQ/SCRIPTS/ECFLOW/query_status.bash jobnr
            # to determine the actual status
            # ==> there should be a refresh, whenever this tab is reloaded!
    
            for job in data_rows_from_db:
                job_dict = {}
                for i, field in enumerate(guiconst.job_fields):
                    job_dict[field] = job[i]
                job_status = job_dict['status']
                if (job_status == convoc_status_dict['active']) or (job_status == convoc_status_dict['waiting']):
                    new_status = get_job_status(job_dict['id'].upper(), job_dict['application'], convoc_status_dict)
                    if job_status != new_status:
                        change_status_of_job(job_dict['id'], new_status)
                        job_status = new_status
    
                data_from_db.append({guitr.jobs_columns[language_id][0]: guitr.application_text[language_id][job_dict['application']],
                                     guitr.jobs_columns[language_id][1]: guitr.status_text[language_id][job_status],
                                     guitr.jobs_columns[language_id][2]: dt.datetime.strptime(job_dict['start_date'],'%Y-%m-%d %H:%M').strftime(guitr.date_format2[language_id]),
                                     guitr.jobs_columns[language_id][3]: "{} {}{}".format(job_dict['forecast_length'], guitr.day_label[language_id], guitr.day_plural_label[language_id] if job_dict['forecast_length'] > 1 else ""),
                                     guitr.jobs_columns[language_id][4]: guitr.region_text[language_id][job_dict['region']],
                                     guitr.jobs_columns[language_id][5]: "{}".format(guitr.species_options[language_id][job_dict['species']] if job_dict['species'] is not None \
                                                                         else ",".join(guitr.species_options[language_id])),
                                     guitr.jobs_columns[language_id][6]: "{}".format(guitr.metrics_options[language_id][job_dict['metric']] if job_dict['metric'] is not None else ""),
                                     guitr.jobs_columns[language_id][7]: "{}".format(emis_info[language_id][" Name"][job_dict['emis_scen']] if job_dict['emis_scen'] is not None \
                                                                         else (guitr.default_text[language_id] if job_dict['application'] == 0 else "")),
                                     guitr.jobs_columns[language_id][8]: dt.datetime.strptime(job_dict['creation_date'],'%Y-%m-%d %H:%M').strftime(guitr.date_format2[language_id]),
                                     guitr.jobs_columns[language_id][9]: job_dict['id']})
        return data_from_db
    
    
    def generate_jobs_table(user_id=None, language_id=0):
        data_from_db = get_my_jobs_from_db(user_id, language_id)
    
        return html.Div([
            dash_table.DataTable(
                id='tbl-interactive',
                columns=[
                    {"name": i, "id": i} for i in guitr.jobs_columns[language_id]
                ],
                data=data_from_db,
                filter_action="native",
                sort_action="native",
                sort_mode="multi",
                row_selectable="single",
                style_header={"fontWeight": "bold"},
                style_data_conditional=[
                    {
                        'if': {
                            'filter_query': '{Status} = "abgebrochen" or {Status} = "aborted"',
                        },
                        'color': 'tomato'
                    },
                    {
                        'if': {
                            'filter_query': '{Status} = "aktiv" or {Status} = "active"',
                        },
                        'color': '#528aae'
                    },
                    {
                        'if': {
                            'filter_query': '{Status} = "in der Warteschlange" or {Status} = "waiting"',
                        },
                        'color': '#bcd2e8'
                    },
                ]
            ),
            html.Div(id='tbl'),
        ], style={'border': '1px solid black', 'border-width': '1px'})
    
    
    
    def create_tabs_layout(user_id=None, language_id=0):
        lhide = True
        if user_id:
            lhide = False
        return dbc.Tabs([
            # tab for "Description"
            dbc.Tab(label=guitr.layout_cards[language_id][0], id="description_tab", children=[
                create_description_content(language_id)
            ], tab_style={"font-size":"40px"}),
            # tab for "Create Jobs"
            dbc.Tab(label=guitr.layout_cards[language_id][1], id="create_jobs_tab", children=[
                create_jobs_tab(language_id)
            ], tab_style={"font-size":"40px"}, disabled=lhide),
            # tab for "My Jobs"
            dbc.Tab(label=guitr.layout_cards[language_id][2], id="my_jobs_tab", children=[
                generate_jobs_table(user_id=user_id, language_id=language_id),
                generate_eurad_im_output_modal(language_id=language_id),
                generate_ml_fcast_output_modal(language_id=language_id),
                generate_eurad_scen_output_modal(container_id="eurad_scen_output_modal_container", language_id=language_id)
            ], tab_style={"font-size":"40px"}, disabled=lhide),
        ], id='layout_tabs')
    
    
    layout = html.Div([
        aai_login,
        register_modal,
        create_tabs_layout(user_id=None, language_id=0),
        # dcc.Store stores the user information
        dcc.Store(id='user-info'),
        # dcc.Store stores the jobs information
        dcc.Store(id='job-info'),
        # dcc.Store stores the plots information
        dcc.Store(id='plot-info'),
    ])
    
    
    @callback(
        Output("login-background", "children"),
        Output("user-info", "data"),
        Output("layout_tabs", "children"),
        Output("login_modal", "is_open", allow_duplicate=True),
        Output("alert_nouser", "children"),
        Input("login_button", "n_clicks"),
        Input("login_close", "n_clicks"),
        State("login_name", "value"),
        State("login_password", "value"),
        background=True,
        running=[
            (Output("login_close", "disabled"), True, False),
        ],
        prevent_initial_call=True
    )
    def login_open(lb_click, lc_click, name, password):
        if ctx.triggered_id == "login_close":
            conn = sqlite3.connect(DATA_PATH.joinpath('destine_de370c_users.db'))
            cur = conn.cursor()
            cur.execute(f"SELECT id, password, language FROM users WHERE name ='{name}'")
            user = cur.fetchone()
            conn.close()
    
            if not user:
                return no_update, no_update, no_update, no_update, dbc.Alert(["No such user!"], color="danger")
            else:
                fernet = Fernet(KEY)
                db_password = fernet.decrypt(user[1]).decode()
                if db_password == password:
                    language_id=user[2]
                    return create_login_button(f"{guitr.user_label[language_id]} {name}"), \
                           '{"user_id": ' + f'{user[0]}, "language_id": {user[2]}' +'}', \
                           create_tabs_layout(user_id=user[0], language_id=language_id),\
                           False, no_update
                else:
                    return no_update, no_update, no_update, no_update, dbc.Alert(["Wrong password given!"], color="danger")
        else:
            return create_login_button(), '{"user_id": -1, "language_id": 0}', \
                   create_tabs_layout() , True, no_update
        
        
    @callback(
        [Output("register_modal", "is_open"),
         Output("login_modal", "is_open", allow_duplicate=True)],
        [Input("register_open", "n_clicks"),
         Input("register_ok_button", "n_clicks"),
         Input("register_close_button", "n_clicks")],
        State("login_modal", "is_open"),
        prevent_initial_call=True
    )
    def register_open(n1, n2, n3, login_is_open):
        if n2 or n3:
            return [False, False]
        if n1:
            return [True, False]
        return [False, login_is_open]
    
    
    @callback(
        Output("tbl-interactive", "data"),
        Output("my_jobs_tab", "children", allow_duplicate=True),
        Input("user-info", "data"),
        prevent_initial_call=True
    )
    def get_user_id(user_dict):
        user_id = json.loads(user_dict)["user_id"]
        language_id = json.loads(user_dict)["language_id"]
        return get_my_jobs_from_db(user_id, language_id), \
            [generate_jobs_table(user_id=user_id, language_id=language_id),
                generate_eurad_im_output_modal(language_id=language_id),
                generate_ml_fcast_output_modal(language_id=language_id),
                generate_eurad_scen_output_modal(container_id="eurad_scen_output_modal_container", language_id=language_id)]
    
    
    @callback(
        Output("eurad_im_modal", "is_open", allow_duplicate=True),
        Input("eurad_im_open", "n_clicks"),
        Input("eurad_im_close", "n_clicks"),
        prevent_initial_call=True
    )
    def eurad_im_modal(open_button, close_button):
        if ctx.triggered_id == "eurad_im_open":
            return True
        else:
            return False
    
    
    @callback(
        [Output("eurad_im_modal", "is_open", allow_duplicate=True),
         Output("my_jobs_tab", "children", allow_duplicate=True)],
         Input("eurad_im_run", "n_clicks"),
        [State("eurad_im_region_choice", "value"),
         State('eurad_im_start_date', 'date'),
         State('eurad_im_forecast_length', 'value'),
         State("user-info", "data")],
        background=True,
        running=[
            (Output("eurad_im_run", "disabled"), True, False),
        ],
        prevent_initial_call=True
    )
    def eurad_im_job_run(run_button, region, startdate, forecast_length, user_dict):
        # add job to user's job list
        user_id = json.loads(user_dict)["user_id"]
        language_id = json.loads(user_dict)["language_id"]
        new_job_dict = {}
        jobnr = get_random_string(12)
        new_job_dict['id'] = jobnr
        # application is EURAD-IM -- should be taken from the controlled vocabulary!
        new_job_dict['application'] = 0
        new_job_dict['region'] = region
        new_job_dict['start_date'] = startdate + ' 00:00'
        new_job_dict['forecast_length'] = int(forecast_length.split()[0])
        forecast_hours = new_job_dict['forecast_length'] * 24
        # take the coding for the status from the controlled vocabulary!
        # set it to "waiting" since it will just be submitted
        new_job_dict['status'] = 2
        # EURAD-IM does not have any species to be chosen
        new_job_dict['species'] = None
        # EURAD-IM does not have any metrics to be chosen
        new_job_dict['metric'] = None
        # EURAD-IM does not have any emission scenario
        new_job_dict['emis_scen'] = None
    
        # submit job
        base_url = f"{UNICORE_BASE}JURECA/rest/core"
        credentials = uc_credentials.UsernamePassword(UNICORE_USER, UNICORE_PASSWORD)
        client = uc_client.Client(credentials, base_url)
        job_description = {'Executable': "/p/project/cjicg21/schroeder5/Destine_AQ/start_destine_demonstrator.sh",
                           'Job type': "ON_LOGIN_NODE",
                           'Arguments': [jobnr, "0", startdate, str(forecast_hours)], }
        job = client.new_job(job_description)
    
        # now create job in db (otherwise the status cannot be determined!)
        create_db_job_entry(user_id, new_job_dict)
    
        # return updated values
        retval = ctx.triggered_id == "eurad_im_open"
        return retval,\
            [generate_jobs_table(user_id=user_id, language_id=language_id),
                generate_eurad_im_output_modal(language_id=language_id),
                generate_ml_fcast_output_modal(language_id=language_id),
                generate_eurad_scen_output_modal(container_id="eurad_scen_output_modal_container", language_id=language_id)]
    
    
    @callback(
        Output("ml_fcast_modal", "is_open", allow_duplicate=True),
        Output("my_jobs_tab", "children", allow_duplicate=True),
        Input("ml_fcast_run", "n_clicks"),
        [State('ml_fcast_body_region', 'value'),
         State('ml_fcast_body_startdate', 'date'),
         State('ml_fcast_body_forecast_length', 'value'),
         State('ml_fcast_body_species', 'value'),
         State('ml_fcast_body_metrics', 'value'),
         State("user-info", "data")],
        prevent_initial_call=True
    )
    def ml_fcast_job_run(run_button, region, startdate, forecast_length, species, metrics, user_dict):
        user_id = json.loads(user_dict)["user_id"]
        language_id = json.loads(user_dict)["language_id"]
        new_job_dict = {}
        jobnr = get_random_string(12)
        new_job_dict['id'] = jobnr
        # application is MLAir -- should be taken from the controlled vocabulary!
        new_job_dict['application'] = 1
        new_job_dict['region'] = region
        new_job_dict['start_date'] = startdate + ' 00:00'
        new_job_dict['forecast_length'] = int(forecast_length.split()[0])
        # also take the coding from the controlled vocabulary!
        # set it to "waiting" since it will just be submitted
        # job is not submitted --> job is already finished
        # new_job_dict['status'] = 2
        new_job_dict['status'] = 0
        # at the moment only ozone is available!
        new_job_dict['species'] = species
        # at the moment only dma8eu is available!
        new_job_dict['metric'] = metrics
        # MLAir does not have any emission scenario
        new_job_dict['emis_scen'] = None
    
    # do not submit the job
    #   # submit job
    #   base_url = f"{UNICORE_BASE}JURECA/rest/core"
    #   credentials = uc_credentials.UsernamePassword(UNICORE_USER, UNICORE_PASSWORD)
    #   client = uc_client.Client(credentials, base_url)
    #   job_description = {'Executable': "/p/project/deepacf/intelliaq/schroeder5/ecflow_mlair/start_destine_mlair_demonstrator.sh", "Job type": "ON_LOGIN_NODE", 'Arguments':[jobnr], }
    #   job = client.new_job(job_description)
    
        # now create job in db (otherwise the status cannot be determined!)
    
        create_db_job_entry(user_id, new_job_dict)
        retval = ctx.triggered_id == "ml_fcast_open"
        return retval,\
            [generate_jobs_table(user_id=user_id, language_id=language_id),
                generate_eurad_im_output_modal(language_id=language_id),
                generate_ml_fcast_output_modal(language_id=language_id),
                generate_eurad_scen_output_modal(container_id="eurad_scen_output_modal_container", language_id=language_id)]
    
    
    @callback(
        [Output("eurad_scen_modal", "is_open", allow_duplicate=True),
         Output("my_jobs_tab", "children", allow_duplicate=True)],
         Input("eurad_scen_run", "n_clicks"),
        [State("eurad_scen_region_choice", "value"),
         State('eurad_scen_start_date', 'date'),
         State('eurad_scen_forecast_length', 'value'),
         State('eurad_scen_emi', 'value'),
         State("user-info", "data")],
        background=True,
        running=[
            (Output("eurad_scen_run", "disabled"), True, False),
        ],
        prevent_initial_call=True
    )
    def eurad_scen_job_run(run_button, region, startdate, forecast_length, emi_scen, user_dict):
        # add job to user's job list
        user_id = json.loads(user_dict)["user_id"]
        language_id = json.loads(user_dict)["language_id"]
        new_job_dict = {}
        jobnr = get_random_string(12)
        new_job_dict['id'] = jobnr
        # application is EURAD-IM -- should be taken from the controlled vocabulary!
        new_job_dict['application'] = 2
        new_job_dict['region'] = region
        new_job_dict['start_date'] = startdate + ' 00:00'
        new_job_dict['forecast_length'] = int(forecast_length.split()[0])
        new_job_dict['emis_scen'] = emi_scen
        forecast_hours = new_job_dict['forecast_length'] * 24
        # take the coding for the status from the controlled vocabulary!
        # set it to "waiting" since it will just be submitted
        new_job_dict['status'] = 2
        # EURAD-IM does not have any species to be chosen
        new_job_dict['species'] = None
        # EURAD-IM does not have any metrics to be chosen
        new_job_dict['metric'] = None
    
        # submit job
        base_url = f"{UNICORE_BASE}JURECA/rest/core"
        credentials = uc_credentials.UsernamePassword(UNICORE_USER, UNICORE_PASSWORD)
        client = uc_client.Client(credentials, base_url)
        job_description = {'Executable': "/p/project/cjicg21/schroeder5/Destine_AQ/start_destine_demonstrator.sh",
                           'Job type': "ON_LOGIN_NODE",
                           'Arguments': [jobnr, str(emi_scen), startdate, str(forecast_hours)], }
        job = client.new_job(job_description)
    
        # now create job in db (otherwise the status cannot be determined!)
        create_db_job_entry(user_id, new_job_dict)
    
        # return updated values
        retval = ctx.triggered_id == "eurad_scen_open"
        return retval,\
            [generate_jobs_table(user_id=user_id, language_id=language_id),
                generate_eurad_im_output_modal(language_id=language_id),
                generate_ml_fcast_output_modal(language_id=language_id),
                generate_eurad_scen_output_modal(container_id="eurad_scen_output_modal_container", language_id=language_id)]
    
    
    @callback(
        Output("mlair_download_result", "data"),
        Input("mlair_output_download", "n_clicks"),
        State("job-info", "data"),
        prevent_initial_call=True
    )
    def mlair_output_download(download_button, job_dict):
    #   jobid = json.loads(job_dict)["jobnr"]
        # infile = str(DATA_PATH.joinpath('MLAIR', f'{jobid}.nc'))
        # demonstrator 
        infile = str(DATA_PATH.joinpath('MLAIR', 'forecasts_DENW067_test.nc'))
        return dcc.send_file(
            infile
        )
    
    
    @callback(
        Output("mlair_download_plot", "data"),
        Input("mlair_plot_download", "n_clicks"),
        [State("job-info", "data"),
         State("plot-info", "data")],
        prevent_initial_call=True
    )
    def mlair_plots_download(download_button, job_dict, plot_dict):
        species = json.loads(plot_dict)["species"]
        station = json.loads(plot_dict)["station"]
        start_date = json.loads(plot_dict)["start_date"]
        fc_length = json.loads(plot_dict)["fc_length"]
    
        # file name according to users selection
        output_file_name = f"mlair_{species}_{station}_{start_date}_{fc_length}.png"
        infile = str(ASSETS_PATH.joinpath('mlair', output_file_name))
        return dcc.send_file(
            infile
        )
    
    
    @callback(
        Output("eurad_im_download_result", "data"),
        Input("eurad_im_output_download", "n_clicks"),
        State("job-info", "data"),
        prevent_initial_call=True
    )
    def eurad_im_output_download(download_button, job_dict):
        jobid = json.loads(job_dict)["jobnr"]
        infile = str(DATA_PATH.joinpath(f'{jobid}.nc'))
        return dcc.send_file(
            infile
        )
    
    
    @callback(
        Output("eurad_im_download_plots", "data"),
        Input("eurad_im_plots_download", "n_clicks"),
        [State("job-info", "data"),
         State("plot-info", "data")],
        prevent_initial_call=True
    )
    def eurad_im_plots_download(download_button, job_dict, plot_dict):
        jobid = json.loads(job_dict)["jobnr"]
        station = json.loads(plot_dict)["station"]
        species = json.loads(plot_dict)["variable"]
        timestamp = json.loads(plot_dict)["time_step"]
        language_id = json.loads(plot_dict)["language_id"]
        ldiff = json.loads(plot_dict)["ldiff"]
        ltarget = json.loads(plot_dict)["ltarget"]
    
        # file names according to users selection
        infile1 = f'job_{jobid}_station_{station}_species_{species}_time_{timestamp}_{language_id}.png'
        if ltarget:
            infile2 = "job_{}_time_{}_species_{}_station_{}_target_{}.png".format(jobid, timestamp, species, station, language_id)
        elif ldiff:
            infile2 = "job_{}_time_{}_species_{}_station_{}_diff_{}.png".format(jobid, timestamp, species, station, language_id)
        else:
            infile2 = "job_{}_time_{}_species_{}_station_{}_{}.png".format(jobid, timestamp, species, station, language_id)
        files = [infile1, infile2]
        zipname = str(ASSETS_PATH.joinpath('eurad', f'job_{jobid}_time_{timestamp}_species_{species}_station_{station}.zip'))
    
        zipf = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
        for file in files:
            zipf.write(str(ASSETS_PATH.joinpath('eurad', file)),file)
        zipf.close()
        return dcc.send_file(
            zipname
        )
    
    
    @callback(
        Output("eurad_im_output_modal", "is_open"),
        Input("eurad_im_output_close", "n_clicks"),
        prevent_initial_call=True
    )
    def eurad_im_output_modal(close_button):
        return False
        
    
    @callback(
        Output("ml_fcast_modal", "is_open"),
        Input("ml_fcast_open", "n_clicks"),
        Input("ml_fcast_close", "n_clicks"),
    )
    def ml_fcast_modal(open_button, close_button):
        if ctx.triggered_id == "ml_fcast_open":
            return True
        else:
            return False
        
    
    @callback(
        Output("ml_fcast_output_modal", "is_open"),
        Input("ml_fcast_output_close", "n_clicks"),
        prevent_initial_call=True
    )
    def ml_fcast_output_modal(close_button):
        return False
        
    
    @callback(
        Output("eurad_scen_modal", "is_open"),
        Input("eurad_scen_open", "n_clicks"),
        Input("eurad_scen_close", "n_clicks"),
    )
    def eurad_scen_modal(open_button, close_button):
        if ctx.triggered_id == "eurad_scen_open":
            return True
        else:
            return False
        
    
    @callback(
        Output("eurad_scen_output_modal", "is_open"),
        Input("eurad_scen_output_close", "n_clicks"),
        prevent_initial_call=True
    )
    def eurad_scen_output_modal(close_button):
        return False
    
    
    @callback(
        Output("help_metrics_modal", "is_open"),
        Input("help_metrics_open", "n_clicks"),
        Input("help_metrics_close", "n_clicks"),
    )
    def eurad_scen_modal(open_button, close_button):
        if ctx.triggered_id == "help_metrics_open":
            return True
        else:
            return False
        
    
    @callback(
        Output("help_emis_modal", "is_open"),
        Input("help_emis_open", "n_clicks"),
        Input("help_emis_close", "n_clicks"),
    )
    def eurad_emis_modal(open_button, close_button):
        if ctx.triggered_id == "help_emis_open":
            return True
        else:
            return False
    
    
    @callback(
        Output('job-info', "data"),
        State('tbl-interactive', "derived_virtual_data"),
        Input('tbl-interactive', "derived_virtual_selected_rows"),
        State('user-info', "data"),
        prevent_initial_call=True
    )
    def postprocess_job(rows, derived_virtual_selected_rows, users_dict):
        jobinfo_dict = {}
        try:
            language_id = json.loads(users_dict)["language_id"]
        except:
            language_id = 0
        jobnr = "bla"
        eurad_im_output_modal_isopen = False
        ml_fcast_output_modal_isopen = False
        eurad_scen_output_modal_isopen = False
    
    #   if ((derived_virtual_selected_rows != []) and (not derived_virtual_selected_rows)):
        if (derived_virtual_selected_rows != []):
            status = rows[derived_virtual_selected_rows[0]][guitr.jobs_columns[language_id][1]]
            application = rows[derived_virtual_selected_rows[0]][guitr.jobs_columns[language_id][0]]
            jobnr = rows[derived_virtual_selected_rows[0]][guitr.jobs_columns[language_id][9]]
            if status == guitr.status_text[language_id][0]:
                eurad_im_output_modal_isopen = (application == guitr.application_text[language_id][0])
                ml_fcast_output_modal_isopen = (application == guitr.application_text[language_id][1])
                eurad_scen_output_modal_isopen = (application == guitr.application_text[language_id][2])
        jobinfo_dict["jobnr"] = jobnr
        jobinfo_dict["eurad_im_output_modal_isopen"] = eurad_im_output_modal_isopen
        jobinfo_dict["ml_fcast_output_modal_isopen"] = ml_fcast_output_modal_isopen
        jobinfo_dict["eurad_scen_output_modal_isopen"] = eurad_scen_output_modal_isopen
        jobinfo_json = json.dumps(jobinfo_dict)
        return jobinfo_json
    
    
    @callback(
        # Output("eurad_im_output_modal_title", "value"),
        # Output("eurad_im_output_modal", "is_open"),
        Output("eurad_im_output_modal_container", "children"),
        Output("ml_fcast_output_modal_container", "children"),
        Output("eurad_scen_output_modal_container", "children"),
        Input("job-info", "data"),
        State("user-info", "data"),
        prevent_initial_call=True
    )
    def get_jobs(jobs_dict, users_dict):
        jobnr = json.loads(jobs_dict)["jobnr"]
        try:
            language_id = json.loads(users_dict)["language_id"]
        except:
            language_id = 0
        eurad_im_output_modal_isopen = json.loads(jobs_dict)["eurad_im_output_modal_isopen"]
        ml_fcast_output_modal_isopen = json.loads(jobs_dict)["ml_fcast_output_modal_isopen"]
        eurad_scen_output_modal_isopen = json.loads(jobs_dict)["eurad_scen_output_modal_isopen"]
        if eurad_im_output_modal_isopen:
            eurad_im_output_modal = generate_eurad_im_output_modal(jobnr, eurad_im_output_modal_isopen, language_id)
        else:
            eurad_im_output_modal = dash.no_update
        if ml_fcast_output_modal_isopen:
            ml_fcast_output_modal = generate_ml_fcast_output_modal(jobnr, ml_fcast_output_modal_isopen, language_id)
        else:
            ml_fcast_output_modal = dash.no_update
        if eurad_scen_output_modal_isopen:
            eurad_scen_output_modal = generate_eurad_scen_output_modal("eurad_scen_output_modal_container", jobnr,
                                                            eurad_scen_output_modal_isopen, language_id)
        else:
            eurad_scen_output_modal = dash.no_update
        return eurad_im_output_modal, ml_fcast_output_modal, eurad_scen_output_modal