| #!/usr/local/bin/python |
| # |
| # 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. |
| # |
| """ DOCSTRING""" |
| |
| # Python Standard Lib Imports |
| import argparse |
| import ConfigParser |
| import datetime |
| import glob |
| import os |
| import sys |
| |
| |
| # RCMES Imports |
| import storage.rcmed as db |
| from toolkit import do_data_prep, process, metrics |
| from utils import misc |
| from classes import JobProperties, Model, GridBox |
| from cli import rcmet_ui as ui |
| |
| parser = argparse.ArgumentParser(description='Regional Climate Model Evaluation Toolkit. Use -h for help and options') |
| parser.add_argument('-c', '--config', dest='CONFIG', help='Path to an evaluation configuration file') |
| args = parser.parse_args() |
| |
| def checkConfigSettings(config): |
| """ This function will check the SETTINGS block of the user supplied config file. |
| This will only check if the working and cache dirs are writable from this program. |
| Additional configuration parameters can be checked here later on. |
| |
| Input:: |
| config - ConfigParser configuration object |
| |
| Output:: |
| none - An exception will be raised if something goes wrong |
| """ |
| settings = config.items('SETTINGS') |
| for key_val in settings: |
| # Check the user provided directories are valid |
| if key_val[0] == 'workDir' or key_val[0] == 'cacheDir': |
| _ = misc.isDirGood(os.path.abspath(key_val[1])) |
| |
| else: |
| pass |
| |
| def setSettings(settings, config): |
| """ |
| This function is used to set the values within the 'SETTINGS' dictionary when a user provides an external |
| configuration file. |
| |
| Input:: |
| settings - Python Dictionary object that will collect the key : value pairs |
| config - A configparse object that contains the external config values |
| |
| Output:: |
| None - The settings dictionary will be updated in place. |
| """ |
| pass |
| |
| def generateModels(modelConfig): |
| """ |
| This function will return a list of Model objects that can easily be used for |
| metric computation and other processing tasks. |
| |
| Input:: |
| modelConfig - list of ('key', 'value') tuples. Below is a list of valid keys |
| filenamepattern - string i.e. '/nas/run/model/output/MOD*precip*.nc' |
| latvariable - string i.e. 'latitude' |
| lonvariable - string i.e. 'longitude' |
| timevariable - string i.e. 't' |
| timestep - string 'monthly' | 'daily' | 'annual' |
| varname - string i.e. 'pr' |
| |
| Output:: |
| modelList - List of Model objects |
| """ |
| # Setup the config Data Dictionary to make parsing easier later |
| configData = {} |
| for entry in modelConfig: |
| configData[entry[0]] = entry[1] |
| |
| modelFileList = None |
| for keyValTuple in modelConfig: |
| if keyValTuple[0] == 'filenamePattern': |
| modelFileList = glob.glob(keyValTuple[1]) |
| modelFileList.sort() |
| |
| # Remove the filenamePattern from the dict since it is no longer used |
| configData.pop('filenamePattern') |
| |
| models = [] |
| for modelFile in modelFileList: |
| # use getModelTimes(modelFile,timeVarName) to generate the modelTimeStep and time list |
| _ , configData['timeStep'] = process.getModelTimes(modelFile, configData['timeVariable']) |
| configData['filename'] = modelFile |
| model = Model(**configData) |
| models.append(model) |
| |
| return models |
| |
| def generateSettings(config): |
| """ |
| Helper function to decouple the argument parsing from the Settings object creation |
| |
| Input:: |
| config - list of ('key', 'value') tuples. |
| workdir - string i.e. '/nas/run/rcmet/work/' |
| cachedir - string i.e. '/tmp/rcmet/cache/' |
| Output:: |
| JobProperties - JobProperties Object |
| """ |
| # Setup the config Data Dictionary to make parsing easier later |
| configData = {} |
| for entry in config: |
| configData[entry[0]] = entry[1] |
| |
| return JobProperties(**configData) |
| |
| def makeDatasetsDictionary(rcmedConfig): |
| """ |
| Helper function to decouple the argument parsing from the RCMEDDataset object creation |
| |
| Input:: |
| rcmedConfig - list of ('key', 'value') tuples. |
| obsDatasetId=3,10 |
| obsParamId=36,32 |
| obsTimeStep=monthly,monthly |
| |
| Output:: |
| datasetDict - Dictionary with dataset metadata |
| # Setup the config Data Dictionary to make parsing easier later |
| """ |
| delimiter = ',' |
| configData = {} |
| for entry in rcmedConfig: |
| if delimiter in entry[1]: |
| # print 'delim found - %s' % entry[1] |
| valueList = entry[1].split(delimiter) |
| configData[entry[0]] = valueList |
| else: |
| configData[entry[0]] = entry[1:] |
| |
| return configData |
| |
| def tempGetYears(): |
| startYear = int(raw_input('Enter start year YYYY \n')) |
| endYear = int(raw_input('Enter end year YYYY \n')) |
| # CGOODALE - Updating the Static endTime to be 31-DEC |
| startTime = datetime.datetime(startYear, 1, 1, 0, 0) |
| endTime = datetime.datetime(endYear, 12, 31, 0, 0) |
| return (startTime, endTime) |
| |
| |
| def runUsingConfig(argsConfig): |
| """ |
| This function is called when a user provides a configuration file to specify an evaluation job. |
| |
| Input:: |
| argsConfig - Path to a ConfigParser compliant file |
| |
| Output:: |
| Plots that visualize the evaluation job. These will be output to SETTINGS.workDir from the config file |
| """ |
| |
| print 'Running using config file: %s' % argsConfig |
| # Parse the Config file |
| userConfig = ConfigParser.SafeConfigParser() |
| userConfig.optionxform = str # This is so the case is preserved on the items in the config file |
| userConfig.read(argsConfig) |
| |
| try: |
| checkConfigSettings(userConfig) |
| except: |
| raise |
| |
| jobProperties = generateSettings(userConfig.items('SETTINGS')) |
| workdir = jobProperties.workDir |
| |
| try: |
| gridBox = GridBox(jobProperties.latMin, jobProperties.lonMin, jobProperties.latMax, |
| jobProperties.lonMax, jobProperties.gridLonStep, jobProperties.gridLatStep) |
| except: |
| gridBox = None |
| |
| models = generateModels(userConfig.items('MODEL')) |
| |
| datasetDict = makeDatasetsDictionary(userConfig.items('RCMED')) |
| |
| |
| # Go get the parameter listing from the database |
| try: |
| params = db.getParams() |
| except: |
| raise |
| |
| obsDatasetList = [] |
| for param_id in datasetDict['obsParamId']: |
| for param in params: |
| if param['parameter_id'] == int(param_id): |
| obsDatasetList.append(param) |
| else: |
| pass |
| |
| #TODO: Unhardcode this when we decided where this belongs in the Config File |
| jobProperties.maskOption = True |
| # User must provide startTime and endTime if not defined |
| if jobProperties.startDate == None or jobProperties.endDate == None: |
| jobProperties.startDate, jobProperties.endDate = misc.userDefinedStartEndTimes(obsDatasetList, models) |
| |
| numOBS, numMDL, nT, ngrdY, ngrdX, Times, lons, lats, obsData, mdlData, obsList, mdlName = do_data_prep.prep_data(jobProperties, obsDatasetList, gridBox, models) |
| |
| print 'Input and regridding of both obs and model data are completed. now move to metrics calculations' |
| |
| try: |
| subRegionConfig = misc.configToDict(userConfig.items('SUB_REGION')) |
| subRegions = misc.parseSubRegions(subRegionConfig) |
| # REORDER SUBREGION OBJECTS until we standardize on Python 2.7 |
| # TODO Remove once Python 2.7 support is finalized |
| if subRegions: |
| subRegions.sort(key=lambda x:x.name) |
| |
| except ConfigParser.NoSectionError: |
| |
| counts = {'observations': numOBS, |
| 'models' : numMDL, |
| 'times' : nT} |
| subRegions = misc.getSubRegionsInteractively(counts, workdir) |
| |
| if len(subRegions) == 0: |
| print 'Processing without SubRegion support' |
| |
| |
| # TODO: New function Call |
| fileOutputOption = jobProperties.writeOutFile |
| modelVarName = models[0].varName |
| metrics.metrics_plots(modelVarName, numOBS, numMDL, nT, ngrdY, ngrdX, Times, lons, lats, obsData, mdlData, obsList, mdlName, workdir, subRegions, fileOutputOption) |
| |
| |
| if __name__ == "__main__": |
| |
| if args.CONFIG: |
| |
| runUsingConfig(args.CONFIG) |
| |
| else: |
| print 'Interactive mode has been enabled' |
| ui.rcmetUI() |
| |
| #rcmet_cordexAF() |