| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| import curses |
| import sys |
| import os |
| import numpy as np |
| import getpass |
| import urllib2 |
| import json |
| from glob import glob |
| |
| from netCDF4 import Dataset |
| from datetime import datetime, timedelta |
| |
| import ocw.metrics as metrics |
| import ocw.plotter as plotter |
| import ocw.dataset_processor as dsp |
| import ocw.evaluation as evaluation |
| import ocw.data_source.rcmed as rcmed |
| from ocw.dataset import Bounds |
| from ocw.data_source.local import load_file |
| import ocw.utils as utils |
| import ocw.data_source.esgf as esgf |
| from ocw_config_runner.configuration_writer import export_evaluation_to_config |
| |
| import ssl |
| if hasattr(ssl, '_create_unverified_context'): |
| ssl._create_default_https_context = ssl._create_unverified_context |
| |
| def ready_screen(page, note=""): |
| ''' Generates page borders, header, footer and notification center. |
| |
| :param page: Name of current page |
| :type page: string |
| :param note: Notification that system returns and will be shown |
| at the bottom of page |
| :type note: string |
| |
| :returns: y and x as location of text on screen |
| :rtype: integer |
| ''' |
| |
| screen.clear() |
| y, x = screen.getmaxyx() |
| screen.border(0) |
| screen.addstr(0, x/2-len(TITLE)/2, TITLE) |
| screen.addstr(y-1, x/2-len(ORGANIZATION)/2, ORGANIZATION) |
| screen.addstr(y-3, 1, "Notification:") |
| for each in range(1, x-1): |
| screen.addstr(y-4, each, "-") |
| if page == "main_menu": |
| screen.addstr(y-3, x-21, "(NC) = Not complete") |
| screen.addstr(y-2, x-21, "(C) = Complete") |
| if page == "settings_screen": |
| for i in range(y-5): |
| screen.addstr(i+1, x/2-2, ".") |
| screen.addstr(y-2, 1, note) |
| |
| return y, x |
| |
| |
| def get_esgf_netCDF_file_name(esgf_dataset_id, esgf_variable): |
| dataset_info = esgf._get_file_download_data(esgf_dataset_id, esgf_variable) |
| netCDF_name = dataset_info[0][0].split("/")[-1] |
| |
| return netCDF_name |
| |
| |
| ############################################################## |
| # Manage Model Screen |
| ############################################################## |
| |
| def load_local_model_screen(header): |
| '''Generates screen to be able to load local model file. |
| Path to model file (netCDF) and variable name is required. |
| |
| :param header: Header of page |
| :type header: string |
| |
| :returns: Notification |
| :rtype: string |
| ''' |
| |
| ready_screen("load_local_model_screen") |
| screen.addstr(1, 1, header + " > Load Local Model File ") |
| screen.addstr(4, 3, "[0]: Enter model full path") |
| screen.addstr(5, 3, "[1]: Select from existing model file/s") |
| screen.addstr(3, 2, "Select Option: ") |
| model_selection_option = screen.getstr() |
| |
| if model_selection_option == '0': |
| screen.addstr(7, 2, "Enter model (netCDF) full path: ") |
| model_full_path = screen.getstr() |
| model_full_path = model_full_path.replace(" ", "") |
| try: |
| netCDF_file = Dataset(model_full_path, 'r') |
| all_netcdf_variables = [variable.encode() for variable in netCDF_file.variables.keys()] |
| screen.addstr(9, 2, "Enter model variable name {0}: ".format(all_netcdf_variables)) |
| variable_name = screen.getstr() |
| try: |
| variable_info = format(netCDF_file.variables[variable_name]).splitlines() |
| for i, info in enumerate(variable_info): |
| screen.addstr(11 + i, 2, info) |
| screen.addstr(22, 2, "Confirm:") |
| screen.addstr(23, 4, "0- No") |
| screen.addstr(24, 4, "1- Yes") |
| screen.addstr(25, 3, "Would you take this variable:") |
| answer = screen.getstr() |
| if answer == "0": |
| note = "WARNING: Model file cannot be added." |
| elif answer == "1": |
| model_dataset = load_file(model_full_path, variable_name) |
| model_datasets.append(dsp.normalize_dataset_datetimes(model_dataset, model_dataset.temporal_resolution())) |
| models_info.append({'directory': model_full_path, 'variable_name': variable_name}) |
| note = "Model file successfully added." |
| else: |
| note = "WARNING: Model file cannot be added." |
| except: |
| note = "WARNING: Model file cannot be added. The variable [{0}] is not accepted. Please try again.".format(variable_name) |
| except: |
| note = "WARNING: Model file cannot be read. Please check the file directory or format. Only netCDF format is accepted." |
| elif model_selection_option == '1': |
| model_path = glob('./data/*.nc') |
| for imodel, model in enumerate(model_path): |
| screen.addstr(8 + imodel, 14, '[%d]: ' %imodel + model[7:]) |
| screen.addstr(7, 2, "Select Model (Model-ID): ") |
| model_id = screen.getstr() |
| try: |
| model_id = int(model_id) |
| netCDF_file = Dataset(model_path[model_id], 'r') |
| all_netcdf_variables = [variable.encode() for variable in netCDF_file.variables.keys()] |
| screen.addstr(10 + imodel, 2, "Enter model variable name {0}: ".format(all_netcdf_variables)) |
| variable_name = screen.getstr() |
| try: |
| variable_info = format(netCDF_file.variables[variable_name]).splitlines() |
| for ii, info in enumerate(variable_info): |
| screen.addstr(11 + imodel + ii, 2, info) |
| screen.addstr(17 + ii, 2, "Confirm:") |
| screen.addstr(18 + ii, 4, "0- No") |
| screen.addstr(19 + ii, 4, "1- Yes") |
| screen.addstr(20 + ii, 3, "Would you take this variable:") |
| answer = screen.getstr() |
| if answer == "0": |
| note = "WARNING: Model file cannot be added." |
| elif answer == "1": |
| model_dataset = load_file(model_path[model_id], variable_name) |
| model_datasets.append(dsp.normalize_dataset_datetimes(model_dataset, model_dataset.temporal_resolution())) |
| models_info.append({'directory': model_path, 'variable_name': variable_name}) |
| note = "Model file successfully added." |
| else: |
| note = "WARNING: Model file cannot be added." |
| except: |
| note = "WARNING: Model file cannot be added. The variable [{0}] is not accepted. Please try again.".format(variable_name) |
| netCDF_file.close() |
| except: |
| note = "WARNING: Model file cannot be read. Please check the file directory or format. Only netCDF format is accepted." |
| else: |
| note = "WARNING: Model file cannot be added." |
| |
| return note |
| |
| |
| def load_esgf_model_screen(header): |
| '''Generates screen to be able to load ESGF model file. |
| |
| :param header: Header of page |
| :type header: string |
| |
| :returns: Notification |
| :rtype: string |
| ''' |
| |
| ready_screen("load_esgf_model_screen") |
| screen.addstr(1, 1, header + " > Download ESGF Dataset ") |
| screen.addstr(6, 1, "Enter Dataset ID:") |
| esgf_dataset_id = screen.getstr() |
| screen.addstr(7, 1, "Enter Variable:") |
| esgf_variable = screen.getstr() |
| screen.addstr(8, 1, "Enter Username:") |
| esgf_username = screen.getstr() |
| screen.addstr(9, 1, "Enter Password:") |
| esgf_password = screen.getstr() |
| if esgf_dataset_id and esgf_variable and esgf_username and esgf_password: |
| try: |
| solr_url = "http://esg-datanode.jpl.nasa.gov/esg-search/search?id={0}&variable={1}&format=application%2Fsolr%2Bjson".format(esgf_dataset_id, esgf_variable) |
| metadata_json = json.load(urllib2.urlopen(solr_url)) |
| if metadata_json['response']['docs'][0]["product"][0] != "observations": |
| screen.addstr(11, 4, "Title: {0}".format(metadata_json['response']['docs'][0]['title'])) |
| screen.addstr(12, 4, "Start Date: {0}".format(metadata_json['response']['docs'][0]['datetime_start'])) |
| screen.addstr(13, 4, "End Date: {0}".format(metadata_json['response']['docs'][0]['datetime_stop'])) |
| screen.addstr(15, 2, "Confirm:") |
| screen.addstr(16, 4, "0- No") |
| screen.addstr(17, 4, "1- Yes") |
| screen.addstr(18, 3, "Would you take this dataset:") |
| answer = screen.getstr() |
| if answer == "0": |
| note = "WARNING: ESGF model file cannot be added." |
| elif answer == "1": |
| try: |
| screen.addstr(20, 4, "Downloading dataset.....") |
| screen.refresh() |
| datasets = esgf.load_dataset(esgf_dataset_id, |
| esgf_variable, |
| esgf_username, |
| esgf_password) |
| netCDF_name = get_esgf_netCDF_file_name(esgf_dataset_id, esgf_variable) |
| netCDF_path = "/tmp/{0}".format(netCDF_name) |
| model_dataset = load_file(netCDF_path, esgf_variable) |
| model_datasets.append(model_dataset) |
| models_info.append({'directory': netCDF_path, 'variable_name': esgf_variable}) |
| note = "Dataset successfully downloaded." |
| except: |
| note = "WARNING: Dataset has not been downloaded. Check your ESGF permission." |
| else: |
| note = "The selected dataset is Observation, please enter model dataset." |
| except: |
| note = "WARNING: Something went wrong in downloading model dataset from ESGF." |
| else: |
| note = "WARNING: No information given and no ESGF dataset has been downloaded." |
| |
| return note |
| |
| |
| def unload_model_screen(header): |
| '''Generates screen to be able to unload model file. |
| It lists all loaded model with index for each. |
| Selection of model with index will remove model from list of models. |
| |
| :param header: Header of page |
| :type header: string |
| |
| :returns: Notification |
| :rtype: string |
| ''' |
| |
| ready_screen("unload_model_screen") |
| screen.addstr(1, 1, header + " > Unload Model File") |
| screen.addstr(6, 1, "List of Model:") |
| for i, model in enumerate(models_info): |
| screen.addstr(8 + i, 10, "Model Number:[{0}] - Model path:[{1}] - Variables:[{2}]".format(str(i), model['directory'], model['variable_name'])) |
| screen.addstr(3, 2, "Select the model number to remove (press enter to go back): ") |
| try: |
| model_remove_index = screen.getstr() |
| models_info.pop(int(model_remove_index)) |
| model_datasets.pop(int(model_remove_index)) |
| note = "Model file unloaded successfully" |
| except: |
| note = "WARNING: Model file not unloaded successfully." |
| |
| return note |
| |
| |
| def list_model_screen(header): |
| '''Generates screen to list all model files. |
| |
| :param header: Header of page |
| :type header: string |
| ''' |
| |
| ready_screen("list_model_screen") |
| screen.addstr(1, 1, header + " > List Model File ") |
| screen.addstr(6, 6, "List of model(s): ") |
| for i, model in enumerate(models_info): |
| screen.addstr(8 + i, 10, "Model Number:[{0}] - Model path:[{1}] - Variables:[{2}]".format(str(i), model['directory'], model['variable_name'])) |
| screen.addstr(4, 4, "Return to Manage Model (press Enter) :") |
| screen.getstr() |
| |
| |
| def manage_model_screen(header, note=""): |
| '''Generates Manage Model screen. |
| |
| :param header: Header of page |
| :type header: string |
| :param note: Notification, defult to empty string. |
| :type note: string |
| ''' |
| |
| option = '' |
| while option != '0': |
| ready_screen("manage_model_screen", note) |
| screen.addstr(1, 1, header) |
| screen.addstr(4, 4, "1 - Load Local Model File") |
| screen.addstr(6, 4, "2 - Load ESGF Model File") |
| screen.addstr(8, 4, "3 - Unload Model File") |
| screen.addstr(10, 4, "4 - List Model File") |
| screen.addstr(12, 4, "0 - Return to Main Menu") |
| screen.addstr(14, 2, "Select an option: ") |
| screen.refresh() |
| option = screen.getstr() |
| |
| if option == '1': |
| note = load_local_model_screen(header) |
| if option == '2': |
| note = load_esgf_model_screen(header) |
| if option == '3': |
| note = unload_model_screen(header) |
| if option == '4': |
| note = list_model_screen(header) |
| note = " " |
| |
| |
| ############################################################## |
| # Manage Observation Screen |
| ############################################################## |
| |
| def select_obs_screen(header): #TODO: if the observation is already selected, don't select again. |
| '''Generates screen to select observation. |
| It reterives list of observations from database and make a table from that. |
| User has to select observation with dataset_id, parameter_id. |
| If the size of terminal screen is small to show whole table, a notification with link to parameter table on website will show up instead. |
| |
| :param header: Header of page |
| :type header: string |
| |
| :returns: Notification |
| :rtype: string |
| ''' |
| |
| ready_screen("select_obs_screen") |
| screen.addstr(1, 1, header + " > Select Observation ") |
| screen.addstr(7, 1, "Observations Table: ") |
| screen.addstr(8, 2, "|D-ID| - |P-ID| - |Database") |
| screen.addstr(9, 2, "|----| - |----| - |--------") |
| all_obs_info = rcmed.get_parameters_metadata() |
| new_all_obs_info = [] |
| for each in all_obs_info: |
| if not each['parameter_id'] in ['72', '73', '74', '75', '80', '42', '81', '84', '85', '86', '89', '90', '91', '94', '95', '96', '97', '98', '99', '100', '101', '103', '106']: |
| new_all_obs_info.append(each) |
| all_obs_info = new_all_obs_info |
| del new_all_obs_info |
| try: |
| for position, obs_info in enumerate(all_obs_info): |
| dataset_id = obs_info['dataset_id'] |
| parameter_id = obs_info['parameter_id'] |
| database = obs_info['database'] |
| line = "|{0:>4}| - |{1:>4}| - |{2}".format(dataset_id, parameter_id, database) |
| if position <= 25: |
| screen.addstr(10 + position, 2, line) |
| elif position > 25 and position <= 50: |
| screen.addstr(8, 50, "|D-ID| - |P-ID| - |Database") |
| screen.addstr(9, 50, "|----| - |----| - |--------") |
| screen.addstr(10 + position - 26, 50, line) |
| else: |
| screen.addstr(8, 100, "|D-ID| - |P-ID| - |Database") |
| screen.addstr(9, 100, "|----| - |----| - |--------") |
| screen.addstr(10 + position - 51, 100, line) |
| except: |
| ready_screen("select_obs_screen") |
| screen.addstr(1, 1, header + " > Select Observation ") |
| screen.addstr(10, 1, "Observation table cannot be shown due to small screen size. ") |
| screen.addstr(11, 1, "Please enlarge your screen and try again or refer to 'https://rcmes.jpl.nasa.gov/content/data-rcmes-database'. ") |
| try: |
| screen.addstr(2, 1, "More info for observation: https://rcmes.jpl.nasa.gov/content/data-rcmes-database") |
| screen.addstr(4, 2, "Enter Dataset ID (D-ID): ") |
| dataset_id = screen.getstr() |
| screen.addstr(5, 2, "Enter Parameter ID (P-ID): ") |
| parameter_id = screen.getstr() |
| |
| for obs in all_obs_info: |
| if obs['dataset_id'] == dataset_id and obs['parameter_id'] == parameter_id: |
| observations_info.append({ |
| 'database':obs['database'], |
| 'dataset_id':dataset_id, |
| 'parameter_id':parameter_id, |
| 'start_date':obs['start_date'], |
| 'end_date':obs['end_date'], |
| 'bounding_box':obs['bounding_box'], |
| 'timestep':obs['timestep'], |
| 'min_lat':float(eval(obs['bounding_box'].encode())[2][0]) if obs['bounding_box'] else None, |
| 'max_lat':float(eval(obs['bounding_box'].encode())[0][0]) if obs['bounding_box'] else None, |
| 'min_lon':float(eval(obs['bounding_box'].encode())[2][1]) if obs['bounding_box'] else None, |
| 'max_lon':float(eval(obs['bounding_box'].encode())[0][1]) if obs['bounding_box'] else None, |
| 'lat_res':float(obs['lat_res'].encode()), |
| 'lon_res':float(obs['lon_res'].encode()), |
| 'unit':obs['units'] |
| }) |
| note = "Observation sucessfully selected." |
| break |
| else: |
| note = "WARNING: Observation cannot be selected. There is no observation with given info." |
| except: |
| note = "WARNING: Observation cannot be selected, dataset or parameter id is wrong." |
| |
| return note |
| |
| |
| def load_esgf_obs_screen(header): |
| '''Generates screen to be able to load ESGF observation file. |
| |
| :param header: Header of page |
| :type header: string |
| |
| :returns: Notification |
| :rtype: string |
| ''' |
| |
| ready_screen("load_esgf_obs_screen") |
| screen.addstr(1, 1, header + " > Download ESGF Dataset ") |
| screen.addstr(6, 1, "Enter Dataset ID:") |
| esgf_dataset_id = screen.getstr() |
| screen.addstr(7, 1, "Enter Variable:") |
| esgf_variable = screen.getstr() |
| screen.addstr(8, 1, "Enter Username:") |
| esgf_username = screen.getstr() |
| screen.addstr(9, 1, "Enter Password:") |
| esgf_password = screen.getstr() |
| if esgf_dataset_id and esgf_variable and esgf_username and esgf_password: |
| try: |
| solr_url = "http://esg-datanode.jpl.nasa.gov/esg-search/search?id={0}&variable={1}&format=application%2Fsolr%2Bjson".format(esgf_dataset_id, esgf_variable) |
| metadata_json = json.load(urllib2.urlopen(solr_url)) |
| all_variables = metadata_json['response']['docs'][0]['variable'] |
| variable_index = all_variables.index(esgf_variable) |
| if metadata_json['response']['docs'][0]["product"][0] == "observations": |
| screen.addstr(11, 4, "Variable Long Name: {0}".format(metadata_json['response']['docs'][0]['variable_long_name'][variable_index])) |
| screen.addstr(12, 4, "Start Date: {0}".format(metadata_json['response']['docs'][0]['datetime_start'])) |
| screen.addstr(13, 4, "End Stop: {0}".format(metadata_json['response']['docs'][0]['datetime_stop'])) |
| screen.addstr(14, 4, "Time Frequency: {0}".format(metadata_json['response']['docs'][0]['time_frequency'])) |
| screen.addstr(15, 4, "Variable Units: {0}".format(metadata_json['response']['docs'][0]['variable_units'][variable_index])) |
| screen.addstr(16, 4, "East Degrees: {0}".format(metadata_json['response']['docs'][0]['east_degrees'])) |
| screen.addstr(17, 4, "North Degrees: {0}".format(metadata_json['response']['docs'][0]['north_degrees'])) |
| screen.addstr(18, 4, "South Degrees: {0}".format(metadata_json['response']['docs'][0]['south_degrees'])) |
| screen.addstr(19, 4, "West Degrees: {0}".format(metadata_json['response']['docs'][0]['west_degrees'])) |
| screen.addstr(22, 2, "Confirm:") |
| screen.addstr(23, 4, "0- No") |
| screen.addstr(24, 4, "1- Yes") |
| screen.addstr(25, 3, "Would you take this dataset:") |
| answer = screen.getstr() |
| if answer == "0": |
| note = "WARNING: ESGF observation file cannot be added." |
| elif answer == "1": |
| try: |
| screen.addstr(27, 4, "Downloading dataset.....") |
| screen.refresh() |
| datasets = esgf.load_dataset(esgf_dataset_id, |
| esgf_variable, |
| esgf_username, |
| esgf_password) |
| netCDF_name = get_esgf_netCDF_file_name(esgf_dataset_id, esgf_variable) |
| netCDF_path = "/tmp/{0}".format(netCDF_name) |
| obs_dataset = load_file(netCDF_path, esgf_variable) |
| observations_info.append({ |
| 'database':"{0}".format(netCDF_path), |
| 'dataset_id':"esgf".format(esgf_variable), |
| 'parameter_id':"{0}".format(esgf_variable), |
| 'start_date': obs_dataset.temporal_boundaries()[0].strftime("%Y-%m-%d"), |
| 'end_date':obs_dataset.temporal_boundaries()[1].strftime("%Y-%m-%d"), |
| #'bounding_box':obs['bounding_box'], |
| 'timestep':"monthly", |
| 'min_lat':obs_dataset.spatial_boundaries()[0], |
| 'max_lat':obs_dataset.spatial_boundaries()[1], |
| 'min_lon':obs_dataset.spatial_boundaries()[2], |
| 'max_lon':obs_dataset.spatial_boundaries()[3], |
| 'lat_res':obs_dataset.spatial_resolution()[0], |
| 'lon_res':obs_dataset.spatial_resolution()[1], |
| 'unit':"{0}".format(metadata_json['response']['docs'][0]['variable_units'][1]) |
| }) |
| note = "Dataset successfully downloaded." |
| except: |
| note = "WARNING: Dataset has not been downloaded." |
| else: |
| note = "The selected dataset is not Observation, please enter observation dataset." |
| except: |
| note = "WARNING: Something went wrong in downloading observation dataset from ESGF." |
| else: |
| note = "WARNING: No information given and no ESGF dataset has been downloaded." |
| |
| return note |
| |
| |
| def unselect_obs_screen(header): |
| '''Generates screen to be able to unselect observations. |
| Observations can be unselected by entering index allocated to them. |
| |
| :param header: Header of page |
| :type header: string |
| |
| :returns: Notification |
| :rtype: string |
| ''' |
| |
| ready_screen("unselect_obs_screen") |
| screen.addstr(1, 1, header + " > Unselect Observation ") |
| screen.addstr(6, 1, "List Observation(s):") |
| for i, obs_info in enumerate(observations_info): |
| screen.addstr(8 + i, 10, " [" + str(i) + "] : " + " Dataset ID: " + obs_info['dataset_id'] + " - Parameter ID: "+ obs_info['parameter_id'] + " - Database: "+ obs_info['database']) |
| screen.addstr(3, 2, "Select the observation to remove (press enter to go back): ") |
| try: |
| obs_remove_index = screen.getstr() |
| observations_info.pop(int(obs_remove_index)) |
| note = "Observation sucessfully unselected." |
| except: |
| note = "WARNING: Unselecting model was not successful." |
| |
| return note |
| |
| |
| def list_obs_screen(header): |
| '''Generates screen to list observations. |
| |
| :param header: Header of page |
| :type header: string |
| ''' |
| |
| ready_screen("list_obs_screen") |
| screen.addstr(1, 1, header + " > List Observation ") |
| screen.addstr(6, 6, "List of observation(s): ") |
| for i, obs_info in enumerate(observations_info): |
| screen.addstr(8 + i, 10, " [" + str(i) + "] : " + " Dataset ID: " + obs_info['dataset_id'] + " - Parameter ID: "+ obs_info['parameter_id'] + " - Database: "+ obs_info['database']) |
| screen.addstr(4, 4, "Return to Manage Observation (press Enter) :") |
| screen.getstr() |
| |
| |
| def manage_obs_screen(header, note=""): |
| '''Generates Manage Observation screen. |
| |
| :param header: Header of page |
| :type header: string |
| :param note: Notification, defult to empty string. |
| :type note: string |
| ''' |
| |
| option = '' |
| while option != '0': |
| ready_screen("manage_obs_screen", note) |
| screen.addstr(1, 1, header) |
| screen.addstr(4, 4, "1 - Select Observation") |
| screen.addstr(6, 4, "2 - Load ESGF Observation") |
| screen.addstr(8, 4, "3 - Unselect Observation") |
| screen.addstr(10, 4, "4 - List Observation") |
| screen.addstr(12, 4, "0 - Return to Main Menu") |
| screen.addstr(14, 2, "Select an option: ") |
| screen.refresh() |
| |
| option = screen.getstr() |
| if option == '1': |
| note = select_obs_screen(header) |
| if option == '2': |
| note = load_esgf_obs_screen(header) |
| if option == '3': |
| note = unselect_obs_screen(header) |
| if option == '4': |
| list_obs_screen(header) |
| note = " " |
| |
| |
| ############################################################## |
| # Run Evaluation Screen |
| ############################################################## |
| |
| def run_screen(model_datasets, models_info, observations_info, |
| overlap_start_time, overlap_end_time, overlap_min_lat, |
| overlap_max_lat, overlap_min_lon, overlap_max_lon, |
| temp_grid_setting, spatial_grid_option, spatial_grid_setting_lat, spatial_grid_setting_lon, reference_dataset, target_datasets, metric, working_directory, plot_title): |
| '''Generates screen to show running evaluation process. |
| |
| :param model_datasets: list of model dataset objects |
| :type model_datasets: list |
| :param models_info: list of dictionaries that contain information for each model |
| :type models_info: list |
| :param observations_info: list of dictionaries that contain information for each observation |
| :type observations_info: list |
| :param overlap_start_time: overlap start time between model and obs start time |
| :type overlap_start_time: datetime |
| :param overlap_end_time: overlap end time between model and obs end time |
| :type overlap_end_time: float |
| :param overlap_min_lat: overlap minimum lat between model and obs minimum lat |
| :type overlap_min_lat: float |
| :param overlap_max_lat: overlap maximum lat between model and obs maximum lat |
| :type overlap_max_lat: float |
| :param overlap_min_lon: overlap minimum lon between model and obs minimum lon |
| :type overlap_min_lon: float |
| :param overlap_max_lon: overlap maximum lon between model and obs maximum lon |
| :type overlap_max_lon: float |
| :param temp_grid_setting: temporal grid option such as hourly, daily, monthly and annually |
| :type temp_grid_setting: string |
| :param spatial_grid_setting: |
| :type spatial_grid_setting: string |
| :param reference_dataset: dictionary of reference dataset |
| :type reference_dataset: dictionary |
| :param target_datasets: dictionary of all target datasets |
| :type target_datasets: dictionary |
| :param metric: name of selected metric |
| :type metric: string |
| :param working_directory: path to a directory for storring outputs |
| :type working_directory: string |
| :param plot_title: Title for plot |
| :type plot_title: string |
| ''' |
| try: |
| target_datasets_ensemble = [] |
| new_model_datasets = model_datasets[:] |
| |
| option = None |
| if option != "0": |
| ready_screen("run_evaluation_screen") |
| y = screen.getmaxyx()[0] |
| screen.addstr(2, 2, "Evaluation started....") |
| screen.refresh() |
| |
| screen.addstr(4, 4, "Retrieving data...") |
| screen.refresh() |
| obs_dataset = [] |
| for i in range(len(observations_info)): |
| if observations_info[i]['dataset_id'] == "esgf": |
| obs_dataset.append(load_file(observations_info[i]['database'], observations_info[i]['parameter_id'])) |
| else: |
| dataset_id = int(observations_info[i]['dataset_id']) |
| parameter_id = int(observations_info[i]['parameter_id']) |
| obs_dataset.append(rcmed.parameter_dataset( |
| dataset_id, |
| parameter_id, |
| overlap_min_lat, |
| overlap_max_lat, |
| overlap_min_lon, |
| overlap_max_lon, |
| overlap_start_time, |
| overlap_end_time)) |
| |
| screen.addstr(4, 4, "--> Data retrieved.") |
| screen.refresh() |
| |
| EVAL_BOUNDS = Bounds(lat_min=overlap_min_lat, lat_max=overlap_max_lat, lon_min=overlap_min_lon, lon_max=overlap_max_lon, start=overlap_start_time, end=overlap_end_time) |
| |
| screen.addstr(5, 4, "Temporally regridding...") |
| screen.refresh() |
| for i in range(len(obs_dataset)): |
| obs_dataset[i] = dsp.temporal_rebin(obs_dataset[i], temp_grid_setting.lower()) |
| |
| for member, each_target_dataset in enumerate(new_model_datasets): |
| new_model_datasets[member] = dsp.temporal_rebin(new_model_datasets[member], temp_grid_setting.lower()) |
| new_model_datasets[member] = dsp.normalize_dataset_datetimes(new_model_datasets[member], temp_grid_setting.lower()) |
| start_index = np.where(new_model_datasets[member].times >= overlap_start_time)[0][0] |
| end_index = np.where(new_model_datasets[member].times <= overlap_end_time)[0][-1] |
| new_model_datasets[member].values=each_target_dataset.values[start_index:end_index+1,:] |
| new_model_datasets[member].times=each_target_dataset.times[start_index:end_index+1] |
| screen.addstr(5, 4, "--> Temporally regridded.") |
| screen.refresh() |
| |
| screen.addstr(6, 4, "Spatially regridding...") |
| screen.refresh() |
| if spatial_grid_option == 'Observation': |
| new_lats = obs_dataset[0].lats |
| new_lons = obs_dataset[0].lons |
| elif spatial_grid_option == 'Model': |
| new_lats = new_model_datasets[0].lats |
| new_lons = new_model_datasets[0].lons |
| else: |
| new_lats = np.arange(overlap_min_lat, overlap_max_lat, spatial_grid_setting_lat) |
| new_lons = np.arange(overlap_min_lon, overlap_max_lon, spatial_grid_setting_lon) |
| if spatial_grid_option != 'Observation': |
| for i in range(len(obs_dataset)): |
| obs_dataset[i] = dsp.spatial_regrid(obs_dataset[i], new_lats, new_lons) |
| obs_dataset[i] = dsp.variable_unit_conversion(obs_dataset[i]) |
| if spatial_grid_option != 'Model': |
| for member, each_target_dataset in enumerate(new_model_datasets): |
| new_model_datasets[member] = dsp.spatial_regrid(new_model_datasets[member], new_lats, new_lons) |
| new_model_datasets[member] = dsp.variable_unit_conversion(new_model_datasets[member]) |
| screen.addstr(6, 4, "--> Spatially regridded.") |
| screen.refresh() |
| |
| obs_dataset = dsp.mask_missing_data(obs_dataset+new_model_datasets)[0:len(obs_dataset)] |
| new_model_datasets = dsp.mask_missing_data(obs_dataset+new_model_datasets)[len(obs_dataset):] |
| |
| if metric == 'bias_of_multiyear_climatology': |
| allNames = [] |
| |
| for model in new_model_datasets: |
| allNames.append(model.name) |
| |
| screen.addstr(7, 4, "Setting up metrics...") |
| screen.refresh() |
| mean_bias = metrics.TemporalMeanBias() |
| pattern_correlation = metrics.PatternCorrelation() |
| spatial_std_dev_ratio = metrics.StdDevRatio() |
| screen.addstr(7, 4, "--> Metrics setting done.") |
| screen.refresh() |
| |
| screen.addstr(8, 4, "Running evaluation.....") |
| screen.refresh() |
| if reference_dataset[:3] == 'obs': |
| reference = obs_dataset[int(reference_dataset[-1])] |
| if reference_dataset[:3] == 'mod': |
| reference = obs_dataset[int(new_model_datasets[-1])] |
| |
| targets = [] |
| for target in target_datasets: |
| if target[:3] == 'obs': |
| targets.append(obs_dataset[int(target[-1])]) |
| if target[:3] == 'mod': |
| targets.append(new_model_datasets[int(target[-1])]) |
| |
| evaluation_result = evaluation.Evaluation(reference, targets, [mean_bias]) |
| #export_evaluation_to_config(evaluation_result) |
| evaluation_result.run() |
| screen.addstr(8, 4, "--> Evaluation Finished.") |
| screen.refresh() |
| |
| screen.addstr(9, 4, "Generating plots....") |
| screen.refresh() |
| new_rcm_bias = evaluation_result.results[0] |
| |
| if not os.path.exists(working_directory): |
| os.makedirs(working_directory) |
| |
| fname = working_directory + 'Bias_contour' |
| fname2= working_directory + 'Obs_contour' |
| fname3= working_directory + 'Model_contour' |
| plotter.draw_contour_map(new_rcm_bias, new_lats, new_lons, gridshape=(2, 5), fname=fname, subtitles=allNames, cmap='coolwarm') |
| plotter.draw_contour_map(utils.calc_temporal_mean(reference), new_lats, new_lons, gridshape=(2, 5), fname=fname2, subtitles=allNames, cmap='rainbow') |
| plotter.draw_contour_map(utils.calc_temporal_mean(targets[0]), new_lats, new_lons, gridshape=(2, 5), fname=fname3, subtitles=allNames, cmap='rainbow') |
| screen.addstr(9, 4, "--> Plots generated.") |
| screen.refresh() |
| screen.addstr(y-2, 1, "Press 'enter' to Exit: ") |
| option = screen.getstr() |
| |
| if metric == 'std': |
| for i in range(len(obs_dataset)): |
| _, obs_dataset[i].values = utils.calc_climatology_year(obs_dataset[i]) |
| obs_dataset[i].values = np.expand_dims(obs_dataset[i].values, axis=0) |
| |
| target_datasets_ensemble = dsp.ensemble(new_model_datasets) |
| target_datasets_ensemble.name = "ENS" |
| new_model_datasets.append(target_datasets_ensemble) |
| |
| for member, each_target_dataset in enumerate(new_model_datasets): |
| _, new_model_datasets[member].values = utils.calc_climatology_year(new_model_datasets[member]) |
| new_model_datasets[member].values = np.expand_dims(new_model_datasets[member].values, axis=0) |
| |
| allNames = [] |
| |
| for model in new_model_datasets: |
| allNames.append(model.name) |
| pattern_correlation = metrics.PatternCorrelation() |
| spatial_std_dev = metrics.StdDevRatio() |
| |
| if reference_dataset[:3] == 'obs': |
| reference = obs_dataset[int(reference_dataset[-1])] |
| if reference_dataset[:3] == 'mod': |
| reference = obs_dataset[int(new_model_datasets[-1])] |
| |
| targets = [] |
| for target in target_datasets: |
| if target[:3] == 'obs': |
| targets.append(obs_dataset[int(target[-1])]) |
| if target[:3] == 'mod': |
| targets.append(new_model_datasets[int(target[-1])]) |
| |
| evaluation_result = evaluation.Evaluation(reference, targets, [spatial_std_dev]) |
| export_evaluation_to_config(evaluation_result) |
| evaluation_result.run() |
| |
| rcm_std_dev = evaluation_result.results |
| evaluation_result = evaluation.Evaluation(reference, targets, [pattern_correlation]) |
| evaluation_result.run() |
| |
| rcm_pat_cor = evaluation_result.results |
| taylor_data = np.array([rcm_std_dev, rcm_pat_cor]).transpose() |
| new_taylor_data = np.squeeze(np.array(taylor_data)) |
| |
| if not os.path.exists(working_directory): |
| os.makedirs(working_directory) |
| |
| fname = working_directory + 'taylor_plot' |
| |
| plotter.draw_taylor_diagram(new_taylor_data, allNames, "CRU31", fname=fname, fmt='png', frameon=False) |
| del new_model_datasets |
| del obs_dataset |
| return "No error" |
| except Exception, error: |
| return "Error: {0}".format(error[0][:200]) |
| |
| |
| ############################################################## |
| # Settings Screen |
| ############################################################## |
| |
| def get_models_temp_bound(): |
| '''Get models temporal bound. |
| |
| :returns: model start and end time |
| :rtypes: (datatime, datetime) |
| ''' |
| |
| models_start_time = [] |
| models_end_time = [] |
| for model in model_datasets: |
| models_start_time.append(model.temporal_boundaries()[0]) |
| models_end_time.append(model.temporal_boundaries()[1]) |
| |
| return models_start_time, models_end_time |
| |
| |
| def get_obs_temp_bound(): |
| '''Get observation temporal bound. |
| |
| :returns: observation start and end time |
| :rtype: (datetime, datetime) |
| ''' |
| |
| observations_start_time = [] |
| observations_end_time = [] |
| for obs in observations_info: |
| obs_start_time = datetime.strptime(obs['start_date'], "%Y-%m-%d") |
| observations_start_time.append(obs_start_time) |
| obs_end_time = datetime.strptime(obs['end_date'], "%Y-%m-%d") |
| observations_end_time.append(obs_end_time) |
| |
| return observations_start_time, observations_end_time |
| |
| |
| def get_models_temp_overlap(models_start_time, models_end_time): |
| '''Calculate temporal overlap between all the models |
| |
| :param models_start_time: models start time |
| :type models_start_time: list of datetimes |
| :param models_end_time: models end time |
| :type models_end_time: list of datetime |
| |
| :returns: overlap start and end time between all the models |
| :rtype: (datetime, datetime) |
| ''' |
| |
| models_overlap_start_time = max(models_start_time) |
| models_overlap_end_time = min(models_end_time) |
| |
| #Need to check if all models have temporal overlap, otherwise return |
| # to main menu and print a warning as notification. |
| if models_overlap_end_time <= models_overlap_start_time: |
| main_menu(model_datasets, models_info, observation_datasets, observations_info, note="WARNING: One or more model does not have temporal overlap with others.") |
| |
| return models_overlap_start_time, models_overlap_end_time |
| |
| |
| def get_obs_temp_overlap(observations_start_time, observations_end_time): |
| '''Calculate temporal overlap between all the observations |
| |
| :param observations_start_time: observations start time |
| :type observations_start_time: list of datetimes |
| :param observations_end_time: observations end time |
| :type observations_end_time: list of datetime |
| |
| :returns: overlap start and end time between all the observations |
| :rtype: (datetime, datetime) |
| ''' |
| |
| obs_overlap_start_time = max(observations_start_time) |
| obs_overlap_end_time = min(observations_end_time) |
| |
| #Need to check if all observations have temporal overlap, otherwise return |
| # to main menu and print a warning as notification. |
| if obs_overlap_end_time <= obs_overlap_start_time: |
| main_menu(model_datasets, models_info, observation_datasets, observations_info, note="WARNING: One or more observation does not have temporal overlap with others.") |
| |
| return obs_overlap_start_time, obs_overlap_end_time |
| |
| |
| def get_all_temp_overlap(models_overlap_start_time, models_overlap_end_time, obs_overlap_start_time, obs_overlap_end_time): |
| '''Calculate temporal overlap between given datasets. |
| |
| :param models_overlap_start_time: models overlap start time |
| :type models_overlap_start_time: list of datetimes |
| :param models_overlap_end_time: models overlap end time |
| :type models_overlap_end_time: list of datetime |
| :param obs_overlap_start_time: obs overlap start time |
| :type obs_overlap_start_time: list of datetimes |
| :param obs_overlap_end_time: obs overlap end time |
| :type obs_overlap_end_time: list of datetimes |
| |
| :returns: overlap start and end time between models and observations |
| :rtype: (datetime, datetime) |
| ''' |
| |
| all_overlap_start_time = max([models_overlap_start_time, obs_overlap_start_time]) |
| all_overlap_end_time = min([models_overlap_end_time, obs_overlap_end_time]) |
| |
| #Need to check if all datasets have temporal overlap, otherwise return |
| # to main menu and print a warning as notification. |
| if all_overlap_end_time <= all_overlap_start_time: |
| main_menu(model_datasets, models_info, observation_datasets, observations_info, note="WARNING: One or more dataset does not have temporal overlap with others.") |
| |
| return all_overlap_start_time, all_overlap_end_time |
| |
| |
| def get_models_spatial_bound(): #TODO: convert longitudes to -180, 180 to match with observation data |
| '''Get all models spatial bound. |
| |
| :returns: all models spatial boundaries |
| :rtype: list |
| ''' |
| |
| models_bound = [] |
| for model in model_datasets: |
| models_bound.append(model.spatial_boundaries()) |
| |
| return models_bound |
| |
| |
| def get_models_spatial_overlap(models_bound): |
| '''Calculate spatial overlap between all models. |
| |
| :param models_bound: all models spatial boundaries information |
| :type models_bound: list |
| |
| :returns: spatial boundaries overlap between all models |
| :rtype: (float, float, float, float) |
| ''' |
| |
| models_overlap_min_lat = max(each[0] for each in models_bound) |
| models_overlap_max_lat = min(each[1] for each in models_bound) |
| models_overlap_min_lon = max(each[2] for each in models_bound) |
| models_overlap_max_lon = min(each[3] for each in models_bound) |
| |
| #Need to check if all models have spatial overlap, otherwise return |
| # to main menu and print a warning as notification. |
| if models_overlap_max_lat <= models_overlap_min_lat or models_overlap_max_lon <= models_overlap_min_lon: |
| main_menu(model_datasets, models_info, observation_datasets, observations_info, note="WARNING: One or more model does not have spatial overlap with others.") |
| |
| return models_overlap_min_lat, models_overlap_max_lat, models_overlap_min_lon, models_overlap_max_lon |
| |
| |
| def get_obs_spatial_bound(): |
| '''Get all observations spatial bound. |
| |
| :returns: all observations spatial boundaries |
| :rtype: list |
| ''' |
| |
| observations_bound = [] |
| for obs in observations_info: |
| observations_bound.append([obs['min_lat'], obs['max_lat'], obs['min_lon'], obs['max_lon']]) |
| |
| return observations_bound |
| |
| |
| def get_obs_spatial_overlap(observations_bound): |
| '''Calculate spatial overlap between all observations. |
| |
| :param observations_bound: all observations spatial boundaries information |
| :type observations_bound: list |
| |
| :returns: spatial boundaries overlap between all observations |
| :rtype: (float, float, float, float) |
| ''' |
| |
| obs_overlap_min_lat = max(each[0] for each in observations_bound) |
| obs_overlap_max_lat = min(each[1] for each in observations_bound) |
| obs_overlap_min_lon = max(each[2] for each in observations_bound) |
| obs_overlap_max_lon = min(each[3] for each in observations_bound) |
| |
| #Need to check if all observations have spatial overlap, otherwise return |
| # to main menu and print a warning as notification. |
| if obs_overlap_max_lat <= obs_overlap_min_lat or obs_overlap_max_lon <= obs_overlap_min_lon: |
| main_menu(model_datasets, models_info, observation_datasets, observations_info, note="WARNING: One or more observation does not have spatial overlap with others.") |
| |
| return obs_overlap_min_lat, obs_overlap_max_lat, obs_overlap_min_lon, obs_overlap_max_lon |
| |
| |
| def get_all_spatial_overlap(models_overlap_min_lat, models_overlap_max_lat, models_overlap_min_lon, models_overlap_max_lon, obs_overlap_min_lat, obs_overlap_max_lat, obs_overlap_min_lon, obs_overlap_max_lon): |
| '''Calculate spatial overlap between all models and observations |
| |
| :param models_overlap_min_lat: min latitude between all models |
| :type models_overlap_min_lat: float |
| :param models_overlap_max_lat: max latitude between all models |
| :type models_overlap_max_lat: float |
| :param models_overlap_min_lon: min longitude between all models |
| :type models_overlap_min_lon: float |
| :param models_overlap_max_lon: max longitude between all models |
| :type models_overlap_max_lon: float |
| :param obs_overlap_min_lat: min latitude between all onservations |
| :type obs_overlap_min_lat: float |
| :param obs_overlap_max_lat: max latitude between all onservations |
| :type obs_overlap_max_lat: float |
| :param obs_overlap_min_lon: min longitude between all onservations |
| :type obs_overlap_min_lon: float |
| :param obs_overlap_max_lon: max longitude between all onservations |
| :type obs_overlap_max_lon: float |
| |
| :returns: spatial boundaries overlap between all models and observations |
| :rtype: (float, float, float, float) |
| ''' |
| |
| all_overlap_min_lat = max([models_overlap_min_lat, obs_overlap_min_lat]) |
| all_overlap_max_lat = min([models_overlap_max_lat, obs_overlap_max_lat]) |
| all_overlap_min_lon = max([models_overlap_min_lon, obs_overlap_min_lon]) |
| all_overlap_max_lon = min([models_overlap_max_lon, obs_overlap_max_lon]) |
| |
| #Need to check if all datasets have spatial overlap, otherwise return |
| # to main menu and print a warning as notification. |
| if all_overlap_max_lat <= all_overlap_min_lat or all_overlap_max_lon <= all_overlap_min_lon: |
| main_menu(model_datasets, models_info, observation_datasets, observations_info, note="WARNING: One or more dataset does not have spatial overlap with others.") |
| |
| return all_overlap_min_lat, all_overlap_max_lat, all_overlap_min_lon, all_overlap_max_lon |
| |
| |
| def get_models_temp_res(): |
| '''Get models temporal resolution. |
| |
| :returns: models resolution |
| :rtypes: string |
| ''' |
| |
| models_resolution = [] |
| for model in model_datasets: |
| models_resolution.append(model.temporal_resolution()) |
| dic = {0:"hourly", 1:"daily", 2:"monthly", 3:"yearly"} |
| models_resolution_key = [] |
| for res in models_resolution: |
| for key, value in dic.items(): |
| if value == res: |
| models_resolution_key.append(key) |
| |
| return dic[max(models_resolution_key)] |
| |
| |
| def get_obs_temp_res(): |
| '''Get observations temporal resolution. |
| |
| :returns: observations resolution |
| :rtypes: string |
| ''' |
| |
| obs_resolution = [] |
| for model in model_datasets: |
| obs_resolution.append(model.temporal_resolution()) |
| dic = {0:"hourly", 1:"daily", 2:"monthly", 3:"yearly"} |
| obs_resolution_key = [] |
| for res in obs_resolution: |
| for key, value in dic.items(): |
| if value == res: |
| obs_resolution_key.append(key) |
| |
| return dic[max(obs_resolution_key)] |
| |
| |
| def get_models_spatial_res(): |
| '''Get models spatial resolution |
| |
| :returns: maximum models latitude and longitude resolution |
| :rtypes: float, float |
| ''' |
| |
| models_lat_res = [] |
| models_lon_res = [] |
| for model in model_datasets: |
| models_lat_res.append(model.spatial_resolution()[0]) |
| models_lon_res.append(model.spatial_resolution()[1]) |
| |
| return max(models_lat_res), max(models_lon_res) |
| |
| |
| def get_obs_spatial_res(): |
| '''Get observations spatial resolution |
| |
| :returns: maximum observations latitude and longitude resolution |
| :rtypes: float, float |
| ''' |
| |
| obs_lat_res = [] |
| obs_lon_res = [] |
| for obs in observations_info: |
| obs_lat_res.append(obs['lat_res']) |
| obs_lon_res.append(obs['lon_res']) |
| |
| return max(obs_lat_res), max(obs_lon_res) |
| |
| |
| def settings_screen(header): |
| '''Generates screen for settings before running evaluation. |
| |
| :param header: Header of page |
| :type header: string |
| ''' |
| |
| note = " " |
| models_start_time, models_end_time = get_models_temp_bound() |
| models_overlap_start_time, models_overlap_end_time = get_models_temp_overlap(models_start_time, models_end_time) |
| observations_start_time, observations_end_time = get_obs_temp_bound() |
| obs_overlap_start_time, obs_overlap_end_time = get_obs_temp_overlap(observations_start_time, observations_end_time) |
| all_overlap_start_time, all_overlap_end_time = get_all_temp_overlap(models_overlap_start_time, models_overlap_end_time, obs_overlap_start_time, obs_overlap_end_time) |
| models_bound = get_models_spatial_bound() |
| models_overlap_min_lat, models_overlap_max_lat, models_overlap_min_lon, models_overlap_max_lon = get_models_spatial_overlap(models_bound) |
| observations_bound = get_obs_spatial_bound() |
| obs_overlap_min_lat, obs_overlap_max_lat, obs_overlap_min_lon, obs_overlap_max_lon = get_obs_spatial_overlap(observations_bound) |
| all_overlap_min_lat, all_overlap_max_lat, all_overlap_min_lon, all_overlap_max_lon = get_all_spatial_overlap(models_overlap_min_lat, |
| models_overlap_max_lat, |
| models_overlap_min_lon, |
| models_overlap_max_lon, |
| obs_overlap_min_lat, |
| obs_overlap_max_lat, |
| obs_overlap_min_lon, |
| obs_overlap_max_lon) |
| model_temp_res = get_models_temp_res() |
| obs_temp_res = get_obs_temp_res() |
| model_lat_res, model_lon_res = get_models_spatial_res() |
| obs_lat_res, obs_lon_res = get_obs_spatial_res() |
| |
| temp_grid_option = "Observation" |
| temp_grid_setting = obs_temp_res |
| spatial_grid_option = "Observation" |
| spatial_grid_setting_lat = obs_lat_res |
| spatial_grid_setting_lon = obs_lon_res |
| models_dict = {} |
| |
| for i in enumerate(models_info): |
| models_dict['mod{0}'.format(i[0])] = models_info[i[0]] |
| obs_dict = {} |
| for i in enumerate(observations_info): |
| obs_dict['obs{0}'.format(i[0])] = observations_info[i[0]] |
| |
| reference_dataset = 'obs0' |
| target_datasets = [] |
| for i in range(len(model_datasets)): |
| target_datasets.append('mod{0}'.format(i)) |
| subregion_path = None |
| metrics_dict = {'1':'bias_of_multiyear_climatology'} |
| metric = 'bias_of_multiyear_climatology' |
| plots = {'bias_of_multiyear_climatology':"contour map"} |
| working_directory = os.getcwd() + "/plots/" #Default value of working directory set to "plots" folder in current directory |
| plot_title = '' #TODO: ask user about plot title or figure out automatically |
| |
| fix_min_time = all_overlap_start_time |
| fix_max_time = all_overlap_end_time |
| fix_min_lat = all_overlap_min_lat |
| fix_max_lat = all_overlap_max_lat |
| fix_min_lon = all_overlap_min_lon |
| fix_max_lon = all_overlap_max_lon |
| |
| option = '' |
| while option != '0': |
| y, x = ready_screen("settings_screen", note) |
| screen.addstr(1, 1, header) |
| screen.addstr(3, 1, "INFORMATION") |
| screen.addstr(4, 1, "===========") |
| screen.addstr(6, 2, "Number of model file: {0}".format(str(len(model_datasets)))) |
| screen.addstr(7, 2, "Number of observation: {0}".format(str(len(observations_info)))) |
| screen.addstr(8, 2, "Temporal Boundaries:") |
| screen.addstr(9, 5, "Start time = {0}".format(all_overlap_start_time)) |
| screen.addstr(10, 5, "End time = {0}".format(all_overlap_end_time)) |
| screen.addstr(11, 2, "Spatial Boundaries:") |
| screen.addstr(12, 5, "min-lat = {0}".format(all_overlap_min_lat)) |
| screen.addstr(13, 5, "max-lat = {0}".format(all_overlap_max_lat)) |
| screen.addstr(14, 5, "min-lon = {0}".format(all_overlap_min_lon)) |
| screen.addstr(15, 5, "max-lon = {0}".format(all_overlap_max_lon)) |
| screen.addstr(16, 2, "Temporal Resolution:") |
| screen.addstr(17, 5, "Model = {0}".format(model_temp_res)) |
| screen.addstr(18, 5, "Observation = {0}".format(obs_temp_res)) |
| screen.addstr(19, 2, "Spatial Resolution:") |
| screen.addstr(20, 5, "Model:") |
| screen.addstr(21, 10, "lat = {0}".format(model_lat_res)) |
| screen.addstr(22, 10, "lon = {0}".format(model_lon_res)) |
| screen.addstr(23, 5, "Observation:") |
| screen.addstr(24, 10, "lat = {0}".format(obs_lat_res)) |
| screen.addstr(25, 10, "lon = {0}".format(obs_lon_res)) |
| screen.addstr(26, 2, "Temporal Grid Option: {0}".format(temp_grid_option)) |
| screen.addstr(27, 2, "Spatial Grid Option: {0}".format(spatial_grid_option)) |
| screen.addstr(28, 2, "Reference Dataset: {0}".format(reference_dataset)) |
| screen.addstr(29, 2, "Target Dataset/s: {0}".format([mod for mod in target_datasets])) |
| screen.addstr(30, 2, "Working Directory:") |
| screen.addstr(31, 5, "{0}".format(working_directory)) |
| screen.addstr(32, 2, "Metric: {0}".format(metric)) |
| screen.addstr(33, 2, "Plot: {0}".format(plots[metric])) |
| |
| screen.addstr(3, x/2, "MODIFICATION and RUN") |
| screen.addstr(4, x/2, "====================") |
| screen.addstr(6, x/2, "1 - Change Temporal Boundaries") |
| screen.addstr(7, x/2, "2 - Change Spatial Boundaries") |
| screen.addstr(8, x/2, "3 - Change Temporal Gridding") |
| screen.addstr(9, x/2, "4 - Change Spatial Gridding") |
| screen.addstr(10, x/2, "5 - Change Reference dataset") |
| screen.addstr(11, x/2, "6 - Change Target dataset/s") |
| screen.addstr(12, x/2, "7 - Change Metric") |
| screen.addstr(13, x/2, "8 - Change Working Directory") |
| screen.addstr(14, x/2, "9 - Show Temporal Boundaries") |
| screen.addstr(15, x/2, "10 - Show Spatial Boundaries") |
| screen.addstr(16, x/2, "0 - Return to Main Menu") |
| screen.addstr(18, x/2, "r - Run Evaluation") |
| screen.addstr(20, x/2, "Select an option: ") |
| |
| screen.refresh() |
| option = screen.getstr() |
| |
| if option == '1': |
| screen.addstr(25, x/2, "Enter Start Time [min time:{0}](Format YYYY-MM-DD)".format(fix_min_time)) |
| screen.addstr(26, x/2, ":") |
| new_start_time = screen.getstr() |
| try: |
| new_start_time = datetime.strptime(new_start_time, '%Y-%m-%d') |
| if new_start_time < fix_min_time \ |
| or new_start_time > fix_max_time \ |
| or new_start_time > all_overlap_end_time: |
| note = "Start time has not changed. " |
| else: |
| all_overlap_start_time = new_start_time |
| note = "Start time has changed successfully. " |
| except: |
| note = "Start time has not changed. " |
| screen.addstr(27, x/2, "Enter End Time [max time:{0}](Format YYYY-MM-DD)".format(fix_max_time)) |
| screen.addstr(28, x/2, ":") |
| new_end_time = screen.getstr() |
| try: |
| new_end_time = datetime.strptime(new_end_time, '%Y-%m-%d') |
| if new_end_time > fix_max_time \ |
| or new_end_time < fix_min_time \ |
| or new_end_time < all_overlap_start_time: |
| note = note + " End time has not changed. " |
| else: |
| all_overlap_end_time = new_end_time |
| note = note + " End time has changed successfully. " |
| except: |
| note = note + " End time has not changed. " |
| |
| if option == '2': |
| screen.addstr(25, x/2, "Enter Minimum Latitude [{0}]:".format(fix_min_lat)) |
| new_min_lat = screen.getstr() |
| try: |
| new_min_lat = float(new_min_lat) |
| if new_min_lat < fix_min_lat or new_min_lat > fix_max_lat or new_min_lat > all_overlap_max_lat: |
| note = "Minimum latitude has not changed. " |
| else: |
| all_overlap_min_lat = new_min_lat |
| note = "Minimum latitude has changed successfully. " |
| except: |
| note = "Minimum latitude has not changed. " |
| screen.addstr(26, x/2, "Enter Maximum Latitude [{0}]:".format(fix_max_lat)) |
| new_max_lat = screen.getstr() |
| try: |
| new_max_lat = float(new_max_lat) |
| if new_max_lat > fix_max_lat or new_max_lat < fix_min_lat or new_max_lat < all_overlap_min_lat: |
| note = note + " Maximum latitude has not changed. " |
| else: |
| all_overlap_max_lat = new_max_lat |
| note = note + "Maximum latitude has changed successfully. " |
| except: |
| note = note + " Maximum latitude has not changed. " |
| screen.addstr(27, x/2, "Enter Minimum Longitude [{0}]:".format(fix_min_lon)) |
| new_min_lon = screen.getstr() |
| try: |
| new_min_lon = float(new_min_lon) |
| if new_min_lon < fix_min_lon or new_min_lon > fix_max_lon or new_min_lon > all_overlap_max_lon: |
| note = note + " Minimum longitude has not changed. " |
| else: |
| all_overlap_min_lon = new_min_lon |
| note = note + "Minimum longitude has changed successfully. " |
| except: |
| note = note + " Minimum longitude has not changed. " |
| screen.addstr(28, x/2, "Enter Maximum Longitude [{0}]:".format(fix_max_lon)) |
| new_max_lon = screen.getstr() |
| try: |
| new_max_lon = float(new_max_lon) |
| if new_max_lon > fix_max_lon or new_max_lon < fix_min_lon or new_max_lon < all_overlap_min_lon: |
| note = note + " Maximum longitude has not changed. " |
| else: |
| all_overlap_max_lon = new_max_lon |
| note = note + "Maximum longitude has changed successfully. " |
| except: |
| note = note + " Maximum longitude has not changed. " |
| |
| if option == '3': |
| screen.addstr(25, x/2, "Enter Temporal Gridding Option [Model or Observation]:") |
| new_temp_grid_option = screen.getstr() |
| if new_temp_grid_option.lower() == 'model': |
| temp_grid_option = 'Model' |
| temp_grid_setting = model_temp_res |
| note = "Temporal gridding option has changed successfully to {0}".format(temp_grid_option) |
| elif new_temp_grid_option.lower() == 'observation': |
| temp_grid_option = 'Observation' |
| temp_grid_setting = obs_temp_res |
| note = "Temporal gridding option has changed successfully to {0}".format(temp_grid_option) |
| else: |
| note = "Temporal gridding option has not changed." |
| |
| if option == '4': |
| screen.addstr(25, x/2, "Enter Spatial Gridding Option [Model, Observation or User]:") |
| new_spatial_grid_option = screen.getstr() |
| if new_spatial_grid_option.lower() == 'model': |
| spatial_grid_option = 'Model' |
| spatial_grid_setting_lat = model_lat_res |
| spatial_grid_setting_lon = model_lon_res |
| note = "Spatial gridding option has changed successfully to {0}".format(spatial_grid_option) |
| elif new_spatial_grid_option.lower() == 'observation': |
| spatial_grid_option = 'Observation' |
| spatial_grid_setting_lat = obs_lat_res |
| spatial_grid_setting_lon = obs_lon_res |
| note = "Spatial gridding option has changed successfully to {0}".format(spatial_grid_option) |
| elif new_spatial_grid_option.lower() == 'user': |
| screen.addstr(26, x/2, "Please enter latitude spatial resolution: ") |
| user_lat_res = screen.getstr() |
| screen.addstr(27, x/2, "Please enter longitude spatial resolution: ") |
| user_lon_res = screen.getstr() |
| try: |
| user_lat_res = float(user_lat_res) |
| user_lon_res = float(user_lon_res) |
| spatial_grid_option = 'User: resolution lat:{0}, lon:{1}'.format(str(user_lat_res), str(user_lon_res)) |
| spatial_grid_setting_lat = user_lat_res |
| spatial_grid_setting_lon = user_lon_res |
| note = "Spatial gridding option has changed successfully to user defined." |
| except: |
| note = "Spatial gridding option has not changed." |
| else: |
| note = "Spatial gridding option has not changed." |
| |
| if option == '5': |
| screen.addstr(25, x/2, "Model/s:") |
| for each in enumerate(models_dict): |
| screen.addstr(26 + each[0], x/2 + 2, "{0}: {1}".format(each[1], models_dict[each[1]]['directory'].split("/")[-1])) |
| screen.addstr(26 + len(models_dict), x/2, "Observation/s:") |
| for each in enumerate(obs_dict): |
| screen.addstr(27 + len(models_dict) + each[0], x/2 + 2, "{0}: {1} - ({2})".format(each[1], obs_dict[each[1]]['database'], obs_dict[each[1]]['unit'])) |
| screen.addstr(27 + len(obs_dict) + len(models_dict), x/2, "Please select reference dataset:") |
| selected_reference = screen.getstr() |
| if selected_reference in models_dict: |
| reference_dataset = selected_reference |
| note = "Reference dataset successfully changed." |
| elif selected_reference in obs_dict: |
| reference_dataset = selected_reference |
| note = "Reference dataset successfully changed." |
| else: |
| note = "Reference dataset did not change." |
| |
| if option == '6': |
| screen.addstr(25, x/2, "Model/s:") |
| for each in enumerate(models_dict): |
| screen.addstr(26 + each[0], x/2 + 2, "{0}: {1}".format(each[1], models_dict[each[1]]['directory'].split("/")[-1])) |
| screen.addstr(26 + len(models_dict), x/2, "Observation/s:") |
| for each in enumerate(obs_dict): |
| screen.addstr(27 + len(models_dict) + each[0], x/2 + 2, "{0}: {1} - ({2})".format(each[1], obs_dict[each[1]]['database'], obs_dict[each[1]]['unit'])) |
| screen.addstr(27 + len(obs_dict) + len(models_dict), x/2, "Please enter target dataset/s (comma separated for multi target):") |
| selected_target = screen.getstr() |
| selected_target = selected_target.split(",") |
| if selected_target != ['']: |
| target_datasets = [] |
| for target in selected_target: |
| if target in models_dict: |
| target_datasets.append(target) |
| note = "Target dataset successfully changed." |
| elif target in obs_dict: |
| target_datasets.append(target) |
| note = "Target dataset successfully changed." |
| else: |
| note = "Target dataset did not change." |
| |
| if option == '7': |
| screen.addstr(25, x/2, "Available metrics:") |
| for i in enumerate(sorted(metrics_dict, key=metrics_dict.get)): |
| screen.addstr(26 + i[0], x/2 + 2, "[{0}] - {1}".format(i[1], metrics_dict[i[1]])) |
| screen.addstr(26 + len(metrics_dict), x/2, "Please select a metric:") |
| metric_id = screen.getstr() |
| if metric_id in metrics_dict: |
| metric = metrics_dict[metric_id] |
| note = "Metric sucessfully changed to {0}".format(metric) |
| else: |
| note = "Metric has not changes" |
| |
| if option == '8': |
| screen.addstr(25, x/2, "Please enter working directory path:") |
| working_directory = screen.getstr() |
| if working_directory: |
| if working_directory[-1] != '/': |
| working_directory = working_directory + "/" |
| else: |
| note = "Working directory has not changed" |
| |
| if option == '9': |
| models_start_time, models_end_time = get_models_temp_bound() |
| line = 25 |
| for i, model in enumerate(model_datasets): |
| #mode_name = models_info[i]['directory'].split("/")[-1] |
| mode_name = 'model %d' %(i+1) |
| line += 1 |
| screen.addstr(line, x/2, "{0}".format(mode_name)) |
| line += 1 |
| screen.addstr(line, x/2 + 3, "Start:{0} - End:{1}".format(models_start_time[i], models_end_time[i])) |
| |
| observations_start_time, observations_end_time = get_obs_temp_bound() |
| for i, obs in enumerate(observations_info): |
| line += 1 |
| screen.addstr(line, x/2, "{0}".format(observations_info[i]['database'])) |
| line += 1 |
| screen.addstr(line, x/2 + 3, "Start:{0} - End:{1}".format(observations_start_time[i], observations_end_time[i])) |
| screen.getstr() |
| |
| if option == '10': |
| models_bound = get_models_spatial_bound() |
| line = 25 |
| for i, model in enumerate(model_datasets): |
| #mode_name = models_info[i]['directory'].split("/")[-1] |
| mode_name = 'model %d' %(i+1) |
| line += 1 |
| screen.addstr(line, x/2, "{0}".format(mode_name)) |
| line += 1 |
| screen.addstr(line, x/2 + 3, "{0}".format(models_bound[i])) |
| |
| observations_bound = get_obs_spatial_bound() |
| for i, obs in enumerate(observations_info): |
| line += 1 |
| screen.addstr(line, x/2, "{0}".format(observations_info[i]['database'])) |
| line += 1 |
| screen.addstr(line, x/2 + 3, "{0}".format(observations_bound[i])) |
| screen.getstr() |
| |
| if option.lower() == 'r': |
| note = run_screen(model_datasets, models_info, observations_info, all_overlap_start_time, all_overlap_end_time, \ |
| all_overlap_min_lat, all_overlap_max_lat, all_overlap_min_lon, all_overlap_max_lon, \ |
| temp_grid_setting, spatial_grid_option, spatial_grid_setting_lat, spatial_grid_setting_lon, reference_dataset, target_datasets, metric, working_directory, plot_title) |
| |
| |
| ############################################################## |
| # Main Menu Screen |
| ############################################################## |
| |
| def main_menu(model_datasets, models_info, observation_datasets, observations_info, note=""): |
| '''This function Generates main menu page. |
| |
| :param model_datasets: list of model dataset objects |
| :type model_datasets: list |
| :param models_info: list of dictionaries that contain information for each model |
| :type models_info: list |
| :param observation_datasets: list of observation dataset objects |
| :type observation_datasets: list |
| :param observations_info: list of dictionaries that contain information for each observation |
| :type observations_info: list |
| ''' |
| |
| option = '' |
| while option != '0': |
| ready_screen("main_menu", note) |
| model_status = "NC" if len(model_datasets) == 0 else "C" #NC (Not Complete), if there is no model added, C (Complete) if model is added |
| obs_status = "NC" if len(observations_info) == 0 else "C" #NC (Not Complete), if there is no observation added, C (Complete) if observation is added |
| screen.addstr(1, 1, "Main Menu:") |
| screen.addstr(4, 4, "1 - Manage Model ({0})".format(model_status)) |
| screen.addstr(6, 4, "2 - Manage Observation ({0})".format(obs_status)) |
| screen.addstr(8, 4, "3 - Run") |
| screen.addstr(10, 4, "0 - EXIT") |
| screen.addstr(16, 2, "Select an option: ") |
| screen.refresh() |
| option = screen.getstr() |
| |
| if option == '1': |
| header = "Main Menu > Manage Model" |
| manage_model_screen(header) |
| if option == '2': |
| header = "Main Menu > Manage Observation" |
| manage_obs_screen(header) |
| if option == '3': |
| if model_status == 'NC' or obs_status == 'NC': |
| main_menu(model_datasets, models_info, observation_datasets, observations_info, note="WARNING: Please complete step 1 and 2 before 3.") |
| else: |
| header = "Main Menu > Run" |
| settings_screen(header) |
| curses.endwin() |
| sys.exit() |
| |
| |
| if __name__ == '__main__': |
| TITLE = "RCMES CLI" |
| ORGANIZATION = "JPL/NASA - JIFRESSE/UCLA" |
| screen = curses.initscr() |
| model_datasets = [] #list of model dataset objects |
| models_info = [] #list of dictionaries that contain information for each model |
| observation_datasets = [] #list of observation dataset objects |
| observations_info = [] #list of dictionaries that contain information for each observation |
| main_menu(model_datasets, models_info, observation_datasets, observations_info) |