diff --git a/doc/Screenshot.png b/doc/Screenshot.png
new file mode 100644
index 00000000..3300f400
Binary files /dev/null and b/doc/Screenshot.png differ
diff --git a/doc/User's_Guide.pdf b/doc/User's_Guide.pdf
new file mode 100644
index 00000000..70ea6e28
Binary files /dev/null and b/doc/User's_Guide.pdf differ
diff --git a/examples/run_calibration.sh b/examples/run_calibration.sh
new file mode 100755
index 00000000..7c2ab26c
--- /dev/null
+++ b/examples/run_calibration.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+# ------------------------------------------------
+# This script automates the entire calibration process
+# from generating input to executing calibration and validation runs.
+# User needs to specify basin, workdir and usrdir.
+#
+# Author: Xia Feng
+# ------------------------------------------------
+
+# Activate virtual environment
+source venv/bin/activate
+python=`which python3`
+
+# Working Directory
+basin='01010101'
+workdir='usrdir/working_dir/'$basin
+
+# Create input data and files
+pyscript1='usrdir/NextGen_Model_Calibration/python/createInput/examples/create_input.py'
+config_file_input='usrdir/NextGen_Model_Calibration/python/createInput/examples/config/input.config'
+echo 'Creating Input Data and Files'
+$python $pyscript1 $config_file_input
+echo 'Input Data and Files are Generated'
+
+# Execute calibration run
+pyscript2='usrdir/NextGen_Model_Calibration/python/runCalibValid/calibration.py'
+config_file_calib=$workdir$'/Input/'$basin'_config_calib.yaml'
+echo 'Running Calibration Simulation'
+$python $pyscript2 $config_file_calib >>'calib_run_out'
+echo 'Calibration Run Is Completed'
+
+# Execute validation run
+pyscript3='usrdir/NextGen_Model_Calibration/python/runCalibValid/validation.py'
+config_file_control=$workdir'/Output/Validation_Run/'$basin'_config_valid_control.yaml'
+config_file_best=$workdir'/Output/Validation_Run/'$basin'_config_valid_best.yaml'
+config_file_valid_run=( $config_file_control $config_file_best )
+run_type=( 'control' 'best' )
+i=0
+while [ $i -le 1 ]
+do
+ echo 'Running Validation' ${run_type[$i]^} 'Simulation'
+ $python $pyscript3 ${config_file_valid_run[$i]} >>'valid_run_out'
+ i=$(($i+1))
+done
+echo 'Validation Run Is Completed'
diff --git a/python/createInput/CHANGELOG.md b/python/createInput/CHANGELOG.md
new file mode 100644
index 00000000..e47878c8
--- /dev/null
+++ b/python/createInput/CHANGELOG.md
@@ -0,0 +1,21 @@
+All notable changes to this project will be documented in this file.
+We follow the [Semantic Versioning 2.0.0](http://semver.org/) format.
+
+
+## x.y.z - YYYY-MM-DD
+
+### Added
+
+- Lorem ipsum dolor sit amet
+
+### Deprecated
+
+- Nothing.
+
+### Removed
+
+- Nothing.
+
+### Fixed
+
+- Nothing.
diff --git a/python/createInput/CONTRIBUTING.md b/python/createInput/CONTRIBUTING.md
new file mode 100644
index 00000000..0f109b26
--- /dev/null
+++ b/python/createInput/CONTRIBUTING.md
@@ -0,0 +1,32 @@
+# Guidance on how to contribute
+
+> All contributions to this project will be released to the public domain.
+> By submitting a pull request or filing a bug, issue, or
+> feature request, you are agreeing to comply with this waiver of copyright interest.
+> Details can be found in our [TERMS](TERMS.md) and [LICENSE](LICENSE).
+
+
+There are two primary ways to help:
+ - Using the issue tracker, and
+ - Changing the code-base.
+
+
+## Using the issue tracker
+
+Use the issue tracker to suggest feature requests, report bugs, and ask questions.
+This is also a great way to connect with the developers of the project as well
+as others who are interested in this solution.
+
+Use the issue tracker to find ways to contribute. Find a bug or a feature, mention in
+the issue that you will take on that effort, then follow the _Changing the code-base_
+guidance below.
+
+
+## Changing the code-base
+
+Generally speaking, you should fork this repository, make changes in your
+own fork, and then submit a pull request. All new code should have associated
+unit tests that validate implemented features and the presence or lack of defects.
+Additionally, the code should follow any stylistic and architectural guidelines
+prescribed by the project. In the absence of such guidelines, mimic the styles
+and patterns in the existing code-base.
diff --git a/python/createInput/INSTALL.md b/python/createInput/INSTALL.md
new file mode 100644
index 00000000..4c199e6d
--- /dev/null
+++ b/python/createInput/INSTALL.md
@@ -0,0 +1,3 @@
+# Installation instructions
+
+Detailed instructions on how to install, configure, and get the project running.
diff --git a/python/createInput/LICENSE b/python/createInput/LICENSE
new file mode 100644
index 00000000..a0230332
--- /dev/null
+++ b/python/createInput/LICENSE
@@ -0,0 +1,7 @@
+“Software code created by U.S. Government employees is not subject to copyright
+in the United States (17 U.S.C. §105). The United States/Department of Commerce
+reserve all rights to seek and obtain copyright protection in countries other
+than the United States for Software authored in its entirety by the Department
+of Commerce. To this end, the Department of Commerce hereby grants to Recipient
+a royalty-free, nonexclusive license to use, copy, and create derivative works
+of the Software outside of the United States.”
diff --git a/python/createInput/README.md b/python/createInput/README.md
new file mode 100644
index 00000000..643ded7e
--- /dev/null
+++ b/python/createInput/README.md
@@ -0,0 +1,11 @@
+## CreateInput
+
+ CreateInput is a Python package to generate all the necessary data and files needed for performing the model parameter calibration and validation in the NextGen modeling framework.
+
+## Files in this Subpackage
+- ___Examples_ Directory__
+ - _create_input.py_: Main script to read master configuration file _input.config_ and call functions in _ginputfunc.py_ to generate the required input data and files.
+ - _config/input.config_: This input configuration file contains all kinds of options related to the basin, calibration settings, hydrofabric file, forcing data, and formulation libraries, etc.
+- ___src_ Directory__
+ - _ginputfunc.py_: Contians various funcitons to create crosswalk file, generate or process BMI initial configuration files, as well as create t-route configuration file, main realization file, and calibration configuration file.
+ - _noaa_owp.py_: Contains function to generate BMI initial configuraiton for Noah-OWP-Modular model.
diff --git a/python/createInput/SECURITY.md b/python/createInput/SECURITY.md
new file mode 100644
index 00000000..0cdd1d99
--- /dev/null
+++ b/python/createInput/SECURITY.md
@@ -0,0 +1,27 @@
+# Security Policy
+
+There MUST be no unpatched vulnerabilities of medium or higher severity that have been publicly known for more than 60 days.
+
+The vulnerability must be patched and released by the project itself (patches may be developed elsewhere). A vulnerability becomes publicly known (for this purpose) once it has a CVE with publicly released non-paywalled information (reported, for example, in the National Vulnerability Database) or when the project has been informed and the information has been released to the public (possibly by the project). A vulnerability is considered medium or higher severity if its Common Vulnerability Scoring System (CVSS) base qualitative score is medium or higher. In CVSS versions 2.0 through 3.1, this is equivalent to a CVSS score of 4.0 or higher. Projects may use the CVSS score as published in a widely-used vulnerability database (such as the National Vulnerability Database) using the most-recent version of CVSS reported in that database. Projects may instead calculate the severity themselves using the latest version of CVSS at the time of the vulnerability disclosure, if the calculation inputs are publicly revealed once the vulnerability is publicly known. Note: this means that users might be left vulnerable to all attackers worldwide for up to 60 days. This criterion is often much easier to meet than what Google recommends in Rebooting responsible disclosure, because Google recommends that the 60-day period start when the project is notified _even_ if the report is not public. Also note that this badge criterion, like other criteria, applies to the individual project. Some projects are part of larger umbrella organizations or larger projects, possibly in multiple layers, and many projects feed their results to other organizations and projects as part of a potentially-complex supply chain. An individual project often cannot control the rest, but an individual project can work to release a vulnerability patch in a timely way. Therefore, we focus solely on the individual project's response time. Once a patch is available from the individual project, others can determine how to deal with the patch (e.g., they can update to the newer version or they can apply just the patch as a cherry-picked solution).
+
+The public repositories MUST NOT leak any valid private credential (e.g., a working password or private key) that is intended to limit public access.
+
+## Supported Versions
+
+Use this section to tell people about which versions of your project are
+currently being supported with security updates.
+
+| Version | Supported |
+| ------- | ------------------ |
+| 5.1.x | :white_check_mark: |
+| 5.0.x | :x: |
+| 4.0.x | :white_check_mark: |
+| < 4.0 | :x: |
+
+## Reporting a Vulnerability
+
+Use this section to tell people how to report a vulnerability.
+
+Tell them where to go, how often they can expect to get an update on a
+reported vulnerability, what to expect if the vulnerability is accepted or
+declined, etc.
diff --git a/python/createInput/TERMS.md b/python/createInput/TERMS.md
new file mode 100644
index 00000000..b49b176b
--- /dev/null
+++ b/python/createInput/TERMS.md
@@ -0,0 +1,19 @@
+## Disclaimer
+
+This repository is a scientific product and is not official communication of the National Oceanic and Atmospheric Administration, or the United States Department of Commerce. All NOAA GitHub project code is provided on an 'as is' basis and the user assumes responsibility for its use. Any claims against the Department of Commerce or Department of Commerce bureaus stemming from the use of this GitHub project will be governed by all applicable Federal law. Any reference to specific commercial products, processes, or services by service mark, trademark, manufacturer, or otherwise, does not constitute or imply their endorsement, recommendation or favoring by the Department of Commerce. The Department of Commerce seal and logo, or the seal and logo of a DOC bureau, shall not be used in any manner to imply endorsement of any commercial product or activity by DOC or the United States Government.
+
+[NOAA GitHub Policy](https://github.com/NOAAGov/Information)
+
+### Other Information
+
+Unless expressly stated otherwise, the person who associated a work with
+this deed makes no warranties about the work, and disclaims liability for
+all uses of the work, to the fullest extent permitted by applicable law.
+When using or citing the work, you should not imply endorsement by the
+author or the affirmer.
+
+## Exceptions
+
+_Source code or other assets that are excluded from the TERMS should be listed
+here. These may include dependencies that may be licensed differently or are
+not in the public domain._
diff --git a/python/createInput/examples/config/input.config b/python/createInput/examples/config/input.config
new file mode 100644
index 00000000..07ab304d
--- /dev/null
+++ b/python/createInput/examples/config/input.config
@@ -0,0 +1,187 @@
+# ------------------------------------------------
+# NextGen Model Calibration Configuration File
+#
+# This file is used to create the input data and
+# files to run calibration.
+# It contains three sections:
+# 1. General
+# 2. Calibration
+# 3. DataFile
+# User needs to fill out the required entries of each
+# section for the specified basin.
+#
+# @author: Xia Feng
+# ------------------------------------------------
+
+[General]
+# Stream gage ID at basin outlet
+basin = 01010101
+
+# Model and module for calibration
+model = cfe
+
+# Calibration or validation run
+run_type = calib
+
+# Main directory to store input, output and other files
+main_dir =
+
+[Calibration]
+# Optimizaition algorithm for parameter estimation
+optimization_algorithm = dds
+
+# Specify algorithm parameters for PSO and GWO only
+# Control parameters c1, c2 and w are only needed for PSO
+swarm_size = 20
+c1 = 2
+c2 = 2
+w = 0.7
+
+# Objective function
+objective_function = kge
+
+# Starting iteration number
+start_iteration = 0
+
+# Number of iterations
+number_iteration = 10
+
+# Whether restart calibration from the stopped iteration
+# 0: Not
+# 1: Yes
+# It should be 0 if start_interation entry is 0.
+restart = 0
+
+# Calibration time period
+calib_start_period = 2019-10-01 00:00:00
+calib_end_period = 2022-10-01 00:00:00
+
+# Calibration evaluation time period
+calib_eval_start_period = 2020-10-01 00:00:00
+calib_eval_end_period = 2022-10-01 00:00:00
+
+# Validation time period
+# These entries are optional.
+# If they are not specified, validation run will not be performed.
+valid_start_period = 2016-10-01 00:00:00
+valid_end_period = 2019-10-01 00:00:00
+
+# Validation evaluation time period
+# These entries are optional.
+# If validation run is not performed, there is no need to fill these two options.
+valid_eval_start_period = 2017-10-01 00:00:00
+valid_eval_end_period = 2019-10-01 00:00:00
+
+# Full evaluation time period
+# These entries are optional.
+# If validation run is not performed, there is no need to fill these two options.
+full_eval_start_period = 2016-10-01 00:00:00
+full_eval_end_period = 2022-10-01 00:00:00
+
+# Save streamflow output and plot at the specified iteration
+# These entries are optional and specified with the default values.
+# 1: Filename is distinguished by the iteration number.
+# 0: Filename is same at different iteration, i.e., overwrite file from the last iteration.
+save_plot_iter = 0
+save_output_iter = 0
+
+# Iteration interval to save plots
+# This entry is optional and specified with the default value.
+save_plot_iter_freq = 50
+
+# Streamflow threshold in cms for the calculation of categorical scores
+# This entry is optional.
+# If it is not specified, categorical metrics will not be calculated.
+streamflow_threshold =
+
+# Stream station name used for the title of plots
+# This entry is optional.
+# If it is not specified, station name will not show up in the title of plots.
+station_name =
+
+# Email address to receive the notification of run completion
+# This entry is optional.
+# If it is not specified, user will not receive email notification after run is completed.
+user_email = foo@example.com
+
+[DataFile]
+# Diretory for forcing data
+forcing_dir =
+
+# Diretory for streamflow observation
+# This entry is optional.
+# If it is not specified, observation will be downloaded on the fly during the calibration.
+obs_dir =
+
+# Diretory for hydrofabric data
+hydrofab_dir =
+
+# Diretory for CFE BMI files
+# This entry is optional.
+# If CFE is not selected, there is no need to fill this entry.
+cfe_dir =
+
+# Diretory for TOPMODEL BMI files
+# This entry is optional.
+# If TOPMODEL is not selected, there is no need to fill this entry.
+topmd_dir =
+
+# Diretory for Noah-OWP-Modular parameter table
+# This entry is optional.
+# If Noah-OWP-Modular is not selected, there is no need to fill this entry.
+noah_parameter_dir =
+
+# Path for model attributes file
+# This entry is optional.
+# If neither CFE, nor Noah-OWP-Modular, nor SFT is selected, there is no need to fill this entry.
+attributes_file =
+
+# Path for calibration parameter file
+# It contains the minimum, maximum, and initial values of parameters for the specified model
+calib_parameter_file =
+
+# Path for LASAM soil parameter file
+# This entry is optional.
+# If LASAM is not selected, there is no need to fill this entry.
+lasam_soil_parameter_file =
+
+# Path for LASAM soil class file
+# This entry is optional.
+# If LASAM is not selected, there is no need to fill this entry.
+lasam_soil_class_file =
+
+# Executable file for running ngen BMI
+ngen_exe_file =
+
+# Library file for CFE
+# This entry is optional.
+# If CFE is not selected, there is no need to fill this entry.
+cfe_lib =
+
+# Library file for SLoth
+sloth_lib =
+
+# Library file for TOPMODEL
+# This entry is optional.
+# If TOPMODEL is not selected, there is no need to fill this entry.
+topmd_lib =
+
+# Library file for Noah-OWP-Modular
+# This entry is optional.
+# If Noah-OWP-Modular is not selected, there is no need to fill this entry.
+noah_lib =
+
+# Library file for soil freeze and thaw (SFT) model
+# This entry is optional.
+# If SFT is not selected, there is no need to fill this entry.
+sft_lib =
+
+# Library file for soil moisture profiles (SMP)
+# This entry is optional.
+# If SMP is not selected, there is no need to fill this entry.
+smp_lib =
+
+# Library file for Lumped Arid and Semi-arid Model (LASAM)
+# This entry is optional.
+# If LASAM is not selected, there is no need to fill this entry.
+lasam_lib =
diff --git a/python/createInput/examples/create_input.py b/python/createInput/examples/create_input.py
new file mode 100644
index 00000000..ea7374ec
--- /dev/null
+++ b/python/createInput/examples/create_input.py
@@ -0,0 +1,225 @@
+"""
+This file reads input configuration file and creates the data and files files
+for executing calibration and validation runs for difference NextGen formulations.
+
+Example usage: python create_input.py input.config
+
+@author: Xia Feng
+"""
+
+import argparse
+import configparser
+import copy
+from datetime import timedelta
+import os
+import sys
+import shutil
+import time
+
+import geopandas as gpd
+import pandas as pd
+
+from createInput import ginputfunc as gfun
+
+def main():
+ # Create command line parser to supply input config file
+ parser = argparse.ArgumentParser()
+ parser.add_argument('input_config', nargs=1, type=str, help='input configuration file')
+ args = parser.parse_args()
+
+ # Read input config file
+ config = configparser.ConfigParser()
+ config.read(args.input_config)
+
+ # General section
+ section = 'General'
+ basin = config.get(section, 'basin')
+ model = config.get(section, 'model')
+ run_type = config.get(section, 'run_type')
+ main_dir = config.get(section, 'main_dir')
+
+ # Calibration section
+ section = 'Calibration'
+ start_iteration = config.getint(section, 'start_iteration')
+ number_iteration = config.getint(section, 'number_iteration')
+ restart = config.getint(section, 'restart')
+ objective = config.get(section, 'objective_function')
+ algorithm = config.get(section, 'optimization_algorithm')
+ swarm_size = config.getint(section, 'swarm_size')
+ c1 = config.getfloat(section, 'c1')
+ c2 = config.getfloat(section, 'c2')
+ w = config.getfloat(section, 'w')
+ save_plot_iter = config.getint(section, 'save_plot_iter')
+ save_output_iter = config.getint(section, 'save_output_iter')
+ save_plot_iter_freq = config.getint(section, 'save_plot_iter_freq')
+ calib_start_period = config.get(section, 'calib_start_period')
+ calib_end_period = config.get(section, 'calib_end_period')
+ calib_eval_start_period = config.get(section, 'calib_eval_start_period')
+ calib_eval_end_period = config.get(section, 'calib_eval_end_period')
+ valid_start_period = config.get(section, 'valid_start_period')
+ valid_end_period = config.get(section, 'valid_end_period')
+ valid_eval_start_period = config.get(section, 'valid_eval_start_period')
+ valid_eval_end_period = config.get(section, 'valid_eval_end_period')
+ full_eval_start_period = config.get(section, 'full_eval_start_period')
+ full_eval_end_period = config.get(section, 'full_eval_end_period')
+ threshold = config.get(section, 'streamflow_threshold')
+ threshold = float(threshold) if threshold else None
+ site_name = config.get(section, 'station_name')
+ user_email = config.get(section, 'user_email')
+
+ # DataFile section
+ section = 'DataFile'
+ forcing_dir = config.get(section, 'forcing_dir')
+ obsflow_dir = config.get(section, 'obs_dir')
+ hydrofab_dir = config.get(section, 'hydrofab_dir')
+ cfe_dir = config.get(section, 'cfe_dir')
+ topmd_dir = config.get(section, 'topmd_dir')
+ noah_params_dir = config.get(section, 'noah_parameter_dir')
+ attr_file = config.get(section, 'attributes_file')
+ calib_params_file = config.get(section, 'calib_parameter_file')
+ lasam_soil_param = config.get(section, 'lasam_soil_parameter_file')
+ lasam_soil_class = config.get(section, 'lasam_soil_class_file')
+ ngen_exe_file = config.get(section, 'ngen_exe_file')
+ cfe_lib = config.get(section, 'cfe_lib')
+ sloth_lib = config.get(section, 'sloth_lib')
+ topmd_lib = config.get(section, 'topmd_lib')
+ noah_lib = config.get(section, 'noah_lib')
+ sft_lib = config.get(section, 'sft_lib')
+ smp_lib = config.get(section, 'smp_lib')
+ lasam_lib = config.get(section, 'lasam_lib')
+
+ # Time period
+ time_period={"run_time_period": {"calib": [calib_start_period, calib_end_period],
+ "valid": [valid_start_period, valid_end_period]},
+ "evaluation_time_period": {"calib": [calib_eval_start_period, calib_eval_end_period],
+ "valid": [valid_eval_start_period, valid_eval_end_period],
+ "full": [full_eval_start_period, full_eval_end_period ]}}
+
+ # General settings
+ strategy = {'type': 'estimation', 'algorithm': algorithm}
+ if algorithm == 'pso':
+ strategy.update({'parameters': {'pool': swarm_size, 'particles': swarm_size, 'options': {'c1': c1, 'c2':c2, 'w':w}}})
+ if algorithm == 'gwo':
+ strategy.update({'parameters': {'pool': swarm_size, 'particles': swarm_size}})
+ general_cfg = {'strategy': strategy, 'name': run_type, 'log': True, 'workdir': None, 'yaml_file': None,
+ 'start_iteration': start_iteration, 'iterations': number_iteration, 'restart': restart}
+
+ # Library files
+ library_file = {
+ 'cfe_noah': {'cfe': cfe_lib, 'noah': noah_lib, 'sloth': sloth_lib},
+ 'topmodel_noah': {'tomodel': topmd_lib, 'noah': noah_lib, 'sloth': sloth_lib},
+ 'cfe_noah_sft': {'cfe': cfe_lib, 'noah': noah_lib, 'sft': sft_lib, 'smp': smp_lib, 'sloth': sloth_lib},
+ 'lasam_noah_sft': {'lasam': lasam_lib, 'noah': noah_lib, 'sft': sft_lib, 'smp': smp_lib, 'sloth': sloth_lib},
+ 'cfe_xaj_noah': {'cfe': cfe_lib, 'noah': noah_lib, 'sloth': sloth_lib},
+ 'cfe_xaj_noah_sft': {'cfe': cfe_lib, 'noah': noah_lib, 'sft': sft_lib, 'smp': smp_lib, 'sloth': sloth_lib},
+ }
+ lib_file = library_file[model]
+
+ # Create Input directory
+ run_dir = os.path.join(main_dir, '_'.join([objective, algorithm]))
+ work_dir = os.path.join(run_dir, model + '/' + basin)
+ input_dir = os.path.join(work_dir, 'Input/')
+ os.makedirs(input_dir, exist_ok=True)
+
+ # Extract hydrofabric files
+ gpkg_file = os.path.join(hydrofab_dir, 'gauge_'+ basin +'.gpkg')
+ catids = gpd.read_file(gpkg_file, layer='divides')['divide_id'].tolist()
+ cat_file = os.path.join(input_dir, os.path.basename(gpkg_file))
+ nexus_file = os.path.join(input_dir, os.path.basename(gpkg_file))
+ walk_file = input_dir + '{}'.format(basin) + '_crosswalk.json'
+ if not os.path.exists(cat_file):
+ os.symlink(gpkg_file, cat_file)
+ gfun.create_walk_file(basin, gpkg_file, walk_file)
+
+ # Extract forcing files
+ forcing_path = os.path.join(input_dir, 'forcing')
+ os.makedirs(forcing_path, exist_ok=True)
+ for catID in catids:
+ ffile = os.path.join(forcing_dir, catID + '.csv')
+ if not os.path.exists(os.path.join(forcing_path, os.path.basename(ffile))):
+ os.symlink(ffile, os.path.join(forcing_path, os.path.basename(ffile)))
+
+ # Extract streamflow observtion
+ if obsflow_dir:
+ obs = pd.read_csv(os.path.join(obsflow_dir, basin + '_hourly_discharge.csv'))[['dateTime','q_cms']]
+ obs = obs.rename(columns={'dateTime': 'value_date', 'q_cms': 'obs_flow'})
+ obsflow_file = input_dir + '{}'.format(basin) + '_hourly_discharge.csv'
+ obs.to_csv(obsflow_file, index=False)
+ else:
+ obsflow_file = None
+
+ # Create cfe input
+ cfe_input_dir = os.path.join(input_dir, 'cfe_input')
+ if model in ['cfe', 'cfe_noah', 'cfe_noah_sft', 'cfe_xaj_noah', 'cfe_xaj_noah_sft']:
+ gfun.create_cfe_input(catids, gpkg_file, attr_file, cfe_input_dir)
+
+ # Create noah input
+ noah_input_dir = os.path.join(input_dir, 'noah_input')
+ if model in ['cfe_noah', 'topmodel_noah', 'cfe_noah_sft', 'lasam_noah_sft', 'cfe_xaj_noah', 'cfe_xaj_noah_sft']:
+ gfun.create_noah_input(catids, time_period, gpkg_file, attr_file, noah_params_dir, noah_input_dir)
+
+ # Create sft and smp input
+ sft_dir = os.path.join(input_dir, 'sft_input')
+ smp_dir = os.path.join(input_dir, 'smp_input')
+ if model in ['cfe_noah_sft', 'lasam_noah_sft', 'cfe_xaj_noah_sft']:
+ gfun.create_sft_smp_input(catids, model, attr_file, cfe_dir, forcing_dir, sft_dir, smp_dir)
+
+ # Create lasam input
+ lasam_dir = os.path.join(input_dir, 'lasam_input')
+ if model in ['lasam_noah_sft']:
+ gfun.create_lasam_input(catids, cfe_dir, lasam_soil_param, lasam_soil_class, lasam_dir)
+
+ # Extract topmodel input
+ topmd_input_dir = os.path.join(input_dir, 'topmodel_input')
+ if model in ['topmodel', 'topmodel_noah']:
+ os.makedirs(topmd_input_dir, exist_ok=True)
+ for catID in catids:
+ run_file = os.path.join(topmd_dir, 'topmod_{}'.format(catID) + '.run')
+ params_file = os.path.join(topmd_dir, 'params_{}'.format(catID) + '.dat')
+ subcat_file = os.path.join(topmd_dir, 'subcat_{}'.format(catID) + '.dat')
+ gfun.change_topmodel_input(catID, run_file, params_file, subcat_file, topmd_input_dir)
+
+ # Create routing configuration file
+ run_configs = ['_troute_config_calib.yaml', '_troute_config_valid_control.yaml', '_troute_config_valid_best.yaml']
+ for file_name, run_name in zip(run_configs, ['calib','valid','valid']):
+ routing_config_file = os.path.join(work_dir + '/Input', '{}'.format(basin) + file_name)
+ if len(time_period['run_time_period'][run_name][0])!=0 & len(time_period['run_time_period'][run_name][0]):
+ run_range = pd.to_datetime(time_period['run_time_period'][run_name])
+ nts = len(pd.date_range(start=run_range[0], end=run_range[1], freq='5T'))-1
+ gfun.create_troute_config(gpkg_file, routing_config_file, time_period['run_time_period'][run_name][0], nts)
+
+ # Create model realization file
+ realization_file = work_dir + '/{}'.format(basin) + '_realization_config_bmi_calib.json'
+ routing_config_file = os.path.join(work_dir + '/Input', '{}'.format(basin) + run_configs[0])
+ bmi_dir = {"cfe": cfe_input_dir, "topmodel": topmd_input_dir, "noah": noah_input_dir, 'sft': sft_dir, 'smp': smp_dir, 'lasam': lasam_dir}
+ rt_dict = {"routing": {"t_route_config_file_with_path": routing_config_file}}
+ gfun.create_realization_file(work_dir, lib_file, bmi_dir, forcing_path, realization_file, model, time_period, rt_dict)
+
+ # Create calibration configuration file
+ calib_config_file = os.path.join(work_dir + '/Input', '{}'.format(basin) + '_config_calib.yaml')
+ model_dict = {'type': 'ngen', 'binary': ngen_exe_file, 'realization': realization_file, 'catchments': cat_file, 'nexus': nexus_file,
+ 'crosswalk': walk_file, 'obsflow': obsflow_file, 'strategy': 'uniform', 'params': None,
+ 'eval_params': {'objective': objective,
+ 'evaluation_start': time_period['evaluation_time_period'][run_type][0],
+ 'evaluation_stop': time_period['evaluation_time_period'][run_type][1],
+ 'valid_start_time': time_period['run_time_period']['valid'][0],
+ 'valid_end_time': time_period['run_time_period']['valid'][1],
+ 'valid_eval_start_time': time_period['evaluation_time_period']['valid'][0],
+ 'valid_eval_end_time': time_period['evaluation_time_period']['valid'][1],
+ 'full_eval_start_time': time_period['evaluation_time_period']['full'][0],
+ 'full_eval_end_time': time_period['evaluation_time_period']['full'][1],
+ 'save_output_iter': save_output_iter,
+ 'save_plot_iter': save_plot_iter,
+ 'save_plot_iter_freq': save_plot_iter_freq,
+ 'basinID': basin,
+ 'threshold': threshold,
+ 'site_name': 'USGS ' + basin + ": " + site_name,
+ 'user': user_email}}
+ general_dict = general_cfg.copy()
+ general_dict['workdir'] = work_dir
+ general_dict['yaml_file'] = calib_config_file
+ gfun.create_calib_config_file(calib_params_file, work_dir, general_dict, model_dict, calib_config_file)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/python/createInput/pyproject.toml b/python/createInput/pyproject.toml
new file mode 100644
index 00000000..ebeac06e
--- /dev/null
+++ b/python/createInput/pyproject.toml
@@ -0,0 +1,6 @@
+[build-system]
+build-backend = "setuptools.build_meta"
+requires = [
+ "setuptools>=42",
+ "wheel",
+]
\ No newline at end of file
diff --git a/python/createInput/setup.cfg b/python/createInput/setup.cfg
new file mode 100644
index 00000000..fc513a88
--- /dev/null
+++ b/python/createInput/setup.cfg
@@ -0,0 +1,51 @@
+[metadata]
+name = createInput
+version = attr: createInput._version.__version__
+author = Xia Feng
+author_email = xia.feng@noaa.gov
+description = A libray to create input data and files needed for caibrating NextGen formulations
+long_description = file: README.md
+long_description_content_type = text/markdown
+license = USDOC
+license_files = LICENSE
+url = https://github.com/Noaa-OWP/NextGen_Model_Calibration/tree/master/python/createInput
+project_urls =
+ source = https://github.com/NOAA-OWP/NextGen_Model_Calibration/python/createInput/src
+ Examples = https://github.com/NOAA-OWP/NextGen_Model_Calibration/python/createInput/examples
+keywords = hydrology, calibration
+classifiers =
+ Development Status :: 3 - Alpha
+ Intended Audience :: Education
+ Intended Audience :: Science/Research
+ License :: Free To Use But Restricted
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: 3.8
+ Programming Language :: Python :: 3.9
+ Topic :: Scientific/Engineering :: Hydrology
+ Operating System :: OS Independent
+
+[options]
+include_package_data = True
+packages = createInput
+package_dir =
+ createInput = src
+python_requires = >=3.7
+install_requires =
+ geopandas
+ matplotlib
+ pandas~=1.1.2
+ pyarrow
+ pydantic<2.0.0
+ pyyaml
+ scipy
+ tables
+ hydrotools.metrics
+ hydrotools.nwis_client
+ pyswarms
+ hypy@git+https://github.com/noaa-owp/hypy@master#egg=hypy&subdirectory=python
+ ngen.config_gen@git+https://github.com/noaa-owp/ngen-cal@master#egg=ngen_config_gen&subdirectory=python/ngen_config_gen
+ ngen.cal@git+https://github.com/noaa-owp/NextGen_Model_Calibration@master#egg=ngen_cal&subdirectory=python/runCalibValid/ngen_cal
+ ngen.config@git+https://github.com/noaa-owp/NextGen_Model_Calibration@master#egg=ngen_config&subdirectory=python/runCalibValid/ngen_conf
+
+[options.packages.find]
+where = src
diff --git a/python/createInput/src/__init__.py b/python/createInput/src/__init__.py
new file mode 100644
index 00000000..e34d8b3b
--- /dev/null
+++ b/python/createInput/src/__init__.py
@@ -0,0 +1,16 @@
+from . import ginputfunc, noaa_owp
+
+from .ginputfunc import (
+ extract_catchment_nexus_xwalk,
+ change_topmodel_input,
+ change_noah_input,
+ create_sft_smp_input,
+ create_lasam_input,
+ create_routing_config,
+ create_realization_file,
+ create_calib_config_file,
+)
+
+from ._version import __version__
+
+
diff --git a/python/createInput/src/_version.py b/python/createInput/src/_version.py
new file mode 100644
index 00000000..3dc1f76b
--- /dev/null
+++ b/python/createInput/src/_version.py
@@ -0,0 +1 @@
+__version__ = "0.1.0"
diff --git a/python/createInput/src/ginputfunc.py b/python/createInput/src/ginputfunc.py
new file mode 100644
index 00000000..7e1958ab
--- /dev/null
+++ b/python/createInput/src/ginputfunc.py
@@ -0,0 +1,867 @@
+"""
+This module contains a variety of functions to create different input files.
+
+@author: Xia Feng
+"""
+
+import copy
+import datetime
+import glob
+import json
+import os
+import re
+import sys
+import shutil
+import subprocess
+from fileinput import FileInput
+from functools import partial
+from typing import List, Union
+from pathlib import Path
+
+import geopandas as gpd
+import pandas as pd
+import yaml
+
+from createInput import NoahOWP
+from ngen.config_gen.file_writer import DefaultFileWriter
+from ngen.config_gen.generate import generate_configs
+from ngen.config_gen.hook_providers import DefaultHookProvider
+from ngen.config_gen.models.cfe import Cfe
+
+__all__ = [
+ 'create_walk_file',
+ 'create_cfe_input',
+ 'create_noah_input',
+ 'create_sft_smp_input',
+ 'create_lasam_input',
+ 'change_topmodel_input',
+ 'create_troute_config',
+ 'create_realization_file',
+ 'create_calib_config_file',
+ ]
+
+
+def create_walk_file(
+ gageID: str,
+ gpkg_file: Union[str, Path],
+ walk_file: Union[str, Path],
+)->None:
+
+ """ Create crosswalk file
+
+ Parameters
+ ----------
+ gageID : stream gage ID at the outlet of basin
+ gpkg_file : hydrofabric GeoPackage file
+ walk_file : crosswalk file
+
+ Returns
+ ----------
+ None
+
+ """
+
+ df_cat = gpd.read_file(gpkg_file, layer='divides')
+ df_cat.set_index('divide_id', inplace=True)
+ df_nexus = gpd.read_file(gpkg_file, layer='nexus')
+ df_nexus.set_index('id', inplace=True)
+ df_flowpaths = gpd.read_file(gpkg_file, layer='flowpaths')
+ df_flowpaths = df_flowpaths.sort_values('hydroseq')
+ df_flowpaths.set_index('toid', inplace=True)
+
+ gageid = []
+ cw = {}
+ for x in df_cat.index:
+ hu = df_nexus.loc[df_cat.loc[x, 'toid'], 'hl_uri']
+ if hu == 'NA' or not hu.startswith('Gages'):
+ catcw = {x: {"Gage_no": ""}}
+ elif hu.startswith('Gages'):
+ if len(hu.split(','))>1 and gageID in hu:
+ gage=gageID
+ else:
+ gage = hu.split('-')[1]
+ gageid.append(gage)
+ if gage == gageID:
+ subdf = df_flowpaths.loc[[df_cat.loc[x, 'toid']]]
+ if subdf.shape[0] == 1:
+ catcw = {x: {"Gage_no": gage}}
+ else:
+ # Select nearest one among multiple catchments draining to the gage
+ if subdf['id'][-1].replace('wb','cat') == x:
+ print(x)
+ catcw = {x: {"Gage_no": gage}}
+ else:
+ catcw = {x: {"Gage_no": ""}}
+ else:
+ catcw = {x: {"Gage_no": ""}}
+ cw.update(catcw)
+ if len(set(gageid))>1:
+ print('more than 1 gage found, please check')
+ with open(walk_file, 'w') as outfile:
+ json.dump(cw, outfile, indent=4, separators=(", ", ": "), sort_keys=False)
+
+
+def create_cfe_input(
+ catids: str,
+ gpkg_file: Union[str, Path],
+ attr_file: Union[str, Path],
+ cfe_input_dir: Union[str, Path],
+)->None:
+
+ """ Create BMI initial configuration file for CFE
+
+ Parameters
+ ----------
+ catids : catchment IDs in the basin
+ gpkg_file : hydrofabric GeoPackage file
+ attr_file : file containing model parameter attributes
+ cfe_input_dir: directory to save configuration files
+
+ Returns
+ ----------
+ None
+
+ """
+
+ os.makedirs(cfe_input_dir, exist_ok=True)
+
+ # Read hydrofabric and attribute file
+ hf: gpd.GeoDataFrame = gpd.read_file(gpkg_file, layer="divides")
+ hf_lnk_data: pd.DataFrame = pd.read_parquet(attr_file)
+ hf_lnk_data = hf_lnk_data[hf_lnk_data["divide_id"].isin(catids)]
+
+ # Generate files
+ hook_provider = DefaultHookProvider(hf=hf, hf_lnk_data=hf_lnk_data)
+ file_writer = DefaultFileWriter(cfe_input_dir)
+ generate_configs(
+ hook_providers=hook_provider,
+ hook_objects=[Cfe],
+ file_writer=file_writer,
+ )
+
+ # Change file name
+ for f in glob.glob(os.path.join(cfe_input_dir, "*ini")):
+ os.rename(f, os.path.join(os.path.dirname(f), re.split("_|\.", os.path.basename(f))[1] + "_bmi_config_cfe.txt"))
+
+
+def create_noah_input(
+ catids: str,
+ time_period: dict,
+ gpkg_file: Union[str, Path],
+ attr_file: Union[str, Path],
+ param_dir_source: Union[str, Path],
+ noah_input_dir: Union[str, Path],
+)->None:
+
+ """ Create BMI initial configuration file for Noah-OWP-Modular
+
+ Parameters
+ ----------
+ catids : catchment IDs in the basin
+ time_period : simulation and evaluation time period
+ gpkg_file : hydrofabric GeoPackage file
+ attr_file : file containing model parameter attributes
+ param_dir_source : source directory containing Noah-OWP-Modular parameter files
+ noah_input_dir: directory to save configuration files
+
+ Returns
+ ----------
+ None
+
+ """
+
+ # Create symlink for parameter directory
+ os.makedirs(noah_input_dir, exist_ok=True)
+ param_dir_symlink = os.path.join(noah_input_dir, os.path.basename(param_dir_source))
+ if not os.path.exists(param_dir_symlink):
+ os.symlink(param_dir_source, param_dir_symlink)
+
+ # Create files for the calibration and validation run
+ for run_name in ['calib','valid']:
+ # time period
+ if time_period['run_time_period'][run_name][0] and time_period['run_time_period'][run_name][1]:
+ start_time = time_period['run_time_period'][run_name][0]
+ start_time = datetime.datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S") + datetime.timedelta(hours=1)
+ start_time = start_time.strftime("%Y%m%d%H%M")
+ end_time = datetime.datetime.strptime(time_period['run_time_period'][run_name][1], "%Y-%m-%d %H:%M:%S").strftime("%Y%m%d%H%M")
+
+ # Read hydrofabric and attribute file
+ hf: gpd.GeoDataFrame = gpd.read_file(gpkg_file, layer="divides")
+ hf_lnk_data: pd.DataFrame = pd.read_parquet(attr_file)
+ hf_lnk_data = hf_lnk_data[hf_lnk_data["divide_id"].isin(catids)]
+
+ # Generate files
+ hook_provider = DefaultHookProvider(hf=hf, hf_lnk_data=hf_lnk_data)
+ file_writer = DefaultFileWriter(noah_input_dir)
+
+ noah_owp = partial(
+ NoahOWP,
+ parameter_dir=param_dir_symlink,
+ start_time=start_time,
+ end_time=end_time,
+ )
+
+ generate_configs(
+ hook_providers=hook_provider,
+ hook_objects=[noah_owp],
+ file_writer=file_writer,
+ )
+
+ # Change file name
+ for f in glob.glob(os.path.join(noah_input_dir, "*namelist")):
+ os.rename(f, os.path.join(os.path.dirname(f), re.split("_|\.", os.path.basename(f))[1] + "_" + run_name + ".input"))
+
+
+def create_sft_smp_input(
+ catids: str,
+ model: str,
+ attr_file: Union[str, Path],
+ cfe_dir: Union[str, Path],
+ forcing_dir: Union[str, Path],
+ sft_dir: Union[str, Path],
+ smp_dir: Union[str, Path],
+)->None:
+
+ """ Create BMI configuration file for soil freeze and thaw module, and soil moisture profiles
+
+ Parameters
+ ----------
+ catids : catchment IDs in the basin
+ model: model and module combination
+ attr_file : file containing model parameter attributes
+ cfe_dir : directory containing cfe bmi configuration files
+ forcing_dir : directory containing forcing files
+ sft_dir : directory for writing sft bmi configuration files
+ smp_dir : directory for writing smp bmi configuration files
+
+ Returns
+ ----------
+ None
+
+ """
+
+ os.makedirs(sft_dir, exist_ok=True)
+ os.makedirs(smp_dir, exist_ok=True)
+
+ # Read attribute file to obtain quartz
+ dfa = pd.read_parquet(attr_file)
+ dfa.set_index('divide_id', inplace=True)
+
+ # Ice fraction scheme
+ if model in ['cfe_noah_sft', 'lasam_noah_sft']:
+ icefscheme = 'Schaake'
+ elif model in ['cfe_xaj_noah_sft']:
+ icefscheme = 'Xinanjiang'
+
+ # Create bmi config files
+ for catID in catids:
+
+ # Read cfe file
+ cfe_bmi_file = os.path.join(cfe_dir, catID + '*.txt')
+ df = pd.read_table(cfe_bmi_file, delimiter='=', names=["Params","Values"], index_col=0)
+
+ # Obtain annual mean surface temperature as proxy for initial soil temperature
+ fdf = pd.read_table(os.path.join(forcing_dir, catID + '.csv'), delimiter=',')
+ mtemp = round(fdf['T2D'].mean(), 2)
+
+ # Create sft list
+ sft_lst = ['verbosity=none', 'soil_moisture_bmi=1', 'end_time=1.[d]', 'dt=1.0[h]',
+ 'soil_params.smcmax=' + df.loc['soil_params.smcmax'][0],
+ 'soil_params.b=' + df.loc['soil_params.b'][0],
+ 'soil_params.satpsi=' + df.loc['soil_params.satpsi'][0],
+ 'soil_params.quartz=' + str(dfa.loc[catID]['quartz']) +'[]',
+ 'ice_fraction_scheme=' + icefscheme, 'soil_z=0.1,0.3,1.0,2.0[m]',
+ 'soil_temperature=' + ','.join([str(mtemp)]*4) + '[K]',
+ ]
+ sft_bmi_file = os.path.join(sft_dir, catID + '_bmi_config_sft.txt')
+ with open(sft_bmi_file, "w") as f:
+ f.writelines('\n'.join(sft_lst))
+
+ # Create smp list
+ smp_lst = ['verbosity=none',
+ 'soil_params.smcmax=' + df.loc['soil_params.smcmax'][0],
+ 'soil_params.b=' + df.loc['soil_params.b'][0],
+ 'soil_params.satpsi=' + df.loc['soil_params.satpsi'][0],
+ 'soil_z=0.1,0.3,1.0,2.0[m]']
+ if model in ['cfe_noah_sft', 'cfe_xaj_noah_sft']:
+ smp_lst += ['soil_storage_model=conceptual', 'soil_storage_depth=2.0']
+ elif model in ['lasam_noah_sft']:
+ smp_lst += ['soil_storage_model=layered', 'soil_moisture_profile_option=constant', 'soil_depth_layers=2.0', 'water_table_depth=10[m]']
+ smp_bmi_file = os.path.join(smp_dir, catID + '_bmi_config_smp.txt')
+ with open(smp_bmi_file, "w") as f:
+ f.writelines('\n'.join(smp_lst))
+
+
+def create_lasam_input(
+ catids: List[str],
+ cfe_bmi_dir: Union[str, Path],
+ soil_param_file: str,
+ soil_class_file: Union[str, Path],
+ lasam_bmi_dir: Union[str, Path],
+)->None:
+
+ """ Create BMI configuration file for Lumped Arid and Semi-arid Model
+
+ Parameters
+ ----------
+ catids : catchment IDs in the basin
+ cfe_bmi_dir : directory for the cfe bmi configuration file
+ soil_param_file : soil hydraulic parameter file
+ soil_class_file : soil texture class file
+ lasam_bmi_dir : directory for the lasam bmi configuration file
+
+ Returns
+ ----------
+ None
+
+ """
+
+ os.makedirs(lasam_dir, exist_ok=True)
+
+ # Create lasam list
+ lasam_lst = ['verbosity=none',
+ 'soil_params_file=' + soil_param_file,
+ 'layer_thickness=200.0[cm]',
+ 'initial_psi=2000.0[cm]',
+ 'timestep=300[sec]',
+ 'endtime=1000[hr]',
+ 'forcing_resolution=3600[sec]',
+ 'ponded_depth_max=0[cm]',
+ 'use_closed_form_G=false',
+ 'layer_soil_type=',
+ 'max_soil_types=25',
+ 'wilting_point_psi=15495.0[cm]',
+ 'giuh_ordinates=',
+ 'sft_coupled=true',
+ 'soil_z=10,30,100.0,200.0[cm]',
+ 'calib_params=true',
+ ]
+
+ # Read soil class file
+ df_soil = pd.read_csv(soil_class_file)
+ df_soil.set_index("id", inplace=True)
+
+ # Create bmi config file
+ for catID in catids:
+ cfe_file_catID = glob.glob(os.path.join(cfe_bmi_dir, catID + '*.txt'))[0]
+ df = pd.read_table(cfe_file_catID, delimiter='=', names=["Params","Values"], index_col=0)
+ lasam_lst_catID = lasam_lst.copy()
+ lasam_lst_catID[9] = lasam_lst_catID[9] + str(df_soil.loc[catID]['category'])
+ lasam_lst_catID[12] = lasam_lst_catID[12] + df.loc['giuh_ordinates'][0]
+ lasam_bmi_file = os.path.join(lasam_bmi_dir, catID + '_bmi_config_lasam.txt')
+
+ with open(lasam_bmi_file, "w") as f:
+ f.writelines('\n'.join(lasam_lst_catID))
+
+
+def change_topmodel_input(
+ catID: str,
+ runfile: Union[str, Path],
+ paramsfile: Union[str, Path],
+ subcatfile: Union[str, Path],
+ inputDir: Union[str, Path],
+)->None:
+
+ """ change options in TOPMODEL input file
+
+ Parameters
+ ----------
+ catID : catchment ID
+ runfile : specify paths for forcing, subcat, parameters, topmodel output and hyd output
+ paramsfile : parameter file
+ subcatfile : subcat file
+ inputDir : directory for storing input files
+
+ Returns
+ ----------
+ None
+
+ """
+
+ # Copy
+ new_runfile = os.path.join(inputDir, '{}'.format(catID) + '_topmodel.run')
+ shutil.copy(runfile, new_runfile)
+ new_params = os.path.join(inputDir, '{}'.format(catID) + '_topmodel_params.dat')
+ shutil.copy(paramsfile, new_params)
+ new_subcat = os.path.join(inputDir, '{}'.format(catID) + '_topmodel_subcat.dat')
+ shutil.copy(subcatfile, new_subcat)
+
+ # read runfile
+ with open(new_runfile, 'r') as infile:
+ list_lines = infile.readlines()
+ lst_lines = copy.deepcopy(list_lines)
+
+ # Change directory in runfile
+ topmod_out = os.path.join(os.path.dirname(os.path.dirname(inputDir)), '{}'.format(catID) + '_topmod.out')
+ hyd_out = os.path.join(os.path.dirname(os.path.dirname(inputDir)), '{}'.format(catID) + '_hyd.out')
+ filePath = [os.path.join(os.path.dirname(inputDir), '{}'.format(catID) + '_forcing.csv'),
+ new_subcat, new_params, topmod_out, hyd_out]
+
+ for i in range(0,5):
+ lst_lines[i+2] = filePath[i] + '\n'
+
+ # Save file
+ with open(new_runfile, 'w') as outfile:
+ outfile.writelines(lst_lines)
+
+def create_troute_config(
+ gpkg_file: Union[str, Path],
+ rt_cfg_file: Union[str, Path],
+ start_date: str,
+ nts: int,
+ #reformat_dir: Union[str, Path],
+)->None:
+
+ """ Create routing configuration YAML file
+
+ Parameters
+ ----------
+ gpkg_file : GeoPackage hydrofabric file
+ rt_cfg_file : t-route configuration YAML file
+ start_date : start date for restart run
+ nts : number of timesteps
+ reformat_dir : directory for the reformatted nexus output files
+
+ Returns
+ ----------
+ None
+
+ """
+
+ # bmi_parameters
+ bmi_param = {"flowpath_columns": ["id", "toid", "lengthkm"],
+ "attributes_columns": ['attributes_id',
+ 'rl_gages',
+ 'rl_NHDWaterbodyComID',
+ 'MusK',
+ 'MusX',
+ 'n',
+ 'So',
+ 'ChSlp',
+ 'BtmWdth',
+ 'nCC',
+ 'TopWdthCC',
+ 'TopWdth'],
+ "waterbody_columns": ['hl_link',
+ 'ifd',
+ 'LkArea',
+ 'LkMxE',
+ 'OrificeA',
+ 'OrificeC',
+ 'OrificeE',
+ 'WeirC',
+ 'WeirE',
+ 'WeirL'],
+ "network_columns": ['network_id', 'hydroseq', 'hl_uri'],
+ }
+
+ # log_parameters
+ log_param = {"showtiming": True, "log_level": 'DEBUG'}
+
+ # network_topology_parameters
+ columns = {"key": "id",
+ "downstream": "toid",
+ "dx": "lengthkm",
+ "n": "n",
+ "ncc": "nCC",
+ "s0": "So",
+ "bw": "BtmWdth",
+ "waterbody": "rl_NHDWaterbodyComID",
+ "gages": "rl_gages",
+ "tw": "TopWdth",
+ "twcc": "TopWdthCC",
+ "musk": "MusK",
+ "musx": "MusX",
+ "cs": "ChSlp",
+ "alt": "alt",
+ }
+
+ dupseg = ["717696", "1311881", "3133581", "1010832", "1023120", "1813525",
+ "1531545", "1304859", "1320604", "1233435", "11816", "1312051",
+ "2723765", "2613174", "846266", "1304891", "1233595", "1996602",
+ "2822462", "2384576", "1021504", "2360642", "1326659", "1826754",
+ "572364", "1336910", "1332558", "1023054", "3133527", "3053788",
+ "3101661", "2043487", "3056866", "1296744", "1233515", "2045165",
+ "1230577", "1010164", "1031669", "1291638", "1637751",
+ ]
+
+ nwtopo_param = {"supernetwork_parameters": {"network_type": "HYFeaturesNetwork",
+ "geo_file_path": gpkg_file,
+ "columns": columns,
+ "duplicate_wb_segments": dupseg},
+ "waterbody_parameters": {"break_network_at_waterbodies": True,
+ "level_pool": {"level_pool_waterbody_parameter_file_path": gpkg_file}},
+ }
+
+ # compute_parameters
+ res_da = {"reservoir_persistence_da":{"reservoir_persistence_usgs": False,
+ "reservoir_persistence_usace": False},
+ "reservoir_rfc_da": {"reservoir_rfc_forecasts": False,
+ "reservoir_rfc_forecasts_time_series_path": None,
+ "reservoir_rfc_forecasts_lookback_hours": 28,
+ "reservoir_rfc_forecasts_offset_hours": 28,
+ "reservoir_rfc_forecast_persist_days": 11},
+ "reservoir_parameter_file": None,
+ }
+
+ stream_da = {"streamflow_nudging": False,
+ "diffusive_streamflow_nudging": False,
+ "gage_segID_crosswalk_file": None,
+ }
+
+ comp_param = {"parallel_compute_method": "by-subnetwork-jit-clustered",
+ "subnetwork_target_size": 10000,
+ "cpu_pool": 16,
+ "compute_kernel": "V02-structured",
+ "assume_short_ts": True,
+ "restart_parameters": {"start_datetime": start_date},
+ "forcing_parameters": {"qts_subdivisions": 12,
+ "dt": 300,
+ "qlat_input_folder": ".",
+ "qlat_file_pattern_filter": "nex-*",
+ "nts": nts,
+ "max_loop_size": divmod(nts*300, 3600)[0]+1},
+ "data_assimilation_parameters": {"usgs_timeslices_folder": None,
+ "usace_timeslices_folder": None,
+ "timeslice_lookback_hours": 48,
+ "qc_threshold": 1,
+ "streamflow_da": stream_da,
+ "reservoir_da": res_da},
+ }
+
+ # output_parameters
+ output_param = {'stream_output': {'stream_output_directory': ".",
+ 'stream_output_time': divmod(nts*300, 3600)[0]+1,
+ 'stream_output_type': '.nc',
+ 'stream_output_internal_frequency': 60,
+ },
+ }
+
+ # Combine all parameters
+ config = {"bmi_parameters": bmi_param,
+ "log_parameters": log_param,
+ "network_topology_parameters": nwtopo_param,
+ "compute_parameters": comp_param,
+ "output_parameters": output_param,
+ }
+
+ # Save configuration into yaml file
+ with open(rt_cfg_file, 'w') as file:
+ yaml.dump(config, file, sort_keys=False, default_flow_style=False, indent=4)
+
+
+def create_realization_file(
+ workdir: Union[str, Path],
+ lib_file: dict,
+ bmi_dir: dict,
+ forcing_dir: Union[str, Path],
+ realization_file: Union[str, Path],
+ model: str,
+ time_period: dict,
+ rt_dict: dict,
+)-> None:
+
+ """ Create realization file for the specified model and module
+
+ Parameters
+ ----------
+ workdir : basin directory for storing all the files
+ lib_file : library file for different model or module
+ bmi_dir : directory for different model or module to store BMI files
+ forcing_dir : directory to store foricng files
+ realization_file : model realization configuration file
+ model: model and module combination
+ time_period : simulation and evaluation time period
+ rt_dict : routing model source file directory and configuration file
+
+ Returns
+ ----------
+ None
+
+ """
+
+ # Create symlinks for libraries
+ lib_mod = {}
+ for key, value in lib_file.items():
+ lib_mod_link = os.path.join(workdir, 'Input/' + os.path.basename(value))
+ lib_mod.update({key: lib_mod_link})
+ if not os.path.exists(lib_mod_link):
+ os.symlink(value, lib_mod_link)
+
+ # noah
+ if model in ["cfe_noah", "topmodel_noah", "cfe_noah_sft", "lasam_noah_sft", "cfe_xaj_noah", "cfe_xaj_noah_sft"]:
+ noah_dict = {"name": "bmi_fortran",
+ "params": {"name": "bmi_fortran",
+ "model_type_name": "NoahOWP",
+ "main_output_variable": "QINSUR",
+ "library_file": lib_mod['noah'],
+ "init_config": os.path.join(bmi_dir['noah'], '{{id}}_calib.input'),
+ "allow_exceed_end_time": True, "fixed_time_step": False, "uses_forcing_file": False,
+ "variables_names_map": {
+ "PRCPNONC": "atmosphere_water__liquid_equivalent_precipitation_rate",
+ "Q2": "atmosphere_air_water~vapor__relative_saturation",
+ "SFCTMP": "land_surface_air__temperature",
+ "UU": "land_surface_wind__x_component_of_velocity",
+ "VV": "land_surface_wind__y_component_of_velocity",
+ "LWDN": "land_surface_radiation~incoming~longwave__energy_flux",
+ "SOLDN": "land_surface_radiation~incoming~shortwave__energy_flux",
+ "SFCPRS": "land_surface_air__pressure"}}}
+ # cfe
+ if model in ["cfe_noah", "cfe_noah_sft", "cfe_xaj_noah", "cfe_xaj_noah_sft"]:
+ cfe_dict = {"name": "bmi_c",
+ "params": {"name": "bmi_c",
+ "model_type_name": "CFE",
+ "main_output_variable": "Q_OUT",
+ "library_file": lib_mod['cfe'],
+ "init_config": os.path.join(bmi_dir['cfe'], '{{id}}_bmi_config_cfe.txt'),
+ "allow_exceed_end_time": True, "fixed_time_step": False, "uses_forcing_file": False,
+ "variables_names_map": {
+ "atmosphere_water__liquid_equivalent_precipitation_rate": "QINSUR",
+ "water_potential_evaporation_flux": "EVAPOTRANS"},
+ "registration_function": "register_bmi_cfe"}}
+ if model in ["cfe_noah", "cfe_xaj_noah"]:
+ items = {"ice_fraction_schaake": "sloth_ice_fraction_schaake",
+ "ice_fraction_xinanjiang": "sloth_ice_fraction_xinanjiang",
+ "soil_moisture_profile": "sloth_smp"}
+ var_name_map= cfe_dict["params"]["variables_names_map"]
+ var_name_map.update(items)
+ cfe_dict["params"]["variables_names_map"] = var_name_map
+
+ # topmodel
+ if model in ["topmodel_noah"]:
+ topm_dict = {"name": "bmi_c",
+ "params": {"name": "bmi_c",
+ "model_type_name": "TOPMODEL",
+ "main_output_variable": "Qout",
+ "library_file": lib_mod['topmodel'],
+ "init_config": os.path.join(bmi_dir['topmodel'], '{{id}}_topmodel.run'),
+ "allow_exceed_end_time": True, "fixed_time_step": False, "uses_forcing_file": False,
+ "variables_names_map": {
+ "atmosphere_water__liquid_equivalent_precipitation_rate": "QINSUR",
+ "water_potential_evaporation_flux": "EVAPOTRANS"},
+ "registration_function": "register_bmi_topmodel"}}
+
+ # sloth
+ if model in ["cfe_noah", "topmodel_noah", "cfe_xaj_noah"]:
+ sloth_dict = {"name": "bmi_c++",
+ "params": {"name": "bmi_c++",
+ "model_type_name": "SLOTH",
+ "main_output_variable": "z",
+ "library_file": lib_mod['sloth'],
+ "init_config": '/dev/null',
+ "allow_exceed_end_time": True,
+ "fixed_time_step": False,
+ "uses_forcing_file": False,
+ "model_params": {
+ "sloth_ice_fraction_schaake(1,double,m,node)": 0.0,
+ "sloth_ice_fraction_xinanjiang(1,double,1,node)": 0.0,
+ "sloth_smp(1,double,1,node)": 0.0}}}
+
+ elif model in ["cfe_noah_sft", "cfe_xaj_noah_sft"]:
+ sloth_dict = {"name": "bmi_c++",
+ "params": {"name": "bmi_c++",
+ "model_type_name": "SLOTH",
+ "main_output_variable": "z",
+ "library_file": lib_mod['sloth'],
+ "init_config": '/dev/null',
+ "allow_exceed_end_time": True,
+ "fixed_time_step": False,
+ "uses_forcing_file": False,
+ "model_params": {
+ "soil_moisture_wetting_fronts(1,double,1,node)": 0.0,
+ "soil_thickness_layered(1,double,1,node)": 0.0,
+ "soil_depth_wetting_fronts(1,double,1,node)": 0.0,
+ "num_wetting_fronts(1,int,1,node)": 1.0,
+ "Qb_topmodel(1,double,1,node)": 0.0,
+ "Qv_topmodel(1,double,1,node)": 0.0,
+ "global_deficit(1,double,1,node)": 0.0}}}
+
+ elif model in ["lasam_noah_sft"]:
+ sloth_dict = {"name": "bmi_c++",
+ "params": {"name": "bmi_c++",
+ "model_type_name": "SLOTH",
+ "main_output_variable": "z",
+ "library_file": lib_mod['sloth'],
+ "init_config": '/dev/null',
+ "allow_exceed_end_time": True,
+ "fixed_time_step": False,
+ "uses_forcing_file": False,
+ "model_params": {
+ "sloth_soil_storage(1,double,m,node)" : 1.0E-10,
+ "sloth_soil_storage_change(1,double,m,node)" : 0.0,
+ "Qb_topmodel(1,double,1,node)": 0.0,
+ "Qv_topmodel(1,double,1,node)": 0.0,
+ "global_deficit(1,double,1,node)": 0.0,
+ "potential_evapotranspiration_rate(1,double,1,node)": 0.0}}}
+
+ # sft
+ if model in ["cfe_noah_sft", "lasam_noah_sft", "cfe_xaj_noah_sft"]:
+ sft_dict = {"name": "bmi_c++",
+ "params": {"name": "bmi_c++",
+ "model_type_name": "SFT",
+ "main_output_variable": "num_cells",
+ "library_file": lib_mod['sft'],
+ "init_config": os.path.join(bmi_dir['sft'], '{{id}}_bmi_config_sft.txt'),
+ "allow_exceed_end_time": True,
+ "uses_forcing_file": False,
+ "variables_names_map": {"ground_temperature" : "TGS"}}}
+
+ # smp
+ if model in ["cfe_noah_sft", "cfe_xaj_noah_sft"]:
+ smp_dict = {"name": "bmi_c++",
+ "params": {"name": "bmi_c++",
+ "model_type_name": "SMP",
+ "main_output_variable": "soil_water_table",
+ "library_file": lib_mod['smp'],
+ "init_config": os.path.join(bmi_dir['smp'], '{{id}}_bmi_config_smp.txt'),
+ "allow_exceed_end_time": True,
+ "uses_forcing_file": False,
+ "variables_names_map": {
+ "soil_storage": "SOIL_STORAGE",
+ "soil_storage_change": "SOIL_STORAGE_CHANGE"}}}
+
+ elif model in ["lasam_noah_sft"]:
+ smp_dict = {"name": "bmi_c++",
+ "params": {"name": "bmi_c++",
+ "model_type_name": "SMP",
+ "main_output_variable": "soil_water_table",
+ "library_file": lib_mod['smp'],
+ "init_config": os.path.join(bmi_dir['smp'], '{{id}}_bmi_config_smp.txt'),
+ "allow_exceed_end_time": True,
+ "uses_forcing_file": False,
+ "variables_names_map": {
+ "soil_storage" : "sloth_soil_storage",
+ "soil_storage_change" : "sloth_soil_storage_change",
+ "soil_moisture_wetting_fronts" : "soil_moisture_wetting_fronts",
+ "soil_depth_wetting_fronts" : "soil_depth_wetting_fronts",
+ "num_wetting_fronts" : "soil_num_wetting_fronts"}}}
+
+ # lasam
+ if model in ["lasam_noah_sft"]:
+ lasam_dict = {"name": "bmi_c++",
+ "params": {"name": "bmi_c++",
+ "model_type_name": "LASAM",
+ "main_output_variable": "precipitation_rate",
+ "library_file": lib_mod['lasam'],
+ "init_config": os.path.join(bmi_dir['lasam'], '{{id}}_bmi_config_lasam.txt'),
+ "allow_exceed_end_time": True,
+ "uses_forcing_file": False,
+ "variables_names_map": {
+ "precipitation_rate" : "QINSUR",
+ "potential_evapotranspiration_rate": "EVAPOTRANS"}}}
+
+ # Combine configurations
+ if model in ["cfe_noah", "cfe_xaj_noah"]:
+ model_type_name = "NoahOWP_CFE"
+ main_output_variable = "Q_OUT"
+ sub_module = [noah_dict, *[cfe_dict, sloth_dict]]
+
+ elif model == "topmodel_noah":
+ model_type_name = "NoahOWP_TOPMODEL"
+ main_output_variable = "Qout"
+ sub_module = [noah_dict, topm_dict]
+
+ elif model in ["cfe_noah_sft", "cfe_xaj_noah_sft"]:
+ model_type_name = "NoahOWP_CFE_SK_SFT_SMP" if model== "cfe_noah_sft" else "NoahOWP_CFE_XAJ_SFT_SMP"
+ main_output_variable = "Q_OUT"
+ output_variables = ["soil_ice_fraction", "TGS", "RAIN_RATE", "DIRECT_RUNOFF", "GIUH_RUNOFF", "NASH_LATERAL_RUNOFF",
+ "DEEP_GW_TO_CHANNEL_FLUX", "Q_OUT", "SOIL_STORAGE", "ice_fraction_schaake", "POTENTIAL_ET", "ACTUAL_ET", "soil_moisture_fraction"]
+ output_header_fields = ["soil_ice_fraction", "ground_temperature", "rain_rate", "direct_runoff", "giuh_runoff", "nash_lateral_runoff",
+ "deep_gw_to_channel_flux", "q_out", "soil_storage", "ice_fraction_schaake", "PET", "AET", "soil_moisture_fraction"]
+ if model=="cfe_xaj_noah_sft":
+ output_variables[9] = "ice_fraction_xinanjiang"
+ output_header_fields[9] = "ice_fraction_xinanjiang"
+ sub_module = [sloth_dict, noah_dict, smp_dict, sft_dict, cfe_dict]
+
+ elif model == "lasam_noah_sft":
+ model_type_name = "NoahOWP_LASAM_SFT_SMP"
+ main_output_variable = "total_discharge"
+ output_variables = ["soil_ice_fraction", "TGS", "precipitation", "potential_evapotranspiratio", "actual_evapotranspiration",
+ "soil_storage", "surface_runoff", "giuh_runoff", "groundwater_to_stream_recharge", "percolation", "total_discharge",
+ "infiltration", "EVAPOTRAN", "soil_moisture_fraction"]
+ output_header_fields = ["soil_ice_fraction", "ground_temperature", "rain_rate", "PET_rate", "actual_ET",
+ "soil_storage", "direct_runoff", "giuh_runoff", "deep_gw_to_channel_flux", "soil_to_gw_flux", "q_out",
+ "infiltration", "PET_NOM", "soil_moisture_fraction"]
+ sub_module = [sloth_dict, noah_dict, smp_dict, sft_dict, lasam_dict]
+
+ gbmain = {"name": "bmi_multi",
+ "params": {"name": "bmi_multi", "model_type_name": model_type_name, "init_config": "",
+ "allow_exceed_end_time": False, "fixed_time_step": False,
+ "uses_forcing_file": False,
+ "main_output_variable": main_output_variable}}
+ if model in ["cfe_noah_sft", "lasam_noah_sft", "cfe_xaj_noah_sft"]:
+ gbmain["params"]["output_variables"] = output_variables
+ gbmain["params"]["output_header_fields"] = output_header_fields
+ gbmain["params"]["modules"] = sub_module
+
+ # global configuration
+ g = {"global": {"formulations": [gbmain],
+ "forcing": {"file_pattern": ".*{{id}}.*.csv", "path": forcing_dir, "provider": "CsvPerFeature"}}}
+
+ # time object
+ t = {"time": {"start_time": time_period['run_time_period']['calib'][0],
+ "end_time": time_period['run_time_period']['calib'][1], "output_interval": 3600}}
+ g.update(t)
+
+ # routing object
+ g.update(rt_dict)
+
+ # save configuration into json file
+ with open(realization_file, 'w') as outfile:
+ json.dump(g, outfile, indent=4, separators=(", ", ": "), sort_keys=False)
+
+
+def create_calib_config_file(
+ calib_params_file: Union[str, Path],
+ workdir: Union[str, Path],
+ general_dict: dict,
+ model_dict: dict,
+ config_yaml_file: Union[str, Path],
+)->None:
+
+ """ Create configuration YAML file for calibration run
+
+ Parameters
+ ----------
+ calib_params_file : file containing min, max and init values of calibration parameters
+ workdir : basin directory for storing all the files
+ general_dict : general settings
+ model_dict : model settings
+ config_yaml_file : configuration YAML file
+
+ Returns
+ ----------
+ None
+
+ """
+
+ # Extract calibration params range
+ df_params = pd.read_fwf(calib_params_file).copy()
+ df_params.set_index('param', inplace=True)
+ calib_params = df_params.groupby('model').groups
+
+ params_range_dict = {}
+ for k, v in calib_params.items():
+ params_range = []
+ for m in v:
+ params_range.append({'name': m, 'min': float(df_params.query('model==@k').loc[m]['min']),
+ 'max': float(df_params.query('model==@k').loc[m]['max']),
+ 'init': float(df_params.query('model==@k').loc[m]['init'])})
+ params_range_dict.update({k: params_range})
+
+ # Create configuration
+ basin_yaml = {'general': general_dict}
+ basin_yaml.update(params_range_dict)
+
+ # Create symlink for ngen executable
+ ngen_file_link = os.path.join(workdir, 'Input/' + os.path.basename(model_dict['binary'])[0:4])
+ if not os.path.exists(ngen_file_link):
+ os.symlink(model_dict['binary'], ngen_file_link)
+
+ model_dict['binary'] = ngen_file_link
+ basin_yaml['model'] = model_dict
+ basin_yaml['model']['params'] = params_range_dict
+
+ # Save configuration into yaml file
+ with open(config_yaml_file, 'w') as file:
+ yaml.dump(basin_yaml, file, sort_keys=False, default_flow_style=False, indent=2)
diff --git a/python/createInput/src/noaa_owp.py b/python/createInput/src/noaa_owp.py
new file mode 100644
index 00000000..c3022098
--- /dev/null
+++ b/python/createInput/src/noaa_owp.py
@@ -0,0 +1,283 @@
+"""
+This module is taken from ngen_config_gen open source package.
+Author made further modifications.
+"""
+
+from typing import Any, Dict, List, TYPE_CHECKING
+from collections import defaultdict
+from pathlib import Path
+
+from pydantic import BaseModel
+
+if TYPE_CHECKING:
+ from ngen.config_gen.hook_providers import HookProvider
+
+import math
+
+from ngen.config.init_config.noahowp import (
+ NoahOWP as NoahOWPConfig,
+ ModelOptions,
+ Location,
+ Forcing,
+ Structure,
+ InitialValues,
+ LandSurfaceType,
+)
+from ngen.config.init_config.noahowp_options import (
+ DynamicVegOption,
+ CanopyStomResistOption,
+ SoilTempBoundaryOption,
+ RunoffOption,
+ SfcDragCoeffOption,
+ FrozenSoilOption,
+ SupercooledWaterOption,
+ RadiativeTransferOption,
+ SnowAlbedoOption,
+ PrecipPhaseOption,
+ SnowsoilTempTimeOption,
+ SubsurfaceOption,
+ StomatalResistanceOption,
+ EvapSrfcResistanceOption,
+ DrainageOption,
+ DynamicVicOption,
+ CropModelOption,
+)
+
+
+class NoahOWP:
+ """
+ NWM 2.2.3 analysis assim physics options
+ source: https://www.nco.ncep.noaa.gov/pmb/codes/nwprod/nwm.v2.2.3/parm/analysis_assim/namelist.hrldas
+ ! Physics options (see the documentation for details)
+ | NoahOWP Name | NoahMP Name | NWM 2.2.3 analysis assim physics options |
+ |-----------------------------|-------------------------------------|------------------------------------------|
+ | dynamic_veg_option | DYNAMIC_VEG_OPTION | 4 |
+ | canopy_stom_resist_option | CANOPY_STOMATAL_RESISTANCE_OPTION | 1 |
+ | stomatal_resistance_option | BTR_OPTION | 1 |
+ | runoff_option | RUNOFF_OPTION | 3 |
+ | sfc_drag_coeff_option | SURFACE_DRAG_OPTION | 1 |
+ | frozen_soil_option | FROZEN_SOIL_OPTION | 1 |
+ | supercooled_water_option | SUPERCOOLED_WATER_OPTION | 1 |
+ | radiative_transfer_option | RADIATIVE_TRANSFER_OPTION | 3 |
+ | snow_albedo_option | SNOW_ALBEDO_OPTION | 1 |
+ | precip_phase_option | PCP_PARTITION_OPTION | 1 |
+ | soil_temp_boundary_option | TBOT_OPTION | 2 |
+ | snowsoil_temp_time_option | TEMP_TIME_SCHEME_OPTION | 3 |
+ | no glacier option | GLACIER_OPTION | 2 |
+ | evap_srfc_resistance_option | SURFACE_RESISTANCE_OPTION | 4 |
+
+ NWM 3.0.6 analysis assim physics options
+ source: https://www.nco.ncep.noaa.gov/pmb/codes/nwprod/nwm.v3.0.6/parm/analysis_assim/namelist.hrldas
+ ! Physics options (see the documentation for details)
+ | NoahOWP Name | NoahMP Name | NWM 3.0.6 analysis assim physics options |
+ |-----------------------------|-------------------------------------|------------------------------------------|
+ | dynamic_veg_option | DYNAMIC_VEG_OPTION | 4 |
+ | canopy_stom_resist_option | CANOPY_STOMATAL_RESISTANCE_OPTION | 1 |
+ | stomatal_resistance_option | BTR_OPTION | 1 |
+ | runoff_option | RUNOFF_OPTION | 7 |
+ | sfc_drag_coeff_option | SURFACE_DRAG_OPTION | 1 |
+ | frozen_soil_option | FROZEN_SOIL_OPTION | 1 |
+ | supercooled_water_option | SUPERCOOLED_WATER_OPTION | 1 |
+ | radiative_transfer_option | RADIATIVE_TRANSFER_OPTION | 3 |
+ | snow_albedo_option | SNOW_ALBEDO_OPTION | 1 |
+ | precip_phase_option | PCP_PARTITION_OPTION | 1 |
+ | soil_temp_boundary_option | TBOT_OPTION | 2 |
+ | snowsoil_temp_time_option | TEMP_TIME_SCHEME_OPTION | 3 |
+ | no glacier option | GLACIER_OPTION | 2 |
+ | evap_srfc_resistance_option | SURFACE_RESISTANCE_OPTION | 4 |
+ | | IMPERV_OPTION | 2 (0: none; 1: total; 2: Alley&Veenhuis; |
+ | | | 9: orig) |
+
+ """
+
+ def __init__(self, start_time: str, end_time: str, parameter_dir: Path):
+ self.data = defaultdict(dict)
+ # NOTE: this might be handled differently in the future
+ self.data["parameters"]["parameter_dir"] = parameter_dir
+
+ # NOTE: expects "%Y%m%d%H%M" (e.g. 200012311730)
+ self.data["timing"]["startdate"] = start_time
+ self.data["timing"]["enddate"] = end_time
+
+ # NOTE: these parameters will likely be removed in the future. They are not used if noah owp
+ # is compiled for use with NextGen.
+ self.data["timing"]["forcing_filename"] = Path("")
+ self.data["timing"]["output_filename"] = Path("")
+
+ def _v2_defaults(self) -> None:
+ # ---------------------------------- Timing ---------------------------------- #
+ # NOTE: in the future this _should_ be pulled from a forcing metadata hook (if one ever exists)
+ self.data["timing"]["dt"] = 3600
+
+ # -------------------------------- Parameters -------------------------------- #
+ # NOTE: Wrf-Hydro configured as NWM uses USGS vegitation classes. Thus, so does HF v1.2 and v2.0
+ self.data["parameters"]["veg_class_name"] = "USGS"
+
+ # TODO: determine how to handle `parameter_dir`
+ # NOTE: theses _could_ be bundled as package data
+ # NOTE: could a parameter to the initializer
+ # NOTE: moved to __init__ for now
+ # self.data["parameters"]["parameter_dir"] =
+
+ # looking through the from wrf-hydro source, it appears that wrf-hydro hard codes `STAS` as the `soil_class_name`
+ # see https://sourcegraph.com/search?q=context:global+repo:https://github.com/NCAR/wrf_hydro_nwm_public+STAS&patternType=standard&sm=1&groupBy=repo
+ self.data["parameters"]["soil_class_name"] = "STAS" # | "STAS-RUC"
+
+ # ---------------------------------- Forcing --------------------------------- #
+ # measurement height for wind speed [m]
+ # NOTE: in the future this _should_ be pulled from a forcing metadata hook (if one ever exists)
+ zref = 10.0
+ # rain-snow temperature threshold
+ rain_snow_thresh = 0.5
+ self.data["forcing"] = Forcing(zref=zref, rain_snow_thresh=rain_snow_thresh)
+
+ # ------------------------------- Model Options ------------------------------ #
+ dynamic_veg_option: DynamicVegOption = (
+ DynamicVegOption.off_use_lai_table_use_max_vegetation_fraction
+ )
+ canopy_stom_resist_option = CanopyStomResistOption.ball_berry
+ stomatal_resistance_option = StomatalResistanceOption.noah
+ runoff_option = RunoffOption.original_surface_and_subsurface_runoff
+ sfc_drag_coeff_option = SfcDragCoeffOption.m_o
+ frozen_soil_option = FrozenSoilOption.linear_effects
+ supercooled_water_option = SupercooledWaterOption.no_iteration
+ radiative_transfer_option = (
+ RadiativeTransferOption.two_stream_applied_to_vegetated_fraction
+ )
+ snow_albedo_option = SnowAlbedoOption.BATS
+ precip_phase_option = PrecipPhaseOption.user_defined_wet_bulb_temperature_threshold
+ soil_temp_boundary_option = SoilTempBoundaryOption.tbot_at_zbot
+ # TODO: needs further verification
+ snowsoil_temp_time_option = (
+ SnowsoilTempTimeOption.semo_implicit_with_fsno_for_ts
+ )
+ # no glacier option
+ evap_srfc_resistance_option = (
+ EvapSrfcResistanceOption.sakaguchi_and_zeng_for_nonsnow_rsurf_eq_rsurf_snow_for_snow
+ )
+ # non noahmp options
+ drainage_option = DrainageOption.dynamic_vic_runoff_with_dynamic_vic_runoff
+ dynamic_vic_option = DynamicVicOption.philip
+ crop_model_option = CropModelOption.none
+ subsurface_option = SubsurfaceOption.one_way_coupled_hydrostatic
+
+ model_options = ModelOptions(
+ precip_phase_option=precip_phase_option,
+ snow_albedo_option=snow_albedo_option,
+ dynamic_veg_option=dynamic_veg_option,
+ runoff_option=runoff_option,
+ drainage_option=drainage_option,
+ frozen_soil_option=frozen_soil_option,
+ dynamic_vic_option=dynamic_vic_option,
+ radiative_transfer_option=radiative_transfer_option,
+ sfc_drag_coeff_option=sfc_drag_coeff_option,
+ canopy_stom_resist_option=canopy_stom_resist_option,
+ crop_model_option=crop_model_option,
+ snowsoil_temp_time_option=snowsoil_temp_time_option,
+ soil_temp_boundary_option=soil_temp_boundary_option,
+ supercooled_water_option=supercooled_water_option,
+ stomatal_resistance_option=stomatal_resistance_option,
+ evap_srfc_resistance_option=evap_srfc_resistance_option,
+ subsurface_option=subsurface_option,
+ )
+ self.data["model_options"] = model_options
+
+ # ------------------------------- InitialValues ------------------------------ #
+
+ # snow/soil level thickness [m]
+ # all nwm version (including 3.0) have always used soil horizons of 10cm 30cm 60cm and 1m; see last 4 values of dzsnso
+ # NOTE: len nsnow + nsoil; thus [nsnow..., nsoil...] in this order
+ # https://github.com/NOAA-OWP/noah-owp-modular/blob/30d0f53e8c14acc4ce74018e06ff7c9410ecc13c/src/DomainType.f90#L66
+ # if you are looking at the fortran source, this is indexed like:
+ # where [-2:0] are snow and [1:4] are soil
+ # [ -2, -1, 0, 1 2, 3, 4]
+ dzsnso: List[float] = [0.0, 0.0, 0.0, 0.1, 0.3, 0.6, 1.0]
+
+ # initial soil ice profile [m^3/m^3]
+ # NOTE: len nsoil
+ # https://github.com/NOAA-OWP/noah-owp-modular/blob/30d0f53e8c14acc4ce74018e06ff7c9410ecc13c/src/WaterType.f90#L110
+ # NOTE: These values likely make no sense
+ sice: List[float] = [0.0, 0.0, 0.0, 0.0]
+
+ # initial soil liquid profile [m^3/m^3]
+ # NOTE: len nsoil
+ # https://github.com/NOAA-OWP/noah-owp-modular/blob/30d0f53e8c14acc4ce74018e06ff7c9410ecc13c/src/WaterType.f90#L111
+ sh2o: List[float] = [0.3, 0.3, 0.3, 0.3]
+
+ # initial water table depth below surface [m]
+ # NOTE: not sure if this _should_ ever be derived. my intuition is this is -2 b.c. the total
+ # soil horizon height is 2m (see `dzsnoso`)
+ zwt: float = -2.0
+
+ initial_values = InitialValues(
+ dzsnso=dzsnso,
+ sice=sice,
+ sh2o=sh2o,
+ zwt=zwt,
+ )
+ self.data["initial_values"] = initial_values
+
+ def hydrofabric_linked_data_hook(
+ self, version: str, divide_id: str, data: Dict[str, Any]
+ ) -> None:
+ # --------------------------------- Location --------------------------------- #
+ lon = data["X"]
+ lat = data["Y"]
+ terrain_slope = data['slope_mean']
+ azimuth = data["aspect_c_mean"]
+ self.data["location"] = Location(
+ lon=lon, lat=lat, terrain_slope=terrain_slope, azimuth=azimuth
+ )
+
+ # --------------------------------- Structure -------------------------------- #
+ # NOTE: Wrf-Hydro configured as NWM uses STAS soil classes. Thus, so does HF v1.2 and v2.0
+ isltyp = data["ISLTYP"]
+ # all nwm versions (including 3.0) have used 4 soil horizons
+ nsoil = 4
+ nsnow = 3
+ # NOTE: Wrf-Hydro configured as NWM uses USGS vegetation classes. Thus, so does HF v1.2 and v2.0
+ # NOTE: this can be derived from Parameters `veg_class_name` field (USGS=27; MODIS=20)
+ nveg = 27
+ vegtyp = data["IVGTYP"]
+ # crop type (SET TO 0, no crops currently supported)
+ # source: https://github.com/NOAA-OWP/noah-owp-modular/blob/30d0f53e8c14acc4ce74018e06ff7c9410ecc13c/src/NamelistRead.f90#L36
+ croptype = 0
+
+ # NOTE: 16 = water bodies in USGS vegetation classification (see MPTABLE.TBL)
+ USGS_VEG_IS_WATER = 16
+ if vegtyp == USGS_VEG_IS_WATER:
+ sfctyp = LandSurfaceType.lake
+ else:
+ sfctyp = LandSurfaceType.soil
+
+ # TODO: not sure where this comes from
+ # soil color index for soil albedo
+ # https://github.com/NOAA-OWP/noah-owp-modular/blob/30d0f53e8c14acc4ce74018e06ff7c9410ecc13c/docs/changelog.md?plain=1#L35C7-L35C168
+ # > SOILCOLOR is hard-coded as 4 in module_sf_noahmpdrv.F in the current release of HRLDAS. SOILCOLOR is used to select the albedo values for dry and saturated soil.
+ # NOTE: it appears that the soil color indexes into the ALBSAT_VIS, ALBSAT_NIR, ALBDRY_VIS, ALBDRY_NIR tables
+ # https://github.com/NOAA-OWP/noah-owp-modular/blob/30d0f53e8c14acc4ce74018e06ff7c9410ecc13c/parameters/MPTABLE.TBL#L328-L331
+ # here is the indexing
+ # https://github.com/NOAA-OWP/noah-owp-modular/blob/30d0f53e8c14acc4ce74018e06ff7c9410ecc13c/src/ParametersType.f90#L303-L306
+ # NOTE: looks like for HRLDAS this is 4
+ soilcolor: int = 4
+ structure = Structure(
+ isltyp=isltyp,
+ nsoil=nsoil,
+ nsnow=nsnow,
+ nveg=nveg,
+ vegtyp=vegtyp,
+ # crop type (SET TO 0, no crops currently supported)
+ # source: https://github.com/NOAA-OWP/noah-owp-modular/blob/30d0f53e8c14acc4ce74018e06ff7c9410ecc13c/src/NamelistRead.f90#L36
+ croptype=croptype,
+ sfctyp=sfctyp,
+ soilcolor=soilcolor,
+ )
+ self.data["structure"] = structure
+
+ def visit(self, hook_provider: "HookProvider") -> None:
+ hook_provider.provide_hydrofabric_linked_data(self)
+
+ self._v2_defaults()
+
+ def build(self) -> BaseModel:
+ return NoahOWPConfig(**self.data)
diff --git a/python/runCalibValid/calibration.py b/python/runCalibValid/calibration.py
new file mode 100644
index 00000000..cd7ccc8b
--- /dev/null
+++ b/python/runCalibValid/calibration.py
@@ -0,0 +1,91 @@
+"""
+This is the main script to read calibration configuration file and execute calibration run.
+
+@author: Nels Frazer and Xia Feng
+"""
+
+import argparse
+from os import chdir
+from pathlib import Path
+
+import yaml
+
+from ngen.cal.agent import Agent
+from ngen.cal.configuration import General
+from ngen.cal.search import dds, dds_set, pso_search, gwo_search
+from ngen.cal.strategy import Algorithm
+
+def main(general: General, model_conf):
+
+ # Seed the random number generators if requested
+ if( general.random_seed is not None):
+ import random
+ random.seed(general.random_seed)
+ import numpy as np
+ np.random.seed(general.random_seed)
+
+ print("Starting calib")
+
+ """
+ TODO calibrate each "catcment" independely, but there may be something interesting in grouping various formulation params
+ into a single variable vector and calibrating a set of heterogenous formultions...
+ """
+ start_iteration = 0
+
+ # Initialize the starting agent
+ agent = Agent(model_conf, general.calib_path, general, general.log, general.restart)
+ if general.strategy.algorithm == Algorithm.dds:
+ start_iteration = general.start_iteration
+ if general.restart:
+ start_iteration = agent.restart()
+ func = dds_set #FIXME what about explicit/dds
+ elif general.strategy.algorithm == Algorithm.pso: #TODO how to restart PSO?
+ if agent.model.strategy != "uniform":
+ print("Can only use PSO with the uniform model strategy")
+ return
+ if general.restart:
+ print("Restart not supported for PSO search, starting at 0")
+ func = pso_search
+ elif general.strategy.algorithm == Algorithm.gwo:
+ if agent.model.strategy != "uniform":
+ print("Can only use GWO with the uniform model strategy")
+ return
+ if general.restart:
+ start_iteration = agent.restart()
+ func = gwo_search
+
+ print("Starting Iteration: {}".format(start_iteration))
+ print("Starting calibration loop")
+
+ # NOTE this assumes we calibrate each catchment independently, it may be possible to design an "aggregate" calibration
+ # that works in a more sophisticated manner.
+ if agent.model.strategy == 'explicit': #FIXME this needs a refactor...should be able to use a calibration_set with explicit loading
+ for catchment in agent.model.adjustables:
+ dds(start_iteration, general.iterations, catchment, agent)
+
+ elif agent.model.strategy == 'independent':
+ #for catchment_set in agent.model.adjustables:
+ func(start_iteration, general.iterations, agent)
+
+ elif agent.model.strategy == 'uniform':
+ func(start_iteration, general.iterations, agent)
+
+
+if __name__ == "__main__":
+
+ # Create the command line parser
+ parser = argparse.ArgumentParser(description='Calibrate catchments in NGEN architecture.')
+ parser.add_argument('config_file', type=Path,
+ help='The configuration yaml file for catchments to be operated on')
+
+ args = parser.parse_args()
+
+ with open(args.config_file) as file:
+ conf = yaml.safe_load(file)
+
+ general = General(**conf['general'])
+
+ # Change directory to workdir
+ chdir(general.workdir)
+
+ main(general, conf['model'])
diff --git a/python/runCalibValid/ngen_cal/CONTRIBUTING.md b/python/runCalibValid/ngen_cal/CONTRIBUTING.md
new file mode 100644
index 00000000..0f109b26
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/CONTRIBUTING.md
@@ -0,0 +1,32 @@
+# Guidance on how to contribute
+
+> All contributions to this project will be released to the public domain.
+> By submitting a pull request or filing a bug, issue, or
+> feature request, you are agreeing to comply with this waiver of copyright interest.
+> Details can be found in our [TERMS](TERMS.md) and [LICENSE](LICENSE).
+
+
+There are two primary ways to help:
+ - Using the issue tracker, and
+ - Changing the code-base.
+
+
+## Using the issue tracker
+
+Use the issue tracker to suggest feature requests, report bugs, and ask questions.
+This is also a great way to connect with the developers of the project as well
+as others who are interested in this solution.
+
+Use the issue tracker to find ways to contribute. Find a bug or a feature, mention in
+the issue that you will take on that effort, then follow the _Changing the code-base_
+guidance below.
+
+
+## Changing the code-base
+
+Generally speaking, you should fork this repository, make changes in your
+own fork, and then submit a pull request. All new code should have associated
+unit tests that validate implemented features and the presence or lack of defects.
+Additionally, the code should follow any stylistic and architectural guidelines
+prescribed by the project. In the absence of such guidelines, mimic the styles
+and patterns in the existing code-base.
diff --git a/python/runCalibValid/ngen_cal/LICENSE b/python/runCalibValid/ngen_cal/LICENSE
new file mode 100644
index 00000000..a0230332
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/LICENSE
@@ -0,0 +1,7 @@
+“Software code created by U.S. Government employees is not subject to copyright
+in the United States (17 U.S.C. §105). The United States/Department of Commerce
+reserve all rights to seek and obtain copyright protection in countries other
+than the United States for Software authored in its entirety by the Department
+of Commerce. To this end, the Department of Commerce hereby grants to Recipient
+a royalty-free, nonexclusive license to use, copy, and create derivative works
+of the Software outside of the United States.”
diff --git a/python/runCalibValid/ngen_cal/MANIFEST.in b/python/runCalibValid/ngen_cal/MANIFEST.in
new file mode 100644
index 00000000..cc0d1164
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/MANIFEST.in
@@ -0,0 +1 @@
+include LICENSE
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_cal/README.md b/python/runCalibValid/ngen_cal/README.md
new file mode 100644
index 00000000..f046cbe1
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/README.md
@@ -0,0 +1,11 @@
+## ngen.cal package
+
+ This standalone tool carries out parameter calibration for different NextGen model formulations. It expands and extends the functionalities of an earlier version of [ngen.cal](https://github.com/NOAA-OWP/ngen-cal/tree/master/python/ngen_cal) with the additional features as follows:
+
+- Adds a statistical module with sixteen metrics for assessing hydrologic model performance
+- Adds a visualization module to generate plots for different calibration and validation outputs, such as hydrograph, flow duration curve, figures of statistical metrics, and calibration parameters (calibration run), etc.
+- Implements grey wolf optimizer (GWO) and associted interfaces for potential implementional of the other swarm optmization algorithms
+- Improves restart capability to clean up the calibration output files and resume the crashed calibration run. Restart functionality is currently implemented for DDS and GWO.
+- Installs capabilites to support the exection of validation runs using the default and best parameter sets, respectively
+
+
diff --git a/python/runCalibValid/ngen_cal/SECURITY.md b/python/runCalibValid/ngen_cal/SECURITY.md
new file mode 100644
index 00000000..0cdd1d99
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/SECURITY.md
@@ -0,0 +1,27 @@
+# Security Policy
+
+There MUST be no unpatched vulnerabilities of medium or higher severity that have been publicly known for more than 60 days.
+
+The vulnerability must be patched and released by the project itself (patches may be developed elsewhere). A vulnerability becomes publicly known (for this purpose) once it has a CVE with publicly released non-paywalled information (reported, for example, in the National Vulnerability Database) or when the project has been informed and the information has been released to the public (possibly by the project). A vulnerability is considered medium or higher severity if its Common Vulnerability Scoring System (CVSS) base qualitative score is medium or higher. In CVSS versions 2.0 through 3.1, this is equivalent to a CVSS score of 4.0 or higher. Projects may use the CVSS score as published in a widely-used vulnerability database (such as the National Vulnerability Database) using the most-recent version of CVSS reported in that database. Projects may instead calculate the severity themselves using the latest version of CVSS at the time of the vulnerability disclosure, if the calculation inputs are publicly revealed once the vulnerability is publicly known. Note: this means that users might be left vulnerable to all attackers worldwide for up to 60 days. This criterion is often much easier to meet than what Google recommends in Rebooting responsible disclosure, because Google recommends that the 60-day period start when the project is notified _even_ if the report is not public. Also note that this badge criterion, like other criteria, applies to the individual project. Some projects are part of larger umbrella organizations or larger projects, possibly in multiple layers, and many projects feed their results to other organizations and projects as part of a potentially-complex supply chain. An individual project often cannot control the rest, but an individual project can work to release a vulnerability patch in a timely way. Therefore, we focus solely on the individual project's response time. Once a patch is available from the individual project, others can determine how to deal with the patch (e.g., they can update to the newer version or they can apply just the patch as a cherry-picked solution).
+
+The public repositories MUST NOT leak any valid private credential (e.g., a working password or private key) that is intended to limit public access.
+
+## Supported Versions
+
+Use this section to tell people about which versions of your project are
+currently being supported with security updates.
+
+| Version | Supported |
+| ------- | ------------------ |
+| 5.1.x | :white_check_mark: |
+| 5.0.x | :x: |
+| 4.0.x | :white_check_mark: |
+| < 4.0 | :x: |
+
+## Reporting a Vulnerability
+
+Use this section to tell people how to report a vulnerability.
+
+Tell them where to go, how often they can expect to get an update on a
+reported vulnerability, what to expect if the vulnerability is accepted or
+declined, etc.
diff --git a/python/runCalibValid/ngen_cal/TERMS.md b/python/runCalibValid/ngen_cal/TERMS.md
new file mode 100644
index 00000000..b49b176b
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/TERMS.md
@@ -0,0 +1,19 @@
+## Disclaimer
+
+This repository is a scientific product and is not official communication of the National Oceanic and Atmospheric Administration, or the United States Department of Commerce. All NOAA GitHub project code is provided on an 'as is' basis and the user assumes responsibility for its use. Any claims against the Department of Commerce or Department of Commerce bureaus stemming from the use of this GitHub project will be governed by all applicable Federal law. Any reference to specific commercial products, processes, or services by service mark, trademark, manufacturer, or otherwise, does not constitute or imply their endorsement, recommendation or favoring by the Department of Commerce. The Department of Commerce seal and logo, or the seal and logo of a DOC bureau, shall not be used in any manner to imply endorsement of any commercial product or activity by DOC or the United States Government.
+
+[NOAA GitHub Policy](https://github.com/NOAAGov/Information)
+
+### Other Information
+
+Unless expressly stated otherwise, the person who associated a work with
+this deed makes no warranties about the work, and disclaims liability for
+all uses of the work, to the fullest extent permitted by applicable law.
+When using or citing the work, you should not imply endorsement by the
+author or the affirmer.
+
+## Exceptions
+
+_Source code or other assets that are excluded from the TERMS should be listed
+here. These may include dependencies that may be licensed differently or are
+not in the public domain._
diff --git a/python/runCalibValid/ngen_cal/changelog.md b/python/runCalibValid/ngen_cal/changelog.md
new file mode 100644
index 00000000..2b9d4b72
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/changelog.md
@@ -0,0 +1,44 @@
+# V 0.2.0
+- Allow ngen configuration to specify routing output file name to look for.
+- `Evaluatable` objects are now responsible for maintaining the `evaluation_parms` property, including `evaluation_range`
+- `evaluation_range` removed from `Meta`
+- `eval_params` bundeled and moved to model config from global, these include the following configuration keys
+ - `evaluation_start`
+ - `evaluation_stop`
+ - `objective`
+- Add `bounds` property to `Adjustable` interface
+- Use an `Agent` abstraction to connect model runtime, calibration objects, and evaluation criteria
+- All model execution now happens in automatically generated subdirectory
+- Introduce PSO global best serach, only applicable for `uniform` stragegy
+- Allow additional search algorithm parameters to be configured by the user
+ - For DDS, the configuration can supply the `neighborhood` parameter as follows, if not supplied, a default of 0.2 is used
+ ```yaml
+ strategy:
+ type: estimation
+ algorithm: dds
+ parameters:
+ neighborhood: 0.5
+ ```
+ - For PSO, the configuration can supply the following parameters
+ ```yaml
+ strategy:
+ type: estimation
+ algorithm: "pso"
+ parameters:
+ pool: 4 #number of processors to use (by default, uses 1)
+ particles: 8 #number of particles to use (by default, uses 4)
+ options: #the PSO parameters (defaults to c1: 0.5, c2: 0.3, w:0.9)
+ c1: 0.1
+ c2: 0.1
+ w: 0.42
+ ```
+- Restart semantics have changed slightly. Restart is only supported for DDS search, with the following caveats:
+ If a user starts with an independent calibration strategy
+ then restarts with a uniform strategy, this will "work" but probably shouldn't.
+ it works cause the independent writes a param df for the nexus that uniform also uses,
+ so data "exists" and it doesn't know its not conistent...
+ Conversely, if you start with uniform then try independent, it will start back at
+ 0 correctly since not all basin params can be loaded.
+ There are probably some similar issues with explicit and independent, since they have
+ similar data semantics.
+- Fix issue with independent strategy not writing ngen forcing configs for target catchments in a way that ngen can handle.
diff --git a/python/runCalibValid/ngen_cal/pyproject.toml b/python/runCalibValid/ngen_cal/pyproject.toml
new file mode 100644
index 00000000..ebeac06e
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/pyproject.toml
@@ -0,0 +1,6 @@
+[build-system]
+build-backend = "setuptools.build_meta"
+requires = [
+ "setuptools>=42",
+ "wheel",
+]
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_cal/setup.cfg b/python/runCalibValid/ngen_cal/setup.cfg
new file mode 100644
index 00000000..5634849c
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/setup.cfg
@@ -0,0 +1,52 @@
+[metadata]
+name = ngen.cal
+version = attr: ngen.cal._version.__version__
+author =
+ Xia Feng
+ Nels J. Frazier
+author_email =
+ xia.feng@noaa.gov
+ nels.frazier@noaa.gov
+description = A library to perform automatic calibration of NextGen formulations
+long_description = file: README.md
+long_description_content_type = text/markdown
+license = USDOC
+license_files = LICENSE
+url = https://github.com/NOAA-OWP/NextGen_Model_Calibration/tree/master/python/runCalibValid/ngen_cal
+classifiers =
+ Development Status :: 3 - Alpha
+ Intended Audience :: Education
+ Intended Audience :: Science/Research
+ License :: Free To Use But Restricted
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: 3.8
+ Programming Language :: Python :: 3.9
+ Topic :: Scientific/Engineering :: Hydrology
+ Operating System :: OS Independent
+
+[options]
+packages = find_namespace:
+package_dir =
+ = src
+install_requires =
+ pydantic<2.0.0
+ pandas~=1.1.2
+ geopandas
+ matplotlib
+ hydrotools.metrics
+ hydrotools.nwis_client
+ pyarrow
+ tables
+ hypy @ git+https://github.com/noaa-owp/hypy@master#egg=hypy&subdirectory=python
+ ngen_config @ git+https://github.com/noaa-owp/NextGen_Model_Calibration@master#egg=ngen_config&subdirectory=python/runCalibValid/ngen_conf
+ pyyaml
+python_requires = >=3.7
+include_package_data = True
+
+[options.packages.find]
+where = src
+
+[options.extras_require]
+develop =
+ pytest
+ pytest-mock
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/__init__.py b/python/runCalibValid/ngen_cal/src/ngen/cal/__init__.py
new file mode 100644
index 00000000..301946d1
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/__init__.py
@@ -0,0 +1,49 @@
+# Monkey patch pydantic to allow schema serialization of PyObject types to string
+from pydantic import PyObject
+def pyobject_schema(cls, field_schema):
+ field_schema['type'] = 'string'
+
+PyObject.__modify_schema__ = classmethod(pyobject_schema)
+
+from .configuration import General, Model
+from .calibratable import Calibratable, Adjustable, Evaluatable
+from .calibration_set import CalibrationSet, UniformCalibrationSet
+from .meta import JobMeta
+
+from . import metric_functions
+from . import plot_functions
+from . import plot_output
+from . import gwo_global_best
+from . import gwo_swarms
+
+from .metric_functions import (
+ treat_values,
+ pearson_corr,
+ mean_abs_error,
+ root_mean_squared_error,
+ rmse_std_ratio,
+ percent_bias,
+ NSE,
+ Weighted_NSE,
+ KGE,
+ categorical_score,
+ pbias_fdc,
+ calculate_all_metrics,
+)
+
+from .plot_functions import (
+ plot_streamflow,
+ plot_streamflow_precipitation,
+ scatterplot_streamflow,
+ plot_output,
+ scatterplot_objfun,
+ trim_axs,
+ scatterplot_var,
+ scatterplot_objfun_metric,
+ barplot_metric,
+ plot_fdc_calib,
+ plot_fdc_valid,
+ plot_cost_hist,
+)
+
+from .validation_run import run_valid_ctrl_best
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/_version.py b/python/runCalibValid/ngen_cal/src/ngen/cal/_version.py
new file mode 100644
index 00000000..0404d810
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/_version.py
@@ -0,0 +1 @@
+__version__ = '0.3.0'
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/agent.py b/python/runCalibValid/ngen_cal/src/ngen/cal/agent.py
new file mode 100644
index 00000000..78be9979
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/agent.py
@@ -0,0 +1,225 @@
+"""
+This module creates working directory and subdirectories, and stores
+properties related to configurations for executing calibration and validation runs.
+
+@author: Nels Frazer, Xia Feng
+"""
+
+from abc import ABC, abstractmethod
+import os
+from pathlib import Path
+from typing import TYPE_CHECKING
+
+import pandas as pd
+
+from .strategy import Algorithm
+from ngen.cal.meta import JobMeta
+from .configuration import Model
+from .utils import pushd
+
+if TYPE_CHECKING:
+ from typing import Sequence, Mapping, Any
+ from pandas import DataFrame
+ from ngen.cal.calibratable import Adjustable
+
+
+class BaseAgent(ABC):
+ """Abstract interface for Agent class."""
+ @property
+ def adjustables(self) -> 'Sequence[Adjustable]':
+ return self.model.adjustables
+
+ def restart(self) -> int:
+ with pushd(self.job.workdir):
+ starts = []
+ for adjustable in self.adjustables:
+ starts.append(adjustable.restart())
+ if all( x == starts[0] for x in starts):
+ #if everyone agrees on the iteration...
+ print('restart iteration from ', starts[0])
+ return starts[0]
+ else:
+ return 0
+
+ @property
+ @abstractmethod
+ def model(self) -> 'Model':
+ pass
+
+ @property
+ @abstractmethod
+ def job(self) -> 'JobMeta':
+ pass
+
+ def update_config(self, i: int, params: 'DataFrame', id: str):
+ """Update realization configuration file to execute BMI run at given iteration.
+
+ parameters
+ ---------
+ i : Current iteration of calibration
+ params : DataFrame containing the parameter name in `param` and value in `i` columns
+ id : catchment id
+
+ """
+ return self.model.update_config(i, params, id, path=self.job.workdir)
+
+ @property
+ def best_params(self) -> str:
+ return self.model.best_params
+
+
+class Agent(BaseAgent):
+ """This is class for agent."""
+ def __init__(self, model_conf: dict, workdir: 'Path', general: 'General', log: bool=False, restart: bool=False, agent_counter=0):
+ """Construct attributes for the Agent class."""
+ self._workdir = workdir
+ self._job = None
+ self._run_name = general.name
+ self._params = general.strategy.parameters
+ self._algorithm = general.strategy.algorithm.value
+ self._yaml_file = general.yaml_file
+ self._calib_path = general.calib_path
+ self._valid_path = general.valid_path
+ self._general = general
+ if restart and 'calib' in self._run_name:
+ # find prior ngen workdirs
+ # FIXME if a user starts with an independent calibration strategy
+ # then restarts with a uniform strategy, this will "work" but probably shouldn't.
+ # it works cause the independent writes a param df for the nexus that uniform also uses,
+ # so data "exists" and it doesn't know its not conistent...
+ # Conversely, if you start with uniform then try independent, it will start back at
+ # 0 correctly since not all basin params can be loaded.
+ # There are probably some similar issues with explicit and independent, since they have
+ # similar data semantics
+ workdirs = list(Path(workdir).rglob(model_conf['type']+"_*_worker"))
+ if( len(workdirs) > 1 and self._algorithm=="pso") :
+ print("More than one existing {} workdir, cannot restart")
+ else:
+ self._job = JobMeta(model_conf['type'], workdir, workdirs[agent_counter], log=log)
+
+ if(self._job is None):
+ self._job = JobMeta(model_conf['type'], workdir, log=log)
+
+ if 'calib' in self._run_name:
+ self._calib_path_output = os.path.join(self._job.workdir, 'Output_Calib')
+ self._output_iter_path = os.path.join(self._job.workdir, 'Output_Iteration')
+ self._plot_iter_path = os.path.join(self._job.workdir, 'Plot_Iteration')
+ os.makedirs(self._calib_path_output, exist_ok=True)
+ os.makedirs(self._output_iter_path, exist_ok=True)
+ os.makedirs(self._plot_iter_path, exist_ok=True)
+
+ if log and 'valid' in self._run_name:
+ self._valid_path_output = os.path.join(self._job.workdir, 'Output_Valid')
+ self._valid_path_plot = os.path.join(self._workdir, 'Plot_Valid')
+ os.makedirs(self._valid_path_output, exist_ok=True)
+ os.makedirs(self._valid_path_plot, exist_ok=True)
+ self._calib_path_output = None
+ self._output_iter_path = None
+ self._plot_iter_path = None
+
+ model_conf['workdir'] = self.job.workdir
+ self._model = Model(model=model_conf)
+ self._model.model.resolve_paths()
+
+ @property
+ def parameters(self) -> 'Mapping[str, Any]':
+ return self._params
+
+ @property
+ def workdir(self) -> 'Path':
+ return self._workdir
+
+ @property
+ def job(self) -> 'JobMeta':
+ return self._job
+
+ @property
+ def model(self) -> 'Model':
+ return self._model.model
+
+ @property
+ def cmd(self) -> str:
+ """Proxy method to build command from contained model binary and args."""
+ return "{} {}".format(self.model.get_binary(), self.model.get_args())
+
+ def create_valid_cmd(self, valid_config_file) -> str:
+ """Build command for validation run."""
+ arg1 = self.model.__root__.catchments.resolve()
+ arg2 = self.model.__root__.nexus.resolve()
+ valid_args = '{} "all" {} "all" {}'.format(arg1, arg2, valid_config_file)
+
+ return "{} {}".format(self.model.get_binary(), valid_args)
+
+ @property
+ def calib_path(self) -> 'Path':
+ """Directory for calibration run."""
+ return self._calib_path
+
+ @property
+ def calib_path_output(self) -> 'Path':
+ """Directory for calibration output."""
+ return self._calib_path_output
+
+ @property
+ def output_iter_path(self) -> 'Path':
+ """Directory for output at each calibration iteartion."""
+ return self._output_iter_path
+
+ @property
+ def plot_iter_path(self) -> 'Path':
+ """Directory for plots at each calibration iteartion"""
+ return self._plot_iter_path
+
+ @property
+ def valid_path(self) -> 'Path':
+ """Directory for output files of validation run."""
+ return self._valid_path
+
+ @property
+ def valid_path_output(self) -> 'Path':
+ """Directory for output files of validation run."""
+ return self._valid_path_output
+
+ @property
+ def valid_path_plot(self) -> 'Path':
+ """Directory for plots of validation run."""
+ return self._valid_path_plot
+
+ @property
+ def algorithm(self) -> str:
+ """Optimization algorithm."""
+ return self._algorithm
+
+ @property
+ def run_name(self) -> 'Path':
+ """Calibration or validation run."""
+ return self._run_name
+
+ @property
+ def yaml_file(self) -> 'Path':
+ """Calibration yaml file."""
+ return self._yaml_file
+
+ @property
+ def df_precip(self) -> float:
+ """Precipitation time series."""
+ return self.model.df_precip
+
+ @property
+ def model_params(self) -> dict:
+ """Model calibration parameters."""
+ return self.model.model_params
+
+ @property
+ def realization_file(self) -> 'Path':
+ """Model realization file."""
+ return self.model.realization_file
+
+ def duplicate(self, restart_flag=False, agent_counter=0) -> 'Agent':
+ #serialize a copy of the model
+ #FIXME ??? if you do self.model.resolve_paths() here, the duplicated agent
+ #doesn't have fully qualified paths...but if you do it in constructor, it works fine...
+ data = self.model.__root__.copy(deep=True)
+ #return a new agent, which has a unique Model instance
+ #and its own Job/workspace
+ return Agent(data.dict(by_alias=True), self._workdir, self._general, log=False, restart=restart_flag, agent_counter=agent_counter)
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/calibratable.py b/python/runCalibValid/ngen_cal/src/ngen/cal/calibratable.py
new file mode 100644
index 00000000..e3ea87d0
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/calibratable.py
@@ -0,0 +1,368 @@
+"""
+This module contains classes and methods to adjust catchment states.
+
+@author: Nels Frazer, Xia Feng
+"""
+
+from abc import ABC, abstractmethod
+from pathlib import Path
+import sys
+from typing import List, Optional, TYPE_CHECKING
+
+import pandas as pd
+from pandas import Series, read_parquet # type: ignore
+
+if TYPE_CHECKING:
+ from datetime import datetime
+ from pathlib import Path
+ from typing import Tuple, Callable
+ from pandas import DataFrame, Series
+ from .model import EvaluationOptions
+
+
+class Adjustable(ABC):
+ """
+ An Adjustable interface defning required properties for adjusting an object's state
+ """
+
+ def __init__(self, df: 'DataFrame'):
+ self._df = df.copy()
+ self._df.drop_duplicates(subset='param', inplace=True)
+ self._adf = df
+
+ @property
+ def df(self) -> 'DataFrame':
+ """
+ A dataframe of the objects parameter values to calculate indexed relative to the variables
+ being calibrated. The columns of the dataframe will be appended to with each search iterations
+ parameter value for that iteration.
+
+ Must have the following columns:
+ param: str Name of the parameters to calibrate
+ lower: float lower limit of the parameter value
+ upper: upper limit of the parameter value
+ 0: float initial value of the parameter
+ #TODO do we need a group index???
+ """
+ return self._df
+
+ def switch_param_name(self, mlst: List, snm: str, dnm: str) -> None:
+ """Switch parameter name
+
+ Parameters
+ ----------
+ mlst : list of model name
+ snm : source parameter name
+ dnm : destination parameter name
+
+ Returns
+ ----------
+ None
+
+ """
+ if any([m in self._adf['model'].unique() for m in mlst]):
+ for m in mlst:
+ if ((self._adf['model']==m) & (self._adf['param']==snm)).any():
+ self._adf.loc[(self._adf['model']==m) & (self._adf['param']==snm), 'param'] = dnm
+
+ def df_fill(self, iteration: int) -> None:
+ """Fill all parameter DataFrame with unique parameter DataFrame"""
+ filter_condition = 'LASAM' not in self._adf['model'].unique() or 'CFE' in self._adf['model'].unique()
+ if iteration>0:
+ if filter_condition:
+ self.switch_param_name(['SFT', 'SMP'], 'smcmax', 'maxsmc')
+ mdf = pd.merge(self._adf, self._df[['param', str(iteration)]], on='param')
+ mdf.sort_values(['model','fac'], inplace=True)
+ self._adf = mdf
+ if filter_condition:
+ self.switch_param_name(['SFT', 'SMP'], 'maxsmc', 'smcmax')
+ if iteration == 0:
+ self._df.reset_index(drop=True, inplace=True)
+ if not all(pd.Series(self._df.index.values)==self._df['fac']):
+ sys.exit('please check parameter order')
+
+ @property
+ def adf(self) -> 'DataFrame':
+ """Contains all calibration parameters"""
+ return self._adf
+
+ @property
+ @abstractmethod
+ def id(self) -> str:
+ """
+ An identifier for this unit, used to save unique checkpoint information.
+ """
+ pass
+
+ @property
+ def variables(self) -> 'Series':
+ """
+ Index series of variables
+ """
+ return Series(self.df.index.values)
+
+ @property
+ def bounds(self) -> 'Tuple[Series]':
+ """The bounds of each parameter that is adjustable
+
+ Returns:
+ Tuple[Series]: returns the (min,max) boundaries of the adjustable parameters
+ """
+ return (self.df['min'], self.df['max'])
+
+ @abstractmethod
+ def update_params(self, iteration: int) -> None:
+ """
+ FIXME update of parameter dataframe is currently done "inplace" -- there is no interface function
+ There likely *should* be one -- the big question is can it be "bundled" with the Evaluatable update function
+ or should it be a unique update/name, e.g. update_params(...) that does this? With the CalibrationMeta
+ refactored largely under the Evaluatable interface, there are a few options for this to consider.
+ Need to decide if this needs to remain???
+ Parameters
+ ----------
+ iteration:
+ int which column of the internal dataframe to use to update the model parameters from
+ """
+ pass
+
+ @property
+ def check_point_file(self) -> 'Path':
+ """
+ Filename checkpoint files are saved to
+ """
+ return Path('parameter_df_state_{}.parquet'.format(self.id))
+
+ def check_point(self, path: 'Path') -> None:
+ """
+ Save calibration information
+ """
+ self.df.to_parquet(path/self.check_point_file)
+
+ def load_df(self, path: 'Path') -> None:
+ """
+ Load saved calibration information
+ """
+ self._df = read_parquet(path/self.check_point_file)
+
+ @abstractmethod
+ def save_output(self, i: int) -> None:
+ """
+ Save the last output of the runtime for iteration i
+ """
+ pass
+
+ def restart(self) -> None:
+ self.load_df('./')
+
+
+class Evaluatable(ABC):
+ """
+ An Evaluatable interface defining required properties for a evaluating and object's state
+ """
+
+ eval_params: 'EvaluationOptions'
+
+ def __init__(self, eval_params: 'EvaluationOptions', **kwargs):
+ """
+ Args:
+ eval_params (EvaluationOptions): The options configuring this evaluatable
+ """
+ self.eval_params = eval_params
+
+ @property
+ @abstractmethod
+ def output(self) -> 'DataFrame':
+ """
+ The output data for the calibrated object
+ Calibration re-reads the output each call, as the output for given calibration is expected to change
+ for each calibration iteration. If the output doesn't exist, should raise RuntimeError
+ """
+ pass
+
+ @property
+ @abstractmethod
+ def observed(self) -> 'DataFrame':
+ """
+ The observed data for this calibratable.
+ This should be rather static, and can be set at initialization then accessed via the property
+ """
+ pass
+
+ @property
+ @abstractmethod
+ def evaluation_range(self) -> 'Tuple[datetime, datetime]':
+ """
+ The datetime range to evaluate the model results at.
+ This should be a tuple in the form of (start_time, end_time).
+ """
+ pass
+
+ @property
+ def objective(self, *args, **kwargs) -> 'Callable':
+ """
+ The objective function to compute cost values with.
+
+ Returns:
+ Callable: objective function which takes simulation and observation time series as args
+ """
+ return self.eval_params.objective
+
+ @property
+ def target(self, *args, **kwargs) -> str:
+ """
+ Minimize or maximize objective function
+ """
+ return self.eval_params.target
+
+ def update(self, i: int, score: float, log: bool, algorithm: str) -> None:
+ """_summary_
+
+ Args:
+ i (int): _description_
+ score (float): _description_
+ log (bool): _description_
+
+ Returns:
+ _type_: _description_
+ """
+ self.eval_params.update(i, score, log, algorithm)
+
+ @property
+ def best_params(self) -> str:
+ """_summary_
+
+ Returns:
+ str: _description_
+ """
+ return self.eval_params._best_params_iteration
+
+ @property
+ def best_score(self) -> float:
+ """_summary_
+
+ Returns:
+ float: _description_
+ """
+ return self.eval_params.best_score
+
+ @property
+ def basinID(self) -> str:
+ """Stream gage ID at the basin outlet"""
+ return self.eval_params.basinID
+
+ @property
+ def threshold(self) -> str:
+ """streamflow threshold for calculation of categorical scores"""
+ return self.eval_params.threshold
+
+ @property
+ def user(self) -> str:
+ """User's email address to receieve run complete message"""
+ return self.eval_params.user
+
+ @property
+ def station_name(self) -> str:
+ """gage station name"""
+ return self.eval_params.site_name
+
+ @property
+ def streamflow_name(self) -> str:
+ """Simulated streamflow variable name"""
+ return self.eval_params.streamflow_name
+
+ @property
+ def output_iter_file(self) -> 'Path':
+ """Output file at each iteration"""
+ return self.eval_params.output_iter_file
+
+ @property
+ def last_output_file(self) -> 'Path':
+ """Output file at last iteration"""
+ return self.eval_params.last_output_file
+
+ @property
+ def best_output_file(self) -> bool:
+ """Output file at best iteration"""
+ return self.eval_params.best_output_file
+
+ @property
+ def metric_iter_file(self) -> Path:
+ """file to store metrics at each iteration"""
+ return self.eval_params.metric_iter_file
+
+ @property
+ def param_iter_file(self) -> Path:
+ """file to store calibrated parameters at each iteration"""
+ return self.eval_params.param_iter_file
+
+ @property
+ def cost_iter_file(self) -> Path:
+ """file to store global and local best cost function at each iteration"""
+ return self.eval_params.cost_iter_file
+
+ @property
+ def best_save_flag(self) -> bool:
+ """Whether save output file at each iteration"""
+ return self.eval_params.best_save_flag
+
+ @property
+ def save_output_iter_flag(self) -> bool:
+ """Whether save output file at each iteration"""
+ return self.eval_params.save_output_iter_flag
+
+ @property
+ def save_plot_iter_flag(self) -> bool:
+ """Whether save plot file at each iteration"""
+ return self.eval_params.save_plot_iter_flag
+
+ @property
+ def save_plot_iter_freq(self) -> bool:
+ """Save plot file every specified iteration"""
+ return self.eval_params.save_plot_iter_freq
+
+ def write_metric_iter_file(self, i: int, score: float, metrics: float) -> None:
+ """Write statistical metrics at each iteration into csv file"""
+ return self.eval_params.write_metric_iter_file(i, score, metrics)
+
+ def write_param_iter_file(self, i: int, params: 'DataFrame') -> None:
+ """Write calibrated parameters at each iteration into csv file"""
+ return self.eval_params.write_param_iter_file(i, params)
+
+ def write_param_all_file(self, i: int, params: 'DataFrame') -> None:
+ """Write calibrated parameters at each iteration into csv file"""
+ return self.eval_params.write_param_all_file(i, params)
+
+ def write_last_iteration(self, i: int) -> None:
+ """Write completed iteration into csv file"""
+ return self.eval_params.write_last_iteration(i)
+
+ def write_cost_iter_file(self, i: int, calib_run_path: Path) -> None:
+ """Write global and local best cost function at each iteration into csv file"""
+ return self.eval_params.write_cost_iter_file(i, calib_run_path)
+
+ def write_hist_file(self, optimizer_result: 'SwarmOptimizer', agent: 'Agent', params_lst: list) -> Path:
+ """Write cost and position history plus gloal best position into csv files"""
+ return self.eval_params.write_hist_file(optimizer_result, agent, params_lst)
+
+ def create_valid_realization_file(self, agent: 'Agent', params: 'pd.DataFrame') -> None:
+ """Create configuration files for validation run"""
+ return self.eval_params.create_valid_realization_file(agent, params)
+
+ def write_valid_metric_file(self, valid_run_path: Path, run_name: str, metrics: float) -> None:
+ """Write statistical metrics files for validation run"""
+ return self.eval_params.write_valid_metric_file(valid_run_path, run_name, metrics)
+
+ def write_run_complete_file(self, run_name: str, path: Path) -> None:
+ """Write empty file if calibration or validation run is completed"""
+ return self.eval_params.write_run_complete_file(run_name, path)
+
+ def restart(self) -> int:
+ return self.eval_params.restart()
+
+
+class Calibratable(Adjustable, Evaluatable):
+ """
+ A Calibratable interface defining required properties for a calibratable object
+ """
+ def __init__(self, df: Optional['DataFrame'] = None):
+ Adjustable.__init__(self, df)
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/calibration_cathment.py b/python/runCalibValid/ngen_cal/src/ngen/cal/calibration_cathment.py
new file mode 100644
index 00000000..0e8a5521
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/calibration_cathment.py
@@ -0,0 +1,148 @@
+"""
+This module creates interface to adjust parameters, store
+output and observation, and perform evaluation for catchments.
+
+@author: Nels Frazer
+"""
+
+import shutil
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from datetime import datetime
+ from pathlib import Path
+ from typing import Tuple
+ from pandas import DataFrame
+ from geopandas import GeoSeries
+ from .model import EvaluationOptions
+
+from pandas import DataFrame, read_csv # type: ignore
+
+from hypy.catchment import FormulatableCatchment # type: ignore
+from hypy.nexus import Nexus
+
+from .calibratable import Adjustable, Evaluatable
+
+
+class AdjustableCatchment(FormulatableCatchment, Adjustable):
+ """A Formulatable catchment that has an Adjustable interface to adjust
+ parameteters used by the catchment.
+ """
+
+ def __init__(self, workdir: 'Path', id: str, nexus, params: dict = {}):
+ """Create an adjustable catchment and initialize its parameter space.
+
+ Parameters:
+ ----------
+ workdir: Working directory
+ id : Catchment id of this unit
+ nexus : Downstream nexus associated with the catchment
+ params : Mapping of parameter names and values. Defaults to {}
+
+ """
+ FormulatableCatchment.__init__(self=self, catchment_id=id, params=params, outflow=nexus)
+ Adjustable.__init__(self=self, df=DataFrame(params).rename(columns={'init': '0'}))
+ #FIXME paramterize
+ self._output_file = workdir/'{}.csv'.format(self.id)
+ self._workdir = workdir
+
+ def save_output(self, i) -> None:
+ """
+ Save the last output to output for iteration i
+ """
+ shutil.move(self._output_file, '{}_last'.format(self._output_file))
+
+ #update handled in meta, TODO remove this method???
+ def update_params(self, iteration: int) -> None:
+ pass
+
+
+class EvaluatableCatchment(Evaluatable):
+ """
+ A catchment which is "observable" which means model output can be evaluated against
+ these observations for this catchment.
+ """
+ def __init__(self, nexus: Nexus, start_time: str, end_time: str, fabric: "GeoSeries", output_var: str, eval_params: 'EvaluationOptions'):
+ """Initialize the evaluatable catchment.
+
+ Parameters:
+ nexus : An NWIS nexus to query stream flow data from
+ start_time : Starting datetime to request observations for
+ end_time : Ending datetime to request observations for
+ fabric : The catchment hydrofabric representation
+ params : _description_. Defaults to {}.
+
+ """
+ super().__init__(eval_params)
+ self._outflow = nexus
+ # If no `main_output_variable`, default to Q_OUT
+ self._output_var = output_var
+
+ # Use the nwis location to pull observation data
+ obs = self.outflow._hydro_location.get_data(start_time, end_time)
+ self._observed = obs.set_index('value_time')['value'].resample('1H').nearest()
+ self._observed.rename('obs_flow', inplace=True)
+
+ # Convert observation from ft^3/s to m^3/s
+ self._observed = self._observed * 0.028316847
+ self._output = None
+ self._fabric = fabric
+ self._eval_range = self.eval_params._eval_range
+
+ @property
+ def evaluation_range(self) -> 'Tuple[datetime, datetime]':
+ return self._eval_range
+
+ @property
+ def output(self) -> 'DataFrame':
+ """adjsut
+ The model output hydrograph for this catchment
+ This re-reads the output file each call, as the output for given calibration catchment changes
+ for each calibration iteration. If it doesn't exist, should return None
+ """
+ try:
+ self._output = read_csv(self._output_file, usecols=["Time", self._output_var], parse_dates=['Time'], index_col='Time', dtype={self._output_var: 'float64'})
+ self._output.rename(columns={self._output_var:'sim_flow'}, inplace=True)
+
+ # Assume model catchment outputs are in m/hr, convert to m^3/s
+ self._output = self._output * self._fabric['area_sqkm']*1000000/3600
+ hydrograph = self._output
+ except FileNotFoundError:
+ hydrograph = None
+ except Exception as e:
+ raise(e)
+ return hydrograph
+
+ @output.setter
+ def output(self, df):
+ self._output = df
+
+ @property
+ def observed(self) -> 'DataFrame':
+ """The observed hydrograph for this catchment FIXME move output/observed to calibratable?"""
+ hydrograph = self._observed
+ if hydrograph is None:
+ raise(RuntimeError("Error reading observation for {}".format(self._id)))
+ return hydrograph
+
+ @observed.setter
+ def observed(self, df):
+ self._observed = df
+
+
+class CalibrationCatchment(AdjustableCatchment, EvaluatableCatchment):
+ """A Calibratable interface defining required properties for a calibratable object."""
+ def __init__(self, workdir: str, id: str, nexus: Nexus, start_time: str, end_time: str, fabric: "GeoSeries", output_var: str, eval_params: 'EvaluationOptions', params: dict = {}):
+ EvaluatableCatchment.__init__(self, nexus, start_time, end_time, fabric, output_var, eval_params)
+ AdjustableCatchment.__init__(self, workdir, id, nexus, params)
+
+ def restart(self) -> int:
+ #TODO validate the dataframe
+ restart_iteration = 0
+ try:
+ super(AdjustableCatchment, self).load_df(self._workdir)
+ restart_iteration = super(EvaluatableCatchment, self).restart()
+ except FileNotFoundError:
+ pass
+ return restart_iteration
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/calibration_set.py b/python/runCalibValid/ngen_cal/src/ngen/cal/calibration_set.py
new file mode 100644
index 00000000..13566262
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/calibration_set.py
@@ -0,0 +1,292 @@
+"""
+This module creates interface to adjust parameters, store
+observation, and save streamflow from calibration and validation
+runs and perform evaluation for a set of calibration catchments.
+
+@author: Nels Frazer, Xia Feng
+"""
+
+import glob
+import os
+from pathlib import Path
+import shutil
+import time
+from typing import TYPE_CHECKING, Sequence
+
+import netCDF4
+import pandas as pd
+from pandas import DataFrame# type: ignore
+
+from hypy.nexus import Nexus
+from .calibratable import Adjustable, Evaluatable
+
+if TYPE_CHECKING:
+ from datetime import datetime
+ from pathlib import Path
+ from typing import Tuple
+ from pandas import DataFrame
+ from .model import EvaluationOptions
+
+
+class CalibrationSet(Evaluatable):
+ """A HY_Features based catchment with additional calibration information/functionality."""
+ def __init__(self,
+ adjustables: Sequence[Adjustable],
+ eval_nexus: Nexus,
+ routing_output: 'Path',
+ start_time: str,
+ end_time: str,
+ eval_params: 'EvaluationOptions',
+ obsflow_file: 'Path',
+ wb_lst: list,
+) -> None:
+ """Construct attributes for the CalibrationSet object.
+
+ Parameters
+ ----------
+ adjustables: Adjustable object
+ eval_nexus : Obesrvable nexus ID
+ routing_output : Routing output file
+ start_time : Starting simulation time
+ end_time : Endig simulation time
+ eval_params : EvaluationOptions object
+ obsflow_file : Streamflow observation file
+
+ """
+ super().__init__(eval_params)
+ self._eval_nexus = eval_nexus
+ self._adjustables = adjustables
+ self._output_file = routing_output
+
+ # Read observation data if observation file is provided
+ if os.path.exists(obsflow_file):
+ obs = pd.read_csv(obsflow_file)
+ obs['value_date'] = pd.DatetimeIndex(obs['value_date'])
+ self._observed = obs.set_index('value_date')
+ else:
+ # Otherwise pull observation from NWIS portal on-the-fly
+ obs =self._eval_nexus._hydro_location.get_data(start_time, end_time)
+ self._observed = obs.set_index('value_time')['value'].resample('1H').nearest()
+ self._observed.rename('obs_flow', inplace=True)
+ self._observed = self._observed * 0.028316847 # Convert observation from ft^3/s to m^3/s
+
+ self._output = None
+ self._eval_range = self.eval_params._eval_range
+ self._valid_eval_range = self.eval_params._valid_eval_range
+ self._full_eval_range = self.eval_params._full_eval_range
+ self._wb_lst = wb_lst
+
+ @property
+ def evaluation_range(self) -> 'Tuple[datetime, datetime]':
+ return self._eval_range
+
+ @property
+ def valid_evaluation_range(self) -> 'Tuple[datetime, datetime]':
+ return self._valid_eval_range
+
+ @property
+ def full_evaluation_range(self) -> 'Tuple[datetime, datetime]':
+ return self._full_eval_range
+
+ @property
+ def adjustables(self):
+ return self._adjustables
+
+ @property
+ def output(self) -> 'DataFrame':
+ """
+ The model output hydrograph for this catchment
+ This re-reads the output file each call, as the output for given calibration catchment changes
+ for each calibration iteration. If it doesn't exist, should return None
+ """
+ try:
+ # Read the routed flow at the eval_nexus
+ ncvar=netCDF4.Dataset(self._output_file, "r")
+ fid_index = [list(ncvar['feature_id'][0:]).index(int(fid)) for fid in self._wb_lst]
+ self._output = pd.DataFrame(data={'sim_flow': pd.DataFrame(ncvar['flow'][fid_index], index=fid_index).T.sum(axis=1)})
+
+ # Get date
+ tnx_file = list(Path(self._output_file).parent.glob("nex*.csv"))[0]
+ tnx_df = pd.read_csv(tnx_file, index_col=0, parse_dates=[1], names=['ts', 'time', 'Q']).set_index('time')
+ dt_range = pd.date_range(tnx_df.index[1], tnx_df.index[-1], len(self._output.index)).round('min')
+ self._output.index = dt_range
+ self._output.index.name='Time'
+ self._output = self._output.resample('1H').first()
+ hydrograph = self._output
+
+ except FileNotFoundError:
+ print("{} not found. Current working directory is {}".format(self._output_file, os.getcwd()))
+ print("Setting output to None")
+ hydrograph = None
+ except Exception as e:
+ raise(e)
+
+ return hydrograph
+
+ @output.setter
+ def output(self, df):
+ self._output = df
+
+ @property
+ def observed(self) -> 'DataFrame':
+ """Observed hydrograph for this catchment."""
+ hydrograph = self._observed
+ if hydrograph is None:
+ raise(RuntimeError("Error reading observation for {}".format(self._id)))
+ return hydrograph
+
+ @observed.setter
+ def observed(self, df):
+ self._observed = df
+
+ def save_output(self, i) -> None:
+ """Save the last output to output for iteration i."""
+ if os.path.exists(elf._output_file):
+ shutil.move(self._output_file, '{}_last'.format(self._output_file))
+
+ def check_point(self, path: 'Path') -> None:
+ """Save calibration information."""
+ for adjustable in self.adjustables:
+ adjustable.df.to_parquet(path/adjustable.check_point_file)
+
+ def restart(self) -> int:
+ try:
+ for adjustable in self.adjustables:
+ adjustable.restart()
+ except FileNotFoundError:
+ return 0
+ return super().restart()
+
+
+class UniformCalibrationSet(CalibrationSet, Adjustable):
+ """A HY_Features based catchment with additional calibration information/functionality"""
+ def __init__(self,
+ eval_nexus: Nexus,
+ routing_output: 'Path',
+ start_time: str,
+ end_time: str,
+ eval_params: 'EvaluationOptions',
+ obsflow_file: 'Path',
+ wb_lst: list,
+ params: dict = {},
+) -> None:
+ """Constructor for the UniformCalibrationSet object."""
+ super().__init__(adjustables=[self], eval_nexus=eval_nexus, routing_output=routing_output, start_time=start_time, end_time=end_time, eval_params=eval_params, obsflow_file=obsflow_file, wb_lst=wb_lst)
+ Adjustable.__init__(self=self, df=DataFrame(params).rename(columns={'init': '0'}))
+
+ #For now, set this to None so meta update does the right thing
+ #at some point, may want to refactor model update to handle this better
+ self._id = None
+
+ # Required Adjustable properties
+ @property
+ def id(self) -> str:
+ """An identifier for this unit, used to save unique checkpoint information."""
+ return self._id
+
+ def save_output(self, i) -> None:
+ """
+ Save the last output to output for iteration i
+ """
+ #FIXME ensure _output_file exists
+ #FIXME re-enable this once more complete
+ shutil.move(self._output_file, '{}_last'.format(self._output_file))
+
+ def save_calib_output(self, i, output_iter_file: 'Path', last_output_file: 'Path', calib_path1: 'Path',
+ calib_path2: 'Path', calib_path3: Path = None, save_output_iter_flag=False) -> None:
+ """Save model output from calibration run.
+
+ Parameters:
+ ----------
+ i : iteration
+ output_iter_file : output file at each iteration
+ last_output_file : last output file
+ calib_path1 : directory to store streamflow file at each iteration
+ calib_path2 : current agent job directory
+ calib_path3 : directory to store catchment and nexsus output plus other output files, default None
+ save_output_iter_flag : whether to save output at each iteration
+
+ """
+ if os.path.exists(self._output_file):
+ flow_output = self._output.reset_index()
+ flow_output = flow_output.rename(columns={'index': 'Time'})
+ if i ==0 or save_output_iter_flag:
+ filename_iter = os.path.join(calib_path1, output_iter_file + str('{:04d}').format(i) +'.csv')
+ flow_output.to_csv(filename_iter, index=False)
+ flow_output.to_csv(last_output_file, index=False)
+ shutil.move(self._output_file, os.path.join(os.path.dirname(last_output_file), '{}_last'.format(self._output_file)))
+ if calib_path3 is None:
+ calib_path3 = calib_path2
+ for csvfl in glob.glob(os.path.join(calib_path2, 'nex*.csv')):
+ shutil.move(csvfl, calib_path3 + '/' + os.path.basename(csvfl))
+ for csvfl in glob.glob(os.path.join(calib_path2, 'cat*.csv')):
+ shutil.move(csvfl, calib_path3 + '/' + os.path.basename(csvfl))
+ if len(glob.glob(os.path.join(calib_path2, '*.out')))>0:
+ for outfl in glob.glob(os.path.join(calib_path2, '*.out')):
+ shutil.move(outfl, calib_path3 + '/' + os.path.basename(outfl))
+
+ def save_best_output(self, best_output_file: 'Path', best_save_flag = False) -> None:
+ """Save the output at the best iteration
+
+ Parameters:
+ ----------
+ best_output_file : Best output file name
+ best_save_flag : Whether save output as best output
+
+ """
+ if self._output is not None and best_save_flag:
+ flow_output = self._output.reset_index()
+ flow_output = flow_output.rename(columns={'index': 'Time'})
+ flow_output.to_csv(best_output_file, index=False)
+
+ def save_valid_output(self, basinid: str, run_name: str, valid_path1: 'Path', valid_path2: 'Path', valid_path3: 'Path') -> None:
+ """Save model output from validation run.
+
+ Parameters:
+ ----------
+ run_name : Control or best run
+ valid_path1 : Validation run main directory
+ valid_path2 : Validation run job work directory
+ valid_path3 : Subdrirectory under valid_path2 to store output files
+
+ """
+ if os.path.exists(self._output_file):
+ flow_output = self._output.reset_index()
+ flow_output = flow_output.rename(columns={'index': 'Time'})
+ filename_valid = os.path.join(valid_path1, basinid + '_output_' + run_name + '.csv')
+ flow_output.to_csv(filename_valid, index=False)
+ shutil.move(self._output_file, os.path.join(valid_path2, '{}_'.format(self._output_file) + run_name))
+ for csvfl in glob.glob(os.path.join(valid_path2, 'nex*.csv')):
+ shutil.move(csvfl, valid_path3 + '/' + os.path.basename(csvfl).split('.')[0] + '_{}'.format(run_name) +'.csv')
+ for csvfl in glob.glob(os.path.join(valid_path2, 'cat*.csv')):
+ shutil.move(csvfl, valid_path3 + '/' + os.path.basename(csvfl).split('.')[0] + '_{}'.format(run_name) +'.csv')
+ if len(glob.glob(os.path.join(valid_path2, '*.out')))>0:
+ for outfl in glob.glob(os.path.join(valid_path2, '*.out')):
+ shutil.move(outfl, valid_path3 + '/' + os.path.basename(outfl).split('.')[0] + '_{}'.format(run_name) +'.out')
+
+ # Update handled in meta, TODO remove this method???
+ def update_params(self, iteration: int) -> None:
+ pass
+
+ # Override this file name
+ @property
+ def check_point_file(self) -> 'Path':
+ return Path('parameter_df_state_{}.parquet'.format(self._eval_nexus.id))
+
+ def restart(self):
+ """Prepare for calibration restart run."""
+ # Reload the evaluation information
+ start_iteration = Evaluatable.restart(self)
+ try:
+ # Reload the param space for the adjustable
+ Adjustable.restart(self)
+ shutil.copy(str(self.check_point_file), str(self.check_point_file) + '_before_restart_' + time.strftime('%Y%m%d_%H%M%S'))
+ try:
+ self.df.pop(str(start_iteration))
+ self.check_point('./')
+ except KeyError:
+ pass
+ except FileNotFoundError:
+ return 0
+
+ return start_iteration
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/configuration.py b/python/runCalibValid/ngen_cal/src/ngen/cal/configuration.py
new file mode 100644
index 00000000..2ed4ca4f
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/configuration.py
@@ -0,0 +1,84 @@
+"""
+This module implements several classes to hold generation confugrations.
+
+@author: Nels Frazer, Xia Feng
+"""
+
+from __future__ import annotations #for pydnaitc
+
+import logging
+import os
+from pathlib import Path
+from typing import Optional, Union
+try: #to get literal in python 3.7, it was added to typing in 3.8
+ from typing import Literal
+except ImportError:
+ from typing_extensions import Literal
+
+from pydantic import BaseModel, Field, DirectoryPath
+
+from .model import PosInt
+from .ngen import Ngen
+from .strategy import Estimation, Sensitivity
+
+logging.basicConfig(
+ level=logging.DEBUG,
+ format="%(asctime)s,%(msecs)d %(levelname)s: %(message)s",
+ datefmt="%H:%M:%S")
+
+
+class General(BaseModel):
+ """General configuration class."""
+ # Required fields
+ strategy: Union[Estimation, Sensitivity] = Field(discriminator='type')
+ iterations: int
+ # Fields with reasonable defaults
+ restart: bool = False
+ start_iteration: PosInt = 0
+ workdir: DirectoryPath = Path("./")
+ name: str
+ yaml_file: Path
+ # Optional fields
+ log: Optional[bool] = False
+ parameter_log_file: Optional[Path]
+ objective_log_file: Optional[Path]
+ random_seed: Optional[int]
+ # Private
+ _calib_path: Path
+ _valid_path: Path
+
+ class Config:
+ """Override configuration for pydantic BaseModel."""
+ underscore_attrs_are_private = True
+ use_enum_values = True
+ smart_union = True
+
+ def __init__(self, **kwargs):
+ super().__init__(**kwargs)
+ self._calib_path = os.path.join(str(self.workdir) + '/Output', 'Calibration_Run')
+ self._valid_path = os.path.join(str(self.workdir) + '/Output', 'Validation_Run')
+ try:
+ os.makedirs(self._calib_path, exist_ok=True)
+ os.makedirs(self._valid_path, exist_ok=True)
+ except OSError as error:
+ print(error)
+
+ @property
+ def calib_path(self) -> 'Path':
+ """Directory for calibration run."""
+ return self._calib_path
+
+ @property
+ def valid_path(self) -> 'Path':
+ """Directory for validation run."""
+ return self._valid_path
+
+
+class NoModel(BaseModel):
+ """A simple empty model data class for testing."""
+ type: Literal['none']
+
+
+class Model(BaseModel):
+ """Composition data class for defining a model configuration."""
+ model: Union[Ngen, NoModel] = Field(discriminator='type')
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/gwo_global_best.py b/python/runCalibValid/ngen_cal/src/ngen/cal/gwo_global_best.py
new file mode 100644
index 00000000..83cb9ba2
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/gwo_global_best.py
@@ -0,0 +1,230 @@
+"""
+This module performs parameter calibration using grey wolf optimization.
+It contains third party open source codes, class GlobalBestGWO from pyswarms
+and class gwo from SwarmPackagePy. Author made further modifications.
+
+@author: Xia Feng
+
+----------------------------------------------------------------------------
+
+pyswarms complies with MIT License as follows:
+
+Copyright (c) 2017, Lester James V. Miranda
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+
+import logging
+from collections import deque
+import multiprocessing as mp
+
+import numpy as np
+
+from pyswarms.backend.operators import compute_pbest, compute_objective_function
+from pyswarms.backend.topology import Star
+from pyswarms.utils.reporter import Reporter
+
+from .gwo_swarms import SwarmOptimizer
+
+
+class GlobalBestGWO(SwarmOptimizer):
+ def __init__(
+ self,
+ n_particles,
+ dimensions,
+ bounds=None,
+ center=1.00,
+ ftol=-np.inf,
+ ftol_iter=1,
+ init_pos=None,
+ start_iter=0,
+ calib_path='./',
+ basinid=None,
+ ):
+ """Initialize the swarm
+
+ Attributes
+ ----------
+ n_particles : int
+ number of particles in the swarm.
+ dimensions : int
+ number of dimensions in the space.
+ bounds : tuple of numpy.ndarray, optional
+ a tuple of size 2 where the first entry is the minimum bound while
+ the second entry is the maximum bound. Each array must be of shape
+ :code:`(dimensions,)`.
+ bh_strategy : str
+ a strategy for the handling of out-of-bounds particles.
+ center : list (default is :code:`None`)
+ an array of size :code:`dimensions`
+ ftol : float
+ relative error in objective_func(best_pos) acceptable for
+ convergence. Default is :code:`-np.inf`
+ ftol_iter : int
+ number of iterations over which the relative error in
+ objective_func(best_pos) is acceptable for convergence.
+ Default is :code:`1`
+ init_pos : numpy.ndarray, optional
+ option to explicitly set the particles' initial positions. Set to
+ :code:`None` if you wish to generate the particles randomly.
+ """
+ super(GlobalBestGWO, self).__init__(
+ n_particles=n_particles,
+ dimensions=dimensions,
+ bounds=bounds,
+ center=center,
+ ftol=ftol,
+ ftol_iter=ftol_iter,
+ init_pos=init_pos,
+ start_iter=start_iter,
+ calib_path=calib_path,
+ basinid=basinid,
+ )
+
+ # Initialize logger
+ self.rep = Reporter(logger=logging.getLogger(__name__))
+ # Initialize the resettable attributes
+ self.reset()
+ # Initialize the topology
+ self.top = Star()
+ self.name = __name__
+
+ def optimize(
+ self, objective_func, iters, n_processes=None, verbose=True, **kwargs
+ ):
+ """Optimize the swarm for a number of iterations
+
+ Performs the optimization to evaluate the objective
+ function :code:`f` for a number of iterations :code:`iter.`
+
+ Parameters
+ ----------
+ objective_func : callable
+ objective function to be evaluated
+ iters : int
+ number of iterations
+ n_processes : int
+ number of processes to use for parallel particle evaluation (default: None = no parallelization)
+ verbose : bool
+ enable or disable the logs and progress bar (default: True = enable logs)
+ kwargs : dict
+ arguments for the objective function
+
+ Returns
+ -------
+ tuple
+ the global best cost and the global best position.
+ """
+ # Apply verbosity
+ if self.start_iter>0:
+ verbose = False
+ if verbose:
+ log_level = logging.INFO
+ else:
+ log_level = logging.NOTSET
+
+ self.rep.log("Obj. func. args: {}".format(kwargs), lvl=logging.DEBUG)
+ self.rep.log(
+ "Optimize for {} iters with {} particles and {} dimensions".format(iters, self.n_particles, self.dimensions),
+ lvl=log_level,
+ )
+
+ # Setup Pool of processes for parallel evaluation
+ pool = None if n_processes is None else mp.Pool(n_processes)
+
+ ftol_history = deque(maxlen=self.ftol_iter)
+
+ # Compute cost of initial swarm
+ if self.start_iter == 0:
+ print("Compute cost of the initial swarm at iteration 1")
+ self.swarm.current_cost = compute_objective_function(self.swarm, objective_func, pool=pool, **kwargs)
+ self.swarm.pbest_cost = self.swarm.current_cost
+ self.swarm.pbest_pos = self.swarm.position
+ alpha, beta, delta = self.__get_abd(self.swarm.n_particles, self.swarm.current_cost)
+ self.update_history(1)
+ initial_iter = self.start_iter
+ else:
+ print("Restart at iteration", self.start_iter)
+ alpha, beta, delta = self.swarm.leader_pos[0], self.swarm.leader_pos[1], self.swarm.leader_pos[2]
+ initial_iter = self.start_iter - 2
+
+ for i in self.rep.pbar(iters, self.name) if verbose else range(initial_iter, iters):
+ a = 2 - 2 * i / iters
+ # Random parameters for alpha wolf
+ r1 = np.random.random((self.n_particles, self.dimensions))
+ r2 = np.random.random((self.n_particles, self.dimensions))
+ A1 = 2 * r1 * a - a
+ C1 = 2 * r2
+ # Random parameters for beta wolf
+ r1 = np.random.random((self.n_particles, self.dimensions))
+ r1 = np.random.random((self.n_particles, self.dimensions))
+ r2 = np.random.random((self.n_particles, self.dimensions))
+ A2 = 2 * r1 * a - a
+ C2 = 2 * r2
+ # Random parameters for delta wolf
+ r1 = np.random.random((self.n_particles, self.dimensions))
+ r2 = np.random.random((self.n_particles, self.dimensions))
+ A3 = 2 * r1 * a - a
+ C3 = 2 * r2
+ # Distance between candidate wolves and leading wolves
+ Dalpha = abs(C1 * alpha - self.swarm.position)
+ Dbeta = abs(C2 * beta - self.swarm.position)
+ Ddelta = abs(C3 * delta - self.swarm.position)
+ # Update position of candidate wolves
+ X1 = alpha - A1 * Dalpha
+ X2 = beta - A2 * Dbeta
+ X3 = delta - A3 * Ddelta
+ self.swarm.position = (X1 + X2 + X3) / 3
+ self.swarm.position = np.clip(self.swarm.position, self.bounds[0], self.bounds[1])
+ # Compute current cost and update local best
+ self.swarm.current_cost = compute_objective_function(self.swarm, objective_func, pool=pool, **kwargs)
+ self.swarm.pbest_pos, self.swarm.pbest_cost = compute_pbest(self.swarm)
+ # Update leader and best cost and the corresponding positions
+ alpha, beta, delta = self.__get_abd(self.swarm.n_particles, self.swarm.current_cost)
+ # Compute best cost and position
+ if verbose:
+ self.rep.hook(best_cost=self.swarm.best_cost)
+ # save history
+ self.update_history(i+2)
+
+ # Obtain the final best_cost and the final best_position
+ final_best_cost = self.swarm.best_cost.copy()
+ final_best_pos = self.swarm.best_pos.copy()
+ # Write report in log and return final cost and position
+ self.rep.log("Optimization finished | best cost: {}, best pos: {}".format(final_best_cost, final_best_pos), lvl=log_level)
+ # Close Pool of Processes
+ if n_processes is not None:
+ pool.close()
+ return (final_best_cost, final_best_pos)
+
+ def __get_abd(self, n, fitness):
+ result = []
+ fitness = [(fitness[i], i) for i in range(n)]
+ fitness.sort()
+ for i in range(3):
+ result.append(self.swarm.position[fitness[i][1]])
+
+ self.swarm.leader_pos = np.array(result)
+ self.swarm.leader_cost = [fitness[i][0] for i in range(3)]
+
+ if self.swarm.leader_cost[0] < self.swarm.best_cost:
+ self.swarm.best_cost = self.swarm.leader_cost[0]
+ self.swarm.best_pos = self.swarm.leader_pos[0]
+
+ return result
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/gwo_swarms.py b/python/runCalibValid/ngen_cal/src/ngen/cal/gwo_swarms.py
new file mode 100644
index 00000000..b134f757
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/gwo_swarms.py
@@ -0,0 +1,467 @@
+"""
+This module contains classes/functions to support swarm optimization.
+It contains third party open source codes from pyswarms, including class
+GlobalBestGWO, class Swarms and function create_swarm.
+Author modified these codes and added function write_hist_iter_file
+and read_hist_iter_file.
+
+@author: Xia Feng
+
+----------------------------------------------------------------------------
+
+pyswarms complies with MIT License:
+
+Copyright (c) 2017, Lester James V. Miranda
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+
+import abc
+from collections import namedtuple
+import logging
+
+import os
+import shutil
+import time
+from typing import Tuple
+
+from attr import attrib, attrs
+from attr.validators import instance_of
+import numpy as np
+import pandas as pd
+
+from pyswarms.utils.reporter import Reporter
+from pyswarms.backend import generate_swarm
+
+
+class SwarmOptimizer(abc.ABC):
+ def __init__(
+ self,
+ n_particles,
+ dimensions,
+ bounds=None,
+ center=1.0,
+ ftol=-np.inf,
+ ftol_iter=1,
+ init_pos=None,
+ start_iter=0,
+ calib_path='./',
+ basinid=None,
+ ):
+ """Initialize the swarm
+
+ Creates a Swarm class depending on the values initialized
+
+ Attributes
+ ----------
+ n_particles : int
+ number of particles in the swarm.
+ dimensions : int
+ number of dimensions in the space.
+ bounds : tuple of numpy.ndarray, optional
+ a tuple of size 2 where the first entry is the minimum bound
+ while the second entry is the maximum bound. Each array must
+ center : list, optional
+ an array of size :code:`dimensions`
+ ftol : float, optional
+ relative error in objective_func(best_pos) acceptable for
+ convergence. Default is :code:`-np.inf`.
+ ftol_iter : int
+ number of iterations over which the relative error in
+ objective_func(best_pos) is acceptable for convergence.
+ Default is :1
+ """
+ # Initialize primary swarm attributes
+ self.n_particles = n_particles
+ self.dimensions = dimensions
+ self.bounds = bounds
+ self.swarm_size = (n_particles, dimensions)
+ self.center = center
+ self.ftol = ftol
+ self.start_iter = start_iter
+ self.hist_path = os.path.join(calib_path, 'History_Iteration')
+ os.makedirs(self.hist_path, exist_ok=True)
+ self.cost_iter_file = os.path.join(self.hist_path, '{}_cost_iteration.csv'.format(basinid))
+ self.pbest_cost_iter_file = os.path.join(self.hist_path, '{}_pbest_cost_iteration.csv'.format(basinid))
+ self.pbest_pos_iter_file = os.path.join(self.hist_path, '{}_pbest_pos_iteration.csv'.format(basinid))
+ self.leader_cost_iter_file = os.path.join(self.hist_path, '{}_leader_cost_iteration.csv'.format(basinid))
+ self.pos_iter_file = os.path.join(self.hist_path, '{}_pos_iteration.csv'.format(basinid))
+ self.leader_pos_iter_file = os.path.join(self.hist_path, '{}_leader_pos_iteration.csv'.format(basinid))
+
+ try:
+ assert ftol_iter > 0 and isinstance(ftol_iter, int)
+ except AssertionError:
+ raise AssertionError(
+ "ftol_iter expects an integer value greater than 0"
+ )
+
+ self.ftol_iter = ftol_iter
+ self.init_pos = init_pos
+ # Initialize named tuple for populating the history list
+ self.ToHistory = namedtuple(
+ "ToHistory",
+ [
+ "best_cost",
+ "pbest_cost",
+ "mean_pbest_cost",
+ "leader_cost",
+ "mean_leader_cost",
+ "position",
+ "leader_position",
+ ],
+ )
+ # Initialize resettable attributes
+ self.reset()
+
+
+ def _populate_history(self, hist):
+ """Populate all history lists.
+
+ The :code:`cost_history`, :code:`mean_pbest_history`, and
+ :code:`neighborhood_best` is expected to have a shape of
+ :code:`(iters,)`,on the other hand, the :code:`pos_history`
+ and :code:`velocity_history` are expected to have a shape of
+ :code:`(iters, n_particles, dimensions)`
+
+ Parameters
+ ----------
+ hist : collections.namedtuple
+ Must be of the same type as self.ToHistory
+ """
+ self.cost_history.append(hist.best_cost)
+ self.pbest_history.append(hist.pbest_cost)
+ self.mean_pbest_history.append(hist.mean_pbest_cost)
+ self.leader_history.append(hist.leader_cost)
+ self.mean_leader_history.append(hist.mean_leader_cost)
+ self.pos_history.append(hist.position)
+ self.leader_pos_history.append(hist.leader_position)
+
+
+ def write_hist_iter_file(self, i: int) -> None:
+ """Write variables generated at each iteration.
+
+ Parameters
+ ----------
+ i : current iteration
+ """
+ df_cost = pd.DataFrame({'iteration': i, 'global_best': self.swarm.best_cost, 'mean_local_best': np.mean(self.swarm.pbest_cost),
+ 'mean_leader_best': np.mean(self.swarm.leader_cost)}, index=[0])
+ df_cost.to_csv(self.cost_iter_file, mode='a', index=False, header=not os.path.exists(self.cost_iter_file))
+
+ pbest_cost = pd.DataFrame(self.swarm.pbest_cost, columns=['local_best'])
+ pbest_cost['iteration'] = i
+ pbest_cost['agent'] = range(self.n_particles)
+ pbest_cost.to_csv(self.pbest_cost_iter_file, mode='a', index=False, header=not os.path.exists(self.pbest_cost_iter_file))
+
+ leader_cost = pd.DataFrame(self.swarm.leader_cost, columns=['leader_best'])
+ leader_cost['iteration'] = i
+ leader_cost['rank'] = range(1, 4)
+ leader_cost.to_csv(self.leader_cost_iter_file, mode='a', index=False, header=not os.path.exists(self.leader_cost_iter_file))
+
+ pos = pd.DataFrame(self.swarm.position)
+ pos['iteration'] = i
+ pos['agent'] = range(self.n_particles)
+ pos.to_csv(self.pos_iter_file, mode='a', index=False, header=not os.path.exists(self.pos_iter_file))
+
+ pbest_pos = pd.DataFrame(self.swarm.pbest_pos)
+ pbest_pos['iteration'] = i
+ pbest_pos['agent'] = range(self.n_particles)
+ pbest_pos.to_csv(self.pbest_pos_iter_file, mode='a', index=False, header=not os.path.exists(self.pbest_pos_iter_file))
+
+ leader_pos = pd.DataFrame(self.swarm.leader_pos)
+ leader_pos['iteration'] = i
+ leader_pos['rank'] = range(1, 4)
+ leader_pos.to_csv(self.leader_pos_iter_file, mode='a', index=False, header=not os.path.exists(self.leader_pos_iter_file))
+
+
+ def read_hist_iter_file(self) -> Tuple:
+ """Read variables used in optimization and clean up files.
+
+ Returns
+ ----------
+ history of variables and the current values
+ """
+ iteration = self.start_iter
+ df_cost = pd.read_csv(self.cost_iter_file)
+ shutil.copy(str(self.cost_iter_file), str(self.cost_iter_file) + '_before_restart_' + time.strftime('%Y%m%d_%H%M%S'))
+ df_cost[df_cost['iteration'] < iteration].to_csv(self.cost_iter_file, index=False)
+
+ best_cost = df_cost[['iteration', 'global_best']]
+ best_cost = best_cost[best_cost['iteration'] < iteration]
+ best = best_cost.iloc[-1]['global_best']
+ best_cost = best_cost['global_best'].tolist()
+
+ mean_pbest_cost = df_cost[['iteration', 'mean_local_best']]
+ mean_pbest_cost = mean_pbest_cost[mean_pbest_cost['iteration'] < iteration]
+ mpbest_cost = mean_pbest_cost['mean_local_best'].tolist()
+
+ mean_leader_cost = df_cost[['iteration', 'mean_leader_best']]
+ mean_leader_cost = mean_leader_cost[mean_leader_cost['iteration'] < iteration]
+ mleader_cost = mean_leader_cost['mean_leader_best'].tolist()
+
+ pbest_cost = pd.read_csv(self.pbest_cost_iter_file)
+ shutil.copy(str(self.pbest_cost_iter_file), str(self.pbest_cost_iter_file) + '_before_restart_' + time.strftime('%Y%m%d_%H%M%S'))
+ pbest_cost = pbest_cost[pbest_cost['iteration'] < iteration]
+ pbest_cost.to_csv(self.pbest_cost_iter_file, index=False)
+ iter_range = pbest_cost['iteration'][~pbest_cost['iteration'].duplicated()].values.tolist()
+ pbest_cost = [pbest_cost[pbest_cost['iteration']==i]['local_best'].tolist() for i in iter_range]
+ pbest = pbest_cost[len(pbest_cost)-1]
+
+ leader_cost = pd.read_csv(self.leader_cost_iter_file)
+ shutil.copy(str(self.leader_cost_iter_file), str(self.leader_cost_iter_file) + '_before_restart_' + time.strftime('%Y%m%d_%H%M%S'))
+ leader_cost = leader_cost[leader_cost['iteration'] < iteration]
+ leader_cost.to_csv(self.leader_cost_iter_file, index=False)
+ leader_cost = [leader_cost[leader_cost['iteration']==i]['leader_best'].tolist() for i in iter_range]
+
+ pos = pd.read_csv(self.pos_iter_file)
+ shutil.copy(str(self.pos_iter_file), str(self.pos_iter_file) + '_before_restart_' + time.strftime('%Y%m%d_%H%M%S'))
+ pos = pos[pos['iteration'] < iteration]
+ pos.to_csv(self.pos_iter_file, index=False)
+ pos = [np.array(pos[pos['iteration']==i].iloc[:,0:self.dimensions]) for i in iter_range]
+ current_pos = pos[len(pos)-1]
+
+ pbest_pos = pd.read_csv(self.pbest_pos_iter_file)
+ shutil.copy(str(self.pbest_pos_iter_file), str(self.pbest_pos_iter_file) + '_before_restart_' + time.strftime('%Y%m%d_%H%M%S'))
+ pbest_pos = pbest_pos[pbest_pos['iteration'] < iteration]
+ pbest_pos.to_csv(self.pbest_pos_iter_file, index=False)
+ pbest_pos = [np.array(pbest_pos[pbest_pos['iteration']==i].iloc[:,0:self.dimensions]) for i in iter_range]
+ current_pbest_pos = pbest_pos[len(pbest_pos)-1]
+
+ leader_pos = pd.read_csv(self.leader_pos_iter_file)
+ shutil.copy(str(self.leader_pos_iter_file), str(self.leader_pos_iter_file) + '_before_restart_' + time.strftime('%Y%m%d_%H%M%S'))
+ leader_pos = leader_pos[leader_pos['iteration'] < iteration]
+ leader_pos.to_csv(self.leader_pos_iter_file, index=False)
+ leader_pos = [np.array(leader_pos[leader_pos['iteration']==i].iloc[:,0:self.dimensions]) for i in iter_range]
+ current_leader_pos = leader_pos[len(leader_pos)-1]
+
+ return (best_cost, pbest_cost, mpbest_cost, leader_cost, mleader_cost, pos, leader_pos, best, pbest, current_pos, current_pbest_pos, current_leader_pos)
+
+
+ def update_history(self, i):
+ """Update history."""
+ hist = self.ToHistory(
+ best_cost=self.swarm.best_cost,
+ pbest_cost=self.swarm.pbest_cost,
+ mean_pbest_cost=np.mean(self.swarm.pbest_cost),
+ leader_cost=self.swarm.leader_cost,
+ mean_leader_cost=np.mean(self.swarm.leader_cost),
+ position=self.swarm.position,
+ leader_position=self.swarm.leader_pos,
+ )
+ self._populate_history(hist)
+ self.write_hist_iter_file(i)
+
+
+ @abc.abstractmethod
+ def optimize(self, objective_func, iters, n_processes=None, **kwargs):
+ """Optimize the swarm for a number of iterations
+
+ Performs the optimization to evaluate the objective
+ function :code:`objective_func` for a number of iterations
+ :code:`iter.`
+
+ Parameters
+ ----------
+ objective_func : function
+ objective function to be evaluated
+ iters : int
+ number of iterations
+ n_processes : int
+ number of processes to use for parallel particle evaluation
+ Default is None with no parallelization
+ kwargs : dict
+ arguments for objective function
+
+ Raises
+ ------
+ NotImplementedError
+ When this method is not implemented.
+ """
+ raise NotImplementedError("SwarmOptimizer::optimize()")
+
+
+ def reset(self):
+ """Reset the attributes of the optimizer
+
+ All variables/atributes that will be re-initialized when this
+ method is defined here. Note that this method
+ can be called twice: (1) during initialization, and (2) when
+ this is called from an instance.
+
+ It is good practice to keep the number of resettable
+ attributes at a minimum. This is to prevent spamming the same
+ object instance with various swarm definitions.
+
+ Normally, swarm definitions are as atomic as possible, where
+ each type of swarm is contained in its own instance. Thus, the
+ following attributes are the only ones recommended to be
+ resettable:
+
+ * Swarm position matrix (self.pos)
+ * Best scores and positions (gbest_cost, gbest_pos, etc.)
+
+ Otherwise, consider using positional arguments.
+ """
+ # Initialize history lists
+ if self.start_iter == 0:
+ self.cost_history = []
+ self.pbest_history = []
+ self.mean_pbest_history = []
+ self.leader_history = []
+ self.mean_leader_history = []
+ self.pos_history = []
+ self.leader_pos_history = []
+ else:
+ result = self.read_hist_iter_file()
+ self.cost_history = result[0]
+ self.pbest_history = result[1]
+ self.mean_pbest_history = result[2]
+ self.leader_history = result[3]
+ self.mean_leader_history = result[4]
+ self.pos_history = result[5]
+ self.leader_pos_history = result[6]
+
+ # Initialize the swarm
+ self.swarm = create_swarm(
+ n_particles=self.n_particles,
+ dimensions=self.dimensions,
+ bounds=self.bounds,
+ center=self.center,
+ init_pos=self.init_pos,
+ )
+ if self.start_iter != 0:
+ self.swarm.best_cost = result[7]
+ self.swarm.pbest_cost = result[8]
+ self.swarm.position = result[9]
+ self.swarm.pbest_pos = result[10]
+ self.swarm.leader_pos = result[11]
+ self.swarm.best_pos = result[11][0]
+
+
+def create_swarm(
+ n_particles,
+ dimensions,
+ bounds=None,
+ center=1.0,
+ init_pos=None,
+):
+ """Generate a Swarm class
+
+ Parameters
+ ----------
+ n_particles : int
+ number of particles to be generated in the swarm.
+ dimensions: int
+ number of dimensions to be generated in the swarm
+ bounds : tuple of np.ndarray or list
+ a tuple of size 2 where the first entry is the minimum bound while
+ the second entry is the maximum bound. Each array must be of shape
+ :code:`(dimensions,)`. Default is `None`
+ center : numpy.ndarray, optional
+ a list of initial positions for generating the swarm. Default is `1`
+ init_pos : numpy.ndarray, optional
+ option to explicitly set the particles' initial positions. Set to
+ :code:`None` if you wish to generate the particles randomly.
+
+ Returns
+ -------
+ Swarm class
+ """
+ position = generate_swarm(
+ n_particles,
+ dimensions,
+ bounds=bounds,
+ center=center,
+ init_pos=init_pos,
+ )
+
+ return Swarm(position)
+
+
+@attrs
+class Swarm(object):
+ """A Swarm Class
+
+ Attributes
+ ----------
+ position : numpy.ndarray
+ position-matrix at a given timestep of shape :code:`(n_particles, dimensions)`
+ n_particles : int
+ number of particles in a swarm.
+ dimensions : int
+ number of dimensions in a swarm.
+ pbest_pos : numpy.ndarray
+ personal best positions of each particle of shape :code:`(n_particles, dimensions)`
+ Default is `None`
+ best_pos : numpy.ndarray
+ best position found by the swarm of shape :code:`(dimensions, )` for
+ the :obj:`pyswarms.backend.topology.Star` topology and
+ :code:`(dimensions, particles)` for the other topologies
+ pbest_cost : numpy.ndarray
+ personal best costs of each particle of shape :code:`(n_particles, )`
+ best_cost : float
+ best cost found by the swarm, default is :obj:`numpy.inf`
+ current_cost : numpy.ndarray
+ the current cost found by the swarm of shape :code:`(n_particles, dimensions)`
+ """
+ # Required attributes
+ position = attrib(type=np.ndarray, validator=instance_of(np.ndarray))
+ # With defaults
+ n_particles = attrib(type=int, validator=instance_of(int))
+ dimensions = attrib(type=int, validator=instance_of(int))
+ best_pos = attrib(
+ type=np.ndarray,
+ default=np.array([]),
+ validator=instance_of(np.ndarray),
+ )
+ pbest_cost = attrib(
+ type=np.ndarray,
+ default=np.array([]),
+ validator=instance_of(np.ndarray),
+ )
+ best_cost = attrib(
+ type=float, default=np.inf, validator=instance_of((int, float))
+ )
+ current_cost = attrib(
+ type=np.ndarray,
+ default=np.array([]),
+ validator=instance_of(np.ndarray),
+ )
+ pbest_pos = attrib(
+ type=np.ndarray,
+ default=np.array([]),
+ validator=instance_of(np.ndarray),
+ )
+ leader_cost = attrib(
+ type=np.ndarray,
+ default=np.array([]),
+ validator=instance_of(np.ndarray),
+ )
+ leader_pos = attrib(
+ type=np.ndarray,
+ default=np.array([]),
+ validator=instance_of(np.ndarray),
+ )
+ @n_particles.default
+ def n_particles_default(self):
+ return self.position.shape[0]
+
+ @dimensions.default
+ def dimensions_default(self):
+ return self.position.shape[1]
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/meta.py b/python/runCalibValid/ngen_cal/src/ngen/cal/meta.py
new file mode 100644
index 00000000..8cd31d77
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/meta.py
@@ -0,0 +1,57 @@
+"""
+This is a class to hold model job run meta data.
+
+@author: Nels Frazer
+"""
+
+import json
+from pathlib import Path
+from tempfile import mkdtemp
+from typing import TYPE_CHECKING
+
+import pandas as pd # type: ignore
+
+from .configuration import General, Model
+
+if TYPE_CHECKING:
+ from pathlib import Path
+ from pandas import DataFrame
+
+
+class JobMeta:
+ """Structure for holding model job meta data."""
+
+ def __init__(self, name: str, parent_workdir: Path, workdir: Path=None, log=False):
+ """Create a job meta data structure.
+
+ Parameters:
+ name (str): Name of the job used to construct log files
+ workdir (Path): Working directory to stage the job under
+ log (bool, optional): Whether or not to create a log file for the job. Defaults to False.
+
+ """
+ if(workdir is None):
+ self._workdir = Path( mkdtemp(dir=parent_workdir, prefix=name+"_", suffix="_worker") ).resolve()
+ else:
+ self._workdir = workdir
+
+ self._log_file = None
+ if(log):
+ self._log_file = self._workdir/Path(name+".log")
+
+ @property
+ def workdir(self) -> 'Path':
+ return self._workdir
+
+ @workdir.setter
+ def workdir(self, path: 'Path') -> None:
+ self._workdir = path
+ if(self._log_file is not None):
+ self._log_file = self._workdir/Path(self._log_file.name)
+
+ @property
+ def log_file(self) -> 'Path':
+ """
+ Path to the job's log file, or None.
+ """
+ return self._log_file
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/metric_functions.py b/python/runCalibValid/ngen_cal/src/ngen/cal/metric_functions.py
new file mode 100644
index 00000000..1bf69607
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/metric_functions.py
@@ -0,0 +1,510 @@
+"""
+This module contains functions to process model output and compute statistical measures.
+@author: Xia Feng
+"""
+
+import math
+from typing import Union, Optional, Dict
+import warnings
+
+import numpy as np
+import pandas as pd
+import scipy.stats as sp
+from scipy.stats import pearsonr
+
+from hydrotools.metrics import metrics as hm
+
+__all__ = ['treat_values',
+ 'pearson_corr',
+ 'mean_abs_error',
+ 'root_mean_squared_error',
+ 'rmse_std_ratio',
+ 'percent_bias',
+ 'NSE',
+ 'Weighted_NSE',
+ 'KGE',
+ 'categorical_score',
+ 'pbias_fdc',
+ ]
+
+
+def treat_values(
+ df: pd.DataFrame,
+ remove_neg: Optional[bool] = False,
+ remove_na: Optional[bool] = False,
+ replace_zero: Optional[bool] = False,
+) -> pd.DataFrame:
+ """Remove NaN, inf and negative values, and replace zero values of time series.
+
+ Parameters
+ ----------
+ df : Contains time series of observation and simulation
+ remove_neg : If True, when negative value occurs at the ith element of observation or simulation
+ the ith element of both observation or simulation is removed.
+ remove_nan : If True, when NaN value occurs at the ith element of observation or simulation,
+ the ith element of both observation or simulation is removed.
+ replace_zero : If True, when the zero value occurs at the ith element of observation or simulation,
+ all observation and simulation are added with 1/100 of mean of observation according to Pushpalatha et al (2012).
+
+ Returns
+ -------
+ df : Ouput DataFrame
+
+ References
+ ----------
+ Pushpalatha, R., C. Perrin, N. L. Moine, V. Andreassian, 2012: A review of efficiency criteria suitable for evaluating low-flow simulations.
+ Journal of Hydrology, 420-421, 171-182.
+
+ """
+
+ df = df.copy()
+ colnames = list(df.columns)
+
+ # Remove rows with duplicated datetime
+ df.drop_duplicates(subset=colnames[0], inplace=True)
+ df.sort_values(by=colnames[0], na_position='last')
+
+ # Remove rows with missing values
+ if remove_na:
+ na_index = df.isin([np.nan, np.inf, -np.inf])
+ df = df[~na_index]
+ df.dropna(inplace=True)
+
+ # Remove rows with negative values
+ if remove_neg:
+ if (df[colnames[1:]]<0).all(axis=1).any():
+ df = df[~(df[colnames[1:]]<0).all(axis=1)]
+
+ # Replace zero values
+ if replace_zero:
+ if df[colnames[1:]].min().values.min() == 0:
+ df[colnames[1:]] = df[colnames[1:]] + 1.0/100.0*df[colnames[1]].mean()
+
+ return df
+
+
+def pearson_corr(
+ y_true: pd.Series,
+ y_pred: pd.Series,
+) -> float:
+ """Compute mean squared error, or optionally root mean squared error.
+
+ Parameters
+ ----------
+ y_true : Ground truth or observations
+ y_pred : Modeled values or simulations
+
+ Returns
+ -------
+ corr : float
+ p_value : float
+
+ """
+
+ # Compute
+ corr, p_value = pearsonr(y_pred, y_true)
+
+ return corr, p_value
+
+
+def mean_abs_error(
+ y_true: pd.Series,
+ y_pred: pd.Series,
+) -> float:
+ """Compute mean absolute error between simulation and observation.
+
+ Parameters
+ y_true : Ground truth or observations
+ y_pred : Modeled values or simulations
+
+ Returns
+ -------
+ Mean absolute error
+
+ """
+
+ return np.sum(np.absolute(np.subtract(y_pred, y_true)))/len(y_true)
+
+
+def root_mean_squared_error(
+ y_true: pd.Series,
+ y_pred: pd.Series,
+ root: Optional[bool] = True,
+) -> float:
+ """Compute root mean squared error, or optionally mean squared error.
+
+ Parameters
+ ----------
+ y_true : Ground truth or observations
+ y_pred : Modeled values or simulations
+ root : When False, return the mean squared error.
+
+ Returns
+ -------
+ Root mean squared error or mean squared error
+
+ """
+
+ # Compute mean squared error
+ MSE = np.sum(np.subtract(y_true, y_pred) ** 2.0) / len(y_true)
+
+ # Return RMSE, optionally return mean squared error
+ if not root:
+ return MSE
+ return np.sqrt(MSE)
+
+
+def rmse_std_ratio(
+ y_true: pd.Series,
+ y_pred: pd.Series,
+ root: Optional[bool] = False,
+) -> float:
+ """Compute ratio of RMSE between simulation and observation to standard deviation of observation.
+
+ Parameters
+ ----------
+ y_true : Ground truth or observations
+ y_pred : Modeled values or simulations
+
+ Returns
+ -------
+ rsr: ratio of RMSE and standard deviation of observation
+
+ """
+
+ rmse = root_mean_squared_error(y_true, y_pred, root=True)
+ denominator = np.std(y_true)
+
+ if denominator != 0:
+ rsr = rmse/denominator
+ else:
+ rsr = np.nan
+ warnings.warn("'np.std(y_true) = 0', can't compute RSR")
+
+ return rsr
+
+
+def percent_bias(
+ y_true: pd.Series,
+ y_pred: pd.Series,
+) -> float:
+ """Compute mean squared error, or optionally root mean squared error.
+
+ Parameters
+ ----------
+ y_true : Ground truth or observations
+ y_pred : Modeled values or simulations
+
+ Returns
+ -------
+ pbias : float
+
+ """
+
+ # compute
+ denominator = np.sum(y_true)
+ pbias = np.sum(np.subtract(y_pred, y_true))/denominator * 100
+
+ if (denominator != 0):
+ return pbias
+ else:
+ return np.nan
+ warnings.warn("'np.sum(y_true) = 0', can't compute PBIAS")
+
+
+def NSE(
+ y_true: pd.Series,
+ y_pred: pd.Series,
+ fun: Optional[str] = None,
+ epsilon: Union[None, str] = [None, "Pushpalatha2012"],
+ normalized: Optional[bool] = False,
+) -> float:
+ """Compute Nash-Sutcliffe efficiency.
+
+ Parameters
+ ----------
+ y_true : Ground truth or observations
+ y_pred : Modeled values or simulations
+ fun: Transformation function applied to y_true and y_pred
+ epsilon: Value added to both y_true and y_pred if fun is logarithm or other functions
+ that are mathematically impossible to compute transformation of zero flows:
+ 1) 0: zero value
+ 2) "Pushpalatha2012": 1/100 of mean of y_true
+ 3) other numeric value
+ normalized : If True, convert Nash-Sutcliffe efficiency to the normalized value.
+
+ Returns
+ ----------
+ Nash-Sutcliffe Efficiency value
+
+ """
+
+ # Transform values
+ if fun == 'log':
+ if epsilon=='Pushpalatha2012':
+ y_true = y_true + np.mean(y_true)/100
+ y_pred = y_pred + np.mean(y_true)/100
+ if y_true.min() == 0.0: # if not np.all(y_true)
+ y_true = y_true + 0.01
+ if y_pred.min() == 0.0:
+ y_pred = y_pred + 0.01
+ y_true = np.log(y_true)
+ y_pred = np.log(y_pred)
+
+ # Compute components
+ numerator = np.sum(np.subtract(y_pred, y_true) ** 2.0) / len(y_true)
+ denominator = np.sum(np.subtract(y_true, np.mean(y_true)) ** 2.0) / len(y_true)
+
+ # Compute score, optionally normalize
+ if (denominator != 0):
+ if normalized:
+ return 1.0 / (1.0 + numerator/denominator)
+ return 1.0 - numerator/denominator
+ else:
+ return np.nan
+ warnings.warn("'denominator = 0', can't compute NSE")
+
+
+def Weighted_NSE(
+ y_true: pd.Series,
+ y_pred: pd.Series,
+ weight: Optional[float] = 0.5,
+ normalized: Optional[bool] = False,
+) -> float:
+ """ Compute weighted average of Nash-Sutcliffe efficiency of raw time series and
+ Nash-Sutcliffe efficiency of logrithmic time series.
+
+ Parameters
+ ----------
+ y_true : Ground truth or observations
+ y_pred : Modeled values or simulations
+ weight : weight value for Nash-Sutcliffe efficiency component
+ normalized : Whether to convert the weighted Nash-Sutcliffe efficiency to the normalized valu
+
+ Returns
+ ----------
+ Weighted Nash-Sutcliffe Efficiency value
+
+ """
+
+ # Compute NSE
+ nse = NSE(y_true, y_pred)
+
+ # Compute NSELog
+ nselog = NSE(y_true, y_pred, fun="log", epsilon='Pushpalatha2012')
+
+ # Compute weighted NSE
+ nsewt = nse*weight + nse*(1-weight)
+
+ if normalized:
+ return 1.0 / (2.0 - nsewt)
+ return nsewt
+
+
+def KGE(
+ y_true: pd.Series,
+ y_pred: pd.Series,
+ r_scale: Optional[float] = 1.0,
+ a_scale: Optional[float] = 1.0,
+ b_scale: Optional[float] = 1.0,
+) -> float:
+ """Compute Kling-Gupta efficiency between simulation and observation.
+
+ Parameters
+ ----------
+ y_true : Ground truth or observations
+ y_pred : Modeled values or simulations
+ r_scale : correlation scaling factor
+ a_scale : relative variability scaling factor
+ b_scale : relative mean scaling factor
+
+ Returns
+ ----------
+ Kling-Gupta efficiency value
+
+ References
+ ----------
+ Gupta, H. V., Kling, H., Yilmaz, K. K., & Martinez, G. F. (2009). Decomposition of the mean
+ squared error and NSE performance criteria: Implications for improving hydrological modelling.
+ Journal of hydrology, 377(1-2), 80-91.
+
+ """
+
+ return hm.kling_gupta_efficiency(y_true, y_pred, r_scale, a_scale, b_scale)
+
+
+def pbias_fdc(
+ y_true: pd.Series,
+ y_pred: pd.Series,
+ bqthr: Optional[float] = 0.9,
+ lqthr: Optional[float] = 0.7,
+ hqthr: Optional[float] = 0.2,
+ pqthr: Optional[float] = 0.1,
+ warning_msg: Optional[bool] = False,
+) -> Dict[str, float]:
+ """Compute percent bias of flow duration curve (FDC) high-segment volume,
+ midsegment slope and low-segment volume according to Yilmaz et al (2008).
+
+ Parameters
+ ----------
+ y_true : Ground truth or observations
+ y_pred : Modeled values or simulations
+ bqthr : baseflow exceedance probability
+ lqthr : low flow exceedance probability
+ hqthr : high flow exceedance probability
+ pqthr : peak flow exceedance probability
+ warning_msg : If True, print warining messages.
+
+ Returns
+ -------
+ Dictionary of pbias of peak flow, slope and low flow of FDC
+
+ References
+ ----------
+ Yilmaz, K. K., H. V. Gupta, and T. Wagener (2008), A process-based diagnostic approach to
+ modelevaluation: Application to the NWS distributed hydrologic model,
+ Water Resource Research, 44, W09417,doi:10.1029/2007WR006716.
+
+ """
+
+ # Sort and rank
+ y_true_sort = np.sort(y_true, axis=0)[::-1]
+ y_pred_sort = np.sort(y_pred, axis=0)[::-1]
+
+ # Compute exceedence probabilities
+ y_true_prob = np.arange(1, len(y_true) + 1) / len(y_true)
+ y_pred_prob = np.arange(1, len(y_pred) + 1) / len(y_pred)
+
+ # Compute pbias of peak flow segment of FDC (require same number of elements)
+ numerator = np.sum(np.subtract(y_pred_sort[y_pred_prob 0:
+ pbias_mseg_fdc = numerator/denominator * 100
+ else:
+ pbias_mseg_fdc = np.nan
+ if warning_msg:
+ warnings.warn("'denominator = 0', can't compute PBIAS for slope of FDC")
+ else:
+ pbias_mseg_fdc = np.nan
+ if warning_msg:
+ warnings.warn("'0 as argument for np.log', can't compute PBIAS for slope of FDC")
+
+ # Compute pbias of low flow segment of FDC
+ term1 = (y_pred_sort[y_pred_prob>bqthr]).min()
+ term2 = y_pred_sort.min()
+ term3 = (y_true_sort[y_true_prob>bqthr]).min()
+ term4 = y_true_sort.min()
+ if (all([term1 != 0, term2 != 0, term3 != 0, term4 != 0])):
+ denominator = np.sum(np.log(y_true_sort[y_true_prob>bqthr]) - np.log(y_true_sort.min()))
+ numerator = np.sum(np.log(y_pred_sort[y_pred_prob>bqthr]) - np.log(y_pred_sort.min())) - denominator
+ if denominator != 0:
+ pbias_lseg_fdc = numerator/denominator * (-100)
+ else:
+ pbias_lseg_fdc = np.nan
+ if warning_msg:
+ warnings.warn("'denominator = 0', can't compute PBIAS for low flow of FDC")
+ else:
+ pbias_lseg_fdc = np.nan
+ if warning_msg:
+ warnings.warn("'0 as argument for np.log', can't compute PBIAS for low flow of FDC")
+
+ return {"HSEG_FDC": pbias_hseg_fdc, "MSEG_FDC": pbias_mseg_fdc, "LSEG_FDC": pbias_lseg_fdc}
+
+
+def categorical_score(
+ y_true: pd.Series,
+ y_pred: pd.Series,
+ threshold: float,
+) -> Dict[str, float]:
+ """Compute probability of detection (POD), probability of false_alarm (FAR),
+ cirtical success index (CSI) and frequency bias (FBIAS).
+
+ Parameters
+ ----------
+ y_true : Ground truth or observations
+ y_pred : Modeled values or simulations
+ threshold : threshold value
+
+ Returns
+ -------
+ Dictionary of categorical score values
+
+ """
+
+ observed = y_true>threshold
+ simulated = y_pred>threshold
+ contingency_table = hm.compute_contingency_table(observed, simulated)
+ pod = hm.probability_of_detection(contingency_table)
+ far = hm.probability_of_false_alarm(contingency_table)
+ csi = hm.threat_score(contingency_table)
+ fbias = hm.frequency_bias(contingency_table)
+
+ return {'POD':pod, 'FAR':far, 'CSI':csi, 'FBIAS':fbias}
+
+
+_all_metrics = [
+ pearson_corr,
+ mean_abs_error,
+ root_mean_squared_error,
+ rmse_std_ratio,
+ percent_bias,
+ NSE,
+ Weighted_NSE,
+ KGE,
+ categorical_score,
+ pbias_fdc,
+]
+
+
+def calculate_all_metrics(
+ y_true: pd.Series,
+ y_pred: pd.Series,
+ threshold: Optional[float] = None,
+) -> Dict[str, float]:
+ """Compute All Statistical Metrics between simulation and observation.
+
+ Parameters
+ ----------
+ y_true : Ground truth or observations
+ y_pred : Modeled values or simulations
+ threshold : threshold value for calculating categorical scores
+
+ Returns
+ ----------
+ result : dictionary of metric values
+
+ """
+
+ metric_name = {"pearson_corr": "Corr", "mean_abs_error": "MAE", "root_mean_squared_error": "RMSE", "rmse_std_ratio": "RSR",
+ "percent_bias": "PBIAS", "Weighted_NSE": "NSEWt", "KGE": "KGE"}
+ result = {}
+ for f in _all_metrics:
+ if f.__name__ == "pearson_corr":
+ result.update({metric_name[f.__name__]: f(y_true, y_pred)[0]})
+ elif f.__name__ == "NSE":
+ result.update({f.__name__: f(y_true, y_pred)})
+ result.update({"NSELog": f(y_true, y_pred, fun = "log", epsilon = "Pushpalatha2012")})
+ elif f.__name__ == "categorical_score":
+ if threshold:
+ result.update(f(y_true, y_pred, threshold))
+ else:
+ result.update({'POD': np.nan, 'FAR': np.nan, 'CSI': np.nan, 'FBIAS': np.nan})
+ elif f.__name__ == "pbias_fdc":
+ result.update(f(y_true, y_pred))
+ else:
+ result.update({metric_name[f.__name__]: f(y_true, y_pred)})
+ return result
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/model.py b/python/runCalibValid/ngen_cal/src/ngen/cal/model.py
new file mode 100644
index 00000000..d289ea86
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/model.py
@@ -0,0 +1,639 @@
+"""
+This module contains methods to process simulation output during model execution.
+
+@author: Xia Feng, Nels Frazer
+"""
+
+from abc import ABC, abstractmethod
+import copy
+from datetime import datetime
+import glob
+import json
+import os
+from pathlib import Path
+import shutil
+import time
+
+from typing import Optional, Tuple, Union
+try: #to get literal in python 3.7, it was added to typing in 3.8
+ from typing import Literal
+except ImportError:
+ from typing_extensions import Literal
+
+import pandas as pd
+from pydantic import BaseModel, DirectoryPath, conint, PyObject, validator, Field
+import yaml
+
+from .strategy import Objective
+
+# additional constrained types
+PosInt = conint(gt=-1)
+
+
+class Configurable(ABC):
+ """Abstract interface for wrapping configurable external models."""
+ @abstractmethod
+ def get_binary() -> str:
+ """Get the binary string to execute.
+
+ Returns:
+ str: The binary name or path used to execute the Configurable model
+ """
+
+ @abstractmethod
+ def get_args() -> str:
+ """Get the args to pass to the binary
+
+ Returns:
+ str: Preconfigured arg string to pass to the binary upon execution
+ """
+
+ @abstractmethod
+ def update_config(*args, **kwargs):
+ pass
+
+class EvaluationOptions(BaseModel):
+ """A class for performance evaluation and output processing during model run."""
+ evaluation_start: Optional[datetime]
+ evaluation_stop: Optional[datetime]
+ _eval_range: Tuple[datetime, datetime] = None
+ valid_start_time: Optional[datetime]
+ valid_end_time: Optional[datetime]
+ valid_eval_start_time: Optional[datetime]
+ valid_eval_end_time: Optional[datetime]
+ full_eval_start_time: Optional[datetime]
+ full_eval_end_time: Optional[datetime]
+ _valid_range: Tuple[datetime, datetime] = None
+ _valid_eval_range: Tuple[datetime, datetime] = None
+ _full_eval_range: Tuple[datetime, datetime] = None
+ objective: Optional[Union[Objective, PyObject]] = Objective.kge
+ target: Union[Literal['min'], Literal['max'], float] = 'min'
+ _best_score: float
+ _best_params_iteration: str = '0'
+ _best_save_flag: bool = None
+ id: Optional[str]
+ basinID: Optional[str]
+ threshold: Optional[float]
+ site_name: Optional[str]
+ streamflow_name: Optional[str] = 'sim_flow'
+ save_output_iteration: Optional[bool] = False
+ save_plot_iteration: Optional[bool] = False
+ save_plot_iter_freq: Optional[int] = 50
+ user: Optional[str] = None
+ _objective_log_file: Path
+ _metric_iter_file: Path
+ _param_iter_file: Path
+ _param_all_file: Path
+ _output_iter_file: Path
+ _last_output_file: Path
+ _best_output_file: Path
+ _last_iter_file: Path
+ _cost_iter_file: Path
+
+
+ class Config:
+ """Override configuration for pydantic BaseModel."""
+ underscore_attrs_are_private = True
+ use_enum_values = False #if true, then objective turns into a str, and things blow up
+
+ def __init__(self, **kwargs):
+ """Assign output files, evaluation time range, and initialize best obejctive function and best iteration."""
+ super().__init__(**kwargs)
+ self._objective_log_file = kwargs.pop('objective_log_file', Path('{}_objective_log.txt'.format(self.basinID)))
+ self._metric_iter_file = kwargs.pop('metric_iter_file', Path('{}_metrics_iteration.csv'.format(self.basinID)))
+ self._param_iter_file = kwargs.pop('param_iter_file', Path('{}_params_iteration.csv'.format(self.basinID)))
+ self._param_all_file = kwargs.pop('param_all_file', Path('{}_params_all.csv'.format(self.basinID)))
+ self._output_iter_file = kwargs.pop('output_iter_file', Path('{}_output_iteration_'.format(self.basinID)))
+ self._last_output_file = kwargs.pop('last_output_file', Path('{}_output_last_iteration.csv'.format(self.basinID)))
+ self._best_output_file = kwargs.pop('best_output_file', Path('{}_output_best_iteration.csv'.format(self.basinID)))
+ self._last_iter_file = kwargs.pop('last_iter_file', Path('{}_last_iteration.csv'.format(self.basinID)))
+ self._cost_iter_file = kwargs.pop('cost_iter_file', Path('{}_cost_iteration.csv'.format(self.basinID)))
+
+ if self.evaluation_start and self.evaluation_stop:
+ self._eval_range = (self.evaluation_start, self.evaluation_stop)
+ else:
+ self._eval_range=None
+ if self.valid_start_time and self.valid_end_time:
+ self._valid_range = (self.valid_start_time, self.valid_end_time)
+ else:
+ self._valid_range=None
+ if self.valid_eval_start_time and self.valid_eval_end_time:
+ self._valid_eval_range = (self.valid_eval_start_time, self.valid_eval_end_time)
+ else:
+ self._valid_eval_range=None
+ if self.full_eval_start_time and self.full_eval_end_time:
+ self._full_eval_range = (self.full_eval_start_time, self.full_eval_end_time)
+ else:
+ self._full_eval_range=None
+ if self.target == 'max':
+ self._best_score = float('-inf')
+ else:
+ self._best_score = float('inf')
+ self._best_params_iteration = '0' #String representation of interger iteration
+
+
+ def update(self, i: int, score: float, log: bool, algorithm: str) -> None:
+ """Update the meta state for iteration `i`
+
+ Parameters
+ ----------
+ i : Current iteration
+ score : Objecfive function
+ log : If True, save objective function at each iteration.
+ algorithm : Optimization algorithm
+
+ """
+ if os.path.exists(self._objective_log_file) and algorithm!="dds":
+ df_log = pd.read_csv(self._objective_log_file).tail(1)
+ self._best_params_iteration = str(df_log.iloc[0]['best_iteration'])
+ self._best_score = df_log.iloc[0]['best_objective_function']
+
+ if self.target == 'min':
+ if score <= self._best_score:
+ self._best_params_iteration = str(i)
+ self._best_score = score
+ self._best_save_flag = True
+ else:
+ self._best_save_flag = False
+ elif self.target == 'max':
+ if score >= self._best_score:
+ self._best_params_iteration = str(i)
+ self._best_score = score
+ self._best_save_flag = True
+ else:
+ self._best_save_flag = False
+ else:
+ if abs( score - self.target ) <= abs(self._best_score - self.target):
+ self._best_params_iteration = str(i)
+ self._best_score = score
+ self._best_save_flag = True
+ else:
+ self._best_save_flag = False
+ if log:
+ self.write_objective_log_file(i, score)
+
+
+ def write_objective_log_file(self, i: int, score: float) -> None:
+ """Write objective funtion and iteration into csv file.
+
+ Parameters
+ ----------
+ i : iteration
+ score : objecfive function
+
+ """
+ if not os.path.exists(self._objective_log_file):
+ with open(self._objective_log_file, 'w') as log_file:
+ log_file.writelines(['iteration,', 'objective_function,', 'best_iteration,', 'best_objective_function\n'])
+ with open(self._objective_log_file, 'a+') as log_file:
+ log_file.writelines(['{}, '.format(i), '{}, '.format(score), '{}, '.format(self._best_params_iteration), '{}\n'.format(self._best_score)])
+
+
+ def write_metric_iter_file(self, i: int, score: float, metrics: float) -> None:
+ """Write statistical metrics at each iteration into csv file.
+
+ Parameters
+ ----------
+ i : iteration
+ metrics : statistical metrics
+
+ """
+ metric_current = {'iteration': i, 'objFunVal': score}
+ metric_current.update(metrics)
+ metric_current = pd.DataFrame([metric_current])
+ metric_current.to_csv(self._metric_iter_file, mode='a', index=False, header=not os.path.exists(self._metric_iter_file))
+
+
+ def write_param_iter_file(self, i: int, params: 'DataFrame') ->None:
+ """Write calibrated parameters at each iteration into csv file.
+
+ Parameters
+ ----------
+ i : iteration
+ params : DataFrame with optimized parameters at each iteration
+
+ """
+ param_current = params.copy()
+ param_current['iteration'] = i
+ param_order = param_current.param
+ param_current = param_current.pivot_table(index='iteration', columns="param", values=str(i))
+ param_current = param_current[param_order]
+ param_current.reset_index(inplace=True)
+ param_current.to_csv(self._param_iter_file, mode='a', index=False, header=not os.path.exists(self._param_iter_file))
+
+
+ def write_param_all_file(self, i: int, params: 'DataFrame') -> None:
+ """Write calibrated parameters at each iteration alongside original min/max values into csv file.
+
+ Parameters
+ ----------
+ i : iteration
+ params : DataFrame with optimized parameters at each iteration
+
+ """
+ df_params = params.copy()
+ df_params.pop('model')
+ param_name = df_params['param']
+ df_params.drop('param', axis=1, inplace=True)
+ df_params = df_params.T.rename(columns = dict(zip(df_params.T.columns, param_name)))
+
+ # Remove rows for plotting
+ df_params.reset_index(inplace=True)
+ if os.path.exists(self._param_all_file):
+ df_params = df_params.tail(1)
+
+ df_params.to_csv(self._param_all_file, mode='a', index=False, header=not os.path.exists(self._param_all_file))
+
+
+ def write_last_iteration(self, i: int) -> None:
+ """Write completed iteration into csv file.
+
+ Parameters
+ ----------
+ i : iteration
+
+ """
+ if not os.path.exists(self._last_iter_file):
+ with open(self._last_iter_file, 'w') as log_file:
+ log_file.writelines(['site_no,', 'last_iteration\n'])
+ with open(self._last_iter_file, 'a+') as log_file:
+ log_file.writelines(['{}, '.format(self.basinID), '{} \n'.format(i)])
+
+
+ def write_cost_iter_file(self, i: int, calib_run_path: Path) -> None:
+ """Write global and local best cost function at each iteration into csv file.
+
+ Parameters
+ ----------
+ i : iteration
+ calib_run_path : directory for calibration run
+
+ """
+ workdirs = [os.path.join(calib_run_path, pnm) for pnm in os.listdir(calib_run_path) if os.path.isdir(os.path.join(calib_run_path, pnm))]
+ df_log = pd.DataFrame()
+ for wdir in workdirs:
+ logfile = os.path.join(wdir, '{}_objective_log.txt'.format(self.basinID))
+ if os.path.exists(logfile):
+ wlog = pd.read_csv(logfile)
+ wlog['agent'] = os.path.basename(wdir)
+ df_log = pd.concat([df_log, wlog], ignore_index=True)
+ df_cost=pd.DataFrame()
+ for iter in range(0, i+1):
+ df_log_iter = df_log[df_log['iteration']==iter][['iteration', 'best_objective_function', 'agent']]
+ best_cost = pd.DataFrame({'iteration': iter, 'global_best': df_log_iter['best_objective_function'].min(),
+ 'local_best': df_log_iter['best_objective_function'].mean()}, index=[0])
+ df_cost = pd.concat([df_cost, best_cost], ignore_index=True)
+ calib_cost_iter_file = os.path.join(calib_run_path, self._cost_iter_file)
+ df_cost.to_csv(calib_cost_iter_file, index=False)
+
+
+ def write_hist_file(self, optimizer_result: 'SwarmOptimizer', agent: 'Agent', params_lst: list) -> None:
+ """Write cost and position history plus global best position into csv files.
+
+ Parameters
+ ----------
+ optimizer_result : SwarmOptimizer object
+ agent : Agent object
+ params_lst : Calibration parameter list
+
+ """
+ # Save best cost
+ cost_hist = {"iteration": range(1, len(optimizer_result.cost_history) + 1),
+ "global_best": optimizer_result.cost_history,
+ "local_best": optimizer_result.mean_pbest_history}
+ if agent.algorithm=="gwo":
+ cost_hist.update({"leader_best": optimizer_result.mean_leader_history})
+ cost_hist = pd.DataFrame(cost_hist)
+ cost_hist_file = os.path.join(agent.workdir, '{}_cost_hist.csv'.format(self.basinID))
+ cost_hist.to_csv(cost_hist_file, index=False)
+
+ # Save parameters of swarms
+ pos_hist = pd.DataFrame()
+ for i in range(len(optimizer_result.pos_history)):
+ pos_df = pd.DataFrame(optimizer_result.pos_history[i], columns=params_lst)
+ pos_df['agent'] = range(1, optimizer_result.swarm.n_particles + 1)
+ pos_df['iteration'] = i + 1
+ pos_hist = pd.concat([pos_hist, pos_df], ignore_index=True)
+ pos_hist_file = os.path.join(agent.workdir, '{}_pos_hist.csv'.format(self.basinID))
+ pos_hist.to_csv(pos_hist_file, index=False)
+
+ # Save best parameters
+ best_pos = pd.DataFrame(optimizer_result.swarm.best_pos, columns=["global_best_params"])
+ best_pos.reset_index(inplace=True, drop=True)
+ best_pos['param'] = params_lst
+ best_pos['model'] = list(agent.model_params.keys())*len(best_pos)
+ best_pos_file = os.path.join(agent.workdir, '{}_global_best_params.csv'.format(self.basinID))
+ best_pos.to_csv(best_pos_file, index=False)
+
+ # Save local and leader best
+ if agent.algorithm=="gwo":
+ pbest_hist = pd.DataFrame()
+ for i in range(len(optimizer_result.pbest_history)):
+ pbest_df = pd.DataFrame(optimizer_result.pbest_history[i], columns=['local_best'])
+ pbest_df['agent'] = range(1, optimizer_result.swarm.n_particles + 1)
+ pbest_df['iteration'] = i + 1
+ pbest_hist = pd.concat([pbest_hist, pbest_df], ignore_index=True)
+ pbest_hist_file = os.path.join(agent.workdir, '{}_pbest_hist.csv'.format(self.basinID))
+ pbest_hist.to_csv(pbest_hist_file, index=False)
+ leader_hist = pd.DataFrame()
+ for i in range(len(optimizer_result.leader_history)):
+ leader_df = pd.DataFrame(optimizer_result.leader_history[i], columns=['leader_best'])
+ leader_df['rank'] = range(1, 4)
+ leader_df['iteration'] = i + 1
+ leader_hist = pd.concat([leader_hist, leader_df], ignore_index=True)
+ leader_hist_file = os.path.join(agent.workdir, '{}_leader_hist.csv'.format(self.basinID))
+ leader_hist.to_csv(leader_hist_file, index=False)
+
+ return cost_hist_file
+
+
+ def create_valid_config_file(self, yaml_file: Path, valid_run_path: Path, valid_config_file: Path, valid_run_name: str) -> None:
+ """Create configuration yaml file for valiation control and best runs.
+
+ Parameters:
+ ----------
+ yaml_file : calibration configuration yaml file
+ valid_run_path : directory for validation run
+ valid_config_file : realization configuration file for control or best run
+ valid_run_name : control or best validation run
+
+ """
+ with open(yaml_file) as file:
+ y = yaml.safe_load(file)
+
+ d = copy.deepcopy(y)
+ d['general']['name'] = valid_run_name
+ f = d['general']['yaml_file']
+ d['general']['yaml_file'] = os.path.join(valid_run_path, os.path.basename(f).replace('calib', valid_run_name))
+ d['model']['realization'] = os.path.join(valid_run_path, valid_config_file)
+ with open(d['general']['yaml_file'], 'w') as yfile:
+ yaml.dump(d, yfile, sort_keys=False, default_flow_style=False, indent=2)
+
+
+ def create_valid_realization_file(self, agent: 'Agent', params: 'pd.DataFrame') -> None:
+ """Create model realization file for valiation control and best runs.
+
+ Parameters:
+ ----------
+ agent : Agent object
+ params : calibration parameters
+
+ """
+ # Create realization file for control run
+ agent.model.update_config(0, params, path = Path(agent.valid_path))
+ configfl = os.path.join(agent.valid_path, os.path.basename(str(agent.realization_file)))
+ config_valid_control_file = os.path.join(agent.valid_path, os.path.basename(configfl).replace("calib","valid_control"))
+ shutil.move(configfl, config_valid_control_file)
+ with open(config_valid_control_file) as fl:
+ config_valid_control = json.load(fl)
+
+ # Create realization file for best run
+ if agent.algorithm!="dds":
+ agent.model.update_config("global_best", params, path = Path(agent.valid_path))
+ else:
+ agent.model.update_config(self._best_params_iteration, params, path = Path(agent.valid_path))
+ config_valid_best_file = os.path.join(agent.valid_path, os.path.basename(configfl).replace("calib","valid_best"))
+ shutil.move(configfl, config_valid_best_file)
+ with open(config_valid_best_file) as fl:
+ config_valid_best = json.load(fl)
+
+ # Replace calib simulation time period with valid sumulation period
+ config_valid_control['time']['start_time'] = datetime.strftime(self._valid_range[0], '%Y-%m-%d %H:%M:%S')
+ config_valid_control['time']['end_time'] = datetime.strftime(self._valid_range[1], '%Y-%m-%d %H:%M:%S')
+ config_valid_best['time']['start_time'] = datetime.strftime(self._valid_range[0], '%Y-%m-%d %H:%M:%S')
+ config_valid_best['time']['end_time'] = datetime.strftime(self._valid_range[1], '%Y-%m-%d %H:%M:%S')
+
+ # Replace namelist of Noah-OWP-Modular and add output variables to SFT related model for control and best run
+ for cf in [config_valid_control, config_valid_best]:
+ for m in cf['global']['formulations'][0]['params']['modules']:
+ if m['params']['model_type_name'] == 'NoahOWP':
+ m1 = m['params']['init_config']
+ m['params']['init_config'] = os.path.join(os.path.dirname(m1), os.path.basename(m1).replace('calib', 'valid'))
+
+ # Replace t-route ymal file
+ rt_control = os.path.basename(config_valid_control['routing']['t_route_config_file_with_path']).replace('calib','valid_control')
+ rt_control = os.path.join(os.path.dirname(config_valid_control['routing']['t_route_config_file_with_path']), rt_control)
+ config_valid_control['routing']['t_route_config_file_with_path'] = rt_control
+ rt_best = os.path.basename(config_valid_best['routing']['t_route_config_file_with_path']).replace('calib','valid_best')
+ rt_best = os.path.join(os.path.dirname(config_valid_best['routing']['t_route_config_file_with_path']), rt_best)
+ config_valid_best['routing']['t_route_config_file_with_path'] = rt_best
+
+ # Add output variables and headers to sft related run
+ for cf in [config_valid_control, config_valid_best]:
+ cf1 = cf['global']['formulations'][0]['params'].popitem()
+ output_variables = list()
+ output_header_fields = list()
+ if cf['global']['formulations'][0]['params']['model_type_name'] in ["NoahOWP_CFE_SK_SFT_SMP", "NoahOWP_CFE_XAJ_SFT_SMP"]:
+ output_variables = ["soil_ice_fraction", "TGS", "RAIN_RATE", "DIRECT_RUNOFF", "GIUH_RUNOFF",
+ "NASH_LATERAL_RUNOFF", "DEEP_GW_TO_CHANNEL_FLUX", "Q_OUT", "SOIL_STORAGE",
+ "ice_fraction_schaake", "POTENTIAL_ET", "ACTUAL_ET", "soil_moisture_fraction"]
+ output_header_fields = ["soil_ice_fraction", "ground_temperature", "rain_rate", "direct_runoff",
+ "giuh_runoff", "nash_lateral_runoff", "deep_gw_to_channel_flux", "q_out",
+ "soil_storage", "ice_fraction_schaake", "PET", "AET", "soil_moisture_fraction"]
+ if cf['global']['formulations'][0]['params']['model_type_name'] == "NoahOWP_CFE_XAJ_SFT_SMP":
+ output_variables[9] = "ice_fraction_xinanjiang"
+ output_header_fields[9] = "ice_fraction_xinanjiang"
+ if cf['global']['formulations'][0]['params']['model_type_name'] == "NoahOWP_LASAM_SFT_SMP":
+ output_variables = ["soil_ice_fraction", "TGS", "precipitation", "potential_evapotranspiratio", "actual_evapotranspiration",
+ "soil_storage", "surface_runoff", "giuh_runoff", "groundwater_to_stream_recharge", "percolation",
+ "total_discharge", "infiltration", "EVAPOTRAN", "soil_moisture_fraction"]
+ output_header_fields = ["soil_ice_fraction", "ground_temperature", "rain_rate", "PET_rate", "actual_ET",
+ "soil_storage", "direct_runoff", "giuh_runoff", "deep_gw_to_channel_flux",
+ "soil_to_gw_flux", "q_out", "infiltration", "PET_NOM", "soil_moisture_fraction"]
+ if len(output_variables)>1 and len(output_header_fields)>1:
+ cf['global']['formulations'][0]['params']['output_variables'] = output_variables
+ cf['global']['formulations'][0]['params']['output_header_fields'] = output_header_fields
+ cf['global']['formulations'][0]['params']['modules'] = cf1[1]
+
+ # Write realization file for control and best run
+ with open(config_valid_control_file, 'w') as outfile:
+ json.dump(config_valid_control, outfile, indent=4, separators=(", ", ": "), sort_keys=False)
+ with open(config_valid_best_file, 'w') as outfile:
+ json.dump(config_valid_best, outfile, indent=4, separators=(", ", ": "), sort_keys=False)
+
+ # Write yaml configuration file for control and best run
+ for valid_run_name, config_valid_file in zip(['valid_control', 'valid_best'], [config_valid_control_file, config_valid_best_file]):
+ self.create_valid_config_file(agent.yaml_file, agent.valid_path, config_valid_file, valid_run_name)
+
+
+ def write_valid_metric_file(self, valid_run_path: Path, valid_run_name: str, metrics: float) -> None:
+ """Write metrics from validation run into csv file.
+
+ Parameters
+ ----------
+ valid_run_path : directory for validation run
+ valid_run_name : control or best validation run
+ metrics : statistical metrics
+
+ """
+ metric_out_file = os.path.join(valid_run_path, '{}'.format(self.basinID) + '_metrics_{}.csv'.format(valid_run_name))
+ metrics.to_csv(metric_out_file, index=False)
+
+
+ def write_run_complete_file(self, run_name: str, path: 'Path') -> None:
+ """Write empty file if calibration or validation run is complete.
+
+ Parameters
+ ----------
+ path : directory to save file
+ run_name : calib, control or best run
+
+ """
+ complete_file = os.path.join(path, '{}'.format(self.basinID) + '_' + '{}'.format(run_name).capitalize() + '_Run_Complete')
+ with open(complete_file, 'w') as fp:
+ pass
+
+ @property
+ def best_score(self) -> float:
+ """Best objective function."""
+ return self._best_score
+
+ @property
+ def best_params(self) -> str:
+ """The best iteration."""
+ return self._best_params_iteration
+
+ @property
+ def objective_log_file(self) -> Path:
+ """The path of the best objective function log file."""
+ if id is not None:
+ prefix = ""
+ else:
+ prefix = f"{self.id}_"
+ return Path(self._objective_log_file.parent, prefix + self._objective_log_file.stem + self._objective_log_file.suffix)
+
+ @property
+ def output_iter_file(self) -> Path:
+ """Output file at each iteration."""
+ return self._output_iter_file
+
+ @property
+ def last_output_file(self) -> Path:
+ """Output file at last iteration."""
+ return self._last_output_file
+
+ @property
+ def best_output_file(self) -> Path:
+ """Output file at best iteration."""
+ return self._best_output_file
+
+ @property
+ def metric_iter_file(self) -> Path:
+ """File to store metrics at each iteration."""
+ return self._metric_iter_file
+
+ @property
+ def param_iter_file(self) -> Path:
+ """File to store calibrated parameters at each iteration."""
+ return self._param_iter_file
+
+ @property
+ def cost_iter_file(self) -> Path:
+ """File to store global and local best cost function at each iteration."""
+ return self._cost_iter_file
+
+ @property
+ def best_save_flag(self) -> bool:
+ """Whether save output file at each iteration."""
+ return self._best_save_flag
+
+ @property
+ def save_output_iter_flag(self) -> bool:
+ """Whether save output file at each iteration."""
+ return self.save_output_iteration
+
+ @property
+ def save_plot_iter_flag(self) -> bool:
+ """Whether save plot file at each iteration."""
+ return self.save_plot_iteration
+
+ @validator("objective")
+ def validate_objective(cls, value):
+ if value is None:
+ print("Objective cannot be none -- setting default objective")
+ value = Objective.kge
+ return value
+
+
+ def read_objective_log_file(self) -> dict:
+ """Read objective function log file.
+
+ Returns
+ ----------
+ current iteration, best iteration, best objective function
+
+ """
+ df_obj = pd.read_csv(str(self._objective_log_file))
+ iteration = df_obj.iloc[-1]['iteration']
+ best_params = df_obj.iloc[-1]['best_iteration']
+ best_score = df_obj.iloc[-1]['best_objective_function']
+ return {'iteration': iteration, 'best_iteration': best_params, 'best_score': best_score}
+
+
+ def organize_file_for_restart(self, i: int) -> dict:
+ """Create copies for files of storing objective function, metrics, and parameters at each iteration,
+ remove the records from the last completed or unfinished iteration and save the remaining records into new files.
+
+ Parameters
+ ----------
+ i : last iteration
+
+ """
+ # Creat copies for iteration files and clean up
+ all_log_files = [str(self._objective_log_file), str(self._metric_iter_file), str(self._param_iter_file)]
+ for infile in all_log_files:
+ shutil.copy(infile, infile + '_before_restart_' + time.strftime('%Y%m%d_%H%M%S'))
+ indata = pd.read_csv(infile)
+ if indata.iloc[-1]['iteration']==i:
+ indata.iloc[0:(len(indata)-1)].to_csv(infile, index=False)
+ elif indata.iloc[-1]['iteration']-i==1 and indata.iloc[-2]['iteration']==i:
+ indata.iloc[0:(len(indata)-2)].to_csv(infile, index=False)
+
+ def restart(self) -> int:
+ """
+ Restart calibration run from the last completed iteration
+
+ Returns
+ ----------
+ start_iteration: iteration to restart calibration
+
+ """
+ df_iter = pd.read_csv(self._last_iter_file, dtype=object)
+ start_iteration = int(df_iter.iloc[-1]['last_iteration'])
+ shutil.copy(str(self._last_iter_file), str(self._last_iter_file) + '_before_restart_' + time.strftime('%Y%m%d_%H%M%S'))
+ df_iter.iloc[0:(len(df_iter)-1)].to_csv(self._last_iter_file, index=False)
+
+ self.organize_file_for_restart(start_iteration)
+
+ df_obj = self.read_objective_log_file()
+ self._best_params_iteration = str(df_obj['best_iteration'])
+ self._best_score = df_obj['best_score']
+
+ return start_iteration
+
+
+class ModelExec(BaseModel, Configurable):
+ """
+ The data class for a given model, which must also be Configurable
+ """
+ binary: str
+ args: Optional[str]
+ workdir: DirectoryPath = Path("./") #FIXME test the various workdirs
+ eval_params: Optional[EvaluationOptions] = Field(default=EvaluationOptions())
+
+ #FIXME formalize type: str = "ModelName"
+ def get_binary(self)->str:
+ """Get the binary string to execute
+
+ Returns:
+ str: The binary name or path used to execute the Configurable model
+ """
+ return self.binary
+
+ def get_args(self)->str:
+ """Get the args to pass to the binary
+
+ Returns:
+ str: Preconfigured arg string to pass to the binary upon execution
+ """
+ return self.args
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/ngen.py b/python/runCalibValid/ngen_cal/src/ngen/cal/ngen.py
new file mode 100644
index 00000000..e4d57f9d
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/ngen.py
@@ -0,0 +1,512 @@
+"""
+This module contains methods to read and save formulation configurations.
+
+@author: Nels Frazer, Xia Feng
+"""
+
+from datetime import datetime
+from enum import Enum
+from functools import reduce
+import glob
+import json
+json.encoder.FLOAT_REPR = str #lambda x: format(x, '%.09f')
+import logging
+logging.disable(logging.DEBUG)
+import os
+from pathlib import Path
+import re
+import shutil
+import sys
+
+from typing import Optional, Sequence, Dict, Mapping, Union
+try: #to get literal in python 3.7, it was added to typing in 3.8
+ from typing import Literal
+except ImportError:
+ from typing_extensions import Literal
+
+import geopandas as gpd
+import pandas as pd
+from pydantic import FilePath, root_validator, BaseModel, Field
+
+from hypy.hydrolocation import NWISLocation # type: ignore
+from hypy.nexus import Nexus # type: ignore
+
+from .calibration_cathment import CalibrationCatchment, AdjustableCatchment
+from .calibration_set import CalibrationSet, UniformCalibrationSet
+from .model import ModelExec, PosInt, Configurable
+from ngen.config.realization import NgenRealization, Realization, CatchmentRealization
+from ngen.config.multi import MultiBMI
+from .parameter import Parameter, Parameters
+
+
+class NgenStrategy(str, Enum):
+ """
+ """
+ #multiplier = "multiplier"
+ uniform = "uniform"
+ explicit = "explicit"
+ independent = "independent"
+
+def _params_as_df(params: Mapping[str, Parameters], name: str = None):
+ if not name:
+ dfs = []
+ for k,v in params.items():
+ df = pd.DataFrame([s.__dict__ for s in v])
+ df['model'] = k
+ df.rename(columns={'name':'param'}, inplace=True)
+ dfs.append(df)
+ dfs = pd.concat(dfs)
+ dfs['fac'] = dfs['param'].factorize()[0]
+ return dfs
+ else:
+ p = params.get(name, [])
+ df = pd.DataFrame([s.__dict__ for s in p])
+ df['model'] = name
+ df.rename(columns={'name':'param'}, inplace=True)
+ df['fac'] = df['param'].factorize()[0]
+ return df
+
+def _map_params_to_realization(params: Mapping[str, Parameters], realization: Realization):
+ # don't even think about calibration multiple formulations at once just yet..
+ module = realization.formulations[0].params
+
+ if isinstance(module, MultiBMI):
+ dfs = []
+ for m in module.modules:
+ dfs.append(_params_as_df(params, m.params.model_name))
+ return pd.concat(dfs)
+ else:
+ return _params_as_df(params, module.model_name)
+
+class NgenBase(ModelExec):
+ """
+ Data class specific for Ngen
+
+ Inherits the ModelParams attributes and Configurable interface
+ """
+ type: Literal['ngen']
+ #required fields
+ # TODO with the ability to generate realizations programaticaly, this may not be
+ # strictly required any longer...for now it "works" so we are using info from
+ # an existing realization to build various calibration realization configs
+ # but we should probably take a closer look at this in the near future
+ realization: FilePath
+ catchments: FilePath
+ nexus: FilePath
+ crosswalk: FilePath
+ ngen_realization: Optional[NgenRealization]
+ routing_output: Optional[Path] = Field(default=Path("flowveldepth_Ngen.h5"))
+ #optional fields
+ partitions: Optional[FilePath]
+ parallel: Optional[PosInt]
+ params: Optional[ Mapping[str, Parameters] ]
+ #dependent fields
+ binary: str = 'ngen'
+ args: Optional[str]
+ obsflow: Optional[FilePath]
+
+ #private, not validated
+ _catchments: Sequence['CalibrationCatchment'] = []
+ _catchment_hydro_fabric: gpd.GeoDataFrame
+ _nexus_hydro_fabric: gpd.GeoDataFrame
+ _x_walk: pd.Series
+ _precip: gpd.GeoDataFrame
+ _wb_lst: list
+
+ class Config:
+ """Override configuration for pydantic BaseModel
+ """
+ underscore_attrs_are_private = True
+ use_enum_values = True
+ smart_union = True
+
+ def __init__(self, **kwargs):
+ #Let pydantic work its magic
+ super().__init__(**kwargs)
+ #Make a copy of the config file, just in case
+ shutil.copy(self.realization, str(self.realization)+'_original')
+
+ self._catchment_hydro_fabric = gpd.read_file(self.catchments, layer='divides')
+ self._catchment_hydro_fabric.set_index('id', inplace=True)
+ self._nexus_hydro_fabric = gpd.read_file(self.nexus, layer='nexus')
+ self._nexus_hydro_fabric.set_index('id', inplace=True)
+
+ self._x_walk = pd.Series(dtype=object)
+ with open(self.crosswalk) as fp:
+ data = json.load(fp)
+ for id, values in data.items():
+ gage = values.get('Gage_no')
+ if gage:
+ if not isinstance(gage, str):
+ gage = gage[0]
+ if gage != "":
+ self._x_walk[id] = gage
+
+ #Read the calibration specific info
+ with open(self.realization) as fp:
+ data = json.load(fp)
+ self.ngen_realization = NgenRealization(**data)
+
+ # Read precipitation foricing
+ start_date = datetime.strftime(self.ngen_realization.time.start_time, '%Y-%m-%d %H:%M:%S')
+ end_date = datetime.strftime(self.ngen_realization.time.end_time, '%Y-%m-%d %H:%M:%S')
+ flst = []
+ for ffile in glob.glob(os.path.join(self.ngen_realization.global_config.forcing.path, '*.csv')):
+ fdata = pd.read_csv(ffile)
+ fdata_copy = fdata.copy()[['Time','RAINRATE']]
+ fdata_copy['Time'] = pd.DatetimeIndex(fdata_copy['Time'])
+ fdata_copy.set_index('Time', inplace=True)
+ fdata_copy = fdata_copy.loc[start_date:end_date]
+ flst.append(fdata_copy)
+
+ suffixes=[f"_{i}" for i in range(len(flst))]
+ flst=[flst[i].add_suffix(suffixes[i]) for i in range(len(flst))]
+ df_precip = reduce(lambda left, right: pd.merge(left, right, left_index=True, right_index=True), flst)
+ dfp = df_precip.sum(axis=1)*3600
+ dfp.name = 'RAINRATE'
+ self._precip = dfp.reset_index()
+
+ @property
+ def config_file(self) -> Path:
+ """Path to the configuration file for this calibration
+
+ Returns:
+ Path: to ngen realization configuration file
+ """
+ return self.realization
+
+ @property
+ def adjustables(self) -> Sequence['CalibrationCatchment']:
+ """A list of Catchments for calibration
+
+ These catchments hold information about the parameters/calibration data for that catchment
+
+ Returns:
+ Sequence[CalibrationCatchment]: A list like container of CalibrationCatchment objects
+ """
+ return self._catchments
+
+ @root_validator
+ def set_defaults(cls, values: Dict):
+ """Compose default values
+
+ This validator will set/adjust the following data values for the class
+ args: if not explicitly configured, ngen args default to
+ catchments "all" nexus "all" realization
+ binary: if parallel is defined and valid then the binary command is adjusted to
+ mpirun -n parallel binary
+ also, if parallel is defined the args are adjusted to include the partition field
+ catchments "" nexus "" realization partitions
+ Args:
+ values (dict): mapping of key/value pairs to validate
+
+ Returns:
+ Dict: validated key/value pairs with default values set for known keys
+ """
+ parallel = values.get('parallel')
+ partitions = values.get('partitions')
+ binary = values.get('binary')
+ args = values.get('args')
+ catchments = values.get('catchments')
+ nexus = values.get('nexus')
+ realization = values.get('realization')
+
+ custom_args = False
+ if( args is None ):
+ #args = '{} "" {} "" {}'.format(catchments.resolve(), nexus.resolve(), realization.name)
+ args = '{} "all" {} "all" {}'.format(catchments.resolve(), nexus.resolve(), realization.name)
+ values['args'] = args
+ else:
+ custom_args = True
+
+ if( parallel is not None and partitions is not None):
+ binary = f'mpirun -n {parallel} {binary}'
+ if not custom_args:
+ # only append this if args weren't already custom defined by user
+ args += f' {partitions}'
+ values['binary'] = binary
+ values['args'] = args
+
+ return values
+
+ @root_validator(pre=True) #pre-check, don't validate anything else if this fails
+ def check_for_partitions(cls, values: dict):
+ """Validate that if parallel is used and valid that partitions is passed (and valid)
+
+ Args:
+ values (dict): values to validate
+
+ Raises:
+ ValueError: If no partition field is defined and parallel support (greater than 1) is requested.
+
+ Returns:
+ dict: Values valid for this rule
+ """
+ parallel = values.get('parallel')
+ partitions = values.get('partitions')
+ if(parallel is not None and parallel > 1 and partitions is None):
+ raise ValueError("Must provide partitions if using parallel")
+ return values
+
+ def update_config(self, i: int, params: 'pd.DataFrame', id: str = None, path=Path("./")):
+ """_summary_
+
+ Args:
+ i (int): _description_
+ params (pd.DataFrame): _description_
+ id (str): _description_
+ """
+
+ if id is None: #Update global
+ module = self.ngen_realization.global_config.formulations[0].params
+ else: #update specific catchment
+ module = self.ngen_realization.catchments[id].formulations[0].params
+
+ groups = params.set_index('param').groupby('model')
+ if isinstance(module, MultiBMI):
+ for m in module.modules:
+ name = m.params.model_name
+ if name in groups.groups:
+ p = groups.get_group(name)
+ m.params.model_params = p[str(i)].to_dict()
+ else:
+ p = groups.get_group(module.model_name)
+ module.model_params = p[str(i)].to_dict()
+ with open(path/self.realization.name, 'w') as fp:
+ fp.write( self.ngen_realization.json(by_alias=True, exclude_none=True, indent=4))
+
+
+class NgenExplicit(NgenBase):
+
+ strategy: Literal[NgenStrategy.explicit]
+
+ def __init__(self, **kwargs):
+ #Let pydantic work its magic
+ super().__init__(**kwargs)
+ #now we work ours
+ start_t = self.ngen_realization.time.start_time
+ end_t = self.ngen_realization.time.end_time
+ #Setup each calibration catchment
+ for id, catchment in self.ngen_realization.catchments.items():
+
+ if hasattr(catchment, 'calibration'):
+ try:
+ fabric = self._catchment_hydro_fabric.loc[id]
+ except KeyError:
+ continue
+ try:
+ nwis = self._x_walk[id]
+ except KeyError:
+ raise(RuntimeError("Cannot establish mapping of catchment {} to nwis location in cross walk".format(id)))
+ try:
+ nexus_data = self._nexus_hydro_fabric.loc[fabric['toid']]
+ except KeyError:
+ raise(RuntimeError("No suitable nexus found for catchment {}".format(id)))
+
+ #establish the hydro location for the observation nexus associated with this catchment
+ location = NWISLocation(nwis, nexus_data.name, nexus_data.geometry)
+ nexus = Nexus(nexus_data.name, location, (), id)
+ output_var = catchment.formulations[0].params.main_output_variable
+ #read params from the realization calibration definition
+ params = {model:[Parameter(**p) for p in params] for model, params in catchment.calibration.items()}
+ params = _map_params_to_realization(params, catchment)
+ #TODO define these extra params in the realization config and parse them out explicity per catchment, cause why not?
+ eval_params = self.eval_params.copy()
+ eval_params.id = id
+ self._catchments.append(CalibrationCatchment(self.workdir, id, nexus, start_t, end_t, fabric, output_var, eval_params, params))
+
+ def update_config(self, i: int, params: 'pd.DataFrame', id: str, **kwargs):
+ """_summary_
+
+ Args:
+ i (int): _description_
+ params (pd.DataFrame): _description_
+ id (str): _description_
+ """
+
+ if id is None:
+ raise RuntimeError("NgenExplicit calibration must recieve an id to update, not None")
+
+ super().update_config(i, params, id, **kwargs)
+
+
+class NgenIndependent(NgenBase):
+ # TODO Error if not routing block in ngen_realization
+ strategy: Literal[NgenStrategy.independent]
+ params: Mapping[str, Parameters] #required in this case...
+
+ def __init__(self, **kwargs):
+ #Let pydantic work its magic
+ super().__init__(**kwargs)
+ # FIXME cannot strip all global params cause things like sloth depend on them
+ # but the global params may have defaults in place that are not the same as the requested
+ # calibration params. This shouldn't be an issue since each catchment overrides the global config
+ # and it won't actually be used, but the global config definition may not be correct.
+ #self._strip_global_params()
+ #now we work ours
+ start_t = self.ngen_realization.time.start_time
+ end_t = self.ngen_realization.time.end_time
+ #Setup each calibration catchment
+ catchments = []
+ eval_nexus = []
+ catchment_realizations = {}
+ g_conf = self.ngen_realization.global_config.copy(deep=True).dict(by_alias=True)
+ for id in self._catchment_hydro_fabric.index:
+ #Copy the global configuration into each catchment
+ catchment_realizations[id] = CatchmentRealization(**g_conf)
+ #Need to fix the forcing definition or ngen will not work
+ #for individual catchment configs, it doesn't apply pattern resolution
+ #and will read the directory `path` key as the file key and will segfault
+ pattern = catchment_realizations[id].forcing.file_pattern
+ path = catchment_realizations[id].forcing.path
+ catchment_realizations[id].forcing.file_pattern = None
+ pattern = pattern.replace("{{id}}", id)
+ pattern = re.compile(pattern.replace("{{ID}}", id))
+ for f in path.iterdir():
+ if pattern.match(f.name):
+ catchment_realizations[id].forcing.path = f.resolve()
+
+
+ self.ngen_realization.catchments = catchment_realizations
+
+ for id, catchment in self.ngen_realization.catchments.items():#data['catchments'].items():
+ try:
+ fabric = self._catchment_hydro_fabric.loc[id]
+ except KeyError: # This probaly isn't strictly required since we built these from the index
+ continue
+ try:
+ nexus_data = self._nexus_hydro_fabric.loc[fabric['toid']]
+ except KeyError:
+ raise(RuntimeError("No suitable nexus found for catchment {}".format(id)))
+ nwis = None
+ try:
+ nwis = self._x_walk.loc[id.replace('cat', 'wb')]
+ except KeyError:
+ try:
+ nwis = self._x_walk.loc[id]
+ except KeyError:
+ nwis = None
+ if nwis is not None:
+ #establish the hydro location for the observation nexus associated with this catchment
+ location = NWISLocation(nwis, nexus_data.name, nexus_data.geometry)
+ nexus = Nexus(nexus_data.name, location, (), id)
+ eval_nexus.append( nexus ) # FIXME why did I make this a tuple???
+ else:
+ #in this case, we don't care if all nexus are observable, just need one downstream
+ #FIXME use the graph to work backwards from an observable nexus to all upstream catchments
+ #and create independent "sets"
+ nexus = Nexus(nexus_data.name, None, (), id)
+ #FIXME pick up params per catchmment somehow???
+ params = _map_params_to_realization(self.params, catchment)
+ catchments.append(AdjustableCatchment(self.workdir, id, nexus, params))
+
+ if len(eval_nexus) != 1:
+ raise RuntimeError( "Currently only a single nexus in the hydrfabric can be gaged")
+ self._catchments.append(CalibrationSet(catchments, eval_nexus[0], self.routing_output, start_t, end_t, self.eval_params))
+
+ def _strip_global_params(self) -> None:
+ module = self.ngen_realization.global_config.formulations[0].params
+ if isinstance(module, MultiBMI):
+ for m in module.modules:
+ m.params.model_params = None
+ else:
+ module.model_params = None
+
+
+class NgenUniform(NgenBase):
+ """
+ Uses a global ngen configuration and permutes just this global parameter space
+ which is applied to each catchment in the hydrofabric being simulated.
+ """
+ # TODO Error if not routing block in ngen_realization
+ strategy: Literal[NgenStrategy.uniform]
+ params: Mapping[str, Parameters] #required in this case...
+
+ def __init__(self, **kwargs):
+ ##Let pydantic work its magic
+ super().__init__(**kwargs)
+ #now we work ours
+ start_t = self.ngen_realization.time.start_time
+ end_t = self.ngen_realization.time.end_time
+ eval_nexus = []
+
+ for id, toid in self._catchment_hydro_fabric['toid'].items():
+ #look for an observable nexus
+ nexus_data = self._nexus_hydro_fabric.loc[toid]
+ nwis = None
+ try:
+ nwis = self._x_walk.loc[id.replace('wb', 'cat')]
+ except KeyError:
+ try:
+ nwis = self._x_walk.loc[id]
+ except KeyError:
+ #not an observable nexus, try the next one
+ continue
+ #establish the hydro location for the observation nexus associated with this catchment
+ location = NWISLocation(nwis, nexus_data.name, nexus_data.geometry)
+ nexus = Nexus(nexus_data.name, location, (), id)
+ eval_nexus.append( nexus )
+ if len(eval_nexus) != 1:
+ raise RuntimeError( "Currently only a single nexus in the hydrfabric can be gaged")
+ params = _params_as_df(self.params)
+
+ # Identify rivers draining to the stream gage
+ self.routing_output = "troute_output_" + start_t.strftime("%Y%m%d%M%H") + ".nc"
+ nexus_id = self._catchment_hydro_fabric.loc[self._x_walk.index[0].replace('cat','wb')]['toid']
+ self._wb_lst = [x.split('-')[1] for x in list(self._catchment_hydro_fabric.query('toid==@nexus_id').index)]
+ self._catchments.append(UniformCalibrationSet(eval_nexus=eval_nexus[0], routing_output=self.routing_output, start_time=start_t, end_time=end_t, eval_params=self.eval_params, obsflow_file=self.obsflow, params=params, wb_lst=self._wb_lst))
+
+class Ngen(BaseModel, Configurable, smart_union=True):
+ __root__: Union[NgenExplicit, NgenIndependent, NgenUniform] = Field(discriminator="strategy")
+
+ #proxy methods for Configurable
+ def get_args(self) -> str:
+ return self.__root__.get_args()
+ def get_binary(self) -> str:
+ return self.__root__.get_binary()
+ def update_config(self, *args, **kwargs):
+ return self.__root__.update_config(*args, **kwargs)
+ #proxy methods for model
+ @property
+ def adjustables(self):
+ return self.__root__._catchments
+
+ @property
+ def strategy(self):
+ return self.__root__.strategy
+
+ def restart(self) -> int:
+ starts = []
+ for catchment in self.adjustables:
+ starts.append(catchment.restart())
+ if all( x == starts[0] for x in starts):
+ #if everyone agress on the iteration...
+ return starts[0]
+ else:
+ return 0
+
+ @property
+ def type(self):
+ return self.__root__.type
+
+ def resolve_paths(self):
+ """resolve any possible relative paths in the realization
+ """
+ if(self.__root__.ngen_realization != None):
+ self.__root__.ngen_realization.resolve_paths()
+
+ @property
+ def best_params(self):
+ return self.__root__.eval_params.best_params
+
+ @property
+ def df_precip(self):
+ return self.__root__._precip
+
+ @property
+ def model_params(self):
+ return self.__root__.params
+
+ @property
+ def realization_file(self):
+ return self.__root__.realization
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/parameter.py b/python/runCalibValid/ngen_cal/src/ngen/cal/parameter.py
new file mode 100644
index 00000000..c6b09807
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/parameter.py
@@ -0,0 +1,22 @@
+"""
+This is a class to hold the name, initial, minimum and maximum values of calibration parameters.
+
+@author: Nels Frazer
+"""
+
+from ast import Param
+from typing import Sequence
+
+from pydantic import BaseModel, Field
+
+
+class Parameter(BaseModel, allow_population_by_field_name = True):
+ """
+ The data class for a given parameter
+ """
+ name: str = Field(alias='param')
+ min: float
+ max: float
+ init: float
+
+Parameters = Sequence[Parameter]
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/plot_functions.py b/python/runCalibValid/ngen_cal/src/ngen/cal/plot_functions.py
new file mode 100644
index 00000000..a367a4f6
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/plot_functions.py
@@ -0,0 +1,726 @@
+"""
+This module contains functions to plot output files from calibration and vallidation runs.
+@author: Xia Feng
+"""
+
+import math
+import os
+import scipy.stats as sp
+from typing import Dict, List, Optional, Union
+
+import matplotlib.pyplot as plt
+import numpy as np
+import pandas as pd
+
+__all__ = ['plot_streamflow',
+ 'plot_streamflow_precipitation',
+ 'scatterplot_streamflow',
+ 'plot_output',
+ 'scatterplot_objfun',
+ 'trim_axs',
+ 'scatterplot_var',
+ 'scatterplot_objfun_metric',
+ 'barplot_metric',
+ 'plot_fdc_calib',
+ 'plot_fdc_valid',
+ 'plot_cost_hist',
+ ]
+
+
+def plot_streamflow(
+ df: pd.DataFrame,
+ plotfile: Union[str, os.PathLike],
+ title: Optional[str] = None,
+ start_calib: Optional[str] = None,
+ end_calib: Optional[str] = None,
+ start_valid: Optional[str] = None,
+ end_valid: Optional[str] = None,
+) -> None:
+ """Plot hydrograph during calibration or validation time period.
+
+ Parameters
+ ----------
+ df : Streamflow time series from observation and different runs
+ plotfile : Image file name
+ title : Gage station name
+ start_calib, end_calib : Starting and ending date for calibration time period
+ start_valid, end_valid : Starting and ending date for validation time period
+
+ Returns:
+ ----------
+ None
+ """
+
+ print('---Plotting Streamflow Time Series---')
+
+ # Obtain column names
+ colname = list(df.columns)
+
+ # Change date column to datetime dtype
+ ts = pd.DatetimeIndex(df[colname[0]])
+ df['Dates'] = ts
+
+ # Plot
+ df = df.iloc[24:] # remove first day with possible big values
+ max0 = math.ceil(pd.melt(df, id_vars=['Time'], value_vars=colname[1:])['value'].max()) * 1.02
+ cols = ['black', 'blue', 'orange', 'tab:green'] # ['k','C1','C0','C3']
+ fig, ax = plt.subplots(figsize=(10, 6), dpi=120, tight_layout=True)
+
+ for x in colname[1:]:
+ ax.plot(df.Dates, df[x], c=cols[colname[1:].index(x)], label=x, linewidth=0.8)
+
+ ax.tick_params(axis='both', which='major', labelsize=12)
+ ax.set(ylim=(0, max0))
+ ax.set_xlabel('Date', fontsize=15)
+ ax.set_ylabel(r'$\mathsf{Streamflow}\ (\mathsf{m^3}/\mathsf{s})$', fontsize=15)
+ for label in ax.get_xticklabels(which='major'):
+ label.set(rotation=30, horizontalalignment='right')
+
+ if title is not None:
+ ax.set_title(title, fontsize=16)
+
+ if start_calib is not None and end_calib is not None and start_valid is not None and end_valid is not None:
+ ax.axvline(x=pd.DatetimeIndex([start_calib]), color="0.8", linestyle="--", linewidth=3)
+ ax.axvline(x=pd.DatetimeIndex([end_calib]), color="0.8", linestyle="--", linewidth=3)
+ if end_calib != start_valid:
+ ax.axvline(x=pd.DatetimeIndex([start_valid]), color="0.8", linestyle="--", linewidth=3)
+ ax.axvline(x=pd.DatetimeIndex([end_valid]), color="0.8", linestyle="--", linewidth=3)
+
+ ax.grid(True, color='0.8', linewidth=0.4)
+ ax.legend(loc='upper right', fontsize=12, frameon=False)
+
+ fig.savefig(plotfile)
+ plt.close()
+
+
+def plot_streamflow_precipitation(
+ df: pd.DataFrame,
+ dfp: pd.DataFrame,
+ plotfile: Union[str, os.PathLike],
+ title: Optional[str] = None,
+ start_calib: Optional[str] = None,
+ end_calib: Optional[str] = None,
+ start_valid: Optional[str] = None,
+ end_valid: Optional[str] = None,
+) -> None:
+ """Plot streamflow and precipitation during calibration or validation time period.
+
+ Parameters
+ ----------
+ df : Streamflow time series from Observation and different runs
+ dfp : Precipitation forcing time series
+ plotfile : Image file name
+ title : Gage station name
+ start_calib, end_calib : Starting and ending date for calibration time period
+ start_valid, end_valid : Starting and ending date for validation time period
+
+ Returns:
+ ----------
+ None
+
+ """
+ print('---Plotting Streamflow Time Series with Precipitation---')
+
+ # Obtain column names
+ colname = list(df.columns)
+
+ # Change date column to datetime dtype
+ ts = pd.DatetimeIndex(df[colname[0]])
+ df['Dates'] = ts
+ ts = pd.DatetimeIndex(dfp[colname[0]])
+ dfp['Dates'] = ts
+
+ # Plot
+ df = df.iloc[24:] # remove first day with possible big values
+ max0 = math.ceil(pd.melt(df, id_vars=colname[0], value_vars=colname[1:])['value'].max()) * 1.02
+ maxp = math.ceil(dfp['RAINRATE'].max())
+ if maxp > 500:
+ yint2 = 100
+ elif maxp > 200 and maxp <= 500:
+ yint2 = 80
+ elif maxp > 100 and maxp <= 200:
+ yint2 = 50
+ elif maxp > 50 and maxp <= 100:
+ yint2 = 20
+ elif maxp > 10 and maxp <= 50:
+ yint2 = 5
+ else:
+ yint2 = 2
+ ytk2 = range(0, 5*maxp+yint2, yint2)
+ label2 = [x if x None:
+ """Plot scatterplot of streamflow between observation and other runs.
+
+ Parameters
+ ----------
+ df : Streamflow time series from Observation and different runs
+ plotfile : Image file
+ title : Gage station name
+
+ Returns:
+ None
+
+ """
+ print('---Plotting Scatterplot of Streamflow between Observation and Other Runs---')
+
+ # Obtain column names and value range
+ colname = list(df.columns)
+ df = df.iloc[24:] # remove first day with possible big values
+ max0 = math.ceil(pd.melt(df, id_vars=['Time'], value_vars=colname[1:])['value'].max()) * 1.02
+
+ # Plot
+ cols = ['b', 'orange','tab:green']
+ fig, ax = plt.subplots(figsize=(10.8, 7.2), tight_layout=True)
+
+ for x in colname[2:]:
+ ax.scatter(df['Observation'], df[x], s=60, label=x, facecolors='none', edgecolors=cols[colname[2:].index(x)], marker ='o')
+ ax.plot([0, 1], [0, 1], transform=ax.transAxes, c='k')
+
+ ax.set(xlim=(0, max0), ylim=(0, max0))
+ ax.tick_params(axis='both', which='major', labelsize=15)
+ ax.set_xlabel(r'$\mathsf{Observed}\ \mathsf{Streamflow}\ (\mathsf{m^3}/\mathsf{s})$', fontsize=18)
+ ax.set_ylabel(r'$\mathsf{Simulated}\ \mathsf{Streamflow}\ (\mathsf{m^3}/\mathsf{s})$', fontsize=18)
+ if title is not None:
+ ax.set_title(title, fontsize=18, weight='bold')
+
+ ax.grid(True, color='0.7', linewidth=0.5)
+ ax.legend(loc='upper left', fontsize=18, markerscale=1.5, frameon=False)
+
+ fig.savefig(plotfile)
+ plt.close()
+
+
+def plot_output(
+ df: pd.DataFrame,
+ plotfile: Union[str, os.PathLike],
+ output_name: List[str],
+ title: Optional[str] = None,
+) -> None:
+ """Plot different model output variables compared with observation.
+
+ Parameters
+ ----------
+ df : Contains model output variables from Observation, Control Run, and Best Run
+ plotfile : Image file
+ output_name : Model output variable names
+ title : Gage station name
+
+ Returns:
+ ----------
+ None
+
+ """
+ print('---Plotting Output from Different Runs---')
+
+ # Change date column to datetime dtype
+ ts = pd.DatetimeIndex(df['Time'])
+ ts_utc = ts.tz_localize("UTC")
+ df['Dates'] = ts_utc
+
+ # Plot
+ colname = output_name[1:]
+ if 'Q_OUT' in output_name:
+ ylabels = [r'$\mathsf{Streamflow}\ (\mathsf{m^3}/\mathsf{s})$', r'$\mathsf{Direct}\ \mathsf{Runoff}\ (\mathsf{m^3}/\mathsf{s})$',
+ r'$\mathsf{GIUH}\ \mathsf{Runoff}\ (\mathsf{m^3}/\mathsf{s})$', r'$\mathsf{Lateral}\ \mathsf{Runoff}\ (\mathsf{m^3}/\mathsf{s})$',
+ r'$\mathsf{Baseflow}\ (\mathsf{m^3}/\mathsf{s})$', r'$\mathsf{Precipitation}\ (\mathsf{mm}/\mathsf{h})$']
+ if 'Qout' in output_name:
+ ylabels = [r'$\mathsf{Streamflow}\ (\mathsf{m^3}/\mathsf{s})$', r'$\mathsf{Total}\ \mathsf{Discharge}\ (\mathsf{m^3}/\mathsf{s})$',
+ r'$\mathsf{Overland}\ \mathsf{Flow}\ (\mathsf{m^3}/\mathsf{s})$', r'$\mathsf{Baseflow}\ (\mathsf{m^3}/\mathsf{s})$',
+ r'$\mathsf{Recharge}\ \mathsf{Flow}\ (\mathsf{m^3}/\mathsf{s})$', r'$\mathsf{Precipitation}\ (\mathsf{mm}/\mathsf{h})$']
+
+ lab1 = ['Control Run','Best Run', 'Observation']
+ lab2 = ['','']
+ x = lambda i: lab1 if i!=5 else lab2
+ y = lambda i: max1 if i!=5 else max2
+
+ # Specify y-axis range
+ list1= [x + '_Control' for x in colname[0:4]]
+ list2= [x + '_Best' for x in colname[0:4]]
+ list1.extend(list2)
+ df = df.iloc[24:] # remove first day with possible big values
+ max1= math.ceil(pd.melt(df, id_vars=['Time'], value_vars=[*list1, 'Observation'])['value'].max())*1.04
+ max2 = math.ceil(df[colname[5] + '_Control'].max())*1.02
+
+ # Plot
+ cols = ['b','r','k']
+ fig, ax = plt.subplots(figsize=(8.5, 11.5), nrows=6, ncols=1, sharex=True)
+ for i in range(len(colname)):
+ lab = x(i)
+ maxval = y(i)
+ ax[i].plot(df['Dates'], df[[colname[i]+'_Control']], c=cols[0], label=lab[0], linewidth=1)
+ ax[i].plot(df['Dates'], df[[colname[i]+'_Best']], c=cols[1], label=lab[1], linewidth=1)
+ if (i==0):
+ ax[i].plot(df['Dates'], df[['Observation']], c=cols[2], label=lab[2], linewidth=1)
+ ax[i].legend(loc='upper left', fontsize=10, frameon=False)
+
+ ax[i].set_ylim(0, maxval)
+ ax[i].set_ylabel(ylabels[i])
+ ax[i].tick_params(axis='both', which='major', labelsize=10)
+ ax[i].grid(True, color='0.7', linewidth=0.5)
+ if (i==5):
+ ax[i].set_xlabel('Date', fontsize=18)
+ ax[i].xaxis.set_label_coords(.5, -.5)
+ for label in ax[i].get_xticklabels(which='major'):
+ label.set(rotation=30, horizontalalignment='right')
+
+ # Set common x-axis label and title
+ fig.add_subplot(111, frameon=False)
+ plt.tick_params(labelcolor='none', which='both', top=False, bottom=False, left=False, right=False)
+ plt.suptitle(title, size=18, weight='bold')
+
+ plt.subplots_adjust(left=0.1, right=0.97, bottom=0.09, top=0.92, hspace=0.1)
+ fig.savefig(plotfile)
+ plt.close()
+
+
+def scatterplot_objfun(
+ metric_file: Union[str, os.PathLike],
+ plotfile: Union[str, os.PathLike],
+ objective_fun_column: str,
+ best_iteration: Optional[int] = None,
+ title: Optional[str] = None,
+) -> None:
+ """Scatterplot between objective function and iteration.
+
+ Parameters
+ ----------
+ metric_file : File containing metrics including objective function at each iteration
+ plotfile : Image file
+ best_iteration : Best iteration
+ title : Gage station name
+
+ Returns:
+ ----------
+ None
+
+ """
+ print('---Plotting Scatterplot between Objective Funtion and Iteration---')
+
+ # Read file
+ df = pd.read_csv(metric_file)
+
+ # Plot
+ fig, ax = plt.subplots(dpi=150, tight_layout=True)
+ ax.plot(df.loc[:,['iteration']], df.loc[:,[objective_fun_column]], marker='o', markersize=5, linewidth=0)
+
+ if best_iteration is not None:
+ bestpt, = ax.plot(best_iteration, df.loc[df['iteration'] == best_iteration, [objective_fun_column]], 'r*', markersize=10)
+ ax.legend(handles=[bestpt], labels=["Best Iteration"], loc="upper right", frameon=False)
+
+ ax.set_xlabel('Iteration', fontsize=15)
+ ax.set_ylabel('Objective Function', fontsize=15)
+ if title is not None:
+ ax.set_title(title, weight='bold', fontsize=12)
+ else:
+ ax.set_title("Scatterplot of Objective Function vs Iteration", weight='bold')
+ ax.grid(True, color='0.7', linewidth=0.6)
+
+ fig.savefig(plotfile)
+ plt.close()
+
+
+def trim_axs(axs, N: int):
+ """Reduce *axs* to *N* Axes. All further Axes are removed from the figure."""
+ axs = axs.flat
+ for ax in axs[N:]:
+ ax.remove()
+ return axs[:N]
+
+
+def scatterplot_var(
+ var_file: Union[str, os.PathLike],
+ plotfile: Union[str, os.PathLike],
+ best_iteration: Optional[int] = None,
+ title: Optional[str] = None,
+) -> None:
+ """Scatterplot between variables (metrics or parameters) and iteration.
+
+ Parameters
+ ----------
+ var_file : File containing calibration metrics or parameters for each iteration
+ plotfile : Image file
+ best_iteration : Best iteration
+ title : Gage station name
+
+ Returns:
+ ----------
+ None
+
+ """
+ print('---Plotting Scatterplot between Variables and Iteration---')
+
+ # Read file
+ df = pd.read_csv(var_file)
+ allcols = list(df.columns)[1:]
+
+ # Define figure arguments
+ if len(allcols) > 15 and len(allcols) < 20:
+ cols = 5
+ elif len(allcols) > 6 and len(allcols) <= 15:
+ cols = 5
+ else:
+ cols = 3
+ rows = math.ceil((len(allcols) - 1)/cols)
+
+ # Plot
+ fig, axs = plt.subplots(rows, cols, figsize=(12, 8), dpi=105, sharex=True)
+ axs = trim_axs(axs, len(allcols))
+ for ax, varname in zip(axs, allcols):
+ ax.plot(df.loc[:,['iteration']], df.loc[:,[varname]], marker='o', markersize=3, linewidth=0)
+ if best_iteration is not None:
+ bestpt, = ax.plot(best_iteration, df.loc[df['iteration']==best_iteration, [varname]], 'ro', markersize=5)
+ if varname==allcols[0]:
+ ax.legend(handles=[bestpt], labels=["Best Iteration"], loc='upper right', frameon=False)
+
+ ax.set_xlim(left=0, right=len(df.index))
+ ax.set_title(varname) if len(varname) < 20 else ax.set_title('_'.join(varname.split('_')[:2]))
+ ax.grid(True, color='0.7', linewidth=0.6)
+
+ # Set common x- and y-axis labels
+ fig.add_subplot(111, frameon=False)
+ plt.tick_params(labelcolor='none', which='both', top=False, bottom=False, left=False, right=False)
+ plt.xlabel("Iteration", fontsize=16)
+
+ plt.suptitle(title, size=20, weight='bold')
+ plt.subplots_adjust(left=0.06, right=0.95, bottom=0.08, top=0.86, hspace=0.25, wspace=0.38)
+ plt.savefig(plotfile)
+ plt.close()
+
+
+def scatterplot_objfun_metric(
+ var_file: Union[str, os.PathLike],
+ plotfile: Union[str, os.PathLike],
+ best_iteration: Optional[int] = None,
+ title: Optional[str] = None,
+) -> None:
+ """Scatterplot between objective function and evaluation metric.
+
+ Parameters:
+ ----------
+ var_file : File containing calibration metrics for each iteration
+ plotfile : Image file
+ best_iteration : Best iteration
+ title : Gage station name
+
+ Returns:
+ ----------
+ None
+
+ """
+ print('---Plotting Scatterplot between Objective Function and Metric---')
+
+ # Read file
+ df = pd.read_csv(var_file)
+ objcol = list(df.columns)[1]
+ allcols = list(df.columns)[2:]
+ idx = df[df.iteration==best_iteration].index
+
+ # Define figure arguments
+ figsize = (12, 8)
+ cols = 4
+ rows = math.ceil(len(allcols)/cols)
+
+ # Plot
+ fig, axs = plt.subplots(rows, cols, figsize=figsize, dpi=105, sharex=True)
+ axs = trim_axs(axs, len(allcols))
+ for ax, varname in zip(axs, allcols):
+ ax.plot(df.loc[:,[objcol]], df.loc[:,[varname]], marker='o', markersize=3, linewidth=0)
+ if best_iteration is not None:
+ bestpt, = ax.plot(df.loc[idx,[objcol]], df.loc[idx, [varname]], 'ro', markersize=5)
+ if varname==allcols[0]:
+ ax.legend(handles=[bestpt], labels=["Best Iteration"], loc='lower right', frameon=False)
+
+ ax.set_xlim(left=0, right=df[objcol].max()*1.2)
+ ax.tick_params(axis='both', which='major', labelsize=9)
+ ax.set_title(varname)
+ ax.grid(True, color='0.7', linewidth=0.6)
+
+ # Set common x- and y-axis labels
+ fig.add_subplot(111, frameon=False)
+ plt.tick_params(labelcolor='none', which='both', top=False, bottom=False, left=False, right=False)
+ plt.xlabel("Objective Function", fontsize=16)
+
+ plt.suptitle(title, size=20, weight='bold')
+ plt.subplots_adjust(left=0.06, right=0.95, bottom=0.08, top=0.85, hspace=0.25, wspace=0.38)
+
+ plt.savefig(plotfile)
+ plt.close()
+
+
+def barplot_metric(
+ df: pd.DataFrame,
+ plotfile: Union[str, os.PathLike],
+ title: Optional[str] = None,
+) -> None:
+ """Barplot of evaluation metrics from different runs.
+
+ Parameters:
+ ----------
+ df : Streamflow time series from Observation and different runs
+ plotfile : Image file
+ title : Gage station name, optional
+
+ Returns:
+ ----------
+ None
+
+ """
+ print('---Plotting Barplot of Metrics---')
+
+ # Set index
+ allcols = list(df.columns)
+ df.set_index(allcols[0:2], inplace=True)
+ allcols = list(df.columns)
+
+ # Specify figure arguments
+ figsize = (12, 8)
+ cols = 4
+ rows = math.ceil(len(allcols)/cols)
+ runtp = list(df.index.get_level_values(0).unique())
+ labels = list(df.index.get_level_values(1).unique())
+ width = 0.35
+ x = np.arange(len(labels))
+ xwidth = [x - width/2, x + width/2]
+
+ # Plot
+ fig, axs = plt.subplots(rows, cols, figsize=figsize, dpi=105, sharex=False)
+ axs = trim_axs(axs, len(allcols))
+ for ax, varname in zip(axs, allcols):
+ if varname==allcols[-1]:
+ label0 = [x.split('_')[1] for x in runtp]
+ else:
+ label0 = ["",""]
+ for i in range(len(runtp)):
+ ax.bar(xwidth[i], df.loc[(runtp[i], labels),varname].values.tolist(), width, label=label0[i])
+
+ ax.set_xticks(x)
+ if allcols.index(varname) in range(len(allcols)-cols, len(allcols)):
+ ax.set_xticklabels(labels)
+ else:
+ ax.set_xticklabels("")
+
+ ax.set_title(varname)
+ if varname==allcols[-1]:
+ ax.legend(bbox_to_anchor=(1, 0.8, 0.15, 0.15), fontsize=12)
+
+ # Set common x- and y-axis labels
+ fig.add_subplot(111, frameon=False)
+ plt.tick_params(labelcolor='none', which='both', top=False, bottom=False, left=False, right=False)
+ plt.xlabel("Simulation Time Period", weight='bold', fontsize=16)
+
+ plt.suptitle(title, size=20, weight='bold')
+ plt.subplots_adjust(left=0.06, right=0.89, bottom=0.08, top=0.85, hspace=0.25, wspace=0.35)
+
+ plt.savefig(plotfile)
+ plt.close()
+
+
+def plot_fdc_calib(
+ df: pd.DataFrame,
+ plotfile: Union[str, os.PathLike],
+ title: Optional[str] = None,
+) -> None:
+ """Plot flow duration curve of observation and simulations.
+
+ Parameters:
+ ----------
+ df : Contains model output variables from Observation, Control Run, and Best Run
+ plotfile : Image file
+ title : Gage station name, optional
+
+ Returns:
+ ----------
+ None
+
+ """
+ print('---Plotting FDC of Observation and Other Runs---')
+
+ # Figure arguments
+ colname = list(df.columns)[1:]
+ df = df.iloc[24:] # remove first day with possible big values
+ max0 = math.ceil(pd.melt(df, id_vars=[df.columns[0]], value_vars=colname[1:])['value'].max()) * 1.02
+
+ # Plot
+ cols = ['k', 'b', 'orange', 'tab:green']
+ fig, ax = plt.subplots(figsize=(10, 6), nrows=1, ncols=1)
+ for i in range(len(colname)):
+ data = np.sort(df[colname[i]])[::-1]
+ ranks = len(data) - sp.rankdata(data, method='min') + 1
+ prob = np.array([(ranks[i]*100/(len(data))) for i in range(len(data))])
+ ax.plot(prob, data, c=cols[i], label=colname[i], linewidth=2, alpha=1)
+
+ ax.set(xlim=(0, 100))
+ ax.tick_params(axis='both', which='major', labelsize=12)
+ ax.grid(True, color='0.7', linewidth=0.5)
+ ax.set_yscale('log')
+ ax.set_ylabel(r'$\mathsf{Streamflow}\ (\mathsf{m^3}/\mathsf{s})$', fontsize=16)
+ ax.legend(loc='lower left', fontsize=13, markerscale=2, frameon=False)
+
+ # Set common x- and y-axis labels
+ fig.add_subplot(111, frameon=False)
+ plt.tick_params(labelcolor='none', which='both', top=False, bottom=False, left=False, right=False)
+ plt.xlabel('Exceedence Probability (%)', weight='normal', fontsize=16)
+
+ plt.suptitle(title, size=16, weight='bold')
+ plt.subplots_adjust(left=0.07, right=0.97, bottom=0.09, top=0.85, wspace=0.05)
+ fig.savefig(plotfile)
+ plt.close()
+
+
+def plot_fdc_valid(
+ df: pd.DataFrame,
+ plotfile: Union[str, os.PathLike],
+ title: Optional[str] = None,
+ time_period: Optional[Dict[str,str]] = None,
+) -> None:
+ """Plot flow duration curve of observation and simulations.
+
+ Parameters:
+ ----------
+ df : Contains model output variables from Observation, Control Run, and Best Run
+ plotfile : Image file
+ title : Gage station name
+ time_period : Simulation time period
+
+ Returns:
+ None
+
+ """
+ print('---Plotting FDC of Observation and Other Runs---')
+
+ # Figure arguments
+ colname = list(df.columns)[1:]
+ df = df.iloc[24:] # remove initial big values
+ max0 = math.ceil(pd.melt(df, id_vars=[df.columns[0]], value_vars=colname[1:])['value'].max()) * 1.02
+
+ # Plot
+ cols = ['k', 'b', 'orange', 'tab:green'] # cols = ['k','C1','C0','C3']
+ keys = list(time_period.keys())
+ df.set_index(df.columns[0], inplace=True)
+ fig, ax = plt.subplots(figsize=(12.2, 5.8), nrows=1, ncols=3, sharey=True)
+ for key, value in time_period.items():
+ df_copy = df.copy()
+ df_sub = df_copy[value[0]:value[1]]
+ j = keys.index(key)
+ for i in range(len(colname)):
+ data = np.sort(df_sub[colname[i]])[::-1]
+ ranks = len(data) - sp.rankdata(data, method='min') + 1
+ prob = np.array([(ranks[i]*100/(len(data))) for i in range(len(data))])
+ ax[j].plot(prob, data, c=cols[i], label=colname[i], linewidth=1, alpha=1)
+
+ ax[j].set(xlim=(0, 100))
+ ax[j].set_yscale('log')
+ ax[j].tick_params(axis='both', which='major', labelsize=10)
+ ax[j].set_title(key, fontsize=12, weight='normal')
+ ax[j].grid(True, color='0.7', linewidth=0.5)
+ if (j==0):
+ ax[j].legend(loc='lower left', fontsize=13, markerscale=2, frameon=False)
+
+ # Set common x- and y-axis labels
+ fig.add_subplot(111, frameon=False)
+ plt.tick_params(labelcolor='none', which='both', top=False, bottom=False, left=False, right=False)
+ plt.xlabel('Exceedence Probability (%)', weight='normal', fontsize=16)
+ plt.ylabel(r'$\mathsf{Streamflow}\ (\mathsf{m^3}/\mathsf{s})$', weight='normal', fontsize=16)
+
+ plt.suptitle(title, size=18, weight='bold')
+ plt.subplots_adjust(left=0.07, right=0.97, bottom=0.09, top=0.82, wspace=0.05)
+ fig.savefig(plotfile)
+ plt.close()
+
+
+def plot_cost_hist(
+ cost_hist_file: Union[str, os.PathLike],
+ plotfile: Union[str, os.PathLike],
+ title: Optional[str] = None,
+) -> None:
+ """Plot convergence curve.
+
+ Parameters:
+ ----------
+ cost_hist_file : File containing global best and mean local best cost function values at each iteration
+ plotfile : Image file
+ title : Figure title
+
+ Returns:
+ ----------
+ None
+
+ """
+ print('---Plotting Convergence Curve for Global and Local Best Values---')
+
+ # Read file
+ df = pd.read_csv(cost_hist_file)
+ df.pop('iteration')
+ colname = df.columns
+ cost_name = {'global_best': 'Global Best', 'local_best': 'Mean Local Best', 'leader_best': 'Mean Leader Best'}
+
+ # Plot
+ cols = {'global_best': 'r', 'local_best': 'b', 'leader_best': 'y'}
+ markers = {'global_best': 'o', 'local_best': '^', 'leader_best': 'd'}
+ fig, ax = plt.subplots(dpi=150, tight_layout=True)
+ for x in colname:
+ ax.plot(np.arange(0,len(df)), df[x], c=cols[x], label=cost_name[x], linewidth=1)
+
+ ax.set_xlabel('Iteration', fontsize=15)
+ ax.set_ylabel('Objective Function', fontsize=15)
+ ax.legend(fontsize=10, loc="upper right", frameon=False)
+ if title is not None:
+ ax.set_title(title, weight='bold', fontsize=10)
+ else:
+ ax.set_title("Convergence Curve", weight='bold')
+ ax.grid(True, color='0.7', linewidth=0.6)
+
+ fig.savefig(plotfile)
+ plt.close()
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/plot_output.py b/python/runCalibValid/ngen_cal/src/ngen/cal/plot_output.py
new file mode 100644
index 00000000..aa0e2fa2
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/plot_output.py
@@ -0,0 +1,262 @@
+"""
+This module contains functions to read output files from calibration
+and validation runs, and generate a variery of plots.
+
+@author: Xia Feng
+"""
+
+import copy
+from functools import reduce
+import glob
+from math import log
+import os
+import subprocess
+from typing import Dict, List, TYPE_CHECKING, Optional, Union
+
+import numpy as np
+import pandas as pd
+
+import ngen.cal.metric_functions as mf
+import ngen.cal.plot_functions as plf
+
+if TYPE_CHECKING:
+ from ngen.cal.agent import Agent
+ from ngen.cal import Evaluatable
+
+__all__ = ['plot_calib_output',
+ 'plot_valid_output',
+ 'plot_cost_func',
+ ]
+
+
+def plot_calib_output(
+ i: int,
+ calibration_object: 'Evaluatable',
+ agent: 'Agent',
+ eval_range: Optional[List[str]] = None,
+) -> None:
+ """Plot streamflow and other model output as well as metrics for calibration run.
+
+ Parameters
+ ----------
+ calibration_object : catchment object
+ meta : meta object
+ eval_range : evaluation time period for calibration run
+
+ Returns
+ ----------
+ None
+
+ """
+ # Output files from different runs
+ control_run = calibration_object.basinID + '_output_iteration_0000.csv'
+ control_run = os.path.join(agent.output_iter_path, control_run)
+ best_run = calibration_object.basinID + '_output_best_iteration.csv'
+ best_run = os.path.join(agent.job.workdir, best_run)
+ last_run = calibration_object.basinID + '_output_last_iteration.csv'
+ last_run = os.path.join(agent.job.workdir, last_run)
+
+ # Read output
+ df_control_run = pd.read_csv(control_run)
+ df_control_run['Time'] = pd.DatetimeIndex(df_control_run['Time'])
+ df_control = df_control_run[['Time', calibration_object.streamflow_name]]
+ df_control = df_control.rename(columns={calibration_object.streamflow_name: 'Control Run'})
+ df_control.set_index('Time', inplace=True)
+ df_best_run = pd.read_csv(best_run)
+ df_best = df_best_run[['Time',calibration_object.streamflow_name]]
+ df_best = df_best.rename(columns={calibration_object.streamflow_name: 'Best Run'})
+ df_best['Time'] = pd.DatetimeIndex(df_best['Time'])
+ df_best.set_index('Time', inplace=True)
+ df_last_run = pd.read_csv(last_run)[['Time',calibration_object.streamflow_name]]
+ df_last = df_last_run[['Time',calibration_object.streamflow_name]]
+ df_last = df_last.rename(columns={calibration_object.streamflow_name: 'Last Run'})
+ df_last['Time'] = pd.DatetimeIndex(df_last['Time'])
+ df_last.set_index('Time', inplace=True)
+ dfs1 = [calibration_object.observed, df_control, df_best, df_last]
+ df_merged = reduce(lambda left, right: pd.merge(left, right, left_index=True, right_index=True, how='right'), dfs1)
+ df_merged = df_merged.rename(columns={'obs_flow': 'Observation'})
+ df_merged[['Control Run','Best Run','Last Run']] = df_merged[['Control Run','Best Run','Last Run']]
+ if df_merged.empty:
+ print("WARNING: can't merge different runs")
+ if eval_range:
+ df_merged = df_merged.loc[eval_range[0]:eval_range[1]]
+ df_merged.reset_index(inplace=True)
+ df_merged = df_merged.rename(columns={'index': 'Time'})
+ df_merged = mf.treat_values(df_merged, remove_neg = True)
+ df_merged_copy1 = copy.deepcopy(df_merged)
+
+ # Plot hydrograph
+ fig_path = agent.plot_iter_path
+ if calibration_object.save_plot_iter_flag:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_hydrograph_iteration_' + str('{:04d}').format(i) + '.png')
+ else:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_hydrograph_iteration.png')
+ title = 'Hydrograph at Iteration = ' + str(i) + '\n' + calibration_object.station_name
+ plf.plot_streamflow(df_merged_copy1, plotfile, title)
+
+ # Plot scatterplot of streamflow from observation and other runs
+ if calibration_object.save_plot_iter_flag:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_scatterplot_streamflow_iteration_' + str('{:04d}').format(i) + '.png')
+ else:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_scatterplot_streamflow_iteration.png')
+ title = 'Scatterplot of Streaflow at Iteration = ' + str(i) + '\n' + calibration_object.station_name
+ df_merged_copy2 = copy.deepcopy(df_merged)
+ plf.scatterplot_streamflow(df_merged_copy2, plotfile, title)
+
+ # Plot flow duration curve from observation and other runs
+ if calibration_object.save_plot_iter_flag:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_fdc_iteration_' + str('{:04d}').format(i) + '.png')
+ else:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_fdc_iteration.png')
+ title = 'Flow Duration Curve at Iteration = ' + str(i) + '\n' + calibration_object.station_name
+ df_merged_copy3 = copy.deepcopy(df_merged)
+ plf.plot_fdc_calib(df_merged_copy3, plotfile, title)
+
+ # Plot time series of streamflow and precipitation
+ if calibration_object.save_plot_iter_flag:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_streamflow_precip_iteration_' + str('{:04d}').format(i) + '.png')
+ else:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_streamflow_precip_iteration.png')
+ title = 'Streamflow and Total Precipitation at Iteration = ' + str(i) + '\n' + calibration_object.station_name
+ df_merged_copy4 = copy.deepcopy(df_merged)
+ plf.plot_streamflow_precipitation(df_merged_copy4, agent.df_precip, plotfile, title)
+
+ # Plot scatterplot between objective function and iteration
+ if calibration_object.save_plot_iter_flag:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_objfun_iteration_' + str('{:04d}').format(i) +'.png')
+ else:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_objfun_iteration.png')
+ title = 'Scatterplot of Objective Function vs Iteration ' + '\n' + calibration_object.station_name
+ plf.scatterplot_objfun(calibration_object.metric_iter_file, plotfile, "objFunVal", int(calibration_object.best_params), title)
+
+ # Plot scatterplot between metrics and iteration
+ if calibration_object.save_plot_iter_flag:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_metric_iteration_' + str('{:04d}').format(i) +'.png')
+ else:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_metric_iteration.png')
+ title = 'Scatterplot of Metrics vs Iteration ' + '\n' + calibration_object.station_name
+ plf.scatterplot_var(calibration_object.metric_iter_file, plotfile, int(calibration_object.best_params), title)
+
+ # Plot scatterplot between metrics and objective function
+ if calibration_object.save_plot_iter_flag:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_metric_objfun_' + str('{:04d}').format(i) +'.png')
+ else:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_metric_objfun.png')
+ title = 'Scatterplot of Metrics vs Objectiv Function ' + '\n' + calibration_object.station_name
+ plf.scatterplot_objfun_metric(calibration_object.metric_iter_file, plotfile, int(calibration_object.best_params), title)
+
+ # Plot scatterplot between parameters and iteration
+ if calibration_object.save_plot_iter_flag:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_param_iteration_' + str('{:04d}').format(i) +'.png')
+ else:
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_param_iteration.png')
+ title = 'Scatterplot of Parameters vs Iteration ' + '\n' + calibration_object.station_name
+ plf.scatterplot_var(calibration_object.param_iter_file, plotfile, int(calibration_object.best_params), title)
+
+ # Plot scatterplot between parameters and iteration
+ if agent.algorithm !='dds':
+ plf.scatterplot_var(calibration_object.param_iter_file, plotfile, int(calibration_object.best_params), title)
+ plot_cost_func(calibration_object, agent, os.path.join(agent.workdir, calibration_object.cost_iter_file), agent.algorithm, calib_iter=False)
+
+def plot_valid_output(
+ calibration_object: 'Evaluatable',
+ agent: 'Agent',
+ time_period: Optional[Dict[str,str]] = None,
+) -> None:
+ """Plot streamflow and other model output as well as metrics for validation run.
+
+ Parameters
+ ----------
+ calibration_object : catchment object
+ calibration_object : calibration_object object
+ time_period : calib, valid and full time periods
+
+ Returns
+ ----------
+ None
+
+ """
+ # Output files from different validation runs
+ control_run = os.path.join(agent.valid_path, calibration_object.basinID + '_output_valid_control.csv')
+ best_run = os.path.join(agent.valid_path, calibration_object.basinID + '_output_valid_best.csv')
+
+ # Read output
+ df_control_run = pd.read_csv(control_run)
+ df_control_run['Time'] = pd.DatetimeIndex(df_control_run['Time'])
+ df_control = df_control_run[['Time', calibration_object.streamflow_name]]
+ df_control = df_control.rename(columns={calibration_object.streamflow_name: 'Control Run'})
+ df_control.set_index('Time', inplace=True)
+ df_best_run = pd.read_csv(best_run)
+ df_best = df_best_run[['Time', calibration_object.streamflow_name]]
+ df_best_run['Time'] = pd.DatetimeIndex(df_best_run['Time'])
+ df_best = df_best.rename(columns={calibration_object.streamflow_name: 'Best Run'})
+ df_best['Time'] = pd.DatetimeIndex(df_best['Time'])
+ df_best.set_index('Time', inplace=True)
+
+ dfs1 = [calibration_object.observed, df_control, df_best]
+ df_merged = reduce(lambda left, right: pd.merge(left, right, left_index=True, right_index=True, how='right'), dfs1)
+ df_merged = df_merged.rename(columns={'obs_flow': 'Observation'})
+ df_merged[['Control Run','Best Run']] = df_merged[['Control Run','Best Run']]
+ df_merged.reset_index(inplace=True)
+ df_merged = df_merged.rename(columns={'index': 'Time'})
+ df_merged = mf.treat_values(df_merged, remove_neg = True)
+ df_merged_copy1 = copy.deepcopy(df_merged)
+
+ # Plot hydrograph
+ fig_path = agent.valid_path_plot
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_hydrograph_valid_run.png')
+ title = 'Hydrograph during Calibration and Validation period' + '\n' + calibration_object.station_name
+ plf.plot_streamflow(df_merged_copy1, plotfile, title, calibration_object.evaluation_range[0], calibration_object.evaluation_range[1],
+ calibration_object.valid_evaluation_range[0], calibration_object.valid_evaluation_range[1])
+
+ # Plot flow duration curve
+ df_merged_copy2 = copy.deepcopy(df_merged)
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_fdc_valid_run.png')
+ title = 'Flow Duration Curve during Calibration and Validation period' + '\n' + calibration_object.station_name
+ plf.plot_fdc_valid(df_merged_copy2, plotfile, title, time_period)
+
+ # Plot time series of streamflow and precipitation
+ df_merged_copy3 = copy.deepcopy(df_merged)
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_streamflow_precip_valid_run.png')
+ title = 'Streamflow and Total Precipitation during Calibration and Validation Period ' + '\n' + calibration_object.station_name
+ plf.plot_streamflow_precipitation(df_merged_copy3, agent.df_precip, plotfile, title, calibration_object.evaluation_range[0],
+ calibration_object.evaluation_range[1], calibration_object.valid_evaluation_range[0], calibration_object.valid_evaluation_range[1])
+
+ # Plot metrics
+ metric_control = os.path.join(agent.valid_path, calibration_object.basinID + '_metrics_valid_control.csv')
+ mdf_control = pd.read_csv(metric_control)
+ metric_best = os.path.join(agent.valid_path, calibration_object.basinID + '_metrics_valid_best.csv')
+ mdf_best = pd.read_csv(metric_best)
+ mdf = pd.concat([mdf_control, mdf_best], ignore_index=True)
+ plotfile = os.path.join(fig_path, calibration_object.basinID + '_barplot_metrics_valid_run.png')
+ title = 'Metrics from Different Simulation Time Period' + '\n' + calibration_object.station_name
+ plf.barplot_metric(mdf, plotfile, title)
+
+def plot_cost_func(
+ calibration_object: 'Evaluatable',
+ agent: 'Agent',
+ cost_hist_file: Union[str, os.PathLike],
+ algorithm: str,
+ calib_iter: Optional[bool] = False,
+) -> None:
+ """Plot convergence curve.
+
+ Parameters
+ ----------
+ calibration_object : Evaluatable object
+ agent : Agent object
+ cost_hist_file : File containing global best and local best ost function values at each iteration
+ algorithm : Optimzation algorithm
+ calib_iter : Whether plot for each iteration or after all iterations are finished, default False
+
+ Returns
+ ----------
+ None
+
+ """
+ if calib_iter:
+ plotfile = os.path.join(agent.workdir, calibration_object.basinID + '_cost_iter.png')
+ else:
+ plotfile = os.path.join(agent.workdir, calibration_object.basinID + '_cost_hist.png')
+ title = algorithm.upper() + ' Convergence Curve ' + '\n' + calibration_object.station_name
+ plf.plot_cost_hist(cost_hist_file, plotfile, title)
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/search.py b/python/runCalibValid/ngen_cal/src/ngen/cal/search.py
new file mode 100644
index 00000000..d2746189
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/search.py
@@ -0,0 +1,456 @@
+"""
+This module contains functions to perform parameter optimization using different algorithms.
+
+@author: Nels Frazer, Xia Feng
+"""
+
+import glob
+from functools import partial
+from math import log
+from multiprocessing import pool
+import os
+import subprocess
+from datetime import datetime
+from typing import Dict, Optional, Tuple, TYPE_CHECKING
+
+import numpy as np # type: ignore
+import pandas as pd # type: ignore
+
+from .gwo_global_best import GlobalBestGWO
+from .metric_functions import treat_values, calculate_all_metrics
+from .plot_output import plot_calib_output, plot_cost_func
+from .utils import pushd, complete_msg
+
+if TYPE_CHECKING:
+ from ngen.cal import Adjustable, Evaluatable
+ from ngen.cal.agent import Agent
+
+
+"""Global private iteration counter
+
+This counter is used by PSO search so that iteration information can be captured
+and recorded from within a generic functional representation of an abstract model
+managed by a calibration agent.
+"""
+__iteration_counter = 1
+
+
+def _execute(meta: 'Agent', i: int = None) -> None:
+ """Execute model run via BMI.
+
+ Parameters
+ ----------
+ meta : Agent object
+ i : Current iteration, default None
+
+ """
+ if meta.job.log_file is None:
+ subprocess.check_call(meta.cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=True, cwd=meta.job.workdir)
+ else:
+ run_log_file = str(meta.job.log_file)
+ if not os.path.exists(run_log_file):
+ with open(run_log_file, 'w') as log_file:
+ log_file.write('Starting ' + '{}'.format(meta.run_name).capitalize() + ' Run\n')
+ if i is not None:
+ with open(run_log_file, 'a+') as log_file:
+ log_file.write('------ Iteration = {}'.format(i) + ' ------\n')
+ with open(run_log_file, 'a+') as log_file:
+ subprocess.check_call(meta.cmd, stdout=log_file, stderr=log_file, shell=True, cwd=meta.job.workdir)
+
+def _calc_metrics(
+ simulated_hydrograph: pd.Series,
+ observed_hydrograph: pd.Series,
+ eval_range: Tuple[datetime, datetime] = None,
+ threshold: Optional[float] = None,
+) -> Dict[str, float]:
+ """Calculate statistical metrics.
+
+ Parameters
+ ----------
+ simulated_hydrograph : Time series of simulated streamflow
+ observed_hydrograph : Time series of observed streamflow
+ eval_range : Evaluation time period for calibration run
+ threshold : Streamflow threshold for calculating categorical scores
+
+ Returns
+ ----------
+ Dictionary of metrics
+
+ """
+ df = pd.merge(simulated_hydrograph, observed_hydrograph, left_index=True, right_index=True)
+ if df.empty:
+ print("WARNING: Cannot compute objective function, do time indicies align?")
+ if eval_range:
+ df = df.loc[eval_range[0]:eval_range[1]]
+
+ df.reset_index(inplace=True)
+ df = treat_values(df, remove_neg = True, remove_na = True)
+ obsflow = df['obs_flow']
+ simflow = df['sim_flow']
+
+ return calculate_all_metrics(obsflow, simflow, threshold)
+
+def _evaluate(i: int, calibration_object: 'Evaluatable', agent: 'Agent', info: bool=False) -> float:
+ """ Calculate objective function and evaluation metrics.
+ Save calibration output and generate plots during iteration.
+
+ parameters
+ ----------
+ i : current iteration
+ calibration_object : Adjustable object
+ agent : Agent object
+ info : whether to print objective, best objective and best parameter to screen, default False
+
+ Returns
+ ----------
+ Objection funciton at current iteration
+
+ """
+ # Calculate objective function and metrics
+ metrics = _calc_metrics(calibration_object.output, calibration_object.observed, calibration_object.evaluation_range, calibration_object.threshold)
+ metric_objective_function = metrics[calibration_object.objective.value.upper()]
+ score = 1 - metric_objective_function if calibration_object.target == 'min' else metric_objective_function
+
+ # Update based on latest objective function and write log files
+ calibration_object.update(i, score, log=True, algorithm=agent.algorithm)
+ if info:
+ print("Current score {}\nBest score {}".format(score, calibration_object.best_score))
+ print("Best parameters at iteration {}".format(calibration_object.best_params))
+
+ # Save metrics
+ calibration_object.write_metric_iter_file(i, score, metrics)
+
+ # Save params
+ calibration_object.write_param_iter_file(i, calibration_object.df[[str(i),'param']])
+
+ # Save output
+ calibration_object.save_calib_output(i, str(calibration_object.output_iter_file), str(calibration_object.last_output_file), agent.output_iter_path,
+ agent.job.workdir, agent.calib_path_output, calibration_object.save_output_iter_flag)
+ calibration_object.save_best_output(str(calibration_object.best_output_file), calibration_object.best_save_flag)
+
+ # Save global and local best cost, and plot
+ if len(glob.glob('*.log'))==1 and agent.algorithm !='dds':
+ calibration_object.write_cost_iter_file(i, agent.workdir)
+
+ # Plot metrics, parameters and output
+ if len(glob.glob('*.log'))==1 and i%calibration_object.save_plot_iter_freq==0:
+ plot_calib_output(i, calibration_object, agent)
+
+ # Save last iteration
+ calibration_object.write_last_iteration(i)
+
+
+def dds_update(iteration: int, inclusion_probability: float, calibration_object: 'Adjustable', agent: 'Agent') -> None:
+ """ Dynamically dimensioned search optimization algorithm.
+
+ parameters
+ ----------
+ iteration : Current iteration
+ inclusion_probability : Probability of each parameter included in neighborhood
+ calibration_object : Adjustable object
+ agent : Agent object
+
+ """
+ print( "inclusion probability: {}".format(inclusion_probability) )
+ neighborhood = calibration_object.variables.sample(frac=inclusion_probability)
+ if neighborhood.empty:
+ neighborhood = calibration_object.variables.sample(n=1)
+ print( "neighborhood:\n{}".format(neighborhood) )
+
+ # Generate new parameter set by perturbng the best parameters
+ calibration_object.df[str(iteration)] = calibration_object.df[agent.best_params]
+ for n in neighborhood:
+ new = calibration_object.df.loc[n, agent.best_params] + calibration_object.df.loc[n, 'sigma']*np.random.normal(0,1)
+ lower = calibration_object.df.loc[n, 'min']
+ upper = calibration_object.df.loc[n, 'max']
+ if new < lower:
+ new = lower + (lower - new)
+ if new > upper:
+ new = lower
+ elif new > upper:
+ new = upper - (new - upper)
+ if new < lower:
+ new = upper
+ calibration_object.df.loc[n, str(iteration)] = new
+
+ # Fill parameters for all formulations with unique parameter
+ calibration_object.df_fill(iteration)
+
+ # Update realization config file with new parameters
+ agent.update_config(iteration, calibration_object.adf[[str(iteration), 'param', 'model']], calibration_object.id)
+
+def dds(start_iteration: int, iterations: int, calibration_object: 'Evaluatable', agent: 'Agent')->None:
+ """Perform parameter optimization using DDS algorithm.
+
+ Parameters
+ ----------
+ start_iteration : starting iteration
+ iterations : total number of iterations
+ agent : Agent object
+
+ """
+ if iterations < 2:
+ raise(ValueError("iterations must be >= 2"))
+ if start_iteration > iterations:
+ raise(ValueError("start_iteration must be <= iterations"))
+
+ init = start_iteration - 1 if start_iteration > 0 else start_iteration
+ neighborhood_size = agent.parameters.get('neighborhood', 0.2)
+ calibration_object.df['sigma'] = neighborhood_size*(calibration_object.df['max'] - calibration_object.df['min'])
+ agent.update_config(init, calibration_object.df[[str(init), 'param', 'model']], calibration_object.id)
+
+ # Produce baseline simulation output using the default parameter set
+ if start_iteration == 0:
+ if calibration_object.output is None:
+ print("Running {} to produce initial simulation".format(agent.cmd))
+ agent.update_config(start_iteration, calibration_object.df[[str(start_iteration), 'param', 'model']], calibration_object.id)
+ _execute(agent, start_iteration)
+ with pushd(agent.job.workdir):
+ _evaluate(0, calibration_object, agent, info=True)
+ calibration_object.check_point(agent.job.workdir)
+ start_iteration += 1
+
+ for i in range(start_iteration, iterations+1):
+ # Calculate probability of inclusion
+ inclusion_probability = 1 - log(i)/log(iterations)
+ dds_update(i, inclusion_probability, calibration_object, agent)
+ # Run cmd
+ print("Running {} for iteration {}".format(agent.cmd, i))
+ _execute(agent, i)
+ with pushd(agent.job.workdir):
+ _evaluate(i, calibration_object, agent)
+ calibration_object.check_point(agent.job.workdir)
+
+def dds_set(start_iteration: int, iterations: int, agent: 'Agent')->None:
+ """Perform parameter optimization using DDS algorithm.
+
+ parameters
+ ----------
+ start_iteration : starting iteration
+ iterations : total number of iterations
+ agent : Agent object
+
+ """
+ # TODO I think the can ultimately be refactored and merged with dds, there only a couple very
+ # minor differenes in this implementation, and I think those can be abstrated away
+ # by carefully crafting sets and adjustables before this function is ever reached.
+ if iterations < 2:
+ raise(ValueError("iterations must be >= 2"))
+ if start_iteration > iterations:
+ raise(ValueError("start_iteration must be <= iterations"))
+
+ neighborhood_size = agent.parameters.get('neighborhood', 0.2)
+ calibration_sets = agent.model.adjustables
+ init = start_iteration - 1 if start_iteration > 0 else start_iteration
+
+ for calibration_set in calibration_sets:
+ for calibration_object in calibration_set.adjustables:
+ calibration_object.df['sigma'] = neighborhood_size*(calibration_object.df['max'] - calibration_object.df['min'])
+ #TODO optimize by passing the set and iterating in update, then only have to write once to file
+ calibration_object.df_fill(init)
+ agent.update_config(init, calibration_object.adf[[str(init), 'param', 'model']], calibration_object.id)
+
+ # Produce baseline simulation output using the default parameter set
+ if start_iteration == 0:
+ if calibration_set.output is None:
+ print("Running {} to produce initial simulation".format(agent.cmd))
+ _execute(agent, start_iteration)
+ with pushd(agent.job.workdir):
+ _evaluate(0, calibration_set, agent, info=True)
+ calibration_set.check_point(agent.job.workdir)
+ start_iteration += 1
+
+ for i in range(start_iteration, iterations+1):
+ # Calculate probability of inclusion
+ inclusion_probability = 1 - log(i)/log(iterations)
+ for calibration_object in calibration_set.adjustables:
+ dds_update(i, inclusion_probability, calibration_object, agent)
+
+ # Execute model run
+ print("Running {} for iteration {}".format(agent.cmd, i))
+ _execute(agent, i)
+ with pushd(agent.job.workdir):
+ _evaluate(i, calibration_set, agent)
+ calibration_set.check_point(agent.job.workdir)
+
+ # Create configuration files for validation run
+ calibration_object.create_valid_realization_file(agent, calibration_object.adf)
+
+ # Indicate completion
+ calibration_object.write_run_complete_file(agent.run_name, agent.workdir)
+ complete_msg(calibration_object.basinID, agent.run_name, agent.workdir, calibration_object.user)
+
+def compute(calibration_object: 'Adjustable', iteration: int, input: Tuple) -> float:
+ """Execute run and evaluate objection function.
+
+ parameters
+ ----------
+ calibration_object : Adjustable object
+ iteration : starting iteration
+ input : Agent and associated parameters
+
+ """
+ params = input[0]
+ agent = input[1]
+
+ # Execute run with the updated parameter set and evaluate objective function
+ calibration_object.df[str(iteration)] = params
+ with pushd(agent.job.workdir):
+ agent.update_config(iteration, calibration_object.df[[str(iteration), 'param', 'model']], calibration_object.id)
+ _execute(agent, iteration)
+ cost = _evaluate(iteration, calibration_object, agent)
+ calibration_object.check_point(agent.job.workdir)
+ return cost
+
+def cost_func( calibration_object: 'Adjustable', agents: 'Agent', pool: int, params: pd.DataFrame):
+ """Compute cost function for each iteration.
+
+ Parameters:
+ ----------
+ calibration_object : Adjustable object
+ agents : Agent object
+ pool : Pool size
+ params : Parameter set
+
+ Returns:
+ ----------
+
+ """
+ global __iteration_counter
+ #TODO implement multi-processing here???
+ func = partial(compute, calibration_object, __iteration_counter)
+ costs = np.fromiter(pool.imap(func, zip(params, agents)), dtype=float)
+ __iteration_counter = __iteration_counter + 1
+
+ return costs
+
+def pso_search(start_iteration: int, iterations: int, agent: 'Agent') -> None:
+ """Search optimal parameter set using PSO algorithm.
+
+ parameters
+ ----------
+ start_iteration : starting iteration
+ iterations : total number of iterations
+ agent : Agent object
+
+ """
+ import pyswarms as ps
+
+ # Utilizing PSO optimizers requires n "particles" to run -- so we need to take the existing meta
+ # and create a unique copy customized for each particle, so then each one gets an execution/update
+ num_particles = agent.parameters.get('particles', 4)
+ pool_size = agent.parameters.get("pool", 1)
+ print("Running PSO with {} particles using {} processes".format(num_particles, pool_size))
+
+ #TODO warn about potential loss of data when particles > pool
+ _pool = pool.Pool(pool_size)
+ agents = [agent] + [ agent.duplicate() for i in range(num_particles-1) ]
+ default_options = {'c1': 0.5, 'c2': 0.3, 'w':0.9}
+ options = agent.parameters.get("options", default_options)
+ for calibration_object in agent.model.adjustables:
+ #Produce the baseline simulation output for first agent
+ if start_iteration == 0:
+ if calibration_object.output is None:
+ print("Running {} to produce initial simulation".format(agent.cmd))
+ agent.update_config(start_iteration, calibration_object.df[[str(start_iteration), 'param', 'model']], calibration_object.id)
+ _execute(agent, start_iteration)
+ with pushd(agent.job.workdir):
+ _evaluate(0, calibration_object, agent, info=True)
+ calibration_object.check_point(agent.job.workdir)
+ bounds = calibration_object.bounds
+ bounds = (bounds[0].values, bounds[1].values)
+
+ # Call instance of PSO
+ # TODO hook other pyswarm algorithms by user selection
+ # TODO hook swarmpackagepy algorithms by user selection (they follow a very similar functional pattern)
+ # A quick look at swarmpackagepy shows that it might be a little more challenging since it does this to update states:
+ """
+ Pbest = self.__agents[
+ np.array([function(x) for x in self.__agents]).argmin()]
+ if function(Pbest) < function(Gbest):
+ Gbest = Pbest
+ """
+ # meaning that the cost_func is called multiple time PER ITERATION, which doesn't coincide with the architecture
+ # we are using here to interface with pyswarm, which only calls the cost_func once per iteration, and tracks other states internally
+ # this is a significant problem, especially considering the computation costs of our "cost_function"
+ optimizer = ps.single.GlobalBestPSO(n_particles=num_particles, dimensions=len(calibration_object.df), options=options, bounds=bounds)
+ cf = partial(cost_func, calibration_object, agents, _pool)
+
+ # Perform optimization
+ # For pyswarm, DO NOT use the embedded multi-processing -- it is impossible to track the mapping of an agent to the params
+ cost, pos = optimizer.optimize(cf, iters=iterations, n_processes=None)
+ calibration_object.df.loc[:,'global_best'] = pos
+ calibration_object.check_point(agent.workdir)
+ print("Best params with cost {}:".format(cost))
+ print(calibration_object.df[['param','global_best']].set_index('param'))
+
+ # Save and plot history
+ cost_hist_file = calibration_object.write_hist_file(optimizer, agent, list(calibration_object.df['param']))
+ plot_cost_func(calibration_object, agent, cost_hist_file, agent.algorithm)
+
+ # Create configuration files for validation run
+ calibration_object.create_valid_realization_file(agent, calibration_object.df)
+
+ # Indicate completion
+ calibration_object.write_run_complete_file(agent.run_name, agent.workdir)
+ complete_msg(calibration_object.basinID, agent.run_name, agent.workdir, calibration_object.user)
+
+def gwo_search(start_iteration: int, iterations: int, agent)->None:
+ """Search optimal parameter set using GWO algorithm.
+
+ parameters
+ ----------
+ start_iteration : start iteration
+ iterations : total number of iterations
+ agent : Agent object
+
+ """
+ global __iteration_counter
+ __iteration_counter = start_iteration + 1 if start_iteration==0 else start_iteration
+ print("_iteration_counter is", __iteration_counter)
+ num_particles = agent.parameters.get('particles', 10)
+ pool_size = agent.parameters.get("pool", num_particles)
+ print("Running GWO with {} particles using {} processes".format(num_particles, pool_size))
+ _pool = pool.Pool(pool_size)
+ if start_iteration ==0:
+ agents = [agent] + [ agent.duplicate() for i in range(num_particles-1) ]
+ else:
+ agents = [agent] + [ agent.duplicate(restart_flag=True, agent_counter=i+1) for i in range(num_particles-1) ]
+ for agent in agents:
+ if len(glob.glob(os.path.join(agent.job.workdir, '*.log')))!=1:
+ agent.restart()
+ for calibration_object in agent.model.adjustables:
+ #Produce the baseline simulation output for first agent
+ if start_iteration == 0:
+ if calibration_object.output is None:
+ print("Running {} to produce initial simulation".format(agent.cmd))
+ agent.update_config(start_iteration, calibration_object.df[[str(start_iteration), 'param', 'model']], calibration_object.id)
+ _execute(agent, start_iteration)
+ with pushd(agent.job.workdir):
+ _evaluate(0, calibration_object, agent, info=True)
+ calibration_object.check_point(agent.job.workdir)
+ bounds = calibration_object.bounds
+ bounds = (bounds[0].values, bounds[1].values)
+
+ # Initialize swarms
+ optimizer = GlobalBestGWO(n_particles=num_particles, dimensions=len(calibration_object.df), bounds=bounds, start_iter=start_iteration,
+ calib_path=agent.calib_path, basinid=calibration_object.basinID)
+ cf = partial(cost_func, calibration_object, agents, _pool)
+
+ # Perform optimization
+ cost, pos = optimizer.optimize(cf, iters=iterations, n_processes=None)
+ calibration_object.df.loc[:,'global_best'] = pos
+ calibration_object.check_point(agent.workdir)
+ print("Best params with cost {}:".format(cost))
+ print(calibration_object.df[['param','global_best']].set_index('param'))
+
+ # Save and plot history
+ cost_hist_file = calibration_object.write_hist_file(optimizer, agent, list(calibration_object.df['param']))
+ plot_cost_func(calibration_object, agent, cost_hist_file, agent.algorithm)
+
+ # Create configuration files for validation run
+ calibration_object.create_valid_realization_file(agent, calibration_object.df)
+
+ # Indicate completion
+ calibration_object.write_run_complete_file(agent.run_name, agent.workdir)
+ complete_msg(calibration_object.basinID, agent.run_name, agent.workdir, calibration_object.user)
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/strategy.py b/python/runCalibValid/ngen_cal/src/ngen/cal/strategy.py
new file mode 100644
index 00000000..58d34a8b
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/strategy.py
@@ -0,0 +1,54 @@
+"""
+This module includes several classes to hold algorithm, objective functions and strategy.
+
+@author: Nels Frazer, Xia Feng
+"""
+
+from enum import Enum
+from pydantic import BaseModel, PyObject, validator
+from typing import Optional, Mapping, Any
+try: #to get literal in python 3.7, it was added to typing in 3.8
+ from typing import Literal
+except ImportError:
+ from typing_extensions import Literal
+
+from . import metric_functions
+#from . import objectives
+
+
+class Algorithm(str, Enum):
+ """Enumeration of supported search algorithms."""
+ dds = "dds"
+ pso = "pso"
+ gwo = "gwo"
+
+class Objective(str, Enum):
+ """Enumeration of supported objective functions."""
+ __func_map__ = {
+ "kge": metric_functions.KGE,
+ "nse": metric_functions.NSE,
+ "rmse": metric_functions.root_mean_squared_error,
+ "rsr": metric_functions.rmse_std_ratio,
+ "nnse": metric_functions. Weighted_NSE,
+ }
+
+ kge = "kge"
+ nse = "nse"
+ nnse = "nnse"
+ rmse = "rmse"
+ rsr = "rsr"
+
+ def __call__(self, *args, **kwargs):
+ return self.__func_map__[self.value](*args, **kwargs)
+
+class Estimation(BaseModel):
+ """Estimation strategy for defining parameter estimation."""
+ type: Literal['estimation']
+
+ algorithm: Algorithm
+ parameters: Optional[Mapping[str, Any]] = {}
+
+class Sensitivity(BaseModel):
+ """Sensitivity strategy for defining a sensitivity analysis"""
+ type: Literal['sensitivity']
+ pass #Not Implemented
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/utils.py b/python/runCalibValid/ngen_cal/src/ngen/cal/utils.py
new file mode 100644
index 00000000..ea7b19b2
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/utils.py
@@ -0,0 +1,68 @@
+"""
+This module contains utility functions for executing calibration and validation run.
+
+@author: Nels Frazer, Xia Feng
+"""
+
+from contextlib import contextmanager
+from email.mime.text import MIMEText
+from os import getcwd, chdir, PathLike
+import smtplib
+from typing import Union
+
+@contextmanager
+def pushd(path: Union[str, PathLike]) -> None:
+ """Change current working directory to the given path.
+
+ Parameters
+ ----------
+ path : New directory path
+
+ Returns
+ ----------
+ None
+
+ """
+ # Save current working directory
+ cwd = getcwd()
+
+ # Change the directory
+ chdir(path)
+ try:
+ yield
+ finally:
+ chdir(cwd)
+
+
+def complete_msg(basinid: str, run_name: str, path: Union[str, PathLike]=None, user_email: str=None) -> None:
+ """Send email notification to user if run is completed.
+
+ Parameters
+ ----------
+ basinid : Basin ID
+ run_name : Calibration or validation run
+ path : Work directory
+ user_email : User email address
+
+ Returns
+ ----------
+ None
+
+ """
+ if user_email:
+ subject = run_name.capitalize() + ' Run for {}'.format(basinid) + ' Is Completed'
+ content = subject + ' at ' + path if path else subject
+ msg = MIMEText(content)
+ msg['Subject'] = subject
+ msg['From'] = 'foo@example.com'
+ msg['To'] = user_email
+ try:
+ server = smtplib.SMTP('foo-server-name')
+ server.sendmail(msg['From'], user_email, msg.as_string())
+ except Exception as e:
+ print(e)
+ print('completion email ' + 'for {}'.format(basinid) + "can't be sent")
+ finally:
+ server.quit()
+ else:
+ print(content)
diff --git a/python/runCalibValid/ngen_cal/src/ngen/cal/validation_run.py b/python/runCalibValid/ngen_cal/src/ngen/cal/validation_run.py
new file mode 100644
index 00000000..0cc8b704
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/src/ngen/cal/validation_run.py
@@ -0,0 +1,59 @@
+"""
+This module contains function to execute validation control and best runs.
+
+@author: Xia Feng
+"""
+
+import os
+import shutil
+import subprocess
+from typing import TYPE_CHECKING
+
+import pandas as pd
+
+from .plot_output import plot_valid_output
+from .search import _execute, _calc_metrics
+from .utils import pushd, complete_msg
+
+if TYPE_CHECKING:
+ from ngen.cal.agent import Agent
+
+
+def run_valid_ctrl_best(agent: 'Agent') -> None:
+ """Execute validation control and best runs, calculate metrics and produce plots.
+
+ Parameters
+ ----------
+ agent : Agent object
+
+ Returns
+ ----------
+ None
+
+ """
+ print("---Start " + agent.run_name + "---")
+ shutil.copy(agent.realization_file, os.path.join(agent.job.workdir, os.path.basename(agent.realization_file)))
+
+ # Calculate metrics
+ for calibration_object in agent.model.adjustables:
+ with pushd(agent.job.workdir):
+ _execute(agent)
+ time_period = {'calib': calibration_object.evaluation_range, 'valid': calibration_object.valid_evaluation_range,
+ 'full': calibration_object.full_evaluation_range}
+ metrics = pd.DataFrame()
+ for key, value in time_period.items():
+ result = _calc_metrics(calibration_object.output, calibration_object.observed, value, calibration_object.threshold)
+ tmp = {**{'run': agent.run_name, 'period': key}, **result}
+ metrics = pd.concat([metrics, pd.DataFrame([tmp])], ignore_index=True)
+ calibration_object.write_valid_metric_file(agent.workdir, agent.run_name, metrics)
+
+ # Save and move output
+ calibration_object.save_valid_output(calibration_object.basinID, agent.run_name, agent.valid_path, agent.job.workdir, agent.valid_path_output)
+
+ # Plot
+ if agent.run_name=='valid_best':
+ plot_valid_output(calibration_object, agent, time_period)
+
+ # Indicate completion
+ calibration_object.write_run_complete_file(agent.run_name, agent.workdir)
+ complete_msg(calibration_object.basinID, agent.run_name, agent.workdir, calibration_object.user)
diff --git a/python/runCalibValid/ngen_cal/tests/__init__.py b/python/runCalibValid/ngen_cal/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/python/runCalibValid/ngen_cal/tests/conftest.py b/python/runCalibValid/ngen_cal/tests/conftest.py
new file mode 100644
index 00000000..26703035
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/conftest.py
@@ -0,0 +1,220 @@
+import pytest
+from typing import Generator, List
+from pathlib import Path
+from copy import deepcopy
+import json
+import pandas as pd # type: ignore
+import geopandas as gpd # type: ignore
+from ngen.cal.configuration import General
+from ngen.cal.ngen import Ngen
+from ngen.cal.meta import JobMeta
+from ngen.cal.calibration_cathment import CalibrationCatchment, EvaluatableCatchment, AdjustableCatchment
+from ngen.cal.model import EvaluationOptions
+from ngen.cal.agent import Agent
+from hypy import Nexus, HydroLocation
+
+from .utils import *
+
+@pytest.fixture(scope="session")
+def workdir(tmpdir_factory):
+ return tmpdir_factory.mktemp("workdir")
+
+@pytest.fixture(scope="session")
+def realization_config(tmpdir_factory) -> str:
+ """
+ Fixture to provide a staged testing input files
+ """
+ fn = tmpdir_factory.mktemp("data").join("realization_config.json")
+ with(open(fn, 'w')) as fp:
+ json.dump(config, fp)
+ return fn
+
+@pytest.fixture(scope="session")
+def general_config(workdir) -> General:
+ """A general configuration using default values where possible
+
+ Returns:
+ General: _description_
+
+ Yields:
+ Iterator[General]: _description_
+ """
+ #override the workdir, must do this to properly clean up
+ #test states, even though this technically overrides the default
+ general_w_defaults.update({"workdir": workdir})
+ general = General(**general_w_defaults)
+ return general
+
+@pytest.fixture(scope="session")
+def general_config_custom(workdir) -> General:
+ """A general configuration using custom values for all possible defaults
+
+ Returns:
+ General: _description_
+
+ Yields:
+ Iterator[General]: _description_
+ """
+ #override the workdir
+ general_no_defaults.update({"workdir": workdir})
+ general = General(**general_no_defaults)
+ return general
+
+@pytest.fixture(scope="session")
+def ngen_config(realization_config, workdir) -> Ngen:
+ """Fixture to provided a staged ngen configuration
+
+ Args:
+ realization_config (str): path to realization config for ngen
+
+ Returns:
+ Ngen: Ngen model data class and configuration
+
+ Yields:
+ Iterator[Ngen]: Ngen model data class and configuration
+ """
+ ngen_config = {"type":"ngen",
+ "strategy":"explicit",
+ "realization": realization_config,
+ "catchments": Path(__file__).parent/"data/catchment_data.geojson",
+ "nexus": Path(__file__).parent/"data/nexus_data.geojson",
+ "crosswalk": Path(__file__).parent/"data/crosswalk.json",
+ "binary": "echo ngen"}
+ ngen_config.update(model_params)
+ ngen_config.update({"workdir": workdir})
+ model = Ngen.parse_obj(ngen_config)
+ return model
+
+# @pytest.fixture
+# def conf(realization_config, workdir) -> Generator[Configuration, None, None]:
+# """
+# Staging of a generator to test
+# """
+# catchment_data = Path(__file__).parent/"data/catchment_data.geojson"
+# nexus_data = Path(__file__).parent/"data/nexus_data.geojson"
+# x_walk = Path(__file__).parent/"data/crosswalk.json"
+# yield Configuration(realization_config, catchment_data, nexus_data, x_walk, workdir)
+
+@pytest.fixture
+def meta(ngen_config, general_config, mocker) -> Generator[JobMeta, None, None]:
+ """
+ build up a meta object to test
+ """
+ m = JobMeta(ngen_config.type, general_config.workdir)
+ yield m
+
+@pytest.fixture
+def agent(ngen_config, general_config) -> Generator['Agent', None, None]:
+ a = Agent(ngen_config.__root__.dict(), general_config.workdir, general_config.log)
+ yield a
+
+@pytest.fixture
+def eval(ngen_config) -> Generator[EvaluationOptions, None, None]:
+ """
+ build an eval options object to test
+ """
+ eval_options = EvaluationOptions(**evaluation_options)
+ yield eval_options
+
+@pytest.fixture
+def fabric():
+ """
+ Mock geoseries for defining catchment gemomentry/attributes
+ """
+ catchment_data = Path(__file__).parent/"data/catchment_data.geojson"
+ df = gpd.read_file(catchment_data)
+ return df.loc[0]
+
+class MockLocation:
+ def __init__(self):
+ now = pd.Timestamp.now().round('H')
+ self.ts = pd.DataFrame({'value':[1,2,3,4,5], "value_time":pd.date_range(now, periods=5, freq='H')})
+
+ def get_data(self, *args, **kwargs):
+ return self.ts
+
+@pytest.fixture
+def nexus():
+ """
+ Mock nexus for building catchments
+ """
+ id = "test_nexus"
+ nexus = Nexus(id, MockLocation())
+
+ return nexus
+
+@pytest.fixture
+def catchment(nexus, fabric, workdir, mocker) -> Generator[CalibrationCatchment, None, None]:
+ """
+ A hy_features catchment implementing the calibratable interface
+ """
+ output = nexus._hydro_location.get_data().rename(columns={'value':'sim_flow'})
+ output.set_index('value_time', inplace=True)
+ #Override the output property so it doesn't try to reload output each time
+ mocker.patch(__name__+'.EvaluatableCatchment.output',
+ new_callable=mocker.PropertyMock,
+ return_value = output
+ )
+ #Disable output saving for testing purpose
+ mocker.patch(__name__+'.AdjustableCatchment.save_output',
+ return_value=None)
+
+ id = 'tst-1'
+ data = deepcopy(config)['catchments'][id]['calibration']['CFE'] # type: ignore
+ data = pd.DataFrame(data)
+ data['model'] = 'CFE'
+ #now = pd.Timestamp.now().round('H')
+ #ts = pd.DataFrame({'obs_flow':[1,2,3,4,5]}, index=pd.date_range(now, periods=5, freq='H'))
+ start = output.index[0]
+ end = output.index[-1]
+ eval_options = EvaluationOptions(**evaluation_options)
+ catchment = CalibrationCatchment(workdir, id, nexus, start, end, fabric, "Q_Out", eval_options, data)
+ #Reset observed here since it does unit conversion from cfs -> cms
+ catchment.observed = output.rename(columns={'sim_flow':'obs_flow'})
+ return catchment
+
+@pytest.fixture
+def catchment2(nexus, fabric, workdir) -> Generator[CalibrationCatchment, None, None]:
+ """
+ A hy_features catchment implementing the calibratable interface
+ Doesn't mock output, can be used to test semantics of erronous output
+ """
+ ts = nexus._hydro_location.get_data().rename(columns={'value':'obs_flow'})
+ ts.set_index('value_time', inplace=True)
+
+ id = 'tst-1'
+ data = deepcopy(config)['catchments'][id]['calibration']['CFE'] # type: ignore
+ data = pd.DataFrame(data)
+ data['model'] = 'CFE'
+ #now = pd.Timestamp.now().round('H')
+ #ts = pd.DataFrame({'obs_flow':[1,2,3,4,5]}, index=pd.date_range(now, periods=5, freq='H'))
+ start = ts.index[0]
+ end = ts.index[-1]
+ eval_options = EvaluationOptions(**evaluation_options)
+ catchment = CalibrationCatchment(workdir, id, nexus, start, end, fabric, 'Q_Out', eval_options, data)
+
+ return catchment
+
+@pytest.fixture
+def explicit_catchments(nexus, fabric, workdir) -> Generator[ List[ CalibrationCatchment ], None, None ]:
+ """
+ A list of explicitly defined calibration catchments
+ """
+ catchments = []
+ ts = nexus._hydro_location.get_data().rename(columns={'value':'obs_flow'})
+ ts.set_index('value_time', inplace=True)
+
+ id = 'tst-1'
+ data = deepcopy(config)['catchments'][id]['calibration']['CFE'] # type: ignore
+ data = pd.DataFrame(data)
+ data['model'] = 'CFE'
+ #now = pd.Timestamp.now().round('H')
+ #ts = pd.DataFrame({'obs_flow':[1,2,3,4,5]}, index=pd.date_range(now, periods=5, freq='H'))
+ start = ts.index[0]
+ end = ts.index[-1]
+ eval_options = EvaluationOptions(**evaluation_options)
+ for i in range(3):
+ id = f"tst-{i}"
+ cat = CalibrationCatchment(workdir, id, nexus, start, end, fabric, 'Q_Out', eval_options, data)
+ catchments.append(cat)
+ yield catchments
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_cal/tests/data/calibration_config.json b/python/runCalibValid/ngen_cal/tests/data/calibration_config.json
new file mode 100644
index 00000000..5109e85c
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/calibration_config.json
@@ -0,0 +1,51 @@
+{
+ "global": {
+ "calibration": { "params": [
+ {"param":"maxsmc", "min": 0.2, "max":1.0, "init": 0.439},
+ {"param":"satdk", "min":0.0, "max":0.000726, "init":0.00000338},
+ {"param":"refkdt", "min":0.1, "max":4.0, "init":3.0},
+ {"param":"slope", "min":0.0, "max": 1.0, "init":0.01},
+ {"param":"bb", "min":0.0, "max":21.9, "init":4.05},
+ {"param":"multiplier", "min":10.7, "max":9997.3, "init":100.0},
+ {"param":"expon", "min":1.0, "max":8.0, "init":6.0}
+ ]}
+ },
+ "catchments": {
+ "cat-87": {
+ "calibration": {"params": [
+ {"param":"maxsmc", "min": 0.2, "max":1.0, "init": 0.439},
+ {"param":"satdk", "min":0.0, "max":0.000726, "init":0.00000338},
+ {"param":"refkdt", "min":0.1, "max":4.0, "init":3.0},
+ {"param":"slope", "min":0.0, "max": 1.0, "init":0.01},
+ {"param":"bb", "min":0.0, "max":21.9, "init":4.05},
+ {"param":"multiplier", "min":10.7, "max":9997.3, "init":100.0},
+ {"param":"expon", "min":1.0, "max":8.0, "init":6.0}
+ ]}
+ },
+ "cat-88": {
+ "calibration": {"params": [
+ {"param":"b", "min": 0.1, "max":100, "init": 10},
+ {"param":"Ks", "min":0.0, "max":1.0, "init":0.1},
+ {"param":"Kq", "min":0.001, "max":1, "init":0.01}
+ ]}
+ },
+ "cat-89": {
+ "calibration": {"params": [
+ {"param":"maxsmc", "min": 0.2, "max":1.0, "init": 0.439},
+ {"param":"satdk", "min":0.0, "max":0.000726, "init":0.00000338},
+ {"param":"refkdt", "min":0.1, "max":4.0, "init":3.0},
+ {"param":"slope", "min":0.0, "max": 1.0, "init":0.01},
+ {"param":"bb", "min":0.0, "max":21.9, "init":4.05},
+ {"param":"multiplier", "min":10.7, "max":9997.3, "init":100.0},
+ {"param":"expon", "min":1.0, "max":8.0, "init":6.0}
+ ]}
+ },
+ "cat-92": {
+ "calibration": {"params": [
+ {"param":"b", "min": 0.1, "max":100, "init": 10},
+ {"param":"Ks", "min":0.0, "max":1.0, "init":0.1},
+ {"param":"Kq", "min":0.001, "max":1, "init":0.01}
+ ]}
+ }
+ }
+}
diff --git a/python/runCalibValid/ngen_cal/tests/data/calibration_r_order.csv b/python/runCalibValid/ngen_cal/tests/data/calibration_r_order.csv
new file mode 100644
index 00000000..07ed7ac9
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/calibration_r_order.csv
@@ -0,0 +1,8 @@
+1, param
+0.439, maxsmc
+0.00000338, satdk
+3.0, refkdt
+0.01, slope
+4.05, bb
+100.0, multiplier
+6.0, expon
diff --git a/python/runCalibValid/ngen_cal/tests/data/cat-87_2015-12-01 00_00_00_2015-12-30 23_00_00.csv b/python/runCalibValid/ngen_cal/tests/data/cat-87_2015-12-01 00_00_00_2015-12-30 23_00_00.csv
new file mode 100644
index 00000000..7ce270c7
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/cat-87_2015-12-01 00_00_00_2015-12-30 23_00_00.csv
@@ -0,0 +1,721 @@
+time,APCP_surface,DLWRF_surface,DSWRF_surface,PRES_surface,SPFH_2maboveground,TMP_2maboveground,UGRD_10maboveground,VGRD_10maboveground,precip_rate
+2015-12-01 00:00:00,0.0,361.20001220703125,0.0,100530.0,0.010499999858438969,287.5,-2.6000001430511475,0.0,0.0
+2015-12-01 01:00:00,0.0,361.20001220703125,0.0,100610.0,0.009800000116229057,287.3000183105469,-2.700000047683716,-0.30000001192092896,0.0
+2015-12-01 02:00:00,0.0,361.20001220703125,0.0,100600.0,0.009099999442696571,286.6000061035156,-2.799999952316284,-0.6000000238418579,0.0
+2015-12-01 03:00:00,0.0,357.6000061035156,0.0,100570.0,0.008700000122189522,285.5,-2.9000000953674316,-0.9000000357627869,0.0
+2015-12-01 04:00:00,0.0,357.6000061035156,0.0,100590.0,0.00839999970048666,284.3000183105469,-2.6000001430511475,-0.30000001192092896,0.0
+2015-12-01 05:00:00,0.0,357.6000061035156,0.0,100540.0,0.007999999448657036,283.8999938964844,-2.299999952316284,0.4000000059604645,0.0
+2015-12-01 06:00:00,0.0,344.1000061035156,0.0,100510.0,0.007699999958276749,283.6000061035156,-2.0,1.0,0.0
+2015-12-01 07:00:00,0.0,344.1000061035156,0.0,100490.0,0.007400000002235174,283.20001220703125,-2.1000001430511475,0.699999988079071,0.0
+2015-12-01 08:00:00,0.0,344.1000061035156,0.0,100550.0,0.007199999876320362,282.8999938964844,-2.200000047683716,0.5,0.0
+2015-12-01 09:00:00,0.0,335.0,0.0,100460.0,0.00699999975040555,282.5,-2.299999952316284,0.20000000298023224,0.0
+2015-12-01 10:00:00,0.0,335.0,0.0,100470.0,0.00699999975040555,282.3000183105469,-2.4000000953674316,0.6000000238418579,0.0
+2015-12-01 11:00:00,0.0,335.0,0.0,100480.0,0.0071000000461936,282.3000183105469,-2.4000000953674316,0.9000000357627869,0.0
+2015-12-01 12:00:00,0.0,350.3999938964844,0.0,100530.0,0.00699999975040555,282.0,-2.4000000953674316,1.3000000715255737,0.0
+2015-12-01 13:00:00,0.0,350.3999938964844,85.0999984741211,100560.0,0.00699999975040555,281.8999938964844,-2.6000001430511475,1.2000000476837158,0.0
+2015-12-01 14:00:00,0.0,350.3000183105469,195.40000915527344,100610.0,0.006899999920278788,282.5,-2.700000047683716,1.100000023841858,0.0
+2015-12-01 15:00:00,0.0,397.0,220.0,100600.0,0.00699999975040555,282.3999938964844,-2.9000000953674316,1.0,0.0
+2015-12-01 16:00:00,0.0,397.0,264.70001220703125,100520.0,0.007199999876320362,282.8000183105469,-2.200000047683716,1.7000000476837158,0.0
+2015-12-01 17:00:00,0.0,397.0,276.5,100510.0,0.007499999832361937,283.1000061035156,-1.5,2.299999952316284,0.0
+2015-12-01 18:00:00,0.0,385.3999938964844,395.20001220703125,100400.0,0.007699999958276749,283.5,-0.800000011920929,3.0,0.0
+2015-12-01 19:00:00,0.0,385.3999938964844,345.6000061035156,100340.0,0.008100000210106373,284.3999938964844,-0.800000011920929,2.9000000953674316,0.0
+2015-12-01 20:00:00,0.0,385.3999938964844,268.20001220703125,100310.0,0.008200000040233135,284.70001220703125,-0.9000000357627869,2.799999952316284,0.0
+2015-12-01 21:00:00,0.0,394.3000183105469,120.5999984741211,100160.0,0.008200000040233135,284.3999938964844,-0.9000000357627869,2.700000047683716,0.0
+2015-12-01 22:00:00,0.0,394.3000183105469,21.0,100200.0,0.00839999970048666,285.1000061035156,-1.3000000715255737,2.299999952316284,0.0
+2015-12-01 23:00:00,0.0,394.3000183105469,0.0,100240.0,0.008599999360740185,285.1000061035156,-1.7000000476837158,1.8000000715255737,0.0
+2015-12-02 00:00:00,0.0,383.3000183105469,0.0,100190.0,0.008599999360740185,285.20001220703125,-2.1000001430511475,1.399999976158142,0.0
+2015-12-02 01:00:00,0.0,383.3000183105469,0.0,100240.0,0.008799999952316284,285.3000183105469,-2.0,1.3000000715255737,0.0
+2015-12-02 02:00:00,0.0,383.3000183105469,0.0,100210.0,0.008799999952316284,285.6000061035156,-2.0,1.100000023841858,0.0
+2015-12-02 03:00:00,0.0,371.3999938964844,0.0,100120.0,0.008899999782443047,285.70001220703125,-2.0,1.0,0.0
+2015-12-02 04:00:00,0.0,371.3999938964844,0.0,100070.0,0.009200000204145908,285.8000183105469,-1.8000000715255737,1.600000023841858,0.0
+2015-12-02 05:00:00,0.0,371.3999938964844,0.0,100010.0,0.008899999782443047,285.70001220703125,-1.7000000476837158,2.1000001430511475,0.0
+2015-12-02 06:00:00,0.0,369.1000061035156,0.0,99970.0,0.009099999442696571,285.8999938964844,-1.600000023841858,2.700000047683716,0.0
+2015-12-02 07:00:00,0.0,369.20001220703125,0.0,99880.0,0.009399999864399433,286.1000061035156,-1.600000023841858,3.0,0.0
+2015-12-02 08:00:00,0.0,369.20001220703125,0.0,99870.0,0.009800000116229057,287.0,-1.7000000476837158,3.4000000953674316,9.493307095661946e-08
+2015-12-02 09:00:00,0.20000000298023224,370.6000061035156,0.0,99740.0,0.00969999935477972,286.70001220703125,-1.7000000476837158,3.799999952316284,0.0
+2015-12-02 10:00:00,0.0,370.6000061035156,0.0,99720.0,0.010499999858438969,288.0,-1.600000023841858,3.700000047683716,0.0
+2015-12-02 11:00:00,0.0,370.6000061035156,0.0,99710.0,0.010999999940395355,288.6000061035156,-1.5,3.6000001430511475,0.0
+2015-12-02 12:00:00,0.0,380.8999938964844,0.0,99710.0,0.01119999960064888,289.3999938964844,-1.399999976158142,3.4000000953674316,0.0
+2015-12-02 13:00:00,0.0,380.8999938964844,72.5,99740.0,0.011699999682605267,289.70001220703125,-0.699999988079071,3.4000000953674316,0.0
+2015-12-02 14:00:00,0.0,380.8000183105469,168.60000610351562,99710.0,0.01209999993443489,290.3000183105469,0.0,3.299999952316284,2.439501431328691e-07
+2015-12-02 15:00:00,0.5,405.1000061035156,130.8000030517578,99850.0,0.012000000104308128,290.3000183105469,0.699999988079071,3.299999952316284,3.9032023482881514e-07
+2015-12-02 16:00:00,0.800000011920929,405.1000061035156,157.5,99840.0,0.011699999682605267,289.8000183105469,1.3000000715255737,3.4000000953674316,9.716329458139992e-08
+2015-12-02 17:00:00,0.20000000298023224,405.1000061035156,164.6999969482422,99710.0,0.011799999512732029,290.1000061035156,1.899999976158142,3.5,0.0
+2015-12-02 18:00:00,0.0,397.5,145.10000610351562,99550.0,0.011699999682605267,290.3999938964844,2.5,3.6000001430511475,0.0
+2015-12-02 19:00:00,0.0,397.5,126.9000015258789,99520.0,0.011399999260902405,290.20001220703125,3.299999952316284,3.5,0.0
+2015-12-02 20:00:00,0.0,397.5,98.5,99400.0,0.011699999682605267,290.0,4.099999904632568,3.5,0.0
+2015-12-02 21:00:00,0.0,376.20001220703125,67.70000457763672,99390.0,0.01209999993443489,290.3999938964844,4.900000095367432,3.4000000953674316,0.0
+2015-12-02 22:00:00,0.0,376.20001220703125,11.699999809265137,99410.0,0.01119999960064888,289.8999938964844,5.0,3.9000000953674316,0.0
+2015-12-02 23:00:00,0.0,376.20001220703125,0.0,99530.0,0.008799999952316284,289.0,5.0,4.5,0.0
+2015-12-03 00:00:00,0.0,350.8000183105469,0.0,99570.0,0.0072999997064471245,287.3000183105469,5.099999904632568,5.099999904632568,0.0
+2015-12-03 01:00:00,0.0,350.8000183105469,0.0,99600.0,0.0066999997943639755,286.20001220703125,4.900000095367432,4.400000095367432,0.0
+2015-12-03 02:00:00,0.0,350.8999938964844,0.0,99680.0,0.0064999996684491634,285.8000183105469,4.800000190734863,3.799999952316284,0.0
+2015-12-03 03:00:00,0.0,296.70001220703125,0.0,99700.0,0.006199999712407589,284.8999938964844,4.599999904632568,3.1000001430511475,0.0
+2015-12-03 04:00:00,0.0,296.70001220703125,0.0,99740.0,0.006000000052154064,284.3000183105469,4.5,2.200000047683716,0.0
+2015-12-03 05:00:00,0.0,296.70001220703125,0.0,99850.0,0.006000000052154064,283.3999938964844,4.400000095367432,1.399999976158142,0.0
+2015-12-03 06:00:00,0.0,279.3999938964844,0.0,99880.0,0.0058999997563660145,282.8000183105469,4.200000286102295,0.5,0.0
+2015-12-03 07:00:00,0.0,279.3999938964844,0.0,99930.0,0.0058999997563660145,282.20001220703125,3.700000047683716,-0.20000000298023224,0.0
+2015-12-03 08:00:00,0.0,279.3999938964844,0.0,100020.0,0.005799999926239252,281.6000061035156,3.299999952316284,-0.9000000357627869,0.0
+2015-12-03 09:00:00,0.0,257.1000061035156,0.0,100040.0,0.005799999926239252,281.0,2.799999952316284,-1.600000023841858,0.0
+2015-12-03 10:00:00,0.0,257.1000061035156,0.0,100130.0,0.005699999630451202,280.6000061035156,2.200000047683716,-2.1000001430511475,0.0
+2015-12-03 11:00:00,0.0,257.1000061035156,0.0,100240.0,0.005499999970197678,280.5,1.600000023841858,-2.6000001430511475,0.0
+2015-12-03 12:00:00,0.0,254.0,0.0,100340.0,0.004999999888241291,279.70001220703125,1.0,-3.1000001430511475,0.0
+2015-12-03 13:00:00,0.0,254.0,111.5999984741211,100460.0,0.004799999762326479,279.70001220703125,0.20000000298023224,-3.9000000953674316,0.0
+2015-12-03 14:00:00,0.0,254.0,263.1000061035156,100550.0,0.00419999985024333,281.20001220703125,-0.6000000238418579,-4.800000190734863,0.0
+2015-12-03 15:00:00,0.0,268.0,390.6000061035156,100680.0,0.003599999938160181,282.3999938964844,-1.399999976158142,-5.599999904632568,0.0
+2015-12-03 16:00:00,0.0,268.0,471.3000183105469,100720.0,0.003499999875202775,283.1000061035156,-1.7000000476837158,-5.200000286102295,0.0
+2015-12-03 17:00:00,0.0,268.0,493.3000183105469,100690.0,0.003599999938160181,283.5,-2.0,-4.900000095367432,0.0
+2015-12-03 18:00:00,0.0,270.8999938964844,491.8999938964844,100700.0,0.003499999875202775,283.6000061035156,-2.299999952316284,-4.5,0.0
+2015-12-03 19:00:00,0.0,270.8999938964844,430.6000061035156,100660.0,0.003700000001117587,283.8000183105469,-1.899999976158142,-4.300000190734863,0.0
+2015-12-03 20:00:00,0.0,270.8999938964844,334.1000061035156,100750.0,0.003599999938160181,283.8999938964844,-1.600000023841858,-4.099999904632568,0.0
+2015-12-03 21:00:00,0.0,255.8000030517578,180.6999969482422,100750.0,0.0037999998312443495,283.3000183105469,-1.3000000715255737,-3.9000000953674316,0.0
+2015-12-03 22:00:00,0.0,255.8000030517578,30.899999618530273,100870.0,0.003999999724328518,282.1000061035156,-1.399999976158142,-3.700000047683716,0.0
+2015-12-03 23:00:00,0.0,255.8000030517578,0.0,100930.0,0.004299999680370092,280.3000183105469,-1.5,-3.4000000953674316,0.0
+2015-12-04 00:00:00,0.0,236.6999969482422,0.0,101010.0,0.00419999985024333,280.3000183105469,-1.5,-3.1000001430511475,0.0
+2015-12-04 01:00:00,0.0,236.6999969482422,0.0,101130.0,0.004299999680370092,279.6000061035156,-1.7000000476837158,-3.1000001430511475,0.0
+2015-12-04 02:00:00,0.0,236.6999969482422,0.0,101170.0,0.00419999985024333,278.70001220703125,-1.8000000715255737,-3.0,0.0
+2015-12-04 03:00:00,0.0,229.5,0.0,101260.0,0.004299999680370092,278.3000183105469,-1.899999976158142,-2.9000000953674316,0.0
+2015-12-04 04:00:00,0.0,229.5,0.0,101300.0,0.00419999985024333,277.6000061035156,-2.0,-2.9000000953674316,0.0
+2015-12-04 05:00:00,0.0,229.5,0.0,101270.0,0.003999999724328518,277.5,-2.0,-2.799999952316284,0.0
+2015-12-04 06:00:00,0.0,222.5,0.0,101270.0,0.003700000001117587,277.70001220703125,-2.0,-2.799999952316284,0.0
+2015-12-04 07:00:00,0.0,222.5,0.0,101400.0,0.0037999998312443495,277.3999938964844,-1.600000023841858,-2.9000000953674316,0.0
+2015-12-04 08:00:00,0.0,222.5,0.0,101460.0,0.003700000001117587,276.3999938964844,-1.2000000476837158,-3.1000001430511475,0.0
+2015-12-04 09:00:00,0.0,217.0,0.0,101450.0,0.003599999938160181,275.3999938964844,-0.800000011920929,-3.200000047683716,0.0
+2015-12-04 10:00:00,0.0,217.0,0.0,101510.0,0.003399999812245369,274.8000183105469,-0.9000000357627869,-3.1000001430511475,0.0
+2015-12-04 11:00:00,0.0,217.0,0.0,101540.0,0.003399999812245369,274.3000183105469,-1.100000023841858,-3.0,0.0
+2015-12-04 12:00:00,0.0,220.3000030517578,0.0,101610.0,0.0032999999821186066,273.6000061035156,-1.3000000715255737,-2.9000000953674316,0.0
+2015-12-04 13:00:00,0.0,220.1999969482422,111.0,101730.0,0.003499999875202775,274.1000061035156,-1.5,-3.200000047683716,0.0
+2015-12-04 14:00:00,0.0,220.1999969482422,265.0,101770.0,0.003700000001117587,276.8999938964844,-1.600000023841858,-3.4000000953674316,0.0
+2015-12-04 15:00:00,0.0,239.60000610351562,424.20001220703125,101810.0,0.003499999875202775,279.5,-1.8000000715255737,-3.700000047683716,0.0
+2015-12-04 16:00:00,0.0,239.60000610351562,512.7000122070312,101760.0,0.003399999812245369,281.8999938964844,-2.4000000953674316,-3.799999952316284,0.0
+2015-12-04 17:00:00,0.0,239.60000610351562,537.1000366210938,101720.0,0.0032999999821186066,283.70001220703125,-3.0,-3.799999952316284,0.0
+2015-12-04 18:00:00,0.0,248.0,520.2999877929688,101680.0,0.0032999999821186066,284.70001220703125,-3.6000001430511475,-3.9000000953674316,0.0
+2015-12-04 19:00:00,0.0,248.0,455.6000061035156,101630.0,0.0031999999191612005,285.5,-3.4000000953674316,-3.700000047683716,0.0
+2015-12-04 20:00:00,0.0,248.10000610351562,353.6000061035156,101600.0,0.0031999999191612005,285.3000183105469,-3.200000047683716,-3.5,0.0
+2015-12-04 21:00:00,0.0,238.3000030517578,155.40000915527344,101600.0,0.0031999999191612005,285.5,-3.0,-3.299999952316284,0.0
+2015-12-04 22:00:00,0.0,238.3000030517578,26.399999618530273,101680.0,0.0032999999821186066,284.1000061035156,-2.1000001430511475,-3.4000000953674316,0.0
+2015-12-04 23:00:00,0.0,238.3000030517578,0.0,101620.0,0.003700000001117587,280.3000183105469,-1.3000000715255737,-3.5,0.0
+2015-12-05 00:00:00,0.0,226.3000030517578,0.0,101720.0,0.0037999998312443495,279.0,-0.4000000059604645,-3.6000001430511475,0.0
+2015-12-05 01:00:00,0.0,226.3000030517578,0.0,101740.0,0.003700000001117587,277.0,-0.699999988079071,-3.4000000953674316,0.0
+2015-12-05 02:00:00,0.0,226.3000030517578,0.0,101830.0,0.003700000001117587,277.0,-1.100000023841858,-3.200000047683716,0.0
+2015-12-05 03:00:00,0.0,222.60000610351562,0.0,101890.0,0.003700000001117587,276.6000061035156,-1.399999976158142,-3.0,0.0
+2015-12-05 04:00:00,0.0,222.60000610351562,0.0,101860.0,0.003599999938160181,276.0,-1.399999976158142,-3.0,0.0
+2015-12-05 05:00:00,0.0,222.60000610351562,0.0,101850.0,0.003599999938160181,274.20001220703125,-1.3000000715255737,-3.0,0.0
+2015-12-05 06:00:00,0.0,220.8000030517578,0.0,101800.0,0.003499999875202775,273.8999938964844,-1.3000000715255737,-3.0,0.0
+2015-12-05 07:00:00,0.0,220.8000030517578,0.0,101920.0,0.003499999875202775,273.8000183105469,-1.3000000715255737,-3.0,0.0
+2015-12-05 08:00:00,0.0,220.8000030517578,0.0,101980.0,0.0032999999821186066,272.3999938964844,-1.2000000476837158,-3.1000001430511475,0.0
+2015-12-05 09:00:00,0.0,221.60000610351562,0.0,101960.0,0.0032999999821186066,272.6000061035156,-1.2000000476837158,-3.1000001430511475,0.0
+2015-12-05 10:00:00,0.0,221.60000610351562,0.0,102000.0,0.0031999999191612005,272.6000061035156,-1.3000000715255737,-3.0,0.0
+2015-12-05 11:00:00,0.0,221.60000610351562,0.0,102040.0,0.0032999999821186066,273.3999938964844,-1.399999976158142,-2.9000000953674316,0.0
+2015-12-05 12:00:00,0.0,227.8000030517578,0.0,102080.0,0.0032999999821186066,272.8000183105469,-1.5,-2.799999952316284,0.0
+2015-12-05 13:00:00,0.0,227.8000030517578,106.9000015258789,102150.0,0.003599999938160181,273.70001220703125,-1.7000000476837158,-3.200000047683716,0.0
+2015-12-05 14:00:00,0.0,227.8000030517578,258.8000183105469,102200.0,0.003599999938160181,277.1000061035156,-1.899999976158142,-3.6000001430511475,0.0
+2015-12-05 15:00:00,0.0,253.8000030517578,414.5,102230.0,0.003599999938160181,279.8999938964844,-2.1000001430511475,-3.9000000953674316,0.0
+2015-12-05 16:00:00,0.0,253.8000030517578,501.8000183105469,102180.0,0.003499999875202775,282.70001220703125,-2.5,-3.9000000953674316,0.0
+2015-12-05 17:00:00,0.0,253.8000030517578,526.1000366210938,102070.0,0.003399999812245369,284.20001220703125,-2.9000000953674316,-3.9000000953674316,0.0
+2015-12-05 18:00:00,0.0,269.0,507.20001220703125,101960.0,0.003399999812245369,285.5,-3.299999952316284,-3.799999952316284,0.0
+2015-12-05 19:00:00,0.0,269.0,444.3000183105469,101880.0,0.003499999875202775,286.70001220703125,-3.0,-3.700000047683716,0.0
+2015-12-05 20:00:00,0.0,269.0,344.8999938964844,101860.0,0.003599999938160181,287.20001220703125,-2.6000001430511475,-3.6000001430511475,0.0
+2015-12-05 21:00:00,0.0,261.20001220703125,149.0,101890.0,0.003499999875202775,286.3999938964844,-2.299999952316284,-3.5,0.0
+2015-12-05 22:00:00,0.0,261.3000183105469,25.200000762939453,101950.0,0.003700000001117587,285.20001220703125,-2.200000047683716,-3.299999952316284,0.0
+2015-12-05 23:00:00,0.0,261.3000183105469,0.0,101960.0,0.003999999724328518,282.3999938964844,-2.200000047683716,-3.1000001430511475,0.0
+2015-12-06 00:00:00,0.0,250.1999969482422,0.0,101960.0,0.0037999998312443495,281.0,-2.200000047683716,-2.9000000953674316,0.0
+2015-12-06 01:00:00,0.0,250.1999969482422,0.0,102030.0,0.0037999998312443495,280.5,-2.200000047683716,-2.9000000953674316,0.0
+2015-12-06 02:00:00,0.0,250.1999969482422,0.0,102060.0,0.0038999998942017555,279.8000183105469,-2.200000047683716,-3.0,0.0
+2015-12-06 03:00:00,0.0,251.1999969482422,0.0,102000.0,0.0038999998942017555,278.8000183105469,-2.200000047683716,-3.0,0.0
+2015-12-06 04:00:00,0.0,251.1999969482422,0.0,102010.0,0.0037999998312443495,277.3000183105469,-2.200000047683716,-2.799999952316284,0.0
+2015-12-06 05:00:00,0.0,251.1999969482422,0.0,102030.0,0.0037999998312443495,277.3999938964844,-2.200000047683716,-2.700000047683716,0.0
+2015-12-06 06:00:00,0.0,267.70001220703125,0.0,101930.0,0.0038999998942017555,277.5,-2.200000047683716,-2.6000001430511475,0.0
+2015-12-06 07:00:00,0.0,267.70001220703125,0.0,101950.0,0.0037999998312443495,277.20001220703125,-2.0,-2.700000047683716,0.0
+2015-12-06 08:00:00,0.0,267.70001220703125,0.0,101890.0,0.0038999998942017555,276.8000183105469,-1.8000000715255737,-2.799999952316284,0.0
+2015-12-06 09:00:00,0.0,296.3999938964844,0.0,101850.0,0.0038999998942017555,276.3999938964844,-1.600000023841858,-2.799999952316284,0.0
+2015-12-06 10:00:00,0.0,296.3999938964844,0.0,101860.0,0.0037999998312443495,275.70001220703125,-1.5,-2.6000001430511475,0.0
+2015-12-06 11:00:00,0.0,296.3999938964844,0.0,101860.0,0.0037999998312443495,274.8000183105469,-1.5,-2.4000000953674316,0.0
+2015-12-06 12:00:00,0.0,272.8999938964844,0.0,101870.0,0.003700000001117587,274.8000183105469,-1.5,-2.200000047683716,0.0
+2015-12-06 13:00:00,0.0,272.8999938964844,102.20000457763672,101920.0,0.0038999998942017555,275.3000183105469,-1.600000023841858,-2.4000000953674316,0.0
+2015-12-06 14:00:00,0.0,272.8000183105469,250.90000915527344,101900.0,0.00419999985024333,278.8000183105469,-1.600000023841858,-2.5,0.0
+2015-12-06 15:00:00,0.0,279.3000183105469,403.0,101840.0,0.004399999976158142,282.0,-1.7000000476837158,-2.6000001430511475,0.0
+2015-12-06 16:00:00,0.0,279.3000183105469,488.5,101810.0,0.004100000020116568,284.3000183105469,-1.8000000715255737,-2.200000047683716,0.0
+2015-12-06 17:00:00,0.0,279.3000183105469,512.6000366210938,101680.0,0.003999999724328518,285.8999938964844,-2.0,-1.7000000476837158,0.0
+2015-12-06 18:00:00,0.0,296.8999938964844,495.6000061035156,101510.0,0.003700000001117587,287.8999938964844,-2.200000047683716,-1.3000000715255737,0.0
+2015-12-06 19:00:00,0.0,296.8999938964844,434.3000183105469,101380.0,0.00419999985024333,289.3000183105469,-2.0,-1.2000000476837158,0.0
+2015-12-06 20:00:00,0.0,296.8999938964844,337.20001220703125,101250.0,0.0044999998062849045,290.1000061035156,-1.8000000715255737,-1.2000000476837158,0.0
+2015-12-06 21:00:00,0.0,288.20001220703125,152.1999969482422,101200.0,0.004799999762326479,290.0,-1.600000023841858,-1.100000023841858,0.0
+2015-12-06 22:00:00,0.0,288.20001220703125,25.700000762939453,101200.0,0.005399999674409628,287.5,-1.5,-0.800000011920929,0.0
+2015-12-06 23:00:00,0.0,288.20001220703125,0.0,101190.0,0.005499999970197678,282.70001220703125,-1.5,-0.4000000059604645,0.0
+2015-12-07 00:00:00,0.0,278.1000061035156,0.0,101200.0,0.00559999980032444,282.1000061035156,-1.5,-0.10000000149011612,0.0
+2015-12-07 01:00:00,0.0,278.1000061035156,0.0,101250.0,0.00559999980032444,281.3000183105469,-1.3000000715255737,-0.30000001192092896,0.0
+2015-12-07 02:00:00,0.0,278.1000061035156,0.0,101220.0,0.0052999998442828655,279.5,-1.0,-0.6000000238418579,0.0
+2015-12-07 03:00:00,0.0,277.20001220703125,0.0,101170.0,0.0050999997183680534,279.20001220703125,-0.800000011920929,-0.9000000357627869,0.0
+2015-12-07 04:00:00,0.0,277.20001220703125,0.0,101120.0,0.004799999762326479,277.6000061035156,-0.5,-1.399999976158142,0.0
+2015-12-07 05:00:00,0.0,277.20001220703125,0.0,101090.0,0.004999999888241291,277.8000183105469,-0.10000000149011612,-1.899999976158142,0.0
+2015-12-07 06:00:00,0.0,272.1000061035156,0.0,101050.0,0.004799999762326479,277.20001220703125,0.20000000298023224,-2.4000000953674316,0.0
+2015-12-07 07:00:00,0.0,272.1000061035156,0.0,101020.0,0.004600000102072954,276.8000183105469,0.10000000149011612,-2.4000000953674316,0.0
+2015-12-07 08:00:00,0.0,272.1000061035156,0.0,100930.0,0.0044999998062849045,276.0,0.0,-2.299999952316284,0.0
+2015-12-07 09:00:00,0.0,277.3000183105469,0.0,100860.0,0.0044999998062849045,275.8000183105469,-0.10000000149011612,-2.299999952316284,0.0
+2015-12-07 10:00:00,0.0,277.3000183105469,0.0,100800.0,0.0044999998062849045,275.5,0.20000000298023224,-2.200000047683716,0.0
+2015-12-07 11:00:00,0.0,277.3000183105469,0.0,100820.0,0.0044999998062849045,275.70001220703125,0.4000000059604645,-2.1000001430511475,0.0
+2015-12-07 12:00:00,0.0,319.0,0.0,100820.0,0.004399999976158142,275.3999938964844,0.699999988079071,-2.0,0.0
+2015-12-07 13:00:00,0.0,318.8999938964844,69.9000015258789,100830.0,0.0044999998062849045,276.0,0.9000000357627869,-1.8000000715255737,0.0
+2015-12-07 14:00:00,0.0,318.8999938964844,174.0,100820.0,0.004999999888241291,278.8999938964844,1.0,-1.600000023841858,0.0
+2015-12-07 15:00:00,0.0,346.70001220703125,285.70001220703125,100780.0,0.005499999970197678,283.1000061035156,1.100000023841858,-1.399999976158142,0.0
+2015-12-07 16:00:00,0.0,346.6000061035156,346.8999938964844,100690.0,0.004900000058114529,286.70001220703125,1.0,-1.5,0.0
+2015-12-07 17:00:00,0.0,346.6000061035156,364.3000183105469,100590.0,0.004799999762326479,289.5,0.9000000357627869,-1.7000000476837158,0.0
+2015-12-07 18:00:00,0.0,342.1000061035156,424.0,100440.0,0.004999999888241291,290.70001220703125,0.699999988079071,-1.8000000715255737,0.0
+2015-12-07 19:00:00,0.0,342.1000061035156,371.70001220703125,100320.0,0.005200000014156103,291.3999938964844,1.0,-1.8000000715255737,0.0
+2015-12-07 20:00:00,0.0,342.1000061035156,288.70001220703125,100280.0,0.005399999674409628,291.70001220703125,1.3000000715255737,-1.7000000476837158,0.0
+2015-12-07 21:00:00,0.0,350.8000183105469,132.60000610351562,100300.0,0.005499999970197678,291.8999938964844,1.5,-1.7000000476837158,0.0
+2015-12-07 22:00:00,0.0,350.8000183105469,22.399999618530273,100340.0,0.005699999630451202,289.70001220703125,1.2000000476837158,-1.5,0.0
+2015-12-07 23:00:00,0.0,350.8000183105469,0.0,100340.0,0.005799999926239252,285.8000183105469,0.9000000357627869,-1.3000000715255737,0.0
+2015-12-08 00:00:00,0.0,317.1000061035156,0.0,100400.0,0.005799999926239252,283.0,0.5,-1.100000023841858,0.0
+2015-12-08 01:00:00,0.0,317.1000061035156,0.0,100480.0,0.005699999630451202,281.8000183105469,0.5,-1.0,0.0
+2015-12-08 02:00:00,0.0,317.1000061035156,0.0,100490.0,0.005799999926239252,281.8000183105469,0.6000000238418579,-1.0,0.0
+2015-12-08 03:00:00,0.0,272.70001220703125,0.0,100470.0,0.005699999630451202,281.8000183105469,0.6000000238418579,-0.9000000357627869,0.0
+2015-12-08 04:00:00,0.0,272.70001220703125,0.0,100500.0,0.005399999674409628,280.8999938964844,0.6000000238418579,-0.6000000238418579,0.0
+2015-12-08 05:00:00,0.0,272.70001220703125,0.0,100520.0,0.005200000014156103,279.6000061035156,0.699999988079071,-0.4000000059604645,0.0
+2015-12-08 06:00:00,0.0,265.1000061035156,0.0,100440.0,0.005200000014156103,280.70001220703125,0.699999988079071,-0.10000000149011612,0.0
+2015-12-08 07:00:00,0.0,265.1000061035156,0.0,100490.0,0.005200000014156103,279.0,0.699999988079071,-0.30000001192092896,0.0
+2015-12-08 08:00:00,0.0,265.1000061035156,0.0,100550.0,0.004999999888241291,277.8000183105469,0.800000011920929,-0.5,0.0
+2015-12-08 09:00:00,0.0,260.3000183105469,0.0,100470.0,0.004900000058114529,277.3999938964844,0.800000011920929,-0.699999988079071,0.0
+2015-12-08 10:00:00,0.0,260.3000183105469,0.0,100440.0,0.004699999932199717,276.0,0.5,-0.699999988079071,0.0
+2015-12-08 11:00:00,0.0,260.3000183105469,0.0,100520.0,0.00419999985024333,274.8000183105469,0.10000000149011612,-0.699999988079071,0.0
+2015-12-08 12:00:00,0.0,258.0,0.0,100560.0,0.0044999998062849045,275.6000061035156,-0.30000001192092896,-0.699999988079071,0.0
+2015-12-08 13:00:00,0.0,257.8999938964844,98.0,100650.0,0.0044999998062849045,275.3999938964844,-0.4000000059604645,-0.6000000238418579,0.0
+2015-12-08 14:00:00,0.0,257.8999938964844,247.3000030517578,100670.0,0.005499999970197678,279.5,-0.6000000238418579,-0.4000000059604645,0.0
+2015-12-08 15:00:00,0.0,285.20001220703125,404.1000061035156,100730.0,0.00559999980032444,282.8000183105469,-0.699999988079071,-0.30000001192092896,0.0
+2015-12-08 16:00:00,0.0,285.20001220703125,491.3000183105469,100710.0,0.005399999674409628,285.70001220703125,-0.699999988079071,0.5,0.0
+2015-12-08 17:00:00,0.0,285.20001220703125,516.5,100580.0,0.0052999998442828655,287.8999938964844,-0.699999988079071,1.3000000715255737,0.0
+2015-12-08 18:00:00,0.0,291.1000061035156,501.8000183105469,100480.0,0.005200000014156103,289.1000061035156,-0.6000000238418579,2.1000001430511475,0.0
+2015-12-08 19:00:00,0.0,291.1000061035156,440.1000061035156,100400.0,0.00559999980032444,290.5,-0.20000000298023224,2.4000000953674316,0.0
+2015-12-08 20:00:00,0.0,291.1000061035156,342.0,100420.0,0.0058999997563660145,290.5,0.20000000298023224,2.700000047683716,0.0
+2015-12-08 21:00:00,0.0,279.8999938964844,148.40000915527344,100320.0,0.006399999838322401,290.0,0.6000000238418579,3.0,0.0
+2015-12-08 22:00:00,0.0,279.8999938964844,25.200000762939453,100360.0,0.006399999838322401,288.3999938964844,0.20000000298023224,2.799999952316284,0.0
+2015-12-08 23:00:00,0.0,279.8999938964844,0.0,100370.0,0.0064999996684491634,284.3999938964844,-0.10000000149011612,2.5,0.0
+2015-12-09 00:00:00,0.0,263.8999938964844,0.0,100390.0,0.006599999964237213,282.3999938964844,-0.4000000059604645,2.299999952316284,0.0
+2015-12-09 01:00:00,0.0,263.8999938964844,0.0,100480.0,0.006399999838322401,281.70001220703125,-0.699999988079071,2.299999952316284,0.0
+2015-12-09 02:00:00,0.0,263.8999938964844,0.0,100490.0,0.006300000008195639,281.20001220703125,-1.0,2.299999952316284,0.0
+2015-12-09 03:00:00,0.0,258.70001220703125,0.0,100430.0,0.0058999997563660145,280.1000061035156,-1.399999976158142,2.299999952316284,0.0
+2015-12-09 04:00:00,0.0,258.70001220703125,0.0,100430.0,0.005699999630451202,279.5,-0.800000011920929,2.1000001430511475,0.0
+2015-12-09 05:00:00,0.0,258.70001220703125,0.0,100430.0,0.005499999970197678,278.8999938964844,-0.30000001192092896,2.0,0.0
+2015-12-09 06:00:00,0.0,255.60000610351562,0.0,100400.0,0.005200000014156103,278.3999938964844,0.30000001192092896,1.899999976158142,0.0
+2015-12-09 07:00:00,0.0,255.60000610351562,0.0,100440.0,0.004999999888241291,277.8000183105469,0.10000000149011612,1.8000000715255737,0.0
+2015-12-09 08:00:00,0.0,255.60000610351562,0.0,100450.0,0.004999999888241291,277.5,0.0,1.7000000476837158,0.0
+2015-12-09 09:00:00,0.0,256.8999938964844,0.0,100350.0,0.005200000014156103,278.0,-0.20000000298023224,1.600000023841858,0.0
+2015-12-09 10:00:00,0.0,256.8999938964844,0.0,100370.0,0.004999999888241291,277.6000061035156,-0.4000000059604645,1.899999976158142,0.0
+2015-12-09 11:00:00,0.0,256.8999938964844,0.0,100400.0,0.004900000058114529,277.0,-0.6000000238418579,2.200000047683716,0.0
+2015-12-09 12:00:00,0.0,267.6000061035156,0.0,100430.0,0.004299999680370092,275.1000061035156,-0.699999988079071,2.5,0.0
+2015-12-09 13:00:00,0.0,267.6000061035156,94.4000015258789,100470.0,0.0044999998062849045,275.3999938964844,-0.699999988079071,1.899999976158142,0.0
+2015-12-09 14:00:00,0.0,267.6000061035156,241.60000610351562,100540.0,0.0052999998442828655,278.8000183105469,-0.6000000238418579,1.2000000476837158,0.0
+2015-12-09 15:00:00,0.0,295.8000183105469,376.0,100480.0,0.006000000052154064,282.3000183105469,-0.6000000238418579,0.5,0.0
+2015-12-09 16:00:00,0.0,295.8000183105469,457.8999938964844,100450.0,0.00559999980032444,286.5,-0.30000001192092896,1.2000000476837158,0.0
+2015-12-09 17:00:00,0.0,295.70001220703125,481.8999938964844,100290.0,0.004900000058114529,289.3999938964844,0.0,1.8000000715255737,0.0
+2015-12-09 18:00:00,0.0,304.3000183105469,491.5,100150.0,0.004699999932199717,290.20001220703125,0.4000000059604645,2.4000000953674316,0.0
+2015-12-09 19:00:00,0.0,304.3000183105469,431.3999938964844,100050.0,0.004600000102072954,291.0,0.800000011920929,2.200000047683716,0.0
+2015-12-09 20:00:00,0.0,304.3000183105469,335.3999938964844,100040.0,0.004299999680370092,291.3000183105469,1.2000000476837158,2.1000001430511475,0.0
+2015-12-09 21:00:00,0.0,292.3000183105469,145.1999969482422,100020.0,0.004600000102072954,290.8000183105469,1.600000023841858,1.899999976158142,0.0
+2015-12-09 22:00:00,0.0,292.3000183105469,24.700000762939453,100070.0,0.004999999888241291,288.20001220703125,1.899999976158142,1.100000023841858,0.0
+2015-12-09 23:00:00,0.0,292.3000183105469,0.0,100080.0,0.0050999997183680534,284.70001220703125,2.200000047683716,0.30000001192092896,0.0
+2015-12-10 00:00:00,0.0,274.6000061035156,0.0,100090.0,0.005200000014156103,284.0,2.5,-0.5,0.0
+2015-12-10 01:00:00,0.0,274.6000061035156,0.0,100120.0,0.005399999674409628,282.0,2.200000047683716,-0.9000000357627869,0.0
+2015-12-10 02:00:00,0.0,274.70001220703125,0.0,100160.0,0.005200000014156103,281.3000183105469,1.899999976158142,-1.2000000476837158,0.0
+2015-12-10 03:00:00,0.0,272.70001220703125,0.0,100100.0,0.0050999997183680534,281.3999938964844,1.600000023841858,-1.600000023841858,0.0
+2015-12-10 04:00:00,0.0,272.70001220703125,0.0,100080.0,0.0052999998442828655,281.3999938964844,1.600000023841858,-1.3000000715255737,0.0
+2015-12-10 05:00:00,0.0,272.70001220703125,0.0,100140.0,0.005399999674409628,281.0,1.600000023841858,-0.9000000357627869,0.0
+2015-12-10 06:00:00,0.0,280.6000061035156,0.0,100110.0,0.005399999674409628,279.3000183105469,1.600000023841858,-0.5,0.0
+2015-12-10 07:00:00,0.0,280.6000061035156,0.0,100070.0,0.0050999997183680534,280.3000183105469,1.600000023841858,-0.5,0.0
+2015-12-10 08:00:00,0.0,280.6000061035156,0.0,100060.0,0.005200000014156103,279.5,1.600000023841858,-0.4000000059604645,0.0
+2015-12-10 09:00:00,0.0,314.70001220703125,0.0,100050.0,0.0052999998442828655,279.6000061035156,1.600000023841858,-0.30000001192092896,0.0
+2015-12-10 10:00:00,0.0,314.70001220703125,0.0,100030.0,0.0050999997183680534,279.6000061035156,0.9000000357627869,-0.20000000298023224,0.0
+2015-12-10 11:00:00,0.0,314.70001220703125,0.0,100070.0,0.005200000014156103,279.3000183105469,0.20000000298023224,0.0,0.0
+2015-12-10 12:00:00,0.0,298.8999938964844,0.0,100070.0,0.005200000014156103,278.6000061035156,-0.5,0.20000000298023224,0.0
+2015-12-10 13:00:00,0.0,298.8999938964844,91.9000015258789,100190.0,0.004799999762326479,277.8999938964844,0.0,0.0,0.0
+2015-12-10 14:00:00,0.0,298.8999938964844,238.6999969482422,100170.0,0.005699999630451202,282.5,0.5,-0.10000000149011612,0.0
+2015-12-10 15:00:00,0.0,304.5,390.70001220703125,100250.0,0.006300000008195639,286.8999938964844,1.0,-0.20000000298023224,0.0
+2015-12-10 16:00:00,0.0,304.5,476.3999938964844,100190.0,0.0071000000461936,289.8000183105469,1.399999976158142,0.6000000238418579,0.0
+2015-12-10 17:00:00,0.0,304.3999938964844,501.8000183105469,100040.0,0.007599999662488699,292.5,1.899999976158142,1.5,0.0
+2015-12-10 18:00:00,0.0,345.8999938964844,421.5,99990.0,0.007899999618530273,293.3999938964844,2.299999952316284,2.299999952316284,0.0
+2015-12-10 19:00:00,0.0,345.8999938964844,370.1000061035156,99930.0,0.007699999958276749,293.6000061035156,2.0,2.799999952316284,0.0
+2015-12-10 20:00:00,0.0,345.8999938964844,287.8999938964844,99930.0,0.007599999662488699,293.6000061035156,1.7000000476837158,3.299999952316284,0.0
+2015-12-10 21:00:00,0.0,342.3999938964844,129.8000030517578,99900.0,0.007799999788403511,293.1000061035156,1.399999976158142,3.799999952316284,0.0
+2015-12-10 22:00:00,0.0,342.3999938964844,22.30000114440918,99950.0,0.007699999958276749,291.70001220703125,1.100000023841858,3.5,0.0
+2015-12-10 23:00:00,0.0,342.3999938964844,0.0,99940.0,0.008100000210106373,288.8999938964844,0.699999988079071,3.200000047683716,0.0
+2015-12-11 00:00:00,0.0,343.6000061035156,0.0,99940.0,0.008200000040233135,287.3000183105469,0.30000001192092896,2.9000000953674316,0.0
+2015-12-11 01:00:00,0.0,343.6000061035156,0.0,100000.0,0.008100000210106373,287.6000061035156,0.10000000149011612,2.6000001430511475,0.0
+2015-12-11 02:00:00,0.0,343.6000061035156,0.0,100050.0,0.007799999788403511,285.6000061035156,-0.10000000149011612,2.299999952316284,0.0
+2015-12-11 03:00:00,0.0,366.20001220703125,0.0,100050.0,0.007899999618530273,285.3000183105469,-0.20000000298023224,2.0,0.0
+2015-12-11 04:00:00,0.0,366.20001220703125,0.0,100040.0,0.007699999958276749,284.8999938964844,0.10000000149011612,2.200000047683716,0.0
+2015-12-11 05:00:00,0.0,366.20001220703125,0.0,100000.0,0.007699999958276749,285.5,0.4000000059604645,2.5,0.0
+2015-12-11 06:00:00,0.0,368.3000183105469,0.0,99960.0,0.0072999997064471245,284.8000183105469,0.699999988079071,2.700000047683716,0.0
+2015-12-11 07:00:00,0.0,368.3000183105469,0.0,99970.0,0.007699999958276749,285.0,1.100000023841858,2.5,0.0
+2015-12-11 08:00:00,0.0,368.3000183105469,0.0,100010.0,0.007499999832361937,285.3000183105469,1.5,2.200000047683716,0.0
+2015-12-11 09:00:00,0.0,310.0,0.0,99980.0,0.007599999662488699,284.8999938964844,1.8000000715255737,1.899999976158142,0.0
+2015-12-11 10:00:00,0.0,310.0,0.0,100000.0,0.0072999997064471245,283.70001220703125,1.600000023841858,2.0,0.0
+2015-12-11 11:00:00,0.0,310.0,0.0,100130.0,0.007499999832361937,283.70001220703125,1.3000000715255737,2.0,0.0
+2015-12-11 12:00:00,0.0,299.1000061035156,0.0,100150.0,0.007400000002235174,282.5,1.0,2.1000001430511475,0.0
+2015-12-11 13:00:00,0.0,299.1000061035156,87.5999984741211,100230.0,0.007599999662488699,283.8999938964844,1.100000023841858,1.899999976158142,0.0
+2015-12-11 14:00:00,0.0,299.1000061035156,230.8000030517578,100320.0,0.008599999360740185,285.20001220703125,1.3000000715255737,1.600000023841858,0.0
+2015-12-11 15:00:00,0.0,331.3999938964844,382.3999938964844,100360.0,0.00969999935477972,287.6000061035156,1.399999976158142,1.399999976158142,0.0
+2015-12-11 16:00:00,0.0,331.3999938964844,467.0,100390.0,0.00989999994635582,288.5,1.7000000476837158,2.1000001430511475,0.0
+2015-12-11 17:00:00,0.0,331.3999938964844,492.3000183105469,100370.0,0.010199999436736107,289.70001220703125,2.0,2.799999952316284,0.0
+2015-12-11 18:00:00,0.0,353.6000061035156,474.3999938964844,100310.0,0.01119999960064888,291.5,2.4000000953674316,3.5,0.0
+2015-12-11 19:00:00,0.0,353.6000061035156,416.8000183105469,100300.0,0.010599999688565731,294.70001220703125,2.299999952316284,3.700000047683716,0.0
+2015-12-11 20:00:00,0.0,353.6000061035156,324.3999938964844,100230.0,0.010199999436736107,295.3000183105469,2.299999952316284,3.799999952316284,0.0
+2015-12-11 21:00:00,0.0,347.6000061035156,137.5,100210.0,0.010400000028312206,294.8000183105469,2.200000047683716,4.0,0.0
+2015-12-11 22:00:00,0.0,347.6000061035156,23.80000114440918,100250.0,0.010699999518692493,293.20001220703125,1.7000000476837158,3.799999952316284,0.0
+2015-12-11 23:00:00,0.0,347.6000061035156,0.0,100290.0,0.010699999518692493,290.20001220703125,1.100000023841858,3.5,0.0
+2015-12-12 00:00:00,0.0,331.3999938964844,0.0,100330.0,0.010900000110268593,290.20001220703125,0.5,3.299999952316284,0.0
+2015-12-12 01:00:00,0.0,331.3999938964844,0.0,100420.0,0.009999999776482582,288.3000183105469,0.5,3.200000047683716,0.0
+2015-12-12 02:00:00,0.0,331.3999938964844,0.0,100420.0,0.00989999994635582,287.6000061035156,0.5,3.1000001430511475,0.0
+2015-12-12 03:00:00,0.0,328.0,0.0,100480.0,0.010099999606609344,288.0,0.5,3.0,0.0
+2015-12-12 04:00:00,0.0,328.0,0.0,100510.0,0.009800000116229057,287.20001220703125,1.100000023841858,3.0,0.0
+2015-12-12 05:00:00,0.0,328.0,0.0,100560.0,0.009399999864399433,286.8000183105469,1.8000000715255737,3.0,0.0
+2015-12-12 06:00:00,0.0,325.20001220703125,0.0,100600.0,0.00969999935477972,287.1000061035156,2.5,3.0,0.0
+2015-12-12 07:00:00,0.0,325.20001220703125,0.0,100630.0,0.009800000116229057,287.70001220703125,2.4000000953674316,2.9000000953674316,0.0
+2015-12-12 08:00:00,0.0,325.20001220703125,0.0,100660.0,0.00969999935477972,287.3999938964844,2.200000047683716,2.799999952316284,0.0
+2015-12-12 09:00:00,0.0,319.8000183105469,0.0,100670.0,0.009599999524652958,287.5,2.1000001430511475,2.700000047683716,0.0
+2015-12-12 10:00:00,0.0,319.8000183105469,0.0,100670.0,0.00969999935477972,287.3999938964844,1.600000023841858,2.700000047683716,0.0
+2015-12-12 11:00:00,0.0,319.8999938964844,0.0,100740.0,0.009499999694526196,286.8999938964844,1.2000000476837158,2.6000001430511475,0.0
+2015-12-12 12:00:00,0.0,316.8999938964844,0.0,100830.0,0.009099999442696571,286.20001220703125,0.800000011920929,2.6000001430511475,0.0
+2015-12-12 13:00:00,0.0,316.8999938964844,84.4000015258789,100870.0,0.009399999864399433,286.5,1.2000000476837158,2.4000000953674316,0.0
+2015-12-12 14:00:00,0.0,316.8999938964844,225.40000915527344,100930.0,0.009999999776482582,288.1000061035156,1.600000023841858,2.200000047683716,0.0
+2015-12-12 15:00:00,0.0,342.3999938964844,377.3000183105469,100960.0,0.010799999348819256,291.1000061035156,1.899999976158142,2.0,0.0
+2015-12-12 16:00:00,0.0,342.3999938964844,461.5,100960.0,0.010900000110268593,293.20001220703125,2.4000000953674316,1.899999976158142,0.0
+2015-12-12 17:00:00,0.0,342.3999938964844,487.0,100820.0,0.010099999606609344,295.1000061035156,2.9000000953674316,1.8000000715255737,0.0
+2015-12-12 18:00:00,0.0,354.3000183105469,475.70001220703125,100790.0,0.009999999776482582,296.1000061035156,3.4000000953674316,1.8000000715255737,0.0
+2015-12-12 19:00:00,0.0,354.3000183105469,418.20001220703125,100720.0,0.010099999606609344,297.0,3.1000001430511475,2.0,0.0
+2015-12-12 20:00:00,0.0,354.3000183105469,325.8000183105469,100670.0,0.010300000198185444,297.20001220703125,2.9000000953674316,2.299999952316284,0.0
+2015-12-12 21:00:00,0.0,339.3999938964844,157.1999969482422,100680.0,0.00989999994635582,296.3999938964844,2.6000001430511475,2.5,0.0
+2015-12-12 22:00:00,0.0,339.3999938964844,27.5,100730.0,0.010599999688565731,293.8999938964844,2.4000000953674316,2.4000000953674316,0.0
+2015-12-12 23:00:00,0.0,339.3999938964844,0.0,100740.0,0.010599999688565731,291.3000183105469,2.200000047683716,2.299999952316284,0.0
+2015-12-13 00:00:00,0.0,318.20001220703125,0.0,100780.0,0.010699999518692493,290.3999938964844,2.0,2.299999952316284,0.0
+2015-12-13 01:00:00,0.0,318.20001220703125,0.0,100810.0,0.010400000028312206,288.6000061035156,1.5,2.1000001430511475,0.0
+2015-12-13 02:00:00,0.0,318.20001220703125,0.0,100860.0,0.009800000116229057,286.8000183105469,0.9000000357627869,1.899999976158142,0.0
+2015-12-13 03:00:00,0.0,310.3999938964844,0.0,100830.0,0.009099999442696571,285.70001220703125,0.30000001192092896,1.7000000476837158,0.0
+2015-12-13 04:00:00,0.0,310.3999938964844,0.0,100840.0,0.008599999360740185,285.3000183105469,0.800000011920929,1.8000000715255737,0.0
+2015-12-13 05:00:00,0.0,310.3999938964844,0.0,100850.0,0.008999999612569809,286.0,1.2000000476837158,1.8000000715255737,0.0
+2015-12-13 06:00:00,0.0,301.70001220703125,0.0,100850.0,0.008299999870359898,284.5,1.600000023841858,1.899999976158142,0.0
+2015-12-13 07:00:00,0.0,301.70001220703125,0.0,100820.0,0.007999999448657036,284.3000183105469,1.3000000715255737,1.899999976158142,0.0
+2015-12-13 08:00:00,0.0,301.70001220703125,0.0,100810.0,0.006899999920278788,283.20001220703125,0.9000000357627869,1.8000000715255737,0.0
+2015-12-13 09:00:00,0.0,293.3999938964844,0.0,100760.0,0.0072999997064471245,283.20001220703125,0.5,1.8000000715255737,0.0
+2015-12-13 10:00:00,0.0,293.3999938964844,0.0,100750.0,0.0072999997064471245,282.3999938964844,0.0,1.399999976158142,0.0
+2015-12-13 11:00:00,0.0,293.5,0.0,100780.0,0.007400000002235174,282.70001220703125,-0.5,1.0,0.0
+2015-12-13 12:00:00,0.0,299.3999938964844,0.0,100810.0,0.006799999624490738,280.8999938964844,-1.100000023841858,0.6000000238418579,0.0
+2015-12-13 13:00:00,0.0,299.3999938964844,83.9000015258789,100790.0,0.0071000000461936,281.8000183105469,-1.0,0.10000000149011612,0.0
+2015-12-13 14:00:00,0.0,299.3999938964844,227.40000915527344,100860.0,0.007899999618530273,284.20001220703125,-0.9000000357627869,-0.30000001192092896,0.0
+2015-12-13 15:00:00,0.0,331.20001220703125,369.0,100800.0,0.008599999360740185,287.8000183105469,-0.9000000357627869,-0.800000011920929,0.0
+2015-12-13 16:00:00,0.0,331.1000061035156,452.0,100790.0,0.008899999782443047,291.3000183105469,-0.9000000357627869,0.4000000059604645,0.0
+2015-12-13 17:00:00,0.0,331.1000061035156,477.3000183105469,100700.0,0.00839999970048666,293.1000061035156,-0.9000000357627869,1.600000023841858,0.0
+2015-12-13 18:00:00,0.0,345.1000061035156,456.8000183105469,100580.0,0.009800000116229057,294.3999938964844,-0.9000000357627869,2.799999952316284,0.0
+2015-12-13 19:00:00,0.0,345.1000061035156,401.8999938964844,100490.0,0.009499999694526196,295.0,-1.3000000715255737,2.799999952316284,0.0
+2015-12-13 20:00:00,0.0,345.1000061035156,313.3000183105469,100420.0,0.010300000198185444,295.5,-1.600000023841858,2.9000000953674316,0.0
+2015-12-13 21:00:00,0.0,324.3000183105469,145.0,100370.0,0.010499999858438969,294.8999938964844,-2.0,3.0,0.0
+2015-12-13 22:00:00,0.0,324.3000183105469,25.700000762939453,100400.0,0.011099999770522118,292.8000183105469,-2.200000047683716,2.4000000953674316,0.0
+2015-12-13 23:00:00,0.0,324.3000183105469,0.0,100370.0,0.010900000110268593,290.1000061035156,-2.4000000953674316,1.7000000476837158,0.0
+2015-12-14 00:00:00,0.0,330.0,0.0,100370.0,0.010900000110268593,289.0,-2.6000001430511475,1.100000023841858,0.0
+2015-12-14 01:00:00,0.0,330.0,0.0,100360.0,0.011299999430775642,289.8999938964844,-2.799999952316284,1.2000000476837158,0.0
+2015-12-14 02:00:00,0.0,330.0,0.0,100380.0,0.011299999430775642,289.8999938964844,-2.9000000953674316,1.3000000715255737,0.0
+2015-12-14 03:00:00,0.0,317.3999938964844,0.0,100320.0,0.01119999960064888,289.5,-3.1000001430511475,1.399999976158142,0.0
+2015-12-14 04:00:00,0.0,317.3999938964844,0.0,100260.0,0.010900000110268593,289.1000061035156,-2.9000000953674316,1.899999976158142,0.0
+2015-12-14 05:00:00,0.0,317.3999938964844,0.0,100270.0,0.011099999770522118,289.0,-2.700000047683716,2.4000000953674316,0.0
+2015-12-14 06:00:00,0.0,324.3000183105469,0.0,100200.0,0.011399999260902405,289.20001220703125,-2.4000000953674316,2.9000000953674316,0.0
+2015-12-14 07:00:00,0.0,324.3000183105469,0.0,100130.0,0.01119999960064888,289.3000183105469,-1.899999976158142,2.9000000953674316,0.0
+2015-12-14 08:00:00,0.0,324.3000183105469,0.0,100020.0,0.011399999260902405,289.3999938964844,-1.5,3.0,0.0
+2015-12-14 09:00:00,0.0,358.3000183105469,0.0,99880.0,0.011500000022351742,290.0,-1.0,3.0,0.0
+2015-12-14 10:00:00,0.0,358.3000183105469,0.0,99810.0,0.011799999512732029,289.8999938964844,-1.600000023841858,3.1000001430511475,0.0
+2015-12-14 11:00:00,0.0,358.3000183105469,0.0,99780.0,0.012000000104308128,289.8999938964844,-2.200000047683716,3.200000047683716,0.0
+2015-12-14 12:00:00,0.0,381.1000061035156,0.0,99710.0,0.011699999682605267,289.8999938964844,-2.799999952316284,3.299999952316284,0.0
+2015-12-14 13:00:00,0.0,381.1000061035156,37.0,99680.0,0.012299999594688416,290.8000183105469,-2.1000001430511475,3.799999952316284,0.0
+2015-12-14 14:00:00,0.0,381.1000061035156,101.80000305175781,99650.0,0.012600000016391277,291.3000183105469,-1.399999976158142,4.300000190734863,7.382353145925361e-07
+2015-12-14 15:00:00,1.5,392.8999938964844,181.90000915527344,99570.0,0.012899999506771564,291.5,-0.699999988079071,4.800000190734863,0.0
+2015-12-14 16:00:00,0.0,392.8999938964844,223.10000610351562,99410.0,0.013399999588727951,292.6000061035156,-0.20000000298023224,4.900000095367432,0.0
+2015-12-14 17:00:00,0.0,392.8999938964844,235.8000030517578,99350.0,0.013899999670684338,293.3999938964844,0.30000001192092896,4.900000095367432,0.0
+2015-12-14 18:00:00,0.0,405.20001220703125,161.5,99270.0,0.014299999922513962,293.8000183105469,0.699999988079071,4.900000095367432,0.0
+2015-12-14 19:00:00,0.0,405.20001220703125,142.10000610351562,99290.0,0.014599999412894249,295.0,1.2000000476837158,4.5,5.090121965577734e-08
+2015-12-14 20:00:00,0.10000000149011612,405.20001220703125,110.9000015258789,99160.0,0.013499999418854713,293.6000061035156,1.600000023841858,4.099999904632568,2.1604080814467757e-06
+2015-12-14 21:00:00,4.300000190734863,395.70001220703125,43.79999923706055,99230.0,0.012299999594688416,291.6000061035156,2.1000001430511475,3.700000047683716,0.0
+2015-12-14 22:00:00,0.0,395.70001220703125,7.900000095367432,99140.0,0.012000000104308128,290.5,2.200000047683716,3.4000000953674316,0.0
+2015-12-14 23:00:00,0.0,395.70001220703125,0.0,99170.0,0.01209999993443489,290.70001220703125,2.4000000953674316,3.1000001430511475,0.0
+2015-12-15 00:00:00,0.0,333.3999938964844,0.0,99160.0,0.012000000104308128,290.3000183105469,2.5,2.700000047683716,0.0
+2015-12-15 01:00:00,0.0,333.3999938964844,0.0,99170.0,0.011899999342858791,290.3999938964844,3.1000001430511475,2.9000000953674316,0.0
+2015-12-15 02:00:00,0.0,333.3999938964844,0.0,99250.0,0.011699999682605267,290.0,3.6000001430511475,3.0,0.0
+2015-12-15 03:00:00,0.0,304.20001220703125,0.0,99280.0,0.011299999430775642,289.3000183105469,4.200000286102295,3.1000001430511475,0.0
+2015-12-15 04:00:00,0.0,304.20001220703125,0.0,99310.0,0.010900000110268593,288.5,4.200000286102295,2.700000047683716,0.0
+2015-12-15 05:00:00,0.0,304.20001220703125,0.0,99320.0,0.00969999935477972,288.20001220703125,4.300000190734863,2.200000047683716,0.0
+2015-12-15 06:00:00,0.0,287.3999938964844,0.0,99320.0,0.008999999612569809,286.8999938964844,4.300000190734863,1.7000000476837158,0.0
+2015-12-15 07:00:00,0.0,287.3999938964844,0.0,99360.0,0.00839999970048666,286.8000183105469,4.099999904632568,1.5,0.0
+2015-12-15 08:00:00,0.0,287.3999938964844,0.0,99340.0,0.007400000002235174,286.1000061035156,3.9000000953674316,1.2000000476837158,0.0
+2015-12-15 09:00:00,0.0,278.3999938964844,0.0,99330.0,0.00699999975040555,285.5,3.700000047683716,0.9000000357627869,0.0
+2015-12-15 10:00:00,0.0,278.3999938964844,0.0,99390.0,0.006899999920278788,284.8000183105469,3.5,0.9000000357627869,0.0
+2015-12-15 11:00:00,0.0,278.3999938964844,0.0,99390.0,0.0066999997943639755,284.6000061035156,3.299999952316284,0.800000011920929,0.0
+2015-12-15 12:00:00,0.0,270.3000183105469,0.0,99480.0,0.0066999997943639755,283.3000183105469,3.1000001430511475,0.699999988079071,0.0
+2015-12-15 13:00:00,0.0,270.3000183105469,82.5,99590.0,0.00699999975040555,282.70001220703125,3.1000001430511475,0.30000001192092896,0.0
+2015-12-15 14:00:00,0.0,270.3000183105469,230.0,99630.0,0.0072999997064471245,284.70001220703125,3.0,-0.10000000149011612,0.0
+2015-12-15 15:00:00,0.0,301.20001220703125,386.70001220703125,99670.0,0.0071000000461936,287.20001220703125,2.9000000953674316,-0.6000000238418579,0.0
+2015-12-15 16:00:00,0.0,301.20001220703125,475.1000061035156,99630.0,0.0072999997064471245,289.70001220703125,2.700000047683716,-0.10000000149011612,0.0
+2015-12-15 17:00:00,0.0,301.20001220703125,502.6000061035156,99560.0,0.007199999876320362,291.70001220703125,2.5,0.30000001192092896,0.0
+2015-12-15 18:00:00,0.0,315.8000183105469,490.0,99520.0,0.00699999975040555,293.6000061035156,2.200000047683716,0.699999988079071,0.0
+2015-12-15 19:00:00,0.0,315.8000183105469,431.70001220703125,99480.0,0.007199999876320362,295.20001220703125,2.0,0.5,0.0
+2015-12-15 20:00:00,0.0,315.8000183105469,337.1000061035156,99490.0,0.006899999920278788,295.6000061035156,1.7000000476837158,0.20000000298023224,0.0
+2015-12-15 21:00:00,0.0,305.8999938964844,148.5,99550.0,0.0071000000461936,295.3999938964844,1.399999976158142,0.0,0.0
+2015-12-15 22:00:00,0.0,305.8999938964844,27.200000762939453,99600.0,0.008100000210106373,292.3999938964844,1.100000023841858,0.30000001192092896,0.0
+2015-12-15 23:00:00,0.0,306.0,0.0,99620.0,0.008299999870359898,288.20001220703125,0.699999988079071,0.5,0.0
+2015-12-16 00:00:00,0.0,288.8999938964844,0.0,99650.0,0.00839999970048666,286.3000183105469,0.4000000059604645,0.800000011920929,0.0
+2015-12-16 01:00:00,0.0,288.8999938964844,0.0,99710.0,0.007999999448657036,285.5,0.20000000298023224,0.10000000149011612,0.0
+2015-12-16 02:00:00,0.0,288.8999938964844,0.0,99710.0,0.008299999870359898,285.0,0.0,-0.699999988079071,0.0
+2015-12-16 03:00:00,0.0,282.20001220703125,0.0,99740.0,0.008200000040233135,284.70001220703125,-0.30000001192092896,-1.399999976158142,0.0
+2015-12-16 04:00:00,0.0,282.20001220703125,0.0,99800.0,0.007799999788403511,283.8000183105469,-0.4000000059604645,-1.2000000476837158,0.0
+2015-12-16 05:00:00,0.0,282.20001220703125,0.0,99830.0,0.006899999920278788,281.20001220703125,-0.6000000238418579,-1.0,0.0
+2015-12-16 06:00:00,0.0,277.0,0.0,99820.0,0.006899999920278788,282.0,-0.699999988079071,-0.9000000357627869,0.0
+2015-12-16 07:00:00,0.0,277.0,0.0,99890.0,0.0064999996684491634,280.6000061035156,-0.9000000357627869,-0.800000011920929,0.0
+2015-12-16 08:00:00,0.0,277.0,0.0,99930.0,0.006300000008195639,279.8999938964844,-1.2000000476837158,-0.800000011920929,0.0
+2015-12-16 09:00:00,0.0,272.8000183105469,0.0,99880.0,0.006199999712407589,280.5,-1.399999976158142,-0.800000011920929,0.0
+2015-12-16 10:00:00,0.0,272.8000183105469,0.0,99880.0,0.006000000052154064,280.20001220703125,-1.8000000715255737,-0.800000011920929,0.0
+2015-12-16 11:00:00,0.0,272.8000183105469,0.0,99980.0,0.005399999674409628,278.3000183105469,-2.200000047683716,-0.800000011920929,0.0
+2015-12-16 12:00:00,0.0,267.5,0.0,100000.0,0.005499999970197678,278.20001220703125,-2.700000047683716,-0.800000011920929,0.0
+2015-12-16 13:00:00,0.0,267.5,81.30000305175781,100070.0,0.0058999997563660145,279.20001220703125,-2.5,-0.9000000357627869,0.0
+2015-12-16 14:00:00,0.0,267.5,230.10000610351562,100140.0,0.006799999624490738,281.5,-2.299999952316284,-1.0,0.0
+2015-12-16 15:00:00,0.0,293.8999938964844,387.3999938964844,100190.0,0.007499999832361937,284.8000183105469,-2.200000047683716,-1.100000023841858,0.0
+2015-12-16 16:00:00,0.0,293.8999938964844,476.6000061035156,100110.0,0.008499999530613422,288.70001220703125,-2.5,-0.6000000238418579,0.0
+2015-12-16 17:00:00,0.0,293.8999938964844,504.70001220703125,100060.0,0.007599999662488699,291.8000183105469,-2.9000000953674316,-0.10000000149011612,0.0
+2015-12-16 18:00:00,0.0,310.1000061035156,489.3000183105469,99980.0,0.007599999662488699,293.8000183105469,-3.299999952316284,0.4000000059604645,0.0
+2015-12-16 19:00:00,0.0,310.1000061035156,431.3000183105469,99930.0,0.007899999618530273,295.0,-3.1000001430511475,0.6000000238418579,0.0
+2015-12-16 20:00:00,0.0,310.1000061035156,337.20001220703125,99920.0,0.007999999448657036,295.20001220703125,-2.799999952316284,0.800000011920929,0.0
+2015-12-16 21:00:00,0.0,305.8000183105469,148.10000610351562,99810.0,0.007899999618530273,294.70001220703125,-2.6000001430511475,1.0,0.0
+2015-12-16 22:00:00,0.0,305.8000183105469,27.600000381469727,99850.0,0.008299999870359898,291.8999938964844,-2.799999952316284,0.6000000238418579,0.0
+2015-12-16 23:00:00,0.0,305.8000183105469,0.0,99890.0,0.008700000122189522,290.1000061035156,-3.0,0.30000001192092896,0.0
+2015-12-17 00:00:00,0.0,311.5,0.0,99900.0,0.008899999782443047,288.70001220703125,-3.200000047683716,0.0,0.0
+2015-12-17 01:00:00,0.0,311.5,0.0,100010.0,0.008599999360740185,286.0,-2.9000000953674316,0.10000000149011612,0.0
+2015-12-17 02:00:00,0.0,311.5,0.0,100000.0,0.008599999360740185,286.3000183105469,-2.6000001430511475,0.20000000298023224,0.0
+2015-12-17 03:00:00,0.0,342.0,0.0,99940.0,0.008499999530613422,286.6000061035156,-2.299999952316284,0.4000000059604645,2.3657042550979653e-07
+2015-12-17 04:00:00,0.5,342.0,0.0,99910.0,0.008799999952316284,287.5,-1.8000000715255737,0.4000000059604645,4.76594374793869e-07
+2015-12-17 05:00:00,1.0,342.0,0.0,99930.0,0.00930000003427267,287.20001220703125,-1.3000000715255737,0.5,1.426301595152609e-06
+2015-12-17 06:00:00,3.0,382.5,0.0,99760.0,0.009499999694526196,286.5,-0.800000011920929,0.5,4.727622629790369e-07
+2015-12-17 07:00:00,1.0,382.3999938964844,0.0,99720.0,0.009399999864399433,286.6000061035156,-1.2000000476837158,0.6000000238418579,1.0409098948042186e-06
+2015-12-17 08:00:00,2.200000047683716,382.3999938964844,0.0,99740.0,0.009499999694526196,286.6000061035156,-1.600000023841858,0.699999988079071,0.0
+2015-12-17 09:00:00,0.0,382.6000061035156,0.0,99710.0,0.00930000003427267,286.5,-2.0,0.699999988079071,0.0
+2015-12-17 10:00:00,0.0,382.6000061035156,0.0,99590.0,0.008999999612569809,286.20001220703125,-2.4000000953674316,0.699999988079071,0.0
+2015-12-17 11:00:00,0.0,382.6000061035156,0.0,99510.0,0.009099999442696571,286.6000061035156,-2.799999952316284,0.699999988079071,1.419422553058779e-06
+2015-12-17 12:00:00,3.0,384.20001220703125,0.0,99450.0,0.00930000003427267,286.3999938964844,-3.200000047683716,0.6000000238418579,2.0784926960470127e-06
+2015-12-17 13:00:00,4.400000095367432,384.20001220703125,34.5,99540.0,0.009499999694526196,286.5,-3.0,1.5,2.0801540021938852e-06
+2015-12-17 14:00:00,4.400000095367432,384.20001220703125,99.20000457763672,99540.0,0.00969999935477972,286.8999938964844,-2.799999952316284,2.4000000953674316,7.588522475838139e-07
+2015-12-17 15:00:00,1.600000023841858,404.20001220703125,157.0,99420.0,0.009800000116229057,287.3000183105469,-2.700000047683716,3.299999952316284,1.0943852648065907e-06
+2015-12-17 16:00:00,2.299999952316284,404.20001220703125,193.40000915527344,99470.0,0.009800000116229057,287.0,-0.6000000238418579,4.300000190734863,1.8037282986643158e-06
+2015-12-17 17:00:00,3.799999952316284,404.20001220703125,204.90000915527344,99360.0,0.009800000116229057,286.8999938964844,1.5,5.400000095367432,0.0
+2015-12-17 18:00:00,0.0,380.20001220703125,242.6999969482422,99310.0,0.010599999688565731,288.0,3.6000001430511475,6.400000095367432,0.0
+2015-12-17 19:00:00,0.0,380.20001220703125,214.10000610351562,99360.0,0.010999999940395355,289.3000183105469,3.799999952316284,5.599999904632568,0.0
+2015-12-17 20:00:00,0.0,380.20001220703125,167.60000610351562,99280.0,0.011399999260902405,289.20001220703125,4.0,4.800000190734863,0.0
+2015-12-17 21:00:00,0.0,371.1000061035156,72.30000305175781,99260.0,0.011399999260902405,289.70001220703125,4.200000286102295,4.0,0.0
+2015-12-17 22:00:00,0.0,371.1000061035156,13.699999809265137,99260.0,0.011899999342858791,289.70001220703125,3.700000047683716,3.9000000953674316,0.0
+2015-12-17 23:00:00,0.0,371.1000061035156,0.0,99330.0,0.011299999430775642,289.0,3.200000047683716,3.700000047683716,0.0
+2015-12-18 00:00:00,0.0,361.8000183105469,0.0,99330.0,0.01119999960064888,289.20001220703125,2.700000047683716,3.5,0.0
+2015-12-18 01:00:00,0.0,361.8000183105469,0.0,99410.0,0.010999999940395355,288.8000183105469,2.200000047683716,3.200000047683716,0.0
+2015-12-18 02:00:00,0.0,361.8000183105469,0.0,99440.0,0.010900000110268593,288.6000061035156,1.7000000476837158,2.9000000953674316,0.0
+2015-12-18 03:00:00,0.0,363.8000183105469,0.0,99430.0,0.010699999518692493,288.3999938964844,1.2000000476837158,2.6000001430511475,0.0
+2015-12-18 04:00:00,0.0,363.8000183105469,0.0,99460.0,0.010699999518692493,288.6000061035156,1.5,2.6000001430511475,0.0
+2015-12-18 05:00:00,0.0,363.8000183105469,0.0,99360.0,0.010699999518692493,288.1000061035156,1.7000000476837158,2.6000001430511475,0.0
+2015-12-18 06:00:00,0.0,344.3999938964844,0.0,99320.0,0.010699999518692493,287.70001220703125,1.899999976158142,2.700000047683716,0.0
+2015-12-18 07:00:00,0.0,344.3999938964844,0.0,99370.0,0.010400000028312206,288.1000061035156,2.0,2.4000000953674316,0.0
+2015-12-18 08:00:00,0.0,344.3999938964844,0.0,99390.0,0.009599999524652958,287.6000061035156,2.200000047683716,2.200000047683716,0.0
+2015-12-18 09:00:00,0.0,321.0,0.0,99340.0,0.009399999864399433,286.70001220703125,2.299999952316284,1.899999976158142,0.0
+2015-12-18 10:00:00,0.0,321.0,0.0,99390.0,0.00839999970048666,285.3000183105469,3.1000001430511475,1.8000000715255737,0.0
+2015-12-18 11:00:00,0.0,321.0,0.0,99440.0,0.0072999997064471245,283.8000183105469,3.799999952316284,1.600000023841858,0.0
+2015-12-18 12:00:00,0.0,269.0,0.0,99560.0,0.006899999920278788,282.8999938964844,4.599999904632568,1.5,0.0
+2015-12-18 13:00:00,0.0,269.0,82.20000457763672,99630.0,0.0066999997943639755,282.20001220703125,5.200000286102295,1.2000000476837158,0.0
+2015-12-18 14:00:00,0.0,269.0,239.3000030517578,99730.0,0.006300000008195639,282.3999938964844,5.700000286102295,0.800000011920929,0.0
+2015-12-18 15:00:00,0.0,263.5,388.8000183105469,99880.0,0.006000000052154064,282.20001220703125,6.300000190734863,0.5,0.0
+2015-12-18 16:00:00,0.0,263.5,479.70001220703125,99910.0,0.005699999630451202,284.0,6.800000190734863,0.20000000298023224,0.0
+2015-12-18 17:00:00,0.0,263.5,508.8999938964844,99850.0,0.0050999997183680534,285.1000061035156,7.300000190734863,-0.10000000149011612,0.0
+2015-12-18 18:00:00,0.0,260.0,503.1000061035156,99810.0,0.003999999724328518,286.70001220703125,7.800000190734863,-0.4000000059604645,0.0
+2015-12-18 19:00:00,0.0,260.0,444.20001220703125,99810.0,0.003399999812245369,287.1000061035156,7.200000286102295,-1.5,0.0
+2015-12-18 20:00:00,0.0,260.0,348.0,99920.0,0.002899999963119626,287.20001220703125,6.5,-2.6000001430511475,0.0
+2015-12-18 21:00:00,0.0,243.5,159.1999969482422,99950.0,0.0023999998811632395,286.1000061035156,5.800000190734863,-3.700000047683716,0.0
+2015-12-18 22:00:00,0.0,243.5,30.899999618530273,100130.0,0.002699999837204814,284.3999938964844,5.099999904632568,-3.4000000953674316,0.0
+2015-12-18 23:00:00,0.0,243.5,0.0,100260.0,0.003000000026077032,282.20001220703125,4.400000095367432,-3.1000001430511475,0.0
+2015-12-19 00:00:00,0.0,225.0,0.0,100400.0,0.0030999998562037945,280.5,3.6000001430511475,-2.799999952316284,0.0
+2015-12-19 01:00:00,0.0,225.0,0.0,100620.0,0.002899999963119626,278.8000183105469,3.4000000953674316,-2.6000001430511475,0.0
+2015-12-19 02:00:00,0.0,225.0,0.0,100790.0,0.00279999990016222,277.0,3.200000047683716,-2.299999952316284,0.0
+2015-12-19 03:00:00,0.0,214.6999969482422,0.0,100840.0,0.00279999990016222,276.0,2.9000000953674316,-2.1000001430511475,0.0
+2015-12-19 04:00:00,0.0,214.6999969482422,0.0,100940.0,0.002899999963119626,275.20001220703125,2.799999952316284,-2.1000001430511475,0.0
+2015-12-19 05:00:00,0.0,214.6999969482422,0.0,101020.0,0.00279999990016222,274.8000183105469,2.700000047683716,-2.0,0.0
+2015-12-19 06:00:00,0.0,206.60000610351562,0.0,101050.0,0.002199999988079071,274.1000061035156,2.6000001430511475,-2.0,0.0
+2015-12-19 07:00:00,0.0,206.60000610351562,0.0,101070.0,0.0024999999441206455,272.6000061035156,2.6000001430511475,-1.8000000715255737,0.0
+2015-12-19 08:00:00,0.0,206.60000610351562,0.0,101130.0,0.0023999998811632395,272.1000061035156,2.6000001430511475,-1.5,0.0
+2015-12-19 09:00:00,0.0,204.60000610351562,0.0,101190.0,0.0024999999441206455,271.70001220703125,2.5,-1.2000000476837158,0.0
+2015-12-19 10:00:00,0.0,204.60000610351562,0.0,101210.0,0.0026000000070780516,271.70001220703125,2.4000000953674316,-0.4000000059604645,0.0
+2015-12-19 11:00:00,0.0,204.60000610351562,0.0,101340.0,0.00279999990016222,270.6000061035156,2.200000047683716,0.4000000059604645,0.0
+2015-12-19 12:00:00,0.0,209.10000610351562,0.0,101420.0,0.002699999837204814,270.70001220703125,2.0,1.2000000476837158,0.0
+2015-12-19 13:00:00,0.0,209.10000610351562,79.0,101550.0,0.002899999963119626,271.3000183105469,2.1000001430511475,0.9000000357627869,0.0
+2015-12-19 14:00:00,0.0,209.10000610351562,233.0,101560.0,0.002899999963119626,273.5,2.200000047683716,0.6000000238418579,0.0
+2015-12-19 15:00:00,0.0,230.10000610351562,394.3000183105469,101690.0,0.00279999990016222,276.3999938964844,2.299999952316284,0.30000001192092896,0.0
+2015-12-19 16:00:00,0.0,230.10000610351562,487.0,101620.0,0.002300000051036477,279.3000183105469,2.9000000953674316,0.699999988079071,0.0
+2015-12-19 17:00:00,0.0,230.10000610351562,517.1000366210938,101550.0,0.002099999925121665,280.8000183105469,3.5,1.0,0.0
+2015-12-19 18:00:00,0.0,240.40000915527344,507.70001220703125,101500.0,0.0016999999061226845,281.70001220703125,4.099999904632568,1.3000000715255737,0.0
+2015-12-19 19:00:00,0.0,240.40000915527344,448.6000061035156,101460.0,0.0018999999156221747,282.6000061035156,3.9000000953674316,1.0,0.0
+2015-12-19 20:00:00,0.0,240.40000915527344,351.8000183105469,101410.0,0.002099999925121665,283.3999938964844,3.700000047683716,0.699999988079071,0.0
+2015-12-19 21:00:00,0.0,233.60000610351562,162.1999969482422,101410.0,0.002099999925121665,283.70001220703125,3.5,0.4000000059604645,0.0
+2015-12-19 22:00:00,0.0,233.60000610351562,32.10000228881836,101450.0,0.002099999925121665,282.3000183105469,3.200000047683716,0.699999988079071,0.0
+2015-12-19 23:00:00,0.0,233.60000610351562,0.0,101540.0,0.002699999837204814,278.8000183105469,2.9000000953674316,1.0,0.0
+2015-12-20 00:00:00,0.0,224.0,0.0,101560.0,0.003000000026077032,276.5,2.6000001430511475,1.3000000715255737,0.0
+2015-12-20 01:00:00,0.0,224.0,0.0,101590.0,0.0030999998562037945,275.8999938964844,2.299999952316284,0.9000000357627869,0.0
+2015-12-20 02:00:00,0.0,224.0,0.0,101580.0,0.003000000026077032,274.6000061035156,2.1000001430511475,0.6000000238418579,0.0
+2015-12-20 03:00:00,0.0,220.3000030517578,0.0,101540.0,0.003000000026077032,273.8000183105469,1.8000000715255737,0.20000000298023224,0.0
+2015-12-20 04:00:00,0.0,220.3000030517578,0.0,101590.0,0.003000000026077032,273.3000183105469,1.399999976158142,-0.4000000059604645,0.0
+2015-12-20 05:00:00,0.0,220.3000030517578,0.0,101620.0,0.002899999963119626,271.8000183105469,1.0,-1.100000023841858,0.0
+2015-12-20 06:00:00,0.0,218.0,0.0,101610.0,0.003000000026077032,272.1000061035156,0.6000000238418579,-1.7000000476837158,0.0
+2015-12-20 07:00:00,0.0,218.0,0.0,101640.0,0.003000000026077032,271.1000061035156,0.4000000059604645,-2.1000001430511475,0.0
+2015-12-20 08:00:00,0.0,218.0,0.0,101660.0,0.003000000026077032,271.5,0.20000000298023224,-2.4000000953674316,0.0
+2015-12-20 09:00:00,0.0,215.8000030517578,0.0,101690.0,0.002899999963119626,271.6000061035156,0.0,-2.799999952316284,0.0
+2015-12-20 10:00:00,0.0,215.8000030517578,0.0,101700.0,0.00279999990016222,271.0,-0.4000000059604645,-2.200000047683716,0.0
+2015-12-20 11:00:00,0.0,215.8000030517578,0.0,101720.0,0.00279999990016222,271.20001220703125,-0.800000011920929,-1.600000023841858,0.0
+2015-12-20 12:00:00,0.0,219.6999969482422,0.0,101720.0,0.00279999990016222,271.20001220703125,-1.3000000715255737,-1.0,0.0
+2015-12-20 13:00:00,0.0,219.6999969482422,76.80000305175781,101850.0,0.002899999963119626,271.20001220703125,-1.5,-0.800000011920929,0.0
+2015-12-20 14:00:00,0.0,219.6999969482422,229.6999969482422,101960.0,0.0031999999191612005,274.5,-1.7000000476837158,-0.699999988079071,0.0
+2015-12-20 15:00:00,0.0,242.6999969482422,390.3999938964844,101930.0,0.003000000026077032,278.6000061035156,-1.899999976158142,-0.5,0.0
+2015-12-20 16:00:00,0.0,242.6999969482422,482.8999938964844,101900.0,0.00279999990016222,282.1000061035156,-2.200000047683716,-0.10000000149011612,0.0
+2015-12-20 17:00:00,0.0,242.60000610351562,513.2000122070312,101840.0,0.0026000000070780516,284.5,-2.5,0.4000000059604645,0.0
+2015-12-20 18:00:00,0.0,254.8000030517578,500.70001220703125,101820.0,0.0023999998811632395,285.5,-2.799999952316284,0.800000011920929,0.0
+2015-12-20 19:00:00,0.0,254.8000030517578,442.8000183105469,101720.0,0.0024999999441206455,286.20001220703125,-2.700000047683716,0.9000000357627869,0.0
+2015-12-20 20:00:00,0.0,254.8000030517578,347.6000061035156,101690.0,0.0026000000070780516,286.1000061035156,-2.5,0.9000000357627869,0.0
+2015-12-20 21:00:00,0.0,253.3000030517578,173.0,101590.0,0.002699999837204814,285.3999938964844,-2.299999952316284,1.0,0.0
+2015-12-20 22:00:00,0.0,253.3000030517578,35.10000228881836,101600.0,0.002899999963119626,283.8999938964844,-2.700000047683716,1.0,0.0
+2015-12-20 23:00:00,0.0,253.3000030517578,0.0,101630.0,0.003399999812245369,281.6000061035156,-3.1000001430511475,1.100000023841858,0.0
+2015-12-21 00:00:00,0.0,250.10000610351562,0.0,101610.0,0.003700000001117587,279.70001220703125,-3.6000001430511475,1.2000000476837158,0.0
+2015-12-21 01:00:00,0.0,250.10000610351562,0.0,101580.0,0.003700000001117587,278.3999938964844,-3.299999952316284,0.6000000238418579,0.0
+2015-12-21 02:00:00,0.0,250.10000610351562,0.0,101630.0,0.003700000001117587,276.6000061035156,-3.1000001430511475,0.10000000149011612,0.0
+2015-12-21 03:00:00,0.0,266.5,0.0,101580.0,0.0037999998312443495,277.3000183105469,-2.799999952316284,-0.4000000059604645,0.0
+2015-12-21 04:00:00,0.0,266.5,0.0,101530.0,0.0037999998312443495,277.70001220703125,-2.799999952316284,-0.800000011920929,0.0
+2015-12-21 05:00:00,0.0,266.5,0.0,101500.0,0.0037999998312443495,277.1000061035156,-2.700000047683716,-1.100000023841858,0.0
+2015-12-21 06:00:00,0.0,289.0,0.0,101480.0,0.003999999724328518,278.0,-2.700000047683716,-1.399999976158142,0.0
+2015-12-21 07:00:00,0.0,289.0,0.0,101460.0,0.004100000020116568,279.1000061035156,-2.5,-1.399999976158142,0.0
+2015-12-21 08:00:00,0.0,289.0,0.0,101470.0,0.00419999985024333,279.0,-2.4000000953674316,-1.3000000715255737,0.0
+2015-12-21 09:00:00,0.0,334.1000061035156,0.0,101380.0,0.00419999985024333,279.3000183105469,-2.299999952316284,-1.2000000476837158,0.0
+2015-12-21 10:00:00,0.0,334.1000061035156,0.0,101340.0,0.004299999680370092,279.0,-2.200000047683716,-1.100000023841858,0.0
+2015-12-21 11:00:00,0.0,334.1000061035156,0.0,101290.0,0.00419999985024333,278.5,-2.1000001430511475,-1.100000023841858,0.0
+2015-12-21 12:00:00,0.0,352.8999938964844,0.0,101310.0,0.004399999976158142,279.1000061035156,-2.0,-1.0,0.0
+2015-12-21 13:00:00,0.0,352.8999938964844,33.29999923706055,101380.0,0.00419999985024333,279.5,-2.0,-0.9000000357627869,0.0
+2015-12-21 14:00:00,0.0,352.8999938964844,100.80000305175781,101310.0,0.00419999985024333,280.0,-2.0,-0.800000011920929,0.0
+2015-12-21 15:00:00,0.0,372.3999938964844,160.90000915527344,101310.0,0.004299999680370092,280.70001220703125,-2.0,-0.699999988079071,0.0
+2015-12-21 16:00:00,0.0,372.3999938964844,199.1999969482422,101300.0,0.0044999998062849045,282.6000061035156,-1.899999976158142,-0.4000000059604645,0.0
+2015-12-21 17:00:00,0.0,372.3999938964844,211.90000915527344,101220.0,0.004900000058114529,283.8000183105469,-1.7000000476837158,-0.20000000298023224,0.0
+2015-12-21 18:00:00,0.0,375.5,290.3999938964844,101150.0,0.004999999888241291,283.8999938964844,-1.5,0.10000000149011612,0.0
+2015-12-21 19:00:00,0.0,375.5,257.0,101050.0,0.005399999674409628,285.0,-1.600000023841858,0.10000000149011612,0.0
+2015-12-21 20:00:00,0.0,375.5,202.0,100890.0,0.00559999980032444,285.8000183105469,-1.8000000715255737,0.10000000149011612,0.0
+2015-12-21 21:00:00,0.0,361.70001220703125,132.8000030517578,100870.0,0.0058999997563660145,285.8000183105469,-1.899999976158142,0.10000000149011612,0.0
+2015-12-21 22:00:00,0.0,361.70001220703125,27.600000381469727,100820.0,0.006099999882280827,285.1000061035156,-2.200000047683716,0.4000000059604645,0.0
+2015-12-21 23:00:00,0.0,361.70001220703125,0.0,100830.0,0.006099999882280827,283.20001220703125,-2.5,0.699999988079071,0.0
+2015-12-22 00:00:00,0.0,357.0,0.0,100740.0,0.006199999712407589,283.20001220703125,-2.700000047683716,1.0,0.0
+2015-12-22 01:00:00,0.0,357.0,0.0,100760.0,0.0064999996684491634,283.0,-2.6000001430511475,0.9000000357627869,0.0
+2015-12-22 02:00:00,0.0,357.0,0.0,100770.0,0.006399999838322401,283.20001220703125,-2.5,0.800000011920929,0.0
+2015-12-22 03:00:00,0.0,369.20001220703125,0.0,100630.0,0.006300000008195639,282.1000061035156,-2.4000000953674316,0.699999988079071,0.0
+2015-12-22 04:00:00,0.0,369.20001220703125,0.0,100600.0,0.006300000008195639,282.5,-2.299999952316284,0.9000000357627869,0.0
+2015-12-22 05:00:00,0.0,369.20001220703125,0.0,100490.0,0.006599999964237213,283.1000061035156,-2.200000047683716,1.100000023841858,5.986149869805075e-07
+2015-12-22 06:00:00,1.3000000715255737,391.20001220703125,0.0,100310.0,0.00699999975040555,282.70001220703125,-2.1000001430511475,1.3000000715255737,2.8464086424883143e-06
+2015-12-22 07:00:00,6.200000286102295,391.1000061035156,0.0,100280.0,0.007499999832361937,283.5,-1.0,1.7000000476837158,3.00210506940693e-06
+2015-12-22 08:00:00,6.5,391.1000061035156,0.0,100110.0,0.008200000040233135,284.3000183105469,0.10000000149011612,2.0,3.392200346615728e-06
+2015-12-22 09:00:00,7.300000190734863,386.1000061035156,0.0,100030.0,0.008700000122189522,285.3000183105469,1.2000000476837158,2.4000000953674316,1.7654831463933217e-05
+2015-12-22 10:00:00,37.70000076293945,386.1000061035156,0.0,100100.0,0.009200000204145908,285.8999938964844,0.800000011920929,2.799999952316284,4.563967315233157e-06
+2015-12-22 11:00:00,9.699999809265137,386.1000061035156,0.0,100180.0,0.008899999782443047,285.3999938964844,0.6000000238418579,3.200000047683716,1.1716610241739401e-06
+2015-12-22 12:00:00,2.5,380.70001220703125,0.0,100160.0,0.009399999864399433,286.20001220703125,0.20000000298023224,3.6000001430511475,6.131225553307689e-07
+2015-12-22 13:00:00,1.3000000715255737,380.70001220703125,34.79999923706055,100130.0,0.009499999694526196,286.3000183105469,0.20000000298023224,3.6000001430511475,3.7760660823191564e-07
+2015-12-22 14:00:00,0.800000011920929,380.70001220703125,106.70000457763672,100230.0,0.009499999694526196,286.6000061035156,0.10000000149011612,3.700000047683716,0.0
+2015-12-22 15:00:00,0.0,384.8000183105469,237.60000610351562,100260.0,0.009999999776482582,287.20001220703125,0.10000000149011612,3.700000047683716,0.0
+2015-12-22 16:00:00,0.0,384.8000183105469,294.6000061035156,100210.0,0.010099999606609344,287.3999938964844,0.20000000298023224,3.5,0.0
+2015-12-22 17:00:00,0.0,384.8000183105469,313.6000061035156,100160.0,0.00989999994635582,287.0,0.30000001192092896,3.4000000953674316,0.0
+2015-12-22 18:00:00,0.0,392.8999938964844,306.5,100010.0,0.010300000198185444,288.0,0.4000000059604645,3.200000047683716,0.0
+2015-12-22 19:00:00,0.0,392.8999938964844,271.6000061035156,99990.0,0.011399999260902405,289.70001220703125,-0.10000000149011612,3.6000001430511475,0.0
+2015-12-22 20:00:00,0.0,392.8999938964844,213.6999969482422,99990.0,0.011699999682605267,290.20001220703125,-0.699999988079071,3.9000000953674316,0.0
+2015-12-22 21:00:00,0.0,388.3999938964844,118.30000305175781,100040.0,0.011599999852478504,290.0,-1.2000000476837158,4.300000190734863,0.0
+2015-12-22 22:00:00,0.0,388.3999938964844,25.200000762939453,99990.0,0.011399999260902405,289.6000061035156,-1.399999976158142,3.700000047683716,0.0
+2015-12-22 23:00:00,0.0,388.3999938964844,0.0,99990.0,0.010799999348819256,288.8000183105469,-1.600000023841858,3.1000001430511475,0.0
+2015-12-23 00:00:00,0.0,383.3000183105469,0.0,100050.0,0.011099999770522118,288.8000183105469,-1.8000000715255737,2.6000001430511475,0.0
+2015-12-23 01:00:00,0.0,383.3000183105469,0.0,100130.0,0.011099999770522118,289.20001220703125,-1.8000000715255737,2.200000047683716,0.0
+2015-12-23 02:00:00,0.0,383.3000183105469,0.0,100110.0,0.011099999770522118,288.8000183105469,-1.899999976158142,1.899999976158142,0.0
+2015-12-23 03:00:00,0.0,385.8000183105469,0.0,100090.0,0.011299999430775642,289.20001220703125,-2.0,1.5,0.0
+2015-12-23 04:00:00,0.0,385.8000183105469,0.0,100050.0,0.01119999960064888,289.0,-1.7000000476837158,1.600000023841858,0.0
+2015-12-23 05:00:00,0.0,385.8000183105469,0.0,100010.0,0.011699999682605267,289.5,-1.5,1.600000023841858,0.0
+2015-12-23 06:00:00,0.0,386.5,0.0,99980.0,0.011899999342858791,289.70001220703125,-1.2000000476837158,1.7000000476837158,0.0
+2015-12-23 07:00:00,0.0,386.5,0.0,100010.0,0.011599999852478504,289.8000183105469,-1.399999976158142,1.7000000476837158,0.0
+2015-12-23 08:00:00,0.0,386.5,0.0,100000.0,0.012000000104308128,289.70001220703125,-1.600000023841858,1.7000000476837158,0.0
+2015-12-23 09:00:00,0.0,391.0,0.0,99970.0,0.011899999342858791,289.8000183105469,-1.8000000715255737,1.7000000476837158,0.0
+2015-12-23 10:00:00,0.0,391.0,0.0,99940.0,0.011699999682605267,289.70001220703125,-2.1000001430511475,1.899999976158142,0.0
+2015-12-23 11:00:00,0.0,391.0,0.0,99920.0,0.011699999682605267,289.3999938964844,-2.5,2.1000001430511475,0.0
+2015-12-23 12:00:00,0.0,389.1000061035156,0.0,99900.0,0.011500000022351742,289.3000183105469,-2.799999952316284,2.4000000953674316,1.8866700062492885e-06
+2015-12-23 13:00:00,3.9000000953674316,389.1000061035156,42.400001525878906,99950.0,0.011699999682605267,289.70001220703125,-2.700000047683716,2.9000000953674316,5.824838155694726e-07
+2015-12-23 14:00:00,1.2000000476837158,389.1000061035156,131.6999969482422,99920.0,0.011899999342858791,289.8000183105469,-2.5,3.5,5.635471187070408e-06
+2015-12-23 15:00:00,11.600000381469727,393.8000183105469,163.0,99920.0,0.012000000104308128,290.0,-2.299999952316284,4.0,8.759635909420274e-07
+2015-12-23 16:00:00,1.8000000715255737,393.8000183105469,202.40000915527344,99860.0,0.01269999984651804,291.20001220703125,-1.899999976158142,4.099999904632568,4.4255319724101603e-07
+2015-12-23 17:00:00,0.9000000357627869,393.8000183105469,215.60000610351562,99740.0,0.013100000098347664,291.8999938964844,-1.399999976158142,4.099999904632568,0.0
+2015-12-23 18:00:00,0.0,405.20001220703125,182.3000030517578,99650.0,0.013700000010430813,292.20001220703125,-1.0,4.200000286102295,4.960924499258517e-06
+2015-12-23 19:00:00,10.0,405.20001220703125,161.60000610351562,99630.0,0.012899999506771564,291.6000061035156,-0.699999988079071,4.0,8.882235019915836e-07
+2015-12-23 20:00:00,1.8000000715255737,405.1000061035156,127.4000015258789,99690.0,0.012799999676644802,291.3000183105469,-0.4000000059604645,3.9000000953674316,2.9529413757094877e-07
+2015-12-23 21:00:00,0.6000000238418579,392.6000061035156,96.80000305175781,99740.0,0.013199999928474426,291.6000061035156,-0.10000000149011612,3.799999952316284,1.085606482825919e-06
+2015-12-23 22:00:00,2.200000047683716,392.6000061035156,21.100000381469727,99730.0,0.012399999424815178,290.8000183105469,-0.20000000298023224,3.200000047683716,3.430094869384076e-07
+2015-12-23 23:00:00,0.699999988079071,392.6000061035156,0.0,99800.0,0.012399999424815178,290.20001220703125,-0.4000000059604645,2.700000047683716,1.8524283800090267e-06
+2015-12-24 00:00:00,3.799999952316284,395.6000061035156,0.0,99980.0,0.012000000104308128,290.0,-0.5,2.200000047683716,6.813049765019497e-07
+2015-12-24 01:00:00,1.399999976158142,395.6000061035156,0.0,99950.0,0.011799999512732029,289.3999938964844,-1.0,2.299999952316284,1.0651743136309484e-06
+2015-12-24 02:00:00,2.200000047683716,395.6000061035156,0.0,100010.0,0.01209999993443489,290.3000183105469,-1.5,2.4000000953674316,7.806404696576303e-07
+2015-12-24 03:00:00,1.600000023841858,396.6000061035156,0.0,100050.0,0.01209999993443489,290.20001220703125,-2.0,2.5,7.799698656241153e-07
+2015-12-24 04:00:00,1.600000023841858,396.6000061035156,0.0,99960.0,0.011699999682605267,290.20001220703125,-1.3000000715255737,3.6000001430511475,0.0
+2015-12-24 05:00:00,0.0,396.6000061035156,0.0,100010.0,0.011799999512732029,289.8000183105469,-0.6000000238418579,4.700000286102295,0.0
+2015-12-24 06:00:00,0.0,392.8000183105469,0.0,99930.0,0.012199999764561653,290.3999938964844,0.10000000149011612,5.900000095367432,0.0
+2015-12-24 07:00:00,0.0,392.8000183105469,0.0,99960.0,0.012399999424815178,290.8000183105469,0.5,5.800000190734863,0.0
+2015-12-24 08:00:00,0.0,392.8000183105469,0.0,100010.0,0.012999999336898327,291.6000061035156,0.9000000357627869,5.800000190734863,0.0
+2015-12-24 09:00:00,0.0,379.6000061035156,0.0,99960.0,0.014099999330937862,293.3999938964844,1.3000000715255737,5.700000286102295,0.0
+2015-12-24 10:00:00,0.0,379.6000061035156,0.0,100010.0,0.014599999412894249,293.5,0.9000000357627869,4.700000286102295,0.0
+2015-12-24 11:00:00,0.0,379.6000061035156,0.0,100040.0,0.014599999412894249,293.8999938964844,0.5,3.700000047683716,0.0
+2015-12-24 12:00:00,0.0,379.20001220703125,0.0,100110.0,0.014699999243021011,293.70001220703125,0.0,2.700000047683716,0.0
+2015-12-24 13:00:00,0.0,379.20001220703125,49.5,100230.0,0.014699999243021011,294.0,0.699999988079071,3.0,0.0
+2015-12-24 14:00:00,0.0,379.20001220703125,155.6999969482422,100320.0,0.014599999412894249,294.20001220703125,1.3000000715255737,3.4000000953674316,0.0
+2015-12-24 15:00:00,0.0,397.6000061035156,267.3000183105469,100410.0,0.01489999983459711,294.8000183105469,2.0,3.799999952316284,0.0
+2015-12-24 16:00:00,0.0,397.6000061035156,332.1000061035156,100400.0,0.01489999983459711,295.6000061035156,3.1000001430511475,3.6000001430511475,0.0
+2015-12-24 17:00:00,0.0,397.6000061035156,354.1000061035156,100420.0,0.01529999915510416,295.1000061035156,4.099999904632568,3.4000000953674316,0.0
+2015-12-24 18:00:00,0.0,400.70001220703125,329.8000183105469,100330.0,0.015599999576807022,295.0,5.200000286102295,3.200000047683716,0.0
+2015-12-24 19:00:00,0.0,400.70001220703125,292.70001220703125,100360.0,0.01549999974668026,295.0,4.700000286102295,2.799999952316284,0.0
+2015-12-24 20:00:00,0.0,400.70001220703125,231.0,100360.0,0.01529999915510416,295.0,4.300000190734863,2.4000000953674316,0.0
+2015-12-24 21:00:00,0.0,403.8000183105469,93.20000457763672,100290.0,0.015199999324977398,295.20001220703125,3.799999952316284,2.0,0.0
+2015-12-24 22:00:00,0.0,403.8000183105469,20.80000114440918,100430.0,0.015699999406933784,294.8999938964844,2.4000000953674316,2.0,3.0511935942961847e-07
+2015-12-24 23:00:00,0.6000000238418579,403.8000183105469,0.0,100520.0,0.014999999664723873,294.5,1.0,2.0,7.599401290699011e-07
+2015-12-25 00:00:00,1.5,391.70001220703125,0.0,100450.0,0.014800000004470348,294.3999938964844,-0.4000000059604645,2.0,5.061538553138688e-08
+2015-12-25 01:00:00,0.10000000149011612,391.70001220703125,0.0,100600.0,0.013199999928474426,292.3999938964844,0.4000000059604645,1.899999976158142,0.0
+2015-12-25 02:00:00,0.0,391.70001220703125,0.0,100720.0,0.012600000016391277,291.8000183105469,1.2000000476837158,1.8000000715255737,0.0
+2015-12-25 03:00:00,0.0,379.20001220703125,0.0,100750.0,0.01269999984651804,291.8000183105469,2.0,1.7000000476837158,1.977323365029267e-07
+2015-12-25 04:00:00,0.4000000059604645,379.20001220703125,0.0,100800.0,0.01249999925494194,291.70001220703125,2.0,1.100000023841858,0.0
+2015-12-25 05:00:00,0.0,379.20001220703125,0.0,100790.0,0.012299999594688416,291.3000183105469,2.0,0.5,9.843137674574662e-08
+2015-12-25 06:00:00,0.20000000298023224,382.1000061035156,0.0,100810.0,0.01249999925494194,291.3999938964844,2.0,-0.10000000149011612,0.0
+2015-12-25 07:00:00,0.0,382.1000061035156,0.0,100770.0,0.012399999424815178,291.0,1.600000023841858,-0.30000001192092896,9.817343559310722e-08
+2015-12-25 08:00:00,0.20000000298023224,382.1000061035156,0.0,100770.0,0.01249999925494194,290.8000183105469,1.3000000715255737,-0.4000000059604645,0.0
+2015-12-25 09:00:00,0.0,386.20001220703125,0.0,100830.0,0.012199999764561653,290.8000183105469,0.9000000357627869,-0.6000000238418579,0.0
+2015-12-25 10:00:00,0.0,386.20001220703125,0.0,100760.0,0.011799999512732029,290.20001220703125,0.0,-0.30000001192092896,0.0
+2015-12-25 11:00:00,0.0,386.20001220703125,0.0,100790.0,0.011899999342858791,290.3999938964844,-0.9000000357627869,-0.10000000149011612,0.0
+2015-12-25 12:00:00,0.0,382.70001220703125,0.0,100870.0,0.01119999960064888,289.5,-1.7000000476837158,0.20000000298023224,0.0
+2015-12-25 13:00:00,0.0,382.70001220703125,55.29999923706055,100890.0,0.011799999512732029,289.6000061035156,-1.399999976158142,0.5,0.0
+2015-12-25 14:00:00,0.0,382.70001220703125,175.90000915527344,100880.0,0.012299999594688416,291.20001220703125,-1.100000023841858,0.800000011920929,0.0
+2015-12-25 15:00:00,0.0,391.3000183105469,320.20001220703125,100870.0,0.013399999588727951,293.0,-0.800000011920929,1.0,0.0
+2015-12-25 16:00:00,0.0,391.3000183105469,398.3000183105469,100910.0,0.013700000010430813,294.0,-0.30000001192092896,1.5,0.0
+2015-12-25 17:00:00,0.0,391.20001220703125,425.1000061035156,100780.0,0.014299999922513962,294.3000183105469,0.20000000298023224,2.1000001430511475,0.0
+2015-12-25 18:00:00,0.0,405.6000061035156,401.1000061035156,100700.0,0.01489999983459711,294.8999938964844,0.699999988079071,2.6000001430511475,0.0
+2015-12-25 19:00:00,0.0,405.6000061035156,356.20001220703125,100690.0,0.014800000004470348,296.20001220703125,1.100000023841858,2.5,0.0
+2015-12-25 20:00:00,0.0,405.6000061035156,281.6000061035156,100710.0,0.014999999664723873,296.3999938964844,1.600000023841858,2.4000000953674316,0.0
+2015-12-25 21:00:00,0.0,404.20001220703125,123.80000305175781,100660.0,0.015099999494850636,297.0,2.0,2.299999952316284,0.0
+2015-12-25 22:00:00,0.0,404.20001220703125,28.399999618530273,100720.0,0.015199999324977398,296.1000061035156,1.3000000715255737,2.0,0.0
+2015-12-25 23:00:00,0.0,404.20001220703125,0.0,100800.0,0.015399999916553497,295.1000061035156,0.699999988079071,1.8000000715255737,0.0
+2015-12-26 00:00:00,0.0,398.3000183105469,0.0,100870.0,0.014599999412894249,294.1000061035156,0.0,1.5,0.0
+2015-12-26 01:00:00,0.0,398.3000183105469,0.0,100890.0,0.013599999248981476,292.8999938964844,-0.4000000059604645,0.9000000357627869,7.488365405375216e-07
+2015-12-26 02:00:00,1.5,398.3000183105469,0.0,100970.0,0.013399999588727951,292.1000061035156,-0.9000000357627869,0.20000000298023224,0.0
+2015-12-26 03:00:00,0.0,397.8999938964844,0.0,100910.0,0.012899999506771564,291.70001220703125,-1.3000000715255737,-0.5,0.0
+2015-12-26 04:00:00,0.0,397.8999938964844,0.0,100900.0,0.01249999925494194,291.3000183105469,-1.2000000476837158,-0.6000000238418579,0.0
+2015-12-26 05:00:00,0.0,397.8999938964844,0.0,100910.0,0.011799999512732029,290.3000183105469,-1.0,-0.699999988079071,0.0
+2015-12-26 06:00:00,0.0,385.8999938964844,0.0,100880.0,0.012299999594688416,291.0,-0.800000011920929,-0.800000011920929,0.0
+2015-12-26 07:00:00,0.0,385.8999938964844,0.0,100940.0,0.011599999852478504,290.5,-1.3000000715255737,-0.6000000238418579,0.0
+2015-12-26 08:00:00,0.0,385.8999938964844,0.0,100930.0,0.011599999852478504,290.20001220703125,-1.7000000476837158,-0.5,0.0
+2015-12-26 09:00:00,0.0,379.5,0.0,100900.0,0.010799999348819256,289.3999938964844,-2.1000001430511475,-0.30000001192092896,0.0
+2015-12-26 10:00:00,0.0,379.5,0.0,100840.0,0.010799999348819256,289.1000061035156,-1.8000000715255737,-0.5,0.0
+2015-12-26 11:00:00,0.0,379.5,0.0,100760.0,0.011099999770522118,289.3999938964844,-1.5,-0.699999988079071,0.0
+2015-12-26 12:00:00,0.0,364.70001220703125,0.0,100780.0,0.01119999960064888,289.8000183105469,-1.2000000476837158,-0.9000000357627869,0.0
+2015-12-26 13:00:00,0.0,364.70001220703125,62.900001525878906,100880.0,0.010999999940395355,289.20001220703125,-1.3000000715255737,-0.800000011920929,0.0
+2015-12-26 14:00:00,0.0,364.70001220703125,202.40000915527344,100980.0,0.011699999682605267,290.8000183105469,-1.399999976158142,-0.800000011920929,0.0
+2015-12-26 15:00:00,0.0,376.6000061035156,354.8000183105469,101080.0,0.01269999984651804,292.5,-1.5,-0.699999988079071,0.0
+2015-12-26 16:00:00,0.0,376.6000061035156,442.0,101100.0,0.012999999336898327,294.0,-1.3000000715255737,0.20000000298023224,0.0
+2015-12-26 17:00:00,0.0,376.5,472.0,100970.0,0.013100000098347664,295.0,-1.100000023841858,1.0,0.0
+2015-12-26 18:00:00,0.0,386.6000061035156,470.6000061035156,100840.0,0.013399999588727951,296.0,-0.9000000357627869,1.899999976158142,0.0
+2015-12-26 19:00:00,0.0,386.6000061035156,418.3999938964844,100840.0,0.013599999248981476,297.3999938964844,-0.800000011920929,1.899999976158142,0.0
+2015-12-26 20:00:00,0.0,386.6000061035156,331.20001220703125,100780.0,0.013799999840557575,297.20001220703125,-0.800000011920929,1.8000000715255737,0.0
+2015-12-26 21:00:00,0.0,373.20001220703125,153.10000610351562,100780.0,0.013799999840557575,296.70001220703125,-0.699999988079071,1.8000000715255737,0.0
+2015-12-26 22:00:00,0.0,373.20001220703125,36.0,100790.0,0.013899999670684338,295.3000183105469,-1.3000000715255737,1.8000000715255737,0.0
+2015-12-26 23:00:00,0.0,373.20001220703125,0.0,100820.0,0.013899999670684338,293.8999938964844,-2.0,1.899999976158142,0.0
+2015-12-27 00:00:00,0.0,358.3999938964844,0.0,100880.0,0.013700000010430813,293.20001220703125,-2.6000001430511475,2.0,0.0
+2015-12-27 01:00:00,0.0,358.3999938964844,0.0,100850.0,0.013499999418854713,293.20001220703125,-2.6000001430511475,1.8000000715255737,0.0
+2015-12-27 02:00:00,0.0,358.3999938964844,0.0,100870.0,0.013299999758601189,292.5,-2.6000001430511475,1.600000023841858,0.0
+2015-12-27 03:00:00,0.0,351.20001220703125,0.0,100870.0,0.013599999248981476,292.1000061035156,-2.6000001430511475,1.5,0.0
+2015-12-27 04:00:00,0.0,351.20001220703125,0.0,100840.0,0.012999999336898327,291.70001220703125,-2.4000000953674316,1.600000023841858,0.0
+2015-12-27 05:00:00,0.0,351.20001220703125,0.0,100770.0,0.013399999588727951,292.3000183105469,-2.200000047683716,1.8000000715255737,0.0
+2015-12-27 06:00:00,0.0,359.8999938964844,0.0,100740.0,0.013399999588727951,292.20001220703125,-2.0,2.0,0.0
+2015-12-27 07:00:00,0.0,359.8999938964844,0.0,100680.0,0.013799999840557575,292.3999938964844,-1.899999976158142,1.8000000715255737,0.0
+2015-12-27 08:00:00,0.0,359.8999938964844,0.0,100750.0,0.013700000010430813,292.3000183105469,-1.8000000715255737,1.600000023841858,0.0
+2015-12-27 09:00:00,0.0,369.1000061035156,0.0,100630.0,0.013799999840557575,292.8000183105469,-1.600000023841858,1.399999976158142,0.0
+2015-12-27 10:00:00,0.0,369.1000061035156,0.0,100650.0,0.013799999840557575,292.5,-1.7000000476837158,1.399999976158142,0.0
+2015-12-27 11:00:00,0.0,369.1000061035156,0.0,100620.0,0.013700000010430813,292.70001220703125,-1.8000000715255737,1.399999976158142,0.0
+2015-12-27 12:00:00,0.0,366.3999938964844,0.0,100650.0,0.013499999418854713,292.3999938964844,-1.899999976158142,1.399999976158142,0.0
+2015-12-27 13:00:00,0.0,366.3999938964844,38.10000228881836,100620.0,0.012799999676644802,292.20001220703125,-1.3000000715255737,1.0,7.441386748887777e-07
+2015-12-27 14:00:00,1.5,366.3999938964844,123.9000015258789,100640.0,0.013199999928474426,292.20001220703125,-0.699999988079071,0.5,2.133197629303288e-06
+2015-12-27 15:00:00,4.300000190734863,391.1000061035156,208.8000030517578,100620.0,0.013399999588727951,292.20001220703125,-0.10000000149011612,0.0,0.0
+2015-12-27 16:00:00,0.0,391.0,260.20001220703125,100590.0,0.013599999248981476,293.1000061035156,0.20000000298023224,0.5,0.0
+2015-12-27 17:00:00,0.0,391.0,278.20001220703125,100480.0,0.0142000000923872,293.70001220703125,0.6000000238418579,1.0,0.0
+2015-12-27 18:00:00,0.0,394.5,305.3999938964844,100380.0,0.014299999922513962,294.20001220703125,1.0,1.5,0.0
+2015-12-27 19:00:00,0.0,394.5,271.8000183105469,100290.0,0.014699999243021011,295.5,1.0,1.600000023841858,0.0
+2015-12-27 20:00:00,0.0,394.3999938964844,215.5,100240.0,0.014499999582767487,295.8999938964844,1.100000023841858,1.7000000476837158,0.0
+2015-12-27 21:00:00,0.0,388.6000061035156,140.40000915527344,100200.0,0.014599999412894249,295.5,1.100000023841858,1.7000000476837158,0.0
+2015-12-27 22:00:00,0.0,388.6000061035156,33.900001525878906,100260.0,0.014599999412894249,294.8999938964844,0.4000000059604645,1.899999976158142,0.0
+2015-12-27 23:00:00,0.0,388.6000061035156,0.0,100270.0,0.014999999664723873,294.70001220703125,-0.30000001192092896,2.1000001430511475,0.0
+2015-12-28 00:00:00,0.0,373.20001220703125,0.0,100260.0,0.014499999582767487,293.6000061035156,-1.0,2.299999952316284,0.0
+2015-12-28 01:00:00,0.0,373.20001220703125,0.0,100310.0,0.013499999418854713,291.8999938964844,-1.2000000476837158,2.299999952316284,0.0
+2015-12-28 02:00:00,0.0,373.20001220703125,0.0,100320.0,0.012999999336898327,291.70001220703125,-1.399999976158142,2.200000047683716,0.0
+2015-12-28 03:00:00,0.0,338.8999938964844,0.0,100320.0,0.012899999506771564,291.3999938964844,-1.600000023841858,2.200000047683716,0.0
+2015-12-28 04:00:00,0.0,338.8999938964844,0.0,100370.0,0.012799999676644802,291.6000061035156,-1.7000000476837158,2.200000047683716,0.0
+2015-12-28 05:00:00,0.0,338.8999938964844,0.0,100340.0,0.012799999676644802,291.1000061035156,-1.8000000715255737,2.200000047683716,0.0
+2015-12-28 06:00:00,0.0,342.3000183105469,0.0,100290.0,0.013499999418854713,291.8999938964844,-1.899999976158142,2.200000047683716,0.0
+2015-12-28 07:00:00,0.0,342.3000183105469,0.0,100300.0,0.013399999588727951,291.8999938964844,-2.1000001430511475,1.7000000476837158,0.0
+2015-12-28 08:00:00,0.0,342.3000183105469,0.0,100340.0,0.013299999758601189,291.70001220703125,-2.4000000953674316,1.100000023841858,0.0
+2015-12-28 09:00:00,0.0,342.1000061035156,0.0,100280.0,0.013299999758601189,291.70001220703125,-2.700000047683716,0.6000000238418579,0.0
+2015-12-28 10:00:00,0.0,342.1000061035156,0.0,100280.0,0.012999999336898327,291.70001220703125,-2.700000047683716,0.5,0.0
+2015-12-28 11:00:00,0.0,342.1000061035156,0.0,100250.0,0.012899999506771564,291.5,-2.700000047683716,0.5,0.0
+2015-12-28 12:00:00,0.0,349.5,0.0,100320.0,0.012799999676644802,291.20001220703125,-2.700000047683716,0.5,0.0
+2015-12-28 13:00:00,0.0,349.5,51.5,100330.0,0.012899999506771564,291.70001220703125,-2.700000047683716,0.10000000149011612,0.0
+2015-12-28 14:00:00,0.0,349.5,169.0,100350.0,0.012899999506771564,291.6000061035156,-2.700000047683716,-0.20000000298023224,0.0
+2015-12-28 15:00:00,0.0,388.6000061035156,240.6999969482422,100330.0,0.013299999758601189,292.20001220703125,-2.700000047683716,-0.5,0.0
+2015-12-28 16:00:00,0.0,388.6000061035156,300.3999938964844,100370.0,0.0142000000923872,293.0,-3.4000000953674316,0.0,0.0
+2015-12-28 17:00:00,0.0,388.5,321.3999938964844,100250.0,0.014599999412894249,293.70001220703125,-4.099999904632568,0.5,0.0
+2015-12-28 18:00:00,0.0,413.5,234.5,100190.0,0.014699999243021011,294.6000061035156,-4.800000190734863,1.0,0.0
+2015-12-28 19:00:00,0.0,413.5,208.90000915527344,100100.0,0.014599999412894249,296.1000061035156,-5.200000286102295,1.100000023841858,0.0
+2015-12-28 20:00:00,0.0,413.5,165.8000030517578,99980.0,0.013799999840557575,296.6000061035156,-5.599999904632568,1.3000000715255737,0.0
+2015-12-28 21:00:00,0.0,390.0,130.5,99910.0,0.013700000010430813,295.8999938964844,-6.0,1.399999976158142,0.0
+2015-12-28 22:00:00,0.0,390.0,32.400001525878906,99950.0,0.0139999995008111,295.1000061035156,-6.400000095367432,1.8000000715255737,0.0
+2015-12-28 23:00:00,0.0,390.1000061035156,0.0,99940.0,0.014999999664723873,294.6000061035156,-6.900000095367432,2.200000047683716,0.0
+2015-12-29 00:00:00,0.0,380.1000061035156,0.0,99970.0,0.01489999983459711,294.6000061035156,-7.400000095367432,2.6000001430511475,0.0
+2015-12-29 01:00:00,0.0,380.1000061035156,0.0,99980.0,0.01549999974668026,295.1000061035156,-6.300000190734863,2.6000001430511475,0.0
+2015-12-29 02:00:00,0.0,380.1000061035156,0.0,99940.0,0.015799999237060547,295.3999938964844,-5.300000190734863,2.6000001430511475,0.0
+2015-12-29 03:00:00,0.0,388.70001220703125,0.0,99940.0,0.01529999915510416,295.1000061035156,-4.300000190734863,2.6000001430511475,2.0379742621031308e-07
+2015-12-29 04:00:00,0.4000000059604645,388.70001220703125,0.0,99940.0,0.015399999916553497,295.0,-3.299999952316284,3.200000047683716,5.090121965577734e-08
+2015-12-29 05:00:00,0.10000000149011612,388.70001220703125,0.0,99950.0,0.014999999664723873,294.70001220703125,-2.299999952316284,3.9000000953674316,1.1166688889383383e-06
+2015-12-29 06:00:00,2.200000047683716,398.3999938964844,0.0,99910.0,0.014800000004470348,294.20001220703125,-1.3000000715255737,4.5,1.1619883724544963e-06
+2015-12-29 07:00:00,2.299999952316284,398.3999938964844,0.0,99880.0,0.014999999664723873,294.8000183105469,-0.20000000298023224,4.900000095367432,2.591074675310334e-06
+2015-12-29 08:00:00,5.099999904632568,398.3999938964844,0.0,99870.0,0.014499999582767487,294.3999938964844,0.800000011920929,5.300000190734863,2.9863077501229664e-06
+2015-12-29 09:00:00,5.900000095367432,387.5,0.0,99900.0,0.014299999922513962,293.5,1.8000000715255737,5.700000286102295,7.529397965630518e-07
+2015-12-29 10:00:00,1.5,387.5,0.0,99920.0,0.0139999995008111,293.20001220703125,2.4000000953674316,5.0,5.506448621350923e-07
+2015-12-29 11:00:00,1.100000023841858,387.5,0.0,99960.0,0.014399999752640724,293.3000183105469,3.1000001430511475,4.400000095367432,0.0
+2015-12-29 12:00:00,0.0,381.5,0.0,99990.0,0.0139999995008111,293.3000183105469,3.700000047683716,3.799999952316284,0.0
+2015-12-29 13:00:00,0.0,381.5,35.5,100080.0,0.0139999995008111,293.1000061035156,3.5,3.6000001430511475,0.0
+2015-12-29 14:00:00,0.0,381.5,117.5999984741211,100180.0,0.0142000000923872,293.3000183105469,3.4000000953674316,3.5,0.0
+2015-12-29 15:00:00,0.0,373.70001220703125,246.90000915527344,100210.0,0.014800000004470348,294.8000183105469,3.200000047683716,3.4000000953674316,0.0
+2015-12-29 16:00:00,0.0,373.70001220703125,308.3999938964844,100230.0,0.014099999330937862,294.5,3.4000000953674316,3.5,0.0
+2015-12-29 17:00:00,0.0,373.70001220703125,330.20001220703125,100220.0,0.013700000010430813,294.3999938964844,3.6000001430511475,3.6000001430511475,0.0
+2015-12-29 18:00:00,0.0,375.20001220703125,375.70001220703125,100160.0,0.013299999758601189,294.8000183105469,3.700000047683716,3.700000047683716,0.0
+2015-12-29 19:00:00,0.0,375.20001220703125,335.1000061035156,100100.0,0.013599999248981476,296.8999938964844,3.299999952316284,3.4000000953674316,0.0
+2015-12-29 20:00:00,0.0,375.20001220703125,266.5,100140.0,0.013599999248981476,296.8999938964844,2.9000000953674316,3.1000001430511475,0.0
+2015-12-29 21:00:00,0.0,365.6000061035156,145.5,100170.0,0.013399999588727951,296.3999938964844,2.5,2.799999952316284,0.0
+2015-12-29 22:00:00,0.0,365.6000061035156,37.0,100250.0,0.01249999925494194,295.3000183105469,2.200000047683716,2.4000000953674316,0.0
+2015-12-29 23:00:00,0.0,365.6000061035156,0.0,100310.0,0.013299999758601189,293.70001220703125,1.899999976158142,2.0,0.0
+2015-12-30 00:00:00,0.0,337.70001220703125,0.0,100400.0,0.013299999758601189,292.70001220703125,1.600000023841858,1.600000023841858,0.0
+2015-12-30 01:00:00,0.0,337.70001220703125,0.0,100430.0,0.013199999928474426,292.6000061035156,1.2000000476837158,1.5,0.0
+2015-12-30 02:00:00,0.0,337.70001220703125,0.0,100530.0,0.012899999506771564,291.70001220703125,0.800000011920929,1.399999976158142,0.0
+2015-12-30 03:00:00,0.0,336.8999938964844,0.0,100520.0,0.01269999984651804,291.20001220703125,0.4000000059604645,1.2000000476837158,0.0
+2015-12-30 04:00:00,0.0,336.8999938964844,0.0,100570.0,0.012399999424815178,290.8999938964844,0.20000000298023224,1.3000000715255737,0.0
+2015-12-30 05:00:00,0.0,336.8999938964844,0.0,100590.0,0.011599999852478504,289.8999938964844,0.0,1.3000000715255737,0.0
+2015-12-30 06:00:00,0.0,353.0,0.0,100620.0,0.012000000104308128,290.1000061035156,-0.20000000298023224,1.3000000715255737,0.0
+2015-12-30 07:00:00,0.0,353.0,0.0,100610.0,0.011899999342858791,290.5,-0.6000000238418579,0.800000011920929,0.0
+2015-12-30 08:00:00,0.0,353.0,0.0,100590.0,0.012000000104308128,290.3999938964844,-1.0,0.20000000298023224,0.0
+2015-12-30 09:00:00,0.0,392.3999938964844,0.0,100630.0,0.011899999342858791,290.3999938964844,-1.399999976158142,-0.4000000059604645,3.418243187032877e-07
+2015-12-30 10:00:00,0.699999988079071,392.3999938964844,0.0,100590.0,0.012399999424815178,290.6000061035156,-1.3000000715255737,-0.20000000298023224,6.848304672955347e-07
+2015-12-30 11:00:00,1.399999976158142,392.3999938964844,0.0,100560.0,0.01249999925494194,291.1000061035156,-1.3000000715255737,0.0,0.0
+2015-12-30 12:00:00,0.0,396.8000183105469,0.0,100510.0,0.01269999984651804,291.3000183105469,-1.3000000715255737,0.20000000298023224,0.0
+2015-12-30 13:00:00,0.0,396.8000183105469,24.600000381469727,100620.0,0.012600000016391277,291.70001220703125,-0.699999988079071,0.20000000298023224,0.0
+2015-12-30 14:00:00,0.0,396.8000183105469,82.0999984741211,100630.0,0.013399999588727951,292.5,-0.20000000298023224,0.10000000149011612,4.9742695856783285e-08
+2015-12-30 15:00:00,0.10000000149011612,400.3000183105469,134.60000610351562,100600.0,0.014099999330937862,293.5,0.30000001192092896,0.0,4.2164631479768285e-06
+2015-12-30 16:00:00,8.40000057220459,400.3000183105469,168.3000030517578,100640.0,0.0139999995008111,292.3999938964844,0.5,0.6000000238418579,1.7294931218208543e-05
+2015-12-30 17:00:00,34.79999923706055,400.3000183105469,180.3000030517578,100590.0,0.012999999336898327,291.5,0.699999988079071,1.3000000715255737,3.599065574767947e-06
+2015-12-30 18:00:00,7.300000190734863,402.20001220703125,183.3000030517578,100610.0,0.012600000016391277,290.8999938964844,0.800000011920929,2.0,2.305066719490677e-06
+2015-12-30 19:00:00,4.700000286102295,402.20001220703125,163.60000610351562,100560.0,0.01249999925494194,291.0,0.800000011920929,1.899999976158142,1.816208554815238e-06
+2015-12-30 20:00:00,3.700000047683716,402.20001220703125,130.3000030517578,100490.0,0.012799999676644802,291.0,0.800000011920929,1.8000000715255737,2.061642257172614e-06
+2015-12-30 21:00:00,4.200000286102295,399.20001220703125,80.4000015258789,100470.0,0.012600000016391277,291.1000061035156,0.800000011920929,1.7000000476837158,4.07775568914086e-06
+2015-12-30 22:00:00,8.300000190734863,399.20001220703125,21.0,100450.0,0.012600000016391277,290.8999938964844,1.0,1.399999976158142,1.6184509790133084e-06
+2015-12-30 23:00:00,3.299999952316284,399.20001220703125,0.0,100520.0,0.01269999984651804,291.1000061035156,1.2000000476837158,1.2000000476837158,6.878141851067213e-07
diff --git a/python/runCalibValid/ngen_cal/tests/data/cat-88_2015-12-01 00_00_00_2015-12-30 23_00_00.csv b/python/runCalibValid/ngen_cal/tests/data/cat-88_2015-12-01 00_00_00_2015-12-30 23_00_00.csv
new file mode 100644
index 00000000..7ce270c7
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/cat-88_2015-12-01 00_00_00_2015-12-30 23_00_00.csv
@@ -0,0 +1,721 @@
+time,APCP_surface,DLWRF_surface,DSWRF_surface,PRES_surface,SPFH_2maboveground,TMP_2maboveground,UGRD_10maboveground,VGRD_10maboveground,precip_rate
+2015-12-01 00:00:00,0.0,361.20001220703125,0.0,100530.0,0.010499999858438969,287.5,-2.6000001430511475,0.0,0.0
+2015-12-01 01:00:00,0.0,361.20001220703125,0.0,100610.0,0.009800000116229057,287.3000183105469,-2.700000047683716,-0.30000001192092896,0.0
+2015-12-01 02:00:00,0.0,361.20001220703125,0.0,100600.0,0.009099999442696571,286.6000061035156,-2.799999952316284,-0.6000000238418579,0.0
+2015-12-01 03:00:00,0.0,357.6000061035156,0.0,100570.0,0.008700000122189522,285.5,-2.9000000953674316,-0.9000000357627869,0.0
+2015-12-01 04:00:00,0.0,357.6000061035156,0.0,100590.0,0.00839999970048666,284.3000183105469,-2.6000001430511475,-0.30000001192092896,0.0
+2015-12-01 05:00:00,0.0,357.6000061035156,0.0,100540.0,0.007999999448657036,283.8999938964844,-2.299999952316284,0.4000000059604645,0.0
+2015-12-01 06:00:00,0.0,344.1000061035156,0.0,100510.0,0.007699999958276749,283.6000061035156,-2.0,1.0,0.0
+2015-12-01 07:00:00,0.0,344.1000061035156,0.0,100490.0,0.007400000002235174,283.20001220703125,-2.1000001430511475,0.699999988079071,0.0
+2015-12-01 08:00:00,0.0,344.1000061035156,0.0,100550.0,0.007199999876320362,282.8999938964844,-2.200000047683716,0.5,0.0
+2015-12-01 09:00:00,0.0,335.0,0.0,100460.0,0.00699999975040555,282.5,-2.299999952316284,0.20000000298023224,0.0
+2015-12-01 10:00:00,0.0,335.0,0.0,100470.0,0.00699999975040555,282.3000183105469,-2.4000000953674316,0.6000000238418579,0.0
+2015-12-01 11:00:00,0.0,335.0,0.0,100480.0,0.0071000000461936,282.3000183105469,-2.4000000953674316,0.9000000357627869,0.0
+2015-12-01 12:00:00,0.0,350.3999938964844,0.0,100530.0,0.00699999975040555,282.0,-2.4000000953674316,1.3000000715255737,0.0
+2015-12-01 13:00:00,0.0,350.3999938964844,85.0999984741211,100560.0,0.00699999975040555,281.8999938964844,-2.6000001430511475,1.2000000476837158,0.0
+2015-12-01 14:00:00,0.0,350.3000183105469,195.40000915527344,100610.0,0.006899999920278788,282.5,-2.700000047683716,1.100000023841858,0.0
+2015-12-01 15:00:00,0.0,397.0,220.0,100600.0,0.00699999975040555,282.3999938964844,-2.9000000953674316,1.0,0.0
+2015-12-01 16:00:00,0.0,397.0,264.70001220703125,100520.0,0.007199999876320362,282.8000183105469,-2.200000047683716,1.7000000476837158,0.0
+2015-12-01 17:00:00,0.0,397.0,276.5,100510.0,0.007499999832361937,283.1000061035156,-1.5,2.299999952316284,0.0
+2015-12-01 18:00:00,0.0,385.3999938964844,395.20001220703125,100400.0,0.007699999958276749,283.5,-0.800000011920929,3.0,0.0
+2015-12-01 19:00:00,0.0,385.3999938964844,345.6000061035156,100340.0,0.008100000210106373,284.3999938964844,-0.800000011920929,2.9000000953674316,0.0
+2015-12-01 20:00:00,0.0,385.3999938964844,268.20001220703125,100310.0,0.008200000040233135,284.70001220703125,-0.9000000357627869,2.799999952316284,0.0
+2015-12-01 21:00:00,0.0,394.3000183105469,120.5999984741211,100160.0,0.008200000040233135,284.3999938964844,-0.9000000357627869,2.700000047683716,0.0
+2015-12-01 22:00:00,0.0,394.3000183105469,21.0,100200.0,0.00839999970048666,285.1000061035156,-1.3000000715255737,2.299999952316284,0.0
+2015-12-01 23:00:00,0.0,394.3000183105469,0.0,100240.0,0.008599999360740185,285.1000061035156,-1.7000000476837158,1.8000000715255737,0.0
+2015-12-02 00:00:00,0.0,383.3000183105469,0.0,100190.0,0.008599999360740185,285.20001220703125,-2.1000001430511475,1.399999976158142,0.0
+2015-12-02 01:00:00,0.0,383.3000183105469,0.0,100240.0,0.008799999952316284,285.3000183105469,-2.0,1.3000000715255737,0.0
+2015-12-02 02:00:00,0.0,383.3000183105469,0.0,100210.0,0.008799999952316284,285.6000061035156,-2.0,1.100000023841858,0.0
+2015-12-02 03:00:00,0.0,371.3999938964844,0.0,100120.0,0.008899999782443047,285.70001220703125,-2.0,1.0,0.0
+2015-12-02 04:00:00,0.0,371.3999938964844,0.0,100070.0,0.009200000204145908,285.8000183105469,-1.8000000715255737,1.600000023841858,0.0
+2015-12-02 05:00:00,0.0,371.3999938964844,0.0,100010.0,0.008899999782443047,285.70001220703125,-1.7000000476837158,2.1000001430511475,0.0
+2015-12-02 06:00:00,0.0,369.1000061035156,0.0,99970.0,0.009099999442696571,285.8999938964844,-1.600000023841858,2.700000047683716,0.0
+2015-12-02 07:00:00,0.0,369.20001220703125,0.0,99880.0,0.009399999864399433,286.1000061035156,-1.600000023841858,3.0,0.0
+2015-12-02 08:00:00,0.0,369.20001220703125,0.0,99870.0,0.009800000116229057,287.0,-1.7000000476837158,3.4000000953674316,9.493307095661946e-08
+2015-12-02 09:00:00,0.20000000298023224,370.6000061035156,0.0,99740.0,0.00969999935477972,286.70001220703125,-1.7000000476837158,3.799999952316284,0.0
+2015-12-02 10:00:00,0.0,370.6000061035156,0.0,99720.0,0.010499999858438969,288.0,-1.600000023841858,3.700000047683716,0.0
+2015-12-02 11:00:00,0.0,370.6000061035156,0.0,99710.0,0.010999999940395355,288.6000061035156,-1.5,3.6000001430511475,0.0
+2015-12-02 12:00:00,0.0,380.8999938964844,0.0,99710.0,0.01119999960064888,289.3999938964844,-1.399999976158142,3.4000000953674316,0.0
+2015-12-02 13:00:00,0.0,380.8999938964844,72.5,99740.0,0.011699999682605267,289.70001220703125,-0.699999988079071,3.4000000953674316,0.0
+2015-12-02 14:00:00,0.0,380.8000183105469,168.60000610351562,99710.0,0.01209999993443489,290.3000183105469,0.0,3.299999952316284,2.439501431328691e-07
+2015-12-02 15:00:00,0.5,405.1000061035156,130.8000030517578,99850.0,0.012000000104308128,290.3000183105469,0.699999988079071,3.299999952316284,3.9032023482881514e-07
+2015-12-02 16:00:00,0.800000011920929,405.1000061035156,157.5,99840.0,0.011699999682605267,289.8000183105469,1.3000000715255737,3.4000000953674316,9.716329458139992e-08
+2015-12-02 17:00:00,0.20000000298023224,405.1000061035156,164.6999969482422,99710.0,0.011799999512732029,290.1000061035156,1.899999976158142,3.5,0.0
+2015-12-02 18:00:00,0.0,397.5,145.10000610351562,99550.0,0.011699999682605267,290.3999938964844,2.5,3.6000001430511475,0.0
+2015-12-02 19:00:00,0.0,397.5,126.9000015258789,99520.0,0.011399999260902405,290.20001220703125,3.299999952316284,3.5,0.0
+2015-12-02 20:00:00,0.0,397.5,98.5,99400.0,0.011699999682605267,290.0,4.099999904632568,3.5,0.0
+2015-12-02 21:00:00,0.0,376.20001220703125,67.70000457763672,99390.0,0.01209999993443489,290.3999938964844,4.900000095367432,3.4000000953674316,0.0
+2015-12-02 22:00:00,0.0,376.20001220703125,11.699999809265137,99410.0,0.01119999960064888,289.8999938964844,5.0,3.9000000953674316,0.0
+2015-12-02 23:00:00,0.0,376.20001220703125,0.0,99530.0,0.008799999952316284,289.0,5.0,4.5,0.0
+2015-12-03 00:00:00,0.0,350.8000183105469,0.0,99570.0,0.0072999997064471245,287.3000183105469,5.099999904632568,5.099999904632568,0.0
+2015-12-03 01:00:00,0.0,350.8000183105469,0.0,99600.0,0.0066999997943639755,286.20001220703125,4.900000095367432,4.400000095367432,0.0
+2015-12-03 02:00:00,0.0,350.8999938964844,0.0,99680.0,0.0064999996684491634,285.8000183105469,4.800000190734863,3.799999952316284,0.0
+2015-12-03 03:00:00,0.0,296.70001220703125,0.0,99700.0,0.006199999712407589,284.8999938964844,4.599999904632568,3.1000001430511475,0.0
+2015-12-03 04:00:00,0.0,296.70001220703125,0.0,99740.0,0.006000000052154064,284.3000183105469,4.5,2.200000047683716,0.0
+2015-12-03 05:00:00,0.0,296.70001220703125,0.0,99850.0,0.006000000052154064,283.3999938964844,4.400000095367432,1.399999976158142,0.0
+2015-12-03 06:00:00,0.0,279.3999938964844,0.0,99880.0,0.0058999997563660145,282.8000183105469,4.200000286102295,0.5,0.0
+2015-12-03 07:00:00,0.0,279.3999938964844,0.0,99930.0,0.0058999997563660145,282.20001220703125,3.700000047683716,-0.20000000298023224,0.0
+2015-12-03 08:00:00,0.0,279.3999938964844,0.0,100020.0,0.005799999926239252,281.6000061035156,3.299999952316284,-0.9000000357627869,0.0
+2015-12-03 09:00:00,0.0,257.1000061035156,0.0,100040.0,0.005799999926239252,281.0,2.799999952316284,-1.600000023841858,0.0
+2015-12-03 10:00:00,0.0,257.1000061035156,0.0,100130.0,0.005699999630451202,280.6000061035156,2.200000047683716,-2.1000001430511475,0.0
+2015-12-03 11:00:00,0.0,257.1000061035156,0.0,100240.0,0.005499999970197678,280.5,1.600000023841858,-2.6000001430511475,0.0
+2015-12-03 12:00:00,0.0,254.0,0.0,100340.0,0.004999999888241291,279.70001220703125,1.0,-3.1000001430511475,0.0
+2015-12-03 13:00:00,0.0,254.0,111.5999984741211,100460.0,0.004799999762326479,279.70001220703125,0.20000000298023224,-3.9000000953674316,0.0
+2015-12-03 14:00:00,0.0,254.0,263.1000061035156,100550.0,0.00419999985024333,281.20001220703125,-0.6000000238418579,-4.800000190734863,0.0
+2015-12-03 15:00:00,0.0,268.0,390.6000061035156,100680.0,0.003599999938160181,282.3999938964844,-1.399999976158142,-5.599999904632568,0.0
+2015-12-03 16:00:00,0.0,268.0,471.3000183105469,100720.0,0.003499999875202775,283.1000061035156,-1.7000000476837158,-5.200000286102295,0.0
+2015-12-03 17:00:00,0.0,268.0,493.3000183105469,100690.0,0.003599999938160181,283.5,-2.0,-4.900000095367432,0.0
+2015-12-03 18:00:00,0.0,270.8999938964844,491.8999938964844,100700.0,0.003499999875202775,283.6000061035156,-2.299999952316284,-4.5,0.0
+2015-12-03 19:00:00,0.0,270.8999938964844,430.6000061035156,100660.0,0.003700000001117587,283.8000183105469,-1.899999976158142,-4.300000190734863,0.0
+2015-12-03 20:00:00,0.0,270.8999938964844,334.1000061035156,100750.0,0.003599999938160181,283.8999938964844,-1.600000023841858,-4.099999904632568,0.0
+2015-12-03 21:00:00,0.0,255.8000030517578,180.6999969482422,100750.0,0.0037999998312443495,283.3000183105469,-1.3000000715255737,-3.9000000953674316,0.0
+2015-12-03 22:00:00,0.0,255.8000030517578,30.899999618530273,100870.0,0.003999999724328518,282.1000061035156,-1.399999976158142,-3.700000047683716,0.0
+2015-12-03 23:00:00,0.0,255.8000030517578,0.0,100930.0,0.004299999680370092,280.3000183105469,-1.5,-3.4000000953674316,0.0
+2015-12-04 00:00:00,0.0,236.6999969482422,0.0,101010.0,0.00419999985024333,280.3000183105469,-1.5,-3.1000001430511475,0.0
+2015-12-04 01:00:00,0.0,236.6999969482422,0.0,101130.0,0.004299999680370092,279.6000061035156,-1.7000000476837158,-3.1000001430511475,0.0
+2015-12-04 02:00:00,0.0,236.6999969482422,0.0,101170.0,0.00419999985024333,278.70001220703125,-1.8000000715255737,-3.0,0.0
+2015-12-04 03:00:00,0.0,229.5,0.0,101260.0,0.004299999680370092,278.3000183105469,-1.899999976158142,-2.9000000953674316,0.0
+2015-12-04 04:00:00,0.0,229.5,0.0,101300.0,0.00419999985024333,277.6000061035156,-2.0,-2.9000000953674316,0.0
+2015-12-04 05:00:00,0.0,229.5,0.0,101270.0,0.003999999724328518,277.5,-2.0,-2.799999952316284,0.0
+2015-12-04 06:00:00,0.0,222.5,0.0,101270.0,0.003700000001117587,277.70001220703125,-2.0,-2.799999952316284,0.0
+2015-12-04 07:00:00,0.0,222.5,0.0,101400.0,0.0037999998312443495,277.3999938964844,-1.600000023841858,-2.9000000953674316,0.0
+2015-12-04 08:00:00,0.0,222.5,0.0,101460.0,0.003700000001117587,276.3999938964844,-1.2000000476837158,-3.1000001430511475,0.0
+2015-12-04 09:00:00,0.0,217.0,0.0,101450.0,0.003599999938160181,275.3999938964844,-0.800000011920929,-3.200000047683716,0.0
+2015-12-04 10:00:00,0.0,217.0,0.0,101510.0,0.003399999812245369,274.8000183105469,-0.9000000357627869,-3.1000001430511475,0.0
+2015-12-04 11:00:00,0.0,217.0,0.0,101540.0,0.003399999812245369,274.3000183105469,-1.100000023841858,-3.0,0.0
+2015-12-04 12:00:00,0.0,220.3000030517578,0.0,101610.0,0.0032999999821186066,273.6000061035156,-1.3000000715255737,-2.9000000953674316,0.0
+2015-12-04 13:00:00,0.0,220.1999969482422,111.0,101730.0,0.003499999875202775,274.1000061035156,-1.5,-3.200000047683716,0.0
+2015-12-04 14:00:00,0.0,220.1999969482422,265.0,101770.0,0.003700000001117587,276.8999938964844,-1.600000023841858,-3.4000000953674316,0.0
+2015-12-04 15:00:00,0.0,239.60000610351562,424.20001220703125,101810.0,0.003499999875202775,279.5,-1.8000000715255737,-3.700000047683716,0.0
+2015-12-04 16:00:00,0.0,239.60000610351562,512.7000122070312,101760.0,0.003399999812245369,281.8999938964844,-2.4000000953674316,-3.799999952316284,0.0
+2015-12-04 17:00:00,0.0,239.60000610351562,537.1000366210938,101720.0,0.0032999999821186066,283.70001220703125,-3.0,-3.799999952316284,0.0
+2015-12-04 18:00:00,0.0,248.0,520.2999877929688,101680.0,0.0032999999821186066,284.70001220703125,-3.6000001430511475,-3.9000000953674316,0.0
+2015-12-04 19:00:00,0.0,248.0,455.6000061035156,101630.0,0.0031999999191612005,285.5,-3.4000000953674316,-3.700000047683716,0.0
+2015-12-04 20:00:00,0.0,248.10000610351562,353.6000061035156,101600.0,0.0031999999191612005,285.3000183105469,-3.200000047683716,-3.5,0.0
+2015-12-04 21:00:00,0.0,238.3000030517578,155.40000915527344,101600.0,0.0031999999191612005,285.5,-3.0,-3.299999952316284,0.0
+2015-12-04 22:00:00,0.0,238.3000030517578,26.399999618530273,101680.0,0.0032999999821186066,284.1000061035156,-2.1000001430511475,-3.4000000953674316,0.0
+2015-12-04 23:00:00,0.0,238.3000030517578,0.0,101620.0,0.003700000001117587,280.3000183105469,-1.3000000715255737,-3.5,0.0
+2015-12-05 00:00:00,0.0,226.3000030517578,0.0,101720.0,0.0037999998312443495,279.0,-0.4000000059604645,-3.6000001430511475,0.0
+2015-12-05 01:00:00,0.0,226.3000030517578,0.0,101740.0,0.003700000001117587,277.0,-0.699999988079071,-3.4000000953674316,0.0
+2015-12-05 02:00:00,0.0,226.3000030517578,0.0,101830.0,0.003700000001117587,277.0,-1.100000023841858,-3.200000047683716,0.0
+2015-12-05 03:00:00,0.0,222.60000610351562,0.0,101890.0,0.003700000001117587,276.6000061035156,-1.399999976158142,-3.0,0.0
+2015-12-05 04:00:00,0.0,222.60000610351562,0.0,101860.0,0.003599999938160181,276.0,-1.399999976158142,-3.0,0.0
+2015-12-05 05:00:00,0.0,222.60000610351562,0.0,101850.0,0.003599999938160181,274.20001220703125,-1.3000000715255737,-3.0,0.0
+2015-12-05 06:00:00,0.0,220.8000030517578,0.0,101800.0,0.003499999875202775,273.8999938964844,-1.3000000715255737,-3.0,0.0
+2015-12-05 07:00:00,0.0,220.8000030517578,0.0,101920.0,0.003499999875202775,273.8000183105469,-1.3000000715255737,-3.0,0.0
+2015-12-05 08:00:00,0.0,220.8000030517578,0.0,101980.0,0.0032999999821186066,272.3999938964844,-1.2000000476837158,-3.1000001430511475,0.0
+2015-12-05 09:00:00,0.0,221.60000610351562,0.0,101960.0,0.0032999999821186066,272.6000061035156,-1.2000000476837158,-3.1000001430511475,0.0
+2015-12-05 10:00:00,0.0,221.60000610351562,0.0,102000.0,0.0031999999191612005,272.6000061035156,-1.3000000715255737,-3.0,0.0
+2015-12-05 11:00:00,0.0,221.60000610351562,0.0,102040.0,0.0032999999821186066,273.3999938964844,-1.399999976158142,-2.9000000953674316,0.0
+2015-12-05 12:00:00,0.0,227.8000030517578,0.0,102080.0,0.0032999999821186066,272.8000183105469,-1.5,-2.799999952316284,0.0
+2015-12-05 13:00:00,0.0,227.8000030517578,106.9000015258789,102150.0,0.003599999938160181,273.70001220703125,-1.7000000476837158,-3.200000047683716,0.0
+2015-12-05 14:00:00,0.0,227.8000030517578,258.8000183105469,102200.0,0.003599999938160181,277.1000061035156,-1.899999976158142,-3.6000001430511475,0.0
+2015-12-05 15:00:00,0.0,253.8000030517578,414.5,102230.0,0.003599999938160181,279.8999938964844,-2.1000001430511475,-3.9000000953674316,0.0
+2015-12-05 16:00:00,0.0,253.8000030517578,501.8000183105469,102180.0,0.003499999875202775,282.70001220703125,-2.5,-3.9000000953674316,0.0
+2015-12-05 17:00:00,0.0,253.8000030517578,526.1000366210938,102070.0,0.003399999812245369,284.20001220703125,-2.9000000953674316,-3.9000000953674316,0.0
+2015-12-05 18:00:00,0.0,269.0,507.20001220703125,101960.0,0.003399999812245369,285.5,-3.299999952316284,-3.799999952316284,0.0
+2015-12-05 19:00:00,0.0,269.0,444.3000183105469,101880.0,0.003499999875202775,286.70001220703125,-3.0,-3.700000047683716,0.0
+2015-12-05 20:00:00,0.0,269.0,344.8999938964844,101860.0,0.003599999938160181,287.20001220703125,-2.6000001430511475,-3.6000001430511475,0.0
+2015-12-05 21:00:00,0.0,261.20001220703125,149.0,101890.0,0.003499999875202775,286.3999938964844,-2.299999952316284,-3.5,0.0
+2015-12-05 22:00:00,0.0,261.3000183105469,25.200000762939453,101950.0,0.003700000001117587,285.20001220703125,-2.200000047683716,-3.299999952316284,0.0
+2015-12-05 23:00:00,0.0,261.3000183105469,0.0,101960.0,0.003999999724328518,282.3999938964844,-2.200000047683716,-3.1000001430511475,0.0
+2015-12-06 00:00:00,0.0,250.1999969482422,0.0,101960.0,0.0037999998312443495,281.0,-2.200000047683716,-2.9000000953674316,0.0
+2015-12-06 01:00:00,0.0,250.1999969482422,0.0,102030.0,0.0037999998312443495,280.5,-2.200000047683716,-2.9000000953674316,0.0
+2015-12-06 02:00:00,0.0,250.1999969482422,0.0,102060.0,0.0038999998942017555,279.8000183105469,-2.200000047683716,-3.0,0.0
+2015-12-06 03:00:00,0.0,251.1999969482422,0.0,102000.0,0.0038999998942017555,278.8000183105469,-2.200000047683716,-3.0,0.0
+2015-12-06 04:00:00,0.0,251.1999969482422,0.0,102010.0,0.0037999998312443495,277.3000183105469,-2.200000047683716,-2.799999952316284,0.0
+2015-12-06 05:00:00,0.0,251.1999969482422,0.0,102030.0,0.0037999998312443495,277.3999938964844,-2.200000047683716,-2.700000047683716,0.0
+2015-12-06 06:00:00,0.0,267.70001220703125,0.0,101930.0,0.0038999998942017555,277.5,-2.200000047683716,-2.6000001430511475,0.0
+2015-12-06 07:00:00,0.0,267.70001220703125,0.0,101950.0,0.0037999998312443495,277.20001220703125,-2.0,-2.700000047683716,0.0
+2015-12-06 08:00:00,0.0,267.70001220703125,0.0,101890.0,0.0038999998942017555,276.8000183105469,-1.8000000715255737,-2.799999952316284,0.0
+2015-12-06 09:00:00,0.0,296.3999938964844,0.0,101850.0,0.0038999998942017555,276.3999938964844,-1.600000023841858,-2.799999952316284,0.0
+2015-12-06 10:00:00,0.0,296.3999938964844,0.0,101860.0,0.0037999998312443495,275.70001220703125,-1.5,-2.6000001430511475,0.0
+2015-12-06 11:00:00,0.0,296.3999938964844,0.0,101860.0,0.0037999998312443495,274.8000183105469,-1.5,-2.4000000953674316,0.0
+2015-12-06 12:00:00,0.0,272.8999938964844,0.0,101870.0,0.003700000001117587,274.8000183105469,-1.5,-2.200000047683716,0.0
+2015-12-06 13:00:00,0.0,272.8999938964844,102.20000457763672,101920.0,0.0038999998942017555,275.3000183105469,-1.600000023841858,-2.4000000953674316,0.0
+2015-12-06 14:00:00,0.0,272.8000183105469,250.90000915527344,101900.0,0.00419999985024333,278.8000183105469,-1.600000023841858,-2.5,0.0
+2015-12-06 15:00:00,0.0,279.3000183105469,403.0,101840.0,0.004399999976158142,282.0,-1.7000000476837158,-2.6000001430511475,0.0
+2015-12-06 16:00:00,0.0,279.3000183105469,488.5,101810.0,0.004100000020116568,284.3000183105469,-1.8000000715255737,-2.200000047683716,0.0
+2015-12-06 17:00:00,0.0,279.3000183105469,512.6000366210938,101680.0,0.003999999724328518,285.8999938964844,-2.0,-1.7000000476837158,0.0
+2015-12-06 18:00:00,0.0,296.8999938964844,495.6000061035156,101510.0,0.003700000001117587,287.8999938964844,-2.200000047683716,-1.3000000715255737,0.0
+2015-12-06 19:00:00,0.0,296.8999938964844,434.3000183105469,101380.0,0.00419999985024333,289.3000183105469,-2.0,-1.2000000476837158,0.0
+2015-12-06 20:00:00,0.0,296.8999938964844,337.20001220703125,101250.0,0.0044999998062849045,290.1000061035156,-1.8000000715255737,-1.2000000476837158,0.0
+2015-12-06 21:00:00,0.0,288.20001220703125,152.1999969482422,101200.0,0.004799999762326479,290.0,-1.600000023841858,-1.100000023841858,0.0
+2015-12-06 22:00:00,0.0,288.20001220703125,25.700000762939453,101200.0,0.005399999674409628,287.5,-1.5,-0.800000011920929,0.0
+2015-12-06 23:00:00,0.0,288.20001220703125,0.0,101190.0,0.005499999970197678,282.70001220703125,-1.5,-0.4000000059604645,0.0
+2015-12-07 00:00:00,0.0,278.1000061035156,0.0,101200.0,0.00559999980032444,282.1000061035156,-1.5,-0.10000000149011612,0.0
+2015-12-07 01:00:00,0.0,278.1000061035156,0.0,101250.0,0.00559999980032444,281.3000183105469,-1.3000000715255737,-0.30000001192092896,0.0
+2015-12-07 02:00:00,0.0,278.1000061035156,0.0,101220.0,0.0052999998442828655,279.5,-1.0,-0.6000000238418579,0.0
+2015-12-07 03:00:00,0.0,277.20001220703125,0.0,101170.0,0.0050999997183680534,279.20001220703125,-0.800000011920929,-0.9000000357627869,0.0
+2015-12-07 04:00:00,0.0,277.20001220703125,0.0,101120.0,0.004799999762326479,277.6000061035156,-0.5,-1.399999976158142,0.0
+2015-12-07 05:00:00,0.0,277.20001220703125,0.0,101090.0,0.004999999888241291,277.8000183105469,-0.10000000149011612,-1.899999976158142,0.0
+2015-12-07 06:00:00,0.0,272.1000061035156,0.0,101050.0,0.004799999762326479,277.20001220703125,0.20000000298023224,-2.4000000953674316,0.0
+2015-12-07 07:00:00,0.0,272.1000061035156,0.0,101020.0,0.004600000102072954,276.8000183105469,0.10000000149011612,-2.4000000953674316,0.0
+2015-12-07 08:00:00,0.0,272.1000061035156,0.0,100930.0,0.0044999998062849045,276.0,0.0,-2.299999952316284,0.0
+2015-12-07 09:00:00,0.0,277.3000183105469,0.0,100860.0,0.0044999998062849045,275.8000183105469,-0.10000000149011612,-2.299999952316284,0.0
+2015-12-07 10:00:00,0.0,277.3000183105469,0.0,100800.0,0.0044999998062849045,275.5,0.20000000298023224,-2.200000047683716,0.0
+2015-12-07 11:00:00,0.0,277.3000183105469,0.0,100820.0,0.0044999998062849045,275.70001220703125,0.4000000059604645,-2.1000001430511475,0.0
+2015-12-07 12:00:00,0.0,319.0,0.0,100820.0,0.004399999976158142,275.3999938964844,0.699999988079071,-2.0,0.0
+2015-12-07 13:00:00,0.0,318.8999938964844,69.9000015258789,100830.0,0.0044999998062849045,276.0,0.9000000357627869,-1.8000000715255737,0.0
+2015-12-07 14:00:00,0.0,318.8999938964844,174.0,100820.0,0.004999999888241291,278.8999938964844,1.0,-1.600000023841858,0.0
+2015-12-07 15:00:00,0.0,346.70001220703125,285.70001220703125,100780.0,0.005499999970197678,283.1000061035156,1.100000023841858,-1.399999976158142,0.0
+2015-12-07 16:00:00,0.0,346.6000061035156,346.8999938964844,100690.0,0.004900000058114529,286.70001220703125,1.0,-1.5,0.0
+2015-12-07 17:00:00,0.0,346.6000061035156,364.3000183105469,100590.0,0.004799999762326479,289.5,0.9000000357627869,-1.7000000476837158,0.0
+2015-12-07 18:00:00,0.0,342.1000061035156,424.0,100440.0,0.004999999888241291,290.70001220703125,0.699999988079071,-1.8000000715255737,0.0
+2015-12-07 19:00:00,0.0,342.1000061035156,371.70001220703125,100320.0,0.005200000014156103,291.3999938964844,1.0,-1.8000000715255737,0.0
+2015-12-07 20:00:00,0.0,342.1000061035156,288.70001220703125,100280.0,0.005399999674409628,291.70001220703125,1.3000000715255737,-1.7000000476837158,0.0
+2015-12-07 21:00:00,0.0,350.8000183105469,132.60000610351562,100300.0,0.005499999970197678,291.8999938964844,1.5,-1.7000000476837158,0.0
+2015-12-07 22:00:00,0.0,350.8000183105469,22.399999618530273,100340.0,0.005699999630451202,289.70001220703125,1.2000000476837158,-1.5,0.0
+2015-12-07 23:00:00,0.0,350.8000183105469,0.0,100340.0,0.005799999926239252,285.8000183105469,0.9000000357627869,-1.3000000715255737,0.0
+2015-12-08 00:00:00,0.0,317.1000061035156,0.0,100400.0,0.005799999926239252,283.0,0.5,-1.100000023841858,0.0
+2015-12-08 01:00:00,0.0,317.1000061035156,0.0,100480.0,0.005699999630451202,281.8000183105469,0.5,-1.0,0.0
+2015-12-08 02:00:00,0.0,317.1000061035156,0.0,100490.0,0.005799999926239252,281.8000183105469,0.6000000238418579,-1.0,0.0
+2015-12-08 03:00:00,0.0,272.70001220703125,0.0,100470.0,0.005699999630451202,281.8000183105469,0.6000000238418579,-0.9000000357627869,0.0
+2015-12-08 04:00:00,0.0,272.70001220703125,0.0,100500.0,0.005399999674409628,280.8999938964844,0.6000000238418579,-0.6000000238418579,0.0
+2015-12-08 05:00:00,0.0,272.70001220703125,0.0,100520.0,0.005200000014156103,279.6000061035156,0.699999988079071,-0.4000000059604645,0.0
+2015-12-08 06:00:00,0.0,265.1000061035156,0.0,100440.0,0.005200000014156103,280.70001220703125,0.699999988079071,-0.10000000149011612,0.0
+2015-12-08 07:00:00,0.0,265.1000061035156,0.0,100490.0,0.005200000014156103,279.0,0.699999988079071,-0.30000001192092896,0.0
+2015-12-08 08:00:00,0.0,265.1000061035156,0.0,100550.0,0.004999999888241291,277.8000183105469,0.800000011920929,-0.5,0.0
+2015-12-08 09:00:00,0.0,260.3000183105469,0.0,100470.0,0.004900000058114529,277.3999938964844,0.800000011920929,-0.699999988079071,0.0
+2015-12-08 10:00:00,0.0,260.3000183105469,0.0,100440.0,0.004699999932199717,276.0,0.5,-0.699999988079071,0.0
+2015-12-08 11:00:00,0.0,260.3000183105469,0.0,100520.0,0.00419999985024333,274.8000183105469,0.10000000149011612,-0.699999988079071,0.0
+2015-12-08 12:00:00,0.0,258.0,0.0,100560.0,0.0044999998062849045,275.6000061035156,-0.30000001192092896,-0.699999988079071,0.0
+2015-12-08 13:00:00,0.0,257.8999938964844,98.0,100650.0,0.0044999998062849045,275.3999938964844,-0.4000000059604645,-0.6000000238418579,0.0
+2015-12-08 14:00:00,0.0,257.8999938964844,247.3000030517578,100670.0,0.005499999970197678,279.5,-0.6000000238418579,-0.4000000059604645,0.0
+2015-12-08 15:00:00,0.0,285.20001220703125,404.1000061035156,100730.0,0.00559999980032444,282.8000183105469,-0.699999988079071,-0.30000001192092896,0.0
+2015-12-08 16:00:00,0.0,285.20001220703125,491.3000183105469,100710.0,0.005399999674409628,285.70001220703125,-0.699999988079071,0.5,0.0
+2015-12-08 17:00:00,0.0,285.20001220703125,516.5,100580.0,0.0052999998442828655,287.8999938964844,-0.699999988079071,1.3000000715255737,0.0
+2015-12-08 18:00:00,0.0,291.1000061035156,501.8000183105469,100480.0,0.005200000014156103,289.1000061035156,-0.6000000238418579,2.1000001430511475,0.0
+2015-12-08 19:00:00,0.0,291.1000061035156,440.1000061035156,100400.0,0.00559999980032444,290.5,-0.20000000298023224,2.4000000953674316,0.0
+2015-12-08 20:00:00,0.0,291.1000061035156,342.0,100420.0,0.0058999997563660145,290.5,0.20000000298023224,2.700000047683716,0.0
+2015-12-08 21:00:00,0.0,279.8999938964844,148.40000915527344,100320.0,0.006399999838322401,290.0,0.6000000238418579,3.0,0.0
+2015-12-08 22:00:00,0.0,279.8999938964844,25.200000762939453,100360.0,0.006399999838322401,288.3999938964844,0.20000000298023224,2.799999952316284,0.0
+2015-12-08 23:00:00,0.0,279.8999938964844,0.0,100370.0,0.0064999996684491634,284.3999938964844,-0.10000000149011612,2.5,0.0
+2015-12-09 00:00:00,0.0,263.8999938964844,0.0,100390.0,0.006599999964237213,282.3999938964844,-0.4000000059604645,2.299999952316284,0.0
+2015-12-09 01:00:00,0.0,263.8999938964844,0.0,100480.0,0.006399999838322401,281.70001220703125,-0.699999988079071,2.299999952316284,0.0
+2015-12-09 02:00:00,0.0,263.8999938964844,0.0,100490.0,0.006300000008195639,281.20001220703125,-1.0,2.299999952316284,0.0
+2015-12-09 03:00:00,0.0,258.70001220703125,0.0,100430.0,0.0058999997563660145,280.1000061035156,-1.399999976158142,2.299999952316284,0.0
+2015-12-09 04:00:00,0.0,258.70001220703125,0.0,100430.0,0.005699999630451202,279.5,-0.800000011920929,2.1000001430511475,0.0
+2015-12-09 05:00:00,0.0,258.70001220703125,0.0,100430.0,0.005499999970197678,278.8999938964844,-0.30000001192092896,2.0,0.0
+2015-12-09 06:00:00,0.0,255.60000610351562,0.0,100400.0,0.005200000014156103,278.3999938964844,0.30000001192092896,1.899999976158142,0.0
+2015-12-09 07:00:00,0.0,255.60000610351562,0.0,100440.0,0.004999999888241291,277.8000183105469,0.10000000149011612,1.8000000715255737,0.0
+2015-12-09 08:00:00,0.0,255.60000610351562,0.0,100450.0,0.004999999888241291,277.5,0.0,1.7000000476837158,0.0
+2015-12-09 09:00:00,0.0,256.8999938964844,0.0,100350.0,0.005200000014156103,278.0,-0.20000000298023224,1.600000023841858,0.0
+2015-12-09 10:00:00,0.0,256.8999938964844,0.0,100370.0,0.004999999888241291,277.6000061035156,-0.4000000059604645,1.899999976158142,0.0
+2015-12-09 11:00:00,0.0,256.8999938964844,0.0,100400.0,0.004900000058114529,277.0,-0.6000000238418579,2.200000047683716,0.0
+2015-12-09 12:00:00,0.0,267.6000061035156,0.0,100430.0,0.004299999680370092,275.1000061035156,-0.699999988079071,2.5,0.0
+2015-12-09 13:00:00,0.0,267.6000061035156,94.4000015258789,100470.0,0.0044999998062849045,275.3999938964844,-0.699999988079071,1.899999976158142,0.0
+2015-12-09 14:00:00,0.0,267.6000061035156,241.60000610351562,100540.0,0.0052999998442828655,278.8000183105469,-0.6000000238418579,1.2000000476837158,0.0
+2015-12-09 15:00:00,0.0,295.8000183105469,376.0,100480.0,0.006000000052154064,282.3000183105469,-0.6000000238418579,0.5,0.0
+2015-12-09 16:00:00,0.0,295.8000183105469,457.8999938964844,100450.0,0.00559999980032444,286.5,-0.30000001192092896,1.2000000476837158,0.0
+2015-12-09 17:00:00,0.0,295.70001220703125,481.8999938964844,100290.0,0.004900000058114529,289.3999938964844,0.0,1.8000000715255737,0.0
+2015-12-09 18:00:00,0.0,304.3000183105469,491.5,100150.0,0.004699999932199717,290.20001220703125,0.4000000059604645,2.4000000953674316,0.0
+2015-12-09 19:00:00,0.0,304.3000183105469,431.3999938964844,100050.0,0.004600000102072954,291.0,0.800000011920929,2.200000047683716,0.0
+2015-12-09 20:00:00,0.0,304.3000183105469,335.3999938964844,100040.0,0.004299999680370092,291.3000183105469,1.2000000476837158,2.1000001430511475,0.0
+2015-12-09 21:00:00,0.0,292.3000183105469,145.1999969482422,100020.0,0.004600000102072954,290.8000183105469,1.600000023841858,1.899999976158142,0.0
+2015-12-09 22:00:00,0.0,292.3000183105469,24.700000762939453,100070.0,0.004999999888241291,288.20001220703125,1.899999976158142,1.100000023841858,0.0
+2015-12-09 23:00:00,0.0,292.3000183105469,0.0,100080.0,0.0050999997183680534,284.70001220703125,2.200000047683716,0.30000001192092896,0.0
+2015-12-10 00:00:00,0.0,274.6000061035156,0.0,100090.0,0.005200000014156103,284.0,2.5,-0.5,0.0
+2015-12-10 01:00:00,0.0,274.6000061035156,0.0,100120.0,0.005399999674409628,282.0,2.200000047683716,-0.9000000357627869,0.0
+2015-12-10 02:00:00,0.0,274.70001220703125,0.0,100160.0,0.005200000014156103,281.3000183105469,1.899999976158142,-1.2000000476837158,0.0
+2015-12-10 03:00:00,0.0,272.70001220703125,0.0,100100.0,0.0050999997183680534,281.3999938964844,1.600000023841858,-1.600000023841858,0.0
+2015-12-10 04:00:00,0.0,272.70001220703125,0.0,100080.0,0.0052999998442828655,281.3999938964844,1.600000023841858,-1.3000000715255737,0.0
+2015-12-10 05:00:00,0.0,272.70001220703125,0.0,100140.0,0.005399999674409628,281.0,1.600000023841858,-0.9000000357627869,0.0
+2015-12-10 06:00:00,0.0,280.6000061035156,0.0,100110.0,0.005399999674409628,279.3000183105469,1.600000023841858,-0.5,0.0
+2015-12-10 07:00:00,0.0,280.6000061035156,0.0,100070.0,0.0050999997183680534,280.3000183105469,1.600000023841858,-0.5,0.0
+2015-12-10 08:00:00,0.0,280.6000061035156,0.0,100060.0,0.005200000014156103,279.5,1.600000023841858,-0.4000000059604645,0.0
+2015-12-10 09:00:00,0.0,314.70001220703125,0.0,100050.0,0.0052999998442828655,279.6000061035156,1.600000023841858,-0.30000001192092896,0.0
+2015-12-10 10:00:00,0.0,314.70001220703125,0.0,100030.0,0.0050999997183680534,279.6000061035156,0.9000000357627869,-0.20000000298023224,0.0
+2015-12-10 11:00:00,0.0,314.70001220703125,0.0,100070.0,0.005200000014156103,279.3000183105469,0.20000000298023224,0.0,0.0
+2015-12-10 12:00:00,0.0,298.8999938964844,0.0,100070.0,0.005200000014156103,278.6000061035156,-0.5,0.20000000298023224,0.0
+2015-12-10 13:00:00,0.0,298.8999938964844,91.9000015258789,100190.0,0.004799999762326479,277.8999938964844,0.0,0.0,0.0
+2015-12-10 14:00:00,0.0,298.8999938964844,238.6999969482422,100170.0,0.005699999630451202,282.5,0.5,-0.10000000149011612,0.0
+2015-12-10 15:00:00,0.0,304.5,390.70001220703125,100250.0,0.006300000008195639,286.8999938964844,1.0,-0.20000000298023224,0.0
+2015-12-10 16:00:00,0.0,304.5,476.3999938964844,100190.0,0.0071000000461936,289.8000183105469,1.399999976158142,0.6000000238418579,0.0
+2015-12-10 17:00:00,0.0,304.3999938964844,501.8000183105469,100040.0,0.007599999662488699,292.5,1.899999976158142,1.5,0.0
+2015-12-10 18:00:00,0.0,345.8999938964844,421.5,99990.0,0.007899999618530273,293.3999938964844,2.299999952316284,2.299999952316284,0.0
+2015-12-10 19:00:00,0.0,345.8999938964844,370.1000061035156,99930.0,0.007699999958276749,293.6000061035156,2.0,2.799999952316284,0.0
+2015-12-10 20:00:00,0.0,345.8999938964844,287.8999938964844,99930.0,0.007599999662488699,293.6000061035156,1.7000000476837158,3.299999952316284,0.0
+2015-12-10 21:00:00,0.0,342.3999938964844,129.8000030517578,99900.0,0.007799999788403511,293.1000061035156,1.399999976158142,3.799999952316284,0.0
+2015-12-10 22:00:00,0.0,342.3999938964844,22.30000114440918,99950.0,0.007699999958276749,291.70001220703125,1.100000023841858,3.5,0.0
+2015-12-10 23:00:00,0.0,342.3999938964844,0.0,99940.0,0.008100000210106373,288.8999938964844,0.699999988079071,3.200000047683716,0.0
+2015-12-11 00:00:00,0.0,343.6000061035156,0.0,99940.0,0.008200000040233135,287.3000183105469,0.30000001192092896,2.9000000953674316,0.0
+2015-12-11 01:00:00,0.0,343.6000061035156,0.0,100000.0,0.008100000210106373,287.6000061035156,0.10000000149011612,2.6000001430511475,0.0
+2015-12-11 02:00:00,0.0,343.6000061035156,0.0,100050.0,0.007799999788403511,285.6000061035156,-0.10000000149011612,2.299999952316284,0.0
+2015-12-11 03:00:00,0.0,366.20001220703125,0.0,100050.0,0.007899999618530273,285.3000183105469,-0.20000000298023224,2.0,0.0
+2015-12-11 04:00:00,0.0,366.20001220703125,0.0,100040.0,0.007699999958276749,284.8999938964844,0.10000000149011612,2.200000047683716,0.0
+2015-12-11 05:00:00,0.0,366.20001220703125,0.0,100000.0,0.007699999958276749,285.5,0.4000000059604645,2.5,0.0
+2015-12-11 06:00:00,0.0,368.3000183105469,0.0,99960.0,0.0072999997064471245,284.8000183105469,0.699999988079071,2.700000047683716,0.0
+2015-12-11 07:00:00,0.0,368.3000183105469,0.0,99970.0,0.007699999958276749,285.0,1.100000023841858,2.5,0.0
+2015-12-11 08:00:00,0.0,368.3000183105469,0.0,100010.0,0.007499999832361937,285.3000183105469,1.5,2.200000047683716,0.0
+2015-12-11 09:00:00,0.0,310.0,0.0,99980.0,0.007599999662488699,284.8999938964844,1.8000000715255737,1.899999976158142,0.0
+2015-12-11 10:00:00,0.0,310.0,0.0,100000.0,0.0072999997064471245,283.70001220703125,1.600000023841858,2.0,0.0
+2015-12-11 11:00:00,0.0,310.0,0.0,100130.0,0.007499999832361937,283.70001220703125,1.3000000715255737,2.0,0.0
+2015-12-11 12:00:00,0.0,299.1000061035156,0.0,100150.0,0.007400000002235174,282.5,1.0,2.1000001430511475,0.0
+2015-12-11 13:00:00,0.0,299.1000061035156,87.5999984741211,100230.0,0.007599999662488699,283.8999938964844,1.100000023841858,1.899999976158142,0.0
+2015-12-11 14:00:00,0.0,299.1000061035156,230.8000030517578,100320.0,0.008599999360740185,285.20001220703125,1.3000000715255737,1.600000023841858,0.0
+2015-12-11 15:00:00,0.0,331.3999938964844,382.3999938964844,100360.0,0.00969999935477972,287.6000061035156,1.399999976158142,1.399999976158142,0.0
+2015-12-11 16:00:00,0.0,331.3999938964844,467.0,100390.0,0.00989999994635582,288.5,1.7000000476837158,2.1000001430511475,0.0
+2015-12-11 17:00:00,0.0,331.3999938964844,492.3000183105469,100370.0,0.010199999436736107,289.70001220703125,2.0,2.799999952316284,0.0
+2015-12-11 18:00:00,0.0,353.6000061035156,474.3999938964844,100310.0,0.01119999960064888,291.5,2.4000000953674316,3.5,0.0
+2015-12-11 19:00:00,0.0,353.6000061035156,416.8000183105469,100300.0,0.010599999688565731,294.70001220703125,2.299999952316284,3.700000047683716,0.0
+2015-12-11 20:00:00,0.0,353.6000061035156,324.3999938964844,100230.0,0.010199999436736107,295.3000183105469,2.299999952316284,3.799999952316284,0.0
+2015-12-11 21:00:00,0.0,347.6000061035156,137.5,100210.0,0.010400000028312206,294.8000183105469,2.200000047683716,4.0,0.0
+2015-12-11 22:00:00,0.0,347.6000061035156,23.80000114440918,100250.0,0.010699999518692493,293.20001220703125,1.7000000476837158,3.799999952316284,0.0
+2015-12-11 23:00:00,0.0,347.6000061035156,0.0,100290.0,0.010699999518692493,290.20001220703125,1.100000023841858,3.5,0.0
+2015-12-12 00:00:00,0.0,331.3999938964844,0.0,100330.0,0.010900000110268593,290.20001220703125,0.5,3.299999952316284,0.0
+2015-12-12 01:00:00,0.0,331.3999938964844,0.0,100420.0,0.009999999776482582,288.3000183105469,0.5,3.200000047683716,0.0
+2015-12-12 02:00:00,0.0,331.3999938964844,0.0,100420.0,0.00989999994635582,287.6000061035156,0.5,3.1000001430511475,0.0
+2015-12-12 03:00:00,0.0,328.0,0.0,100480.0,0.010099999606609344,288.0,0.5,3.0,0.0
+2015-12-12 04:00:00,0.0,328.0,0.0,100510.0,0.009800000116229057,287.20001220703125,1.100000023841858,3.0,0.0
+2015-12-12 05:00:00,0.0,328.0,0.0,100560.0,0.009399999864399433,286.8000183105469,1.8000000715255737,3.0,0.0
+2015-12-12 06:00:00,0.0,325.20001220703125,0.0,100600.0,0.00969999935477972,287.1000061035156,2.5,3.0,0.0
+2015-12-12 07:00:00,0.0,325.20001220703125,0.0,100630.0,0.009800000116229057,287.70001220703125,2.4000000953674316,2.9000000953674316,0.0
+2015-12-12 08:00:00,0.0,325.20001220703125,0.0,100660.0,0.00969999935477972,287.3999938964844,2.200000047683716,2.799999952316284,0.0
+2015-12-12 09:00:00,0.0,319.8000183105469,0.0,100670.0,0.009599999524652958,287.5,2.1000001430511475,2.700000047683716,0.0
+2015-12-12 10:00:00,0.0,319.8000183105469,0.0,100670.0,0.00969999935477972,287.3999938964844,1.600000023841858,2.700000047683716,0.0
+2015-12-12 11:00:00,0.0,319.8999938964844,0.0,100740.0,0.009499999694526196,286.8999938964844,1.2000000476837158,2.6000001430511475,0.0
+2015-12-12 12:00:00,0.0,316.8999938964844,0.0,100830.0,0.009099999442696571,286.20001220703125,0.800000011920929,2.6000001430511475,0.0
+2015-12-12 13:00:00,0.0,316.8999938964844,84.4000015258789,100870.0,0.009399999864399433,286.5,1.2000000476837158,2.4000000953674316,0.0
+2015-12-12 14:00:00,0.0,316.8999938964844,225.40000915527344,100930.0,0.009999999776482582,288.1000061035156,1.600000023841858,2.200000047683716,0.0
+2015-12-12 15:00:00,0.0,342.3999938964844,377.3000183105469,100960.0,0.010799999348819256,291.1000061035156,1.899999976158142,2.0,0.0
+2015-12-12 16:00:00,0.0,342.3999938964844,461.5,100960.0,0.010900000110268593,293.20001220703125,2.4000000953674316,1.899999976158142,0.0
+2015-12-12 17:00:00,0.0,342.3999938964844,487.0,100820.0,0.010099999606609344,295.1000061035156,2.9000000953674316,1.8000000715255737,0.0
+2015-12-12 18:00:00,0.0,354.3000183105469,475.70001220703125,100790.0,0.009999999776482582,296.1000061035156,3.4000000953674316,1.8000000715255737,0.0
+2015-12-12 19:00:00,0.0,354.3000183105469,418.20001220703125,100720.0,0.010099999606609344,297.0,3.1000001430511475,2.0,0.0
+2015-12-12 20:00:00,0.0,354.3000183105469,325.8000183105469,100670.0,0.010300000198185444,297.20001220703125,2.9000000953674316,2.299999952316284,0.0
+2015-12-12 21:00:00,0.0,339.3999938964844,157.1999969482422,100680.0,0.00989999994635582,296.3999938964844,2.6000001430511475,2.5,0.0
+2015-12-12 22:00:00,0.0,339.3999938964844,27.5,100730.0,0.010599999688565731,293.8999938964844,2.4000000953674316,2.4000000953674316,0.0
+2015-12-12 23:00:00,0.0,339.3999938964844,0.0,100740.0,0.010599999688565731,291.3000183105469,2.200000047683716,2.299999952316284,0.0
+2015-12-13 00:00:00,0.0,318.20001220703125,0.0,100780.0,0.010699999518692493,290.3999938964844,2.0,2.299999952316284,0.0
+2015-12-13 01:00:00,0.0,318.20001220703125,0.0,100810.0,0.010400000028312206,288.6000061035156,1.5,2.1000001430511475,0.0
+2015-12-13 02:00:00,0.0,318.20001220703125,0.0,100860.0,0.009800000116229057,286.8000183105469,0.9000000357627869,1.899999976158142,0.0
+2015-12-13 03:00:00,0.0,310.3999938964844,0.0,100830.0,0.009099999442696571,285.70001220703125,0.30000001192092896,1.7000000476837158,0.0
+2015-12-13 04:00:00,0.0,310.3999938964844,0.0,100840.0,0.008599999360740185,285.3000183105469,0.800000011920929,1.8000000715255737,0.0
+2015-12-13 05:00:00,0.0,310.3999938964844,0.0,100850.0,0.008999999612569809,286.0,1.2000000476837158,1.8000000715255737,0.0
+2015-12-13 06:00:00,0.0,301.70001220703125,0.0,100850.0,0.008299999870359898,284.5,1.600000023841858,1.899999976158142,0.0
+2015-12-13 07:00:00,0.0,301.70001220703125,0.0,100820.0,0.007999999448657036,284.3000183105469,1.3000000715255737,1.899999976158142,0.0
+2015-12-13 08:00:00,0.0,301.70001220703125,0.0,100810.0,0.006899999920278788,283.20001220703125,0.9000000357627869,1.8000000715255737,0.0
+2015-12-13 09:00:00,0.0,293.3999938964844,0.0,100760.0,0.0072999997064471245,283.20001220703125,0.5,1.8000000715255737,0.0
+2015-12-13 10:00:00,0.0,293.3999938964844,0.0,100750.0,0.0072999997064471245,282.3999938964844,0.0,1.399999976158142,0.0
+2015-12-13 11:00:00,0.0,293.5,0.0,100780.0,0.007400000002235174,282.70001220703125,-0.5,1.0,0.0
+2015-12-13 12:00:00,0.0,299.3999938964844,0.0,100810.0,0.006799999624490738,280.8999938964844,-1.100000023841858,0.6000000238418579,0.0
+2015-12-13 13:00:00,0.0,299.3999938964844,83.9000015258789,100790.0,0.0071000000461936,281.8000183105469,-1.0,0.10000000149011612,0.0
+2015-12-13 14:00:00,0.0,299.3999938964844,227.40000915527344,100860.0,0.007899999618530273,284.20001220703125,-0.9000000357627869,-0.30000001192092896,0.0
+2015-12-13 15:00:00,0.0,331.20001220703125,369.0,100800.0,0.008599999360740185,287.8000183105469,-0.9000000357627869,-0.800000011920929,0.0
+2015-12-13 16:00:00,0.0,331.1000061035156,452.0,100790.0,0.008899999782443047,291.3000183105469,-0.9000000357627869,0.4000000059604645,0.0
+2015-12-13 17:00:00,0.0,331.1000061035156,477.3000183105469,100700.0,0.00839999970048666,293.1000061035156,-0.9000000357627869,1.600000023841858,0.0
+2015-12-13 18:00:00,0.0,345.1000061035156,456.8000183105469,100580.0,0.009800000116229057,294.3999938964844,-0.9000000357627869,2.799999952316284,0.0
+2015-12-13 19:00:00,0.0,345.1000061035156,401.8999938964844,100490.0,0.009499999694526196,295.0,-1.3000000715255737,2.799999952316284,0.0
+2015-12-13 20:00:00,0.0,345.1000061035156,313.3000183105469,100420.0,0.010300000198185444,295.5,-1.600000023841858,2.9000000953674316,0.0
+2015-12-13 21:00:00,0.0,324.3000183105469,145.0,100370.0,0.010499999858438969,294.8999938964844,-2.0,3.0,0.0
+2015-12-13 22:00:00,0.0,324.3000183105469,25.700000762939453,100400.0,0.011099999770522118,292.8000183105469,-2.200000047683716,2.4000000953674316,0.0
+2015-12-13 23:00:00,0.0,324.3000183105469,0.0,100370.0,0.010900000110268593,290.1000061035156,-2.4000000953674316,1.7000000476837158,0.0
+2015-12-14 00:00:00,0.0,330.0,0.0,100370.0,0.010900000110268593,289.0,-2.6000001430511475,1.100000023841858,0.0
+2015-12-14 01:00:00,0.0,330.0,0.0,100360.0,0.011299999430775642,289.8999938964844,-2.799999952316284,1.2000000476837158,0.0
+2015-12-14 02:00:00,0.0,330.0,0.0,100380.0,0.011299999430775642,289.8999938964844,-2.9000000953674316,1.3000000715255737,0.0
+2015-12-14 03:00:00,0.0,317.3999938964844,0.0,100320.0,0.01119999960064888,289.5,-3.1000001430511475,1.399999976158142,0.0
+2015-12-14 04:00:00,0.0,317.3999938964844,0.0,100260.0,0.010900000110268593,289.1000061035156,-2.9000000953674316,1.899999976158142,0.0
+2015-12-14 05:00:00,0.0,317.3999938964844,0.0,100270.0,0.011099999770522118,289.0,-2.700000047683716,2.4000000953674316,0.0
+2015-12-14 06:00:00,0.0,324.3000183105469,0.0,100200.0,0.011399999260902405,289.20001220703125,-2.4000000953674316,2.9000000953674316,0.0
+2015-12-14 07:00:00,0.0,324.3000183105469,0.0,100130.0,0.01119999960064888,289.3000183105469,-1.899999976158142,2.9000000953674316,0.0
+2015-12-14 08:00:00,0.0,324.3000183105469,0.0,100020.0,0.011399999260902405,289.3999938964844,-1.5,3.0,0.0
+2015-12-14 09:00:00,0.0,358.3000183105469,0.0,99880.0,0.011500000022351742,290.0,-1.0,3.0,0.0
+2015-12-14 10:00:00,0.0,358.3000183105469,0.0,99810.0,0.011799999512732029,289.8999938964844,-1.600000023841858,3.1000001430511475,0.0
+2015-12-14 11:00:00,0.0,358.3000183105469,0.0,99780.0,0.012000000104308128,289.8999938964844,-2.200000047683716,3.200000047683716,0.0
+2015-12-14 12:00:00,0.0,381.1000061035156,0.0,99710.0,0.011699999682605267,289.8999938964844,-2.799999952316284,3.299999952316284,0.0
+2015-12-14 13:00:00,0.0,381.1000061035156,37.0,99680.0,0.012299999594688416,290.8000183105469,-2.1000001430511475,3.799999952316284,0.0
+2015-12-14 14:00:00,0.0,381.1000061035156,101.80000305175781,99650.0,0.012600000016391277,291.3000183105469,-1.399999976158142,4.300000190734863,7.382353145925361e-07
+2015-12-14 15:00:00,1.5,392.8999938964844,181.90000915527344,99570.0,0.012899999506771564,291.5,-0.699999988079071,4.800000190734863,0.0
+2015-12-14 16:00:00,0.0,392.8999938964844,223.10000610351562,99410.0,0.013399999588727951,292.6000061035156,-0.20000000298023224,4.900000095367432,0.0
+2015-12-14 17:00:00,0.0,392.8999938964844,235.8000030517578,99350.0,0.013899999670684338,293.3999938964844,0.30000001192092896,4.900000095367432,0.0
+2015-12-14 18:00:00,0.0,405.20001220703125,161.5,99270.0,0.014299999922513962,293.8000183105469,0.699999988079071,4.900000095367432,0.0
+2015-12-14 19:00:00,0.0,405.20001220703125,142.10000610351562,99290.0,0.014599999412894249,295.0,1.2000000476837158,4.5,5.090121965577734e-08
+2015-12-14 20:00:00,0.10000000149011612,405.20001220703125,110.9000015258789,99160.0,0.013499999418854713,293.6000061035156,1.600000023841858,4.099999904632568,2.1604080814467757e-06
+2015-12-14 21:00:00,4.300000190734863,395.70001220703125,43.79999923706055,99230.0,0.012299999594688416,291.6000061035156,2.1000001430511475,3.700000047683716,0.0
+2015-12-14 22:00:00,0.0,395.70001220703125,7.900000095367432,99140.0,0.012000000104308128,290.5,2.200000047683716,3.4000000953674316,0.0
+2015-12-14 23:00:00,0.0,395.70001220703125,0.0,99170.0,0.01209999993443489,290.70001220703125,2.4000000953674316,3.1000001430511475,0.0
+2015-12-15 00:00:00,0.0,333.3999938964844,0.0,99160.0,0.012000000104308128,290.3000183105469,2.5,2.700000047683716,0.0
+2015-12-15 01:00:00,0.0,333.3999938964844,0.0,99170.0,0.011899999342858791,290.3999938964844,3.1000001430511475,2.9000000953674316,0.0
+2015-12-15 02:00:00,0.0,333.3999938964844,0.0,99250.0,0.011699999682605267,290.0,3.6000001430511475,3.0,0.0
+2015-12-15 03:00:00,0.0,304.20001220703125,0.0,99280.0,0.011299999430775642,289.3000183105469,4.200000286102295,3.1000001430511475,0.0
+2015-12-15 04:00:00,0.0,304.20001220703125,0.0,99310.0,0.010900000110268593,288.5,4.200000286102295,2.700000047683716,0.0
+2015-12-15 05:00:00,0.0,304.20001220703125,0.0,99320.0,0.00969999935477972,288.20001220703125,4.300000190734863,2.200000047683716,0.0
+2015-12-15 06:00:00,0.0,287.3999938964844,0.0,99320.0,0.008999999612569809,286.8999938964844,4.300000190734863,1.7000000476837158,0.0
+2015-12-15 07:00:00,0.0,287.3999938964844,0.0,99360.0,0.00839999970048666,286.8000183105469,4.099999904632568,1.5,0.0
+2015-12-15 08:00:00,0.0,287.3999938964844,0.0,99340.0,0.007400000002235174,286.1000061035156,3.9000000953674316,1.2000000476837158,0.0
+2015-12-15 09:00:00,0.0,278.3999938964844,0.0,99330.0,0.00699999975040555,285.5,3.700000047683716,0.9000000357627869,0.0
+2015-12-15 10:00:00,0.0,278.3999938964844,0.0,99390.0,0.006899999920278788,284.8000183105469,3.5,0.9000000357627869,0.0
+2015-12-15 11:00:00,0.0,278.3999938964844,0.0,99390.0,0.0066999997943639755,284.6000061035156,3.299999952316284,0.800000011920929,0.0
+2015-12-15 12:00:00,0.0,270.3000183105469,0.0,99480.0,0.0066999997943639755,283.3000183105469,3.1000001430511475,0.699999988079071,0.0
+2015-12-15 13:00:00,0.0,270.3000183105469,82.5,99590.0,0.00699999975040555,282.70001220703125,3.1000001430511475,0.30000001192092896,0.0
+2015-12-15 14:00:00,0.0,270.3000183105469,230.0,99630.0,0.0072999997064471245,284.70001220703125,3.0,-0.10000000149011612,0.0
+2015-12-15 15:00:00,0.0,301.20001220703125,386.70001220703125,99670.0,0.0071000000461936,287.20001220703125,2.9000000953674316,-0.6000000238418579,0.0
+2015-12-15 16:00:00,0.0,301.20001220703125,475.1000061035156,99630.0,0.0072999997064471245,289.70001220703125,2.700000047683716,-0.10000000149011612,0.0
+2015-12-15 17:00:00,0.0,301.20001220703125,502.6000061035156,99560.0,0.007199999876320362,291.70001220703125,2.5,0.30000001192092896,0.0
+2015-12-15 18:00:00,0.0,315.8000183105469,490.0,99520.0,0.00699999975040555,293.6000061035156,2.200000047683716,0.699999988079071,0.0
+2015-12-15 19:00:00,0.0,315.8000183105469,431.70001220703125,99480.0,0.007199999876320362,295.20001220703125,2.0,0.5,0.0
+2015-12-15 20:00:00,0.0,315.8000183105469,337.1000061035156,99490.0,0.006899999920278788,295.6000061035156,1.7000000476837158,0.20000000298023224,0.0
+2015-12-15 21:00:00,0.0,305.8999938964844,148.5,99550.0,0.0071000000461936,295.3999938964844,1.399999976158142,0.0,0.0
+2015-12-15 22:00:00,0.0,305.8999938964844,27.200000762939453,99600.0,0.008100000210106373,292.3999938964844,1.100000023841858,0.30000001192092896,0.0
+2015-12-15 23:00:00,0.0,306.0,0.0,99620.0,0.008299999870359898,288.20001220703125,0.699999988079071,0.5,0.0
+2015-12-16 00:00:00,0.0,288.8999938964844,0.0,99650.0,0.00839999970048666,286.3000183105469,0.4000000059604645,0.800000011920929,0.0
+2015-12-16 01:00:00,0.0,288.8999938964844,0.0,99710.0,0.007999999448657036,285.5,0.20000000298023224,0.10000000149011612,0.0
+2015-12-16 02:00:00,0.0,288.8999938964844,0.0,99710.0,0.008299999870359898,285.0,0.0,-0.699999988079071,0.0
+2015-12-16 03:00:00,0.0,282.20001220703125,0.0,99740.0,0.008200000040233135,284.70001220703125,-0.30000001192092896,-1.399999976158142,0.0
+2015-12-16 04:00:00,0.0,282.20001220703125,0.0,99800.0,0.007799999788403511,283.8000183105469,-0.4000000059604645,-1.2000000476837158,0.0
+2015-12-16 05:00:00,0.0,282.20001220703125,0.0,99830.0,0.006899999920278788,281.20001220703125,-0.6000000238418579,-1.0,0.0
+2015-12-16 06:00:00,0.0,277.0,0.0,99820.0,0.006899999920278788,282.0,-0.699999988079071,-0.9000000357627869,0.0
+2015-12-16 07:00:00,0.0,277.0,0.0,99890.0,0.0064999996684491634,280.6000061035156,-0.9000000357627869,-0.800000011920929,0.0
+2015-12-16 08:00:00,0.0,277.0,0.0,99930.0,0.006300000008195639,279.8999938964844,-1.2000000476837158,-0.800000011920929,0.0
+2015-12-16 09:00:00,0.0,272.8000183105469,0.0,99880.0,0.006199999712407589,280.5,-1.399999976158142,-0.800000011920929,0.0
+2015-12-16 10:00:00,0.0,272.8000183105469,0.0,99880.0,0.006000000052154064,280.20001220703125,-1.8000000715255737,-0.800000011920929,0.0
+2015-12-16 11:00:00,0.0,272.8000183105469,0.0,99980.0,0.005399999674409628,278.3000183105469,-2.200000047683716,-0.800000011920929,0.0
+2015-12-16 12:00:00,0.0,267.5,0.0,100000.0,0.005499999970197678,278.20001220703125,-2.700000047683716,-0.800000011920929,0.0
+2015-12-16 13:00:00,0.0,267.5,81.30000305175781,100070.0,0.0058999997563660145,279.20001220703125,-2.5,-0.9000000357627869,0.0
+2015-12-16 14:00:00,0.0,267.5,230.10000610351562,100140.0,0.006799999624490738,281.5,-2.299999952316284,-1.0,0.0
+2015-12-16 15:00:00,0.0,293.8999938964844,387.3999938964844,100190.0,0.007499999832361937,284.8000183105469,-2.200000047683716,-1.100000023841858,0.0
+2015-12-16 16:00:00,0.0,293.8999938964844,476.6000061035156,100110.0,0.008499999530613422,288.70001220703125,-2.5,-0.6000000238418579,0.0
+2015-12-16 17:00:00,0.0,293.8999938964844,504.70001220703125,100060.0,0.007599999662488699,291.8000183105469,-2.9000000953674316,-0.10000000149011612,0.0
+2015-12-16 18:00:00,0.0,310.1000061035156,489.3000183105469,99980.0,0.007599999662488699,293.8000183105469,-3.299999952316284,0.4000000059604645,0.0
+2015-12-16 19:00:00,0.0,310.1000061035156,431.3000183105469,99930.0,0.007899999618530273,295.0,-3.1000001430511475,0.6000000238418579,0.0
+2015-12-16 20:00:00,0.0,310.1000061035156,337.20001220703125,99920.0,0.007999999448657036,295.20001220703125,-2.799999952316284,0.800000011920929,0.0
+2015-12-16 21:00:00,0.0,305.8000183105469,148.10000610351562,99810.0,0.007899999618530273,294.70001220703125,-2.6000001430511475,1.0,0.0
+2015-12-16 22:00:00,0.0,305.8000183105469,27.600000381469727,99850.0,0.008299999870359898,291.8999938964844,-2.799999952316284,0.6000000238418579,0.0
+2015-12-16 23:00:00,0.0,305.8000183105469,0.0,99890.0,0.008700000122189522,290.1000061035156,-3.0,0.30000001192092896,0.0
+2015-12-17 00:00:00,0.0,311.5,0.0,99900.0,0.008899999782443047,288.70001220703125,-3.200000047683716,0.0,0.0
+2015-12-17 01:00:00,0.0,311.5,0.0,100010.0,0.008599999360740185,286.0,-2.9000000953674316,0.10000000149011612,0.0
+2015-12-17 02:00:00,0.0,311.5,0.0,100000.0,0.008599999360740185,286.3000183105469,-2.6000001430511475,0.20000000298023224,0.0
+2015-12-17 03:00:00,0.0,342.0,0.0,99940.0,0.008499999530613422,286.6000061035156,-2.299999952316284,0.4000000059604645,2.3657042550979653e-07
+2015-12-17 04:00:00,0.5,342.0,0.0,99910.0,0.008799999952316284,287.5,-1.8000000715255737,0.4000000059604645,4.76594374793869e-07
+2015-12-17 05:00:00,1.0,342.0,0.0,99930.0,0.00930000003427267,287.20001220703125,-1.3000000715255737,0.5,1.426301595152609e-06
+2015-12-17 06:00:00,3.0,382.5,0.0,99760.0,0.009499999694526196,286.5,-0.800000011920929,0.5,4.727622629790369e-07
+2015-12-17 07:00:00,1.0,382.3999938964844,0.0,99720.0,0.009399999864399433,286.6000061035156,-1.2000000476837158,0.6000000238418579,1.0409098948042186e-06
+2015-12-17 08:00:00,2.200000047683716,382.3999938964844,0.0,99740.0,0.009499999694526196,286.6000061035156,-1.600000023841858,0.699999988079071,0.0
+2015-12-17 09:00:00,0.0,382.6000061035156,0.0,99710.0,0.00930000003427267,286.5,-2.0,0.699999988079071,0.0
+2015-12-17 10:00:00,0.0,382.6000061035156,0.0,99590.0,0.008999999612569809,286.20001220703125,-2.4000000953674316,0.699999988079071,0.0
+2015-12-17 11:00:00,0.0,382.6000061035156,0.0,99510.0,0.009099999442696571,286.6000061035156,-2.799999952316284,0.699999988079071,1.419422553058779e-06
+2015-12-17 12:00:00,3.0,384.20001220703125,0.0,99450.0,0.00930000003427267,286.3999938964844,-3.200000047683716,0.6000000238418579,2.0784926960470127e-06
+2015-12-17 13:00:00,4.400000095367432,384.20001220703125,34.5,99540.0,0.009499999694526196,286.5,-3.0,1.5,2.0801540021938852e-06
+2015-12-17 14:00:00,4.400000095367432,384.20001220703125,99.20000457763672,99540.0,0.00969999935477972,286.8999938964844,-2.799999952316284,2.4000000953674316,7.588522475838139e-07
+2015-12-17 15:00:00,1.600000023841858,404.20001220703125,157.0,99420.0,0.009800000116229057,287.3000183105469,-2.700000047683716,3.299999952316284,1.0943852648065907e-06
+2015-12-17 16:00:00,2.299999952316284,404.20001220703125,193.40000915527344,99470.0,0.009800000116229057,287.0,-0.6000000238418579,4.300000190734863,1.8037282986643158e-06
+2015-12-17 17:00:00,3.799999952316284,404.20001220703125,204.90000915527344,99360.0,0.009800000116229057,286.8999938964844,1.5,5.400000095367432,0.0
+2015-12-17 18:00:00,0.0,380.20001220703125,242.6999969482422,99310.0,0.010599999688565731,288.0,3.6000001430511475,6.400000095367432,0.0
+2015-12-17 19:00:00,0.0,380.20001220703125,214.10000610351562,99360.0,0.010999999940395355,289.3000183105469,3.799999952316284,5.599999904632568,0.0
+2015-12-17 20:00:00,0.0,380.20001220703125,167.60000610351562,99280.0,0.011399999260902405,289.20001220703125,4.0,4.800000190734863,0.0
+2015-12-17 21:00:00,0.0,371.1000061035156,72.30000305175781,99260.0,0.011399999260902405,289.70001220703125,4.200000286102295,4.0,0.0
+2015-12-17 22:00:00,0.0,371.1000061035156,13.699999809265137,99260.0,0.011899999342858791,289.70001220703125,3.700000047683716,3.9000000953674316,0.0
+2015-12-17 23:00:00,0.0,371.1000061035156,0.0,99330.0,0.011299999430775642,289.0,3.200000047683716,3.700000047683716,0.0
+2015-12-18 00:00:00,0.0,361.8000183105469,0.0,99330.0,0.01119999960064888,289.20001220703125,2.700000047683716,3.5,0.0
+2015-12-18 01:00:00,0.0,361.8000183105469,0.0,99410.0,0.010999999940395355,288.8000183105469,2.200000047683716,3.200000047683716,0.0
+2015-12-18 02:00:00,0.0,361.8000183105469,0.0,99440.0,0.010900000110268593,288.6000061035156,1.7000000476837158,2.9000000953674316,0.0
+2015-12-18 03:00:00,0.0,363.8000183105469,0.0,99430.0,0.010699999518692493,288.3999938964844,1.2000000476837158,2.6000001430511475,0.0
+2015-12-18 04:00:00,0.0,363.8000183105469,0.0,99460.0,0.010699999518692493,288.6000061035156,1.5,2.6000001430511475,0.0
+2015-12-18 05:00:00,0.0,363.8000183105469,0.0,99360.0,0.010699999518692493,288.1000061035156,1.7000000476837158,2.6000001430511475,0.0
+2015-12-18 06:00:00,0.0,344.3999938964844,0.0,99320.0,0.010699999518692493,287.70001220703125,1.899999976158142,2.700000047683716,0.0
+2015-12-18 07:00:00,0.0,344.3999938964844,0.0,99370.0,0.010400000028312206,288.1000061035156,2.0,2.4000000953674316,0.0
+2015-12-18 08:00:00,0.0,344.3999938964844,0.0,99390.0,0.009599999524652958,287.6000061035156,2.200000047683716,2.200000047683716,0.0
+2015-12-18 09:00:00,0.0,321.0,0.0,99340.0,0.009399999864399433,286.70001220703125,2.299999952316284,1.899999976158142,0.0
+2015-12-18 10:00:00,0.0,321.0,0.0,99390.0,0.00839999970048666,285.3000183105469,3.1000001430511475,1.8000000715255737,0.0
+2015-12-18 11:00:00,0.0,321.0,0.0,99440.0,0.0072999997064471245,283.8000183105469,3.799999952316284,1.600000023841858,0.0
+2015-12-18 12:00:00,0.0,269.0,0.0,99560.0,0.006899999920278788,282.8999938964844,4.599999904632568,1.5,0.0
+2015-12-18 13:00:00,0.0,269.0,82.20000457763672,99630.0,0.0066999997943639755,282.20001220703125,5.200000286102295,1.2000000476837158,0.0
+2015-12-18 14:00:00,0.0,269.0,239.3000030517578,99730.0,0.006300000008195639,282.3999938964844,5.700000286102295,0.800000011920929,0.0
+2015-12-18 15:00:00,0.0,263.5,388.8000183105469,99880.0,0.006000000052154064,282.20001220703125,6.300000190734863,0.5,0.0
+2015-12-18 16:00:00,0.0,263.5,479.70001220703125,99910.0,0.005699999630451202,284.0,6.800000190734863,0.20000000298023224,0.0
+2015-12-18 17:00:00,0.0,263.5,508.8999938964844,99850.0,0.0050999997183680534,285.1000061035156,7.300000190734863,-0.10000000149011612,0.0
+2015-12-18 18:00:00,0.0,260.0,503.1000061035156,99810.0,0.003999999724328518,286.70001220703125,7.800000190734863,-0.4000000059604645,0.0
+2015-12-18 19:00:00,0.0,260.0,444.20001220703125,99810.0,0.003399999812245369,287.1000061035156,7.200000286102295,-1.5,0.0
+2015-12-18 20:00:00,0.0,260.0,348.0,99920.0,0.002899999963119626,287.20001220703125,6.5,-2.6000001430511475,0.0
+2015-12-18 21:00:00,0.0,243.5,159.1999969482422,99950.0,0.0023999998811632395,286.1000061035156,5.800000190734863,-3.700000047683716,0.0
+2015-12-18 22:00:00,0.0,243.5,30.899999618530273,100130.0,0.002699999837204814,284.3999938964844,5.099999904632568,-3.4000000953674316,0.0
+2015-12-18 23:00:00,0.0,243.5,0.0,100260.0,0.003000000026077032,282.20001220703125,4.400000095367432,-3.1000001430511475,0.0
+2015-12-19 00:00:00,0.0,225.0,0.0,100400.0,0.0030999998562037945,280.5,3.6000001430511475,-2.799999952316284,0.0
+2015-12-19 01:00:00,0.0,225.0,0.0,100620.0,0.002899999963119626,278.8000183105469,3.4000000953674316,-2.6000001430511475,0.0
+2015-12-19 02:00:00,0.0,225.0,0.0,100790.0,0.00279999990016222,277.0,3.200000047683716,-2.299999952316284,0.0
+2015-12-19 03:00:00,0.0,214.6999969482422,0.0,100840.0,0.00279999990016222,276.0,2.9000000953674316,-2.1000001430511475,0.0
+2015-12-19 04:00:00,0.0,214.6999969482422,0.0,100940.0,0.002899999963119626,275.20001220703125,2.799999952316284,-2.1000001430511475,0.0
+2015-12-19 05:00:00,0.0,214.6999969482422,0.0,101020.0,0.00279999990016222,274.8000183105469,2.700000047683716,-2.0,0.0
+2015-12-19 06:00:00,0.0,206.60000610351562,0.0,101050.0,0.002199999988079071,274.1000061035156,2.6000001430511475,-2.0,0.0
+2015-12-19 07:00:00,0.0,206.60000610351562,0.0,101070.0,0.0024999999441206455,272.6000061035156,2.6000001430511475,-1.8000000715255737,0.0
+2015-12-19 08:00:00,0.0,206.60000610351562,0.0,101130.0,0.0023999998811632395,272.1000061035156,2.6000001430511475,-1.5,0.0
+2015-12-19 09:00:00,0.0,204.60000610351562,0.0,101190.0,0.0024999999441206455,271.70001220703125,2.5,-1.2000000476837158,0.0
+2015-12-19 10:00:00,0.0,204.60000610351562,0.0,101210.0,0.0026000000070780516,271.70001220703125,2.4000000953674316,-0.4000000059604645,0.0
+2015-12-19 11:00:00,0.0,204.60000610351562,0.0,101340.0,0.00279999990016222,270.6000061035156,2.200000047683716,0.4000000059604645,0.0
+2015-12-19 12:00:00,0.0,209.10000610351562,0.0,101420.0,0.002699999837204814,270.70001220703125,2.0,1.2000000476837158,0.0
+2015-12-19 13:00:00,0.0,209.10000610351562,79.0,101550.0,0.002899999963119626,271.3000183105469,2.1000001430511475,0.9000000357627869,0.0
+2015-12-19 14:00:00,0.0,209.10000610351562,233.0,101560.0,0.002899999963119626,273.5,2.200000047683716,0.6000000238418579,0.0
+2015-12-19 15:00:00,0.0,230.10000610351562,394.3000183105469,101690.0,0.00279999990016222,276.3999938964844,2.299999952316284,0.30000001192092896,0.0
+2015-12-19 16:00:00,0.0,230.10000610351562,487.0,101620.0,0.002300000051036477,279.3000183105469,2.9000000953674316,0.699999988079071,0.0
+2015-12-19 17:00:00,0.0,230.10000610351562,517.1000366210938,101550.0,0.002099999925121665,280.8000183105469,3.5,1.0,0.0
+2015-12-19 18:00:00,0.0,240.40000915527344,507.70001220703125,101500.0,0.0016999999061226845,281.70001220703125,4.099999904632568,1.3000000715255737,0.0
+2015-12-19 19:00:00,0.0,240.40000915527344,448.6000061035156,101460.0,0.0018999999156221747,282.6000061035156,3.9000000953674316,1.0,0.0
+2015-12-19 20:00:00,0.0,240.40000915527344,351.8000183105469,101410.0,0.002099999925121665,283.3999938964844,3.700000047683716,0.699999988079071,0.0
+2015-12-19 21:00:00,0.0,233.60000610351562,162.1999969482422,101410.0,0.002099999925121665,283.70001220703125,3.5,0.4000000059604645,0.0
+2015-12-19 22:00:00,0.0,233.60000610351562,32.10000228881836,101450.0,0.002099999925121665,282.3000183105469,3.200000047683716,0.699999988079071,0.0
+2015-12-19 23:00:00,0.0,233.60000610351562,0.0,101540.0,0.002699999837204814,278.8000183105469,2.9000000953674316,1.0,0.0
+2015-12-20 00:00:00,0.0,224.0,0.0,101560.0,0.003000000026077032,276.5,2.6000001430511475,1.3000000715255737,0.0
+2015-12-20 01:00:00,0.0,224.0,0.0,101590.0,0.0030999998562037945,275.8999938964844,2.299999952316284,0.9000000357627869,0.0
+2015-12-20 02:00:00,0.0,224.0,0.0,101580.0,0.003000000026077032,274.6000061035156,2.1000001430511475,0.6000000238418579,0.0
+2015-12-20 03:00:00,0.0,220.3000030517578,0.0,101540.0,0.003000000026077032,273.8000183105469,1.8000000715255737,0.20000000298023224,0.0
+2015-12-20 04:00:00,0.0,220.3000030517578,0.0,101590.0,0.003000000026077032,273.3000183105469,1.399999976158142,-0.4000000059604645,0.0
+2015-12-20 05:00:00,0.0,220.3000030517578,0.0,101620.0,0.002899999963119626,271.8000183105469,1.0,-1.100000023841858,0.0
+2015-12-20 06:00:00,0.0,218.0,0.0,101610.0,0.003000000026077032,272.1000061035156,0.6000000238418579,-1.7000000476837158,0.0
+2015-12-20 07:00:00,0.0,218.0,0.0,101640.0,0.003000000026077032,271.1000061035156,0.4000000059604645,-2.1000001430511475,0.0
+2015-12-20 08:00:00,0.0,218.0,0.0,101660.0,0.003000000026077032,271.5,0.20000000298023224,-2.4000000953674316,0.0
+2015-12-20 09:00:00,0.0,215.8000030517578,0.0,101690.0,0.002899999963119626,271.6000061035156,0.0,-2.799999952316284,0.0
+2015-12-20 10:00:00,0.0,215.8000030517578,0.0,101700.0,0.00279999990016222,271.0,-0.4000000059604645,-2.200000047683716,0.0
+2015-12-20 11:00:00,0.0,215.8000030517578,0.0,101720.0,0.00279999990016222,271.20001220703125,-0.800000011920929,-1.600000023841858,0.0
+2015-12-20 12:00:00,0.0,219.6999969482422,0.0,101720.0,0.00279999990016222,271.20001220703125,-1.3000000715255737,-1.0,0.0
+2015-12-20 13:00:00,0.0,219.6999969482422,76.80000305175781,101850.0,0.002899999963119626,271.20001220703125,-1.5,-0.800000011920929,0.0
+2015-12-20 14:00:00,0.0,219.6999969482422,229.6999969482422,101960.0,0.0031999999191612005,274.5,-1.7000000476837158,-0.699999988079071,0.0
+2015-12-20 15:00:00,0.0,242.6999969482422,390.3999938964844,101930.0,0.003000000026077032,278.6000061035156,-1.899999976158142,-0.5,0.0
+2015-12-20 16:00:00,0.0,242.6999969482422,482.8999938964844,101900.0,0.00279999990016222,282.1000061035156,-2.200000047683716,-0.10000000149011612,0.0
+2015-12-20 17:00:00,0.0,242.60000610351562,513.2000122070312,101840.0,0.0026000000070780516,284.5,-2.5,0.4000000059604645,0.0
+2015-12-20 18:00:00,0.0,254.8000030517578,500.70001220703125,101820.0,0.0023999998811632395,285.5,-2.799999952316284,0.800000011920929,0.0
+2015-12-20 19:00:00,0.0,254.8000030517578,442.8000183105469,101720.0,0.0024999999441206455,286.20001220703125,-2.700000047683716,0.9000000357627869,0.0
+2015-12-20 20:00:00,0.0,254.8000030517578,347.6000061035156,101690.0,0.0026000000070780516,286.1000061035156,-2.5,0.9000000357627869,0.0
+2015-12-20 21:00:00,0.0,253.3000030517578,173.0,101590.0,0.002699999837204814,285.3999938964844,-2.299999952316284,1.0,0.0
+2015-12-20 22:00:00,0.0,253.3000030517578,35.10000228881836,101600.0,0.002899999963119626,283.8999938964844,-2.700000047683716,1.0,0.0
+2015-12-20 23:00:00,0.0,253.3000030517578,0.0,101630.0,0.003399999812245369,281.6000061035156,-3.1000001430511475,1.100000023841858,0.0
+2015-12-21 00:00:00,0.0,250.10000610351562,0.0,101610.0,0.003700000001117587,279.70001220703125,-3.6000001430511475,1.2000000476837158,0.0
+2015-12-21 01:00:00,0.0,250.10000610351562,0.0,101580.0,0.003700000001117587,278.3999938964844,-3.299999952316284,0.6000000238418579,0.0
+2015-12-21 02:00:00,0.0,250.10000610351562,0.0,101630.0,0.003700000001117587,276.6000061035156,-3.1000001430511475,0.10000000149011612,0.0
+2015-12-21 03:00:00,0.0,266.5,0.0,101580.0,0.0037999998312443495,277.3000183105469,-2.799999952316284,-0.4000000059604645,0.0
+2015-12-21 04:00:00,0.0,266.5,0.0,101530.0,0.0037999998312443495,277.70001220703125,-2.799999952316284,-0.800000011920929,0.0
+2015-12-21 05:00:00,0.0,266.5,0.0,101500.0,0.0037999998312443495,277.1000061035156,-2.700000047683716,-1.100000023841858,0.0
+2015-12-21 06:00:00,0.0,289.0,0.0,101480.0,0.003999999724328518,278.0,-2.700000047683716,-1.399999976158142,0.0
+2015-12-21 07:00:00,0.0,289.0,0.0,101460.0,0.004100000020116568,279.1000061035156,-2.5,-1.399999976158142,0.0
+2015-12-21 08:00:00,0.0,289.0,0.0,101470.0,0.00419999985024333,279.0,-2.4000000953674316,-1.3000000715255737,0.0
+2015-12-21 09:00:00,0.0,334.1000061035156,0.0,101380.0,0.00419999985024333,279.3000183105469,-2.299999952316284,-1.2000000476837158,0.0
+2015-12-21 10:00:00,0.0,334.1000061035156,0.0,101340.0,0.004299999680370092,279.0,-2.200000047683716,-1.100000023841858,0.0
+2015-12-21 11:00:00,0.0,334.1000061035156,0.0,101290.0,0.00419999985024333,278.5,-2.1000001430511475,-1.100000023841858,0.0
+2015-12-21 12:00:00,0.0,352.8999938964844,0.0,101310.0,0.004399999976158142,279.1000061035156,-2.0,-1.0,0.0
+2015-12-21 13:00:00,0.0,352.8999938964844,33.29999923706055,101380.0,0.00419999985024333,279.5,-2.0,-0.9000000357627869,0.0
+2015-12-21 14:00:00,0.0,352.8999938964844,100.80000305175781,101310.0,0.00419999985024333,280.0,-2.0,-0.800000011920929,0.0
+2015-12-21 15:00:00,0.0,372.3999938964844,160.90000915527344,101310.0,0.004299999680370092,280.70001220703125,-2.0,-0.699999988079071,0.0
+2015-12-21 16:00:00,0.0,372.3999938964844,199.1999969482422,101300.0,0.0044999998062849045,282.6000061035156,-1.899999976158142,-0.4000000059604645,0.0
+2015-12-21 17:00:00,0.0,372.3999938964844,211.90000915527344,101220.0,0.004900000058114529,283.8000183105469,-1.7000000476837158,-0.20000000298023224,0.0
+2015-12-21 18:00:00,0.0,375.5,290.3999938964844,101150.0,0.004999999888241291,283.8999938964844,-1.5,0.10000000149011612,0.0
+2015-12-21 19:00:00,0.0,375.5,257.0,101050.0,0.005399999674409628,285.0,-1.600000023841858,0.10000000149011612,0.0
+2015-12-21 20:00:00,0.0,375.5,202.0,100890.0,0.00559999980032444,285.8000183105469,-1.8000000715255737,0.10000000149011612,0.0
+2015-12-21 21:00:00,0.0,361.70001220703125,132.8000030517578,100870.0,0.0058999997563660145,285.8000183105469,-1.899999976158142,0.10000000149011612,0.0
+2015-12-21 22:00:00,0.0,361.70001220703125,27.600000381469727,100820.0,0.006099999882280827,285.1000061035156,-2.200000047683716,0.4000000059604645,0.0
+2015-12-21 23:00:00,0.0,361.70001220703125,0.0,100830.0,0.006099999882280827,283.20001220703125,-2.5,0.699999988079071,0.0
+2015-12-22 00:00:00,0.0,357.0,0.0,100740.0,0.006199999712407589,283.20001220703125,-2.700000047683716,1.0,0.0
+2015-12-22 01:00:00,0.0,357.0,0.0,100760.0,0.0064999996684491634,283.0,-2.6000001430511475,0.9000000357627869,0.0
+2015-12-22 02:00:00,0.0,357.0,0.0,100770.0,0.006399999838322401,283.20001220703125,-2.5,0.800000011920929,0.0
+2015-12-22 03:00:00,0.0,369.20001220703125,0.0,100630.0,0.006300000008195639,282.1000061035156,-2.4000000953674316,0.699999988079071,0.0
+2015-12-22 04:00:00,0.0,369.20001220703125,0.0,100600.0,0.006300000008195639,282.5,-2.299999952316284,0.9000000357627869,0.0
+2015-12-22 05:00:00,0.0,369.20001220703125,0.0,100490.0,0.006599999964237213,283.1000061035156,-2.200000047683716,1.100000023841858,5.986149869805075e-07
+2015-12-22 06:00:00,1.3000000715255737,391.20001220703125,0.0,100310.0,0.00699999975040555,282.70001220703125,-2.1000001430511475,1.3000000715255737,2.8464086424883143e-06
+2015-12-22 07:00:00,6.200000286102295,391.1000061035156,0.0,100280.0,0.007499999832361937,283.5,-1.0,1.7000000476837158,3.00210506940693e-06
+2015-12-22 08:00:00,6.5,391.1000061035156,0.0,100110.0,0.008200000040233135,284.3000183105469,0.10000000149011612,2.0,3.392200346615728e-06
+2015-12-22 09:00:00,7.300000190734863,386.1000061035156,0.0,100030.0,0.008700000122189522,285.3000183105469,1.2000000476837158,2.4000000953674316,1.7654831463933217e-05
+2015-12-22 10:00:00,37.70000076293945,386.1000061035156,0.0,100100.0,0.009200000204145908,285.8999938964844,0.800000011920929,2.799999952316284,4.563967315233157e-06
+2015-12-22 11:00:00,9.699999809265137,386.1000061035156,0.0,100180.0,0.008899999782443047,285.3999938964844,0.6000000238418579,3.200000047683716,1.1716610241739401e-06
+2015-12-22 12:00:00,2.5,380.70001220703125,0.0,100160.0,0.009399999864399433,286.20001220703125,0.20000000298023224,3.6000001430511475,6.131225553307689e-07
+2015-12-22 13:00:00,1.3000000715255737,380.70001220703125,34.79999923706055,100130.0,0.009499999694526196,286.3000183105469,0.20000000298023224,3.6000001430511475,3.7760660823191564e-07
+2015-12-22 14:00:00,0.800000011920929,380.70001220703125,106.70000457763672,100230.0,0.009499999694526196,286.6000061035156,0.10000000149011612,3.700000047683716,0.0
+2015-12-22 15:00:00,0.0,384.8000183105469,237.60000610351562,100260.0,0.009999999776482582,287.20001220703125,0.10000000149011612,3.700000047683716,0.0
+2015-12-22 16:00:00,0.0,384.8000183105469,294.6000061035156,100210.0,0.010099999606609344,287.3999938964844,0.20000000298023224,3.5,0.0
+2015-12-22 17:00:00,0.0,384.8000183105469,313.6000061035156,100160.0,0.00989999994635582,287.0,0.30000001192092896,3.4000000953674316,0.0
+2015-12-22 18:00:00,0.0,392.8999938964844,306.5,100010.0,0.010300000198185444,288.0,0.4000000059604645,3.200000047683716,0.0
+2015-12-22 19:00:00,0.0,392.8999938964844,271.6000061035156,99990.0,0.011399999260902405,289.70001220703125,-0.10000000149011612,3.6000001430511475,0.0
+2015-12-22 20:00:00,0.0,392.8999938964844,213.6999969482422,99990.0,0.011699999682605267,290.20001220703125,-0.699999988079071,3.9000000953674316,0.0
+2015-12-22 21:00:00,0.0,388.3999938964844,118.30000305175781,100040.0,0.011599999852478504,290.0,-1.2000000476837158,4.300000190734863,0.0
+2015-12-22 22:00:00,0.0,388.3999938964844,25.200000762939453,99990.0,0.011399999260902405,289.6000061035156,-1.399999976158142,3.700000047683716,0.0
+2015-12-22 23:00:00,0.0,388.3999938964844,0.0,99990.0,0.010799999348819256,288.8000183105469,-1.600000023841858,3.1000001430511475,0.0
+2015-12-23 00:00:00,0.0,383.3000183105469,0.0,100050.0,0.011099999770522118,288.8000183105469,-1.8000000715255737,2.6000001430511475,0.0
+2015-12-23 01:00:00,0.0,383.3000183105469,0.0,100130.0,0.011099999770522118,289.20001220703125,-1.8000000715255737,2.200000047683716,0.0
+2015-12-23 02:00:00,0.0,383.3000183105469,0.0,100110.0,0.011099999770522118,288.8000183105469,-1.899999976158142,1.899999976158142,0.0
+2015-12-23 03:00:00,0.0,385.8000183105469,0.0,100090.0,0.011299999430775642,289.20001220703125,-2.0,1.5,0.0
+2015-12-23 04:00:00,0.0,385.8000183105469,0.0,100050.0,0.01119999960064888,289.0,-1.7000000476837158,1.600000023841858,0.0
+2015-12-23 05:00:00,0.0,385.8000183105469,0.0,100010.0,0.011699999682605267,289.5,-1.5,1.600000023841858,0.0
+2015-12-23 06:00:00,0.0,386.5,0.0,99980.0,0.011899999342858791,289.70001220703125,-1.2000000476837158,1.7000000476837158,0.0
+2015-12-23 07:00:00,0.0,386.5,0.0,100010.0,0.011599999852478504,289.8000183105469,-1.399999976158142,1.7000000476837158,0.0
+2015-12-23 08:00:00,0.0,386.5,0.0,100000.0,0.012000000104308128,289.70001220703125,-1.600000023841858,1.7000000476837158,0.0
+2015-12-23 09:00:00,0.0,391.0,0.0,99970.0,0.011899999342858791,289.8000183105469,-1.8000000715255737,1.7000000476837158,0.0
+2015-12-23 10:00:00,0.0,391.0,0.0,99940.0,0.011699999682605267,289.70001220703125,-2.1000001430511475,1.899999976158142,0.0
+2015-12-23 11:00:00,0.0,391.0,0.0,99920.0,0.011699999682605267,289.3999938964844,-2.5,2.1000001430511475,0.0
+2015-12-23 12:00:00,0.0,389.1000061035156,0.0,99900.0,0.011500000022351742,289.3000183105469,-2.799999952316284,2.4000000953674316,1.8866700062492885e-06
+2015-12-23 13:00:00,3.9000000953674316,389.1000061035156,42.400001525878906,99950.0,0.011699999682605267,289.70001220703125,-2.700000047683716,2.9000000953674316,5.824838155694726e-07
+2015-12-23 14:00:00,1.2000000476837158,389.1000061035156,131.6999969482422,99920.0,0.011899999342858791,289.8000183105469,-2.5,3.5,5.635471187070408e-06
+2015-12-23 15:00:00,11.600000381469727,393.8000183105469,163.0,99920.0,0.012000000104308128,290.0,-2.299999952316284,4.0,8.759635909420274e-07
+2015-12-23 16:00:00,1.8000000715255737,393.8000183105469,202.40000915527344,99860.0,0.01269999984651804,291.20001220703125,-1.899999976158142,4.099999904632568,4.4255319724101603e-07
+2015-12-23 17:00:00,0.9000000357627869,393.8000183105469,215.60000610351562,99740.0,0.013100000098347664,291.8999938964844,-1.399999976158142,4.099999904632568,0.0
+2015-12-23 18:00:00,0.0,405.20001220703125,182.3000030517578,99650.0,0.013700000010430813,292.20001220703125,-1.0,4.200000286102295,4.960924499258517e-06
+2015-12-23 19:00:00,10.0,405.20001220703125,161.60000610351562,99630.0,0.012899999506771564,291.6000061035156,-0.699999988079071,4.0,8.882235019915836e-07
+2015-12-23 20:00:00,1.8000000715255737,405.1000061035156,127.4000015258789,99690.0,0.012799999676644802,291.3000183105469,-0.4000000059604645,3.9000000953674316,2.9529413757094877e-07
+2015-12-23 21:00:00,0.6000000238418579,392.6000061035156,96.80000305175781,99740.0,0.013199999928474426,291.6000061035156,-0.10000000149011612,3.799999952316284,1.085606482825919e-06
+2015-12-23 22:00:00,2.200000047683716,392.6000061035156,21.100000381469727,99730.0,0.012399999424815178,290.8000183105469,-0.20000000298023224,3.200000047683716,3.430094869384076e-07
+2015-12-23 23:00:00,0.699999988079071,392.6000061035156,0.0,99800.0,0.012399999424815178,290.20001220703125,-0.4000000059604645,2.700000047683716,1.8524283800090267e-06
+2015-12-24 00:00:00,3.799999952316284,395.6000061035156,0.0,99980.0,0.012000000104308128,290.0,-0.5,2.200000047683716,6.813049765019497e-07
+2015-12-24 01:00:00,1.399999976158142,395.6000061035156,0.0,99950.0,0.011799999512732029,289.3999938964844,-1.0,2.299999952316284,1.0651743136309484e-06
+2015-12-24 02:00:00,2.200000047683716,395.6000061035156,0.0,100010.0,0.01209999993443489,290.3000183105469,-1.5,2.4000000953674316,7.806404696576303e-07
+2015-12-24 03:00:00,1.600000023841858,396.6000061035156,0.0,100050.0,0.01209999993443489,290.20001220703125,-2.0,2.5,7.799698656241153e-07
+2015-12-24 04:00:00,1.600000023841858,396.6000061035156,0.0,99960.0,0.011699999682605267,290.20001220703125,-1.3000000715255737,3.6000001430511475,0.0
+2015-12-24 05:00:00,0.0,396.6000061035156,0.0,100010.0,0.011799999512732029,289.8000183105469,-0.6000000238418579,4.700000286102295,0.0
+2015-12-24 06:00:00,0.0,392.8000183105469,0.0,99930.0,0.012199999764561653,290.3999938964844,0.10000000149011612,5.900000095367432,0.0
+2015-12-24 07:00:00,0.0,392.8000183105469,0.0,99960.0,0.012399999424815178,290.8000183105469,0.5,5.800000190734863,0.0
+2015-12-24 08:00:00,0.0,392.8000183105469,0.0,100010.0,0.012999999336898327,291.6000061035156,0.9000000357627869,5.800000190734863,0.0
+2015-12-24 09:00:00,0.0,379.6000061035156,0.0,99960.0,0.014099999330937862,293.3999938964844,1.3000000715255737,5.700000286102295,0.0
+2015-12-24 10:00:00,0.0,379.6000061035156,0.0,100010.0,0.014599999412894249,293.5,0.9000000357627869,4.700000286102295,0.0
+2015-12-24 11:00:00,0.0,379.6000061035156,0.0,100040.0,0.014599999412894249,293.8999938964844,0.5,3.700000047683716,0.0
+2015-12-24 12:00:00,0.0,379.20001220703125,0.0,100110.0,0.014699999243021011,293.70001220703125,0.0,2.700000047683716,0.0
+2015-12-24 13:00:00,0.0,379.20001220703125,49.5,100230.0,0.014699999243021011,294.0,0.699999988079071,3.0,0.0
+2015-12-24 14:00:00,0.0,379.20001220703125,155.6999969482422,100320.0,0.014599999412894249,294.20001220703125,1.3000000715255737,3.4000000953674316,0.0
+2015-12-24 15:00:00,0.0,397.6000061035156,267.3000183105469,100410.0,0.01489999983459711,294.8000183105469,2.0,3.799999952316284,0.0
+2015-12-24 16:00:00,0.0,397.6000061035156,332.1000061035156,100400.0,0.01489999983459711,295.6000061035156,3.1000001430511475,3.6000001430511475,0.0
+2015-12-24 17:00:00,0.0,397.6000061035156,354.1000061035156,100420.0,0.01529999915510416,295.1000061035156,4.099999904632568,3.4000000953674316,0.0
+2015-12-24 18:00:00,0.0,400.70001220703125,329.8000183105469,100330.0,0.015599999576807022,295.0,5.200000286102295,3.200000047683716,0.0
+2015-12-24 19:00:00,0.0,400.70001220703125,292.70001220703125,100360.0,0.01549999974668026,295.0,4.700000286102295,2.799999952316284,0.0
+2015-12-24 20:00:00,0.0,400.70001220703125,231.0,100360.0,0.01529999915510416,295.0,4.300000190734863,2.4000000953674316,0.0
+2015-12-24 21:00:00,0.0,403.8000183105469,93.20000457763672,100290.0,0.015199999324977398,295.20001220703125,3.799999952316284,2.0,0.0
+2015-12-24 22:00:00,0.0,403.8000183105469,20.80000114440918,100430.0,0.015699999406933784,294.8999938964844,2.4000000953674316,2.0,3.0511935942961847e-07
+2015-12-24 23:00:00,0.6000000238418579,403.8000183105469,0.0,100520.0,0.014999999664723873,294.5,1.0,2.0,7.599401290699011e-07
+2015-12-25 00:00:00,1.5,391.70001220703125,0.0,100450.0,0.014800000004470348,294.3999938964844,-0.4000000059604645,2.0,5.061538553138688e-08
+2015-12-25 01:00:00,0.10000000149011612,391.70001220703125,0.0,100600.0,0.013199999928474426,292.3999938964844,0.4000000059604645,1.899999976158142,0.0
+2015-12-25 02:00:00,0.0,391.70001220703125,0.0,100720.0,0.012600000016391277,291.8000183105469,1.2000000476837158,1.8000000715255737,0.0
+2015-12-25 03:00:00,0.0,379.20001220703125,0.0,100750.0,0.01269999984651804,291.8000183105469,2.0,1.7000000476837158,1.977323365029267e-07
+2015-12-25 04:00:00,0.4000000059604645,379.20001220703125,0.0,100800.0,0.01249999925494194,291.70001220703125,2.0,1.100000023841858,0.0
+2015-12-25 05:00:00,0.0,379.20001220703125,0.0,100790.0,0.012299999594688416,291.3000183105469,2.0,0.5,9.843137674574662e-08
+2015-12-25 06:00:00,0.20000000298023224,382.1000061035156,0.0,100810.0,0.01249999925494194,291.3999938964844,2.0,-0.10000000149011612,0.0
+2015-12-25 07:00:00,0.0,382.1000061035156,0.0,100770.0,0.012399999424815178,291.0,1.600000023841858,-0.30000001192092896,9.817343559310722e-08
+2015-12-25 08:00:00,0.20000000298023224,382.1000061035156,0.0,100770.0,0.01249999925494194,290.8000183105469,1.3000000715255737,-0.4000000059604645,0.0
+2015-12-25 09:00:00,0.0,386.20001220703125,0.0,100830.0,0.012199999764561653,290.8000183105469,0.9000000357627869,-0.6000000238418579,0.0
+2015-12-25 10:00:00,0.0,386.20001220703125,0.0,100760.0,0.011799999512732029,290.20001220703125,0.0,-0.30000001192092896,0.0
+2015-12-25 11:00:00,0.0,386.20001220703125,0.0,100790.0,0.011899999342858791,290.3999938964844,-0.9000000357627869,-0.10000000149011612,0.0
+2015-12-25 12:00:00,0.0,382.70001220703125,0.0,100870.0,0.01119999960064888,289.5,-1.7000000476837158,0.20000000298023224,0.0
+2015-12-25 13:00:00,0.0,382.70001220703125,55.29999923706055,100890.0,0.011799999512732029,289.6000061035156,-1.399999976158142,0.5,0.0
+2015-12-25 14:00:00,0.0,382.70001220703125,175.90000915527344,100880.0,0.012299999594688416,291.20001220703125,-1.100000023841858,0.800000011920929,0.0
+2015-12-25 15:00:00,0.0,391.3000183105469,320.20001220703125,100870.0,0.013399999588727951,293.0,-0.800000011920929,1.0,0.0
+2015-12-25 16:00:00,0.0,391.3000183105469,398.3000183105469,100910.0,0.013700000010430813,294.0,-0.30000001192092896,1.5,0.0
+2015-12-25 17:00:00,0.0,391.20001220703125,425.1000061035156,100780.0,0.014299999922513962,294.3000183105469,0.20000000298023224,2.1000001430511475,0.0
+2015-12-25 18:00:00,0.0,405.6000061035156,401.1000061035156,100700.0,0.01489999983459711,294.8999938964844,0.699999988079071,2.6000001430511475,0.0
+2015-12-25 19:00:00,0.0,405.6000061035156,356.20001220703125,100690.0,0.014800000004470348,296.20001220703125,1.100000023841858,2.5,0.0
+2015-12-25 20:00:00,0.0,405.6000061035156,281.6000061035156,100710.0,0.014999999664723873,296.3999938964844,1.600000023841858,2.4000000953674316,0.0
+2015-12-25 21:00:00,0.0,404.20001220703125,123.80000305175781,100660.0,0.015099999494850636,297.0,2.0,2.299999952316284,0.0
+2015-12-25 22:00:00,0.0,404.20001220703125,28.399999618530273,100720.0,0.015199999324977398,296.1000061035156,1.3000000715255737,2.0,0.0
+2015-12-25 23:00:00,0.0,404.20001220703125,0.0,100800.0,0.015399999916553497,295.1000061035156,0.699999988079071,1.8000000715255737,0.0
+2015-12-26 00:00:00,0.0,398.3000183105469,0.0,100870.0,0.014599999412894249,294.1000061035156,0.0,1.5,0.0
+2015-12-26 01:00:00,0.0,398.3000183105469,0.0,100890.0,0.013599999248981476,292.8999938964844,-0.4000000059604645,0.9000000357627869,7.488365405375216e-07
+2015-12-26 02:00:00,1.5,398.3000183105469,0.0,100970.0,0.013399999588727951,292.1000061035156,-0.9000000357627869,0.20000000298023224,0.0
+2015-12-26 03:00:00,0.0,397.8999938964844,0.0,100910.0,0.012899999506771564,291.70001220703125,-1.3000000715255737,-0.5,0.0
+2015-12-26 04:00:00,0.0,397.8999938964844,0.0,100900.0,0.01249999925494194,291.3000183105469,-1.2000000476837158,-0.6000000238418579,0.0
+2015-12-26 05:00:00,0.0,397.8999938964844,0.0,100910.0,0.011799999512732029,290.3000183105469,-1.0,-0.699999988079071,0.0
+2015-12-26 06:00:00,0.0,385.8999938964844,0.0,100880.0,0.012299999594688416,291.0,-0.800000011920929,-0.800000011920929,0.0
+2015-12-26 07:00:00,0.0,385.8999938964844,0.0,100940.0,0.011599999852478504,290.5,-1.3000000715255737,-0.6000000238418579,0.0
+2015-12-26 08:00:00,0.0,385.8999938964844,0.0,100930.0,0.011599999852478504,290.20001220703125,-1.7000000476837158,-0.5,0.0
+2015-12-26 09:00:00,0.0,379.5,0.0,100900.0,0.010799999348819256,289.3999938964844,-2.1000001430511475,-0.30000001192092896,0.0
+2015-12-26 10:00:00,0.0,379.5,0.0,100840.0,0.010799999348819256,289.1000061035156,-1.8000000715255737,-0.5,0.0
+2015-12-26 11:00:00,0.0,379.5,0.0,100760.0,0.011099999770522118,289.3999938964844,-1.5,-0.699999988079071,0.0
+2015-12-26 12:00:00,0.0,364.70001220703125,0.0,100780.0,0.01119999960064888,289.8000183105469,-1.2000000476837158,-0.9000000357627869,0.0
+2015-12-26 13:00:00,0.0,364.70001220703125,62.900001525878906,100880.0,0.010999999940395355,289.20001220703125,-1.3000000715255737,-0.800000011920929,0.0
+2015-12-26 14:00:00,0.0,364.70001220703125,202.40000915527344,100980.0,0.011699999682605267,290.8000183105469,-1.399999976158142,-0.800000011920929,0.0
+2015-12-26 15:00:00,0.0,376.6000061035156,354.8000183105469,101080.0,0.01269999984651804,292.5,-1.5,-0.699999988079071,0.0
+2015-12-26 16:00:00,0.0,376.6000061035156,442.0,101100.0,0.012999999336898327,294.0,-1.3000000715255737,0.20000000298023224,0.0
+2015-12-26 17:00:00,0.0,376.5,472.0,100970.0,0.013100000098347664,295.0,-1.100000023841858,1.0,0.0
+2015-12-26 18:00:00,0.0,386.6000061035156,470.6000061035156,100840.0,0.013399999588727951,296.0,-0.9000000357627869,1.899999976158142,0.0
+2015-12-26 19:00:00,0.0,386.6000061035156,418.3999938964844,100840.0,0.013599999248981476,297.3999938964844,-0.800000011920929,1.899999976158142,0.0
+2015-12-26 20:00:00,0.0,386.6000061035156,331.20001220703125,100780.0,0.013799999840557575,297.20001220703125,-0.800000011920929,1.8000000715255737,0.0
+2015-12-26 21:00:00,0.0,373.20001220703125,153.10000610351562,100780.0,0.013799999840557575,296.70001220703125,-0.699999988079071,1.8000000715255737,0.0
+2015-12-26 22:00:00,0.0,373.20001220703125,36.0,100790.0,0.013899999670684338,295.3000183105469,-1.3000000715255737,1.8000000715255737,0.0
+2015-12-26 23:00:00,0.0,373.20001220703125,0.0,100820.0,0.013899999670684338,293.8999938964844,-2.0,1.899999976158142,0.0
+2015-12-27 00:00:00,0.0,358.3999938964844,0.0,100880.0,0.013700000010430813,293.20001220703125,-2.6000001430511475,2.0,0.0
+2015-12-27 01:00:00,0.0,358.3999938964844,0.0,100850.0,0.013499999418854713,293.20001220703125,-2.6000001430511475,1.8000000715255737,0.0
+2015-12-27 02:00:00,0.0,358.3999938964844,0.0,100870.0,0.013299999758601189,292.5,-2.6000001430511475,1.600000023841858,0.0
+2015-12-27 03:00:00,0.0,351.20001220703125,0.0,100870.0,0.013599999248981476,292.1000061035156,-2.6000001430511475,1.5,0.0
+2015-12-27 04:00:00,0.0,351.20001220703125,0.0,100840.0,0.012999999336898327,291.70001220703125,-2.4000000953674316,1.600000023841858,0.0
+2015-12-27 05:00:00,0.0,351.20001220703125,0.0,100770.0,0.013399999588727951,292.3000183105469,-2.200000047683716,1.8000000715255737,0.0
+2015-12-27 06:00:00,0.0,359.8999938964844,0.0,100740.0,0.013399999588727951,292.20001220703125,-2.0,2.0,0.0
+2015-12-27 07:00:00,0.0,359.8999938964844,0.0,100680.0,0.013799999840557575,292.3999938964844,-1.899999976158142,1.8000000715255737,0.0
+2015-12-27 08:00:00,0.0,359.8999938964844,0.0,100750.0,0.013700000010430813,292.3000183105469,-1.8000000715255737,1.600000023841858,0.0
+2015-12-27 09:00:00,0.0,369.1000061035156,0.0,100630.0,0.013799999840557575,292.8000183105469,-1.600000023841858,1.399999976158142,0.0
+2015-12-27 10:00:00,0.0,369.1000061035156,0.0,100650.0,0.013799999840557575,292.5,-1.7000000476837158,1.399999976158142,0.0
+2015-12-27 11:00:00,0.0,369.1000061035156,0.0,100620.0,0.013700000010430813,292.70001220703125,-1.8000000715255737,1.399999976158142,0.0
+2015-12-27 12:00:00,0.0,366.3999938964844,0.0,100650.0,0.013499999418854713,292.3999938964844,-1.899999976158142,1.399999976158142,0.0
+2015-12-27 13:00:00,0.0,366.3999938964844,38.10000228881836,100620.0,0.012799999676644802,292.20001220703125,-1.3000000715255737,1.0,7.441386748887777e-07
+2015-12-27 14:00:00,1.5,366.3999938964844,123.9000015258789,100640.0,0.013199999928474426,292.20001220703125,-0.699999988079071,0.5,2.133197629303288e-06
+2015-12-27 15:00:00,4.300000190734863,391.1000061035156,208.8000030517578,100620.0,0.013399999588727951,292.20001220703125,-0.10000000149011612,0.0,0.0
+2015-12-27 16:00:00,0.0,391.0,260.20001220703125,100590.0,0.013599999248981476,293.1000061035156,0.20000000298023224,0.5,0.0
+2015-12-27 17:00:00,0.0,391.0,278.20001220703125,100480.0,0.0142000000923872,293.70001220703125,0.6000000238418579,1.0,0.0
+2015-12-27 18:00:00,0.0,394.5,305.3999938964844,100380.0,0.014299999922513962,294.20001220703125,1.0,1.5,0.0
+2015-12-27 19:00:00,0.0,394.5,271.8000183105469,100290.0,0.014699999243021011,295.5,1.0,1.600000023841858,0.0
+2015-12-27 20:00:00,0.0,394.3999938964844,215.5,100240.0,0.014499999582767487,295.8999938964844,1.100000023841858,1.7000000476837158,0.0
+2015-12-27 21:00:00,0.0,388.6000061035156,140.40000915527344,100200.0,0.014599999412894249,295.5,1.100000023841858,1.7000000476837158,0.0
+2015-12-27 22:00:00,0.0,388.6000061035156,33.900001525878906,100260.0,0.014599999412894249,294.8999938964844,0.4000000059604645,1.899999976158142,0.0
+2015-12-27 23:00:00,0.0,388.6000061035156,0.0,100270.0,0.014999999664723873,294.70001220703125,-0.30000001192092896,2.1000001430511475,0.0
+2015-12-28 00:00:00,0.0,373.20001220703125,0.0,100260.0,0.014499999582767487,293.6000061035156,-1.0,2.299999952316284,0.0
+2015-12-28 01:00:00,0.0,373.20001220703125,0.0,100310.0,0.013499999418854713,291.8999938964844,-1.2000000476837158,2.299999952316284,0.0
+2015-12-28 02:00:00,0.0,373.20001220703125,0.0,100320.0,0.012999999336898327,291.70001220703125,-1.399999976158142,2.200000047683716,0.0
+2015-12-28 03:00:00,0.0,338.8999938964844,0.0,100320.0,0.012899999506771564,291.3999938964844,-1.600000023841858,2.200000047683716,0.0
+2015-12-28 04:00:00,0.0,338.8999938964844,0.0,100370.0,0.012799999676644802,291.6000061035156,-1.7000000476837158,2.200000047683716,0.0
+2015-12-28 05:00:00,0.0,338.8999938964844,0.0,100340.0,0.012799999676644802,291.1000061035156,-1.8000000715255737,2.200000047683716,0.0
+2015-12-28 06:00:00,0.0,342.3000183105469,0.0,100290.0,0.013499999418854713,291.8999938964844,-1.899999976158142,2.200000047683716,0.0
+2015-12-28 07:00:00,0.0,342.3000183105469,0.0,100300.0,0.013399999588727951,291.8999938964844,-2.1000001430511475,1.7000000476837158,0.0
+2015-12-28 08:00:00,0.0,342.3000183105469,0.0,100340.0,0.013299999758601189,291.70001220703125,-2.4000000953674316,1.100000023841858,0.0
+2015-12-28 09:00:00,0.0,342.1000061035156,0.0,100280.0,0.013299999758601189,291.70001220703125,-2.700000047683716,0.6000000238418579,0.0
+2015-12-28 10:00:00,0.0,342.1000061035156,0.0,100280.0,0.012999999336898327,291.70001220703125,-2.700000047683716,0.5,0.0
+2015-12-28 11:00:00,0.0,342.1000061035156,0.0,100250.0,0.012899999506771564,291.5,-2.700000047683716,0.5,0.0
+2015-12-28 12:00:00,0.0,349.5,0.0,100320.0,0.012799999676644802,291.20001220703125,-2.700000047683716,0.5,0.0
+2015-12-28 13:00:00,0.0,349.5,51.5,100330.0,0.012899999506771564,291.70001220703125,-2.700000047683716,0.10000000149011612,0.0
+2015-12-28 14:00:00,0.0,349.5,169.0,100350.0,0.012899999506771564,291.6000061035156,-2.700000047683716,-0.20000000298023224,0.0
+2015-12-28 15:00:00,0.0,388.6000061035156,240.6999969482422,100330.0,0.013299999758601189,292.20001220703125,-2.700000047683716,-0.5,0.0
+2015-12-28 16:00:00,0.0,388.6000061035156,300.3999938964844,100370.0,0.0142000000923872,293.0,-3.4000000953674316,0.0,0.0
+2015-12-28 17:00:00,0.0,388.5,321.3999938964844,100250.0,0.014599999412894249,293.70001220703125,-4.099999904632568,0.5,0.0
+2015-12-28 18:00:00,0.0,413.5,234.5,100190.0,0.014699999243021011,294.6000061035156,-4.800000190734863,1.0,0.0
+2015-12-28 19:00:00,0.0,413.5,208.90000915527344,100100.0,0.014599999412894249,296.1000061035156,-5.200000286102295,1.100000023841858,0.0
+2015-12-28 20:00:00,0.0,413.5,165.8000030517578,99980.0,0.013799999840557575,296.6000061035156,-5.599999904632568,1.3000000715255737,0.0
+2015-12-28 21:00:00,0.0,390.0,130.5,99910.0,0.013700000010430813,295.8999938964844,-6.0,1.399999976158142,0.0
+2015-12-28 22:00:00,0.0,390.0,32.400001525878906,99950.0,0.0139999995008111,295.1000061035156,-6.400000095367432,1.8000000715255737,0.0
+2015-12-28 23:00:00,0.0,390.1000061035156,0.0,99940.0,0.014999999664723873,294.6000061035156,-6.900000095367432,2.200000047683716,0.0
+2015-12-29 00:00:00,0.0,380.1000061035156,0.0,99970.0,0.01489999983459711,294.6000061035156,-7.400000095367432,2.6000001430511475,0.0
+2015-12-29 01:00:00,0.0,380.1000061035156,0.0,99980.0,0.01549999974668026,295.1000061035156,-6.300000190734863,2.6000001430511475,0.0
+2015-12-29 02:00:00,0.0,380.1000061035156,0.0,99940.0,0.015799999237060547,295.3999938964844,-5.300000190734863,2.6000001430511475,0.0
+2015-12-29 03:00:00,0.0,388.70001220703125,0.0,99940.0,0.01529999915510416,295.1000061035156,-4.300000190734863,2.6000001430511475,2.0379742621031308e-07
+2015-12-29 04:00:00,0.4000000059604645,388.70001220703125,0.0,99940.0,0.015399999916553497,295.0,-3.299999952316284,3.200000047683716,5.090121965577734e-08
+2015-12-29 05:00:00,0.10000000149011612,388.70001220703125,0.0,99950.0,0.014999999664723873,294.70001220703125,-2.299999952316284,3.9000000953674316,1.1166688889383383e-06
+2015-12-29 06:00:00,2.200000047683716,398.3999938964844,0.0,99910.0,0.014800000004470348,294.20001220703125,-1.3000000715255737,4.5,1.1619883724544963e-06
+2015-12-29 07:00:00,2.299999952316284,398.3999938964844,0.0,99880.0,0.014999999664723873,294.8000183105469,-0.20000000298023224,4.900000095367432,2.591074675310334e-06
+2015-12-29 08:00:00,5.099999904632568,398.3999938964844,0.0,99870.0,0.014499999582767487,294.3999938964844,0.800000011920929,5.300000190734863,2.9863077501229664e-06
+2015-12-29 09:00:00,5.900000095367432,387.5,0.0,99900.0,0.014299999922513962,293.5,1.8000000715255737,5.700000286102295,7.529397965630518e-07
+2015-12-29 10:00:00,1.5,387.5,0.0,99920.0,0.0139999995008111,293.20001220703125,2.4000000953674316,5.0,5.506448621350923e-07
+2015-12-29 11:00:00,1.100000023841858,387.5,0.0,99960.0,0.014399999752640724,293.3000183105469,3.1000001430511475,4.400000095367432,0.0
+2015-12-29 12:00:00,0.0,381.5,0.0,99990.0,0.0139999995008111,293.3000183105469,3.700000047683716,3.799999952316284,0.0
+2015-12-29 13:00:00,0.0,381.5,35.5,100080.0,0.0139999995008111,293.1000061035156,3.5,3.6000001430511475,0.0
+2015-12-29 14:00:00,0.0,381.5,117.5999984741211,100180.0,0.0142000000923872,293.3000183105469,3.4000000953674316,3.5,0.0
+2015-12-29 15:00:00,0.0,373.70001220703125,246.90000915527344,100210.0,0.014800000004470348,294.8000183105469,3.200000047683716,3.4000000953674316,0.0
+2015-12-29 16:00:00,0.0,373.70001220703125,308.3999938964844,100230.0,0.014099999330937862,294.5,3.4000000953674316,3.5,0.0
+2015-12-29 17:00:00,0.0,373.70001220703125,330.20001220703125,100220.0,0.013700000010430813,294.3999938964844,3.6000001430511475,3.6000001430511475,0.0
+2015-12-29 18:00:00,0.0,375.20001220703125,375.70001220703125,100160.0,0.013299999758601189,294.8000183105469,3.700000047683716,3.700000047683716,0.0
+2015-12-29 19:00:00,0.0,375.20001220703125,335.1000061035156,100100.0,0.013599999248981476,296.8999938964844,3.299999952316284,3.4000000953674316,0.0
+2015-12-29 20:00:00,0.0,375.20001220703125,266.5,100140.0,0.013599999248981476,296.8999938964844,2.9000000953674316,3.1000001430511475,0.0
+2015-12-29 21:00:00,0.0,365.6000061035156,145.5,100170.0,0.013399999588727951,296.3999938964844,2.5,2.799999952316284,0.0
+2015-12-29 22:00:00,0.0,365.6000061035156,37.0,100250.0,0.01249999925494194,295.3000183105469,2.200000047683716,2.4000000953674316,0.0
+2015-12-29 23:00:00,0.0,365.6000061035156,0.0,100310.0,0.013299999758601189,293.70001220703125,1.899999976158142,2.0,0.0
+2015-12-30 00:00:00,0.0,337.70001220703125,0.0,100400.0,0.013299999758601189,292.70001220703125,1.600000023841858,1.600000023841858,0.0
+2015-12-30 01:00:00,0.0,337.70001220703125,0.0,100430.0,0.013199999928474426,292.6000061035156,1.2000000476837158,1.5,0.0
+2015-12-30 02:00:00,0.0,337.70001220703125,0.0,100530.0,0.012899999506771564,291.70001220703125,0.800000011920929,1.399999976158142,0.0
+2015-12-30 03:00:00,0.0,336.8999938964844,0.0,100520.0,0.01269999984651804,291.20001220703125,0.4000000059604645,1.2000000476837158,0.0
+2015-12-30 04:00:00,0.0,336.8999938964844,0.0,100570.0,0.012399999424815178,290.8999938964844,0.20000000298023224,1.3000000715255737,0.0
+2015-12-30 05:00:00,0.0,336.8999938964844,0.0,100590.0,0.011599999852478504,289.8999938964844,0.0,1.3000000715255737,0.0
+2015-12-30 06:00:00,0.0,353.0,0.0,100620.0,0.012000000104308128,290.1000061035156,-0.20000000298023224,1.3000000715255737,0.0
+2015-12-30 07:00:00,0.0,353.0,0.0,100610.0,0.011899999342858791,290.5,-0.6000000238418579,0.800000011920929,0.0
+2015-12-30 08:00:00,0.0,353.0,0.0,100590.0,0.012000000104308128,290.3999938964844,-1.0,0.20000000298023224,0.0
+2015-12-30 09:00:00,0.0,392.3999938964844,0.0,100630.0,0.011899999342858791,290.3999938964844,-1.399999976158142,-0.4000000059604645,3.418243187032877e-07
+2015-12-30 10:00:00,0.699999988079071,392.3999938964844,0.0,100590.0,0.012399999424815178,290.6000061035156,-1.3000000715255737,-0.20000000298023224,6.848304672955347e-07
+2015-12-30 11:00:00,1.399999976158142,392.3999938964844,0.0,100560.0,0.01249999925494194,291.1000061035156,-1.3000000715255737,0.0,0.0
+2015-12-30 12:00:00,0.0,396.8000183105469,0.0,100510.0,0.01269999984651804,291.3000183105469,-1.3000000715255737,0.20000000298023224,0.0
+2015-12-30 13:00:00,0.0,396.8000183105469,24.600000381469727,100620.0,0.012600000016391277,291.70001220703125,-0.699999988079071,0.20000000298023224,0.0
+2015-12-30 14:00:00,0.0,396.8000183105469,82.0999984741211,100630.0,0.013399999588727951,292.5,-0.20000000298023224,0.10000000149011612,4.9742695856783285e-08
+2015-12-30 15:00:00,0.10000000149011612,400.3000183105469,134.60000610351562,100600.0,0.014099999330937862,293.5,0.30000001192092896,0.0,4.2164631479768285e-06
+2015-12-30 16:00:00,8.40000057220459,400.3000183105469,168.3000030517578,100640.0,0.0139999995008111,292.3999938964844,0.5,0.6000000238418579,1.7294931218208543e-05
+2015-12-30 17:00:00,34.79999923706055,400.3000183105469,180.3000030517578,100590.0,0.012999999336898327,291.5,0.699999988079071,1.3000000715255737,3.599065574767947e-06
+2015-12-30 18:00:00,7.300000190734863,402.20001220703125,183.3000030517578,100610.0,0.012600000016391277,290.8999938964844,0.800000011920929,2.0,2.305066719490677e-06
+2015-12-30 19:00:00,4.700000286102295,402.20001220703125,163.60000610351562,100560.0,0.01249999925494194,291.0,0.800000011920929,1.899999976158142,1.816208554815238e-06
+2015-12-30 20:00:00,3.700000047683716,402.20001220703125,130.3000030517578,100490.0,0.012799999676644802,291.0,0.800000011920929,1.8000000715255737,2.061642257172614e-06
+2015-12-30 21:00:00,4.200000286102295,399.20001220703125,80.4000015258789,100470.0,0.012600000016391277,291.1000061035156,0.800000011920929,1.7000000476837158,4.07775568914086e-06
+2015-12-30 22:00:00,8.300000190734863,399.20001220703125,21.0,100450.0,0.012600000016391277,290.8999938964844,1.0,1.399999976158142,1.6184509790133084e-06
+2015-12-30 23:00:00,3.299999952316284,399.20001220703125,0.0,100520.0,0.01269999984651804,291.1000061035156,1.2000000476837158,1.2000000476837158,6.878141851067213e-07
diff --git a/python/runCalibValid/ngen_cal/tests/data/cat-89_2015-12-01 00_00_00_2015-12-30 23_00_00.csv b/python/runCalibValid/ngen_cal/tests/data/cat-89_2015-12-01 00_00_00_2015-12-30 23_00_00.csv
new file mode 100644
index 00000000..7ce270c7
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/cat-89_2015-12-01 00_00_00_2015-12-30 23_00_00.csv
@@ -0,0 +1,721 @@
+time,APCP_surface,DLWRF_surface,DSWRF_surface,PRES_surface,SPFH_2maboveground,TMP_2maboveground,UGRD_10maboveground,VGRD_10maboveground,precip_rate
+2015-12-01 00:00:00,0.0,361.20001220703125,0.0,100530.0,0.010499999858438969,287.5,-2.6000001430511475,0.0,0.0
+2015-12-01 01:00:00,0.0,361.20001220703125,0.0,100610.0,0.009800000116229057,287.3000183105469,-2.700000047683716,-0.30000001192092896,0.0
+2015-12-01 02:00:00,0.0,361.20001220703125,0.0,100600.0,0.009099999442696571,286.6000061035156,-2.799999952316284,-0.6000000238418579,0.0
+2015-12-01 03:00:00,0.0,357.6000061035156,0.0,100570.0,0.008700000122189522,285.5,-2.9000000953674316,-0.9000000357627869,0.0
+2015-12-01 04:00:00,0.0,357.6000061035156,0.0,100590.0,0.00839999970048666,284.3000183105469,-2.6000001430511475,-0.30000001192092896,0.0
+2015-12-01 05:00:00,0.0,357.6000061035156,0.0,100540.0,0.007999999448657036,283.8999938964844,-2.299999952316284,0.4000000059604645,0.0
+2015-12-01 06:00:00,0.0,344.1000061035156,0.0,100510.0,0.007699999958276749,283.6000061035156,-2.0,1.0,0.0
+2015-12-01 07:00:00,0.0,344.1000061035156,0.0,100490.0,0.007400000002235174,283.20001220703125,-2.1000001430511475,0.699999988079071,0.0
+2015-12-01 08:00:00,0.0,344.1000061035156,0.0,100550.0,0.007199999876320362,282.8999938964844,-2.200000047683716,0.5,0.0
+2015-12-01 09:00:00,0.0,335.0,0.0,100460.0,0.00699999975040555,282.5,-2.299999952316284,0.20000000298023224,0.0
+2015-12-01 10:00:00,0.0,335.0,0.0,100470.0,0.00699999975040555,282.3000183105469,-2.4000000953674316,0.6000000238418579,0.0
+2015-12-01 11:00:00,0.0,335.0,0.0,100480.0,0.0071000000461936,282.3000183105469,-2.4000000953674316,0.9000000357627869,0.0
+2015-12-01 12:00:00,0.0,350.3999938964844,0.0,100530.0,0.00699999975040555,282.0,-2.4000000953674316,1.3000000715255737,0.0
+2015-12-01 13:00:00,0.0,350.3999938964844,85.0999984741211,100560.0,0.00699999975040555,281.8999938964844,-2.6000001430511475,1.2000000476837158,0.0
+2015-12-01 14:00:00,0.0,350.3000183105469,195.40000915527344,100610.0,0.006899999920278788,282.5,-2.700000047683716,1.100000023841858,0.0
+2015-12-01 15:00:00,0.0,397.0,220.0,100600.0,0.00699999975040555,282.3999938964844,-2.9000000953674316,1.0,0.0
+2015-12-01 16:00:00,0.0,397.0,264.70001220703125,100520.0,0.007199999876320362,282.8000183105469,-2.200000047683716,1.7000000476837158,0.0
+2015-12-01 17:00:00,0.0,397.0,276.5,100510.0,0.007499999832361937,283.1000061035156,-1.5,2.299999952316284,0.0
+2015-12-01 18:00:00,0.0,385.3999938964844,395.20001220703125,100400.0,0.007699999958276749,283.5,-0.800000011920929,3.0,0.0
+2015-12-01 19:00:00,0.0,385.3999938964844,345.6000061035156,100340.0,0.008100000210106373,284.3999938964844,-0.800000011920929,2.9000000953674316,0.0
+2015-12-01 20:00:00,0.0,385.3999938964844,268.20001220703125,100310.0,0.008200000040233135,284.70001220703125,-0.9000000357627869,2.799999952316284,0.0
+2015-12-01 21:00:00,0.0,394.3000183105469,120.5999984741211,100160.0,0.008200000040233135,284.3999938964844,-0.9000000357627869,2.700000047683716,0.0
+2015-12-01 22:00:00,0.0,394.3000183105469,21.0,100200.0,0.00839999970048666,285.1000061035156,-1.3000000715255737,2.299999952316284,0.0
+2015-12-01 23:00:00,0.0,394.3000183105469,0.0,100240.0,0.008599999360740185,285.1000061035156,-1.7000000476837158,1.8000000715255737,0.0
+2015-12-02 00:00:00,0.0,383.3000183105469,0.0,100190.0,0.008599999360740185,285.20001220703125,-2.1000001430511475,1.399999976158142,0.0
+2015-12-02 01:00:00,0.0,383.3000183105469,0.0,100240.0,0.008799999952316284,285.3000183105469,-2.0,1.3000000715255737,0.0
+2015-12-02 02:00:00,0.0,383.3000183105469,0.0,100210.0,0.008799999952316284,285.6000061035156,-2.0,1.100000023841858,0.0
+2015-12-02 03:00:00,0.0,371.3999938964844,0.0,100120.0,0.008899999782443047,285.70001220703125,-2.0,1.0,0.0
+2015-12-02 04:00:00,0.0,371.3999938964844,0.0,100070.0,0.009200000204145908,285.8000183105469,-1.8000000715255737,1.600000023841858,0.0
+2015-12-02 05:00:00,0.0,371.3999938964844,0.0,100010.0,0.008899999782443047,285.70001220703125,-1.7000000476837158,2.1000001430511475,0.0
+2015-12-02 06:00:00,0.0,369.1000061035156,0.0,99970.0,0.009099999442696571,285.8999938964844,-1.600000023841858,2.700000047683716,0.0
+2015-12-02 07:00:00,0.0,369.20001220703125,0.0,99880.0,0.009399999864399433,286.1000061035156,-1.600000023841858,3.0,0.0
+2015-12-02 08:00:00,0.0,369.20001220703125,0.0,99870.0,0.009800000116229057,287.0,-1.7000000476837158,3.4000000953674316,9.493307095661946e-08
+2015-12-02 09:00:00,0.20000000298023224,370.6000061035156,0.0,99740.0,0.00969999935477972,286.70001220703125,-1.7000000476837158,3.799999952316284,0.0
+2015-12-02 10:00:00,0.0,370.6000061035156,0.0,99720.0,0.010499999858438969,288.0,-1.600000023841858,3.700000047683716,0.0
+2015-12-02 11:00:00,0.0,370.6000061035156,0.0,99710.0,0.010999999940395355,288.6000061035156,-1.5,3.6000001430511475,0.0
+2015-12-02 12:00:00,0.0,380.8999938964844,0.0,99710.0,0.01119999960064888,289.3999938964844,-1.399999976158142,3.4000000953674316,0.0
+2015-12-02 13:00:00,0.0,380.8999938964844,72.5,99740.0,0.011699999682605267,289.70001220703125,-0.699999988079071,3.4000000953674316,0.0
+2015-12-02 14:00:00,0.0,380.8000183105469,168.60000610351562,99710.0,0.01209999993443489,290.3000183105469,0.0,3.299999952316284,2.439501431328691e-07
+2015-12-02 15:00:00,0.5,405.1000061035156,130.8000030517578,99850.0,0.012000000104308128,290.3000183105469,0.699999988079071,3.299999952316284,3.9032023482881514e-07
+2015-12-02 16:00:00,0.800000011920929,405.1000061035156,157.5,99840.0,0.011699999682605267,289.8000183105469,1.3000000715255737,3.4000000953674316,9.716329458139992e-08
+2015-12-02 17:00:00,0.20000000298023224,405.1000061035156,164.6999969482422,99710.0,0.011799999512732029,290.1000061035156,1.899999976158142,3.5,0.0
+2015-12-02 18:00:00,0.0,397.5,145.10000610351562,99550.0,0.011699999682605267,290.3999938964844,2.5,3.6000001430511475,0.0
+2015-12-02 19:00:00,0.0,397.5,126.9000015258789,99520.0,0.011399999260902405,290.20001220703125,3.299999952316284,3.5,0.0
+2015-12-02 20:00:00,0.0,397.5,98.5,99400.0,0.011699999682605267,290.0,4.099999904632568,3.5,0.0
+2015-12-02 21:00:00,0.0,376.20001220703125,67.70000457763672,99390.0,0.01209999993443489,290.3999938964844,4.900000095367432,3.4000000953674316,0.0
+2015-12-02 22:00:00,0.0,376.20001220703125,11.699999809265137,99410.0,0.01119999960064888,289.8999938964844,5.0,3.9000000953674316,0.0
+2015-12-02 23:00:00,0.0,376.20001220703125,0.0,99530.0,0.008799999952316284,289.0,5.0,4.5,0.0
+2015-12-03 00:00:00,0.0,350.8000183105469,0.0,99570.0,0.0072999997064471245,287.3000183105469,5.099999904632568,5.099999904632568,0.0
+2015-12-03 01:00:00,0.0,350.8000183105469,0.0,99600.0,0.0066999997943639755,286.20001220703125,4.900000095367432,4.400000095367432,0.0
+2015-12-03 02:00:00,0.0,350.8999938964844,0.0,99680.0,0.0064999996684491634,285.8000183105469,4.800000190734863,3.799999952316284,0.0
+2015-12-03 03:00:00,0.0,296.70001220703125,0.0,99700.0,0.006199999712407589,284.8999938964844,4.599999904632568,3.1000001430511475,0.0
+2015-12-03 04:00:00,0.0,296.70001220703125,0.0,99740.0,0.006000000052154064,284.3000183105469,4.5,2.200000047683716,0.0
+2015-12-03 05:00:00,0.0,296.70001220703125,0.0,99850.0,0.006000000052154064,283.3999938964844,4.400000095367432,1.399999976158142,0.0
+2015-12-03 06:00:00,0.0,279.3999938964844,0.0,99880.0,0.0058999997563660145,282.8000183105469,4.200000286102295,0.5,0.0
+2015-12-03 07:00:00,0.0,279.3999938964844,0.0,99930.0,0.0058999997563660145,282.20001220703125,3.700000047683716,-0.20000000298023224,0.0
+2015-12-03 08:00:00,0.0,279.3999938964844,0.0,100020.0,0.005799999926239252,281.6000061035156,3.299999952316284,-0.9000000357627869,0.0
+2015-12-03 09:00:00,0.0,257.1000061035156,0.0,100040.0,0.005799999926239252,281.0,2.799999952316284,-1.600000023841858,0.0
+2015-12-03 10:00:00,0.0,257.1000061035156,0.0,100130.0,0.005699999630451202,280.6000061035156,2.200000047683716,-2.1000001430511475,0.0
+2015-12-03 11:00:00,0.0,257.1000061035156,0.0,100240.0,0.005499999970197678,280.5,1.600000023841858,-2.6000001430511475,0.0
+2015-12-03 12:00:00,0.0,254.0,0.0,100340.0,0.004999999888241291,279.70001220703125,1.0,-3.1000001430511475,0.0
+2015-12-03 13:00:00,0.0,254.0,111.5999984741211,100460.0,0.004799999762326479,279.70001220703125,0.20000000298023224,-3.9000000953674316,0.0
+2015-12-03 14:00:00,0.0,254.0,263.1000061035156,100550.0,0.00419999985024333,281.20001220703125,-0.6000000238418579,-4.800000190734863,0.0
+2015-12-03 15:00:00,0.0,268.0,390.6000061035156,100680.0,0.003599999938160181,282.3999938964844,-1.399999976158142,-5.599999904632568,0.0
+2015-12-03 16:00:00,0.0,268.0,471.3000183105469,100720.0,0.003499999875202775,283.1000061035156,-1.7000000476837158,-5.200000286102295,0.0
+2015-12-03 17:00:00,0.0,268.0,493.3000183105469,100690.0,0.003599999938160181,283.5,-2.0,-4.900000095367432,0.0
+2015-12-03 18:00:00,0.0,270.8999938964844,491.8999938964844,100700.0,0.003499999875202775,283.6000061035156,-2.299999952316284,-4.5,0.0
+2015-12-03 19:00:00,0.0,270.8999938964844,430.6000061035156,100660.0,0.003700000001117587,283.8000183105469,-1.899999976158142,-4.300000190734863,0.0
+2015-12-03 20:00:00,0.0,270.8999938964844,334.1000061035156,100750.0,0.003599999938160181,283.8999938964844,-1.600000023841858,-4.099999904632568,0.0
+2015-12-03 21:00:00,0.0,255.8000030517578,180.6999969482422,100750.0,0.0037999998312443495,283.3000183105469,-1.3000000715255737,-3.9000000953674316,0.0
+2015-12-03 22:00:00,0.0,255.8000030517578,30.899999618530273,100870.0,0.003999999724328518,282.1000061035156,-1.399999976158142,-3.700000047683716,0.0
+2015-12-03 23:00:00,0.0,255.8000030517578,0.0,100930.0,0.004299999680370092,280.3000183105469,-1.5,-3.4000000953674316,0.0
+2015-12-04 00:00:00,0.0,236.6999969482422,0.0,101010.0,0.00419999985024333,280.3000183105469,-1.5,-3.1000001430511475,0.0
+2015-12-04 01:00:00,0.0,236.6999969482422,0.0,101130.0,0.004299999680370092,279.6000061035156,-1.7000000476837158,-3.1000001430511475,0.0
+2015-12-04 02:00:00,0.0,236.6999969482422,0.0,101170.0,0.00419999985024333,278.70001220703125,-1.8000000715255737,-3.0,0.0
+2015-12-04 03:00:00,0.0,229.5,0.0,101260.0,0.004299999680370092,278.3000183105469,-1.899999976158142,-2.9000000953674316,0.0
+2015-12-04 04:00:00,0.0,229.5,0.0,101300.0,0.00419999985024333,277.6000061035156,-2.0,-2.9000000953674316,0.0
+2015-12-04 05:00:00,0.0,229.5,0.0,101270.0,0.003999999724328518,277.5,-2.0,-2.799999952316284,0.0
+2015-12-04 06:00:00,0.0,222.5,0.0,101270.0,0.003700000001117587,277.70001220703125,-2.0,-2.799999952316284,0.0
+2015-12-04 07:00:00,0.0,222.5,0.0,101400.0,0.0037999998312443495,277.3999938964844,-1.600000023841858,-2.9000000953674316,0.0
+2015-12-04 08:00:00,0.0,222.5,0.0,101460.0,0.003700000001117587,276.3999938964844,-1.2000000476837158,-3.1000001430511475,0.0
+2015-12-04 09:00:00,0.0,217.0,0.0,101450.0,0.003599999938160181,275.3999938964844,-0.800000011920929,-3.200000047683716,0.0
+2015-12-04 10:00:00,0.0,217.0,0.0,101510.0,0.003399999812245369,274.8000183105469,-0.9000000357627869,-3.1000001430511475,0.0
+2015-12-04 11:00:00,0.0,217.0,0.0,101540.0,0.003399999812245369,274.3000183105469,-1.100000023841858,-3.0,0.0
+2015-12-04 12:00:00,0.0,220.3000030517578,0.0,101610.0,0.0032999999821186066,273.6000061035156,-1.3000000715255737,-2.9000000953674316,0.0
+2015-12-04 13:00:00,0.0,220.1999969482422,111.0,101730.0,0.003499999875202775,274.1000061035156,-1.5,-3.200000047683716,0.0
+2015-12-04 14:00:00,0.0,220.1999969482422,265.0,101770.0,0.003700000001117587,276.8999938964844,-1.600000023841858,-3.4000000953674316,0.0
+2015-12-04 15:00:00,0.0,239.60000610351562,424.20001220703125,101810.0,0.003499999875202775,279.5,-1.8000000715255737,-3.700000047683716,0.0
+2015-12-04 16:00:00,0.0,239.60000610351562,512.7000122070312,101760.0,0.003399999812245369,281.8999938964844,-2.4000000953674316,-3.799999952316284,0.0
+2015-12-04 17:00:00,0.0,239.60000610351562,537.1000366210938,101720.0,0.0032999999821186066,283.70001220703125,-3.0,-3.799999952316284,0.0
+2015-12-04 18:00:00,0.0,248.0,520.2999877929688,101680.0,0.0032999999821186066,284.70001220703125,-3.6000001430511475,-3.9000000953674316,0.0
+2015-12-04 19:00:00,0.0,248.0,455.6000061035156,101630.0,0.0031999999191612005,285.5,-3.4000000953674316,-3.700000047683716,0.0
+2015-12-04 20:00:00,0.0,248.10000610351562,353.6000061035156,101600.0,0.0031999999191612005,285.3000183105469,-3.200000047683716,-3.5,0.0
+2015-12-04 21:00:00,0.0,238.3000030517578,155.40000915527344,101600.0,0.0031999999191612005,285.5,-3.0,-3.299999952316284,0.0
+2015-12-04 22:00:00,0.0,238.3000030517578,26.399999618530273,101680.0,0.0032999999821186066,284.1000061035156,-2.1000001430511475,-3.4000000953674316,0.0
+2015-12-04 23:00:00,0.0,238.3000030517578,0.0,101620.0,0.003700000001117587,280.3000183105469,-1.3000000715255737,-3.5,0.0
+2015-12-05 00:00:00,0.0,226.3000030517578,0.0,101720.0,0.0037999998312443495,279.0,-0.4000000059604645,-3.6000001430511475,0.0
+2015-12-05 01:00:00,0.0,226.3000030517578,0.0,101740.0,0.003700000001117587,277.0,-0.699999988079071,-3.4000000953674316,0.0
+2015-12-05 02:00:00,0.0,226.3000030517578,0.0,101830.0,0.003700000001117587,277.0,-1.100000023841858,-3.200000047683716,0.0
+2015-12-05 03:00:00,0.0,222.60000610351562,0.0,101890.0,0.003700000001117587,276.6000061035156,-1.399999976158142,-3.0,0.0
+2015-12-05 04:00:00,0.0,222.60000610351562,0.0,101860.0,0.003599999938160181,276.0,-1.399999976158142,-3.0,0.0
+2015-12-05 05:00:00,0.0,222.60000610351562,0.0,101850.0,0.003599999938160181,274.20001220703125,-1.3000000715255737,-3.0,0.0
+2015-12-05 06:00:00,0.0,220.8000030517578,0.0,101800.0,0.003499999875202775,273.8999938964844,-1.3000000715255737,-3.0,0.0
+2015-12-05 07:00:00,0.0,220.8000030517578,0.0,101920.0,0.003499999875202775,273.8000183105469,-1.3000000715255737,-3.0,0.0
+2015-12-05 08:00:00,0.0,220.8000030517578,0.0,101980.0,0.0032999999821186066,272.3999938964844,-1.2000000476837158,-3.1000001430511475,0.0
+2015-12-05 09:00:00,0.0,221.60000610351562,0.0,101960.0,0.0032999999821186066,272.6000061035156,-1.2000000476837158,-3.1000001430511475,0.0
+2015-12-05 10:00:00,0.0,221.60000610351562,0.0,102000.0,0.0031999999191612005,272.6000061035156,-1.3000000715255737,-3.0,0.0
+2015-12-05 11:00:00,0.0,221.60000610351562,0.0,102040.0,0.0032999999821186066,273.3999938964844,-1.399999976158142,-2.9000000953674316,0.0
+2015-12-05 12:00:00,0.0,227.8000030517578,0.0,102080.0,0.0032999999821186066,272.8000183105469,-1.5,-2.799999952316284,0.0
+2015-12-05 13:00:00,0.0,227.8000030517578,106.9000015258789,102150.0,0.003599999938160181,273.70001220703125,-1.7000000476837158,-3.200000047683716,0.0
+2015-12-05 14:00:00,0.0,227.8000030517578,258.8000183105469,102200.0,0.003599999938160181,277.1000061035156,-1.899999976158142,-3.6000001430511475,0.0
+2015-12-05 15:00:00,0.0,253.8000030517578,414.5,102230.0,0.003599999938160181,279.8999938964844,-2.1000001430511475,-3.9000000953674316,0.0
+2015-12-05 16:00:00,0.0,253.8000030517578,501.8000183105469,102180.0,0.003499999875202775,282.70001220703125,-2.5,-3.9000000953674316,0.0
+2015-12-05 17:00:00,0.0,253.8000030517578,526.1000366210938,102070.0,0.003399999812245369,284.20001220703125,-2.9000000953674316,-3.9000000953674316,0.0
+2015-12-05 18:00:00,0.0,269.0,507.20001220703125,101960.0,0.003399999812245369,285.5,-3.299999952316284,-3.799999952316284,0.0
+2015-12-05 19:00:00,0.0,269.0,444.3000183105469,101880.0,0.003499999875202775,286.70001220703125,-3.0,-3.700000047683716,0.0
+2015-12-05 20:00:00,0.0,269.0,344.8999938964844,101860.0,0.003599999938160181,287.20001220703125,-2.6000001430511475,-3.6000001430511475,0.0
+2015-12-05 21:00:00,0.0,261.20001220703125,149.0,101890.0,0.003499999875202775,286.3999938964844,-2.299999952316284,-3.5,0.0
+2015-12-05 22:00:00,0.0,261.3000183105469,25.200000762939453,101950.0,0.003700000001117587,285.20001220703125,-2.200000047683716,-3.299999952316284,0.0
+2015-12-05 23:00:00,0.0,261.3000183105469,0.0,101960.0,0.003999999724328518,282.3999938964844,-2.200000047683716,-3.1000001430511475,0.0
+2015-12-06 00:00:00,0.0,250.1999969482422,0.0,101960.0,0.0037999998312443495,281.0,-2.200000047683716,-2.9000000953674316,0.0
+2015-12-06 01:00:00,0.0,250.1999969482422,0.0,102030.0,0.0037999998312443495,280.5,-2.200000047683716,-2.9000000953674316,0.0
+2015-12-06 02:00:00,0.0,250.1999969482422,0.0,102060.0,0.0038999998942017555,279.8000183105469,-2.200000047683716,-3.0,0.0
+2015-12-06 03:00:00,0.0,251.1999969482422,0.0,102000.0,0.0038999998942017555,278.8000183105469,-2.200000047683716,-3.0,0.0
+2015-12-06 04:00:00,0.0,251.1999969482422,0.0,102010.0,0.0037999998312443495,277.3000183105469,-2.200000047683716,-2.799999952316284,0.0
+2015-12-06 05:00:00,0.0,251.1999969482422,0.0,102030.0,0.0037999998312443495,277.3999938964844,-2.200000047683716,-2.700000047683716,0.0
+2015-12-06 06:00:00,0.0,267.70001220703125,0.0,101930.0,0.0038999998942017555,277.5,-2.200000047683716,-2.6000001430511475,0.0
+2015-12-06 07:00:00,0.0,267.70001220703125,0.0,101950.0,0.0037999998312443495,277.20001220703125,-2.0,-2.700000047683716,0.0
+2015-12-06 08:00:00,0.0,267.70001220703125,0.0,101890.0,0.0038999998942017555,276.8000183105469,-1.8000000715255737,-2.799999952316284,0.0
+2015-12-06 09:00:00,0.0,296.3999938964844,0.0,101850.0,0.0038999998942017555,276.3999938964844,-1.600000023841858,-2.799999952316284,0.0
+2015-12-06 10:00:00,0.0,296.3999938964844,0.0,101860.0,0.0037999998312443495,275.70001220703125,-1.5,-2.6000001430511475,0.0
+2015-12-06 11:00:00,0.0,296.3999938964844,0.0,101860.0,0.0037999998312443495,274.8000183105469,-1.5,-2.4000000953674316,0.0
+2015-12-06 12:00:00,0.0,272.8999938964844,0.0,101870.0,0.003700000001117587,274.8000183105469,-1.5,-2.200000047683716,0.0
+2015-12-06 13:00:00,0.0,272.8999938964844,102.20000457763672,101920.0,0.0038999998942017555,275.3000183105469,-1.600000023841858,-2.4000000953674316,0.0
+2015-12-06 14:00:00,0.0,272.8000183105469,250.90000915527344,101900.0,0.00419999985024333,278.8000183105469,-1.600000023841858,-2.5,0.0
+2015-12-06 15:00:00,0.0,279.3000183105469,403.0,101840.0,0.004399999976158142,282.0,-1.7000000476837158,-2.6000001430511475,0.0
+2015-12-06 16:00:00,0.0,279.3000183105469,488.5,101810.0,0.004100000020116568,284.3000183105469,-1.8000000715255737,-2.200000047683716,0.0
+2015-12-06 17:00:00,0.0,279.3000183105469,512.6000366210938,101680.0,0.003999999724328518,285.8999938964844,-2.0,-1.7000000476837158,0.0
+2015-12-06 18:00:00,0.0,296.8999938964844,495.6000061035156,101510.0,0.003700000001117587,287.8999938964844,-2.200000047683716,-1.3000000715255737,0.0
+2015-12-06 19:00:00,0.0,296.8999938964844,434.3000183105469,101380.0,0.00419999985024333,289.3000183105469,-2.0,-1.2000000476837158,0.0
+2015-12-06 20:00:00,0.0,296.8999938964844,337.20001220703125,101250.0,0.0044999998062849045,290.1000061035156,-1.8000000715255737,-1.2000000476837158,0.0
+2015-12-06 21:00:00,0.0,288.20001220703125,152.1999969482422,101200.0,0.004799999762326479,290.0,-1.600000023841858,-1.100000023841858,0.0
+2015-12-06 22:00:00,0.0,288.20001220703125,25.700000762939453,101200.0,0.005399999674409628,287.5,-1.5,-0.800000011920929,0.0
+2015-12-06 23:00:00,0.0,288.20001220703125,0.0,101190.0,0.005499999970197678,282.70001220703125,-1.5,-0.4000000059604645,0.0
+2015-12-07 00:00:00,0.0,278.1000061035156,0.0,101200.0,0.00559999980032444,282.1000061035156,-1.5,-0.10000000149011612,0.0
+2015-12-07 01:00:00,0.0,278.1000061035156,0.0,101250.0,0.00559999980032444,281.3000183105469,-1.3000000715255737,-0.30000001192092896,0.0
+2015-12-07 02:00:00,0.0,278.1000061035156,0.0,101220.0,0.0052999998442828655,279.5,-1.0,-0.6000000238418579,0.0
+2015-12-07 03:00:00,0.0,277.20001220703125,0.0,101170.0,0.0050999997183680534,279.20001220703125,-0.800000011920929,-0.9000000357627869,0.0
+2015-12-07 04:00:00,0.0,277.20001220703125,0.0,101120.0,0.004799999762326479,277.6000061035156,-0.5,-1.399999976158142,0.0
+2015-12-07 05:00:00,0.0,277.20001220703125,0.0,101090.0,0.004999999888241291,277.8000183105469,-0.10000000149011612,-1.899999976158142,0.0
+2015-12-07 06:00:00,0.0,272.1000061035156,0.0,101050.0,0.004799999762326479,277.20001220703125,0.20000000298023224,-2.4000000953674316,0.0
+2015-12-07 07:00:00,0.0,272.1000061035156,0.0,101020.0,0.004600000102072954,276.8000183105469,0.10000000149011612,-2.4000000953674316,0.0
+2015-12-07 08:00:00,0.0,272.1000061035156,0.0,100930.0,0.0044999998062849045,276.0,0.0,-2.299999952316284,0.0
+2015-12-07 09:00:00,0.0,277.3000183105469,0.0,100860.0,0.0044999998062849045,275.8000183105469,-0.10000000149011612,-2.299999952316284,0.0
+2015-12-07 10:00:00,0.0,277.3000183105469,0.0,100800.0,0.0044999998062849045,275.5,0.20000000298023224,-2.200000047683716,0.0
+2015-12-07 11:00:00,0.0,277.3000183105469,0.0,100820.0,0.0044999998062849045,275.70001220703125,0.4000000059604645,-2.1000001430511475,0.0
+2015-12-07 12:00:00,0.0,319.0,0.0,100820.0,0.004399999976158142,275.3999938964844,0.699999988079071,-2.0,0.0
+2015-12-07 13:00:00,0.0,318.8999938964844,69.9000015258789,100830.0,0.0044999998062849045,276.0,0.9000000357627869,-1.8000000715255737,0.0
+2015-12-07 14:00:00,0.0,318.8999938964844,174.0,100820.0,0.004999999888241291,278.8999938964844,1.0,-1.600000023841858,0.0
+2015-12-07 15:00:00,0.0,346.70001220703125,285.70001220703125,100780.0,0.005499999970197678,283.1000061035156,1.100000023841858,-1.399999976158142,0.0
+2015-12-07 16:00:00,0.0,346.6000061035156,346.8999938964844,100690.0,0.004900000058114529,286.70001220703125,1.0,-1.5,0.0
+2015-12-07 17:00:00,0.0,346.6000061035156,364.3000183105469,100590.0,0.004799999762326479,289.5,0.9000000357627869,-1.7000000476837158,0.0
+2015-12-07 18:00:00,0.0,342.1000061035156,424.0,100440.0,0.004999999888241291,290.70001220703125,0.699999988079071,-1.8000000715255737,0.0
+2015-12-07 19:00:00,0.0,342.1000061035156,371.70001220703125,100320.0,0.005200000014156103,291.3999938964844,1.0,-1.8000000715255737,0.0
+2015-12-07 20:00:00,0.0,342.1000061035156,288.70001220703125,100280.0,0.005399999674409628,291.70001220703125,1.3000000715255737,-1.7000000476837158,0.0
+2015-12-07 21:00:00,0.0,350.8000183105469,132.60000610351562,100300.0,0.005499999970197678,291.8999938964844,1.5,-1.7000000476837158,0.0
+2015-12-07 22:00:00,0.0,350.8000183105469,22.399999618530273,100340.0,0.005699999630451202,289.70001220703125,1.2000000476837158,-1.5,0.0
+2015-12-07 23:00:00,0.0,350.8000183105469,0.0,100340.0,0.005799999926239252,285.8000183105469,0.9000000357627869,-1.3000000715255737,0.0
+2015-12-08 00:00:00,0.0,317.1000061035156,0.0,100400.0,0.005799999926239252,283.0,0.5,-1.100000023841858,0.0
+2015-12-08 01:00:00,0.0,317.1000061035156,0.0,100480.0,0.005699999630451202,281.8000183105469,0.5,-1.0,0.0
+2015-12-08 02:00:00,0.0,317.1000061035156,0.0,100490.0,0.005799999926239252,281.8000183105469,0.6000000238418579,-1.0,0.0
+2015-12-08 03:00:00,0.0,272.70001220703125,0.0,100470.0,0.005699999630451202,281.8000183105469,0.6000000238418579,-0.9000000357627869,0.0
+2015-12-08 04:00:00,0.0,272.70001220703125,0.0,100500.0,0.005399999674409628,280.8999938964844,0.6000000238418579,-0.6000000238418579,0.0
+2015-12-08 05:00:00,0.0,272.70001220703125,0.0,100520.0,0.005200000014156103,279.6000061035156,0.699999988079071,-0.4000000059604645,0.0
+2015-12-08 06:00:00,0.0,265.1000061035156,0.0,100440.0,0.005200000014156103,280.70001220703125,0.699999988079071,-0.10000000149011612,0.0
+2015-12-08 07:00:00,0.0,265.1000061035156,0.0,100490.0,0.005200000014156103,279.0,0.699999988079071,-0.30000001192092896,0.0
+2015-12-08 08:00:00,0.0,265.1000061035156,0.0,100550.0,0.004999999888241291,277.8000183105469,0.800000011920929,-0.5,0.0
+2015-12-08 09:00:00,0.0,260.3000183105469,0.0,100470.0,0.004900000058114529,277.3999938964844,0.800000011920929,-0.699999988079071,0.0
+2015-12-08 10:00:00,0.0,260.3000183105469,0.0,100440.0,0.004699999932199717,276.0,0.5,-0.699999988079071,0.0
+2015-12-08 11:00:00,0.0,260.3000183105469,0.0,100520.0,0.00419999985024333,274.8000183105469,0.10000000149011612,-0.699999988079071,0.0
+2015-12-08 12:00:00,0.0,258.0,0.0,100560.0,0.0044999998062849045,275.6000061035156,-0.30000001192092896,-0.699999988079071,0.0
+2015-12-08 13:00:00,0.0,257.8999938964844,98.0,100650.0,0.0044999998062849045,275.3999938964844,-0.4000000059604645,-0.6000000238418579,0.0
+2015-12-08 14:00:00,0.0,257.8999938964844,247.3000030517578,100670.0,0.005499999970197678,279.5,-0.6000000238418579,-0.4000000059604645,0.0
+2015-12-08 15:00:00,0.0,285.20001220703125,404.1000061035156,100730.0,0.00559999980032444,282.8000183105469,-0.699999988079071,-0.30000001192092896,0.0
+2015-12-08 16:00:00,0.0,285.20001220703125,491.3000183105469,100710.0,0.005399999674409628,285.70001220703125,-0.699999988079071,0.5,0.0
+2015-12-08 17:00:00,0.0,285.20001220703125,516.5,100580.0,0.0052999998442828655,287.8999938964844,-0.699999988079071,1.3000000715255737,0.0
+2015-12-08 18:00:00,0.0,291.1000061035156,501.8000183105469,100480.0,0.005200000014156103,289.1000061035156,-0.6000000238418579,2.1000001430511475,0.0
+2015-12-08 19:00:00,0.0,291.1000061035156,440.1000061035156,100400.0,0.00559999980032444,290.5,-0.20000000298023224,2.4000000953674316,0.0
+2015-12-08 20:00:00,0.0,291.1000061035156,342.0,100420.0,0.0058999997563660145,290.5,0.20000000298023224,2.700000047683716,0.0
+2015-12-08 21:00:00,0.0,279.8999938964844,148.40000915527344,100320.0,0.006399999838322401,290.0,0.6000000238418579,3.0,0.0
+2015-12-08 22:00:00,0.0,279.8999938964844,25.200000762939453,100360.0,0.006399999838322401,288.3999938964844,0.20000000298023224,2.799999952316284,0.0
+2015-12-08 23:00:00,0.0,279.8999938964844,0.0,100370.0,0.0064999996684491634,284.3999938964844,-0.10000000149011612,2.5,0.0
+2015-12-09 00:00:00,0.0,263.8999938964844,0.0,100390.0,0.006599999964237213,282.3999938964844,-0.4000000059604645,2.299999952316284,0.0
+2015-12-09 01:00:00,0.0,263.8999938964844,0.0,100480.0,0.006399999838322401,281.70001220703125,-0.699999988079071,2.299999952316284,0.0
+2015-12-09 02:00:00,0.0,263.8999938964844,0.0,100490.0,0.006300000008195639,281.20001220703125,-1.0,2.299999952316284,0.0
+2015-12-09 03:00:00,0.0,258.70001220703125,0.0,100430.0,0.0058999997563660145,280.1000061035156,-1.399999976158142,2.299999952316284,0.0
+2015-12-09 04:00:00,0.0,258.70001220703125,0.0,100430.0,0.005699999630451202,279.5,-0.800000011920929,2.1000001430511475,0.0
+2015-12-09 05:00:00,0.0,258.70001220703125,0.0,100430.0,0.005499999970197678,278.8999938964844,-0.30000001192092896,2.0,0.0
+2015-12-09 06:00:00,0.0,255.60000610351562,0.0,100400.0,0.005200000014156103,278.3999938964844,0.30000001192092896,1.899999976158142,0.0
+2015-12-09 07:00:00,0.0,255.60000610351562,0.0,100440.0,0.004999999888241291,277.8000183105469,0.10000000149011612,1.8000000715255737,0.0
+2015-12-09 08:00:00,0.0,255.60000610351562,0.0,100450.0,0.004999999888241291,277.5,0.0,1.7000000476837158,0.0
+2015-12-09 09:00:00,0.0,256.8999938964844,0.0,100350.0,0.005200000014156103,278.0,-0.20000000298023224,1.600000023841858,0.0
+2015-12-09 10:00:00,0.0,256.8999938964844,0.0,100370.0,0.004999999888241291,277.6000061035156,-0.4000000059604645,1.899999976158142,0.0
+2015-12-09 11:00:00,0.0,256.8999938964844,0.0,100400.0,0.004900000058114529,277.0,-0.6000000238418579,2.200000047683716,0.0
+2015-12-09 12:00:00,0.0,267.6000061035156,0.0,100430.0,0.004299999680370092,275.1000061035156,-0.699999988079071,2.5,0.0
+2015-12-09 13:00:00,0.0,267.6000061035156,94.4000015258789,100470.0,0.0044999998062849045,275.3999938964844,-0.699999988079071,1.899999976158142,0.0
+2015-12-09 14:00:00,0.0,267.6000061035156,241.60000610351562,100540.0,0.0052999998442828655,278.8000183105469,-0.6000000238418579,1.2000000476837158,0.0
+2015-12-09 15:00:00,0.0,295.8000183105469,376.0,100480.0,0.006000000052154064,282.3000183105469,-0.6000000238418579,0.5,0.0
+2015-12-09 16:00:00,0.0,295.8000183105469,457.8999938964844,100450.0,0.00559999980032444,286.5,-0.30000001192092896,1.2000000476837158,0.0
+2015-12-09 17:00:00,0.0,295.70001220703125,481.8999938964844,100290.0,0.004900000058114529,289.3999938964844,0.0,1.8000000715255737,0.0
+2015-12-09 18:00:00,0.0,304.3000183105469,491.5,100150.0,0.004699999932199717,290.20001220703125,0.4000000059604645,2.4000000953674316,0.0
+2015-12-09 19:00:00,0.0,304.3000183105469,431.3999938964844,100050.0,0.004600000102072954,291.0,0.800000011920929,2.200000047683716,0.0
+2015-12-09 20:00:00,0.0,304.3000183105469,335.3999938964844,100040.0,0.004299999680370092,291.3000183105469,1.2000000476837158,2.1000001430511475,0.0
+2015-12-09 21:00:00,0.0,292.3000183105469,145.1999969482422,100020.0,0.004600000102072954,290.8000183105469,1.600000023841858,1.899999976158142,0.0
+2015-12-09 22:00:00,0.0,292.3000183105469,24.700000762939453,100070.0,0.004999999888241291,288.20001220703125,1.899999976158142,1.100000023841858,0.0
+2015-12-09 23:00:00,0.0,292.3000183105469,0.0,100080.0,0.0050999997183680534,284.70001220703125,2.200000047683716,0.30000001192092896,0.0
+2015-12-10 00:00:00,0.0,274.6000061035156,0.0,100090.0,0.005200000014156103,284.0,2.5,-0.5,0.0
+2015-12-10 01:00:00,0.0,274.6000061035156,0.0,100120.0,0.005399999674409628,282.0,2.200000047683716,-0.9000000357627869,0.0
+2015-12-10 02:00:00,0.0,274.70001220703125,0.0,100160.0,0.005200000014156103,281.3000183105469,1.899999976158142,-1.2000000476837158,0.0
+2015-12-10 03:00:00,0.0,272.70001220703125,0.0,100100.0,0.0050999997183680534,281.3999938964844,1.600000023841858,-1.600000023841858,0.0
+2015-12-10 04:00:00,0.0,272.70001220703125,0.0,100080.0,0.0052999998442828655,281.3999938964844,1.600000023841858,-1.3000000715255737,0.0
+2015-12-10 05:00:00,0.0,272.70001220703125,0.0,100140.0,0.005399999674409628,281.0,1.600000023841858,-0.9000000357627869,0.0
+2015-12-10 06:00:00,0.0,280.6000061035156,0.0,100110.0,0.005399999674409628,279.3000183105469,1.600000023841858,-0.5,0.0
+2015-12-10 07:00:00,0.0,280.6000061035156,0.0,100070.0,0.0050999997183680534,280.3000183105469,1.600000023841858,-0.5,0.0
+2015-12-10 08:00:00,0.0,280.6000061035156,0.0,100060.0,0.005200000014156103,279.5,1.600000023841858,-0.4000000059604645,0.0
+2015-12-10 09:00:00,0.0,314.70001220703125,0.0,100050.0,0.0052999998442828655,279.6000061035156,1.600000023841858,-0.30000001192092896,0.0
+2015-12-10 10:00:00,0.0,314.70001220703125,0.0,100030.0,0.0050999997183680534,279.6000061035156,0.9000000357627869,-0.20000000298023224,0.0
+2015-12-10 11:00:00,0.0,314.70001220703125,0.0,100070.0,0.005200000014156103,279.3000183105469,0.20000000298023224,0.0,0.0
+2015-12-10 12:00:00,0.0,298.8999938964844,0.0,100070.0,0.005200000014156103,278.6000061035156,-0.5,0.20000000298023224,0.0
+2015-12-10 13:00:00,0.0,298.8999938964844,91.9000015258789,100190.0,0.004799999762326479,277.8999938964844,0.0,0.0,0.0
+2015-12-10 14:00:00,0.0,298.8999938964844,238.6999969482422,100170.0,0.005699999630451202,282.5,0.5,-0.10000000149011612,0.0
+2015-12-10 15:00:00,0.0,304.5,390.70001220703125,100250.0,0.006300000008195639,286.8999938964844,1.0,-0.20000000298023224,0.0
+2015-12-10 16:00:00,0.0,304.5,476.3999938964844,100190.0,0.0071000000461936,289.8000183105469,1.399999976158142,0.6000000238418579,0.0
+2015-12-10 17:00:00,0.0,304.3999938964844,501.8000183105469,100040.0,0.007599999662488699,292.5,1.899999976158142,1.5,0.0
+2015-12-10 18:00:00,0.0,345.8999938964844,421.5,99990.0,0.007899999618530273,293.3999938964844,2.299999952316284,2.299999952316284,0.0
+2015-12-10 19:00:00,0.0,345.8999938964844,370.1000061035156,99930.0,0.007699999958276749,293.6000061035156,2.0,2.799999952316284,0.0
+2015-12-10 20:00:00,0.0,345.8999938964844,287.8999938964844,99930.0,0.007599999662488699,293.6000061035156,1.7000000476837158,3.299999952316284,0.0
+2015-12-10 21:00:00,0.0,342.3999938964844,129.8000030517578,99900.0,0.007799999788403511,293.1000061035156,1.399999976158142,3.799999952316284,0.0
+2015-12-10 22:00:00,0.0,342.3999938964844,22.30000114440918,99950.0,0.007699999958276749,291.70001220703125,1.100000023841858,3.5,0.0
+2015-12-10 23:00:00,0.0,342.3999938964844,0.0,99940.0,0.008100000210106373,288.8999938964844,0.699999988079071,3.200000047683716,0.0
+2015-12-11 00:00:00,0.0,343.6000061035156,0.0,99940.0,0.008200000040233135,287.3000183105469,0.30000001192092896,2.9000000953674316,0.0
+2015-12-11 01:00:00,0.0,343.6000061035156,0.0,100000.0,0.008100000210106373,287.6000061035156,0.10000000149011612,2.6000001430511475,0.0
+2015-12-11 02:00:00,0.0,343.6000061035156,0.0,100050.0,0.007799999788403511,285.6000061035156,-0.10000000149011612,2.299999952316284,0.0
+2015-12-11 03:00:00,0.0,366.20001220703125,0.0,100050.0,0.007899999618530273,285.3000183105469,-0.20000000298023224,2.0,0.0
+2015-12-11 04:00:00,0.0,366.20001220703125,0.0,100040.0,0.007699999958276749,284.8999938964844,0.10000000149011612,2.200000047683716,0.0
+2015-12-11 05:00:00,0.0,366.20001220703125,0.0,100000.0,0.007699999958276749,285.5,0.4000000059604645,2.5,0.0
+2015-12-11 06:00:00,0.0,368.3000183105469,0.0,99960.0,0.0072999997064471245,284.8000183105469,0.699999988079071,2.700000047683716,0.0
+2015-12-11 07:00:00,0.0,368.3000183105469,0.0,99970.0,0.007699999958276749,285.0,1.100000023841858,2.5,0.0
+2015-12-11 08:00:00,0.0,368.3000183105469,0.0,100010.0,0.007499999832361937,285.3000183105469,1.5,2.200000047683716,0.0
+2015-12-11 09:00:00,0.0,310.0,0.0,99980.0,0.007599999662488699,284.8999938964844,1.8000000715255737,1.899999976158142,0.0
+2015-12-11 10:00:00,0.0,310.0,0.0,100000.0,0.0072999997064471245,283.70001220703125,1.600000023841858,2.0,0.0
+2015-12-11 11:00:00,0.0,310.0,0.0,100130.0,0.007499999832361937,283.70001220703125,1.3000000715255737,2.0,0.0
+2015-12-11 12:00:00,0.0,299.1000061035156,0.0,100150.0,0.007400000002235174,282.5,1.0,2.1000001430511475,0.0
+2015-12-11 13:00:00,0.0,299.1000061035156,87.5999984741211,100230.0,0.007599999662488699,283.8999938964844,1.100000023841858,1.899999976158142,0.0
+2015-12-11 14:00:00,0.0,299.1000061035156,230.8000030517578,100320.0,0.008599999360740185,285.20001220703125,1.3000000715255737,1.600000023841858,0.0
+2015-12-11 15:00:00,0.0,331.3999938964844,382.3999938964844,100360.0,0.00969999935477972,287.6000061035156,1.399999976158142,1.399999976158142,0.0
+2015-12-11 16:00:00,0.0,331.3999938964844,467.0,100390.0,0.00989999994635582,288.5,1.7000000476837158,2.1000001430511475,0.0
+2015-12-11 17:00:00,0.0,331.3999938964844,492.3000183105469,100370.0,0.010199999436736107,289.70001220703125,2.0,2.799999952316284,0.0
+2015-12-11 18:00:00,0.0,353.6000061035156,474.3999938964844,100310.0,0.01119999960064888,291.5,2.4000000953674316,3.5,0.0
+2015-12-11 19:00:00,0.0,353.6000061035156,416.8000183105469,100300.0,0.010599999688565731,294.70001220703125,2.299999952316284,3.700000047683716,0.0
+2015-12-11 20:00:00,0.0,353.6000061035156,324.3999938964844,100230.0,0.010199999436736107,295.3000183105469,2.299999952316284,3.799999952316284,0.0
+2015-12-11 21:00:00,0.0,347.6000061035156,137.5,100210.0,0.010400000028312206,294.8000183105469,2.200000047683716,4.0,0.0
+2015-12-11 22:00:00,0.0,347.6000061035156,23.80000114440918,100250.0,0.010699999518692493,293.20001220703125,1.7000000476837158,3.799999952316284,0.0
+2015-12-11 23:00:00,0.0,347.6000061035156,0.0,100290.0,0.010699999518692493,290.20001220703125,1.100000023841858,3.5,0.0
+2015-12-12 00:00:00,0.0,331.3999938964844,0.0,100330.0,0.010900000110268593,290.20001220703125,0.5,3.299999952316284,0.0
+2015-12-12 01:00:00,0.0,331.3999938964844,0.0,100420.0,0.009999999776482582,288.3000183105469,0.5,3.200000047683716,0.0
+2015-12-12 02:00:00,0.0,331.3999938964844,0.0,100420.0,0.00989999994635582,287.6000061035156,0.5,3.1000001430511475,0.0
+2015-12-12 03:00:00,0.0,328.0,0.0,100480.0,0.010099999606609344,288.0,0.5,3.0,0.0
+2015-12-12 04:00:00,0.0,328.0,0.0,100510.0,0.009800000116229057,287.20001220703125,1.100000023841858,3.0,0.0
+2015-12-12 05:00:00,0.0,328.0,0.0,100560.0,0.009399999864399433,286.8000183105469,1.8000000715255737,3.0,0.0
+2015-12-12 06:00:00,0.0,325.20001220703125,0.0,100600.0,0.00969999935477972,287.1000061035156,2.5,3.0,0.0
+2015-12-12 07:00:00,0.0,325.20001220703125,0.0,100630.0,0.009800000116229057,287.70001220703125,2.4000000953674316,2.9000000953674316,0.0
+2015-12-12 08:00:00,0.0,325.20001220703125,0.0,100660.0,0.00969999935477972,287.3999938964844,2.200000047683716,2.799999952316284,0.0
+2015-12-12 09:00:00,0.0,319.8000183105469,0.0,100670.0,0.009599999524652958,287.5,2.1000001430511475,2.700000047683716,0.0
+2015-12-12 10:00:00,0.0,319.8000183105469,0.0,100670.0,0.00969999935477972,287.3999938964844,1.600000023841858,2.700000047683716,0.0
+2015-12-12 11:00:00,0.0,319.8999938964844,0.0,100740.0,0.009499999694526196,286.8999938964844,1.2000000476837158,2.6000001430511475,0.0
+2015-12-12 12:00:00,0.0,316.8999938964844,0.0,100830.0,0.009099999442696571,286.20001220703125,0.800000011920929,2.6000001430511475,0.0
+2015-12-12 13:00:00,0.0,316.8999938964844,84.4000015258789,100870.0,0.009399999864399433,286.5,1.2000000476837158,2.4000000953674316,0.0
+2015-12-12 14:00:00,0.0,316.8999938964844,225.40000915527344,100930.0,0.009999999776482582,288.1000061035156,1.600000023841858,2.200000047683716,0.0
+2015-12-12 15:00:00,0.0,342.3999938964844,377.3000183105469,100960.0,0.010799999348819256,291.1000061035156,1.899999976158142,2.0,0.0
+2015-12-12 16:00:00,0.0,342.3999938964844,461.5,100960.0,0.010900000110268593,293.20001220703125,2.4000000953674316,1.899999976158142,0.0
+2015-12-12 17:00:00,0.0,342.3999938964844,487.0,100820.0,0.010099999606609344,295.1000061035156,2.9000000953674316,1.8000000715255737,0.0
+2015-12-12 18:00:00,0.0,354.3000183105469,475.70001220703125,100790.0,0.009999999776482582,296.1000061035156,3.4000000953674316,1.8000000715255737,0.0
+2015-12-12 19:00:00,0.0,354.3000183105469,418.20001220703125,100720.0,0.010099999606609344,297.0,3.1000001430511475,2.0,0.0
+2015-12-12 20:00:00,0.0,354.3000183105469,325.8000183105469,100670.0,0.010300000198185444,297.20001220703125,2.9000000953674316,2.299999952316284,0.0
+2015-12-12 21:00:00,0.0,339.3999938964844,157.1999969482422,100680.0,0.00989999994635582,296.3999938964844,2.6000001430511475,2.5,0.0
+2015-12-12 22:00:00,0.0,339.3999938964844,27.5,100730.0,0.010599999688565731,293.8999938964844,2.4000000953674316,2.4000000953674316,0.0
+2015-12-12 23:00:00,0.0,339.3999938964844,0.0,100740.0,0.010599999688565731,291.3000183105469,2.200000047683716,2.299999952316284,0.0
+2015-12-13 00:00:00,0.0,318.20001220703125,0.0,100780.0,0.010699999518692493,290.3999938964844,2.0,2.299999952316284,0.0
+2015-12-13 01:00:00,0.0,318.20001220703125,0.0,100810.0,0.010400000028312206,288.6000061035156,1.5,2.1000001430511475,0.0
+2015-12-13 02:00:00,0.0,318.20001220703125,0.0,100860.0,0.009800000116229057,286.8000183105469,0.9000000357627869,1.899999976158142,0.0
+2015-12-13 03:00:00,0.0,310.3999938964844,0.0,100830.0,0.009099999442696571,285.70001220703125,0.30000001192092896,1.7000000476837158,0.0
+2015-12-13 04:00:00,0.0,310.3999938964844,0.0,100840.0,0.008599999360740185,285.3000183105469,0.800000011920929,1.8000000715255737,0.0
+2015-12-13 05:00:00,0.0,310.3999938964844,0.0,100850.0,0.008999999612569809,286.0,1.2000000476837158,1.8000000715255737,0.0
+2015-12-13 06:00:00,0.0,301.70001220703125,0.0,100850.0,0.008299999870359898,284.5,1.600000023841858,1.899999976158142,0.0
+2015-12-13 07:00:00,0.0,301.70001220703125,0.0,100820.0,0.007999999448657036,284.3000183105469,1.3000000715255737,1.899999976158142,0.0
+2015-12-13 08:00:00,0.0,301.70001220703125,0.0,100810.0,0.006899999920278788,283.20001220703125,0.9000000357627869,1.8000000715255737,0.0
+2015-12-13 09:00:00,0.0,293.3999938964844,0.0,100760.0,0.0072999997064471245,283.20001220703125,0.5,1.8000000715255737,0.0
+2015-12-13 10:00:00,0.0,293.3999938964844,0.0,100750.0,0.0072999997064471245,282.3999938964844,0.0,1.399999976158142,0.0
+2015-12-13 11:00:00,0.0,293.5,0.0,100780.0,0.007400000002235174,282.70001220703125,-0.5,1.0,0.0
+2015-12-13 12:00:00,0.0,299.3999938964844,0.0,100810.0,0.006799999624490738,280.8999938964844,-1.100000023841858,0.6000000238418579,0.0
+2015-12-13 13:00:00,0.0,299.3999938964844,83.9000015258789,100790.0,0.0071000000461936,281.8000183105469,-1.0,0.10000000149011612,0.0
+2015-12-13 14:00:00,0.0,299.3999938964844,227.40000915527344,100860.0,0.007899999618530273,284.20001220703125,-0.9000000357627869,-0.30000001192092896,0.0
+2015-12-13 15:00:00,0.0,331.20001220703125,369.0,100800.0,0.008599999360740185,287.8000183105469,-0.9000000357627869,-0.800000011920929,0.0
+2015-12-13 16:00:00,0.0,331.1000061035156,452.0,100790.0,0.008899999782443047,291.3000183105469,-0.9000000357627869,0.4000000059604645,0.0
+2015-12-13 17:00:00,0.0,331.1000061035156,477.3000183105469,100700.0,0.00839999970048666,293.1000061035156,-0.9000000357627869,1.600000023841858,0.0
+2015-12-13 18:00:00,0.0,345.1000061035156,456.8000183105469,100580.0,0.009800000116229057,294.3999938964844,-0.9000000357627869,2.799999952316284,0.0
+2015-12-13 19:00:00,0.0,345.1000061035156,401.8999938964844,100490.0,0.009499999694526196,295.0,-1.3000000715255737,2.799999952316284,0.0
+2015-12-13 20:00:00,0.0,345.1000061035156,313.3000183105469,100420.0,0.010300000198185444,295.5,-1.600000023841858,2.9000000953674316,0.0
+2015-12-13 21:00:00,0.0,324.3000183105469,145.0,100370.0,0.010499999858438969,294.8999938964844,-2.0,3.0,0.0
+2015-12-13 22:00:00,0.0,324.3000183105469,25.700000762939453,100400.0,0.011099999770522118,292.8000183105469,-2.200000047683716,2.4000000953674316,0.0
+2015-12-13 23:00:00,0.0,324.3000183105469,0.0,100370.0,0.010900000110268593,290.1000061035156,-2.4000000953674316,1.7000000476837158,0.0
+2015-12-14 00:00:00,0.0,330.0,0.0,100370.0,0.010900000110268593,289.0,-2.6000001430511475,1.100000023841858,0.0
+2015-12-14 01:00:00,0.0,330.0,0.0,100360.0,0.011299999430775642,289.8999938964844,-2.799999952316284,1.2000000476837158,0.0
+2015-12-14 02:00:00,0.0,330.0,0.0,100380.0,0.011299999430775642,289.8999938964844,-2.9000000953674316,1.3000000715255737,0.0
+2015-12-14 03:00:00,0.0,317.3999938964844,0.0,100320.0,0.01119999960064888,289.5,-3.1000001430511475,1.399999976158142,0.0
+2015-12-14 04:00:00,0.0,317.3999938964844,0.0,100260.0,0.010900000110268593,289.1000061035156,-2.9000000953674316,1.899999976158142,0.0
+2015-12-14 05:00:00,0.0,317.3999938964844,0.0,100270.0,0.011099999770522118,289.0,-2.700000047683716,2.4000000953674316,0.0
+2015-12-14 06:00:00,0.0,324.3000183105469,0.0,100200.0,0.011399999260902405,289.20001220703125,-2.4000000953674316,2.9000000953674316,0.0
+2015-12-14 07:00:00,0.0,324.3000183105469,0.0,100130.0,0.01119999960064888,289.3000183105469,-1.899999976158142,2.9000000953674316,0.0
+2015-12-14 08:00:00,0.0,324.3000183105469,0.0,100020.0,0.011399999260902405,289.3999938964844,-1.5,3.0,0.0
+2015-12-14 09:00:00,0.0,358.3000183105469,0.0,99880.0,0.011500000022351742,290.0,-1.0,3.0,0.0
+2015-12-14 10:00:00,0.0,358.3000183105469,0.0,99810.0,0.011799999512732029,289.8999938964844,-1.600000023841858,3.1000001430511475,0.0
+2015-12-14 11:00:00,0.0,358.3000183105469,0.0,99780.0,0.012000000104308128,289.8999938964844,-2.200000047683716,3.200000047683716,0.0
+2015-12-14 12:00:00,0.0,381.1000061035156,0.0,99710.0,0.011699999682605267,289.8999938964844,-2.799999952316284,3.299999952316284,0.0
+2015-12-14 13:00:00,0.0,381.1000061035156,37.0,99680.0,0.012299999594688416,290.8000183105469,-2.1000001430511475,3.799999952316284,0.0
+2015-12-14 14:00:00,0.0,381.1000061035156,101.80000305175781,99650.0,0.012600000016391277,291.3000183105469,-1.399999976158142,4.300000190734863,7.382353145925361e-07
+2015-12-14 15:00:00,1.5,392.8999938964844,181.90000915527344,99570.0,0.012899999506771564,291.5,-0.699999988079071,4.800000190734863,0.0
+2015-12-14 16:00:00,0.0,392.8999938964844,223.10000610351562,99410.0,0.013399999588727951,292.6000061035156,-0.20000000298023224,4.900000095367432,0.0
+2015-12-14 17:00:00,0.0,392.8999938964844,235.8000030517578,99350.0,0.013899999670684338,293.3999938964844,0.30000001192092896,4.900000095367432,0.0
+2015-12-14 18:00:00,0.0,405.20001220703125,161.5,99270.0,0.014299999922513962,293.8000183105469,0.699999988079071,4.900000095367432,0.0
+2015-12-14 19:00:00,0.0,405.20001220703125,142.10000610351562,99290.0,0.014599999412894249,295.0,1.2000000476837158,4.5,5.090121965577734e-08
+2015-12-14 20:00:00,0.10000000149011612,405.20001220703125,110.9000015258789,99160.0,0.013499999418854713,293.6000061035156,1.600000023841858,4.099999904632568,2.1604080814467757e-06
+2015-12-14 21:00:00,4.300000190734863,395.70001220703125,43.79999923706055,99230.0,0.012299999594688416,291.6000061035156,2.1000001430511475,3.700000047683716,0.0
+2015-12-14 22:00:00,0.0,395.70001220703125,7.900000095367432,99140.0,0.012000000104308128,290.5,2.200000047683716,3.4000000953674316,0.0
+2015-12-14 23:00:00,0.0,395.70001220703125,0.0,99170.0,0.01209999993443489,290.70001220703125,2.4000000953674316,3.1000001430511475,0.0
+2015-12-15 00:00:00,0.0,333.3999938964844,0.0,99160.0,0.012000000104308128,290.3000183105469,2.5,2.700000047683716,0.0
+2015-12-15 01:00:00,0.0,333.3999938964844,0.0,99170.0,0.011899999342858791,290.3999938964844,3.1000001430511475,2.9000000953674316,0.0
+2015-12-15 02:00:00,0.0,333.3999938964844,0.0,99250.0,0.011699999682605267,290.0,3.6000001430511475,3.0,0.0
+2015-12-15 03:00:00,0.0,304.20001220703125,0.0,99280.0,0.011299999430775642,289.3000183105469,4.200000286102295,3.1000001430511475,0.0
+2015-12-15 04:00:00,0.0,304.20001220703125,0.0,99310.0,0.010900000110268593,288.5,4.200000286102295,2.700000047683716,0.0
+2015-12-15 05:00:00,0.0,304.20001220703125,0.0,99320.0,0.00969999935477972,288.20001220703125,4.300000190734863,2.200000047683716,0.0
+2015-12-15 06:00:00,0.0,287.3999938964844,0.0,99320.0,0.008999999612569809,286.8999938964844,4.300000190734863,1.7000000476837158,0.0
+2015-12-15 07:00:00,0.0,287.3999938964844,0.0,99360.0,0.00839999970048666,286.8000183105469,4.099999904632568,1.5,0.0
+2015-12-15 08:00:00,0.0,287.3999938964844,0.0,99340.0,0.007400000002235174,286.1000061035156,3.9000000953674316,1.2000000476837158,0.0
+2015-12-15 09:00:00,0.0,278.3999938964844,0.0,99330.0,0.00699999975040555,285.5,3.700000047683716,0.9000000357627869,0.0
+2015-12-15 10:00:00,0.0,278.3999938964844,0.0,99390.0,0.006899999920278788,284.8000183105469,3.5,0.9000000357627869,0.0
+2015-12-15 11:00:00,0.0,278.3999938964844,0.0,99390.0,0.0066999997943639755,284.6000061035156,3.299999952316284,0.800000011920929,0.0
+2015-12-15 12:00:00,0.0,270.3000183105469,0.0,99480.0,0.0066999997943639755,283.3000183105469,3.1000001430511475,0.699999988079071,0.0
+2015-12-15 13:00:00,0.0,270.3000183105469,82.5,99590.0,0.00699999975040555,282.70001220703125,3.1000001430511475,0.30000001192092896,0.0
+2015-12-15 14:00:00,0.0,270.3000183105469,230.0,99630.0,0.0072999997064471245,284.70001220703125,3.0,-0.10000000149011612,0.0
+2015-12-15 15:00:00,0.0,301.20001220703125,386.70001220703125,99670.0,0.0071000000461936,287.20001220703125,2.9000000953674316,-0.6000000238418579,0.0
+2015-12-15 16:00:00,0.0,301.20001220703125,475.1000061035156,99630.0,0.0072999997064471245,289.70001220703125,2.700000047683716,-0.10000000149011612,0.0
+2015-12-15 17:00:00,0.0,301.20001220703125,502.6000061035156,99560.0,0.007199999876320362,291.70001220703125,2.5,0.30000001192092896,0.0
+2015-12-15 18:00:00,0.0,315.8000183105469,490.0,99520.0,0.00699999975040555,293.6000061035156,2.200000047683716,0.699999988079071,0.0
+2015-12-15 19:00:00,0.0,315.8000183105469,431.70001220703125,99480.0,0.007199999876320362,295.20001220703125,2.0,0.5,0.0
+2015-12-15 20:00:00,0.0,315.8000183105469,337.1000061035156,99490.0,0.006899999920278788,295.6000061035156,1.7000000476837158,0.20000000298023224,0.0
+2015-12-15 21:00:00,0.0,305.8999938964844,148.5,99550.0,0.0071000000461936,295.3999938964844,1.399999976158142,0.0,0.0
+2015-12-15 22:00:00,0.0,305.8999938964844,27.200000762939453,99600.0,0.008100000210106373,292.3999938964844,1.100000023841858,0.30000001192092896,0.0
+2015-12-15 23:00:00,0.0,306.0,0.0,99620.0,0.008299999870359898,288.20001220703125,0.699999988079071,0.5,0.0
+2015-12-16 00:00:00,0.0,288.8999938964844,0.0,99650.0,0.00839999970048666,286.3000183105469,0.4000000059604645,0.800000011920929,0.0
+2015-12-16 01:00:00,0.0,288.8999938964844,0.0,99710.0,0.007999999448657036,285.5,0.20000000298023224,0.10000000149011612,0.0
+2015-12-16 02:00:00,0.0,288.8999938964844,0.0,99710.0,0.008299999870359898,285.0,0.0,-0.699999988079071,0.0
+2015-12-16 03:00:00,0.0,282.20001220703125,0.0,99740.0,0.008200000040233135,284.70001220703125,-0.30000001192092896,-1.399999976158142,0.0
+2015-12-16 04:00:00,0.0,282.20001220703125,0.0,99800.0,0.007799999788403511,283.8000183105469,-0.4000000059604645,-1.2000000476837158,0.0
+2015-12-16 05:00:00,0.0,282.20001220703125,0.0,99830.0,0.006899999920278788,281.20001220703125,-0.6000000238418579,-1.0,0.0
+2015-12-16 06:00:00,0.0,277.0,0.0,99820.0,0.006899999920278788,282.0,-0.699999988079071,-0.9000000357627869,0.0
+2015-12-16 07:00:00,0.0,277.0,0.0,99890.0,0.0064999996684491634,280.6000061035156,-0.9000000357627869,-0.800000011920929,0.0
+2015-12-16 08:00:00,0.0,277.0,0.0,99930.0,0.006300000008195639,279.8999938964844,-1.2000000476837158,-0.800000011920929,0.0
+2015-12-16 09:00:00,0.0,272.8000183105469,0.0,99880.0,0.006199999712407589,280.5,-1.399999976158142,-0.800000011920929,0.0
+2015-12-16 10:00:00,0.0,272.8000183105469,0.0,99880.0,0.006000000052154064,280.20001220703125,-1.8000000715255737,-0.800000011920929,0.0
+2015-12-16 11:00:00,0.0,272.8000183105469,0.0,99980.0,0.005399999674409628,278.3000183105469,-2.200000047683716,-0.800000011920929,0.0
+2015-12-16 12:00:00,0.0,267.5,0.0,100000.0,0.005499999970197678,278.20001220703125,-2.700000047683716,-0.800000011920929,0.0
+2015-12-16 13:00:00,0.0,267.5,81.30000305175781,100070.0,0.0058999997563660145,279.20001220703125,-2.5,-0.9000000357627869,0.0
+2015-12-16 14:00:00,0.0,267.5,230.10000610351562,100140.0,0.006799999624490738,281.5,-2.299999952316284,-1.0,0.0
+2015-12-16 15:00:00,0.0,293.8999938964844,387.3999938964844,100190.0,0.007499999832361937,284.8000183105469,-2.200000047683716,-1.100000023841858,0.0
+2015-12-16 16:00:00,0.0,293.8999938964844,476.6000061035156,100110.0,0.008499999530613422,288.70001220703125,-2.5,-0.6000000238418579,0.0
+2015-12-16 17:00:00,0.0,293.8999938964844,504.70001220703125,100060.0,0.007599999662488699,291.8000183105469,-2.9000000953674316,-0.10000000149011612,0.0
+2015-12-16 18:00:00,0.0,310.1000061035156,489.3000183105469,99980.0,0.007599999662488699,293.8000183105469,-3.299999952316284,0.4000000059604645,0.0
+2015-12-16 19:00:00,0.0,310.1000061035156,431.3000183105469,99930.0,0.007899999618530273,295.0,-3.1000001430511475,0.6000000238418579,0.0
+2015-12-16 20:00:00,0.0,310.1000061035156,337.20001220703125,99920.0,0.007999999448657036,295.20001220703125,-2.799999952316284,0.800000011920929,0.0
+2015-12-16 21:00:00,0.0,305.8000183105469,148.10000610351562,99810.0,0.007899999618530273,294.70001220703125,-2.6000001430511475,1.0,0.0
+2015-12-16 22:00:00,0.0,305.8000183105469,27.600000381469727,99850.0,0.008299999870359898,291.8999938964844,-2.799999952316284,0.6000000238418579,0.0
+2015-12-16 23:00:00,0.0,305.8000183105469,0.0,99890.0,0.008700000122189522,290.1000061035156,-3.0,0.30000001192092896,0.0
+2015-12-17 00:00:00,0.0,311.5,0.0,99900.0,0.008899999782443047,288.70001220703125,-3.200000047683716,0.0,0.0
+2015-12-17 01:00:00,0.0,311.5,0.0,100010.0,0.008599999360740185,286.0,-2.9000000953674316,0.10000000149011612,0.0
+2015-12-17 02:00:00,0.0,311.5,0.0,100000.0,0.008599999360740185,286.3000183105469,-2.6000001430511475,0.20000000298023224,0.0
+2015-12-17 03:00:00,0.0,342.0,0.0,99940.0,0.008499999530613422,286.6000061035156,-2.299999952316284,0.4000000059604645,2.3657042550979653e-07
+2015-12-17 04:00:00,0.5,342.0,0.0,99910.0,0.008799999952316284,287.5,-1.8000000715255737,0.4000000059604645,4.76594374793869e-07
+2015-12-17 05:00:00,1.0,342.0,0.0,99930.0,0.00930000003427267,287.20001220703125,-1.3000000715255737,0.5,1.426301595152609e-06
+2015-12-17 06:00:00,3.0,382.5,0.0,99760.0,0.009499999694526196,286.5,-0.800000011920929,0.5,4.727622629790369e-07
+2015-12-17 07:00:00,1.0,382.3999938964844,0.0,99720.0,0.009399999864399433,286.6000061035156,-1.2000000476837158,0.6000000238418579,1.0409098948042186e-06
+2015-12-17 08:00:00,2.200000047683716,382.3999938964844,0.0,99740.0,0.009499999694526196,286.6000061035156,-1.600000023841858,0.699999988079071,0.0
+2015-12-17 09:00:00,0.0,382.6000061035156,0.0,99710.0,0.00930000003427267,286.5,-2.0,0.699999988079071,0.0
+2015-12-17 10:00:00,0.0,382.6000061035156,0.0,99590.0,0.008999999612569809,286.20001220703125,-2.4000000953674316,0.699999988079071,0.0
+2015-12-17 11:00:00,0.0,382.6000061035156,0.0,99510.0,0.009099999442696571,286.6000061035156,-2.799999952316284,0.699999988079071,1.419422553058779e-06
+2015-12-17 12:00:00,3.0,384.20001220703125,0.0,99450.0,0.00930000003427267,286.3999938964844,-3.200000047683716,0.6000000238418579,2.0784926960470127e-06
+2015-12-17 13:00:00,4.400000095367432,384.20001220703125,34.5,99540.0,0.009499999694526196,286.5,-3.0,1.5,2.0801540021938852e-06
+2015-12-17 14:00:00,4.400000095367432,384.20001220703125,99.20000457763672,99540.0,0.00969999935477972,286.8999938964844,-2.799999952316284,2.4000000953674316,7.588522475838139e-07
+2015-12-17 15:00:00,1.600000023841858,404.20001220703125,157.0,99420.0,0.009800000116229057,287.3000183105469,-2.700000047683716,3.299999952316284,1.0943852648065907e-06
+2015-12-17 16:00:00,2.299999952316284,404.20001220703125,193.40000915527344,99470.0,0.009800000116229057,287.0,-0.6000000238418579,4.300000190734863,1.8037282986643158e-06
+2015-12-17 17:00:00,3.799999952316284,404.20001220703125,204.90000915527344,99360.0,0.009800000116229057,286.8999938964844,1.5,5.400000095367432,0.0
+2015-12-17 18:00:00,0.0,380.20001220703125,242.6999969482422,99310.0,0.010599999688565731,288.0,3.6000001430511475,6.400000095367432,0.0
+2015-12-17 19:00:00,0.0,380.20001220703125,214.10000610351562,99360.0,0.010999999940395355,289.3000183105469,3.799999952316284,5.599999904632568,0.0
+2015-12-17 20:00:00,0.0,380.20001220703125,167.60000610351562,99280.0,0.011399999260902405,289.20001220703125,4.0,4.800000190734863,0.0
+2015-12-17 21:00:00,0.0,371.1000061035156,72.30000305175781,99260.0,0.011399999260902405,289.70001220703125,4.200000286102295,4.0,0.0
+2015-12-17 22:00:00,0.0,371.1000061035156,13.699999809265137,99260.0,0.011899999342858791,289.70001220703125,3.700000047683716,3.9000000953674316,0.0
+2015-12-17 23:00:00,0.0,371.1000061035156,0.0,99330.0,0.011299999430775642,289.0,3.200000047683716,3.700000047683716,0.0
+2015-12-18 00:00:00,0.0,361.8000183105469,0.0,99330.0,0.01119999960064888,289.20001220703125,2.700000047683716,3.5,0.0
+2015-12-18 01:00:00,0.0,361.8000183105469,0.0,99410.0,0.010999999940395355,288.8000183105469,2.200000047683716,3.200000047683716,0.0
+2015-12-18 02:00:00,0.0,361.8000183105469,0.0,99440.0,0.010900000110268593,288.6000061035156,1.7000000476837158,2.9000000953674316,0.0
+2015-12-18 03:00:00,0.0,363.8000183105469,0.0,99430.0,0.010699999518692493,288.3999938964844,1.2000000476837158,2.6000001430511475,0.0
+2015-12-18 04:00:00,0.0,363.8000183105469,0.0,99460.0,0.010699999518692493,288.6000061035156,1.5,2.6000001430511475,0.0
+2015-12-18 05:00:00,0.0,363.8000183105469,0.0,99360.0,0.010699999518692493,288.1000061035156,1.7000000476837158,2.6000001430511475,0.0
+2015-12-18 06:00:00,0.0,344.3999938964844,0.0,99320.0,0.010699999518692493,287.70001220703125,1.899999976158142,2.700000047683716,0.0
+2015-12-18 07:00:00,0.0,344.3999938964844,0.0,99370.0,0.010400000028312206,288.1000061035156,2.0,2.4000000953674316,0.0
+2015-12-18 08:00:00,0.0,344.3999938964844,0.0,99390.0,0.009599999524652958,287.6000061035156,2.200000047683716,2.200000047683716,0.0
+2015-12-18 09:00:00,0.0,321.0,0.0,99340.0,0.009399999864399433,286.70001220703125,2.299999952316284,1.899999976158142,0.0
+2015-12-18 10:00:00,0.0,321.0,0.0,99390.0,0.00839999970048666,285.3000183105469,3.1000001430511475,1.8000000715255737,0.0
+2015-12-18 11:00:00,0.0,321.0,0.0,99440.0,0.0072999997064471245,283.8000183105469,3.799999952316284,1.600000023841858,0.0
+2015-12-18 12:00:00,0.0,269.0,0.0,99560.0,0.006899999920278788,282.8999938964844,4.599999904632568,1.5,0.0
+2015-12-18 13:00:00,0.0,269.0,82.20000457763672,99630.0,0.0066999997943639755,282.20001220703125,5.200000286102295,1.2000000476837158,0.0
+2015-12-18 14:00:00,0.0,269.0,239.3000030517578,99730.0,0.006300000008195639,282.3999938964844,5.700000286102295,0.800000011920929,0.0
+2015-12-18 15:00:00,0.0,263.5,388.8000183105469,99880.0,0.006000000052154064,282.20001220703125,6.300000190734863,0.5,0.0
+2015-12-18 16:00:00,0.0,263.5,479.70001220703125,99910.0,0.005699999630451202,284.0,6.800000190734863,0.20000000298023224,0.0
+2015-12-18 17:00:00,0.0,263.5,508.8999938964844,99850.0,0.0050999997183680534,285.1000061035156,7.300000190734863,-0.10000000149011612,0.0
+2015-12-18 18:00:00,0.0,260.0,503.1000061035156,99810.0,0.003999999724328518,286.70001220703125,7.800000190734863,-0.4000000059604645,0.0
+2015-12-18 19:00:00,0.0,260.0,444.20001220703125,99810.0,0.003399999812245369,287.1000061035156,7.200000286102295,-1.5,0.0
+2015-12-18 20:00:00,0.0,260.0,348.0,99920.0,0.002899999963119626,287.20001220703125,6.5,-2.6000001430511475,0.0
+2015-12-18 21:00:00,0.0,243.5,159.1999969482422,99950.0,0.0023999998811632395,286.1000061035156,5.800000190734863,-3.700000047683716,0.0
+2015-12-18 22:00:00,0.0,243.5,30.899999618530273,100130.0,0.002699999837204814,284.3999938964844,5.099999904632568,-3.4000000953674316,0.0
+2015-12-18 23:00:00,0.0,243.5,0.0,100260.0,0.003000000026077032,282.20001220703125,4.400000095367432,-3.1000001430511475,0.0
+2015-12-19 00:00:00,0.0,225.0,0.0,100400.0,0.0030999998562037945,280.5,3.6000001430511475,-2.799999952316284,0.0
+2015-12-19 01:00:00,0.0,225.0,0.0,100620.0,0.002899999963119626,278.8000183105469,3.4000000953674316,-2.6000001430511475,0.0
+2015-12-19 02:00:00,0.0,225.0,0.0,100790.0,0.00279999990016222,277.0,3.200000047683716,-2.299999952316284,0.0
+2015-12-19 03:00:00,0.0,214.6999969482422,0.0,100840.0,0.00279999990016222,276.0,2.9000000953674316,-2.1000001430511475,0.0
+2015-12-19 04:00:00,0.0,214.6999969482422,0.0,100940.0,0.002899999963119626,275.20001220703125,2.799999952316284,-2.1000001430511475,0.0
+2015-12-19 05:00:00,0.0,214.6999969482422,0.0,101020.0,0.00279999990016222,274.8000183105469,2.700000047683716,-2.0,0.0
+2015-12-19 06:00:00,0.0,206.60000610351562,0.0,101050.0,0.002199999988079071,274.1000061035156,2.6000001430511475,-2.0,0.0
+2015-12-19 07:00:00,0.0,206.60000610351562,0.0,101070.0,0.0024999999441206455,272.6000061035156,2.6000001430511475,-1.8000000715255737,0.0
+2015-12-19 08:00:00,0.0,206.60000610351562,0.0,101130.0,0.0023999998811632395,272.1000061035156,2.6000001430511475,-1.5,0.0
+2015-12-19 09:00:00,0.0,204.60000610351562,0.0,101190.0,0.0024999999441206455,271.70001220703125,2.5,-1.2000000476837158,0.0
+2015-12-19 10:00:00,0.0,204.60000610351562,0.0,101210.0,0.0026000000070780516,271.70001220703125,2.4000000953674316,-0.4000000059604645,0.0
+2015-12-19 11:00:00,0.0,204.60000610351562,0.0,101340.0,0.00279999990016222,270.6000061035156,2.200000047683716,0.4000000059604645,0.0
+2015-12-19 12:00:00,0.0,209.10000610351562,0.0,101420.0,0.002699999837204814,270.70001220703125,2.0,1.2000000476837158,0.0
+2015-12-19 13:00:00,0.0,209.10000610351562,79.0,101550.0,0.002899999963119626,271.3000183105469,2.1000001430511475,0.9000000357627869,0.0
+2015-12-19 14:00:00,0.0,209.10000610351562,233.0,101560.0,0.002899999963119626,273.5,2.200000047683716,0.6000000238418579,0.0
+2015-12-19 15:00:00,0.0,230.10000610351562,394.3000183105469,101690.0,0.00279999990016222,276.3999938964844,2.299999952316284,0.30000001192092896,0.0
+2015-12-19 16:00:00,0.0,230.10000610351562,487.0,101620.0,0.002300000051036477,279.3000183105469,2.9000000953674316,0.699999988079071,0.0
+2015-12-19 17:00:00,0.0,230.10000610351562,517.1000366210938,101550.0,0.002099999925121665,280.8000183105469,3.5,1.0,0.0
+2015-12-19 18:00:00,0.0,240.40000915527344,507.70001220703125,101500.0,0.0016999999061226845,281.70001220703125,4.099999904632568,1.3000000715255737,0.0
+2015-12-19 19:00:00,0.0,240.40000915527344,448.6000061035156,101460.0,0.0018999999156221747,282.6000061035156,3.9000000953674316,1.0,0.0
+2015-12-19 20:00:00,0.0,240.40000915527344,351.8000183105469,101410.0,0.002099999925121665,283.3999938964844,3.700000047683716,0.699999988079071,0.0
+2015-12-19 21:00:00,0.0,233.60000610351562,162.1999969482422,101410.0,0.002099999925121665,283.70001220703125,3.5,0.4000000059604645,0.0
+2015-12-19 22:00:00,0.0,233.60000610351562,32.10000228881836,101450.0,0.002099999925121665,282.3000183105469,3.200000047683716,0.699999988079071,0.0
+2015-12-19 23:00:00,0.0,233.60000610351562,0.0,101540.0,0.002699999837204814,278.8000183105469,2.9000000953674316,1.0,0.0
+2015-12-20 00:00:00,0.0,224.0,0.0,101560.0,0.003000000026077032,276.5,2.6000001430511475,1.3000000715255737,0.0
+2015-12-20 01:00:00,0.0,224.0,0.0,101590.0,0.0030999998562037945,275.8999938964844,2.299999952316284,0.9000000357627869,0.0
+2015-12-20 02:00:00,0.0,224.0,0.0,101580.0,0.003000000026077032,274.6000061035156,2.1000001430511475,0.6000000238418579,0.0
+2015-12-20 03:00:00,0.0,220.3000030517578,0.0,101540.0,0.003000000026077032,273.8000183105469,1.8000000715255737,0.20000000298023224,0.0
+2015-12-20 04:00:00,0.0,220.3000030517578,0.0,101590.0,0.003000000026077032,273.3000183105469,1.399999976158142,-0.4000000059604645,0.0
+2015-12-20 05:00:00,0.0,220.3000030517578,0.0,101620.0,0.002899999963119626,271.8000183105469,1.0,-1.100000023841858,0.0
+2015-12-20 06:00:00,0.0,218.0,0.0,101610.0,0.003000000026077032,272.1000061035156,0.6000000238418579,-1.7000000476837158,0.0
+2015-12-20 07:00:00,0.0,218.0,0.0,101640.0,0.003000000026077032,271.1000061035156,0.4000000059604645,-2.1000001430511475,0.0
+2015-12-20 08:00:00,0.0,218.0,0.0,101660.0,0.003000000026077032,271.5,0.20000000298023224,-2.4000000953674316,0.0
+2015-12-20 09:00:00,0.0,215.8000030517578,0.0,101690.0,0.002899999963119626,271.6000061035156,0.0,-2.799999952316284,0.0
+2015-12-20 10:00:00,0.0,215.8000030517578,0.0,101700.0,0.00279999990016222,271.0,-0.4000000059604645,-2.200000047683716,0.0
+2015-12-20 11:00:00,0.0,215.8000030517578,0.0,101720.0,0.00279999990016222,271.20001220703125,-0.800000011920929,-1.600000023841858,0.0
+2015-12-20 12:00:00,0.0,219.6999969482422,0.0,101720.0,0.00279999990016222,271.20001220703125,-1.3000000715255737,-1.0,0.0
+2015-12-20 13:00:00,0.0,219.6999969482422,76.80000305175781,101850.0,0.002899999963119626,271.20001220703125,-1.5,-0.800000011920929,0.0
+2015-12-20 14:00:00,0.0,219.6999969482422,229.6999969482422,101960.0,0.0031999999191612005,274.5,-1.7000000476837158,-0.699999988079071,0.0
+2015-12-20 15:00:00,0.0,242.6999969482422,390.3999938964844,101930.0,0.003000000026077032,278.6000061035156,-1.899999976158142,-0.5,0.0
+2015-12-20 16:00:00,0.0,242.6999969482422,482.8999938964844,101900.0,0.00279999990016222,282.1000061035156,-2.200000047683716,-0.10000000149011612,0.0
+2015-12-20 17:00:00,0.0,242.60000610351562,513.2000122070312,101840.0,0.0026000000070780516,284.5,-2.5,0.4000000059604645,0.0
+2015-12-20 18:00:00,0.0,254.8000030517578,500.70001220703125,101820.0,0.0023999998811632395,285.5,-2.799999952316284,0.800000011920929,0.0
+2015-12-20 19:00:00,0.0,254.8000030517578,442.8000183105469,101720.0,0.0024999999441206455,286.20001220703125,-2.700000047683716,0.9000000357627869,0.0
+2015-12-20 20:00:00,0.0,254.8000030517578,347.6000061035156,101690.0,0.0026000000070780516,286.1000061035156,-2.5,0.9000000357627869,0.0
+2015-12-20 21:00:00,0.0,253.3000030517578,173.0,101590.0,0.002699999837204814,285.3999938964844,-2.299999952316284,1.0,0.0
+2015-12-20 22:00:00,0.0,253.3000030517578,35.10000228881836,101600.0,0.002899999963119626,283.8999938964844,-2.700000047683716,1.0,0.0
+2015-12-20 23:00:00,0.0,253.3000030517578,0.0,101630.0,0.003399999812245369,281.6000061035156,-3.1000001430511475,1.100000023841858,0.0
+2015-12-21 00:00:00,0.0,250.10000610351562,0.0,101610.0,0.003700000001117587,279.70001220703125,-3.6000001430511475,1.2000000476837158,0.0
+2015-12-21 01:00:00,0.0,250.10000610351562,0.0,101580.0,0.003700000001117587,278.3999938964844,-3.299999952316284,0.6000000238418579,0.0
+2015-12-21 02:00:00,0.0,250.10000610351562,0.0,101630.0,0.003700000001117587,276.6000061035156,-3.1000001430511475,0.10000000149011612,0.0
+2015-12-21 03:00:00,0.0,266.5,0.0,101580.0,0.0037999998312443495,277.3000183105469,-2.799999952316284,-0.4000000059604645,0.0
+2015-12-21 04:00:00,0.0,266.5,0.0,101530.0,0.0037999998312443495,277.70001220703125,-2.799999952316284,-0.800000011920929,0.0
+2015-12-21 05:00:00,0.0,266.5,0.0,101500.0,0.0037999998312443495,277.1000061035156,-2.700000047683716,-1.100000023841858,0.0
+2015-12-21 06:00:00,0.0,289.0,0.0,101480.0,0.003999999724328518,278.0,-2.700000047683716,-1.399999976158142,0.0
+2015-12-21 07:00:00,0.0,289.0,0.0,101460.0,0.004100000020116568,279.1000061035156,-2.5,-1.399999976158142,0.0
+2015-12-21 08:00:00,0.0,289.0,0.0,101470.0,0.00419999985024333,279.0,-2.4000000953674316,-1.3000000715255737,0.0
+2015-12-21 09:00:00,0.0,334.1000061035156,0.0,101380.0,0.00419999985024333,279.3000183105469,-2.299999952316284,-1.2000000476837158,0.0
+2015-12-21 10:00:00,0.0,334.1000061035156,0.0,101340.0,0.004299999680370092,279.0,-2.200000047683716,-1.100000023841858,0.0
+2015-12-21 11:00:00,0.0,334.1000061035156,0.0,101290.0,0.00419999985024333,278.5,-2.1000001430511475,-1.100000023841858,0.0
+2015-12-21 12:00:00,0.0,352.8999938964844,0.0,101310.0,0.004399999976158142,279.1000061035156,-2.0,-1.0,0.0
+2015-12-21 13:00:00,0.0,352.8999938964844,33.29999923706055,101380.0,0.00419999985024333,279.5,-2.0,-0.9000000357627869,0.0
+2015-12-21 14:00:00,0.0,352.8999938964844,100.80000305175781,101310.0,0.00419999985024333,280.0,-2.0,-0.800000011920929,0.0
+2015-12-21 15:00:00,0.0,372.3999938964844,160.90000915527344,101310.0,0.004299999680370092,280.70001220703125,-2.0,-0.699999988079071,0.0
+2015-12-21 16:00:00,0.0,372.3999938964844,199.1999969482422,101300.0,0.0044999998062849045,282.6000061035156,-1.899999976158142,-0.4000000059604645,0.0
+2015-12-21 17:00:00,0.0,372.3999938964844,211.90000915527344,101220.0,0.004900000058114529,283.8000183105469,-1.7000000476837158,-0.20000000298023224,0.0
+2015-12-21 18:00:00,0.0,375.5,290.3999938964844,101150.0,0.004999999888241291,283.8999938964844,-1.5,0.10000000149011612,0.0
+2015-12-21 19:00:00,0.0,375.5,257.0,101050.0,0.005399999674409628,285.0,-1.600000023841858,0.10000000149011612,0.0
+2015-12-21 20:00:00,0.0,375.5,202.0,100890.0,0.00559999980032444,285.8000183105469,-1.8000000715255737,0.10000000149011612,0.0
+2015-12-21 21:00:00,0.0,361.70001220703125,132.8000030517578,100870.0,0.0058999997563660145,285.8000183105469,-1.899999976158142,0.10000000149011612,0.0
+2015-12-21 22:00:00,0.0,361.70001220703125,27.600000381469727,100820.0,0.006099999882280827,285.1000061035156,-2.200000047683716,0.4000000059604645,0.0
+2015-12-21 23:00:00,0.0,361.70001220703125,0.0,100830.0,0.006099999882280827,283.20001220703125,-2.5,0.699999988079071,0.0
+2015-12-22 00:00:00,0.0,357.0,0.0,100740.0,0.006199999712407589,283.20001220703125,-2.700000047683716,1.0,0.0
+2015-12-22 01:00:00,0.0,357.0,0.0,100760.0,0.0064999996684491634,283.0,-2.6000001430511475,0.9000000357627869,0.0
+2015-12-22 02:00:00,0.0,357.0,0.0,100770.0,0.006399999838322401,283.20001220703125,-2.5,0.800000011920929,0.0
+2015-12-22 03:00:00,0.0,369.20001220703125,0.0,100630.0,0.006300000008195639,282.1000061035156,-2.4000000953674316,0.699999988079071,0.0
+2015-12-22 04:00:00,0.0,369.20001220703125,0.0,100600.0,0.006300000008195639,282.5,-2.299999952316284,0.9000000357627869,0.0
+2015-12-22 05:00:00,0.0,369.20001220703125,0.0,100490.0,0.006599999964237213,283.1000061035156,-2.200000047683716,1.100000023841858,5.986149869805075e-07
+2015-12-22 06:00:00,1.3000000715255737,391.20001220703125,0.0,100310.0,0.00699999975040555,282.70001220703125,-2.1000001430511475,1.3000000715255737,2.8464086424883143e-06
+2015-12-22 07:00:00,6.200000286102295,391.1000061035156,0.0,100280.0,0.007499999832361937,283.5,-1.0,1.7000000476837158,3.00210506940693e-06
+2015-12-22 08:00:00,6.5,391.1000061035156,0.0,100110.0,0.008200000040233135,284.3000183105469,0.10000000149011612,2.0,3.392200346615728e-06
+2015-12-22 09:00:00,7.300000190734863,386.1000061035156,0.0,100030.0,0.008700000122189522,285.3000183105469,1.2000000476837158,2.4000000953674316,1.7654831463933217e-05
+2015-12-22 10:00:00,37.70000076293945,386.1000061035156,0.0,100100.0,0.009200000204145908,285.8999938964844,0.800000011920929,2.799999952316284,4.563967315233157e-06
+2015-12-22 11:00:00,9.699999809265137,386.1000061035156,0.0,100180.0,0.008899999782443047,285.3999938964844,0.6000000238418579,3.200000047683716,1.1716610241739401e-06
+2015-12-22 12:00:00,2.5,380.70001220703125,0.0,100160.0,0.009399999864399433,286.20001220703125,0.20000000298023224,3.6000001430511475,6.131225553307689e-07
+2015-12-22 13:00:00,1.3000000715255737,380.70001220703125,34.79999923706055,100130.0,0.009499999694526196,286.3000183105469,0.20000000298023224,3.6000001430511475,3.7760660823191564e-07
+2015-12-22 14:00:00,0.800000011920929,380.70001220703125,106.70000457763672,100230.0,0.009499999694526196,286.6000061035156,0.10000000149011612,3.700000047683716,0.0
+2015-12-22 15:00:00,0.0,384.8000183105469,237.60000610351562,100260.0,0.009999999776482582,287.20001220703125,0.10000000149011612,3.700000047683716,0.0
+2015-12-22 16:00:00,0.0,384.8000183105469,294.6000061035156,100210.0,0.010099999606609344,287.3999938964844,0.20000000298023224,3.5,0.0
+2015-12-22 17:00:00,0.0,384.8000183105469,313.6000061035156,100160.0,0.00989999994635582,287.0,0.30000001192092896,3.4000000953674316,0.0
+2015-12-22 18:00:00,0.0,392.8999938964844,306.5,100010.0,0.010300000198185444,288.0,0.4000000059604645,3.200000047683716,0.0
+2015-12-22 19:00:00,0.0,392.8999938964844,271.6000061035156,99990.0,0.011399999260902405,289.70001220703125,-0.10000000149011612,3.6000001430511475,0.0
+2015-12-22 20:00:00,0.0,392.8999938964844,213.6999969482422,99990.0,0.011699999682605267,290.20001220703125,-0.699999988079071,3.9000000953674316,0.0
+2015-12-22 21:00:00,0.0,388.3999938964844,118.30000305175781,100040.0,0.011599999852478504,290.0,-1.2000000476837158,4.300000190734863,0.0
+2015-12-22 22:00:00,0.0,388.3999938964844,25.200000762939453,99990.0,0.011399999260902405,289.6000061035156,-1.399999976158142,3.700000047683716,0.0
+2015-12-22 23:00:00,0.0,388.3999938964844,0.0,99990.0,0.010799999348819256,288.8000183105469,-1.600000023841858,3.1000001430511475,0.0
+2015-12-23 00:00:00,0.0,383.3000183105469,0.0,100050.0,0.011099999770522118,288.8000183105469,-1.8000000715255737,2.6000001430511475,0.0
+2015-12-23 01:00:00,0.0,383.3000183105469,0.0,100130.0,0.011099999770522118,289.20001220703125,-1.8000000715255737,2.200000047683716,0.0
+2015-12-23 02:00:00,0.0,383.3000183105469,0.0,100110.0,0.011099999770522118,288.8000183105469,-1.899999976158142,1.899999976158142,0.0
+2015-12-23 03:00:00,0.0,385.8000183105469,0.0,100090.0,0.011299999430775642,289.20001220703125,-2.0,1.5,0.0
+2015-12-23 04:00:00,0.0,385.8000183105469,0.0,100050.0,0.01119999960064888,289.0,-1.7000000476837158,1.600000023841858,0.0
+2015-12-23 05:00:00,0.0,385.8000183105469,0.0,100010.0,0.011699999682605267,289.5,-1.5,1.600000023841858,0.0
+2015-12-23 06:00:00,0.0,386.5,0.0,99980.0,0.011899999342858791,289.70001220703125,-1.2000000476837158,1.7000000476837158,0.0
+2015-12-23 07:00:00,0.0,386.5,0.0,100010.0,0.011599999852478504,289.8000183105469,-1.399999976158142,1.7000000476837158,0.0
+2015-12-23 08:00:00,0.0,386.5,0.0,100000.0,0.012000000104308128,289.70001220703125,-1.600000023841858,1.7000000476837158,0.0
+2015-12-23 09:00:00,0.0,391.0,0.0,99970.0,0.011899999342858791,289.8000183105469,-1.8000000715255737,1.7000000476837158,0.0
+2015-12-23 10:00:00,0.0,391.0,0.0,99940.0,0.011699999682605267,289.70001220703125,-2.1000001430511475,1.899999976158142,0.0
+2015-12-23 11:00:00,0.0,391.0,0.0,99920.0,0.011699999682605267,289.3999938964844,-2.5,2.1000001430511475,0.0
+2015-12-23 12:00:00,0.0,389.1000061035156,0.0,99900.0,0.011500000022351742,289.3000183105469,-2.799999952316284,2.4000000953674316,1.8866700062492885e-06
+2015-12-23 13:00:00,3.9000000953674316,389.1000061035156,42.400001525878906,99950.0,0.011699999682605267,289.70001220703125,-2.700000047683716,2.9000000953674316,5.824838155694726e-07
+2015-12-23 14:00:00,1.2000000476837158,389.1000061035156,131.6999969482422,99920.0,0.011899999342858791,289.8000183105469,-2.5,3.5,5.635471187070408e-06
+2015-12-23 15:00:00,11.600000381469727,393.8000183105469,163.0,99920.0,0.012000000104308128,290.0,-2.299999952316284,4.0,8.759635909420274e-07
+2015-12-23 16:00:00,1.8000000715255737,393.8000183105469,202.40000915527344,99860.0,0.01269999984651804,291.20001220703125,-1.899999976158142,4.099999904632568,4.4255319724101603e-07
+2015-12-23 17:00:00,0.9000000357627869,393.8000183105469,215.60000610351562,99740.0,0.013100000098347664,291.8999938964844,-1.399999976158142,4.099999904632568,0.0
+2015-12-23 18:00:00,0.0,405.20001220703125,182.3000030517578,99650.0,0.013700000010430813,292.20001220703125,-1.0,4.200000286102295,4.960924499258517e-06
+2015-12-23 19:00:00,10.0,405.20001220703125,161.60000610351562,99630.0,0.012899999506771564,291.6000061035156,-0.699999988079071,4.0,8.882235019915836e-07
+2015-12-23 20:00:00,1.8000000715255737,405.1000061035156,127.4000015258789,99690.0,0.012799999676644802,291.3000183105469,-0.4000000059604645,3.9000000953674316,2.9529413757094877e-07
+2015-12-23 21:00:00,0.6000000238418579,392.6000061035156,96.80000305175781,99740.0,0.013199999928474426,291.6000061035156,-0.10000000149011612,3.799999952316284,1.085606482825919e-06
+2015-12-23 22:00:00,2.200000047683716,392.6000061035156,21.100000381469727,99730.0,0.012399999424815178,290.8000183105469,-0.20000000298023224,3.200000047683716,3.430094869384076e-07
+2015-12-23 23:00:00,0.699999988079071,392.6000061035156,0.0,99800.0,0.012399999424815178,290.20001220703125,-0.4000000059604645,2.700000047683716,1.8524283800090267e-06
+2015-12-24 00:00:00,3.799999952316284,395.6000061035156,0.0,99980.0,0.012000000104308128,290.0,-0.5,2.200000047683716,6.813049765019497e-07
+2015-12-24 01:00:00,1.399999976158142,395.6000061035156,0.0,99950.0,0.011799999512732029,289.3999938964844,-1.0,2.299999952316284,1.0651743136309484e-06
+2015-12-24 02:00:00,2.200000047683716,395.6000061035156,0.0,100010.0,0.01209999993443489,290.3000183105469,-1.5,2.4000000953674316,7.806404696576303e-07
+2015-12-24 03:00:00,1.600000023841858,396.6000061035156,0.0,100050.0,0.01209999993443489,290.20001220703125,-2.0,2.5,7.799698656241153e-07
+2015-12-24 04:00:00,1.600000023841858,396.6000061035156,0.0,99960.0,0.011699999682605267,290.20001220703125,-1.3000000715255737,3.6000001430511475,0.0
+2015-12-24 05:00:00,0.0,396.6000061035156,0.0,100010.0,0.011799999512732029,289.8000183105469,-0.6000000238418579,4.700000286102295,0.0
+2015-12-24 06:00:00,0.0,392.8000183105469,0.0,99930.0,0.012199999764561653,290.3999938964844,0.10000000149011612,5.900000095367432,0.0
+2015-12-24 07:00:00,0.0,392.8000183105469,0.0,99960.0,0.012399999424815178,290.8000183105469,0.5,5.800000190734863,0.0
+2015-12-24 08:00:00,0.0,392.8000183105469,0.0,100010.0,0.012999999336898327,291.6000061035156,0.9000000357627869,5.800000190734863,0.0
+2015-12-24 09:00:00,0.0,379.6000061035156,0.0,99960.0,0.014099999330937862,293.3999938964844,1.3000000715255737,5.700000286102295,0.0
+2015-12-24 10:00:00,0.0,379.6000061035156,0.0,100010.0,0.014599999412894249,293.5,0.9000000357627869,4.700000286102295,0.0
+2015-12-24 11:00:00,0.0,379.6000061035156,0.0,100040.0,0.014599999412894249,293.8999938964844,0.5,3.700000047683716,0.0
+2015-12-24 12:00:00,0.0,379.20001220703125,0.0,100110.0,0.014699999243021011,293.70001220703125,0.0,2.700000047683716,0.0
+2015-12-24 13:00:00,0.0,379.20001220703125,49.5,100230.0,0.014699999243021011,294.0,0.699999988079071,3.0,0.0
+2015-12-24 14:00:00,0.0,379.20001220703125,155.6999969482422,100320.0,0.014599999412894249,294.20001220703125,1.3000000715255737,3.4000000953674316,0.0
+2015-12-24 15:00:00,0.0,397.6000061035156,267.3000183105469,100410.0,0.01489999983459711,294.8000183105469,2.0,3.799999952316284,0.0
+2015-12-24 16:00:00,0.0,397.6000061035156,332.1000061035156,100400.0,0.01489999983459711,295.6000061035156,3.1000001430511475,3.6000001430511475,0.0
+2015-12-24 17:00:00,0.0,397.6000061035156,354.1000061035156,100420.0,0.01529999915510416,295.1000061035156,4.099999904632568,3.4000000953674316,0.0
+2015-12-24 18:00:00,0.0,400.70001220703125,329.8000183105469,100330.0,0.015599999576807022,295.0,5.200000286102295,3.200000047683716,0.0
+2015-12-24 19:00:00,0.0,400.70001220703125,292.70001220703125,100360.0,0.01549999974668026,295.0,4.700000286102295,2.799999952316284,0.0
+2015-12-24 20:00:00,0.0,400.70001220703125,231.0,100360.0,0.01529999915510416,295.0,4.300000190734863,2.4000000953674316,0.0
+2015-12-24 21:00:00,0.0,403.8000183105469,93.20000457763672,100290.0,0.015199999324977398,295.20001220703125,3.799999952316284,2.0,0.0
+2015-12-24 22:00:00,0.0,403.8000183105469,20.80000114440918,100430.0,0.015699999406933784,294.8999938964844,2.4000000953674316,2.0,3.0511935942961847e-07
+2015-12-24 23:00:00,0.6000000238418579,403.8000183105469,0.0,100520.0,0.014999999664723873,294.5,1.0,2.0,7.599401290699011e-07
+2015-12-25 00:00:00,1.5,391.70001220703125,0.0,100450.0,0.014800000004470348,294.3999938964844,-0.4000000059604645,2.0,5.061538553138688e-08
+2015-12-25 01:00:00,0.10000000149011612,391.70001220703125,0.0,100600.0,0.013199999928474426,292.3999938964844,0.4000000059604645,1.899999976158142,0.0
+2015-12-25 02:00:00,0.0,391.70001220703125,0.0,100720.0,0.012600000016391277,291.8000183105469,1.2000000476837158,1.8000000715255737,0.0
+2015-12-25 03:00:00,0.0,379.20001220703125,0.0,100750.0,0.01269999984651804,291.8000183105469,2.0,1.7000000476837158,1.977323365029267e-07
+2015-12-25 04:00:00,0.4000000059604645,379.20001220703125,0.0,100800.0,0.01249999925494194,291.70001220703125,2.0,1.100000023841858,0.0
+2015-12-25 05:00:00,0.0,379.20001220703125,0.0,100790.0,0.012299999594688416,291.3000183105469,2.0,0.5,9.843137674574662e-08
+2015-12-25 06:00:00,0.20000000298023224,382.1000061035156,0.0,100810.0,0.01249999925494194,291.3999938964844,2.0,-0.10000000149011612,0.0
+2015-12-25 07:00:00,0.0,382.1000061035156,0.0,100770.0,0.012399999424815178,291.0,1.600000023841858,-0.30000001192092896,9.817343559310722e-08
+2015-12-25 08:00:00,0.20000000298023224,382.1000061035156,0.0,100770.0,0.01249999925494194,290.8000183105469,1.3000000715255737,-0.4000000059604645,0.0
+2015-12-25 09:00:00,0.0,386.20001220703125,0.0,100830.0,0.012199999764561653,290.8000183105469,0.9000000357627869,-0.6000000238418579,0.0
+2015-12-25 10:00:00,0.0,386.20001220703125,0.0,100760.0,0.011799999512732029,290.20001220703125,0.0,-0.30000001192092896,0.0
+2015-12-25 11:00:00,0.0,386.20001220703125,0.0,100790.0,0.011899999342858791,290.3999938964844,-0.9000000357627869,-0.10000000149011612,0.0
+2015-12-25 12:00:00,0.0,382.70001220703125,0.0,100870.0,0.01119999960064888,289.5,-1.7000000476837158,0.20000000298023224,0.0
+2015-12-25 13:00:00,0.0,382.70001220703125,55.29999923706055,100890.0,0.011799999512732029,289.6000061035156,-1.399999976158142,0.5,0.0
+2015-12-25 14:00:00,0.0,382.70001220703125,175.90000915527344,100880.0,0.012299999594688416,291.20001220703125,-1.100000023841858,0.800000011920929,0.0
+2015-12-25 15:00:00,0.0,391.3000183105469,320.20001220703125,100870.0,0.013399999588727951,293.0,-0.800000011920929,1.0,0.0
+2015-12-25 16:00:00,0.0,391.3000183105469,398.3000183105469,100910.0,0.013700000010430813,294.0,-0.30000001192092896,1.5,0.0
+2015-12-25 17:00:00,0.0,391.20001220703125,425.1000061035156,100780.0,0.014299999922513962,294.3000183105469,0.20000000298023224,2.1000001430511475,0.0
+2015-12-25 18:00:00,0.0,405.6000061035156,401.1000061035156,100700.0,0.01489999983459711,294.8999938964844,0.699999988079071,2.6000001430511475,0.0
+2015-12-25 19:00:00,0.0,405.6000061035156,356.20001220703125,100690.0,0.014800000004470348,296.20001220703125,1.100000023841858,2.5,0.0
+2015-12-25 20:00:00,0.0,405.6000061035156,281.6000061035156,100710.0,0.014999999664723873,296.3999938964844,1.600000023841858,2.4000000953674316,0.0
+2015-12-25 21:00:00,0.0,404.20001220703125,123.80000305175781,100660.0,0.015099999494850636,297.0,2.0,2.299999952316284,0.0
+2015-12-25 22:00:00,0.0,404.20001220703125,28.399999618530273,100720.0,0.015199999324977398,296.1000061035156,1.3000000715255737,2.0,0.0
+2015-12-25 23:00:00,0.0,404.20001220703125,0.0,100800.0,0.015399999916553497,295.1000061035156,0.699999988079071,1.8000000715255737,0.0
+2015-12-26 00:00:00,0.0,398.3000183105469,0.0,100870.0,0.014599999412894249,294.1000061035156,0.0,1.5,0.0
+2015-12-26 01:00:00,0.0,398.3000183105469,0.0,100890.0,0.013599999248981476,292.8999938964844,-0.4000000059604645,0.9000000357627869,7.488365405375216e-07
+2015-12-26 02:00:00,1.5,398.3000183105469,0.0,100970.0,0.013399999588727951,292.1000061035156,-0.9000000357627869,0.20000000298023224,0.0
+2015-12-26 03:00:00,0.0,397.8999938964844,0.0,100910.0,0.012899999506771564,291.70001220703125,-1.3000000715255737,-0.5,0.0
+2015-12-26 04:00:00,0.0,397.8999938964844,0.0,100900.0,0.01249999925494194,291.3000183105469,-1.2000000476837158,-0.6000000238418579,0.0
+2015-12-26 05:00:00,0.0,397.8999938964844,0.0,100910.0,0.011799999512732029,290.3000183105469,-1.0,-0.699999988079071,0.0
+2015-12-26 06:00:00,0.0,385.8999938964844,0.0,100880.0,0.012299999594688416,291.0,-0.800000011920929,-0.800000011920929,0.0
+2015-12-26 07:00:00,0.0,385.8999938964844,0.0,100940.0,0.011599999852478504,290.5,-1.3000000715255737,-0.6000000238418579,0.0
+2015-12-26 08:00:00,0.0,385.8999938964844,0.0,100930.0,0.011599999852478504,290.20001220703125,-1.7000000476837158,-0.5,0.0
+2015-12-26 09:00:00,0.0,379.5,0.0,100900.0,0.010799999348819256,289.3999938964844,-2.1000001430511475,-0.30000001192092896,0.0
+2015-12-26 10:00:00,0.0,379.5,0.0,100840.0,0.010799999348819256,289.1000061035156,-1.8000000715255737,-0.5,0.0
+2015-12-26 11:00:00,0.0,379.5,0.0,100760.0,0.011099999770522118,289.3999938964844,-1.5,-0.699999988079071,0.0
+2015-12-26 12:00:00,0.0,364.70001220703125,0.0,100780.0,0.01119999960064888,289.8000183105469,-1.2000000476837158,-0.9000000357627869,0.0
+2015-12-26 13:00:00,0.0,364.70001220703125,62.900001525878906,100880.0,0.010999999940395355,289.20001220703125,-1.3000000715255737,-0.800000011920929,0.0
+2015-12-26 14:00:00,0.0,364.70001220703125,202.40000915527344,100980.0,0.011699999682605267,290.8000183105469,-1.399999976158142,-0.800000011920929,0.0
+2015-12-26 15:00:00,0.0,376.6000061035156,354.8000183105469,101080.0,0.01269999984651804,292.5,-1.5,-0.699999988079071,0.0
+2015-12-26 16:00:00,0.0,376.6000061035156,442.0,101100.0,0.012999999336898327,294.0,-1.3000000715255737,0.20000000298023224,0.0
+2015-12-26 17:00:00,0.0,376.5,472.0,100970.0,0.013100000098347664,295.0,-1.100000023841858,1.0,0.0
+2015-12-26 18:00:00,0.0,386.6000061035156,470.6000061035156,100840.0,0.013399999588727951,296.0,-0.9000000357627869,1.899999976158142,0.0
+2015-12-26 19:00:00,0.0,386.6000061035156,418.3999938964844,100840.0,0.013599999248981476,297.3999938964844,-0.800000011920929,1.899999976158142,0.0
+2015-12-26 20:00:00,0.0,386.6000061035156,331.20001220703125,100780.0,0.013799999840557575,297.20001220703125,-0.800000011920929,1.8000000715255737,0.0
+2015-12-26 21:00:00,0.0,373.20001220703125,153.10000610351562,100780.0,0.013799999840557575,296.70001220703125,-0.699999988079071,1.8000000715255737,0.0
+2015-12-26 22:00:00,0.0,373.20001220703125,36.0,100790.0,0.013899999670684338,295.3000183105469,-1.3000000715255737,1.8000000715255737,0.0
+2015-12-26 23:00:00,0.0,373.20001220703125,0.0,100820.0,0.013899999670684338,293.8999938964844,-2.0,1.899999976158142,0.0
+2015-12-27 00:00:00,0.0,358.3999938964844,0.0,100880.0,0.013700000010430813,293.20001220703125,-2.6000001430511475,2.0,0.0
+2015-12-27 01:00:00,0.0,358.3999938964844,0.0,100850.0,0.013499999418854713,293.20001220703125,-2.6000001430511475,1.8000000715255737,0.0
+2015-12-27 02:00:00,0.0,358.3999938964844,0.0,100870.0,0.013299999758601189,292.5,-2.6000001430511475,1.600000023841858,0.0
+2015-12-27 03:00:00,0.0,351.20001220703125,0.0,100870.0,0.013599999248981476,292.1000061035156,-2.6000001430511475,1.5,0.0
+2015-12-27 04:00:00,0.0,351.20001220703125,0.0,100840.0,0.012999999336898327,291.70001220703125,-2.4000000953674316,1.600000023841858,0.0
+2015-12-27 05:00:00,0.0,351.20001220703125,0.0,100770.0,0.013399999588727951,292.3000183105469,-2.200000047683716,1.8000000715255737,0.0
+2015-12-27 06:00:00,0.0,359.8999938964844,0.0,100740.0,0.013399999588727951,292.20001220703125,-2.0,2.0,0.0
+2015-12-27 07:00:00,0.0,359.8999938964844,0.0,100680.0,0.013799999840557575,292.3999938964844,-1.899999976158142,1.8000000715255737,0.0
+2015-12-27 08:00:00,0.0,359.8999938964844,0.0,100750.0,0.013700000010430813,292.3000183105469,-1.8000000715255737,1.600000023841858,0.0
+2015-12-27 09:00:00,0.0,369.1000061035156,0.0,100630.0,0.013799999840557575,292.8000183105469,-1.600000023841858,1.399999976158142,0.0
+2015-12-27 10:00:00,0.0,369.1000061035156,0.0,100650.0,0.013799999840557575,292.5,-1.7000000476837158,1.399999976158142,0.0
+2015-12-27 11:00:00,0.0,369.1000061035156,0.0,100620.0,0.013700000010430813,292.70001220703125,-1.8000000715255737,1.399999976158142,0.0
+2015-12-27 12:00:00,0.0,366.3999938964844,0.0,100650.0,0.013499999418854713,292.3999938964844,-1.899999976158142,1.399999976158142,0.0
+2015-12-27 13:00:00,0.0,366.3999938964844,38.10000228881836,100620.0,0.012799999676644802,292.20001220703125,-1.3000000715255737,1.0,7.441386748887777e-07
+2015-12-27 14:00:00,1.5,366.3999938964844,123.9000015258789,100640.0,0.013199999928474426,292.20001220703125,-0.699999988079071,0.5,2.133197629303288e-06
+2015-12-27 15:00:00,4.300000190734863,391.1000061035156,208.8000030517578,100620.0,0.013399999588727951,292.20001220703125,-0.10000000149011612,0.0,0.0
+2015-12-27 16:00:00,0.0,391.0,260.20001220703125,100590.0,0.013599999248981476,293.1000061035156,0.20000000298023224,0.5,0.0
+2015-12-27 17:00:00,0.0,391.0,278.20001220703125,100480.0,0.0142000000923872,293.70001220703125,0.6000000238418579,1.0,0.0
+2015-12-27 18:00:00,0.0,394.5,305.3999938964844,100380.0,0.014299999922513962,294.20001220703125,1.0,1.5,0.0
+2015-12-27 19:00:00,0.0,394.5,271.8000183105469,100290.0,0.014699999243021011,295.5,1.0,1.600000023841858,0.0
+2015-12-27 20:00:00,0.0,394.3999938964844,215.5,100240.0,0.014499999582767487,295.8999938964844,1.100000023841858,1.7000000476837158,0.0
+2015-12-27 21:00:00,0.0,388.6000061035156,140.40000915527344,100200.0,0.014599999412894249,295.5,1.100000023841858,1.7000000476837158,0.0
+2015-12-27 22:00:00,0.0,388.6000061035156,33.900001525878906,100260.0,0.014599999412894249,294.8999938964844,0.4000000059604645,1.899999976158142,0.0
+2015-12-27 23:00:00,0.0,388.6000061035156,0.0,100270.0,0.014999999664723873,294.70001220703125,-0.30000001192092896,2.1000001430511475,0.0
+2015-12-28 00:00:00,0.0,373.20001220703125,0.0,100260.0,0.014499999582767487,293.6000061035156,-1.0,2.299999952316284,0.0
+2015-12-28 01:00:00,0.0,373.20001220703125,0.0,100310.0,0.013499999418854713,291.8999938964844,-1.2000000476837158,2.299999952316284,0.0
+2015-12-28 02:00:00,0.0,373.20001220703125,0.0,100320.0,0.012999999336898327,291.70001220703125,-1.399999976158142,2.200000047683716,0.0
+2015-12-28 03:00:00,0.0,338.8999938964844,0.0,100320.0,0.012899999506771564,291.3999938964844,-1.600000023841858,2.200000047683716,0.0
+2015-12-28 04:00:00,0.0,338.8999938964844,0.0,100370.0,0.012799999676644802,291.6000061035156,-1.7000000476837158,2.200000047683716,0.0
+2015-12-28 05:00:00,0.0,338.8999938964844,0.0,100340.0,0.012799999676644802,291.1000061035156,-1.8000000715255737,2.200000047683716,0.0
+2015-12-28 06:00:00,0.0,342.3000183105469,0.0,100290.0,0.013499999418854713,291.8999938964844,-1.899999976158142,2.200000047683716,0.0
+2015-12-28 07:00:00,0.0,342.3000183105469,0.0,100300.0,0.013399999588727951,291.8999938964844,-2.1000001430511475,1.7000000476837158,0.0
+2015-12-28 08:00:00,0.0,342.3000183105469,0.0,100340.0,0.013299999758601189,291.70001220703125,-2.4000000953674316,1.100000023841858,0.0
+2015-12-28 09:00:00,0.0,342.1000061035156,0.0,100280.0,0.013299999758601189,291.70001220703125,-2.700000047683716,0.6000000238418579,0.0
+2015-12-28 10:00:00,0.0,342.1000061035156,0.0,100280.0,0.012999999336898327,291.70001220703125,-2.700000047683716,0.5,0.0
+2015-12-28 11:00:00,0.0,342.1000061035156,0.0,100250.0,0.012899999506771564,291.5,-2.700000047683716,0.5,0.0
+2015-12-28 12:00:00,0.0,349.5,0.0,100320.0,0.012799999676644802,291.20001220703125,-2.700000047683716,0.5,0.0
+2015-12-28 13:00:00,0.0,349.5,51.5,100330.0,0.012899999506771564,291.70001220703125,-2.700000047683716,0.10000000149011612,0.0
+2015-12-28 14:00:00,0.0,349.5,169.0,100350.0,0.012899999506771564,291.6000061035156,-2.700000047683716,-0.20000000298023224,0.0
+2015-12-28 15:00:00,0.0,388.6000061035156,240.6999969482422,100330.0,0.013299999758601189,292.20001220703125,-2.700000047683716,-0.5,0.0
+2015-12-28 16:00:00,0.0,388.6000061035156,300.3999938964844,100370.0,0.0142000000923872,293.0,-3.4000000953674316,0.0,0.0
+2015-12-28 17:00:00,0.0,388.5,321.3999938964844,100250.0,0.014599999412894249,293.70001220703125,-4.099999904632568,0.5,0.0
+2015-12-28 18:00:00,0.0,413.5,234.5,100190.0,0.014699999243021011,294.6000061035156,-4.800000190734863,1.0,0.0
+2015-12-28 19:00:00,0.0,413.5,208.90000915527344,100100.0,0.014599999412894249,296.1000061035156,-5.200000286102295,1.100000023841858,0.0
+2015-12-28 20:00:00,0.0,413.5,165.8000030517578,99980.0,0.013799999840557575,296.6000061035156,-5.599999904632568,1.3000000715255737,0.0
+2015-12-28 21:00:00,0.0,390.0,130.5,99910.0,0.013700000010430813,295.8999938964844,-6.0,1.399999976158142,0.0
+2015-12-28 22:00:00,0.0,390.0,32.400001525878906,99950.0,0.0139999995008111,295.1000061035156,-6.400000095367432,1.8000000715255737,0.0
+2015-12-28 23:00:00,0.0,390.1000061035156,0.0,99940.0,0.014999999664723873,294.6000061035156,-6.900000095367432,2.200000047683716,0.0
+2015-12-29 00:00:00,0.0,380.1000061035156,0.0,99970.0,0.01489999983459711,294.6000061035156,-7.400000095367432,2.6000001430511475,0.0
+2015-12-29 01:00:00,0.0,380.1000061035156,0.0,99980.0,0.01549999974668026,295.1000061035156,-6.300000190734863,2.6000001430511475,0.0
+2015-12-29 02:00:00,0.0,380.1000061035156,0.0,99940.0,0.015799999237060547,295.3999938964844,-5.300000190734863,2.6000001430511475,0.0
+2015-12-29 03:00:00,0.0,388.70001220703125,0.0,99940.0,0.01529999915510416,295.1000061035156,-4.300000190734863,2.6000001430511475,2.0379742621031308e-07
+2015-12-29 04:00:00,0.4000000059604645,388.70001220703125,0.0,99940.0,0.015399999916553497,295.0,-3.299999952316284,3.200000047683716,5.090121965577734e-08
+2015-12-29 05:00:00,0.10000000149011612,388.70001220703125,0.0,99950.0,0.014999999664723873,294.70001220703125,-2.299999952316284,3.9000000953674316,1.1166688889383383e-06
+2015-12-29 06:00:00,2.200000047683716,398.3999938964844,0.0,99910.0,0.014800000004470348,294.20001220703125,-1.3000000715255737,4.5,1.1619883724544963e-06
+2015-12-29 07:00:00,2.299999952316284,398.3999938964844,0.0,99880.0,0.014999999664723873,294.8000183105469,-0.20000000298023224,4.900000095367432,2.591074675310334e-06
+2015-12-29 08:00:00,5.099999904632568,398.3999938964844,0.0,99870.0,0.014499999582767487,294.3999938964844,0.800000011920929,5.300000190734863,2.9863077501229664e-06
+2015-12-29 09:00:00,5.900000095367432,387.5,0.0,99900.0,0.014299999922513962,293.5,1.8000000715255737,5.700000286102295,7.529397965630518e-07
+2015-12-29 10:00:00,1.5,387.5,0.0,99920.0,0.0139999995008111,293.20001220703125,2.4000000953674316,5.0,5.506448621350923e-07
+2015-12-29 11:00:00,1.100000023841858,387.5,0.0,99960.0,0.014399999752640724,293.3000183105469,3.1000001430511475,4.400000095367432,0.0
+2015-12-29 12:00:00,0.0,381.5,0.0,99990.0,0.0139999995008111,293.3000183105469,3.700000047683716,3.799999952316284,0.0
+2015-12-29 13:00:00,0.0,381.5,35.5,100080.0,0.0139999995008111,293.1000061035156,3.5,3.6000001430511475,0.0
+2015-12-29 14:00:00,0.0,381.5,117.5999984741211,100180.0,0.0142000000923872,293.3000183105469,3.4000000953674316,3.5,0.0
+2015-12-29 15:00:00,0.0,373.70001220703125,246.90000915527344,100210.0,0.014800000004470348,294.8000183105469,3.200000047683716,3.4000000953674316,0.0
+2015-12-29 16:00:00,0.0,373.70001220703125,308.3999938964844,100230.0,0.014099999330937862,294.5,3.4000000953674316,3.5,0.0
+2015-12-29 17:00:00,0.0,373.70001220703125,330.20001220703125,100220.0,0.013700000010430813,294.3999938964844,3.6000001430511475,3.6000001430511475,0.0
+2015-12-29 18:00:00,0.0,375.20001220703125,375.70001220703125,100160.0,0.013299999758601189,294.8000183105469,3.700000047683716,3.700000047683716,0.0
+2015-12-29 19:00:00,0.0,375.20001220703125,335.1000061035156,100100.0,0.013599999248981476,296.8999938964844,3.299999952316284,3.4000000953674316,0.0
+2015-12-29 20:00:00,0.0,375.20001220703125,266.5,100140.0,0.013599999248981476,296.8999938964844,2.9000000953674316,3.1000001430511475,0.0
+2015-12-29 21:00:00,0.0,365.6000061035156,145.5,100170.0,0.013399999588727951,296.3999938964844,2.5,2.799999952316284,0.0
+2015-12-29 22:00:00,0.0,365.6000061035156,37.0,100250.0,0.01249999925494194,295.3000183105469,2.200000047683716,2.4000000953674316,0.0
+2015-12-29 23:00:00,0.0,365.6000061035156,0.0,100310.0,0.013299999758601189,293.70001220703125,1.899999976158142,2.0,0.0
+2015-12-30 00:00:00,0.0,337.70001220703125,0.0,100400.0,0.013299999758601189,292.70001220703125,1.600000023841858,1.600000023841858,0.0
+2015-12-30 01:00:00,0.0,337.70001220703125,0.0,100430.0,0.013199999928474426,292.6000061035156,1.2000000476837158,1.5,0.0
+2015-12-30 02:00:00,0.0,337.70001220703125,0.0,100530.0,0.012899999506771564,291.70001220703125,0.800000011920929,1.399999976158142,0.0
+2015-12-30 03:00:00,0.0,336.8999938964844,0.0,100520.0,0.01269999984651804,291.20001220703125,0.4000000059604645,1.2000000476837158,0.0
+2015-12-30 04:00:00,0.0,336.8999938964844,0.0,100570.0,0.012399999424815178,290.8999938964844,0.20000000298023224,1.3000000715255737,0.0
+2015-12-30 05:00:00,0.0,336.8999938964844,0.0,100590.0,0.011599999852478504,289.8999938964844,0.0,1.3000000715255737,0.0
+2015-12-30 06:00:00,0.0,353.0,0.0,100620.0,0.012000000104308128,290.1000061035156,-0.20000000298023224,1.3000000715255737,0.0
+2015-12-30 07:00:00,0.0,353.0,0.0,100610.0,0.011899999342858791,290.5,-0.6000000238418579,0.800000011920929,0.0
+2015-12-30 08:00:00,0.0,353.0,0.0,100590.0,0.012000000104308128,290.3999938964844,-1.0,0.20000000298023224,0.0
+2015-12-30 09:00:00,0.0,392.3999938964844,0.0,100630.0,0.011899999342858791,290.3999938964844,-1.399999976158142,-0.4000000059604645,3.418243187032877e-07
+2015-12-30 10:00:00,0.699999988079071,392.3999938964844,0.0,100590.0,0.012399999424815178,290.6000061035156,-1.3000000715255737,-0.20000000298023224,6.848304672955347e-07
+2015-12-30 11:00:00,1.399999976158142,392.3999938964844,0.0,100560.0,0.01249999925494194,291.1000061035156,-1.3000000715255737,0.0,0.0
+2015-12-30 12:00:00,0.0,396.8000183105469,0.0,100510.0,0.01269999984651804,291.3000183105469,-1.3000000715255737,0.20000000298023224,0.0
+2015-12-30 13:00:00,0.0,396.8000183105469,24.600000381469727,100620.0,0.012600000016391277,291.70001220703125,-0.699999988079071,0.20000000298023224,0.0
+2015-12-30 14:00:00,0.0,396.8000183105469,82.0999984741211,100630.0,0.013399999588727951,292.5,-0.20000000298023224,0.10000000149011612,4.9742695856783285e-08
+2015-12-30 15:00:00,0.10000000149011612,400.3000183105469,134.60000610351562,100600.0,0.014099999330937862,293.5,0.30000001192092896,0.0,4.2164631479768285e-06
+2015-12-30 16:00:00,8.40000057220459,400.3000183105469,168.3000030517578,100640.0,0.0139999995008111,292.3999938964844,0.5,0.6000000238418579,1.7294931218208543e-05
+2015-12-30 17:00:00,34.79999923706055,400.3000183105469,180.3000030517578,100590.0,0.012999999336898327,291.5,0.699999988079071,1.3000000715255737,3.599065574767947e-06
+2015-12-30 18:00:00,7.300000190734863,402.20001220703125,183.3000030517578,100610.0,0.012600000016391277,290.8999938964844,0.800000011920929,2.0,2.305066719490677e-06
+2015-12-30 19:00:00,4.700000286102295,402.20001220703125,163.60000610351562,100560.0,0.01249999925494194,291.0,0.800000011920929,1.899999976158142,1.816208554815238e-06
+2015-12-30 20:00:00,3.700000047683716,402.20001220703125,130.3000030517578,100490.0,0.012799999676644802,291.0,0.800000011920929,1.8000000715255737,2.061642257172614e-06
+2015-12-30 21:00:00,4.200000286102295,399.20001220703125,80.4000015258789,100470.0,0.012600000016391277,291.1000061035156,0.800000011920929,1.7000000476837158,4.07775568914086e-06
+2015-12-30 22:00:00,8.300000190734863,399.20001220703125,21.0,100450.0,0.012600000016391277,290.8999938964844,1.0,1.399999976158142,1.6184509790133084e-06
+2015-12-30 23:00:00,3.299999952316284,399.20001220703125,0.0,100520.0,0.01269999984651804,291.1000061035156,1.2000000476837158,1.2000000476837158,6.878141851067213e-07
diff --git a/python/runCalibValid/ngen_cal/tests/data/cat-92_2015-12-01 00_00_00_2015-12-30 23_00_00.csv b/python/runCalibValid/ngen_cal/tests/data/cat-92_2015-12-01 00_00_00_2015-12-30 23_00_00.csv
new file mode 100644
index 00000000..7ce270c7
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/cat-92_2015-12-01 00_00_00_2015-12-30 23_00_00.csv
@@ -0,0 +1,721 @@
+time,APCP_surface,DLWRF_surface,DSWRF_surface,PRES_surface,SPFH_2maboveground,TMP_2maboveground,UGRD_10maboveground,VGRD_10maboveground,precip_rate
+2015-12-01 00:00:00,0.0,361.20001220703125,0.0,100530.0,0.010499999858438969,287.5,-2.6000001430511475,0.0,0.0
+2015-12-01 01:00:00,0.0,361.20001220703125,0.0,100610.0,0.009800000116229057,287.3000183105469,-2.700000047683716,-0.30000001192092896,0.0
+2015-12-01 02:00:00,0.0,361.20001220703125,0.0,100600.0,0.009099999442696571,286.6000061035156,-2.799999952316284,-0.6000000238418579,0.0
+2015-12-01 03:00:00,0.0,357.6000061035156,0.0,100570.0,0.008700000122189522,285.5,-2.9000000953674316,-0.9000000357627869,0.0
+2015-12-01 04:00:00,0.0,357.6000061035156,0.0,100590.0,0.00839999970048666,284.3000183105469,-2.6000001430511475,-0.30000001192092896,0.0
+2015-12-01 05:00:00,0.0,357.6000061035156,0.0,100540.0,0.007999999448657036,283.8999938964844,-2.299999952316284,0.4000000059604645,0.0
+2015-12-01 06:00:00,0.0,344.1000061035156,0.0,100510.0,0.007699999958276749,283.6000061035156,-2.0,1.0,0.0
+2015-12-01 07:00:00,0.0,344.1000061035156,0.0,100490.0,0.007400000002235174,283.20001220703125,-2.1000001430511475,0.699999988079071,0.0
+2015-12-01 08:00:00,0.0,344.1000061035156,0.0,100550.0,0.007199999876320362,282.8999938964844,-2.200000047683716,0.5,0.0
+2015-12-01 09:00:00,0.0,335.0,0.0,100460.0,0.00699999975040555,282.5,-2.299999952316284,0.20000000298023224,0.0
+2015-12-01 10:00:00,0.0,335.0,0.0,100470.0,0.00699999975040555,282.3000183105469,-2.4000000953674316,0.6000000238418579,0.0
+2015-12-01 11:00:00,0.0,335.0,0.0,100480.0,0.0071000000461936,282.3000183105469,-2.4000000953674316,0.9000000357627869,0.0
+2015-12-01 12:00:00,0.0,350.3999938964844,0.0,100530.0,0.00699999975040555,282.0,-2.4000000953674316,1.3000000715255737,0.0
+2015-12-01 13:00:00,0.0,350.3999938964844,85.0999984741211,100560.0,0.00699999975040555,281.8999938964844,-2.6000001430511475,1.2000000476837158,0.0
+2015-12-01 14:00:00,0.0,350.3000183105469,195.40000915527344,100610.0,0.006899999920278788,282.5,-2.700000047683716,1.100000023841858,0.0
+2015-12-01 15:00:00,0.0,397.0,220.0,100600.0,0.00699999975040555,282.3999938964844,-2.9000000953674316,1.0,0.0
+2015-12-01 16:00:00,0.0,397.0,264.70001220703125,100520.0,0.007199999876320362,282.8000183105469,-2.200000047683716,1.7000000476837158,0.0
+2015-12-01 17:00:00,0.0,397.0,276.5,100510.0,0.007499999832361937,283.1000061035156,-1.5,2.299999952316284,0.0
+2015-12-01 18:00:00,0.0,385.3999938964844,395.20001220703125,100400.0,0.007699999958276749,283.5,-0.800000011920929,3.0,0.0
+2015-12-01 19:00:00,0.0,385.3999938964844,345.6000061035156,100340.0,0.008100000210106373,284.3999938964844,-0.800000011920929,2.9000000953674316,0.0
+2015-12-01 20:00:00,0.0,385.3999938964844,268.20001220703125,100310.0,0.008200000040233135,284.70001220703125,-0.9000000357627869,2.799999952316284,0.0
+2015-12-01 21:00:00,0.0,394.3000183105469,120.5999984741211,100160.0,0.008200000040233135,284.3999938964844,-0.9000000357627869,2.700000047683716,0.0
+2015-12-01 22:00:00,0.0,394.3000183105469,21.0,100200.0,0.00839999970048666,285.1000061035156,-1.3000000715255737,2.299999952316284,0.0
+2015-12-01 23:00:00,0.0,394.3000183105469,0.0,100240.0,0.008599999360740185,285.1000061035156,-1.7000000476837158,1.8000000715255737,0.0
+2015-12-02 00:00:00,0.0,383.3000183105469,0.0,100190.0,0.008599999360740185,285.20001220703125,-2.1000001430511475,1.399999976158142,0.0
+2015-12-02 01:00:00,0.0,383.3000183105469,0.0,100240.0,0.008799999952316284,285.3000183105469,-2.0,1.3000000715255737,0.0
+2015-12-02 02:00:00,0.0,383.3000183105469,0.0,100210.0,0.008799999952316284,285.6000061035156,-2.0,1.100000023841858,0.0
+2015-12-02 03:00:00,0.0,371.3999938964844,0.0,100120.0,0.008899999782443047,285.70001220703125,-2.0,1.0,0.0
+2015-12-02 04:00:00,0.0,371.3999938964844,0.0,100070.0,0.009200000204145908,285.8000183105469,-1.8000000715255737,1.600000023841858,0.0
+2015-12-02 05:00:00,0.0,371.3999938964844,0.0,100010.0,0.008899999782443047,285.70001220703125,-1.7000000476837158,2.1000001430511475,0.0
+2015-12-02 06:00:00,0.0,369.1000061035156,0.0,99970.0,0.009099999442696571,285.8999938964844,-1.600000023841858,2.700000047683716,0.0
+2015-12-02 07:00:00,0.0,369.20001220703125,0.0,99880.0,0.009399999864399433,286.1000061035156,-1.600000023841858,3.0,0.0
+2015-12-02 08:00:00,0.0,369.20001220703125,0.0,99870.0,0.009800000116229057,287.0,-1.7000000476837158,3.4000000953674316,9.493307095661946e-08
+2015-12-02 09:00:00,0.20000000298023224,370.6000061035156,0.0,99740.0,0.00969999935477972,286.70001220703125,-1.7000000476837158,3.799999952316284,0.0
+2015-12-02 10:00:00,0.0,370.6000061035156,0.0,99720.0,0.010499999858438969,288.0,-1.600000023841858,3.700000047683716,0.0
+2015-12-02 11:00:00,0.0,370.6000061035156,0.0,99710.0,0.010999999940395355,288.6000061035156,-1.5,3.6000001430511475,0.0
+2015-12-02 12:00:00,0.0,380.8999938964844,0.0,99710.0,0.01119999960064888,289.3999938964844,-1.399999976158142,3.4000000953674316,0.0
+2015-12-02 13:00:00,0.0,380.8999938964844,72.5,99740.0,0.011699999682605267,289.70001220703125,-0.699999988079071,3.4000000953674316,0.0
+2015-12-02 14:00:00,0.0,380.8000183105469,168.60000610351562,99710.0,0.01209999993443489,290.3000183105469,0.0,3.299999952316284,2.439501431328691e-07
+2015-12-02 15:00:00,0.5,405.1000061035156,130.8000030517578,99850.0,0.012000000104308128,290.3000183105469,0.699999988079071,3.299999952316284,3.9032023482881514e-07
+2015-12-02 16:00:00,0.800000011920929,405.1000061035156,157.5,99840.0,0.011699999682605267,289.8000183105469,1.3000000715255737,3.4000000953674316,9.716329458139992e-08
+2015-12-02 17:00:00,0.20000000298023224,405.1000061035156,164.6999969482422,99710.0,0.011799999512732029,290.1000061035156,1.899999976158142,3.5,0.0
+2015-12-02 18:00:00,0.0,397.5,145.10000610351562,99550.0,0.011699999682605267,290.3999938964844,2.5,3.6000001430511475,0.0
+2015-12-02 19:00:00,0.0,397.5,126.9000015258789,99520.0,0.011399999260902405,290.20001220703125,3.299999952316284,3.5,0.0
+2015-12-02 20:00:00,0.0,397.5,98.5,99400.0,0.011699999682605267,290.0,4.099999904632568,3.5,0.0
+2015-12-02 21:00:00,0.0,376.20001220703125,67.70000457763672,99390.0,0.01209999993443489,290.3999938964844,4.900000095367432,3.4000000953674316,0.0
+2015-12-02 22:00:00,0.0,376.20001220703125,11.699999809265137,99410.0,0.01119999960064888,289.8999938964844,5.0,3.9000000953674316,0.0
+2015-12-02 23:00:00,0.0,376.20001220703125,0.0,99530.0,0.008799999952316284,289.0,5.0,4.5,0.0
+2015-12-03 00:00:00,0.0,350.8000183105469,0.0,99570.0,0.0072999997064471245,287.3000183105469,5.099999904632568,5.099999904632568,0.0
+2015-12-03 01:00:00,0.0,350.8000183105469,0.0,99600.0,0.0066999997943639755,286.20001220703125,4.900000095367432,4.400000095367432,0.0
+2015-12-03 02:00:00,0.0,350.8999938964844,0.0,99680.0,0.0064999996684491634,285.8000183105469,4.800000190734863,3.799999952316284,0.0
+2015-12-03 03:00:00,0.0,296.70001220703125,0.0,99700.0,0.006199999712407589,284.8999938964844,4.599999904632568,3.1000001430511475,0.0
+2015-12-03 04:00:00,0.0,296.70001220703125,0.0,99740.0,0.006000000052154064,284.3000183105469,4.5,2.200000047683716,0.0
+2015-12-03 05:00:00,0.0,296.70001220703125,0.0,99850.0,0.006000000052154064,283.3999938964844,4.400000095367432,1.399999976158142,0.0
+2015-12-03 06:00:00,0.0,279.3999938964844,0.0,99880.0,0.0058999997563660145,282.8000183105469,4.200000286102295,0.5,0.0
+2015-12-03 07:00:00,0.0,279.3999938964844,0.0,99930.0,0.0058999997563660145,282.20001220703125,3.700000047683716,-0.20000000298023224,0.0
+2015-12-03 08:00:00,0.0,279.3999938964844,0.0,100020.0,0.005799999926239252,281.6000061035156,3.299999952316284,-0.9000000357627869,0.0
+2015-12-03 09:00:00,0.0,257.1000061035156,0.0,100040.0,0.005799999926239252,281.0,2.799999952316284,-1.600000023841858,0.0
+2015-12-03 10:00:00,0.0,257.1000061035156,0.0,100130.0,0.005699999630451202,280.6000061035156,2.200000047683716,-2.1000001430511475,0.0
+2015-12-03 11:00:00,0.0,257.1000061035156,0.0,100240.0,0.005499999970197678,280.5,1.600000023841858,-2.6000001430511475,0.0
+2015-12-03 12:00:00,0.0,254.0,0.0,100340.0,0.004999999888241291,279.70001220703125,1.0,-3.1000001430511475,0.0
+2015-12-03 13:00:00,0.0,254.0,111.5999984741211,100460.0,0.004799999762326479,279.70001220703125,0.20000000298023224,-3.9000000953674316,0.0
+2015-12-03 14:00:00,0.0,254.0,263.1000061035156,100550.0,0.00419999985024333,281.20001220703125,-0.6000000238418579,-4.800000190734863,0.0
+2015-12-03 15:00:00,0.0,268.0,390.6000061035156,100680.0,0.003599999938160181,282.3999938964844,-1.399999976158142,-5.599999904632568,0.0
+2015-12-03 16:00:00,0.0,268.0,471.3000183105469,100720.0,0.003499999875202775,283.1000061035156,-1.7000000476837158,-5.200000286102295,0.0
+2015-12-03 17:00:00,0.0,268.0,493.3000183105469,100690.0,0.003599999938160181,283.5,-2.0,-4.900000095367432,0.0
+2015-12-03 18:00:00,0.0,270.8999938964844,491.8999938964844,100700.0,0.003499999875202775,283.6000061035156,-2.299999952316284,-4.5,0.0
+2015-12-03 19:00:00,0.0,270.8999938964844,430.6000061035156,100660.0,0.003700000001117587,283.8000183105469,-1.899999976158142,-4.300000190734863,0.0
+2015-12-03 20:00:00,0.0,270.8999938964844,334.1000061035156,100750.0,0.003599999938160181,283.8999938964844,-1.600000023841858,-4.099999904632568,0.0
+2015-12-03 21:00:00,0.0,255.8000030517578,180.6999969482422,100750.0,0.0037999998312443495,283.3000183105469,-1.3000000715255737,-3.9000000953674316,0.0
+2015-12-03 22:00:00,0.0,255.8000030517578,30.899999618530273,100870.0,0.003999999724328518,282.1000061035156,-1.399999976158142,-3.700000047683716,0.0
+2015-12-03 23:00:00,0.0,255.8000030517578,0.0,100930.0,0.004299999680370092,280.3000183105469,-1.5,-3.4000000953674316,0.0
+2015-12-04 00:00:00,0.0,236.6999969482422,0.0,101010.0,0.00419999985024333,280.3000183105469,-1.5,-3.1000001430511475,0.0
+2015-12-04 01:00:00,0.0,236.6999969482422,0.0,101130.0,0.004299999680370092,279.6000061035156,-1.7000000476837158,-3.1000001430511475,0.0
+2015-12-04 02:00:00,0.0,236.6999969482422,0.0,101170.0,0.00419999985024333,278.70001220703125,-1.8000000715255737,-3.0,0.0
+2015-12-04 03:00:00,0.0,229.5,0.0,101260.0,0.004299999680370092,278.3000183105469,-1.899999976158142,-2.9000000953674316,0.0
+2015-12-04 04:00:00,0.0,229.5,0.0,101300.0,0.00419999985024333,277.6000061035156,-2.0,-2.9000000953674316,0.0
+2015-12-04 05:00:00,0.0,229.5,0.0,101270.0,0.003999999724328518,277.5,-2.0,-2.799999952316284,0.0
+2015-12-04 06:00:00,0.0,222.5,0.0,101270.0,0.003700000001117587,277.70001220703125,-2.0,-2.799999952316284,0.0
+2015-12-04 07:00:00,0.0,222.5,0.0,101400.0,0.0037999998312443495,277.3999938964844,-1.600000023841858,-2.9000000953674316,0.0
+2015-12-04 08:00:00,0.0,222.5,0.0,101460.0,0.003700000001117587,276.3999938964844,-1.2000000476837158,-3.1000001430511475,0.0
+2015-12-04 09:00:00,0.0,217.0,0.0,101450.0,0.003599999938160181,275.3999938964844,-0.800000011920929,-3.200000047683716,0.0
+2015-12-04 10:00:00,0.0,217.0,0.0,101510.0,0.003399999812245369,274.8000183105469,-0.9000000357627869,-3.1000001430511475,0.0
+2015-12-04 11:00:00,0.0,217.0,0.0,101540.0,0.003399999812245369,274.3000183105469,-1.100000023841858,-3.0,0.0
+2015-12-04 12:00:00,0.0,220.3000030517578,0.0,101610.0,0.0032999999821186066,273.6000061035156,-1.3000000715255737,-2.9000000953674316,0.0
+2015-12-04 13:00:00,0.0,220.1999969482422,111.0,101730.0,0.003499999875202775,274.1000061035156,-1.5,-3.200000047683716,0.0
+2015-12-04 14:00:00,0.0,220.1999969482422,265.0,101770.0,0.003700000001117587,276.8999938964844,-1.600000023841858,-3.4000000953674316,0.0
+2015-12-04 15:00:00,0.0,239.60000610351562,424.20001220703125,101810.0,0.003499999875202775,279.5,-1.8000000715255737,-3.700000047683716,0.0
+2015-12-04 16:00:00,0.0,239.60000610351562,512.7000122070312,101760.0,0.003399999812245369,281.8999938964844,-2.4000000953674316,-3.799999952316284,0.0
+2015-12-04 17:00:00,0.0,239.60000610351562,537.1000366210938,101720.0,0.0032999999821186066,283.70001220703125,-3.0,-3.799999952316284,0.0
+2015-12-04 18:00:00,0.0,248.0,520.2999877929688,101680.0,0.0032999999821186066,284.70001220703125,-3.6000001430511475,-3.9000000953674316,0.0
+2015-12-04 19:00:00,0.0,248.0,455.6000061035156,101630.0,0.0031999999191612005,285.5,-3.4000000953674316,-3.700000047683716,0.0
+2015-12-04 20:00:00,0.0,248.10000610351562,353.6000061035156,101600.0,0.0031999999191612005,285.3000183105469,-3.200000047683716,-3.5,0.0
+2015-12-04 21:00:00,0.0,238.3000030517578,155.40000915527344,101600.0,0.0031999999191612005,285.5,-3.0,-3.299999952316284,0.0
+2015-12-04 22:00:00,0.0,238.3000030517578,26.399999618530273,101680.0,0.0032999999821186066,284.1000061035156,-2.1000001430511475,-3.4000000953674316,0.0
+2015-12-04 23:00:00,0.0,238.3000030517578,0.0,101620.0,0.003700000001117587,280.3000183105469,-1.3000000715255737,-3.5,0.0
+2015-12-05 00:00:00,0.0,226.3000030517578,0.0,101720.0,0.0037999998312443495,279.0,-0.4000000059604645,-3.6000001430511475,0.0
+2015-12-05 01:00:00,0.0,226.3000030517578,0.0,101740.0,0.003700000001117587,277.0,-0.699999988079071,-3.4000000953674316,0.0
+2015-12-05 02:00:00,0.0,226.3000030517578,0.0,101830.0,0.003700000001117587,277.0,-1.100000023841858,-3.200000047683716,0.0
+2015-12-05 03:00:00,0.0,222.60000610351562,0.0,101890.0,0.003700000001117587,276.6000061035156,-1.399999976158142,-3.0,0.0
+2015-12-05 04:00:00,0.0,222.60000610351562,0.0,101860.0,0.003599999938160181,276.0,-1.399999976158142,-3.0,0.0
+2015-12-05 05:00:00,0.0,222.60000610351562,0.0,101850.0,0.003599999938160181,274.20001220703125,-1.3000000715255737,-3.0,0.0
+2015-12-05 06:00:00,0.0,220.8000030517578,0.0,101800.0,0.003499999875202775,273.8999938964844,-1.3000000715255737,-3.0,0.0
+2015-12-05 07:00:00,0.0,220.8000030517578,0.0,101920.0,0.003499999875202775,273.8000183105469,-1.3000000715255737,-3.0,0.0
+2015-12-05 08:00:00,0.0,220.8000030517578,0.0,101980.0,0.0032999999821186066,272.3999938964844,-1.2000000476837158,-3.1000001430511475,0.0
+2015-12-05 09:00:00,0.0,221.60000610351562,0.0,101960.0,0.0032999999821186066,272.6000061035156,-1.2000000476837158,-3.1000001430511475,0.0
+2015-12-05 10:00:00,0.0,221.60000610351562,0.0,102000.0,0.0031999999191612005,272.6000061035156,-1.3000000715255737,-3.0,0.0
+2015-12-05 11:00:00,0.0,221.60000610351562,0.0,102040.0,0.0032999999821186066,273.3999938964844,-1.399999976158142,-2.9000000953674316,0.0
+2015-12-05 12:00:00,0.0,227.8000030517578,0.0,102080.0,0.0032999999821186066,272.8000183105469,-1.5,-2.799999952316284,0.0
+2015-12-05 13:00:00,0.0,227.8000030517578,106.9000015258789,102150.0,0.003599999938160181,273.70001220703125,-1.7000000476837158,-3.200000047683716,0.0
+2015-12-05 14:00:00,0.0,227.8000030517578,258.8000183105469,102200.0,0.003599999938160181,277.1000061035156,-1.899999976158142,-3.6000001430511475,0.0
+2015-12-05 15:00:00,0.0,253.8000030517578,414.5,102230.0,0.003599999938160181,279.8999938964844,-2.1000001430511475,-3.9000000953674316,0.0
+2015-12-05 16:00:00,0.0,253.8000030517578,501.8000183105469,102180.0,0.003499999875202775,282.70001220703125,-2.5,-3.9000000953674316,0.0
+2015-12-05 17:00:00,0.0,253.8000030517578,526.1000366210938,102070.0,0.003399999812245369,284.20001220703125,-2.9000000953674316,-3.9000000953674316,0.0
+2015-12-05 18:00:00,0.0,269.0,507.20001220703125,101960.0,0.003399999812245369,285.5,-3.299999952316284,-3.799999952316284,0.0
+2015-12-05 19:00:00,0.0,269.0,444.3000183105469,101880.0,0.003499999875202775,286.70001220703125,-3.0,-3.700000047683716,0.0
+2015-12-05 20:00:00,0.0,269.0,344.8999938964844,101860.0,0.003599999938160181,287.20001220703125,-2.6000001430511475,-3.6000001430511475,0.0
+2015-12-05 21:00:00,0.0,261.20001220703125,149.0,101890.0,0.003499999875202775,286.3999938964844,-2.299999952316284,-3.5,0.0
+2015-12-05 22:00:00,0.0,261.3000183105469,25.200000762939453,101950.0,0.003700000001117587,285.20001220703125,-2.200000047683716,-3.299999952316284,0.0
+2015-12-05 23:00:00,0.0,261.3000183105469,0.0,101960.0,0.003999999724328518,282.3999938964844,-2.200000047683716,-3.1000001430511475,0.0
+2015-12-06 00:00:00,0.0,250.1999969482422,0.0,101960.0,0.0037999998312443495,281.0,-2.200000047683716,-2.9000000953674316,0.0
+2015-12-06 01:00:00,0.0,250.1999969482422,0.0,102030.0,0.0037999998312443495,280.5,-2.200000047683716,-2.9000000953674316,0.0
+2015-12-06 02:00:00,0.0,250.1999969482422,0.0,102060.0,0.0038999998942017555,279.8000183105469,-2.200000047683716,-3.0,0.0
+2015-12-06 03:00:00,0.0,251.1999969482422,0.0,102000.0,0.0038999998942017555,278.8000183105469,-2.200000047683716,-3.0,0.0
+2015-12-06 04:00:00,0.0,251.1999969482422,0.0,102010.0,0.0037999998312443495,277.3000183105469,-2.200000047683716,-2.799999952316284,0.0
+2015-12-06 05:00:00,0.0,251.1999969482422,0.0,102030.0,0.0037999998312443495,277.3999938964844,-2.200000047683716,-2.700000047683716,0.0
+2015-12-06 06:00:00,0.0,267.70001220703125,0.0,101930.0,0.0038999998942017555,277.5,-2.200000047683716,-2.6000001430511475,0.0
+2015-12-06 07:00:00,0.0,267.70001220703125,0.0,101950.0,0.0037999998312443495,277.20001220703125,-2.0,-2.700000047683716,0.0
+2015-12-06 08:00:00,0.0,267.70001220703125,0.0,101890.0,0.0038999998942017555,276.8000183105469,-1.8000000715255737,-2.799999952316284,0.0
+2015-12-06 09:00:00,0.0,296.3999938964844,0.0,101850.0,0.0038999998942017555,276.3999938964844,-1.600000023841858,-2.799999952316284,0.0
+2015-12-06 10:00:00,0.0,296.3999938964844,0.0,101860.0,0.0037999998312443495,275.70001220703125,-1.5,-2.6000001430511475,0.0
+2015-12-06 11:00:00,0.0,296.3999938964844,0.0,101860.0,0.0037999998312443495,274.8000183105469,-1.5,-2.4000000953674316,0.0
+2015-12-06 12:00:00,0.0,272.8999938964844,0.0,101870.0,0.003700000001117587,274.8000183105469,-1.5,-2.200000047683716,0.0
+2015-12-06 13:00:00,0.0,272.8999938964844,102.20000457763672,101920.0,0.0038999998942017555,275.3000183105469,-1.600000023841858,-2.4000000953674316,0.0
+2015-12-06 14:00:00,0.0,272.8000183105469,250.90000915527344,101900.0,0.00419999985024333,278.8000183105469,-1.600000023841858,-2.5,0.0
+2015-12-06 15:00:00,0.0,279.3000183105469,403.0,101840.0,0.004399999976158142,282.0,-1.7000000476837158,-2.6000001430511475,0.0
+2015-12-06 16:00:00,0.0,279.3000183105469,488.5,101810.0,0.004100000020116568,284.3000183105469,-1.8000000715255737,-2.200000047683716,0.0
+2015-12-06 17:00:00,0.0,279.3000183105469,512.6000366210938,101680.0,0.003999999724328518,285.8999938964844,-2.0,-1.7000000476837158,0.0
+2015-12-06 18:00:00,0.0,296.8999938964844,495.6000061035156,101510.0,0.003700000001117587,287.8999938964844,-2.200000047683716,-1.3000000715255737,0.0
+2015-12-06 19:00:00,0.0,296.8999938964844,434.3000183105469,101380.0,0.00419999985024333,289.3000183105469,-2.0,-1.2000000476837158,0.0
+2015-12-06 20:00:00,0.0,296.8999938964844,337.20001220703125,101250.0,0.0044999998062849045,290.1000061035156,-1.8000000715255737,-1.2000000476837158,0.0
+2015-12-06 21:00:00,0.0,288.20001220703125,152.1999969482422,101200.0,0.004799999762326479,290.0,-1.600000023841858,-1.100000023841858,0.0
+2015-12-06 22:00:00,0.0,288.20001220703125,25.700000762939453,101200.0,0.005399999674409628,287.5,-1.5,-0.800000011920929,0.0
+2015-12-06 23:00:00,0.0,288.20001220703125,0.0,101190.0,0.005499999970197678,282.70001220703125,-1.5,-0.4000000059604645,0.0
+2015-12-07 00:00:00,0.0,278.1000061035156,0.0,101200.0,0.00559999980032444,282.1000061035156,-1.5,-0.10000000149011612,0.0
+2015-12-07 01:00:00,0.0,278.1000061035156,0.0,101250.0,0.00559999980032444,281.3000183105469,-1.3000000715255737,-0.30000001192092896,0.0
+2015-12-07 02:00:00,0.0,278.1000061035156,0.0,101220.0,0.0052999998442828655,279.5,-1.0,-0.6000000238418579,0.0
+2015-12-07 03:00:00,0.0,277.20001220703125,0.0,101170.0,0.0050999997183680534,279.20001220703125,-0.800000011920929,-0.9000000357627869,0.0
+2015-12-07 04:00:00,0.0,277.20001220703125,0.0,101120.0,0.004799999762326479,277.6000061035156,-0.5,-1.399999976158142,0.0
+2015-12-07 05:00:00,0.0,277.20001220703125,0.0,101090.0,0.004999999888241291,277.8000183105469,-0.10000000149011612,-1.899999976158142,0.0
+2015-12-07 06:00:00,0.0,272.1000061035156,0.0,101050.0,0.004799999762326479,277.20001220703125,0.20000000298023224,-2.4000000953674316,0.0
+2015-12-07 07:00:00,0.0,272.1000061035156,0.0,101020.0,0.004600000102072954,276.8000183105469,0.10000000149011612,-2.4000000953674316,0.0
+2015-12-07 08:00:00,0.0,272.1000061035156,0.0,100930.0,0.0044999998062849045,276.0,0.0,-2.299999952316284,0.0
+2015-12-07 09:00:00,0.0,277.3000183105469,0.0,100860.0,0.0044999998062849045,275.8000183105469,-0.10000000149011612,-2.299999952316284,0.0
+2015-12-07 10:00:00,0.0,277.3000183105469,0.0,100800.0,0.0044999998062849045,275.5,0.20000000298023224,-2.200000047683716,0.0
+2015-12-07 11:00:00,0.0,277.3000183105469,0.0,100820.0,0.0044999998062849045,275.70001220703125,0.4000000059604645,-2.1000001430511475,0.0
+2015-12-07 12:00:00,0.0,319.0,0.0,100820.0,0.004399999976158142,275.3999938964844,0.699999988079071,-2.0,0.0
+2015-12-07 13:00:00,0.0,318.8999938964844,69.9000015258789,100830.0,0.0044999998062849045,276.0,0.9000000357627869,-1.8000000715255737,0.0
+2015-12-07 14:00:00,0.0,318.8999938964844,174.0,100820.0,0.004999999888241291,278.8999938964844,1.0,-1.600000023841858,0.0
+2015-12-07 15:00:00,0.0,346.70001220703125,285.70001220703125,100780.0,0.005499999970197678,283.1000061035156,1.100000023841858,-1.399999976158142,0.0
+2015-12-07 16:00:00,0.0,346.6000061035156,346.8999938964844,100690.0,0.004900000058114529,286.70001220703125,1.0,-1.5,0.0
+2015-12-07 17:00:00,0.0,346.6000061035156,364.3000183105469,100590.0,0.004799999762326479,289.5,0.9000000357627869,-1.7000000476837158,0.0
+2015-12-07 18:00:00,0.0,342.1000061035156,424.0,100440.0,0.004999999888241291,290.70001220703125,0.699999988079071,-1.8000000715255737,0.0
+2015-12-07 19:00:00,0.0,342.1000061035156,371.70001220703125,100320.0,0.005200000014156103,291.3999938964844,1.0,-1.8000000715255737,0.0
+2015-12-07 20:00:00,0.0,342.1000061035156,288.70001220703125,100280.0,0.005399999674409628,291.70001220703125,1.3000000715255737,-1.7000000476837158,0.0
+2015-12-07 21:00:00,0.0,350.8000183105469,132.60000610351562,100300.0,0.005499999970197678,291.8999938964844,1.5,-1.7000000476837158,0.0
+2015-12-07 22:00:00,0.0,350.8000183105469,22.399999618530273,100340.0,0.005699999630451202,289.70001220703125,1.2000000476837158,-1.5,0.0
+2015-12-07 23:00:00,0.0,350.8000183105469,0.0,100340.0,0.005799999926239252,285.8000183105469,0.9000000357627869,-1.3000000715255737,0.0
+2015-12-08 00:00:00,0.0,317.1000061035156,0.0,100400.0,0.005799999926239252,283.0,0.5,-1.100000023841858,0.0
+2015-12-08 01:00:00,0.0,317.1000061035156,0.0,100480.0,0.005699999630451202,281.8000183105469,0.5,-1.0,0.0
+2015-12-08 02:00:00,0.0,317.1000061035156,0.0,100490.0,0.005799999926239252,281.8000183105469,0.6000000238418579,-1.0,0.0
+2015-12-08 03:00:00,0.0,272.70001220703125,0.0,100470.0,0.005699999630451202,281.8000183105469,0.6000000238418579,-0.9000000357627869,0.0
+2015-12-08 04:00:00,0.0,272.70001220703125,0.0,100500.0,0.005399999674409628,280.8999938964844,0.6000000238418579,-0.6000000238418579,0.0
+2015-12-08 05:00:00,0.0,272.70001220703125,0.0,100520.0,0.005200000014156103,279.6000061035156,0.699999988079071,-0.4000000059604645,0.0
+2015-12-08 06:00:00,0.0,265.1000061035156,0.0,100440.0,0.005200000014156103,280.70001220703125,0.699999988079071,-0.10000000149011612,0.0
+2015-12-08 07:00:00,0.0,265.1000061035156,0.0,100490.0,0.005200000014156103,279.0,0.699999988079071,-0.30000001192092896,0.0
+2015-12-08 08:00:00,0.0,265.1000061035156,0.0,100550.0,0.004999999888241291,277.8000183105469,0.800000011920929,-0.5,0.0
+2015-12-08 09:00:00,0.0,260.3000183105469,0.0,100470.0,0.004900000058114529,277.3999938964844,0.800000011920929,-0.699999988079071,0.0
+2015-12-08 10:00:00,0.0,260.3000183105469,0.0,100440.0,0.004699999932199717,276.0,0.5,-0.699999988079071,0.0
+2015-12-08 11:00:00,0.0,260.3000183105469,0.0,100520.0,0.00419999985024333,274.8000183105469,0.10000000149011612,-0.699999988079071,0.0
+2015-12-08 12:00:00,0.0,258.0,0.0,100560.0,0.0044999998062849045,275.6000061035156,-0.30000001192092896,-0.699999988079071,0.0
+2015-12-08 13:00:00,0.0,257.8999938964844,98.0,100650.0,0.0044999998062849045,275.3999938964844,-0.4000000059604645,-0.6000000238418579,0.0
+2015-12-08 14:00:00,0.0,257.8999938964844,247.3000030517578,100670.0,0.005499999970197678,279.5,-0.6000000238418579,-0.4000000059604645,0.0
+2015-12-08 15:00:00,0.0,285.20001220703125,404.1000061035156,100730.0,0.00559999980032444,282.8000183105469,-0.699999988079071,-0.30000001192092896,0.0
+2015-12-08 16:00:00,0.0,285.20001220703125,491.3000183105469,100710.0,0.005399999674409628,285.70001220703125,-0.699999988079071,0.5,0.0
+2015-12-08 17:00:00,0.0,285.20001220703125,516.5,100580.0,0.0052999998442828655,287.8999938964844,-0.699999988079071,1.3000000715255737,0.0
+2015-12-08 18:00:00,0.0,291.1000061035156,501.8000183105469,100480.0,0.005200000014156103,289.1000061035156,-0.6000000238418579,2.1000001430511475,0.0
+2015-12-08 19:00:00,0.0,291.1000061035156,440.1000061035156,100400.0,0.00559999980032444,290.5,-0.20000000298023224,2.4000000953674316,0.0
+2015-12-08 20:00:00,0.0,291.1000061035156,342.0,100420.0,0.0058999997563660145,290.5,0.20000000298023224,2.700000047683716,0.0
+2015-12-08 21:00:00,0.0,279.8999938964844,148.40000915527344,100320.0,0.006399999838322401,290.0,0.6000000238418579,3.0,0.0
+2015-12-08 22:00:00,0.0,279.8999938964844,25.200000762939453,100360.0,0.006399999838322401,288.3999938964844,0.20000000298023224,2.799999952316284,0.0
+2015-12-08 23:00:00,0.0,279.8999938964844,0.0,100370.0,0.0064999996684491634,284.3999938964844,-0.10000000149011612,2.5,0.0
+2015-12-09 00:00:00,0.0,263.8999938964844,0.0,100390.0,0.006599999964237213,282.3999938964844,-0.4000000059604645,2.299999952316284,0.0
+2015-12-09 01:00:00,0.0,263.8999938964844,0.0,100480.0,0.006399999838322401,281.70001220703125,-0.699999988079071,2.299999952316284,0.0
+2015-12-09 02:00:00,0.0,263.8999938964844,0.0,100490.0,0.006300000008195639,281.20001220703125,-1.0,2.299999952316284,0.0
+2015-12-09 03:00:00,0.0,258.70001220703125,0.0,100430.0,0.0058999997563660145,280.1000061035156,-1.399999976158142,2.299999952316284,0.0
+2015-12-09 04:00:00,0.0,258.70001220703125,0.0,100430.0,0.005699999630451202,279.5,-0.800000011920929,2.1000001430511475,0.0
+2015-12-09 05:00:00,0.0,258.70001220703125,0.0,100430.0,0.005499999970197678,278.8999938964844,-0.30000001192092896,2.0,0.0
+2015-12-09 06:00:00,0.0,255.60000610351562,0.0,100400.0,0.005200000014156103,278.3999938964844,0.30000001192092896,1.899999976158142,0.0
+2015-12-09 07:00:00,0.0,255.60000610351562,0.0,100440.0,0.004999999888241291,277.8000183105469,0.10000000149011612,1.8000000715255737,0.0
+2015-12-09 08:00:00,0.0,255.60000610351562,0.0,100450.0,0.004999999888241291,277.5,0.0,1.7000000476837158,0.0
+2015-12-09 09:00:00,0.0,256.8999938964844,0.0,100350.0,0.005200000014156103,278.0,-0.20000000298023224,1.600000023841858,0.0
+2015-12-09 10:00:00,0.0,256.8999938964844,0.0,100370.0,0.004999999888241291,277.6000061035156,-0.4000000059604645,1.899999976158142,0.0
+2015-12-09 11:00:00,0.0,256.8999938964844,0.0,100400.0,0.004900000058114529,277.0,-0.6000000238418579,2.200000047683716,0.0
+2015-12-09 12:00:00,0.0,267.6000061035156,0.0,100430.0,0.004299999680370092,275.1000061035156,-0.699999988079071,2.5,0.0
+2015-12-09 13:00:00,0.0,267.6000061035156,94.4000015258789,100470.0,0.0044999998062849045,275.3999938964844,-0.699999988079071,1.899999976158142,0.0
+2015-12-09 14:00:00,0.0,267.6000061035156,241.60000610351562,100540.0,0.0052999998442828655,278.8000183105469,-0.6000000238418579,1.2000000476837158,0.0
+2015-12-09 15:00:00,0.0,295.8000183105469,376.0,100480.0,0.006000000052154064,282.3000183105469,-0.6000000238418579,0.5,0.0
+2015-12-09 16:00:00,0.0,295.8000183105469,457.8999938964844,100450.0,0.00559999980032444,286.5,-0.30000001192092896,1.2000000476837158,0.0
+2015-12-09 17:00:00,0.0,295.70001220703125,481.8999938964844,100290.0,0.004900000058114529,289.3999938964844,0.0,1.8000000715255737,0.0
+2015-12-09 18:00:00,0.0,304.3000183105469,491.5,100150.0,0.004699999932199717,290.20001220703125,0.4000000059604645,2.4000000953674316,0.0
+2015-12-09 19:00:00,0.0,304.3000183105469,431.3999938964844,100050.0,0.004600000102072954,291.0,0.800000011920929,2.200000047683716,0.0
+2015-12-09 20:00:00,0.0,304.3000183105469,335.3999938964844,100040.0,0.004299999680370092,291.3000183105469,1.2000000476837158,2.1000001430511475,0.0
+2015-12-09 21:00:00,0.0,292.3000183105469,145.1999969482422,100020.0,0.004600000102072954,290.8000183105469,1.600000023841858,1.899999976158142,0.0
+2015-12-09 22:00:00,0.0,292.3000183105469,24.700000762939453,100070.0,0.004999999888241291,288.20001220703125,1.899999976158142,1.100000023841858,0.0
+2015-12-09 23:00:00,0.0,292.3000183105469,0.0,100080.0,0.0050999997183680534,284.70001220703125,2.200000047683716,0.30000001192092896,0.0
+2015-12-10 00:00:00,0.0,274.6000061035156,0.0,100090.0,0.005200000014156103,284.0,2.5,-0.5,0.0
+2015-12-10 01:00:00,0.0,274.6000061035156,0.0,100120.0,0.005399999674409628,282.0,2.200000047683716,-0.9000000357627869,0.0
+2015-12-10 02:00:00,0.0,274.70001220703125,0.0,100160.0,0.005200000014156103,281.3000183105469,1.899999976158142,-1.2000000476837158,0.0
+2015-12-10 03:00:00,0.0,272.70001220703125,0.0,100100.0,0.0050999997183680534,281.3999938964844,1.600000023841858,-1.600000023841858,0.0
+2015-12-10 04:00:00,0.0,272.70001220703125,0.0,100080.0,0.0052999998442828655,281.3999938964844,1.600000023841858,-1.3000000715255737,0.0
+2015-12-10 05:00:00,0.0,272.70001220703125,0.0,100140.0,0.005399999674409628,281.0,1.600000023841858,-0.9000000357627869,0.0
+2015-12-10 06:00:00,0.0,280.6000061035156,0.0,100110.0,0.005399999674409628,279.3000183105469,1.600000023841858,-0.5,0.0
+2015-12-10 07:00:00,0.0,280.6000061035156,0.0,100070.0,0.0050999997183680534,280.3000183105469,1.600000023841858,-0.5,0.0
+2015-12-10 08:00:00,0.0,280.6000061035156,0.0,100060.0,0.005200000014156103,279.5,1.600000023841858,-0.4000000059604645,0.0
+2015-12-10 09:00:00,0.0,314.70001220703125,0.0,100050.0,0.0052999998442828655,279.6000061035156,1.600000023841858,-0.30000001192092896,0.0
+2015-12-10 10:00:00,0.0,314.70001220703125,0.0,100030.0,0.0050999997183680534,279.6000061035156,0.9000000357627869,-0.20000000298023224,0.0
+2015-12-10 11:00:00,0.0,314.70001220703125,0.0,100070.0,0.005200000014156103,279.3000183105469,0.20000000298023224,0.0,0.0
+2015-12-10 12:00:00,0.0,298.8999938964844,0.0,100070.0,0.005200000014156103,278.6000061035156,-0.5,0.20000000298023224,0.0
+2015-12-10 13:00:00,0.0,298.8999938964844,91.9000015258789,100190.0,0.004799999762326479,277.8999938964844,0.0,0.0,0.0
+2015-12-10 14:00:00,0.0,298.8999938964844,238.6999969482422,100170.0,0.005699999630451202,282.5,0.5,-0.10000000149011612,0.0
+2015-12-10 15:00:00,0.0,304.5,390.70001220703125,100250.0,0.006300000008195639,286.8999938964844,1.0,-0.20000000298023224,0.0
+2015-12-10 16:00:00,0.0,304.5,476.3999938964844,100190.0,0.0071000000461936,289.8000183105469,1.399999976158142,0.6000000238418579,0.0
+2015-12-10 17:00:00,0.0,304.3999938964844,501.8000183105469,100040.0,0.007599999662488699,292.5,1.899999976158142,1.5,0.0
+2015-12-10 18:00:00,0.0,345.8999938964844,421.5,99990.0,0.007899999618530273,293.3999938964844,2.299999952316284,2.299999952316284,0.0
+2015-12-10 19:00:00,0.0,345.8999938964844,370.1000061035156,99930.0,0.007699999958276749,293.6000061035156,2.0,2.799999952316284,0.0
+2015-12-10 20:00:00,0.0,345.8999938964844,287.8999938964844,99930.0,0.007599999662488699,293.6000061035156,1.7000000476837158,3.299999952316284,0.0
+2015-12-10 21:00:00,0.0,342.3999938964844,129.8000030517578,99900.0,0.007799999788403511,293.1000061035156,1.399999976158142,3.799999952316284,0.0
+2015-12-10 22:00:00,0.0,342.3999938964844,22.30000114440918,99950.0,0.007699999958276749,291.70001220703125,1.100000023841858,3.5,0.0
+2015-12-10 23:00:00,0.0,342.3999938964844,0.0,99940.0,0.008100000210106373,288.8999938964844,0.699999988079071,3.200000047683716,0.0
+2015-12-11 00:00:00,0.0,343.6000061035156,0.0,99940.0,0.008200000040233135,287.3000183105469,0.30000001192092896,2.9000000953674316,0.0
+2015-12-11 01:00:00,0.0,343.6000061035156,0.0,100000.0,0.008100000210106373,287.6000061035156,0.10000000149011612,2.6000001430511475,0.0
+2015-12-11 02:00:00,0.0,343.6000061035156,0.0,100050.0,0.007799999788403511,285.6000061035156,-0.10000000149011612,2.299999952316284,0.0
+2015-12-11 03:00:00,0.0,366.20001220703125,0.0,100050.0,0.007899999618530273,285.3000183105469,-0.20000000298023224,2.0,0.0
+2015-12-11 04:00:00,0.0,366.20001220703125,0.0,100040.0,0.007699999958276749,284.8999938964844,0.10000000149011612,2.200000047683716,0.0
+2015-12-11 05:00:00,0.0,366.20001220703125,0.0,100000.0,0.007699999958276749,285.5,0.4000000059604645,2.5,0.0
+2015-12-11 06:00:00,0.0,368.3000183105469,0.0,99960.0,0.0072999997064471245,284.8000183105469,0.699999988079071,2.700000047683716,0.0
+2015-12-11 07:00:00,0.0,368.3000183105469,0.0,99970.0,0.007699999958276749,285.0,1.100000023841858,2.5,0.0
+2015-12-11 08:00:00,0.0,368.3000183105469,0.0,100010.0,0.007499999832361937,285.3000183105469,1.5,2.200000047683716,0.0
+2015-12-11 09:00:00,0.0,310.0,0.0,99980.0,0.007599999662488699,284.8999938964844,1.8000000715255737,1.899999976158142,0.0
+2015-12-11 10:00:00,0.0,310.0,0.0,100000.0,0.0072999997064471245,283.70001220703125,1.600000023841858,2.0,0.0
+2015-12-11 11:00:00,0.0,310.0,0.0,100130.0,0.007499999832361937,283.70001220703125,1.3000000715255737,2.0,0.0
+2015-12-11 12:00:00,0.0,299.1000061035156,0.0,100150.0,0.007400000002235174,282.5,1.0,2.1000001430511475,0.0
+2015-12-11 13:00:00,0.0,299.1000061035156,87.5999984741211,100230.0,0.007599999662488699,283.8999938964844,1.100000023841858,1.899999976158142,0.0
+2015-12-11 14:00:00,0.0,299.1000061035156,230.8000030517578,100320.0,0.008599999360740185,285.20001220703125,1.3000000715255737,1.600000023841858,0.0
+2015-12-11 15:00:00,0.0,331.3999938964844,382.3999938964844,100360.0,0.00969999935477972,287.6000061035156,1.399999976158142,1.399999976158142,0.0
+2015-12-11 16:00:00,0.0,331.3999938964844,467.0,100390.0,0.00989999994635582,288.5,1.7000000476837158,2.1000001430511475,0.0
+2015-12-11 17:00:00,0.0,331.3999938964844,492.3000183105469,100370.0,0.010199999436736107,289.70001220703125,2.0,2.799999952316284,0.0
+2015-12-11 18:00:00,0.0,353.6000061035156,474.3999938964844,100310.0,0.01119999960064888,291.5,2.4000000953674316,3.5,0.0
+2015-12-11 19:00:00,0.0,353.6000061035156,416.8000183105469,100300.0,0.010599999688565731,294.70001220703125,2.299999952316284,3.700000047683716,0.0
+2015-12-11 20:00:00,0.0,353.6000061035156,324.3999938964844,100230.0,0.010199999436736107,295.3000183105469,2.299999952316284,3.799999952316284,0.0
+2015-12-11 21:00:00,0.0,347.6000061035156,137.5,100210.0,0.010400000028312206,294.8000183105469,2.200000047683716,4.0,0.0
+2015-12-11 22:00:00,0.0,347.6000061035156,23.80000114440918,100250.0,0.010699999518692493,293.20001220703125,1.7000000476837158,3.799999952316284,0.0
+2015-12-11 23:00:00,0.0,347.6000061035156,0.0,100290.0,0.010699999518692493,290.20001220703125,1.100000023841858,3.5,0.0
+2015-12-12 00:00:00,0.0,331.3999938964844,0.0,100330.0,0.010900000110268593,290.20001220703125,0.5,3.299999952316284,0.0
+2015-12-12 01:00:00,0.0,331.3999938964844,0.0,100420.0,0.009999999776482582,288.3000183105469,0.5,3.200000047683716,0.0
+2015-12-12 02:00:00,0.0,331.3999938964844,0.0,100420.0,0.00989999994635582,287.6000061035156,0.5,3.1000001430511475,0.0
+2015-12-12 03:00:00,0.0,328.0,0.0,100480.0,0.010099999606609344,288.0,0.5,3.0,0.0
+2015-12-12 04:00:00,0.0,328.0,0.0,100510.0,0.009800000116229057,287.20001220703125,1.100000023841858,3.0,0.0
+2015-12-12 05:00:00,0.0,328.0,0.0,100560.0,0.009399999864399433,286.8000183105469,1.8000000715255737,3.0,0.0
+2015-12-12 06:00:00,0.0,325.20001220703125,0.0,100600.0,0.00969999935477972,287.1000061035156,2.5,3.0,0.0
+2015-12-12 07:00:00,0.0,325.20001220703125,0.0,100630.0,0.009800000116229057,287.70001220703125,2.4000000953674316,2.9000000953674316,0.0
+2015-12-12 08:00:00,0.0,325.20001220703125,0.0,100660.0,0.00969999935477972,287.3999938964844,2.200000047683716,2.799999952316284,0.0
+2015-12-12 09:00:00,0.0,319.8000183105469,0.0,100670.0,0.009599999524652958,287.5,2.1000001430511475,2.700000047683716,0.0
+2015-12-12 10:00:00,0.0,319.8000183105469,0.0,100670.0,0.00969999935477972,287.3999938964844,1.600000023841858,2.700000047683716,0.0
+2015-12-12 11:00:00,0.0,319.8999938964844,0.0,100740.0,0.009499999694526196,286.8999938964844,1.2000000476837158,2.6000001430511475,0.0
+2015-12-12 12:00:00,0.0,316.8999938964844,0.0,100830.0,0.009099999442696571,286.20001220703125,0.800000011920929,2.6000001430511475,0.0
+2015-12-12 13:00:00,0.0,316.8999938964844,84.4000015258789,100870.0,0.009399999864399433,286.5,1.2000000476837158,2.4000000953674316,0.0
+2015-12-12 14:00:00,0.0,316.8999938964844,225.40000915527344,100930.0,0.009999999776482582,288.1000061035156,1.600000023841858,2.200000047683716,0.0
+2015-12-12 15:00:00,0.0,342.3999938964844,377.3000183105469,100960.0,0.010799999348819256,291.1000061035156,1.899999976158142,2.0,0.0
+2015-12-12 16:00:00,0.0,342.3999938964844,461.5,100960.0,0.010900000110268593,293.20001220703125,2.4000000953674316,1.899999976158142,0.0
+2015-12-12 17:00:00,0.0,342.3999938964844,487.0,100820.0,0.010099999606609344,295.1000061035156,2.9000000953674316,1.8000000715255737,0.0
+2015-12-12 18:00:00,0.0,354.3000183105469,475.70001220703125,100790.0,0.009999999776482582,296.1000061035156,3.4000000953674316,1.8000000715255737,0.0
+2015-12-12 19:00:00,0.0,354.3000183105469,418.20001220703125,100720.0,0.010099999606609344,297.0,3.1000001430511475,2.0,0.0
+2015-12-12 20:00:00,0.0,354.3000183105469,325.8000183105469,100670.0,0.010300000198185444,297.20001220703125,2.9000000953674316,2.299999952316284,0.0
+2015-12-12 21:00:00,0.0,339.3999938964844,157.1999969482422,100680.0,0.00989999994635582,296.3999938964844,2.6000001430511475,2.5,0.0
+2015-12-12 22:00:00,0.0,339.3999938964844,27.5,100730.0,0.010599999688565731,293.8999938964844,2.4000000953674316,2.4000000953674316,0.0
+2015-12-12 23:00:00,0.0,339.3999938964844,0.0,100740.0,0.010599999688565731,291.3000183105469,2.200000047683716,2.299999952316284,0.0
+2015-12-13 00:00:00,0.0,318.20001220703125,0.0,100780.0,0.010699999518692493,290.3999938964844,2.0,2.299999952316284,0.0
+2015-12-13 01:00:00,0.0,318.20001220703125,0.0,100810.0,0.010400000028312206,288.6000061035156,1.5,2.1000001430511475,0.0
+2015-12-13 02:00:00,0.0,318.20001220703125,0.0,100860.0,0.009800000116229057,286.8000183105469,0.9000000357627869,1.899999976158142,0.0
+2015-12-13 03:00:00,0.0,310.3999938964844,0.0,100830.0,0.009099999442696571,285.70001220703125,0.30000001192092896,1.7000000476837158,0.0
+2015-12-13 04:00:00,0.0,310.3999938964844,0.0,100840.0,0.008599999360740185,285.3000183105469,0.800000011920929,1.8000000715255737,0.0
+2015-12-13 05:00:00,0.0,310.3999938964844,0.0,100850.0,0.008999999612569809,286.0,1.2000000476837158,1.8000000715255737,0.0
+2015-12-13 06:00:00,0.0,301.70001220703125,0.0,100850.0,0.008299999870359898,284.5,1.600000023841858,1.899999976158142,0.0
+2015-12-13 07:00:00,0.0,301.70001220703125,0.0,100820.0,0.007999999448657036,284.3000183105469,1.3000000715255737,1.899999976158142,0.0
+2015-12-13 08:00:00,0.0,301.70001220703125,0.0,100810.0,0.006899999920278788,283.20001220703125,0.9000000357627869,1.8000000715255737,0.0
+2015-12-13 09:00:00,0.0,293.3999938964844,0.0,100760.0,0.0072999997064471245,283.20001220703125,0.5,1.8000000715255737,0.0
+2015-12-13 10:00:00,0.0,293.3999938964844,0.0,100750.0,0.0072999997064471245,282.3999938964844,0.0,1.399999976158142,0.0
+2015-12-13 11:00:00,0.0,293.5,0.0,100780.0,0.007400000002235174,282.70001220703125,-0.5,1.0,0.0
+2015-12-13 12:00:00,0.0,299.3999938964844,0.0,100810.0,0.006799999624490738,280.8999938964844,-1.100000023841858,0.6000000238418579,0.0
+2015-12-13 13:00:00,0.0,299.3999938964844,83.9000015258789,100790.0,0.0071000000461936,281.8000183105469,-1.0,0.10000000149011612,0.0
+2015-12-13 14:00:00,0.0,299.3999938964844,227.40000915527344,100860.0,0.007899999618530273,284.20001220703125,-0.9000000357627869,-0.30000001192092896,0.0
+2015-12-13 15:00:00,0.0,331.20001220703125,369.0,100800.0,0.008599999360740185,287.8000183105469,-0.9000000357627869,-0.800000011920929,0.0
+2015-12-13 16:00:00,0.0,331.1000061035156,452.0,100790.0,0.008899999782443047,291.3000183105469,-0.9000000357627869,0.4000000059604645,0.0
+2015-12-13 17:00:00,0.0,331.1000061035156,477.3000183105469,100700.0,0.00839999970048666,293.1000061035156,-0.9000000357627869,1.600000023841858,0.0
+2015-12-13 18:00:00,0.0,345.1000061035156,456.8000183105469,100580.0,0.009800000116229057,294.3999938964844,-0.9000000357627869,2.799999952316284,0.0
+2015-12-13 19:00:00,0.0,345.1000061035156,401.8999938964844,100490.0,0.009499999694526196,295.0,-1.3000000715255737,2.799999952316284,0.0
+2015-12-13 20:00:00,0.0,345.1000061035156,313.3000183105469,100420.0,0.010300000198185444,295.5,-1.600000023841858,2.9000000953674316,0.0
+2015-12-13 21:00:00,0.0,324.3000183105469,145.0,100370.0,0.010499999858438969,294.8999938964844,-2.0,3.0,0.0
+2015-12-13 22:00:00,0.0,324.3000183105469,25.700000762939453,100400.0,0.011099999770522118,292.8000183105469,-2.200000047683716,2.4000000953674316,0.0
+2015-12-13 23:00:00,0.0,324.3000183105469,0.0,100370.0,0.010900000110268593,290.1000061035156,-2.4000000953674316,1.7000000476837158,0.0
+2015-12-14 00:00:00,0.0,330.0,0.0,100370.0,0.010900000110268593,289.0,-2.6000001430511475,1.100000023841858,0.0
+2015-12-14 01:00:00,0.0,330.0,0.0,100360.0,0.011299999430775642,289.8999938964844,-2.799999952316284,1.2000000476837158,0.0
+2015-12-14 02:00:00,0.0,330.0,0.0,100380.0,0.011299999430775642,289.8999938964844,-2.9000000953674316,1.3000000715255737,0.0
+2015-12-14 03:00:00,0.0,317.3999938964844,0.0,100320.0,0.01119999960064888,289.5,-3.1000001430511475,1.399999976158142,0.0
+2015-12-14 04:00:00,0.0,317.3999938964844,0.0,100260.0,0.010900000110268593,289.1000061035156,-2.9000000953674316,1.899999976158142,0.0
+2015-12-14 05:00:00,0.0,317.3999938964844,0.0,100270.0,0.011099999770522118,289.0,-2.700000047683716,2.4000000953674316,0.0
+2015-12-14 06:00:00,0.0,324.3000183105469,0.0,100200.0,0.011399999260902405,289.20001220703125,-2.4000000953674316,2.9000000953674316,0.0
+2015-12-14 07:00:00,0.0,324.3000183105469,0.0,100130.0,0.01119999960064888,289.3000183105469,-1.899999976158142,2.9000000953674316,0.0
+2015-12-14 08:00:00,0.0,324.3000183105469,0.0,100020.0,0.011399999260902405,289.3999938964844,-1.5,3.0,0.0
+2015-12-14 09:00:00,0.0,358.3000183105469,0.0,99880.0,0.011500000022351742,290.0,-1.0,3.0,0.0
+2015-12-14 10:00:00,0.0,358.3000183105469,0.0,99810.0,0.011799999512732029,289.8999938964844,-1.600000023841858,3.1000001430511475,0.0
+2015-12-14 11:00:00,0.0,358.3000183105469,0.0,99780.0,0.012000000104308128,289.8999938964844,-2.200000047683716,3.200000047683716,0.0
+2015-12-14 12:00:00,0.0,381.1000061035156,0.0,99710.0,0.011699999682605267,289.8999938964844,-2.799999952316284,3.299999952316284,0.0
+2015-12-14 13:00:00,0.0,381.1000061035156,37.0,99680.0,0.012299999594688416,290.8000183105469,-2.1000001430511475,3.799999952316284,0.0
+2015-12-14 14:00:00,0.0,381.1000061035156,101.80000305175781,99650.0,0.012600000016391277,291.3000183105469,-1.399999976158142,4.300000190734863,7.382353145925361e-07
+2015-12-14 15:00:00,1.5,392.8999938964844,181.90000915527344,99570.0,0.012899999506771564,291.5,-0.699999988079071,4.800000190734863,0.0
+2015-12-14 16:00:00,0.0,392.8999938964844,223.10000610351562,99410.0,0.013399999588727951,292.6000061035156,-0.20000000298023224,4.900000095367432,0.0
+2015-12-14 17:00:00,0.0,392.8999938964844,235.8000030517578,99350.0,0.013899999670684338,293.3999938964844,0.30000001192092896,4.900000095367432,0.0
+2015-12-14 18:00:00,0.0,405.20001220703125,161.5,99270.0,0.014299999922513962,293.8000183105469,0.699999988079071,4.900000095367432,0.0
+2015-12-14 19:00:00,0.0,405.20001220703125,142.10000610351562,99290.0,0.014599999412894249,295.0,1.2000000476837158,4.5,5.090121965577734e-08
+2015-12-14 20:00:00,0.10000000149011612,405.20001220703125,110.9000015258789,99160.0,0.013499999418854713,293.6000061035156,1.600000023841858,4.099999904632568,2.1604080814467757e-06
+2015-12-14 21:00:00,4.300000190734863,395.70001220703125,43.79999923706055,99230.0,0.012299999594688416,291.6000061035156,2.1000001430511475,3.700000047683716,0.0
+2015-12-14 22:00:00,0.0,395.70001220703125,7.900000095367432,99140.0,0.012000000104308128,290.5,2.200000047683716,3.4000000953674316,0.0
+2015-12-14 23:00:00,0.0,395.70001220703125,0.0,99170.0,0.01209999993443489,290.70001220703125,2.4000000953674316,3.1000001430511475,0.0
+2015-12-15 00:00:00,0.0,333.3999938964844,0.0,99160.0,0.012000000104308128,290.3000183105469,2.5,2.700000047683716,0.0
+2015-12-15 01:00:00,0.0,333.3999938964844,0.0,99170.0,0.011899999342858791,290.3999938964844,3.1000001430511475,2.9000000953674316,0.0
+2015-12-15 02:00:00,0.0,333.3999938964844,0.0,99250.0,0.011699999682605267,290.0,3.6000001430511475,3.0,0.0
+2015-12-15 03:00:00,0.0,304.20001220703125,0.0,99280.0,0.011299999430775642,289.3000183105469,4.200000286102295,3.1000001430511475,0.0
+2015-12-15 04:00:00,0.0,304.20001220703125,0.0,99310.0,0.010900000110268593,288.5,4.200000286102295,2.700000047683716,0.0
+2015-12-15 05:00:00,0.0,304.20001220703125,0.0,99320.0,0.00969999935477972,288.20001220703125,4.300000190734863,2.200000047683716,0.0
+2015-12-15 06:00:00,0.0,287.3999938964844,0.0,99320.0,0.008999999612569809,286.8999938964844,4.300000190734863,1.7000000476837158,0.0
+2015-12-15 07:00:00,0.0,287.3999938964844,0.0,99360.0,0.00839999970048666,286.8000183105469,4.099999904632568,1.5,0.0
+2015-12-15 08:00:00,0.0,287.3999938964844,0.0,99340.0,0.007400000002235174,286.1000061035156,3.9000000953674316,1.2000000476837158,0.0
+2015-12-15 09:00:00,0.0,278.3999938964844,0.0,99330.0,0.00699999975040555,285.5,3.700000047683716,0.9000000357627869,0.0
+2015-12-15 10:00:00,0.0,278.3999938964844,0.0,99390.0,0.006899999920278788,284.8000183105469,3.5,0.9000000357627869,0.0
+2015-12-15 11:00:00,0.0,278.3999938964844,0.0,99390.0,0.0066999997943639755,284.6000061035156,3.299999952316284,0.800000011920929,0.0
+2015-12-15 12:00:00,0.0,270.3000183105469,0.0,99480.0,0.0066999997943639755,283.3000183105469,3.1000001430511475,0.699999988079071,0.0
+2015-12-15 13:00:00,0.0,270.3000183105469,82.5,99590.0,0.00699999975040555,282.70001220703125,3.1000001430511475,0.30000001192092896,0.0
+2015-12-15 14:00:00,0.0,270.3000183105469,230.0,99630.0,0.0072999997064471245,284.70001220703125,3.0,-0.10000000149011612,0.0
+2015-12-15 15:00:00,0.0,301.20001220703125,386.70001220703125,99670.0,0.0071000000461936,287.20001220703125,2.9000000953674316,-0.6000000238418579,0.0
+2015-12-15 16:00:00,0.0,301.20001220703125,475.1000061035156,99630.0,0.0072999997064471245,289.70001220703125,2.700000047683716,-0.10000000149011612,0.0
+2015-12-15 17:00:00,0.0,301.20001220703125,502.6000061035156,99560.0,0.007199999876320362,291.70001220703125,2.5,0.30000001192092896,0.0
+2015-12-15 18:00:00,0.0,315.8000183105469,490.0,99520.0,0.00699999975040555,293.6000061035156,2.200000047683716,0.699999988079071,0.0
+2015-12-15 19:00:00,0.0,315.8000183105469,431.70001220703125,99480.0,0.007199999876320362,295.20001220703125,2.0,0.5,0.0
+2015-12-15 20:00:00,0.0,315.8000183105469,337.1000061035156,99490.0,0.006899999920278788,295.6000061035156,1.7000000476837158,0.20000000298023224,0.0
+2015-12-15 21:00:00,0.0,305.8999938964844,148.5,99550.0,0.0071000000461936,295.3999938964844,1.399999976158142,0.0,0.0
+2015-12-15 22:00:00,0.0,305.8999938964844,27.200000762939453,99600.0,0.008100000210106373,292.3999938964844,1.100000023841858,0.30000001192092896,0.0
+2015-12-15 23:00:00,0.0,306.0,0.0,99620.0,0.008299999870359898,288.20001220703125,0.699999988079071,0.5,0.0
+2015-12-16 00:00:00,0.0,288.8999938964844,0.0,99650.0,0.00839999970048666,286.3000183105469,0.4000000059604645,0.800000011920929,0.0
+2015-12-16 01:00:00,0.0,288.8999938964844,0.0,99710.0,0.007999999448657036,285.5,0.20000000298023224,0.10000000149011612,0.0
+2015-12-16 02:00:00,0.0,288.8999938964844,0.0,99710.0,0.008299999870359898,285.0,0.0,-0.699999988079071,0.0
+2015-12-16 03:00:00,0.0,282.20001220703125,0.0,99740.0,0.008200000040233135,284.70001220703125,-0.30000001192092896,-1.399999976158142,0.0
+2015-12-16 04:00:00,0.0,282.20001220703125,0.0,99800.0,0.007799999788403511,283.8000183105469,-0.4000000059604645,-1.2000000476837158,0.0
+2015-12-16 05:00:00,0.0,282.20001220703125,0.0,99830.0,0.006899999920278788,281.20001220703125,-0.6000000238418579,-1.0,0.0
+2015-12-16 06:00:00,0.0,277.0,0.0,99820.0,0.006899999920278788,282.0,-0.699999988079071,-0.9000000357627869,0.0
+2015-12-16 07:00:00,0.0,277.0,0.0,99890.0,0.0064999996684491634,280.6000061035156,-0.9000000357627869,-0.800000011920929,0.0
+2015-12-16 08:00:00,0.0,277.0,0.0,99930.0,0.006300000008195639,279.8999938964844,-1.2000000476837158,-0.800000011920929,0.0
+2015-12-16 09:00:00,0.0,272.8000183105469,0.0,99880.0,0.006199999712407589,280.5,-1.399999976158142,-0.800000011920929,0.0
+2015-12-16 10:00:00,0.0,272.8000183105469,0.0,99880.0,0.006000000052154064,280.20001220703125,-1.8000000715255737,-0.800000011920929,0.0
+2015-12-16 11:00:00,0.0,272.8000183105469,0.0,99980.0,0.005399999674409628,278.3000183105469,-2.200000047683716,-0.800000011920929,0.0
+2015-12-16 12:00:00,0.0,267.5,0.0,100000.0,0.005499999970197678,278.20001220703125,-2.700000047683716,-0.800000011920929,0.0
+2015-12-16 13:00:00,0.0,267.5,81.30000305175781,100070.0,0.0058999997563660145,279.20001220703125,-2.5,-0.9000000357627869,0.0
+2015-12-16 14:00:00,0.0,267.5,230.10000610351562,100140.0,0.006799999624490738,281.5,-2.299999952316284,-1.0,0.0
+2015-12-16 15:00:00,0.0,293.8999938964844,387.3999938964844,100190.0,0.007499999832361937,284.8000183105469,-2.200000047683716,-1.100000023841858,0.0
+2015-12-16 16:00:00,0.0,293.8999938964844,476.6000061035156,100110.0,0.008499999530613422,288.70001220703125,-2.5,-0.6000000238418579,0.0
+2015-12-16 17:00:00,0.0,293.8999938964844,504.70001220703125,100060.0,0.007599999662488699,291.8000183105469,-2.9000000953674316,-0.10000000149011612,0.0
+2015-12-16 18:00:00,0.0,310.1000061035156,489.3000183105469,99980.0,0.007599999662488699,293.8000183105469,-3.299999952316284,0.4000000059604645,0.0
+2015-12-16 19:00:00,0.0,310.1000061035156,431.3000183105469,99930.0,0.007899999618530273,295.0,-3.1000001430511475,0.6000000238418579,0.0
+2015-12-16 20:00:00,0.0,310.1000061035156,337.20001220703125,99920.0,0.007999999448657036,295.20001220703125,-2.799999952316284,0.800000011920929,0.0
+2015-12-16 21:00:00,0.0,305.8000183105469,148.10000610351562,99810.0,0.007899999618530273,294.70001220703125,-2.6000001430511475,1.0,0.0
+2015-12-16 22:00:00,0.0,305.8000183105469,27.600000381469727,99850.0,0.008299999870359898,291.8999938964844,-2.799999952316284,0.6000000238418579,0.0
+2015-12-16 23:00:00,0.0,305.8000183105469,0.0,99890.0,0.008700000122189522,290.1000061035156,-3.0,0.30000001192092896,0.0
+2015-12-17 00:00:00,0.0,311.5,0.0,99900.0,0.008899999782443047,288.70001220703125,-3.200000047683716,0.0,0.0
+2015-12-17 01:00:00,0.0,311.5,0.0,100010.0,0.008599999360740185,286.0,-2.9000000953674316,0.10000000149011612,0.0
+2015-12-17 02:00:00,0.0,311.5,0.0,100000.0,0.008599999360740185,286.3000183105469,-2.6000001430511475,0.20000000298023224,0.0
+2015-12-17 03:00:00,0.0,342.0,0.0,99940.0,0.008499999530613422,286.6000061035156,-2.299999952316284,0.4000000059604645,2.3657042550979653e-07
+2015-12-17 04:00:00,0.5,342.0,0.0,99910.0,0.008799999952316284,287.5,-1.8000000715255737,0.4000000059604645,4.76594374793869e-07
+2015-12-17 05:00:00,1.0,342.0,0.0,99930.0,0.00930000003427267,287.20001220703125,-1.3000000715255737,0.5,1.426301595152609e-06
+2015-12-17 06:00:00,3.0,382.5,0.0,99760.0,0.009499999694526196,286.5,-0.800000011920929,0.5,4.727622629790369e-07
+2015-12-17 07:00:00,1.0,382.3999938964844,0.0,99720.0,0.009399999864399433,286.6000061035156,-1.2000000476837158,0.6000000238418579,1.0409098948042186e-06
+2015-12-17 08:00:00,2.200000047683716,382.3999938964844,0.0,99740.0,0.009499999694526196,286.6000061035156,-1.600000023841858,0.699999988079071,0.0
+2015-12-17 09:00:00,0.0,382.6000061035156,0.0,99710.0,0.00930000003427267,286.5,-2.0,0.699999988079071,0.0
+2015-12-17 10:00:00,0.0,382.6000061035156,0.0,99590.0,0.008999999612569809,286.20001220703125,-2.4000000953674316,0.699999988079071,0.0
+2015-12-17 11:00:00,0.0,382.6000061035156,0.0,99510.0,0.009099999442696571,286.6000061035156,-2.799999952316284,0.699999988079071,1.419422553058779e-06
+2015-12-17 12:00:00,3.0,384.20001220703125,0.0,99450.0,0.00930000003427267,286.3999938964844,-3.200000047683716,0.6000000238418579,2.0784926960470127e-06
+2015-12-17 13:00:00,4.400000095367432,384.20001220703125,34.5,99540.0,0.009499999694526196,286.5,-3.0,1.5,2.0801540021938852e-06
+2015-12-17 14:00:00,4.400000095367432,384.20001220703125,99.20000457763672,99540.0,0.00969999935477972,286.8999938964844,-2.799999952316284,2.4000000953674316,7.588522475838139e-07
+2015-12-17 15:00:00,1.600000023841858,404.20001220703125,157.0,99420.0,0.009800000116229057,287.3000183105469,-2.700000047683716,3.299999952316284,1.0943852648065907e-06
+2015-12-17 16:00:00,2.299999952316284,404.20001220703125,193.40000915527344,99470.0,0.009800000116229057,287.0,-0.6000000238418579,4.300000190734863,1.8037282986643158e-06
+2015-12-17 17:00:00,3.799999952316284,404.20001220703125,204.90000915527344,99360.0,0.009800000116229057,286.8999938964844,1.5,5.400000095367432,0.0
+2015-12-17 18:00:00,0.0,380.20001220703125,242.6999969482422,99310.0,0.010599999688565731,288.0,3.6000001430511475,6.400000095367432,0.0
+2015-12-17 19:00:00,0.0,380.20001220703125,214.10000610351562,99360.0,0.010999999940395355,289.3000183105469,3.799999952316284,5.599999904632568,0.0
+2015-12-17 20:00:00,0.0,380.20001220703125,167.60000610351562,99280.0,0.011399999260902405,289.20001220703125,4.0,4.800000190734863,0.0
+2015-12-17 21:00:00,0.0,371.1000061035156,72.30000305175781,99260.0,0.011399999260902405,289.70001220703125,4.200000286102295,4.0,0.0
+2015-12-17 22:00:00,0.0,371.1000061035156,13.699999809265137,99260.0,0.011899999342858791,289.70001220703125,3.700000047683716,3.9000000953674316,0.0
+2015-12-17 23:00:00,0.0,371.1000061035156,0.0,99330.0,0.011299999430775642,289.0,3.200000047683716,3.700000047683716,0.0
+2015-12-18 00:00:00,0.0,361.8000183105469,0.0,99330.0,0.01119999960064888,289.20001220703125,2.700000047683716,3.5,0.0
+2015-12-18 01:00:00,0.0,361.8000183105469,0.0,99410.0,0.010999999940395355,288.8000183105469,2.200000047683716,3.200000047683716,0.0
+2015-12-18 02:00:00,0.0,361.8000183105469,0.0,99440.0,0.010900000110268593,288.6000061035156,1.7000000476837158,2.9000000953674316,0.0
+2015-12-18 03:00:00,0.0,363.8000183105469,0.0,99430.0,0.010699999518692493,288.3999938964844,1.2000000476837158,2.6000001430511475,0.0
+2015-12-18 04:00:00,0.0,363.8000183105469,0.0,99460.0,0.010699999518692493,288.6000061035156,1.5,2.6000001430511475,0.0
+2015-12-18 05:00:00,0.0,363.8000183105469,0.0,99360.0,0.010699999518692493,288.1000061035156,1.7000000476837158,2.6000001430511475,0.0
+2015-12-18 06:00:00,0.0,344.3999938964844,0.0,99320.0,0.010699999518692493,287.70001220703125,1.899999976158142,2.700000047683716,0.0
+2015-12-18 07:00:00,0.0,344.3999938964844,0.0,99370.0,0.010400000028312206,288.1000061035156,2.0,2.4000000953674316,0.0
+2015-12-18 08:00:00,0.0,344.3999938964844,0.0,99390.0,0.009599999524652958,287.6000061035156,2.200000047683716,2.200000047683716,0.0
+2015-12-18 09:00:00,0.0,321.0,0.0,99340.0,0.009399999864399433,286.70001220703125,2.299999952316284,1.899999976158142,0.0
+2015-12-18 10:00:00,0.0,321.0,0.0,99390.0,0.00839999970048666,285.3000183105469,3.1000001430511475,1.8000000715255737,0.0
+2015-12-18 11:00:00,0.0,321.0,0.0,99440.0,0.0072999997064471245,283.8000183105469,3.799999952316284,1.600000023841858,0.0
+2015-12-18 12:00:00,0.0,269.0,0.0,99560.0,0.006899999920278788,282.8999938964844,4.599999904632568,1.5,0.0
+2015-12-18 13:00:00,0.0,269.0,82.20000457763672,99630.0,0.0066999997943639755,282.20001220703125,5.200000286102295,1.2000000476837158,0.0
+2015-12-18 14:00:00,0.0,269.0,239.3000030517578,99730.0,0.006300000008195639,282.3999938964844,5.700000286102295,0.800000011920929,0.0
+2015-12-18 15:00:00,0.0,263.5,388.8000183105469,99880.0,0.006000000052154064,282.20001220703125,6.300000190734863,0.5,0.0
+2015-12-18 16:00:00,0.0,263.5,479.70001220703125,99910.0,0.005699999630451202,284.0,6.800000190734863,0.20000000298023224,0.0
+2015-12-18 17:00:00,0.0,263.5,508.8999938964844,99850.0,0.0050999997183680534,285.1000061035156,7.300000190734863,-0.10000000149011612,0.0
+2015-12-18 18:00:00,0.0,260.0,503.1000061035156,99810.0,0.003999999724328518,286.70001220703125,7.800000190734863,-0.4000000059604645,0.0
+2015-12-18 19:00:00,0.0,260.0,444.20001220703125,99810.0,0.003399999812245369,287.1000061035156,7.200000286102295,-1.5,0.0
+2015-12-18 20:00:00,0.0,260.0,348.0,99920.0,0.002899999963119626,287.20001220703125,6.5,-2.6000001430511475,0.0
+2015-12-18 21:00:00,0.0,243.5,159.1999969482422,99950.0,0.0023999998811632395,286.1000061035156,5.800000190734863,-3.700000047683716,0.0
+2015-12-18 22:00:00,0.0,243.5,30.899999618530273,100130.0,0.002699999837204814,284.3999938964844,5.099999904632568,-3.4000000953674316,0.0
+2015-12-18 23:00:00,0.0,243.5,0.0,100260.0,0.003000000026077032,282.20001220703125,4.400000095367432,-3.1000001430511475,0.0
+2015-12-19 00:00:00,0.0,225.0,0.0,100400.0,0.0030999998562037945,280.5,3.6000001430511475,-2.799999952316284,0.0
+2015-12-19 01:00:00,0.0,225.0,0.0,100620.0,0.002899999963119626,278.8000183105469,3.4000000953674316,-2.6000001430511475,0.0
+2015-12-19 02:00:00,0.0,225.0,0.0,100790.0,0.00279999990016222,277.0,3.200000047683716,-2.299999952316284,0.0
+2015-12-19 03:00:00,0.0,214.6999969482422,0.0,100840.0,0.00279999990016222,276.0,2.9000000953674316,-2.1000001430511475,0.0
+2015-12-19 04:00:00,0.0,214.6999969482422,0.0,100940.0,0.002899999963119626,275.20001220703125,2.799999952316284,-2.1000001430511475,0.0
+2015-12-19 05:00:00,0.0,214.6999969482422,0.0,101020.0,0.00279999990016222,274.8000183105469,2.700000047683716,-2.0,0.0
+2015-12-19 06:00:00,0.0,206.60000610351562,0.0,101050.0,0.002199999988079071,274.1000061035156,2.6000001430511475,-2.0,0.0
+2015-12-19 07:00:00,0.0,206.60000610351562,0.0,101070.0,0.0024999999441206455,272.6000061035156,2.6000001430511475,-1.8000000715255737,0.0
+2015-12-19 08:00:00,0.0,206.60000610351562,0.0,101130.0,0.0023999998811632395,272.1000061035156,2.6000001430511475,-1.5,0.0
+2015-12-19 09:00:00,0.0,204.60000610351562,0.0,101190.0,0.0024999999441206455,271.70001220703125,2.5,-1.2000000476837158,0.0
+2015-12-19 10:00:00,0.0,204.60000610351562,0.0,101210.0,0.0026000000070780516,271.70001220703125,2.4000000953674316,-0.4000000059604645,0.0
+2015-12-19 11:00:00,0.0,204.60000610351562,0.0,101340.0,0.00279999990016222,270.6000061035156,2.200000047683716,0.4000000059604645,0.0
+2015-12-19 12:00:00,0.0,209.10000610351562,0.0,101420.0,0.002699999837204814,270.70001220703125,2.0,1.2000000476837158,0.0
+2015-12-19 13:00:00,0.0,209.10000610351562,79.0,101550.0,0.002899999963119626,271.3000183105469,2.1000001430511475,0.9000000357627869,0.0
+2015-12-19 14:00:00,0.0,209.10000610351562,233.0,101560.0,0.002899999963119626,273.5,2.200000047683716,0.6000000238418579,0.0
+2015-12-19 15:00:00,0.0,230.10000610351562,394.3000183105469,101690.0,0.00279999990016222,276.3999938964844,2.299999952316284,0.30000001192092896,0.0
+2015-12-19 16:00:00,0.0,230.10000610351562,487.0,101620.0,0.002300000051036477,279.3000183105469,2.9000000953674316,0.699999988079071,0.0
+2015-12-19 17:00:00,0.0,230.10000610351562,517.1000366210938,101550.0,0.002099999925121665,280.8000183105469,3.5,1.0,0.0
+2015-12-19 18:00:00,0.0,240.40000915527344,507.70001220703125,101500.0,0.0016999999061226845,281.70001220703125,4.099999904632568,1.3000000715255737,0.0
+2015-12-19 19:00:00,0.0,240.40000915527344,448.6000061035156,101460.0,0.0018999999156221747,282.6000061035156,3.9000000953674316,1.0,0.0
+2015-12-19 20:00:00,0.0,240.40000915527344,351.8000183105469,101410.0,0.002099999925121665,283.3999938964844,3.700000047683716,0.699999988079071,0.0
+2015-12-19 21:00:00,0.0,233.60000610351562,162.1999969482422,101410.0,0.002099999925121665,283.70001220703125,3.5,0.4000000059604645,0.0
+2015-12-19 22:00:00,0.0,233.60000610351562,32.10000228881836,101450.0,0.002099999925121665,282.3000183105469,3.200000047683716,0.699999988079071,0.0
+2015-12-19 23:00:00,0.0,233.60000610351562,0.0,101540.0,0.002699999837204814,278.8000183105469,2.9000000953674316,1.0,0.0
+2015-12-20 00:00:00,0.0,224.0,0.0,101560.0,0.003000000026077032,276.5,2.6000001430511475,1.3000000715255737,0.0
+2015-12-20 01:00:00,0.0,224.0,0.0,101590.0,0.0030999998562037945,275.8999938964844,2.299999952316284,0.9000000357627869,0.0
+2015-12-20 02:00:00,0.0,224.0,0.0,101580.0,0.003000000026077032,274.6000061035156,2.1000001430511475,0.6000000238418579,0.0
+2015-12-20 03:00:00,0.0,220.3000030517578,0.0,101540.0,0.003000000026077032,273.8000183105469,1.8000000715255737,0.20000000298023224,0.0
+2015-12-20 04:00:00,0.0,220.3000030517578,0.0,101590.0,0.003000000026077032,273.3000183105469,1.399999976158142,-0.4000000059604645,0.0
+2015-12-20 05:00:00,0.0,220.3000030517578,0.0,101620.0,0.002899999963119626,271.8000183105469,1.0,-1.100000023841858,0.0
+2015-12-20 06:00:00,0.0,218.0,0.0,101610.0,0.003000000026077032,272.1000061035156,0.6000000238418579,-1.7000000476837158,0.0
+2015-12-20 07:00:00,0.0,218.0,0.0,101640.0,0.003000000026077032,271.1000061035156,0.4000000059604645,-2.1000001430511475,0.0
+2015-12-20 08:00:00,0.0,218.0,0.0,101660.0,0.003000000026077032,271.5,0.20000000298023224,-2.4000000953674316,0.0
+2015-12-20 09:00:00,0.0,215.8000030517578,0.0,101690.0,0.002899999963119626,271.6000061035156,0.0,-2.799999952316284,0.0
+2015-12-20 10:00:00,0.0,215.8000030517578,0.0,101700.0,0.00279999990016222,271.0,-0.4000000059604645,-2.200000047683716,0.0
+2015-12-20 11:00:00,0.0,215.8000030517578,0.0,101720.0,0.00279999990016222,271.20001220703125,-0.800000011920929,-1.600000023841858,0.0
+2015-12-20 12:00:00,0.0,219.6999969482422,0.0,101720.0,0.00279999990016222,271.20001220703125,-1.3000000715255737,-1.0,0.0
+2015-12-20 13:00:00,0.0,219.6999969482422,76.80000305175781,101850.0,0.002899999963119626,271.20001220703125,-1.5,-0.800000011920929,0.0
+2015-12-20 14:00:00,0.0,219.6999969482422,229.6999969482422,101960.0,0.0031999999191612005,274.5,-1.7000000476837158,-0.699999988079071,0.0
+2015-12-20 15:00:00,0.0,242.6999969482422,390.3999938964844,101930.0,0.003000000026077032,278.6000061035156,-1.899999976158142,-0.5,0.0
+2015-12-20 16:00:00,0.0,242.6999969482422,482.8999938964844,101900.0,0.00279999990016222,282.1000061035156,-2.200000047683716,-0.10000000149011612,0.0
+2015-12-20 17:00:00,0.0,242.60000610351562,513.2000122070312,101840.0,0.0026000000070780516,284.5,-2.5,0.4000000059604645,0.0
+2015-12-20 18:00:00,0.0,254.8000030517578,500.70001220703125,101820.0,0.0023999998811632395,285.5,-2.799999952316284,0.800000011920929,0.0
+2015-12-20 19:00:00,0.0,254.8000030517578,442.8000183105469,101720.0,0.0024999999441206455,286.20001220703125,-2.700000047683716,0.9000000357627869,0.0
+2015-12-20 20:00:00,0.0,254.8000030517578,347.6000061035156,101690.0,0.0026000000070780516,286.1000061035156,-2.5,0.9000000357627869,0.0
+2015-12-20 21:00:00,0.0,253.3000030517578,173.0,101590.0,0.002699999837204814,285.3999938964844,-2.299999952316284,1.0,0.0
+2015-12-20 22:00:00,0.0,253.3000030517578,35.10000228881836,101600.0,0.002899999963119626,283.8999938964844,-2.700000047683716,1.0,0.0
+2015-12-20 23:00:00,0.0,253.3000030517578,0.0,101630.0,0.003399999812245369,281.6000061035156,-3.1000001430511475,1.100000023841858,0.0
+2015-12-21 00:00:00,0.0,250.10000610351562,0.0,101610.0,0.003700000001117587,279.70001220703125,-3.6000001430511475,1.2000000476837158,0.0
+2015-12-21 01:00:00,0.0,250.10000610351562,0.0,101580.0,0.003700000001117587,278.3999938964844,-3.299999952316284,0.6000000238418579,0.0
+2015-12-21 02:00:00,0.0,250.10000610351562,0.0,101630.0,0.003700000001117587,276.6000061035156,-3.1000001430511475,0.10000000149011612,0.0
+2015-12-21 03:00:00,0.0,266.5,0.0,101580.0,0.0037999998312443495,277.3000183105469,-2.799999952316284,-0.4000000059604645,0.0
+2015-12-21 04:00:00,0.0,266.5,0.0,101530.0,0.0037999998312443495,277.70001220703125,-2.799999952316284,-0.800000011920929,0.0
+2015-12-21 05:00:00,0.0,266.5,0.0,101500.0,0.0037999998312443495,277.1000061035156,-2.700000047683716,-1.100000023841858,0.0
+2015-12-21 06:00:00,0.0,289.0,0.0,101480.0,0.003999999724328518,278.0,-2.700000047683716,-1.399999976158142,0.0
+2015-12-21 07:00:00,0.0,289.0,0.0,101460.0,0.004100000020116568,279.1000061035156,-2.5,-1.399999976158142,0.0
+2015-12-21 08:00:00,0.0,289.0,0.0,101470.0,0.00419999985024333,279.0,-2.4000000953674316,-1.3000000715255737,0.0
+2015-12-21 09:00:00,0.0,334.1000061035156,0.0,101380.0,0.00419999985024333,279.3000183105469,-2.299999952316284,-1.2000000476837158,0.0
+2015-12-21 10:00:00,0.0,334.1000061035156,0.0,101340.0,0.004299999680370092,279.0,-2.200000047683716,-1.100000023841858,0.0
+2015-12-21 11:00:00,0.0,334.1000061035156,0.0,101290.0,0.00419999985024333,278.5,-2.1000001430511475,-1.100000023841858,0.0
+2015-12-21 12:00:00,0.0,352.8999938964844,0.0,101310.0,0.004399999976158142,279.1000061035156,-2.0,-1.0,0.0
+2015-12-21 13:00:00,0.0,352.8999938964844,33.29999923706055,101380.0,0.00419999985024333,279.5,-2.0,-0.9000000357627869,0.0
+2015-12-21 14:00:00,0.0,352.8999938964844,100.80000305175781,101310.0,0.00419999985024333,280.0,-2.0,-0.800000011920929,0.0
+2015-12-21 15:00:00,0.0,372.3999938964844,160.90000915527344,101310.0,0.004299999680370092,280.70001220703125,-2.0,-0.699999988079071,0.0
+2015-12-21 16:00:00,0.0,372.3999938964844,199.1999969482422,101300.0,0.0044999998062849045,282.6000061035156,-1.899999976158142,-0.4000000059604645,0.0
+2015-12-21 17:00:00,0.0,372.3999938964844,211.90000915527344,101220.0,0.004900000058114529,283.8000183105469,-1.7000000476837158,-0.20000000298023224,0.0
+2015-12-21 18:00:00,0.0,375.5,290.3999938964844,101150.0,0.004999999888241291,283.8999938964844,-1.5,0.10000000149011612,0.0
+2015-12-21 19:00:00,0.0,375.5,257.0,101050.0,0.005399999674409628,285.0,-1.600000023841858,0.10000000149011612,0.0
+2015-12-21 20:00:00,0.0,375.5,202.0,100890.0,0.00559999980032444,285.8000183105469,-1.8000000715255737,0.10000000149011612,0.0
+2015-12-21 21:00:00,0.0,361.70001220703125,132.8000030517578,100870.0,0.0058999997563660145,285.8000183105469,-1.899999976158142,0.10000000149011612,0.0
+2015-12-21 22:00:00,0.0,361.70001220703125,27.600000381469727,100820.0,0.006099999882280827,285.1000061035156,-2.200000047683716,0.4000000059604645,0.0
+2015-12-21 23:00:00,0.0,361.70001220703125,0.0,100830.0,0.006099999882280827,283.20001220703125,-2.5,0.699999988079071,0.0
+2015-12-22 00:00:00,0.0,357.0,0.0,100740.0,0.006199999712407589,283.20001220703125,-2.700000047683716,1.0,0.0
+2015-12-22 01:00:00,0.0,357.0,0.0,100760.0,0.0064999996684491634,283.0,-2.6000001430511475,0.9000000357627869,0.0
+2015-12-22 02:00:00,0.0,357.0,0.0,100770.0,0.006399999838322401,283.20001220703125,-2.5,0.800000011920929,0.0
+2015-12-22 03:00:00,0.0,369.20001220703125,0.0,100630.0,0.006300000008195639,282.1000061035156,-2.4000000953674316,0.699999988079071,0.0
+2015-12-22 04:00:00,0.0,369.20001220703125,0.0,100600.0,0.006300000008195639,282.5,-2.299999952316284,0.9000000357627869,0.0
+2015-12-22 05:00:00,0.0,369.20001220703125,0.0,100490.0,0.006599999964237213,283.1000061035156,-2.200000047683716,1.100000023841858,5.986149869805075e-07
+2015-12-22 06:00:00,1.3000000715255737,391.20001220703125,0.0,100310.0,0.00699999975040555,282.70001220703125,-2.1000001430511475,1.3000000715255737,2.8464086424883143e-06
+2015-12-22 07:00:00,6.200000286102295,391.1000061035156,0.0,100280.0,0.007499999832361937,283.5,-1.0,1.7000000476837158,3.00210506940693e-06
+2015-12-22 08:00:00,6.5,391.1000061035156,0.0,100110.0,0.008200000040233135,284.3000183105469,0.10000000149011612,2.0,3.392200346615728e-06
+2015-12-22 09:00:00,7.300000190734863,386.1000061035156,0.0,100030.0,0.008700000122189522,285.3000183105469,1.2000000476837158,2.4000000953674316,1.7654831463933217e-05
+2015-12-22 10:00:00,37.70000076293945,386.1000061035156,0.0,100100.0,0.009200000204145908,285.8999938964844,0.800000011920929,2.799999952316284,4.563967315233157e-06
+2015-12-22 11:00:00,9.699999809265137,386.1000061035156,0.0,100180.0,0.008899999782443047,285.3999938964844,0.6000000238418579,3.200000047683716,1.1716610241739401e-06
+2015-12-22 12:00:00,2.5,380.70001220703125,0.0,100160.0,0.009399999864399433,286.20001220703125,0.20000000298023224,3.6000001430511475,6.131225553307689e-07
+2015-12-22 13:00:00,1.3000000715255737,380.70001220703125,34.79999923706055,100130.0,0.009499999694526196,286.3000183105469,0.20000000298023224,3.6000001430511475,3.7760660823191564e-07
+2015-12-22 14:00:00,0.800000011920929,380.70001220703125,106.70000457763672,100230.0,0.009499999694526196,286.6000061035156,0.10000000149011612,3.700000047683716,0.0
+2015-12-22 15:00:00,0.0,384.8000183105469,237.60000610351562,100260.0,0.009999999776482582,287.20001220703125,0.10000000149011612,3.700000047683716,0.0
+2015-12-22 16:00:00,0.0,384.8000183105469,294.6000061035156,100210.0,0.010099999606609344,287.3999938964844,0.20000000298023224,3.5,0.0
+2015-12-22 17:00:00,0.0,384.8000183105469,313.6000061035156,100160.0,0.00989999994635582,287.0,0.30000001192092896,3.4000000953674316,0.0
+2015-12-22 18:00:00,0.0,392.8999938964844,306.5,100010.0,0.010300000198185444,288.0,0.4000000059604645,3.200000047683716,0.0
+2015-12-22 19:00:00,0.0,392.8999938964844,271.6000061035156,99990.0,0.011399999260902405,289.70001220703125,-0.10000000149011612,3.6000001430511475,0.0
+2015-12-22 20:00:00,0.0,392.8999938964844,213.6999969482422,99990.0,0.011699999682605267,290.20001220703125,-0.699999988079071,3.9000000953674316,0.0
+2015-12-22 21:00:00,0.0,388.3999938964844,118.30000305175781,100040.0,0.011599999852478504,290.0,-1.2000000476837158,4.300000190734863,0.0
+2015-12-22 22:00:00,0.0,388.3999938964844,25.200000762939453,99990.0,0.011399999260902405,289.6000061035156,-1.399999976158142,3.700000047683716,0.0
+2015-12-22 23:00:00,0.0,388.3999938964844,0.0,99990.0,0.010799999348819256,288.8000183105469,-1.600000023841858,3.1000001430511475,0.0
+2015-12-23 00:00:00,0.0,383.3000183105469,0.0,100050.0,0.011099999770522118,288.8000183105469,-1.8000000715255737,2.6000001430511475,0.0
+2015-12-23 01:00:00,0.0,383.3000183105469,0.0,100130.0,0.011099999770522118,289.20001220703125,-1.8000000715255737,2.200000047683716,0.0
+2015-12-23 02:00:00,0.0,383.3000183105469,0.0,100110.0,0.011099999770522118,288.8000183105469,-1.899999976158142,1.899999976158142,0.0
+2015-12-23 03:00:00,0.0,385.8000183105469,0.0,100090.0,0.011299999430775642,289.20001220703125,-2.0,1.5,0.0
+2015-12-23 04:00:00,0.0,385.8000183105469,0.0,100050.0,0.01119999960064888,289.0,-1.7000000476837158,1.600000023841858,0.0
+2015-12-23 05:00:00,0.0,385.8000183105469,0.0,100010.0,0.011699999682605267,289.5,-1.5,1.600000023841858,0.0
+2015-12-23 06:00:00,0.0,386.5,0.0,99980.0,0.011899999342858791,289.70001220703125,-1.2000000476837158,1.7000000476837158,0.0
+2015-12-23 07:00:00,0.0,386.5,0.0,100010.0,0.011599999852478504,289.8000183105469,-1.399999976158142,1.7000000476837158,0.0
+2015-12-23 08:00:00,0.0,386.5,0.0,100000.0,0.012000000104308128,289.70001220703125,-1.600000023841858,1.7000000476837158,0.0
+2015-12-23 09:00:00,0.0,391.0,0.0,99970.0,0.011899999342858791,289.8000183105469,-1.8000000715255737,1.7000000476837158,0.0
+2015-12-23 10:00:00,0.0,391.0,0.0,99940.0,0.011699999682605267,289.70001220703125,-2.1000001430511475,1.899999976158142,0.0
+2015-12-23 11:00:00,0.0,391.0,0.0,99920.0,0.011699999682605267,289.3999938964844,-2.5,2.1000001430511475,0.0
+2015-12-23 12:00:00,0.0,389.1000061035156,0.0,99900.0,0.011500000022351742,289.3000183105469,-2.799999952316284,2.4000000953674316,1.8866700062492885e-06
+2015-12-23 13:00:00,3.9000000953674316,389.1000061035156,42.400001525878906,99950.0,0.011699999682605267,289.70001220703125,-2.700000047683716,2.9000000953674316,5.824838155694726e-07
+2015-12-23 14:00:00,1.2000000476837158,389.1000061035156,131.6999969482422,99920.0,0.011899999342858791,289.8000183105469,-2.5,3.5,5.635471187070408e-06
+2015-12-23 15:00:00,11.600000381469727,393.8000183105469,163.0,99920.0,0.012000000104308128,290.0,-2.299999952316284,4.0,8.759635909420274e-07
+2015-12-23 16:00:00,1.8000000715255737,393.8000183105469,202.40000915527344,99860.0,0.01269999984651804,291.20001220703125,-1.899999976158142,4.099999904632568,4.4255319724101603e-07
+2015-12-23 17:00:00,0.9000000357627869,393.8000183105469,215.60000610351562,99740.0,0.013100000098347664,291.8999938964844,-1.399999976158142,4.099999904632568,0.0
+2015-12-23 18:00:00,0.0,405.20001220703125,182.3000030517578,99650.0,0.013700000010430813,292.20001220703125,-1.0,4.200000286102295,4.960924499258517e-06
+2015-12-23 19:00:00,10.0,405.20001220703125,161.60000610351562,99630.0,0.012899999506771564,291.6000061035156,-0.699999988079071,4.0,8.882235019915836e-07
+2015-12-23 20:00:00,1.8000000715255737,405.1000061035156,127.4000015258789,99690.0,0.012799999676644802,291.3000183105469,-0.4000000059604645,3.9000000953674316,2.9529413757094877e-07
+2015-12-23 21:00:00,0.6000000238418579,392.6000061035156,96.80000305175781,99740.0,0.013199999928474426,291.6000061035156,-0.10000000149011612,3.799999952316284,1.085606482825919e-06
+2015-12-23 22:00:00,2.200000047683716,392.6000061035156,21.100000381469727,99730.0,0.012399999424815178,290.8000183105469,-0.20000000298023224,3.200000047683716,3.430094869384076e-07
+2015-12-23 23:00:00,0.699999988079071,392.6000061035156,0.0,99800.0,0.012399999424815178,290.20001220703125,-0.4000000059604645,2.700000047683716,1.8524283800090267e-06
+2015-12-24 00:00:00,3.799999952316284,395.6000061035156,0.0,99980.0,0.012000000104308128,290.0,-0.5,2.200000047683716,6.813049765019497e-07
+2015-12-24 01:00:00,1.399999976158142,395.6000061035156,0.0,99950.0,0.011799999512732029,289.3999938964844,-1.0,2.299999952316284,1.0651743136309484e-06
+2015-12-24 02:00:00,2.200000047683716,395.6000061035156,0.0,100010.0,0.01209999993443489,290.3000183105469,-1.5,2.4000000953674316,7.806404696576303e-07
+2015-12-24 03:00:00,1.600000023841858,396.6000061035156,0.0,100050.0,0.01209999993443489,290.20001220703125,-2.0,2.5,7.799698656241153e-07
+2015-12-24 04:00:00,1.600000023841858,396.6000061035156,0.0,99960.0,0.011699999682605267,290.20001220703125,-1.3000000715255737,3.6000001430511475,0.0
+2015-12-24 05:00:00,0.0,396.6000061035156,0.0,100010.0,0.011799999512732029,289.8000183105469,-0.6000000238418579,4.700000286102295,0.0
+2015-12-24 06:00:00,0.0,392.8000183105469,0.0,99930.0,0.012199999764561653,290.3999938964844,0.10000000149011612,5.900000095367432,0.0
+2015-12-24 07:00:00,0.0,392.8000183105469,0.0,99960.0,0.012399999424815178,290.8000183105469,0.5,5.800000190734863,0.0
+2015-12-24 08:00:00,0.0,392.8000183105469,0.0,100010.0,0.012999999336898327,291.6000061035156,0.9000000357627869,5.800000190734863,0.0
+2015-12-24 09:00:00,0.0,379.6000061035156,0.0,99960.0,0.014099999330937862,293.3999938964844,1.3000000715255737,5.700000286102295,0.0
+2015-12-24 10:00:00,0.0,379.6000061035156,0.0,100010.0,0.014599999412894249,293.5,0.9000000357627869,4.700000286102295,0.0
+2015-12-24 11:00:00,0.0,379.6000061035156,0.0,100040.0,0.014599999412894249,293.8999938964844,0.5,3.700000047683716,0.0
+2015-12-24 12:00:00,0.0,379.20001220703125,0.0,100110.0,0.014699999243021011,293.70001220703125,0.0,2.700000047683716,0.0
+2015-12-24 13:00:00,0.0,379.20001220703125,49.5,100230.0,0.014699999243021011,294.0,0.699999988079071,3.0,0.0
+2015-12-24 14:00:00,0.0,379.20001220703125,155.6999969482422,100320.0,0.014599999412894249,294.20001220703125,1.3000000715255737,3.4000000953674316,0.0
+2015-12-24 15:00:00,0.0,397.6000061035156,267.3000183105469,100410.0,0.01489999983459711,294.8000183105469,2.0,3.799999952316284,0.0
+2015-12-24 16:00:00,0.0,397.6000061035156,332.1000061035156,100400.0,0.01489999983459711,295.6000061035156,3.1000001430511475,3.6000001430511475,0.0
+2015-12-24 17:00:00,0.0,397.6000061035156,354.1000061035156,100420.0,0.01529999915510416,295.1000061035156,4.099999904632568,3.4000000953674316,0.0
+2015-12-24 18:00:00,0.0,400.70001220703125,329.8000183105469,100330.0,0.015599999576807022,295.0,5.200000286102295,3.200000047683716,0.0
+2015-12-24 19:00:00,0.0,400.70001220703125,292.70001220703125,100360.0,0.01549999974668026,295.0,4.700000286102295,2.799999952316284,0.0
+2015-12-24 20:00:00,0.0,400.70001220703125,231.0,100360.0,0.01529999915510416,295.0,4.300000190734863,2.4000000953674316,0.0
+2015-12-24 21:00:00,0.0,403.8000183105469,93.20000457763672,100290.0,0.015199999324977398,295.20001220703125,3.799999952316284,2.0,0.0
+2015-12-24 22:00:00,0.0,403.8000183105469,20.80000114440918,100430.0,0.015699999406933784,294.8999938964844,2.4000000953674316,2.0,3.0511935942961847e-07
+2015-12-24 23:00:00,0.6000000238418579,403.8000183105469,0.0,100520.0,0.014999999664723873,294.5,1.0,2.0,7.599401290699011e-07
+2015-12-25 00:00:00,1.5,391.70001220703125,0.0,100450.0,0.014800000004470348,294.3999938964844,-0.4000000059604645,2.0,5.061538553138688e-08
+2015-12-25 01:00:00,0.10000000149011612,391.70001220703125,0.0,100600.0,0.013199999928474426,292.3999938964844,0.4000000059604645,1.899999976158142,0.0
+2015-12-25 02:00:00,0.0,391.70001220703125,0.0,100720.0,0.012600000016391277,291.8000183105469,1.2000000476837158,1.8000000715255737,0.0
+2015-12-25 03:00:00,0.0,379.20001220703125,0.0,100750.0,0.01269999984651804,291.8000183105469,2.0,1.7000000476837158,1.977323365029267e-07
+2015-12-25 04:00:00,0.4000000059604645,379.20001220703125,0.0,100800.0,0.01249999925494194,291.70001220703125,2.0,1.100000023841858,0.0
+2015-12-25 05:00:00,0.0,379.20001220703125,0.0,100790.0,0.012299999594688416,291.3000183105469,2.0,0.5,9.843137674574662e-08
+2015-12-25 06:00:00,0.20000000298023224,382.1000061035156,0.0,100810.0,0.01249999925494194,291.3999938964844,2.0,-0.10000000149011612,0.0
+2015-12-25 07:00:00,0.0,382.1000061035156,0.0,100770.0,0.012399999424815178,291.0,1.600000023841858,-0.30000001192092896,9.817343559310722e-08
+2015-12-25 08:00:00,0.20000000298023224,382.1000061035156,0.0,100770.0,0.01249999925494194,290.8000183105469,1.3000000715255737,-0.4000000059604645,0.0
+2015-12-25 09:00:00,0.0,386.20001220703125,0.0,100830.0,0.012199999764561653,290.8000183105469,0.9000000357627869,-0.6000000238418579,0.0
+2015-12-25 10:00:00,0.0,386.20001220703125,0.0,100760.0,0.011799999512732029,290.20001220703125,0.0,-0.30000001192092896,0.0
+2015-12-25 11:00:00,0.0,386.20001220703125,0.0,100790.0,0.011899999342858791,290.3999938964844,-0.9000000357627869,-0.10000000149011612,0.0
+2015-12-25 12:00:00,0.0,382.70001220703125,0.0,100870.0,0.01119999960064888,289.5,-1.7000000476837158,0.20000000298023224,0.0
+2015-12-25 13:00:00,0.0,382.70001220703125,55.29999923706055,100890.0,0.011799999512732029,289.6000061035156,-1.399999976158142,0.5,0.0
+2015-12-25 14:00:00,0.0,382.70001220703125,175.90000915527344,100880.0,0.012299999594688416,291.20001220703125,-1.100000023841858,0.800000011920929,0.0
+2015-12-25 15:00:00,0.0,391.3000183105469,320.20001220703125,100870.0,0.013399999588727951,293.0,-0.800000011920929,1.0,0.0
+2015-12-25 16:00:00,0.0,391.3000183105469,398.3000183105469,100910.0,0.013700000010430813,294.0,-0.30000001192092896,1.5,0.0
+2015-12-25 17:00:00,0.0,391.20001220703125,425.1000061035156,100780.0,0.014299999922513962,294.3000183105469,0.20000000298023224,2.1000001430511475,0.0
+2015-12-25 18:00:00,0.0,405.6000061035156,401.1000061035156,100700.0,0.01489999983459711,294.8999938964844,0.699999988079071,2.6000001430511475,0.0
+2015-12-25 19:00:00,0.0,405.6000061035156,356.20001220703125,100690.0,0.014800000004470348,296.20001220703125,1.100000023841858,2.5,0.0
+2015-12-25 20:00:00,0.0,405.6000061035156,281.6000061035156,100710.0,0.014999999664723873,296.3999938964844,1.600000023841858,2.4000000953674316,0.0
+2015-12-25 21:00:00,0.0,404.20001220703125,123.80000305175781,100660.0,0.015099999494850636,297.0,2.0,2.299999952316284,0.0
+2015-12-25 22:00:00,0.0,404.20001220703125,28.399999618530273,100720.0,0.015199999324977398,296.1000061035156,1.3000000715255737,2.0,0.0
+2015-12-25 23:00:00,0.0,404.20001220703125,0.0,100800.0,0.015399999916553497,295.1000061035156,0.699999988079071,1.8000000715255737,0.0
+2015-12-26 00:00:00,0.0,398.3000183105469,0.0,100870.0,0.014599999412894249,294.1000061035156,0.0,1.5,0.0
+2015-12-26 01:00:00,0.0,398.3000183105469,0.0,100890.0,0.013599999248981476,292.8999938964844,-0.4000000059604645,0.9000000357627869,7.488365405375216e-07
+2015-12-26 02:00:00,1.5,398.3000183105469,0.0,100970.0,0.013399999588727951,292.1000061035156,-0.9000000357627869,0.20000000298023224,0.0
+2015-12-26 03:00:00,0.0,397.8999938964844,0.0,100910.0,0.012899999506771564,291.70001220703125,-1.3000000715255737,-0.5,0.0
+2015-12-26 04:00:00,0.0,397.8999938964844,0.0,100900.0,0.01249999925494194,291.3000183105469,-1.2000000476837158,-0.6000000238418579,0.0
+2015-12-26 05:00:00,0.0,397.8999938964844,0.0,100910.0,0.011799999512732029,290.3000183105469,-1.0,-0.699999988079071,0.0
+2015-12-26 06:00:00,0.0,385.8999938964844,0.0,100880.0,0.012299999594688416,291.0,-0.800000011920929,-0.800000011920929,0.0
+2015-12-26 07:00:00,0.0,385.8999938964844,0.0,100940.0,0.011599999852478504,290.5,-1.3000000715255737,-0.6000000238418579,0.0
+2015-12-26 08:00:00,0.0,385.8999938964844,0.0,100930.0,0.011599999852478504,290.20001220703125,-1.7000000476837158,-0.5,0.0
+2015-12-26 09:00:00,0.0,379.5,0.0,100900.0,0.010799999348819256,289.3999938964844,-2.1000001430511475,-0.30000001192092896,0.0
+2015-12-26 10:00:00,0.0,379.5,0.0,100840.0,0.010799999348819256,289.1000061035156,-1.8000000715255737,-0.5,0.0
+2015-12-26 11:00:00,0.0,379.5,0.0,100760.0,0.011099999770522118,289.3999938964844,-1.5,-0.699999988079071,0.0
+2015-12-26 12:00:00,0.0,364.70001220703125,0.0,100780.0,0.01119999960064888,289.8000183105469,-1.2000000476837158,-0.9000000357627869,0.0
+2015-12-26 13:00:00,0.0,364.70001220703125,62.900001525878906,100880.0,0.010999999940395355,289.20001220703125,-1.3000000715255737,-0.800000011920929,0.0
+2015-12-26 14:00:00,0.0,364.70001220703125,202.40000915527344,100980.0,0.011699999682605267,290.8000183105469,-1.399999976158142,-0.800000011920929,0.0
+2015-12-26 15:00:00,0.0,376.6000061035156,354.8000183105469,101080.0,0.01269999984651804,292.5,-1.5,-0.699999988079071,0.0
+2015-12-26 16:00:00,0.0,376.6000061035156,442.0,101100.0,0.012999999336898327,294.0,-1.3000000715255737,0.20000000298023224,0.0
+2015-12-26 17:00:00,0.0,376.5,472.0,100970.0,0.013100000098347664,295.0,-1.100000023841858,1.0,0.0
+2015-12-26 18:00:00,0.0,386.6000061035156,470.6000061035156,100840.0,0.013399999588727951,296.0,-0.9000000357627869,1.899999976158142,0.0
+2015-12-26 19:00:00,0.0,386.6000061035156,418.3999938964844,100840.0,0.013599999248981476,297.3999938964844,-0.800000011920929,1.899999976158142,0.0
+2015-12-26 20:00:00,0.0,386.6000061035156,331.20001220703125,100780.0,0.013799999840557575,297.20001220703125,-0.800000011920929,1.8000000715255737,0.0
+2015-12-26 21:00:00,0.0,373.20001220703125,153.10000610351562,100780.0,0.013799999840557575,296.70001220703125,-0.699999988079071,1.8000000715255737,0.0
+2015-12-26 22:00:00,0.0,373.20001220703125,36.0,100790.0,0.013899999670684338,295.3000183105469,-1.3000000715255737,1.8000000715255737,0.0
+2015-12-26 23:00:00,0.0,373.20001220703125,0.0,100820.0,0.013899999670684338,293.8999938964844,-2.0,1.899999976158142,0.0
+2015-12-27 00:00:00,0.0,358.3999938964844,0.0,100880.0,0.013700000010430813,293.20001220703125,-2.6000001430511475,2.0,0.0
+2015-12-27 01:00:00,0.0,358.3999938964844,0.0,100850.0,0.013499999418854713,293.20001220703125,-2.6000001430511475,1.8000000715255737,0.0
+2015-12-27 02:00:00,0.0,358.3999938964844,0.0,100870.0,0.013299999758601189,292.5,-2.6000001430511475,1.600000023841858,0.0
+2015-12-27 03:00:00,0.0,351.20001220703125,0.0,100870.0,0.013599999248981476,292.1000061035156,-2.6000001430511475,1.5,0.0
+2015-12-27 04:00:00,0.0,351.20001220703125,0.0,100840.0,0.012999999336898327,291.70001220703125,-2.4000000953674316,1.600000023841858,0.0
+2015-12-27 05:00:00,0.0,351.20001220703125,0.0,100770.0,0.013399999588727951,292.3000183105469,-2.200000047683716,1.8000000715255737,0.0
+2015-12-27 06:00:00,0.0,359.8999938964844,0.0,100740.0,0.013399999588727951,292.20001220703125,-2.0,2.0,0.0
+2015-12-27 07:00:00,0.0,359.8999938964844,0.0,100680.0,0.013799999840557575,292.3999938964844,-1.899999976158142,1.8000000715255737,0.0
+2015-12-27 08:00:00,0.0,359.8999938964844,0.0,100750.0,0.013700000010430813,292.3000183105469,-1.8000000715255737,1.600000023841858,0.0
+2015-12-27 09:00:00,0.0,369.1000061035156,0.0,100630.0,0.013799999840557575,292.8000183105469,-1.600000023841858,1.399999976158142,0.0
+2015-12-27 10:00:00,0.0,369.1000061035156,0.0,100650.0,0.013799999840557575,292.5,-1.7000000476837158,1.399999976158142,0.0
+2015-12-27 11:00:00,0.0,369.1000061035156,0.0,100620.0,0.013700000010430813,292.70001220703125,-1.8000000715255737,1.399999976158142,0.0
+2015-12-27 12:00:00,0.0,366.3999938964844,0.0,100650.0,0.013499999418854713,292.3999938964844,-1.899999976158142,1.399999976158142,0.0
+2015-12-27 13:00:00,0.0,366.3999938964844,38.10000228881836,100620.0,0.012799999676644802,292.20001220703125,-1.3000000715255737,1.0,7.441386748887777e-07
+2015-12-27 14:00:00,1.5,366.3999938964844,123.9000015258789,100640.0,0.013199999928474426,292.20001220703125,-0.699999988079071,0.5,2.133197629303288e-06
+2015-12-27 15:00:00,4.300000190734863,391.1000061035156,208.8000030517578,100620.0,0.013399999588727951,292.20001220703125,-0.10000000149011612,0.0,0.0
+2015-12-27 16:00:00,0.0,391.0,260.20001220703125,100590.0,0.013599999248981476,293.1000061035156,0.20000000298023224,0.5,0.0
+2015-12-27 17:00:00,0.0,391.0,278.20001220703125,100480.0,0.0142000000923872,293.70001220703125,0.6000000238418579,1.0,0.0
+2015-12-27 18:00:00,0.0,394.5,305.3999938964844,100380.0,0.014299999922513962,294.20001220703125,1.0,1.5,0.0
+2015-12-27 19:00:00,0.0,394.5,271.8000183105469,100290.0,0.014699999243021011,295.5,1.0,1.600000023841858,0.0
+2015-12-27 20:00:00,0.0,394.3999938964844,215.5,100240.0,0.014499999582767487,295.8999938964844,1.100000023841858,1.7000000476837158,0.0
+2015-12-27 21:00:00,0.0,388.6000061035156,140.40000915527344,100200.0,0.014599999412894249,295.5,1.100000023841858,1.7000000476837158,0.0
+2015-12-27 22:00:00,0.0,388.6000061035156,33.900001525878906,100260.0,0.014599999412894249,294.8999938964844,0.4000000059604645,1.899999976158142,0.0
+2015-12-27 23:00:00,0.0,388.6000061035156,0.0,100270.0,0.014999999664723873,294.70001220703125,-0.30000001192092896,2.1000001430511475,0.0
+2015-12-28 00:00:00,0.0,373.20001220703125,0.0,100260.0,0.014499999582767487,293.6000061035156,-1.0,2.299999952316284,0.0
+2015-12-28 01:00:00,0.0,373.20001220703125,0.0,100310.0,0.013499999418854713,291.8999938964844,-1.2000000476837158,2.299999952316284,0.0
+2015-12-28 02:00:00,0.0,373.20001220703125,0.0,100320.0,0.012999999336898327,291.70001220703125,-1.399999976158142,2.200000047683716,0.0
+2015-12-28 03:00:00,0.0,338.8999938964844,0.0,100320.0,0.012899999506771564,291.3999938964844,-1.600000023841858,2.200000047683716,0.0
+2015-12-28 04:00:00,0.0,338.8999938964844,0.0,100370.0,0.012799999676644802,291.6000061035156,-1.7000000476837158,2.200000047683716,0.0
+2015-12-28 05:00:00,0.0,338.8999938964844,0.0,100340.0,0.012799999676644802,291.1000061035156,-1.8000000715255737,2.200000047683716,0.0
+2015-12-28 06:00:00,0.0,342.3000183105469,0.0,100290.0,0.013499999418854713,291.8999938964844,-1.899999976158142,2.200000047683716,0.0
+2015-12-28 07:00:00,0.0,342.3000183105469,0.0,100300.0,0.013399999588727951,291.8999938964844,-2.1000001430511475,1.7000000476837158,0.0
+2015-12-28 08:00:00,0.0,342.3000183105469,0.0,100340.0,0.013299999758601189,291.70001220703125,-2.4000000953674316,1.100000023841858,0.0
+2015-12-28 09:00:00,0.0,342.1000061035156,0.0,100280.0,0.013299999758601189,291.70001220703125,-2.700000047683716,0.6000000238418579,0.0
+2015-12-28 10:00:00,0.0,342.1000061035156,0.0,100280.0,0.012999999336898327,291.70001220703125,-2.700000047683716,0.5,0.0
+2015-12-28 11:00:00,0.0,342.1000061035156,0.0,100250.0,0.012899999506771564,291.5,-2.700000047683716,0.5,0.0
+2015-12-28 12:00:00,0.0,349.5,0.0,100320.0,0.012799999676644802,291.20001220703125,-2.700000047683716,0.5,0.0
+2015-12-28 13:00:00,0.0,349.5,51.5,100330.0,0.012899999506771564,291.70001220703125,-2.700000047683716,0.10000000149011612,0.0
+2015-12-28 14:00:00,0.0,349.5,169.0,100350.0,0.012899999506771564,291.6000061035156,-2.700000047683716,-0.20000000298023224,0.0
+2015-12-28 15:00:00,0.0,388.6000061035156,240.6999969482422,100330.0,0.013299999758601189,292.20001220703125,-2.700000047683716,-0.5,0.0
+2015-12-28 16:00:00,0.0,388.6000061035156,300.3999938964844,100370.0,0.0142000000923872,293.0,-3.4000000953674316,0.0,0.0
+2015-12-28 17:00:00,0.0,388.5,321.3999938964844,100250.0,0.014599999412894249,293.70001220703125,-4.099999904632568,0.5,0.0
+2015-12-28 18:00:00,0.0,413.5,234.5,100190.0,0.014699999243021011,294.6000061035156,-4.800000190734863,1.0,0.0
+2015-12-28 19:00:00,0.0,413.5,208.90000915527344,100100.0,0.014599999412894249,296.1000061035156,-5.200000286102295,1.100000023841858,0.0
+2015-12-28 20:00:00,0.0,413.5,165.8000030517578,99980.0,0.013799999840557575,296.6000061035156,-5.599999904632568,1.3000000715255737,0.0
+2015-12-28 21:00:00,0.0,390.0,130.5,99910.0,0.013700000010430813,295.8999938964844,-6.0,1.399999976158142,0.0
+2015-12-28 22:00:00,0.0,390.0,32.400001525878906,99950.0,0.0139999995008111,295.1000061035156,-6.400000095367432,1.8000000715255737,0.0
+2015-12-28 23:00:00,0.0,390.1000061035156,0.0,99940.0,0.014999999664723873,294.6000061035156,-6.900000095367432,2.200000047683716,0.0
+2015-12-29 00:00:00,0.0,380.1000061035156,0.0,99970.0,0.01489999983459711,294.6000061035156,-7.400000095367432,2.6000001430511475,0.0
+2015-12-29 01:00:00,0.0,380.1000061035156,0.0,99980.0,0.01549999974668026,295.1000061035156,-6.300000190734863,2.6000001430511475,0.0
+2015-12-29 02:00:00,0.0,380.1000061035156,0.0,99940.0,0.015799999237060547,295.3999938964844,-5.300000190734863,2.6000001430511475,0.0
+2015-12-29 03:00:00,0.0,388.70001220703125,0.0,99940.0,0.01529999915510416,295.1000061035156,-4.300000190734863,2.6000001430511475,2.0379742621031308e-07
+2015-12-29 04:00:00,0.4000000059604645,388.70001220703125,0.0,99940.0,0.015399999916553497,295.0,-3.299999952316284,3.200000047683716,5.090121965577734e-08
+2015-12-29 05:00:00,0.10000000149011612,388.70001220703125,0.0,99950.0,0.014999999664723873,294.70001220703125,-2.299999952316284,3.9000000953674316,1.1166688889383383e-06
+2015-12-29 06:00:00,2.200000047683716,398.3999938964844,0.0,99910.0,0.014800000004470348,294.20001220703125,-1.3000000715255737,4.5,1.1619883724544963e-06
+2015-12-29 07:00:00,2.299999952316284,398.3999938964844,0.0,99880.0,0.014999999664723873,294.8000183105469,-0.20000000298023224,4.900000095367432,2.591074675310334e-06
+2015-12-29 08:00:00,5.099999904632568,398.3999938964844,0.0,99870.0,0.014499999582767487,294.3999938964844,0.800000011920929,5.300000190734863,2.9863077501229664e-06
+2015-12-29 09:00:00,5.900000095367432,387.5,0.0,99900.0,0.014299999922513962,293.5,1.8000000715255737,5.700000286102295,7.529397965630518e-07
+2015-12-29 10:00:00,1.5,387.5,0.0,99920.0,0.0139999995008111,293.20001220703125,2.4000000953674316,5.0,5.506448621350923e-07
+2015-12-29 11:00:00,1.100000023841858,387.5,0.0,99960.0,0.014399999752640724,293.3000183105469,3.1000001430511475,4.400000095367432,0.0
+2015-12-29 12:00:00,0.0,381.5,0.0,99990.0,0.0139999995008111,293.3000183105469,3.700000047683716,3.799999952316284,0.0
+2015-12-29 13:00:00,0.0,381.5,35.5,100080.0,0.0139999995008111,293.1000061035156,3.5,3.6000001430511475,0.0
+2015-12-29 14:00:00,0.0,381.5,117.5999984741211,100180.0,0.0142000000923872,293.3000183105469,3.4000000953674316,3.5,0.0
+2015-12-29 15:00:00,0.0,373.70001220703125,246.90000915527344,100210.0,0.014800000004470348,294.8000183105469,3.200000047683716,3.4000000953674316,0.0
+2015-12-29 16:00:00,0.0,373.70001220703125,308.3999938964844,100230.0,0.014099999330937862,294.5,3.4000000953674316,3.5,0.0
+2015-12-29 17:00:00,0.0,373.70001220703125,330.20001220703125,100220.0,0.013700000010430813,294.3999938964844,3.6000001430511475,3.6000001430511475,0.0
+2015-12-29 18:00:00,0.0,375.20001220703125,375.70001220703125,100160.0,0.013299999758601189,294.8000183105469,3.700000047683716,3.700000047683716,0.0
+2015-12-29 19:00:00,0.0,375.20001220703125,335.1000061035156,100100.0,0.013599999248981476,296.8999938964844,3.299999952316284,3.4000000953674316,0.0
+2015-12-29 20:00:00,0.0,375.20001220703125,266.5,100140.0,0.013599999248981476,296.8999938964844,2.9000000953674316,3.1000001430511475,0.0
+2015-12-29 21:00:00,0.0,365.6000061035156,145.5,100170.0,0.013399999588727951,296.3999938964844,2.5,2.799999952316284,0.0
+2015-12-29 22:00:00,0.0,365.6000061035156,37.0,100250.0,0.01249999925494194,295.3000183105469,2.200000047683716,2.4000000953674316,0.0
+2015-12-29 23:00:00,0.0,365.6000061035156,0.0,100310.0,0.013299999758601189,293.70001220703125,1.899999976158142,2.0,0.0
+2015-12-30 00:00:00,0.0,337.70001220703125,0.0,100400.0,0.013299999758601189,292.70001220703125,1.600000023841858,1.600000023841858,0.0
+2015-12-30 01:00:00,0.0,337.70001220703125,0.0,100430.0,0.013199999928474426,292.6000061035156,1.2000000476837158,1.5,0.0
+2015-12-30 02:00:00,0.0,337.70001220703125,0.0,100530.0,0.012899999506771564,291.70001220703125,0.800000011920929,1.399999976158142,0.0
+2015-12-30 03:00:00,0.0,336.8999938964844,0.0,100520.0,0.01269999984651804,291.20001220703125,0.4000000059604645,1.2000000476837158,0.0
+2015-12-30 04:00:00,0.0,336.8999938964844,0.0,100570.0,0.012399999424815178,290.8999938964844,0.20000000298023224,1.3000000715255737,0.0
+2015-12-30 05:00:00,0.0,336.8999938964844,0.0,100590.0,0.011599999852478504,289.8999938964844,0.0,1.3000000715255737,0.0
+2015-12-30 06:00:00,0.0,353.0,0.0,100620.0,0.012000000104308128,290.1000061035156,-0.20000000298023224,1.3000000715255737,0.0
+2015-12-30 07:00:00,0.0,353.0,0.0,100610.0,0.011899999342858791,290.5,-0.6000000238418579,0.800000011920929,0.0
+2015-12-30 08:00:00,0.0,353.0,0.0,100590.0,0.012000000104308128,290.3999938964844,-1.0,0.20000000298023224,0.0
+2015-12-30 09:00:00,0.0,392.3999938964844,0.0,100630.0,0.011899999342858791,290.3999938964844,-1.399999976158142,-0.4000000059604645,3.418243187032877e-07
+2015-12-30 10:00:00,0.699999988079071,392.3999938964844,0.0,100590.0,0.012399999424815178,290.6000061035156,-1.3000000715255737,-0.20000000298023224,6.848304672955347e-07
+2015-12-30 11:00:00,1.399999976158142,392.3999938964844,0.0,100560.0,0.01249999925494194,291.1000061035156,-1.3000000715255737,0.0,0.0
+2015-12-30 12:00:00,0.0,396.8000183105469,0.0,100510.0,0.01269999984651804,291.3000183105469,-1.3000000715255737,0.20000000298023224,0.0
+2015-12-30 13:00:00,0.0,396.8000183105469,24.600000381469727,100620.0,0.012600000016391277,291.70001220703125,-0.699999988079071,0.20000000298023224,0.0
+2015-12-30 14:00:00,0.0,396.8000183105469,82.0999984741211,100630.0,0.013399999588727951,292.5,-0.20000000298023224,0.10000000149011612,4.9742695856783285e-08
+2015-12-30 15:00:00,0.10000000149011612,400.3000183105469,134.60000610351562,100600.0,0.014099999330937862,293.5,0.30000001192092896,0.0,4.2164631479768285e-06
+2015-12-30 16:00:00,8.40000057220459,400.3000183105469,168.3000030517578,100640.0,0.0139999995008111,292.3999938964844,0.5,0.6000000238418579,1.7294931218208543e-05
+2015-12-30 17:00:00,34.79999923706055,400.3000183105469,180.3000030517578,100590.0,0.012999999336898327,291.5,0.699999988079071,1.3000000715255737,3.599065574767947e-06
+2015-12-30 18:00:00,7.300000190734863,402.20001220703125,183.3000030517578,100610.0,0.012600000016391277,290.8999938964844,0.800000011920929,2.0,2.305066719490677e-06
+2015-12-30 19:00:00,4.700000286102295,402.20001220703125,163.60000610351562,100560.0,0.01249999925494194,291.0,0.800000011920929,1.899999976158142,1.816208554815238e-06
+2015-12-30 20:00:00,3.700000047683716,402.20001220703125,130.3000030517578,100490.0,0.012799999676644802,291.0,0.800000011920929,1.8000000715255737,2.061642257172614e-06
+2015-12-30 21:00:00,4.200000286102295,399.20001220703125,80.4000015258789,100470.0,0.012600000016391277,291.1000061035156,0.800000011920929,1.7000000476837158,4.07775568914086e-06
+2015-12-30 22:00:00,8.300000190734863,399.20001220703125,21.0,100450.0,0.012600000016391277,290.8999938964844,1.0,1.399999976158142,1.6184509790133084e-06
+2015-12-30 23:00:00,3.299999952316284,399.20001220703125,0.0,100520.0,0.01269999984651804,291.1000061035156,1.2000000476837158,1.2000000476837158,6.878141851067213e-07
diff --git a/python/runCalibValid/ngen_cal/tests/data/catchment_data.geojson b/python/runCalibValid/ngen_cal/tests/data/catchment_data.geojson
new file mode 100644
index 00000000..5554259e
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/catchment_data.geojson
@@ -0,0 +1,10 @@
+{
+"type": "FeatureCollection",
+"name": "catchment_data",
+"features": [
+ { "type": "Feature", "properties": { "id": "cat-88", "area_sqkm": 2.4996043350007979, "toid": "nex-92", "realization": "hymod" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -80.851104626927935, 35.28713712710789 ], [ -80.851263208721718, 35.287278638103359 ], [ -80.853061455083264, 35.287700414579497 ], [ -80.854019411292541, 35.288479704100062 ], [ -80.855802256669392, 35.289703368356967 ], [ -80.857251494709189, 35.290105212759258 ], [ -80.85732468908553, 35.290530379655713 ], [ -80.857102318400294, 35.292317284541205 ], [ -80.856577189891865, 35.29258865716946 ], [ -80.855956742626915, 35.293600631387093 ], [ -80.856838091281091, 35.297390482546497 ], [ -80.856231107900527, 35.297702239295575 ], [ -80.855814167913024, 35.298208133960877 ], [ -80.854673881362572, 35.299396835802575 ], [ -80.853394658371428, 35.300056223100952 ], [ -80.854521190266397, 35.301614777010897 ], [ -80.85495367878103, 35.302864745465634 ], [ -80.854289331926068, 35.305271029745214 ], [ -80.854667529640636, 35.305644583965829 ], [ -80.854793530469934, 35.305805091102215 ], [ -80.854594281116263, 35.305906592345202 ], [ -80.854011784567817, 35.306609448568516 ], [ -80.851759248478444, 35.306864970387451 ], [ -80.851267745796008, 35.30737628194921 ], [ -80.850678042676833, 35.308088750968786 ], [ -80.848806913346181, 35.30793780906393 ], [ -80.846290200194801, 35.307486610455292 ], [ -80.841317399626931, 35.308259197854959 ], [ -80.84042534463569, 35.308559286437934 ], [ -80.839938199964493, 35.308375184646742 ], [ -80.83980976939732, 35.307514479925899 ], [ -80.839413253269043, 35.306692935812976 ], [ -80.839466127225577, 35.303842707383218 ], [ -80.838817643559622, 35.303266633276479 ], [ -80.839171132122317, 35.302287990913115 ], [ -80.839192370073306, 35.301786054338685 ], [ -80.839973619816092, 35.301026058475038 ], [ -80.840250986394054, 35.300255954488229 ], [ -80.840274564646435, 35.29971600934384 ], [ -80.840510079681849, 35.299063560496116 ], [ -80.840292769297847, 35.298346083004994 ], [ -80.840020699069285, 35.297784708526002 ], [ -80.840726926026818, 35.296923882843195 ], [ -80.842340967823688, 35.297357819646685 ], [ -80.844031457898652, 35.296077314023542 ], [ -80.844942725391348, 35.295680155152567 ], [ -80.845897851409902, 35.294007196242781 ], [ -80.845914132921749, 35.293042163875199 ], [ -80.846848013251446, 35.290976392425002 ], [ -80.848524594087536, 35.290661181357088 ], [ -80.849107720043023, 35.28944077423003 ], [ -80.85019980090793, 35.287951150922254 ], [ -80.851104626927935, 35.28713712710789 ] ] ] ] } },
+ { "type": "Feature", "properties": { "id": "cat-89", "area_sqkm": 1.415484062777683, "toid": "nex-92", "realization": "tshirt" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -80.836951237220191, 35.288832315806779 ], [ -80.837433292708752, 35.287104697487017 ], [ -80.837755367327347, 35.286493035938896 ], [ -80.838289462420889, 35.286441315592377 ], [ -80.841367792390386, 35.286528773816656 ], [ -80.842317981366804, 35.284893506525727 ], [ -80.843210390851425, 35.28448518011156 ], [ -80.844299636276261, 35.283156323138741 ], [ -80.844120016032321, 35.282552025575363 ], [ -80.843563156496955, 35.282057810716211 ], [ -80.843598108393721, 35.28129006395298 ], [ -80.844899506220685, 35.280058992929078 ], [ -80.84762067794027, 35.279796248008502 ], [ -80.848155274104968, 35.280902962804937 ], [ -80.848336565341938, 35.281499021332522 ], [ -80.849104524542241, 35.283085450007043 ], [ -80.849620648245875, 35.285194909563735 ], [ -80.849937798890593, 35.285477935823828 ], [ -80.851104626927935, 35.28713712710789 ], [ -80.85019980090793, 35.287951150922254 ], [ -80.849107720043023, 35.28944077423003 ], [ -80.848524594087536, 35.290661181357088 ], [ -80.846848013251446, 35.290976392425002 ], [ -80.845914132921749, 35.293042163875199 ], [ -80.845897851409902, 35.294007196242781 ], [ -80.844942725391348, 35.295680155152567 ], [ -80.844031457898652, 35.296077314023542 ], [ -80.842340967823688, 35.297357819646685 ], [ -80.840726926026818, 35.296923882843195 ], [ -80.84061283314432, 35.296756450426138 ], [ -80.83929612731437, 35.295624958601664 ], [ -80.839011882013764, 35.29464841111286 ], [ -80.838688801951392, 35.294368812262512 ], [ -80.838460633213714, 35.294033942557199 ], [ -80.837975655942245, 35.293614494101902 ], [ -80.837448942540377, 35.292837883561639 ], [ -80.835333419519969, 35.292054660163203 ], [ -80.835906434333012, 35.290597374132894 ], [ -80.835924563689318, 35.289477503820358 ], [ -80.836535324576232, 35.289015802269866 ], [ -80.836951237220191, 35.288832315806779 ] ] ] ] } },
+ { "type": "Feature", "properties": { "id": "cat-92", "area_sqkm": 4.4186682694450576, "toid": "nex-94", "realization": "hymod" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -80.85296492168726, 35.264300527759367 ], [ -80.853112602047361, 35.264682270725118 ], [ -80.853104474298135, 35.265856526035748 ], [ -80.853728211090754, 35.266662553358316 ], [ -80.853791056449396, 35.267480980223219 ], [ -80.852777089272195, 35.268620243618415 ], [ -80.853253154182184, 35.269044529679604 ], [ -80.853796224125887, 35.27083319327248 ], [ -80.8543252958832, 35.271928310153974 ], [ -80.854550560992379, 35.27345074669747 ], [ -80.853844188410591, 35.275410279748925 ], [ -80.853800825322409, 35.276380254115644 ], [ -80.854833851942757, 35.27605613782687 ], [ -80.855816389519703, 35.27685792835566 ], [ -80.856130979027071, 35.27789326547299 ], [ -80.856448123493237, 35.278176276146468 ], [ -80.856418346783144, 35.279830973714432 ], [ -80.856682718815762, 35.280378645524955 ], [ -80.856720638031277, 35.282801394110002 ], [ -80.85797355005748, 35.28365957945956 ], [ -80.859376832051382, 35.285652460232527 ], [ -80.859151599731547, 35.286278808850845 ], [ -80.859114374071012, 35.287139455718481 ], [ -80.858559089758828, 35.287680535533291 ], [ -80.85794395385372, 35.289259422426134 ], [ -80.857479898707879, 35.289712763184838 ], [ -80.857251494709189, 35.290105212759258 ], [ -80.855802256669392, 35.289703368356967 ], [ -80.854019411292541, 35.288479704100062 ], [ -80.853061455083264, 35.287700414579497 ], [ -80.851263208721718, 35.287278638103359 ], [ -80.851104626927935, 35.28713712710789 ], [ -80.849937798890593, 35.285477935823828 ], [ -80.849620648245875, 35.285194909563735 ], [ -80.849104524542241, 35.283085450007043 ], [ -80.848336565341938, 35.281499021332522 ], [ -80.848155274104968, 35.280902962804937 ], [ -80.84762067794027, 35.279796248008502 ], [ -80.844899506220685, 35.280058992929078 ], [ -80.843598108393721, 35.28129006395298 ], [ -80.843563156496955, 35.282057810716211 ], [ -80.844120016032321, 35.282552025575363 ], [ -80.844299636276261, 35.283156323138741 ], [ -80.843210390851425, 35.28448518011156 ], [ -80.842317981366804, 35.284893506525727 ], [ -80.841367792390386, 35.286528773816656 ], [ -80.838289462420889, 35.286441315592377 ], [ -80.837755367327347, 35.286493035938896 ], [ -80.8361338573838, 35.286110823349865 ], [ -80.835931967518476, 35.284748530327938 ], [ -80.835392154325845, 35.283893569532751 ], [ -80.835158951192199, 35.283123016573917 ], [ -80.834094760929446, 35.281441021612139 ], [ -80.834168622407276, 35.279738590895057 ], [ -80.834851763425817, 35.278374323992203 ], [ -80.834383889334276, 35.276578394963344 ], [ -80.834784947860612, 35.275468054060966 ], [ -80.834497773513476, 35.275059742146034 ], [ -80.833523941172572, 35.274691476135182 ], [ -80.833289923125079, 35.274360044492084 ], [ -80.832733193040568, 35.273865774730247 ], [ -80.832769603707234, 35.273038770265124 ], [ -80.834811233534282, 35.272054362638272 ], [ -80.83682099581614, 35.271861013278418 ], [ -80.837102293310835, 35.2712039407959 ], [ -80.836922131386061, 35.270062860250349 ], [ -80.836393116304123, 35.268929323690841 ], [ -80.837931814297761, 35.268235925057795 ], [ -80.838721478207717, 35.268155821435457 ], [ -80.838629237997509, 35.267656047116276 ], [ -80.837967135356521, 35.266081096754981 ], [ -80.838098724147329, 35.265198860897669 ], [ -80.838873722412771, 35.263148408292437 ], [ -80.840200724656142, 35.260745380817717 ], [ -80.841062973346411, 35.260736226835775 ], [ -80.842100531914028, 35.26056125076564 ], [ -80.842367130781795, 35.260939430886779 ], [ -80.84328273113708, 35.260966742700944 ], [ -80.8440706317744, 35.262530519539659 ], [ -80.846439361346341, 35.263425261779517 ], [ -80.847792126385727, 35.264058549842439 ], [ -80.848819088514247, 35.263884249606143 ], [ -80.85296492168726, 35.264300527759367 ] ] ] ] } },
+ { "type": "Feature", "properties": { "id": "tst-1", "area_sqkm": 15.617167355002097, "toid": "nex-94" , "realization": "tshirt"}, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -80.840200724656142, 35.260745380817717 ], [ -80.838873722412771, 35.263148408292437 ], [ -80.838098724147329, 35.265198860897669 ], [ -80.837967135356521, 35.266081096754981 ], [ -80.838629237997509, 35.267656047116276 ], [ -80.838721478207717, 35.268155821435457 ], [ -80.837931814297761, 35.268235925057795 ], [ -80.836393116304123, 35.268929323690841 ], [ -80.836922131386061, 35.270062860250349 ], [ -80.837102293310835, 35.2712039407959 ], [ -80.83682099581614, 35.271861013278418 ], [ -80.834811233534282, 35.272054362638272 ], [ -80.832769603707234, 35.273038770265124 ], [ -80.832733193040568, 35.273865774730247 ], [ -80.833289923125079, 35.274360044492084 ], [ -80.833523941172572, 35.274691476135182 ], [ -80.834497773513476, 35.275059742146034 ], [ -80.834784947860612, 35.275468054060966 ], [ -80.834383889334276, 35.276578394963344 ], [ -80.834851763425817, 35.278374323992203 ], [ -80.834168622407276, 35.279738590895057 ], [ -80.834094760929446, 35.281441021612139 ], [ -80.835158951192199, 35.283123016573917 ], [ -80.835392154325845, 35.283893569532751 ], [ -80.835931967518476, 35.284748530327938 ], [ -80.8361338573838, 35.286110823349865 ], [ -80.837755367327347, 35.286493035938896 ], [ -80.837433292708752, 35.287104697487017 ], [ -80.836951237220191, 35.288832315806779 ], [ -80.836535324576232, 35.289015802269866 ], [ -80.835924563689318, 35.289477503820358 ], [ -80.835906434333012, 35.290597374132894 ], [ -80.835333419519969, 35.292054660163203 ], [ -80.837448942540377, 35.292837883561639 ], [ -80.837975655942245, 35.293614494101902 ], [ -80.838460633213714, 35.294033942557199 ], [ -80.838688801951392, 35.294368812262512 ], [ -80.839011882013764, 35.29464841111286 ], [ -80.83929612731437, 35.295624958601664 ], [ -80.84061283314432, 35.296756450426138 ], [ -80.840726926026818, 35.296923882843195 ], [ -80.840020699069285, 35.297784708526002 ], [ -80.840292769297847, 35.298346083004994 ], [ -80.840510079681849, 35.299063560496116 ], [ -80.840274564646435, 35.29971600934384 ], [ -80.840250986394054, 35.300255954488229 ], [ -80.839973619816092, 35.301026058475038 ], [ -80.839192370073306, 35.301786054338685 ], [ -80.839171132122317, 35.302287990913115 ], [ -80.838817643559622, 35.303266633276479 ], [ -80.839466127225577, 35.303842707383218 ], [ -80.839413253269043, 35.306692935812976 ], [ -80.83980976939732, 35.307514479925899 ], [ -80.839938199964493, 35.308375184646742 ], [ -80.84042534463569, 35.308559286437934 ], [ -80.838173317849666, 35.310579372152183 ], [ -80.836967619167396, 35.311500641152215 ], [ -80.834594257093656, 35.313810235058021 ], [ -80.833910370643565, 35.314241346184069 ], [ -80.833518204552192, 35.314451445150333 ], [ -80.832738080860537, 35.314203992799243 ], [ -80.831118511988777, 35.313743611858541 ], [ -80.828978664443667, 35.311709797803765 ], [ -80.826867739921454, 35.310755136462454 ], [ -80.825183581529245, 35.311249519295799 ], [ -80.824489571737374, 35.310586610376255 ], [ -80.823749166770114, 35.309614494646745 ], [ -80.822734108633966, 35.30864504713751 ], [ -80.822363691975909, 35.307521515609118 ], [ -80.82096519219516, 35.307246824111935 ], [ -80.820120474045339, 35.307283514823851 ], [ -80.819456397177348, 35.306259721643151 ], [ -80.819751960125203, 35.305504672385958 ], [ -80.819318391652871, 35.305395608173548 ], [ -80.81897439035518, 35.305391083637751 ], [ -80.817181566018562, 35.304704654632587 ], [ -80.81613914374536, 35.304439915842423 ], [ -80.81550046105329, 35.304433327058561 ], [ -80.813551269005728, 35.302542742102752 ], [ -80.811879220601881, 35.301674296443707 ], [ -80.809590416993316, 35.301691103359232 ], [ -80.80773376901557, 35.301876227803497 ], [ -80.806673633372924, 35.301002407703145 ], [ -80.805370731017021, 35.300987910585143 ], [ -80.80440840264913, 35.30074432158559 ], [ -80.80407208780737, 35.300740749411659 ], [ -80.802953000805459, 35.300438465772643 ], [ -80.802694394313988, 35.30011222659283 ], [ -80.801672143870263, 35.299313263845768 ], [ -80.798839346069897, 35.297786916606235 ], [ -80.796501622530045, 35.294839923428476 ], [ -80.796352026946934, 35.294693161441408 ], [ -80.797013063716804, 35.293811877035317 ], [ -80.79827514700581, 35.292819865116059 ], [ -80.799344190370135, 35.290585126935817 ], [ -80.799865864531867, 35.289872161475628 ], [ -80.800424936416377, 35.288553433248225 ], [ -80.800999565966492, 35.287575826069961 ], [ -80.801644642528231, 35.286049848674438 ], [ -80.802994150786773, 35.284214175356311 ], [ -80.803387347107247, 35.283117645845103 ], [ -80.803586605010764, 35.283016228962545 ], [ -80.804279975172705, 35.281156814930092 ], [ -80.806134861170818, 35.280201663047706 ], [ -80.808732269996199, 35.277073050856899 ], [ -80.810209920767477, 35.275029213450317 ], [ -80.812364186138083, 35.272220387006463 ], [ -80.814614542161735, 35.270126347809637 ], [ -80.814740573356502, 35.269116070867831 ], [ -80.815443344755096, 35.266574815236226 ], [ -80.816921006541605, 35.265199166155284 ], [ -80.817495173470775, 35.264064569072858 ], [ -80.817548002162056, 35.263643031839841 ], [ -80.817841618418484, 35.262582414020166 ], [ -80.81995755042071, 35.260988247188557 ], [ -80.82143336243314, 35.258581449228224 ], [ -80.823913683653544, 35.25595299595917 ], [ -80.826895601462766, 35.255436266943242 ], [ -80.827376964815357, 35.253515464266862 ], [ -80.827652387272337, 35.25167381804598 ], [ -80.82789125678481, 35.25154583682162 ], [ -80.828275864390264, 35.252070919314946 ], [ -80.828883752439793, 35.251305705854463 ], [ -80.832442853064705, 35.251443015783693 ], [ -80.832884118696072, 35.251538290718514 ], [ -80.833436636854245, 35.252290889577438 ], [ -80.834127526193001, 35.252927792263698 ], [ -80.834887423704444, 35.254407494448408 ], [ -80.835158896766401, 35.256131233273109 ], [ -80.835514393985079, 35.256459427254597 ], [ -80.835754296018081, 35.256787405670153 ], [ -80.836627672334103, 35.257592160960733 ], [ -80.837152456244226, 35.259247076509176 ], [ -80.838536127025009, 35.259961128279642 ], [ -80.839388515910656, 35.260516960216215 ], [ -80.840200724656142, 35.260745380817717 ] ] ] ] } }
+]
+}
diff --git a/python/runCalibValid/ngen_cal/tests/data/catchment_edge_list.csv b/python/runCalibValid/ngen_cal/tests/data/catchment_edge_list.csv
new file mode 100644
index 00000000..bb77767b
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/catchment_edge_list.csv
@@ -0,0 +1,8 @@
+"ID","toID"
+"catchment_8895442","nexus_250031932"
+"catchment_8895520","nexus_250031930"
+"catchment_8895396","nexus_250031903"
+"catchment_8895402","nexus_250031930"
+"nexus_250031932","catchment_8895402"
+"nexus_250031930","catchment_8895396"
+"nexus_250031903","catchment_0"
diff --git a/python/runCalibValid/ngen_cal/tests/data/crosswalk.json b/python/runCalibValid/ngen_cal/tests/data/crosswalk.json
new file mode 100644
index 00000000..8b2c71cb
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/crosswalk.json
@@ -0,0 +1,7 @@
+{
+ "tst-1":
+ {
+ "outlet_COMID": "9731248",
+ "Gage_no": ["02146211"]
+ }
+}
diff --git a/python/runCalibValid/ngen_cal/tests/data/example_realization_config.json b/python/runCalibValid/ngen_cal/tests/data/example_realization_config.json
new file mode 100644
index 00000000..06f329e0
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/example_realization_config.json
@@ -0,0 +1,164 @@
+{
+ "global": {
+ "tshirt": {
+ "maxsmc": 0.439,
+ "wltsmc": 0.066,
+ "satdk": 0.00000338,
+ "satpsi": 0.355,
+ "slope": 1.0,
+ "scaled_distribution_fn_shape_parameter": 4.05,
+ "multiplier": 0.0,
+ "alpha_fc": 0.33,
+ "Klf": 0.01,
+ "Kn": 0.03,
+ "nash_n": 2,
+ "Cgw": 0.01,
+ "expon": 6.0,
+ "max_groundwater_storage_meters": 1.0,
+ "nash_storage": [
+ 0.0,
+ 0.0
+ ],
+ "soil_storage_percentage": 0.667,
+ "groundwater_storage_percentage": 0.5,
+ "timestep": 3600
+ },
+ "giuh": {
+ "giuh_path": "./test/data/giuh/GIUH.json",
+ "crosswalk_path": "./data/crosswalk.json"
+ },
+ "forcing": {
+ "file_pattern": ".*{{ID}}.*.csv",
+ "path": "./data/forcing/",
+ "start_time": "2015-12-01 00:00:00",
+ "end_time": "2015-12-30 23:00:00"
+ }
+ },
+ "catchments": {
+ "test-catchment": {
+ "formulations": [
+ {
+ "name": "tshirt",
+ "params": {
+ "some_param": 0.09651470957144681,
+ "maxsmc": 0.439,
+ "wltsmc": 0.066,
+ "satdk": 3.38e-06,
+ "satpsi": 0.355,
+ "slope": 1.0,
+ "scaled_distribution_fn_shape_parameter": 4.05,
+ "multiplier": 0.0,
+ "alpha_fc": 0.33,
+ "Klf": 0.01,
+ "Kn": 0.03,
+ "nash_n": 2,
+ "Cgw": 0.01,
+ "expon": 6.0,
+ "max_groundwater_storage_meters": 1.0,
+ "nash_storage": [
+ 0.0,
+ 0.0
+ ],
+ "soil_storage_percentage": 0.667,
+ "groundwater_storage_percentage": 0.5,
+ "timestep": 3600
+ }
+ }
+ ],
+ "giuh": {
+ "giuh_path": "./test/data/giuh/GIUH.json",
+ "crosswalk_path": "./data/crosswalk.json"
+ },
+ "forcing": {
+ "path": "./python/ngen_cal/test/data/cat-87_2015-12-01 00_00_00_2015-12-30 23_00_00.csv",
+ "start_time": "2015-12-01 00:00:00",
+ "end_time": "2015-12-30 23:00:00"
+ },
+ "calibration": { "params": [
+ {"param": "maxsmc",
+ "min": 0.2,
+ "max": 1.0,
+ "init": 0.439}
+ ]
+ }
+ },
+ "cat-88": {
+ "simple_lumped": {
+ "sr": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "storage": 1.0,
+ "max_storage": 1000.0,
+ "a": 1.0,
+ "b": 10.0,
+ "Ks": 0.1,
+ "Kq": 0.01,
+ "n": 3,
+ "t": 0
+ },
+ "forcing": {
+ "path": "./python/ngen_cal/test/data/cat-88_2015-12-01 00_00_00_2015-12-30 23_00_00.csv",
+ "start_time": "2015-12-01 00:00:00",
+ "end_time": "2015-12-30 23:00:00"
+ }
+ },
+ "cat-89": {
+ "tshirt": {
+ "maxsmc": 0.439,
+ "wltsmc": 0.066,
+ "satdk": 0.00000338,
+ "satpsi": 0.355,
+ "slope": 1.0,
+ "scaled_distribution_fn_shape_parameter": 4.05,
+ "multiplier": 0.0,
+ "alpha_fc": 0.33,
+ "Klf": 0.01,
+ "Kn": 0.03,
+ "nash_n": 2,
+ "Cgw": 0.01,
+ "expon": 6.0,
+ "max_groundwater_storage_meters": 1.0,
+ "nash_storage": [
+ 0.0,
+ 0.0
+ ],
+ "soil_storage_percentage": 0.667,
+ "groundwater_storage_percentage": 0.5,
+ "timestep": 3600
+ },
+ "giuh": {
+ "giuh_path": "./test/data/giuh/GIUH.json",
+ "crosswalk_path": "./data/crosswalk.json"
+ },
+ "forcing": {
+ "path": "./python/ngen_cal/test/data/cat-89_2015-12-01 00_00_00_2015-12-30 23_00_00.csv",
+ "start_time": "2015-12-01 00:00:00",
+ "end_time": "2015-12-30 23:00:00"
+ }
+ },
+ "cat-92": {
+ "simple_lumped": {
+ "sr": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "storage": 1.0,
+ "max_storage": 1000.0,
+ "a": 1.0,
+ "b": 10.0,
+ "Ks": 0.1,
+ "Kq": 0.01,
+ "n": 3,
+ "t": 0
+ },
+ "forcing": {
+ "path": "./python/ngen_cal/test/data/cat-92_2015-12-01 00_00_00_2015-12-30 23_00_00.csv",
+ "start_time": "2015-12-01 00:00:00",
+ "end_time": "2015-12-30 23:00:00"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_cal/tests/data/nexus_data.geojson b/python/runCalibValid/ngen_cal/tests/data/nexus_data.geojson
new file mode 100644
index 00000000..cc28473e
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/nexus_data.geojson
@@ -0,0 +1,8 @@
+{
+"type": "FeatureCollection",
+"name": "nexus_data",
+"features": [
+ { "type": "Feature", "properties": { "id": "nex-94", "toid": "cat-94" }, "geometry": { "type": "Point", "coordinates": [ -80.839973317999977, 35.260912878110311 ] } },
+ { "type": "Feature", "properties": { "id": "nex-92", "toid": "cat-92" }, "geometry": { "type": "Point", "coordinates": [ -80.851219317999949, 35.286910811110019 ] } }
+]
+}
diff --git a/python/runCalibValid/ngen_cal/tests/data/waterbody_data.geojson b/python/runCalibValid/ngen_cal/tests/data/waterbody_data.geojson
new file mode 100644
index 00000000..958cbb55
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/waterbody_data.geojson
@@ -0,0 +1,11 @@
+{
+"type": "FeatureCollection",
+"name": "waterbody_data",
+"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
+"features": [
+ { "type": "Feature", "properties": { "ID": "wat-88", "length_km": 1.643, "slope_percent": 0.0061219, "main_id": 33, "toID": "wat-92", "realized_catchment": "cat-88" }, "geometry": { "type": "LineString", "coordinates": [ [ -80.848198317999959, 35.300537611109924 ], [ -80.848617517999969, 35.299965078109913 ], [ -80.848841317999984, 35.29882001110991 ], [ -80.849539984999979, 35.297926878109926 ], [ -80.85068638499996, 35.294766478109928 ], [ -80.851999585, 35.293690278109956 ], [ -80.852279117999956, 35.293232278109969 ], [ -80.852279317999944, 35.292178678109977 ], [ -80.852167717999976, 35.291789278109995 ], [ -80.85211211799999, 35.290873211109961 ], [ -80.851832984999987, 35.289819611110033 ], [ -80.851163117999988, 35.288422411110048 ], [ -80.851163317999976, 35.287506278110101 ], [ -80.851302984999961, 35.287254278110005 ], [ -80.851219317999949, 35.286910811110019 ] ] } },
+ { "type": "Feature", "properties": { "ID": "wat-89", "length_km": 0.718, "slope_percent": 0.10601113, "main_id": 65, "toID": "wat-92", "realized_catchment": "cat-89" }, "geometry": { "type": "LineString", "coordinates": [ [ -80.844180584999947, 35.286153478110094 ], [ -80.845995984999945, 35.286795211110018 ], [ -80.846750117999989, 35.286795411110042 ], [ -80.847476317999963, 35.28700167811003 ], [ -80.84783931799997, 35.287185011110026 ], [ -80.848425784999975, 35.287803478109993 ], [ -80.84881678499994, 35.287757811110012 ], [ -80.849459517999932, 35.287345611109998 ], [ -80.850493117999974, 35.287025078110084 ], [ -80.851219317999949, 35.286910811110019 ] ] } },
+ { "type": "Feature", "properties": { "ID": "wat-87", "length_km": 7.138, "slope_percent": 0.00579278, "main_id": 1, "toID": "wat-94", "realized_catchment": "cat-87" }, "geometry": { "type": "LineString", "coordinates": [ [ -80.836321584999951, 35.307382611109766 ], [ -80.835874984999975, 35.306764211109801 ], [ -80.835539717999964, 35.306535078109832 ], [ -80.833053317999941, 35.306099011109822 ], [ -80.832718117999946, 35.305938611109895 ], [ -80.83160111799998, 35.304999211109774 ], [ -80.830679317999966, 35.304517811109733 ], [ -80.829478384999945, 35.303601278109838 ], [ -80.829031784999984, 35.302959811109908 ], [ -80.828082184999971, 35.302318278109858 ], [ -80.828082384999959, 35.302020478109895 ], [ -80.828474584999981, 35.300280011109805 ], [ -80.828475117999986, 35.299295078109921 ], [ -80.828223984999966, 35.298859811109899 ], [ -80.827944717999969, 35.298630811109874 ], [ -80.826632117999964, 35.298103611109923 ], [ -80.825793784999973, 35.298400878109902 ], [ -80.825682117999975, 35.298332078109887 ], [ -80.825626384999964, 35.297942811109877 ], [ -80.825347317999956, 35.297415878109923 ], [ -80.825319584999974, 35.297186878109855 ], [ -80.825235784999961, 35.297141078109952 ], [ -80.825236317999952, 35.296316478109972 ], [ -80.82501291799997, 35.296018678109917 ], [ -80.824678117999952, 35.295194011109906 ], [ -80.824510584999985, 35.295102411109951 ], [ -80.824035717999948, 35.29510207810992 ], [ -80.823700917999986, 35.294369078109895 ], [ -80.823227117999977, 35.292628278109994 ], [ -80.822919984999956, 35.292399078109966 ], [ -80.822333517999937, 35.292146878109968 ], [ -80.821383784999981, 35.292100678110067 ], [ -80.821020784999959, 35.291848611109998 ], [ -80.821048984999948, 35.291527878109989 ], [ -80.821132717999944, 35.291436411109892 ], [ -80.821133317999966, 35.290611811109983 ], [ -80.821049584999969, 35.290588878109958 ], [ -80.820937984999958, 35.290337011110033 ], [ -80.820463184999937, 35.290130611110023 ], [ -80.819904984999937, 35.289534878109968 ], [ -80.819681784999943, 35.289168278110012 ], [ -80.819626184999947, 35.288687278109947 ], [ -80.819514717999937, 35.288389478110012 ], [ -80.818900384999949, 35.28799987811 ], [ -80.818956784999955, 35.287312811109963 ], [ -80.819460184999969, 35.28625947811004 ], [ -80.819516517999944, 35.285801478110074 ], [ -80.819098317999973, 35.28461027811003 ], [ -80.819070717999978, 35.284060611110085 ], [ -80.818987184999969, 35.283717011110078 ], [ -80.818428985, 35.282960878109996 ], [ -80.818345517999944, 35.282342478110088 ], [ -80.818625517999976, 35.281495211110069 ], [ -80.818681717999937, 35.28101427811005 ], [ -80.82035851799999, 35.279480478110052 ], [ -80.820945384999959, 35.279022678110124 ], [ -80.821336717999941, 35.278541878110119 ], [ -80.822510384999987, 35.277649211110088 ], [ -80.823040984999977, 35.27760361111018 ], [ -80.823627517999967, 35.277855811110193 ], [ -80.824493184999938, 35.277970678110151 ], [ -80.825611117999983, 35.276711411110149 ], [ -80.825806717999967, 35.276322211110113 ], [ -80.825862917999984, 35.275864011110137 ], [ -80.826142584999957, 35.275108278110181 ], [ -80.826198984999962, 35.274306678110179 ], [ -80.825892117999956, 35.273734011110179 ], [ -80.825864717999949, 35.273001078110163 ], [ -80.826144517999978, 35.272176678110164 ], [ -80.826843317999987, 35.271054678110168 ], [ -80.828296384999987, 35.269360411110185 ], [ -80.828603784999984, 35.269108678110229 ], [ -80.830307717999972, 35.268216011110162 ], [ -80.831285384999958, 35.267849878110219 ], [ -80.832095584999934, 35.267231811110243 ], [ -80.832486784999958, 35.26670507811022 ], [ -80.833688184999986, 35.265606211110253 ], [ -80.834051517999967, 35.265125278110311 ], [ -80.834275317999982, 35.264300878110319 ], [ -80.834526917999938, 35.263865811110307 ], [ -80.834861984999975, 35.263499411110324 ], [ -80.83609111799997, 35.262652411110295 ], [ -80.837403784999935, 35.261988611110297 ], [ -80.839973317999977, 35.260912878110311 ] ] } },
+ { "type": "Feature", "properties": { "ID": "wat-92", "length_km": 3.448, "slope_percent": 0.00735062, "main_id": 33, "toID": "wat-94", "realized_catchment": "cat-92" }, "geometry": { "type": "LineString", "coordinates": [ [ -80.851219317999949, 35.286910811110019 ], [ -80.851582984999951, 35.28500987811006 ], [ -80.851583184999981, 35.284254078109981 ], [ -80.850829784999974, 35.281459678110075 ], [ -80.85080211799999, 35.28068101111009 ], [ -80.850243984999963, 35.279146411110112 ], [ -80.850132517999953, 35.278550811110151 ], [ -80.850048717999982, 35.27848207811013 ], [ -80.849937184999987, 35.277634678110196 ], [ -80.849378917999957, 35.276581011110153 ], [ -80.84904391799995, 35.27623741111023 ], [ -80.848150317999952, 35.275802078110232 ], [ -80.847982784999928, 35.275641678110034 ], [ -80.847955117999959, 35.274977478110088 ], [ -80.848541717999979, 35.274382211110193 ], [ -80.848541917999967, 35.273992811110119 ], [ -80.848262784999974, 35.273603411110166 ], [ -80.847899717999951, 35.273420078110185 ], [ -80.847145584999964, 35.273580278110181 ], [ -80.846224117999952, 35.27328227811023 ], [ -80.84588911799996, 35.272961478110233 ], [ -80.845749517999934, 35.272572078110144 ], [ -80.845526184999983, 35.27234307811019 ], [ -80.845582384999943, 35.271220811110098 ], [ -80.845191517999965, 35.271060411110213 ], [ -80.844269984999983, 35.270991411110245 ], [ -80.844214317999956, 35.270625011110234 ], [ -80.844409784999982, 35.270487611110248 ], [ -80.844521717999953, 35.270235811110169 ], [ -80.844354184999986, 35.269960811110238 ], [ -80.844313717999967, 35.269810811110183 ], [ -80.844353317999946, 35.269580678110259 ], [ -80.843664384999954, 35.26881261111027 ], [ -80.843929517999982, 35.267870211110257 ], [ -80.844075584999985, 35.267739211110225 ], [ -80.844019784999958, 35.267510078110234 ], [ -80.843377917999987, 35.266364811110307 ], [ -80.841144917999941, 35.263844811110246 ], [ -80.840558917999957, 35.262974411110285 ], [ -80.840335984999953, 35.261783211110277 ], [ -80.839973317999977, 35.260912878110311 ] ] } }
+]
+}
diff --git a/python/runCalibValid/ngen_cal/tests/data/waterbody_edge_list.csv b/python/runCalibValid/ngen_cal/tests/data/waterbody_edge_list.csv
new file mode 100644
index 00000000..eede5660
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/data/waterbody_edge_list.csv
@@ -0,0 +1,8 @@
+"ID","toID"
+"waterbody_8895442","nexus_250031932"
+"waterbody_8895520","nexus_250031930"
+"waterbody_8895396","nexus_250031903"
+"waterbody_8895402","nexus_250031930"
+"nexus_250031932","waterbody_8895402"
+"nexus_250031930","waterbody_8895396"
+"nexus_250031903","waterbody_0"
diff --git a/python/runCalibValid/ngen_cal/tests/test_agent.py b/python/runCalibValid/ngen_cal/tests/test_agent.py
new file mode 100644
index 00000000..34f39162
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/test_agent.py
@@ -0,0 +1,30 @@
+import pytest
+import pandas as pd # type: ignore
+import json
+import os
+from pathlib import Path
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from ngen.cal.agent import Agent
+
+"""
+ Test suite for reading and manipulating ngen configration files
+"""
+
+@pytest.mark.usefixtures("agent", "realization_config")
+def test_update_config(agent: 'Agent', realization_config: str) -> None:
+ """
+ Ensure that update config properly updates and serializes the config
+ """
+ i = 0
+ params = pd.DataFrame({"model":"CFE","0":4.2, "param":"some_param"}, index=[0])
+ id = 'tst-1'
+ agent.job.workdir = Path(realization_config).parent
+ agent.update_config(i, params, id)
+ with open(realization_config) as fp:
+ data = json.load(fp)
+ assert data['catchments'][id]['formulations'][0]['params']['model_params']['some_param'] == 4.2
+
+#FIXME expand update unit tests...specifically that optmizing min/max and values
+#is consistent, for example
diff --git a/python/runCalibValid/ngen_cal/tests/test_calibration_catchment.py b/python/runCalibValid/ngen_cal/tests/test_calibration_catchment.py
new file mode 100644
index 00000000..d13ee276
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/test_calibration_catchment.py
@@ -0,0 +1,41 @@
+import pytest
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from ngen.cal.calibration_cathment import CalibrationCatchment
+
+"""
+ Test suite for calibratable_catchment
+"""
+
+@pytest.mark.usefixtures("catchment")
+def test_df(catchment: 'CalibrationCatchment') -> None:
+ """
+ Test the catchments proper construction of the parameter dataframe
+ """
+ assert catchment.df.iloc[0]['param'] == 'some_param'
+ assert catchment.df.iloc[0]['0'] == 0.5
+ assert catchment.df.iloc[0]['min'] == 0.0
+ assert catchment.df.iloc[0]['max'] == 1.0
+
+@pytest.mark.usefixtures("catchment2")
+def test_output(catchment2: 'CalibrationCatchment', monkeypatch) -> None:
+ """
+ Test proper handling of non-existent output
+ """
+ import pandas as pd
+ monkeypatch.setattr(pd, "read_csv", lambda *args, **kwargs: FileNotFoundError())
+ output = catchment2.output
+ assert output == None
+
+@pytest.mark.usefixtures("catchment")
+def test_observed(catchment: 'CalibrationCatchment') -> None:
+ """
+ Test proper handling of non-existent output
+ """
+ catchment.observed = None
+ with pytest.raises(RuntimeError):
+ obs = catchment.observed
+
+#TODO test catchment_set
+#TODO test evaluation_range?
diff --git a/python/runCalibValid/ngen_cal/tests/test_configuration.py b/python/runCalibValid/ngen_cal/tests/test_configuration.py
new file mode 100644
index 00000000..009df7cf
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/test_configuration.py
@@ -0,0 +1,30 @@
+import pytest
+from typing import TYPE_CHECKING, Generator
+
+from .utils import config
+
+if TYPE_CHECKING:
+ from ngen.cal.configuration import Configuration
+"""
+ Test suite for reading and manipulating ngen configration files
+"""
+
+# TODO determmine if any unit tests of General config are appropriate
+# pydantic is thoroughly tested upstream, but it may be a good idea to
+# write some simple tests around the defaults
+# may also want to implment some testing around the Model union/parsing
+
+# @pytest.mark.usefixtures("conf", "realization_config")
+# def test_config_file(conf: 'Configuration', realization_config: str) -> None:
+# """
+# Test configuration property `config_file`
+# """
+# assert conf.config_file == realization_config
+
+# @pytest.mark.usefixtures("conf")
+# def test_catchments(conf: 'Configuration') -> None:
+# """
+# Ensure that only the catchment marked with "calibration" is used in the configuration
+# """
+# assert len(conf.catchments) == 1
+# assert conf.catchments[0].id == 'test-catchment'
diff --git a/python/runCalibValid/ngen_cal/tests/test_model.py b/python/runCalibValid/ngen_cal/tests/test_model.py
new file mode 100644
index 00000000..d43342d5
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/test_model.py
@@ -0,0 +1,72 @@
+import pytest
+import pandas as pd # type: ignore
+import json
+from typing import TYPE_CHECKING
+from ngen.cal.ngen import Ngen
+if TYPE_CHECKING:
+ from ngen.cal.model import EvaluationOptions
+ from pydantic import DirectoryPath
+
+"""
+ Test suite for reading and manipulating ngen configration files
+"""
+
+def test_update(eval: 'EvaluationOptions') -> None:
+ """
+ Test score update function with a worse score
+ """
+ eval._best_score = 0.5
+ i = 1
+ score = 1.0
+ log = False
+ eval.update(i, score, log)
+ assert eval.best_score == 0.5
+ assert eval.best_params == '0'
+
+def test_update_1(eval: 'EvaluationOptions') -> None:
+ """
+ Test score update function with a better score
+ """
+ eval._best_score = 1
+ i = 1
+ score = 0.1
+ log = False
+ eval.update(i, score, log)
+ assert eval.best_score == 0.1
+ assert eval.best_params == '1'
+
+def test_restart(ngen_config: 'Ngen') -> None:
+ """
+ Test restarting from minimal meta, no logs available
+ should "restart" at iteration 0
+ """
+ iteration = ngen_config.restart()
+ assert iteration == 0
+
+def test_restart_1(ngen_config: 'Ngen', eval: 'EvaluationOptions', workdir: 'DirectoryPath') -> None:
+ """
+ Test retarting from serialized logs
+ """
+ eval._best_score = 1
+ ngen_config.adjustables[0]._best_score = 1
+ eval._best_params_iteration = "1"
+ ngen_config.adjustables[0]._best_params = "1"
+ eval.write_param_log_file(2)
+
+ #make sure the catchment param df is saved before trying to restart
+ ngen_config.adjustables[0].check_point(workdir)
+
+ iteration = ngen_config.restart()
+ assert iteration == 3
+ assert ngen_config.adjustables[0].eval_params.best_score == 1
+ assert ngen_config.adjustables[0].eval_params.best_params == '1'
+
+#TODO test calibration_set/uniform
+#TODO test multiple explicit -- test_restart_1 uses explicit but only validates a single catchment
+def test_explicit(explicit_catchments) -> None:
+ """
+ Test that a set of independt, explicity handled catchments operates as intended
+ """
+
+
+ pass
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_cal/tests/test_objectives.py b/python/runCalibValid/ngen_cal/tests/test_objectives.py
new file mode 100644
index 00000000..7c5a6018
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/test_objectives.py
@@ -0,0 +1,73 @@
+import pytest
+from math import inf
+from typing import TYPE_CHECKING
+import pandas as pd # type: ignore
+if TYPE_CHECKING:
+ from pandas import DataFrame
+from ngen.cal.objectives import *
+
+#A data frame of "perfectly simulated" data
+perfect_data = pd.DataFrame({'Simulated_cms':[0,1,2,3,4,5], 'Observed_cms':[0,1,2,3,4,5]})
+under_estimate = pd.DataFrame({'Simulated_cms':[0,0,0,0,0], 'Observed_cms':[1,1,1,1,1]})
+#TODO deal with divide by zero in objectives
+over_estimate = pd.DataFrame({'Simulated_cms':[2,2,2,2,2], 'Observed_cms':[1,1,1,1,1]})
+
+@pytest.mark.parametrize(
+"data, expected",
+[
+ pytest.param(perfect_data, 1.0),
+ pytest.param(under_estimate, -inf),
+ pytest.param(over_estimate, -inf)
+]
+)
+def test_nse(data, expected):
+ result = nash_sutcliffe(data['Observed_cms'], data['Simulated_cms'])
+ assert result == expected
+
+@pytest.mark.parametrize(
+"data, expected",
+[
+ pytest.param(perfect_data, 1.0),
+ pytest.param(under_estimate, 0.0),
+ pytest.param(over_estimate, 0)
+]
+)
+def test_nnse(data, expected):
+ result = normalized_nash_sutcliffe(data['Observed_cms'], data['Simulated_cms'])
+ assert result == expected
+
+@pytest.mark.parametrize(
+"data, expected",
+[
+ pytest.param(perfect_data, 0.0),
+ pytest.param(under_estimate, -1.0),
+ pytest.param(over_estimate, 1.0)
+]
+)
+def test_peak(data, expected):
+ result = peak_error_single(data['Observed_cms'], data['Simulated_cms'])
+ assert result == expected
+
+@pytest.mark.parametrize(
+"data, expected",
+[
+ pytest.param(perfect_data, 0.0),
+ pytest.param(under_estimate, -1.0),
+ pytest.param(over_estimate, 1.0)
+]
+)
+def test_volume(data, expected):
+ result = volume_error(data['Observed_cms'], data['Simulated_cms'])
+ assert result == expected
+
+@pytest.mark.parametrize(
+"data, expected",
+[
+ pytest.param(perfect_data, 0.0),
+ pytest.param(under_estimate, 1.0),
+ pytest.param(over_estimate, 1.0)
+]
+)
+def test_custom(data, expected):
+ result = custom(data['Observed_cms'], data['Simulated_cms'])
+ assert result == expected
diff --git a/python/runCalibValid/ngen_cal/tests/test_search.py b/python/runCalibValid/ngen_cal/tests/test_search.py
new file mode 100644
index 00000000..b8e26514
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/test_search.py
@@ -0,0 +1,22 @@
+import pytest
+from typing import TYPE_CHECKING
+
+from ngen.cal.search import dds
+
+if TYPE_CHECKING:
+ from ngen.cal.meta import CalibrationMeta
+ from ngen.cal.calibration_cathment import CalibrationCatchment
+ from ngen.cal.agent import Agent
+
+"""
+ Test suite for calibrtion search algorithms
+"""
+
+@pytest.mark.usefixtures("catchment", "agent")
+def test_dds(catchment: 'CalibrationCatchment', agent: 'Agent') -> None:
+ """
+ Test dds is callable
+ """
+ ret = dds(1, 2, catchment, agent)
+ assert catchment.best_score == 0.0
+ assert catchment.best_params == '2'
diff --git a/python/runCalibValid/ngen_cal/tests/utils.py b/python/runCalibValid/ngen_cal/tests/utils.py
new file mode 100644
index 00000000..619434f8
--- /dev/null
+++ b/python/runCalibValid/ngen_cal/tests/utils.py
@@ -0,0 +1,151 @@
+from pathlib import Path
+_where = str(Path(__file__).parent)
+global_config = {
+ "global": {
+ "formulations": [
+ {
+ "name": "bmi_c",
+ "params": {
+ "name": "bmi_c",
+ "model_type_name": "CFE",
+ "main_output_variable": "Q_OUT",
+ "init_config": "/Users/nels.frazier/workspace/ngen//data/bmi/c/cfe/cat-27_bmi_config.ini",
+ "allow_exceed_end_time": False,
+ "fixed_time_step": False,
+ "uses_forcing_file": False,
+ "variables_names_map": {
+ "atmosphere_water__liquid_equivalent_precipitation_rate": "precip_rate",
+ "water_potential_evaporation_flux": "potential_evapotranspiration",
+ "atmosphere_air_water~vapor__relative_saturation": "SPFH_2maboveground",
+ "land_surface_air__temperature": "TMP_2maboveground",
+ "land_surface_wind__x_component_of_velocity": "UGRD_10maboveground",
+ "land_surface_wind__y_component_of_velocity": "VGRD_10maboveground",
+ "land_surface_radiation~incoming~longwave__energy_flux": "DLWRF_surface",
+ "land_surface_radiation~incoming~shortwave__energy_flux": "DSWRF_surface",
+ "land_surface_air__pressure": "PRES_surface"
+ },
+ "model_params": {
+ "maxsmc": 0.21470105463393196,
+ "satdk": 0.0003343056064723208,
+ "slope": 0.5836411296916055,
+ "multiplier": 465.8926732378259,
+ "expon": 7.813285220525254
+ },
+ "library_file": "/Users/nels.frazier/workspace/ngen/extern/cfe/cmake_build/libcfebmi.dylib",
+ "registration_function": "register_bmi_cfe"
+ }
+ }
+ ],
+ "forcing": {
+ #FIXME regex not working???
+ #"file_pattern": ".*{{ID}}.*csv",
+ "path":_where+"/data/cat-87_2015-12-01 00_00_00_2015-12-30 23_00_00.csv",
+ "start_time": "2015-12-01 00:00:00",
+ "end_time": "2015-12-30 23:00:00"
+ }
+ }
+}
+
+time = {
+ "time": {
+ "start_time": "2015-12-01 00:00:00",
+ "end_time": "2015-12-30 23:00:00",
+ "output_interval": 3600
+ }
+}
+
+catchment = {
+ "tst-1": {
+ "formulations": [
+ {
+ "name": "bmi_c",
+ "params": {
+ "name": "bmi_c",
+ "model_type_name": "CFE",
+ "main_output_variable": "Q_OUT",
+ "init_config": "/Users/nels.frazier/workspace/ngen//data/bmi/c/cfe/cat-27_bmi_config.ini",
+ "allow_exceed_end_time": False,
+ "fixed_time_step": False,
+ "uses_forcing_file": False,
+ "variables_names_map": {
+ "atmosphere_water__liquid_equivalent_precipitation_rate": "precip_rate",
+ "water_potential_evaporation_flux": "potential_evapotranspiration",
+ "atmosphere_air_water~vapor__relative_saturation": "SPFH_2maboveground",
+ "land_surface_air__temperature": "TMP_2maboveground",
+ "land_surface_wind__x_component_of_velocity": "UGRD_10maboveground",
+ "land_surface_wind__y_component_of_velocity": "VGRD_10maboveground",
+ "land_surface_radiation~incoming~longwave__energy_flux": "DLWRF_surface",
+ "land_surface_radiation~incoming~shortwave__energy_flux": "DSWRF_surface",
+ "land_surface_air__pressure": "PRES_surface"
+ },
+ "model_params": {
+ "maxsmc": 0.21470105463393196,
+ "satdk": 0.0003343056064723208,
+ "slope": 0.5836411296916055,
+ "multiplier": 465.8926732378259,
+ "expon": 7.813285220525254
+ },
+ "library_file": "/Users/nels.frazier/workspace/ngen/extern/cfe/cmake_build/libcfebmi.dylib",
+ "registration_function": "register_bmi_cfe"
+ }
+ }
+ ],
+ "forcing": {
+ "path": _where+"/data/cat-87_2015-12-01 00_00_00_2015-12-30 23_00_00.csv",
+ "start_time": "2015-12-01 00:00:00",
+ "end_time": "2015-12-30 23:00:00"
+ },
+ "calibration": {"CFE": [
+ {
+ "param": "some_param",
+ "min": 0.0,
+ "max": 1.0,
+ "init": 0.5
+ },
+ {
+ "param": "maxsmc",
+ "min": 0.2,
+ "max": 1.0,
+ "init": 0.439
+ }
+ ]}
+ }
+}
+
+
+one_catchment = {
+ "catchments": {**catchment}
+}
+
+two_catchment = {
+ "catchments": {**catchment, **catchment}
+}
+
+config = {**global_config, **time, **one_catchment}
+
+algorithm_good = {"algorithm": "dds"}
+algorithm_bad = {"algorithm": "foo"}
+
+strategy_estimation = {"type": "estimation", **algorithm_good}
+strategy_sensitivity = {"type": "sensitivity"}
+
+general_no_defaults = {"strategy":strategy_estimation,
+ "iterations": 10,
+ "restart": True,
+ "start_iteration": 5,
+ "workdir": "/tmp",
+ "log_file": "test_log",
+ "parameter_log_file": "test_param_log",
+ "objectective_log_file": "test_obj_log"}
+
+general_w_defaults = {"strategy":strategy_estimation,
+ "iterations": 10,
+ "evaluation_start": "2015-12-01 00:00:00",
+ "evaluation_stop": "2015-12-30 23:00:00"}
+
+evaluation_options = {"eval_params":{
+ "evaluation_start": "2015-12-01 00:00:00",
+ "evaluation_stop": "2015-12-30 23:00:00"}
+ }
+
+model_params = {"binary":"echo", "args":"ngen args", **evaluation_options}
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_conf/CONTRIBUTING.md b/python/runCalibValid/ngen_conf/CONTRIBUTING.md
new file mode 100644
index 00000000..0f109b26
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/CONTRIBUTING.md
@@ -0,0 +1,32 @@
+# Guidance on how to contribute
+
+> All contributions to this project will be released to the public domain.
+> By submitting a pull request or filing a bug, issue, or
+> feature request, you are agreeing to comply with this waiver of copyright interest.
+> Details can be found in our [TERMS](TERMS.md) and [LICENSE](LICENSE).
+
+
+There are two primary ways to help:
+ - Using the issue tracker, and
+ - Changing the code-base.
+
+
+## Using the issue tracker
+
+Use the issue tracker to suggest feature requests, report bugs, and ask questions.
+This is also a great way to connect with the developers of the project as well
+as others who are interested in this solution.
+
+Use the issue tracker to find ways to contribute. Find a bug or a feature, mention in
+the issue that you will take on that effort, then follow the _Changing the code-base_
+guidance below.
+
+
+## Changing the code-base
+
+Generally speaking, you should fork this repository, make changes in your
+own fork, and then submit a pull request. All new code should have associated
+unit tests that validate implemented features and the presence or lack of defects.
+Additionally, the code should follow any stylistic and architectural guidelines
+prescribed by the project. In the absence of such guidelines, mimic the styles
+and patterns in the existing code-base.
diff --git a/python/runCalibValid/ngen_conf/LICENSE b/python/runCalibValid/ngen_conf/LICENSE
new file mode 100644
index 00000000..a0230332
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/LICENSE
@@ -0,0 +1,7 @@
+“Software code created by U.S. Government employees is not subject to copyright
+in the United States (17 U.S.C. §105). The United States/Department of Commerce
+reserve all rights to seek and obtain copyright protection in countries other
+than the United States for Software authored in its entirety by the Department
+of Commerce. To this end, the Department of Commerce hereby grants to Recipient
+a royalty-free, nonexclusive license to use, copy, and create derivative works
+of the Software outside of the United States.”
diff --git a/python/runCalibValid/ngen_conf/MANIFEST.in b/python/runCalibValid/ngen_conf/MANIFEST.in
new file mode 100644
index 00000000..cc0d1164
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/MANIFEST.in
@@ -0,0 +1 @@
+include LICENSE
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_conf/README.md b/python/runCalibValid/ngen_conf/README.md
new file mode 100644
index 00000000..c3a7ae03
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/README.md
@@ -0,0 +1,8 @@
+## ngen.config package
+
+ This package parses and validates the configurations of different NextGen model formulations for calibration or validation simulations. It is based on an earlier version of [ngen.config](https://github.com/NOAA-OWP/ngen-cal/tree/master/python/ngen_conf) with inclusion of the following model and model component:
+
+- Lumped Arid/Semi-arid Model (LASAM)
+- soil freeze-thaw model (SFT)
+- soil moisture profiles (SMP)
+
diff --git a/python/runCalibValid/ngen_conf/SECURITY.md b/python/runCalibValid/ngen_conf/SECURITY.md
new file mode 100644
index 00000000..0cdd1d99
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/SECURITY.md
@@ -0,0 +1,27 @@
+# Security Policy
+
+There MUST be no unpatched vulnerabilities of medium or higher severity that have been publicly known for more than 60 days.
+
+The vulnerability must be patched and released by the project itself (patches may be developed elsewhere). A vulnerability becomes publicly known (for this purpose) once it has a CVE with publicly released non-paywalled information (reported, for example, in the National Vulnerability Database) or when the project has been informed and the information has been released to the public (possibly by the project). A vulnerability is considered medium or higher severity if its Common Vulnerability Scoring System (CVSS) base qualitative score is medium or higher. In CVSS versions 2.0 through 3.1, this is equivalent to a CVSS score of 4.0 or higher. Projects may use the CVSS score as published in a widely-used vulnerability database (such as the National Vulnerability Database) using the most-recent version of CVSS reported in that database. Projects may instead calculate the severity themselves using the latest version of CVSS at the time of the vulnerability disclosure, if the calculation inputs are publicly revealed once the vulnerability is publicly known. Note: this means that users might be left vulnerable to all attackers worldwide for up to 60 days. This criterion is often much easier to meet than what Google recommends in Rebooting responsible disclosure, because Google recommends that the 60-day period start when the project is notified _even_ if the report is not public. Also note that this badge criterion, like other criteria, applies to the individual project. Some projects are part of larger umbrella organizations or larger projects, possibly in multiple layers, and many projects feed their results to other organizations and projects as part of a potentially-complex supply chain. An individual project often cannot control the rest, but an individual project can work to release a vulnerability patch in a timely way. Therefore, we focus solely on the individual project's response time. Once a patch is available from the individual project, others can determine how to deal with the patch (e.g., they can update to the newer version or they can apply just the patch as a cherry-picked solution).
+
+The public repositories MUST NOT leak any valid private credential (e.g., a working password or private key) that is intended to limit public access.
+
+## Supported Versions
+
+Use this section to tell people about which versions of your project are
+currently being supported with security updates.
+
+| Version | Supported |
+| ------- | ------------------ |
+| 5.1.x | :white_check_mark: |
+| 5.0.x | :x: |
+| 4.0.x | :white_check_mark: |
+| < 4.0 | :x: |
+
+## Reporting a Vulnerability
+
+Use this section to tell people how to report a vulnerability.
+
+Tell them where to go, how often they can expect to get an update on a
+reported vulnerability, what to expect if the vulnerability is accepted or
+declined, etc.
diff --git a/python/runCalibValid/ngen_conf/TERMS.md b/python/runCalibValid/ngen_conf/TERMS.md
new file mode 100644
index 00000000..b49b176b
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/TERMS.md
@@ -0,0 +1,19 @@
+## Disclaimer
+
+This repository is a scientific product and is not official communication of the National Oceanic and Atmospheric Administration, or the United States Department of Commerce. All NOAA GitHub project code is provided on an 'as is' basis and the user assumes responsibility for its use. Any claims against the Department of Commerce or Department of Commerce bureaus stemming from the use of this GitHub project will be governed by all applicable Federal law. Any reference to specific commercial products, processes, or services by service mark, trademark, manufacturer, or otherwise, does not constitute or imply their endorsement, recommendation or favoring by the Department of Commerce. The Department of Commerce seal and logo, or the seal and logo of a DOC bureau, shall not be used in any manner to imply endorsement of any commercial product or activity by DOC or the United States Government.
+
+[NOAA GitHub Policy](https://github.com/NOAAGov/Information)
+
+### Other Information
+
+Unless expressly stated otherwise, the person who associated a work with
+this deed makes no warranties about the work, and disclaims liability for
+all uses of the work, to the fullest extent permitted by applicable law.
+When using or citing the work, you should not imply endorsement by the
+author or the affirmer.
+
+## Exceptions
+
+_Source code or other assets that are excluded from the TERMS should be listed
+here. These may include dependencies that may be licensed differently or are
+not in the public domain._
diff --git a/python/runCalibValid/ngen_conf/changelog.md b/python/runCalibValid/ngen_conf/changelog.md
new file mode 100644
index 00000000..70ea4884
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/changelog.md
@@ -0,0 +1,4 @@
+# Version 0.1.2
+- Better path/pattern handling
+- `resolve_paths` function added to resolve potential relative paths into absolute paths if needed
+- Fix unit test path for `test_cfe_sloth`
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_conf/pyproject.toml b/python/runCalibValid/ngen_conf/pyproject.toml
new file mode 100644
index 00000000..ebeac06e
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/pyproject.toml
@@ -0,0 +1,6 @@
+[build-system]
+build-backend = "setuptools.build_meta"
+requires = [
+ "setuptools>=42",
+ "wheel",
+]
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_conf/setup.cfg b/python/runCalibValid/ngen_conf/setup.cfg
new file mode 100644
index 00000000..f1067045
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/setup.cfg
@@ -0,0 +1,41 @@
+[metadata]
+name = ngen.config
+version = attr: ngen.config._version.__version__
+author =
+ Nels J. Frazier
+ Xia Feng
+author_email =
+ nels.frazier@noaa.gov
+ xia.fen@noaa.gov
+description = A library to parse and validate realization configuration file
+long_description = file: README.md
+long_description_content_type = text/markdown
+license = USDOC
+license_files = LICENSE
+url = https://github.com/NOAA-OWP/NextGen_Model_Calibration/tree/master/python/runCalibValid/ngen_conf
+classifiers =
+ Development Status :: 3 - Alpha
+ Intended Audience :: Education
+ Intended Audience :: Science/Research
+ License :: Free To Use But Restricted
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: 3.8
+ Programming Language :: Python :: 3.9
+ Topic :: Scientific/Engineering :: Hydrology
+ Operating System :: OS Independent
+
+[options]
+packages = find_namespace:
+package_dir =
+ = src
+install_requires =
+ pydantic
+python_requires = >=3.7
+include_package_data = True
+
+[options.packages.find]
+where = src
+
+[options.extras_require]
+develop =
+ pytest
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/__init__.py b/python/runCalibValid/ngen_conf/src/ngen/config/__init__.py
new file mode 100644
index 00000000..9bf15601
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/__init__.py
@@ -0,0 +1,9 @@
+from ._version import __version__
+
+# Monkey patch some types required to support python 3.7
+try:
+ from typing import Literal
+except ImportError:
+ import typing
+ from typing_extensions import Literal
+ typing.Literal = Literal
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/_version.py b/python/runCalibValid/ngen_conf/src/ngen/config/_version.py
new file mode 100644
index 00000000..0404d810
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/_version.py
@@ -0,0 +1 @@
+__version__ = '0.3.0'
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/all_formulations.py b/python/runCalibValid/ngen_conf/src/ngen/config/all_formulations.py
new file mode 100644
index 00000000..dcb50844
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/all_formulations.py
@@ -0,0 +1,20 @@
+from typing import Union
+
+from .cfe import CFE
+from .pet import PET
+from .lstm import LSTM
+from .noahowp import NoahOWP
+from .multi import MultiBMI
+from .topmod import Topmod
+from .sloth import SLOTH
+from .sft import SFT
+from .smp import SMP
+from .lasam import LASAM
+
+
+#NOTE the order of this union is important for validation
+#unless the model class is using smart_union!
+KnownFormulations = Union[Topmod, CFE, PET, NoahOWP, LSTM, SLOTH, MultiBMI, SFT, SMP, LASAM]
+
+#See notes in multi.py and formulation.py about the recursive
+#type of MultiBMI modules and how the forward_refs are handled.
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/bmi_formulation.py b/python/runCalibValid/ngen_conf/src/ngen/config/bmi_formulation.py
new file mode 100644
index 00000000..a78631b9
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/bmi_formulation.py
@@ -0,0 +1,226 @@
+from pydantic import BaseModel, FilePath, DirectoryPath, PyObject, Field, root_validator, validator
+from typing import Mapping, Optional, Union, Sequence, Any
+from pathlib import Path
+from sys import platform
+
+import logging
+logger = logging.getLogger('bmi_formulation')
+logger.addHandler(logging.StreamHandler())
+logger.setLevel(logging.INFO)
+
+class BMIParams(BaseModel, smart_union=True, allow_population_by_field_name = True):
+ """The base of all BMI paramterized ngen model configurations.
+
+ This class holds the common configuiration requirements for general BMI models
+ used in by the ngen model framework.
+
+ The class args here set configuration options of the BaseModel meta class.
+
+ smart_union (bool):
+ Use smart_union capabilities https://pydantic-docs.helpmanual.io/usage/model_config/#smart-union
+
+ allow_population_by_field_name (bool):
+ Initialize the allow_population_by_field_name config of the BaseModel meta class.
+ Allows objects to be created with keyword args which match the python class attribute
+ names or the field name/alias
+ https://pydantic-docs.helpmanual.io/usage/model_config/#:~:text=default%3A%20False)-,allow_population_by_field_name,-whether%20an%20aliased
+ """
+
+ #required fields
+ name: str
+ model_name: str = Field(alias='model_type_name')
+ main_output_variable: str
+ config: Union[Path] = Field(alias='init_config') #Bmi config, can be a file or a str pattern
+
+ #reasonable defaultable fields
+ allow_exceed_end_time: bool = False
+ fixed_time_step: bool = False
+ uses_forcing_file: bool = False
+ name_map: Mapping[str, str] = Field(None, alias='variables_names_map')
+
+ #strictly optional fields (null/none) by default
+ output_vars: Optional[Sequence[str]] = Field(None, alias="output_variables")
+ output_headers: Optional[Sequence[str]] = Field(None, alias="output_header_fields")
+ model_params: Optional[Mapping[str, str]]
+
+ #non exposed fields, derived from fields and used to build up and validate certain components
+ #such as configuration path/file
+ _config_prefix: Optional[DirectoryPath] = Field(default=None, alias="config_prefix")
+ _output_map: Optional[Mapping[str, str]] = Field(None, alias="output_map")
+
+ def resolve_paths(self):
+ """_summary_
+
+ Returns:
+ _type_: _description_
+ """
+ if(isinstance(self.config, Path)):
+ #Not sure why this is needed, but I found one case
+ #where a forumulation has an empty string config...
+ self.config = self.config.resolve()
+
+ @root_validator(pre=True)
+ def validate_output_fields(cls, values):
+ """Build the output_vars and output_headers from a mapping type if provided.
+
+ Since this is a pre validator, this will apply before any other validation happens
+ so the output fields will get further validated once set here.
+
+ Args:
+ values (dict): The values being used to initialize the class.
+
+ Returns:
+ dict: The values dict with `output_headers` and `output_vars` set from `output_map` if provided.
+ """
+ output_map = values.get("output_map", {})
+ output_headers = values.get("output_headers", [])
+ output_vars = values.get("output_vars", [])
+ if output_map:
+ if output_vars:
+ logger.info("BMIParams provided output map and output variables list. List values will be ignored")
+ output_vars = []
+ output_headers = []
+ for k,v in output_map.items():
+ output_vars.append(k)
+ if v != '':
+ output_headers.append(v)
+ else:
+ output_headers.append(k)
+ values['output_vars'] = output_vars
+ values['output_headers'] = output_headers
+ return values
+
+ @validator("name_map", always=True, pre=True)
+ def update_name_map(cls, name_map: Mapping[str, str]) -> Mapping[str, str]:
+ """Update any default name map, ensuring the provided keys are overridden by the given `name_map`.
+
+ If `name_map` contains keys that exist in the default name map, the default mapping gets
+ updated by the values in `name_map`. If the default keys are not in `name_map` then they
+ will exist in the objects `variables_names_map` alongside the mappings in `name_map`
+
+ This validator runs "always", even if the class isn't provided a `name_map` argument.
+ It also runs prior to other validation, so the name_map is still subject to validating
+ as a Mapping[str, str].
+
+ Args:
+ name_map (Mapping[str, str]): The desired name mapping.
+
+ Returns:
+ Mapping[str, str]: The default name map updated with key/value pairs in `name_map`
+ """
+ if hasattr(cls, "_variable_names_map"):
+ if name_map:
+ #need to copy here or we end up overwriting the class attribute for the
+ #life of the interperter...not really the indended semantics...
+ names = cls._variable_names_map.copy()
+ names.update(name_map)
+ return names
+ return cls._variable_names_map
+ return name_map
+
+
+ @root_validator(pre=True)
+ def build_config_path(cls, values: Mapping[str, Any]):
+ """Build a complete path for the init_config file if a prefix is provided.
+
+ Join the `config_prefix` and the `config` fields to make complete path for `config`.
+ If no `config_prefix` is provided to the class, then `config` is left unchanged.
+
+ Args:
+ values (Mapping[str, Any]): All attributes being assigned to this class
+
+ Returns:
+ Mapping[str, Any]: Attributes to assign to the class, with a (possibly) modified `config` attribute
+ """
+ prefix = values.get('config_prefix')
+ if prefix:
+ values['config'] = prefix.joinpath(values['config'])
+ conf_str = str(values['config'])
+ #not the most efficient...but need to know if we need to type cast to a str
+ #or look for a filepath
+ if "{{" in conf_str and "}}" in conf_str:
+ values['config'] = conf_str
+ return values
+
+ @classmethod
+ def get_system_lib_extension(cls) -> str:
+ """Detect and return the dynamic library extension for the current platformm
+
+ Returns:
+ str: The dynamic library extension used on the system (.so for `linux`, .dylib for `darwin`)
+ """
+ if platform == "linux":
+ return '.so'
+ elif platform == "darwin":
+ return '.dylib'
+
+class BMILib(BMIParams):
+ """Intermidiate type for BMI parameters requiring library files
+ """
+ #required
+ #try file path first, otherwise use str and find extension
+ library: Path = Field(alias="library_file")
+ #optional
+ _library_prefix: Optional[DirectoryPath] = Field(None, alias="library_prefix")
+
+ def resolve_paths(self):
+ super().resolve_paths()
+ self.library = self.library.resolve()
+
+ @root_validator(pre=True)
+ def build_library_path(cls, values: Mapping[str, Any]) -> Mapping[str, Any]:
+ """Build a complete path for the library file if a prefix is provided.
+
+ Join the `library_prefix` and the `library` fields to make complete path for `library`.
+ If no `library_prefix` is provided to the class, then `library` is left unchanged.
+
+ Additionally, this method will change the library suffix based on the detectable platform.
+ On `linux`, the library suffix will be `.so`
+ on `darwin`, the library suffix will be `.dylib`
+
+ Args:
+ values (Mapping[str, Any]): All attributes being assigned to this class
+
+ Returns:
+ Mapping[str, Any]: Attributes to assign to the class, with a (possibly) modified `library` attribute
+ """
+ lib_path = values.get('library_prefix')
+ lib = values.get('library') or values.get('library_file')
+ if lib_path:
+ lib = lib_path.joinpath(lib)
+ values['library'] = Path(lib).with_suffix( cls.get_system_lib_extension() )
+ return values
+
+class BMIC(BMILib):
+ """Intermediate type for BMI C library configurations
+ This class adds a `registration_function` requirement,
+ as well as fixes the `name` of the `BMIParams` attribute to a constant, `bmi_c`
+ for all subclasses
+ """
+ registration_function: str
+ name = Field("bmi_c", const=True)
+
+class BMIFortran(BMILib):
+ """Interrmediate type for BMI Fortran library configurations
+ This class fixes the `name` of the `BMIParams` attribute to a constant, `bmi_fortran`
+ for all subclasses
+ """
+ name:str = Field("bmi_fortran", const=True)
+
+class BMIPython(BMIParams):
+ """Intermediate type for BMI Python library configurations
+ This class adds a `python_type` requirement,
+ as well as fixes the `name` of the `BMIParams` attribute to a constant, `bmi_python`
+ for all subclasses
+ """
+ python_type: Union[PyObject, str]
+ name: str = Field("bmi_python", const=True)
+
+class BMICxx(BMILib):
+ """Intermediate type for BMI C++ library configurations
+ This class adds a `registration_function` requirement,
+ as well as fixes the `name` of the `BMIParams` attribute to a constant, `bmi_c++`
+ for all subclasses
+ """
+ registration_function: str
+ name: str = Field("bmi_c++", const=True)
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/cfe.py b/python/runCalibValid/ngen_conf/src/ngen/config/cfe.py
new file mode 100644
index 00000000..13efe1b8
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/cfe.py
@@ -0,0 +1,31 @@
+from typing import Optional
+from pydantic import BaseModel, Field
+
+from .bmi_formulation import BMIC
+
+class CFEParams(BaseModel):
+ """Class for validating CFE Parameters
+ """
+ maxsmc: Optional[float]
+ satdk: Optional[float]
+ slope: Optional[float]
+ bb: Optional[float]
+ multiplier: Optional[float]
+ expon: Optional[float]
+
+class CFE(BMIC):
+ """A BMIC implementation for the CFE ngen module
+ """
+ model_params: Optional[CFEParams]
+ main_output_variable: str = 'Q_OUT'
+ registration_function: str = "register_bmi_cfe"
+ #NOTE aliases don't propagate to subclasses, so we have to repeat the alias
+ model_name: str = Field("CFE", const=True, alias="model_type_name")
+
+ #can set some default name map entries...will be overridden at construction
+ #if a name_map with the same key is passed in, otherwise the name_map
+ #will also include these mappings
+ _variable_names_map = {
+ #"water_potential_evaporation_flux": "EVAPOTRANS",
+ "atmosphere_water__liquid_equivalent_precipitation_rate": "QINSUR"
+ }
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/configurations.py b/python/runCalibValid/ngen_conf/src/ngen/config/configurations.py
new file mode 100644
index 00000000..b05554a8
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/configurations.py
@@ -0,0 +1,64 @@
+from enum import Enum
+from datetime import datetime
+from pydantic import BaseModel, DirectoryPath, FilePath, conint, Field
+from typing import Union, Optional
+from pathlib import Path
+
+PosInt = conint(gt=0)
+
+class Forcing(BaseModel, smart_union=True):
+ """Model for ngen forcing component inputs
+ """
+
+ class Provider(str, Enum):
+ """Enumeration of the supported NGEN forcing provider strings
+ """
+ CSV = "CsvPerFeature"
+ NetCDF = "NetCDF"
+
+ #required
+ file_pattern: Optional[Union[FilePath, str]]
+ path: Union[DirectoryPath, FilePath]
+ #reasonable? default
+ provider: Provider = Field(Provider.CSV)
+
+ def resolve_paths(self):
+ if isinstance(self.file_pattern, Path):
+ self.file_pattern = self.file_pattern.resolve()
+ self.path = self.path.resolve()
+
+class Time(BaseModel):
+ """Model for ngen time configuraiton components
+ """
+ #required
+ start_time: datetime
+ end_time: datetime
+ #reasonable default (defacto, actually???)
+ output_interval: PosInt = 3600
+
+ #FIXME https://github.com/samuelcolvin/pydantic/issues/2277
+ #Until 1.10, it looks like nested encoder config doesn't apply
+ #so you have to define the encoder at the top level object that
+ #will be serialized...
+ class Config:
+ #override how datetime format looks in .json()
+ json_encoders = {
+ datetime: lambda v: v.strftime("%Y-%m-%d %H:%M:%S")
+ }
+
+class Routing(BaseModel):
+ """Model for ngen routing configuration information
+ """
+ #required
+ config: FilePath = Field(alias='t_route_config_file_with_path')
+ #optional/not used TODO make default None?
+ path: Optional[str] = Field('', alias='t_route_connection_path') #TODO deprecate this field?
+
+ def resolve_paths(self):
+ self.config = self.config.resolve()
+
+ def dict(self, **kwargs):
+ #Can override the `dict` call so we ALWAYS `use_aliases` when this model
+ #is serialized
+ kwargs.setdefault('by_alias', True)
+ return super().dict(**kwargs)
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/formulation.py b/python/runCalibValid/ngen_conf/src/ngen/config/formulation.py
new file mode 100644
index 00000000..f91257ce
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/formulation.py
@@ -0,0 +1,20 @@
+from pydantic import BaseModel, Field
+
+class Formulation(BaseModel, smart_union=True):
+ """Model of an ngen formulation
+ """
+ #TODO make this an enum?
+ name: str
+ params: "KnownFormulations" = Field(descriminator="model_name")
+
+ def resolve_paths(self):
+ self.params.resolve_paths()
+
+#NOTE To avoid circular import and support recrusive modules
+#note that `params` is one of KnownFormulations,
+#of which MultiBMI may be one of those.
+#A MultiBMI has a sequence of Formulation objects, making a recursive type
+# So we defer type cheking and importing the KnownFormulations until after
+#MultiBMI is defined, then update_forward_refs()
+from .all_formulations import KnownFormulations
+Formulation.update_forward_refs()
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/lasam.py b/python/runCalibValid/ngen_conf/src/ngen/config/lasam.py
new file mode 100644
index 00000000..193eeff8
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/lasam.py
@@ -0,0 +1,23 @@
+from pydantic import BaseModel, Field
+from typing import Optional, Mapping
+
+from .bmi_formulation import BMICxx
+
+
+class LASAMParams(BaseModel):
+ """Class for validating LASAM Parameters
+ """
+ pass
+
+class LASAM(BMICxx):
+ """A BMIC++ implementation for LASAM module
+ """
+ model_params: LASAMParams = None
+ registration_function: str = "none"
+ main_output_variable: str = 'precipitation_rate'
+ model_name: str = Field("LASAM", const=True, alias="model_type_name")
+
+ _variable_names_map = {
+ "precipitation_rate": "QINSUR",
+ "potential_evapotranspiration_rate": "EVAPOTRANS"
+ }
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/lstm.py b/python/runCalibValid/ngen_conf/src/ngen/config/lstm.py
new file mode 100644
index 00000000..270bacd6
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/lstm.py
@@ -0,0 +1,16 @@
+from pydantic import PyObject, Field
+from typing import Literal, Union
+from .bmi_formulation import BMIPython
+
+class LSTM(BMIPython):
+ """A BMIPython implementation for an ngen LSTM module
+ """
+ #should all be reasonable defaults for LSTM
+ python_type: Union[PyObject, str] = "bmi_lstm.bmi_LSTM"
+ main_output_variable: Literal["land_surface_water__runoff_depth"] = "land_surface_water__runoff_depth"
+ #NOTE aliases don't propagate to subclasses, so we have to repeat the alias
+ model_name: str = Field("LSTM", alias="model_type_name")
+
+ _variable_names_map = {
+ "atmosphere_water__time_integral_of_precipitation_mass_flux":"RAINRATE"
+ }
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/multi.py b/python/runCalibValid/ngen_conf/src/ngen/config/multi.py
new file mode 100644
index 00000000..0f2016ce
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/multi.py
@@ -0,0 +1,85 @@
+from typing import Sequence, Mapping, Any, Optional
+from pydantic import root_validator, Field
+
+from .bmi_formulation import BMIParams
+
+class MultiBMI(BMIParams, smart_union=True):
+ """A MultiBMI model definition
+ Implements and overrids several BMIParams attributes,
+ and includes a recursive Formulation list `modules`
+ """
+ #required
+ #Due to a recursive formulation definition, have to postpone this
+ #type definition and use `update_forward_refs`
+ modules: Sequence["Formulation"]
+ #defaults
+ name: str = Field("bmi_multi", const=True)
+
+ #strictly optional (can be none/null)
+ # NOTE this is derived from the list of modules
+ main_output_variable: Optional[str]
+ #NOTE aliases don't propagate to subclasses, so we have to repeat the alias
+ model_name: Optional[str] = Field(alias="model_type_name")
+
+ #override const since these shouldn't be used for multi bmi, but are currently
+ #required to exist as keys for ngen
+ config: Optional[str] = Field('', const=True, alias="init_config")
+ _config_prefix: Optional[str] = Field(None, const=True, alias="config_prefix")
+ name_map: Mapping[str, str] = Field(None, const=True) #not relevant for multi-bmi
+ model_params: Optional[Mapping[str, str]] = Field(None, const=True) #not relevant for multi-bmi
+
+ def resolve_paths(self):
+ for m in self.modules:
+ m.resolve_paths()
+
+ @root_validator(pre=True)
+ def build_model_name(cls, values: Mapping[str, Any]):
+ """Construct the model name, if none provided.
+
+ If no model name is provided, the multiBMI model_type_name
+ is constructed by joining each module's name using `_`
+
+ Args:
+ values (Mapping[str, Any]): Attributes to assgign to the class, including all defaults
+
+ Returns:
+ Mapping[str, Any]: Attributes to assign to the class, with a (possibly) modifed `model_name`
+ """
+ name = values.get('model_name')
+ modules = values.get('modules')
+ if not name and modules:
+ try:
+ names = [ m['params']['model_name'] for m in modules ]
+ except KeyError:
+ names = [ m['params']['model_type_name'] for m in modules ]
+ values['model_name'] = '_'.join( names )
+ return values
+
+ @root_validator(pre=True)
+ def pick_main_output(cls, values: Mapping[str, Any]) -> Mapping[str, Any]:
+ """Determine the main_output_variable, if none is provided.
+
+ If no main_output_variable is provided to the class, the value
+ is selected from the LAST module provided in the `modules` input.
+
+ Args:
+ values (Mapping[str, Any]): Attributes to assgign to the class, including all defaults
+
+ Returns:
+ Mapping[str, Any]: Attributes to assign to the class, with a (possibly) modifed `main_output_variable`
+ """
+ var = values.get('main_output_variable')
+ modules = values.get('modules')
+ if not var and modules:
+ values['main_output_variable'] = modules[-1]['params']['main_output_variable']
+ return values
+
+#NOTE To avoid circular import and support recrusive modules
+#note the `modules` is a sequence of Formulations
+#which has a `params` of type KnownFormulations
+#of which MultiBMI may be one of those. So we defer
+#type cheking and importing the Formulation until after
+#MultiBMI is defined, then update_forward_refs()
+#from ngen.config.formulation import Formulation
+from .formulation import Formulation
+MultiBMI.update_forward_refs()
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/noahowp.py b/python/runCalibValid/ngen_conf/src/ngen/config/noahowp.py
new file mode 100644
index 00000000..aa23494e
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/noahowp.py
@@ -0,0 +1,31 @@
+from pydantic import BaseModel, Field
+
+from .bmi_formulation import BMIFortran
+
+
+class NoahOWPParams(BaseModel):
+ """Class for validating NoahOWP Parameters
+ """
+ #define params which can be adjusted here
+ #see cfe.py for example
+ pass
+
+class NoahOWP(BMIFortran):
+ """A BMIFortran implementation for a noahowp module
+ """
+ #NGEN complains about 'model_params' = {} in input...use none to remove it for now
+ model_params: NoahOWPParams = None
+ main_output_variable: str = 'QINSUR'
+ #NOTE aliases don't propagate to subclasses, so we have to repeat the alias
+ model_name: str = Field("NoahOWP", const=True, alias="model_type_name")
+
+ _variable_names_map = {
+ "PRCPNONC": "atmosphere_water__liquid_equivalent_precipitation_rate",
+ "Q2": "atmosphere_air_water~vapor__relative_saturation",
+ "SFCTMP": "land_surface_air__temperature",
+ "UU": "land_surface_wind__x_component_of_velocity",
+ "VV": "land_surface_wind__y_component_of_velocity",
+ "LWDN": "land_surface_radiation~incoming~longwave__energy_flux",
+ "SOLDN": "land_surface_radiation~incoming~shortwave__energy_flux",
+ "SFCPRS": "land_surface_air__pressure"
+ }
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/pet.py b/python/runCalibValid/ngen_conf/src/ngen/config/pet.py
new file mode 100644
index 00000000..3ad32ffc
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/pet.py
@@ -0,0 +1,15 @@
+from pydantic import PyObject, Field
+from typing import Literal, Union
+from .bmi_formulation import BMIC
+
+class PET(BMIC):
+ """A C implementation of several ET calculation algorithms
+ """
+ #should all be reasonable defaults for pET
+ main_output_variable: Literal["water_potential_evaporation_flux"] = "water_potential_evaporation_flux"
+ #NOTE aliases don't propagate to subclasses, so we have to repeat the alias
+ model_name: str = Field("PET", alias="model_type_name")
+
+ _variable_names_map = {
+ "water_potential_evaporation_flux":"water_potential_evaporation_flux"
+ }
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/realization.py b/python/runCalibValid/ngen_conf/src/ngen/config/realization.py
new file mode 100644
index 00000000..7f882adb
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/realization.py
@@ -0,0 +1,49 @@
+from pydantic import BaseModel, Field
+from typing import Optional, Mapping, Sequence, Any
+from datetime import datetime
+from .configurations import Forcing, Time, Routing
+from .formulation import Formulation
+
+class Realization(BaseModel):
+ """Simple model of a Realization, containing formulations and forcing
+ """
+ formulations: Sequence[Formulation]
+ forcing: Forcing
+ calibration: Optional[ Mapping[ str, Sequence[ Any ]] ]
+
+ def resolve_paths(self):
+ for f in self.formulations:
+ f.resolve_paths()
+ if(self.forcing):
+ self.forcing.resolve_paths()
+
+class CatchmentRealization(Realization):
+ forcing: Optional[Forcing]
+
+class NgenRealization(BaseModel):
+ """A complete ngen realization confiiguration model, including global and catchment overrides
+ """
+ global_config: Realization = Field(alias='global')
+ time: Time
+ routing: Optional[Routing]
+ #FIXME have not tested catchments...
+ catchments: Optional[ Mapping[str, CatchmentRealization] ] = {}
+
+ #FIXME https://github.com/samuelcolvin/pydantic/issues/2277
+ #Until 1.10, it looks like nested encoder config doesn't apply
+ #so you have to define the encoder at the top level object that
+ #will be serialized...
+ class Config:
+ allow_population_by_field_name = True
+ json_encoders = {
+ datetime: lambda v: v.strftime("%Y-%m-%d %H:%M:%S")
+ }
+
+ def resolve_paths(self):
+ """resolve possible relative paths in configuration
+ """
+ self.global_config.resolve_paths()
+ for k,v in self.catchments.items():
+ v.resolve_paths()
+ if(self.routing != None):
+ self.routing.resolve_paths()
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/sft.py b/python/runCalibValid/ngen_conf/src/ngen/config/sft.py
new file mode 100644
index 00000000..ec4a249c
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/sft.py
@@ -0,0 +1,22 @@
+from pydantic import BaseModel, Field
+from typing import Optional, Mapping
+
+from .bmi_formulation import BMICxx
+
+
+class SFTParams(BaseModel):
+ """Class for validating SFT Parameters
+ """
+ pass
+
+class SFT(BMICxx):
+ """A BMIC++ implementation for SFT module
+ """
+ model_params: SFTParams = None
+ registration_function: str = "none"
+ main_output_variable: str = 'num_cells'
+ model_name: str = Field("SFT", const=True, alias="model_type_name")
+
+ _variable_names_map = {
+ "ground_temperature": "TG"
+ }
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/sloth.py b/python/runCalibValid/ngen_conf/src/ngen/config/sloth.py
new file mode 100644
index 00000000..ccfbb99d
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/sloth.py
@@ -0,0 +1,12 @@
+from typing import Optional, Mapping
+from pydantic import BaseModel, Field
+
+from .bmi_formulation import BMICxx
+
+class SLOTH(BMICxx):
+ """A BMICXX implementation for the SLOTH ngen module
+ """
+ model_params: Optional[Mapping[str, str]] #Is this a better represntation of SLOTH params??? just generic mappings?
+ registration_function: str = "none" #FIXME this isn't required for CXX bmi in ngen?
+ #NOTE aliases don't propagate to subclasses, so we have to repeat the alias
+ model_name: str = Field("SLOTH", const=True, alias="model_type_name")
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/smp.py b/python/runCalibValid/ngen_conf/src/ngen/config/smp.py
new file mode 100644
index 00000000..be7d17f6
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/smp.py
@@ -0,0 +1,18 @@
+from pydantic import BaseModel, Field
+from typing import Optional, Mapping
+
+from .bmi_formulation import BMICxx
+
+
+class SMP(BMICxx):
+ """A BMIC++ implementation for SMP module
+ """
+ registration_function: str = "none"
+ main_output_variable: str = 'soil_water_table'
+ model_name: str = Field("SMP", const=True, alias="model_type_name")
+
+ _variable_names_map = {
+ "soil_storage" : "SOIL_STORAGE",
+ "soil_storage_change" : "SOIL_STORAGE_CHANGE"
+
+ }
diff --git a/python/runCalibValid/ngen_conf/src/ngen/config/topmod.py b/python/runCalibValid/ngen_conf/src/ngen/config/topmod.py
new file mode 100644
index 00000000..0266e505
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/src/ngen/config/topmod.py
@@ -0,0 +1,30 @@
+from typing import Optional
+from pydantic import BaseModel, Field
+
+from .bmi_formulation import BMIC
+
+class TopmodParams(BaseModel):
+ """Class for validating Topmod Parameters
+ """
+ sr0: Optional[float]
+ srmax: Optional[float]
+ szm: Optional[float]
+ t0: Optional[float]
+ td: Optional[float]
+
+class Topmod(BMIC):
+ """A BMIC implementation for the Topmod ngen module
+ """
+ model_params: Optional[TopmodParams]
+ main_output_variable: str = 'Qout'
+ registration_function: str = "register_bmi_topmodel"
+ #NOTE aliases don't propagate to subclasses, so we have to repeat the alias
+ model_name: str = Field("TOPMODEL", const=True, alias="model_type_name")
+
+ #can set some default name map entries...will be overridden at construction
+ #if a name_map with the same key is passed in, otherwise the name_map
+ #will also include these mappings
+ _variable_names_map = {
+ #"water_potential_evaporation_flux": "EVAPOTRANS",
+ "atmosphere_water__liquid_equivalent_precipitation_rate": "QINSUR"
+ }
diff --git a/python/runCalibValid/ngen_conf/tests/conftest.py b/python/runCalibValid/ngen_conf/tests/conftest.py
new file mode 100644
index 00000000..7bcf6bb5
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/conftest.py
@@ -0,0 +1,114 @@
+import pytest
+from pathlib import Path
+from ngen.config.configurations import Forcing, Time, Routing
+from ngen.config.formulation import Formulation
+from ngen.config.cfe import CFE
+from ngen.config.sloth import SLOTH
+from ngen.config.noahowp import NoahOWP
+from ngen.config.multi import MultiBMI
+
+#set the workdir relative to this test config
+#and use that to look for test data
+_workdir=Path(__file__).parent
+
+"""
+Fixtures for setting up various ngen-conf components for testing
+"""
+@pytest.fixture
+def forcing(request):
+ which = request.param
+ if which == "netcdf":
+ provider = Forcing.Provider.NetCDF
+ else:
+ #default to csv
+ provider = Forcing.Provider.CSV
+ print(provider)
+ forcing = _workdir.joinpath("data/forcing/")
+ #Share forcing for all formulations
+ return Forcing(file_pattern=".*{{id}}.*.csv", path=forcing, provider=provider)
+
+@pytest.fixture
+def time():
+ return Time(start_time="2019-06-01 00:00:00", end_time="2019-06-07 23:00:00")
+
+@pytest.fixture
+def routing():
+ return Routing(path="extern/t-route/src/ngen_routing/src", config="ngen_routing.yaml" )
+
+@pytest.fixture
+def cfe_params():
+ path = _workdir.joinpath("data/CFE/")
+ data = {'config_prefix':path,
+ # 'config': "{{id}}_config.txt",
+ 'config': "config.txt",
+ 'library_prefix':path,
+ 'library': 'libfakecfe.so',
+ 'model_params':{'slope':0.42, 'expon':42}}
+ return data
+
+@pytest.fixture
+def sloth_params():
+ path = _workdir.joinpath("data/sloth/")
+ data = {'config_prefix':path,
+ # 'config': "{{id}}_config.txt",
+ 'config': "config.txt",
+ 'library_prefix':path,
+ 'library': 'libfakesloth.so',
+ 'main_output_variable': 'TEST'}
+ return data
+
+@pytest.fixture
+def topmod_params():
+ path = _workdir.joinpath("data/CFE/")
+ data = {'config_prefix':path,
+ # 'config': "{{id}}_config.txt",
+ 'config': "config.txt",
+ 'library_prefix':path,
+ 'library': 'libfakecfe.so',
+ 'model_params':{'t0':0.42, 'szm':42}}
+ return data
+
+@pytest.fixture
+def noahowp_params():
+ path = _workdir.joinpath("data/NOAH/")
+ libpath = _workdir.joinpath("data/CFE")
+ data = {'config_prefix':path,
+ 'config': "{{id}}.input",
+ 'library_prefix': libpath,
+ 'library': 'libfakecfe.so'
+ }
+ return data
+
+@pytest.fixture
+def cfe(cfe_params):
+ return CFE(**cfe_params)
+
+@pytest.fixture
+def sloth(sloth_params):
+ return SLOTH(**sloth_params)
+
+@pytest.fixture
+def noahowp(noahowp_params):
+ return NoahOWP(**noahowp_params)
+
+@pytest.fixture
+def multi(cfe, noahowp, forcing):
+ cfe.allow_exceed_end_time=True
+ noahowp.allow_exceed_end_time=True
+ f1 = Formulation(name=noahowp.name, params=noahowp)
+ f2 = Formulation(name=cfe.name, params=cfe)
+ return MultiBMI(modules=[f1.dict(), f2.dict()], allow_exceed_end_time=True)
+
+@pytest.fixture
+def lstm_params():
+ path = _workdir.joinpath("data/CFE/")
+ data = {'config_prefix':path,
+ 'config': "{{id}}_config.txt"}
+ return data
+
+@pytest.fixture
+def multi_params(cfe, noahowp):
+ data = {"modules":[Formulation(name=noahowp.name, params=noahowp).dict(),
+ Formulation(name=cfe.name, params=cfe).dict()]
+ }
+ return data
diff --git a/python/runCalibValid/ngen_conf/tests/data/CFE/config.txt b/python/runCalibValid/ngen_conf/tests/data/CFE/config.txt
new file mode 100644
index 00000000..3e03c5b6
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/data/CFE/config.txt
@@ -0,0 +1,25 @@
+forcing_file=BMI
+surface_partitioning_scheme=Schaake
+soil_params.depth=2.0[m]
+soil_params.b=2.0[]
+soil_params.satdk=4.297e-06[m s-1]
+soil_params.satpsi=0.067700443[m]
+soil_params.slop=0.004442011[m/m]
+soil_params.smcmax=0.492374256[m/m]
+soil_params.wltsmc=0.037198688[m/m]
+soil_params.expon=1.0[]
+soil_params.expon_secondary=1.0[]
+refkdt=3.780091047
+max_gw_storage=0.011187639236[m]
+Cgw=1.8e-05[m h-1]
+expon=5.0[]
+gw_storage=0.05[m/m]
+alpha_fc=0.33
+soil_storage=0.05[m/m]
+K_nash=0.03[]
+K_lf=0.01[]
+nash_storage=0.0,0.0
+num_timesteps=1
+verbosity=1
+DEBUG=0
+giuh_ordinates=0.08,0.08,0.07,0.08,0.09,0.08,0.07,0.08,0.08,0.06,0.06,0.05,0.05,0.07
diff --git a/python/runCalibValid/ngen_conf/tests/data/CFE/libfakecfe.dylib b/python/runCalibValid/ngen_conf/tests/data/CFE/libfakecfe.dylib
new file mode 100644
index 00000000..e69de29b
diff --git a/python/runCalibValid/ngen_conf/tests/data/NOAH/cat-1.input b/python/runCalibValid/ngen_conf/tests/data/NOAH/cat-1.input
new file mode 100644
index 00000000..4b952fd9
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/data/NOAH/cat-1.input
@@ -0,0 +1,73 @@
+&timing ! and output
+ dt = 3600.0 ! timestep [seconds]
+ startdate = "200710010000" ! UTC time start of simulation (YYYYMMDDhhmm)
+ enddate = "201912310000" ! UTC time end of simulation (YYYYMMDDhhmm)
+ input_filename = "./forcing/cat-1.csv" ! change filename to match your forcing data
+ output_filename = "out_cat-1.csv"
+/
+
+¶meters
+ parameter_dir = "./tests/data/NOAH/parameters/"
+ general_table = "GENPARM.TBL" ! general param tables and misc params
+ soil_table = "SOILPARM.TBL" ! soil param table
+ noahowp_table = "MPTABLE.TBL" ! model param tables (includes veg)
+ soil_class_name = "STAS" ! soil class data source - "STAS" or "STAS-RUC"
+ veg_class_name = "USGS" ! vegetation class data source - "USGS" or "USGS"
+/
+
+&location ! for point runs, needs to be modified for gridded
+ lat = 33.763923154942475 ! latitude [degrees]
+ lon = -116.57047432754845 ! longitude [degrees]
+/
+
+&forcing
+ ZREF = 10.0 ! measurement height for wind speed
+/
+
+&model_options ! see OptionsType.f90 for details
+ precip_phase_option = 1
+ snow_albedo_option = 1
+ dynamic_veg_option = 4
+ runoff_option = 3
+ drainage_option = 8
+ frozen_soil_option = 1
+ dynamic_vic_option = 1
+ radiative_transfer_option = 3
+ sfc_drag_coeff_option = 1
+ canopy_stom_resist_option = 1
+ crop_model_option = 0
+ snowsoil_temp_time_option = 3
+ soil_temp_boundary_option = 2
+ supercooled_water_option = 1
+ stomatal_resistance_option = 1
+ evap_srfc_resistance_option = 4
+ subsurface_option = 2
+/
+
+&structure
+ isltyp = 16 ! soil texture class
+ nsoil = 4 ! number of soil levels
+ nsnow = 3 ! number of snow levels
+ nveg = 27 ! number of vegetation types
+ structure_option = 1 ! 1: use preset zsoil; 2: uniform levels
+ soil_depth = 2.0 ! total soil thickness [m] for structure_option > 1
+ vegtyp = 7 ! vegetation type
+ croptype = 0 ! crop type (0 = no crops)
+ sfctyp = 1 ! land surface type, 1:soil, 2:lake
+ soilcolor = 4 ! soil color code
+/
+
+&fixed_initial
+ zsoil = -0.1, -0.4, -1.0, -2.0 ! depth to level interface [m]
+ dzsnso = 0.0, 0.0, 0.0, 0.1, 0.3, 0.6, 1.0 ! level thickness [m]
+ sice = 0.0, 0.0, 0.0, 0.0 ! initial soil ice profile [vol]
+ sh2o = 0.3, 0.3, 0.3, 0.3 ! initial soil liquid profile [vol]
+ zwt = -2.0 ! initial water table depth below surface [m]
+/
+
+&uniform_initial
+ initial_uniform = .true. ! initial all levels the same
+ initial_sh2o_value = 0.3 ! constant soil liquid value [vol]
+ initial_sice_value = 0.0 ! constant soil ice value [vol]
+ initial_zwt = -2.0 ! initial water table depth below surface [m]
+/
diff --git a/python/runCalibValid/ngen_conf/tests/data/NOAH/libfakenoah.dylib b/python/runCalibValid/ngen_conf/tests/data/NOAH/libfakenoah.dylib
new file mode 100644
index 00000000..e69de29b
diff --git a/python/runCalibValid/ngen_conf/tests/data/NOAH/namelist.input b/python/runCalibValid/ngen_conf/tests/data/NOAH/namelist.input
new file mode 100644
index 00000000..c04f234e
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/data/NOAH/namelist.input
@@ -0,0 +1,66 @@
+&timing ! and input/output paths
+ dt = 1800.0 ! timestep [seconds]
+ startdate = "199801010630" ! UTC time start of simulation (YYYYMMDDhhmm)
+ enddate = "199901010630" ! UTC time end of simulation (YYYYMMDDhhmm)
+ forcing_filename = "../data/bondville.dat" ! file containing forcing data
+ output_filename = "../data/output.nc"
+/
+
+¶meters
+ parameter_dir = "./data/NOAH/parameters/" ! location of input parameter files
+ general_table = "GENPARM.TBL" ! general param tables and misc params
+ soil_table = "SOILPARM.TBL" ! soil param table
+ noahowp_table = "MPTABLE.TBL" ! model param tables (includes veg)
+ soil_class_name = "STAS" ! soil class data source - "STAS" or "STAS-RUC"
+ veg_class_name = "MODIFIED_IGBP_MODIS_NOAH" ! vegetation class data source - "MODIFIED_IGBP_MODIS_NOAH" or "USGS"
+/
+
+&location ! for point runs
+ lat = 40.01 ! latitude [degrees] (-90 to 90)
+ lon = -88.37 ! longitude [degrees] (-180 to 180)
+ terrain_slope = 0.0 ! terrain slope [degrees]
+ azimuth = 0.0 ! terrain azimuth or aspect [degrees clockwise from north]
+/
+
+&forcing
+ ZREF = 10.0 ! measurement height for wind speed (m)
+ rain_snow_thresh = 1.0 ! rain-snow temperature threshold (degrees Celcius)
+/
+
+&model_options ! see OptionsType.f90 for details
+ precip_phase_option = 1
+ snow_albedo_option = 1
+ dynamic_veg_option = 1
+ runoff_option = 8
+ drainage_option = 8
+ frozen_soil_option = 1
+ dynamic_vic_option = 1
+ radiative_transfer_option = 3
+ sfc_drag_coeff_option = 1
+ canopy_stom_resist_option = 1
+ crop_model_option = 0
+ snowsoil_temp_time_option = 3
+ soil_temp_boundary_option = 2
+ supercooled_water_option = 1
+ stomatal_resistance_option = 1
+ evap_srfc_resistance_option = 1
+ subsurface_option = 1
+/
+
+&structure
+ isltyp = 1 ! soil texture class
+ nsoil = 4 ! number of soil levels
+ nsnow = 3 ! number of snow levels
+ nveg = 20 ! number of vegetation types
+ vegtyp = 1 ! vegetation type
+ croptype = 0 ! crop type (0 = no crops; this option is currently inactive)
+ sfctyp = 1 ! land surface type, 1:soil, 2:lake
+ soilcolor = 4 ! soil color code
+/
+
+&initial_values
+ dzsnso = 0.0, 0.0, 0.0, 0.1, 0.3, 0.6, 1.0 ! level thickness [m]
+ sice = 0.0, 0.0, 0.0, 0.0 ! initial soil ice profile [m3/m3]
+ sh2o = 0.3, 0.3, 0.3, 0.3 ! initial soil liquid profile [m3/m3]
+ zwt = -2.0 ! initial water table depth below surface [m]
+/
diff --git a/python/runCalibValid/ngen_conf/tests/data/NOAH/parameters/GENPARM.TBL b/python/runCalibValid/ngen_conf/tests/data/NOAH/parameters/GENPARM.TBL
new file mode 100644
index 00000000..35cc460e
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/data/NOAH/parameters/GENPARM.TBL
@@ -0,0 +1,38 @@
+General Parameters
+SLOPE_DATA
+9
+0.1
+0.6
+1.0
+0.35
+0.55
+0.8
+0.63
+0.0
+0.0
+SBETA_DATA
+-2.0
+FXEXP_DATA
+2.0
+CSOIL_DATA
+2.00E+6
+SALP_DATA
+2.6
+REFDK_DATA
+2.0E-6
+REFKDT_DATA
+3.0
+FRZK_DATA
+0.15
+ZBOT_DATA
+-8.0
+CZIL_DATA
+0.1
+SMLOW_DATA
+0.5
+SMHIGH_DATA
+3.0
+LVCOEF_DATA
+0.5
+Z0_DATA
+0.002
diff --git a/python/runCalibValid/ngen_conf/tests/data/NOAH/parameters/MPTABLE.TBL b/python/runCalibValid/ngen_conf/tests/data/NOAH/parameters/MPTABLE.TBL
new file mode 100644
index 00000000..20fa5bf2
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/data/NOAH/parameters/MPTABLE.TBL
@@ -0,0 +1,650 @@
+&usgs_veg_categories
+ VEG_DATASET_DESCRIPTION = "USGS"
+ NVEG = 27
+/
+&usgs_veg_parameters
+ ! NVEG = 27
+ ! 1: Urban and Built-Up Land
+ ! 2: Dryland Cropland and Pasture
+ ! 3: Irrigated Cropland and Pasture
+ ! 4: Mixed Dryland/Irrigated Cropland and Pasture
+ ! 5: Cropland/Grassland Mosaic
+ ! 6: Cropland/Woodland Mosaic
+ ! 7: Grassland
+ ! 8: Shrubland
+ ! 9: Mixed Shrubland/Grassland
+ ! 10: Savanna
+ ! 11: Deciduous Broadleaf Forest
+ ! 12: Deciduous Needleleaf Forest
+ ! 13: Evergreen Broadleaf Forest
+ ! 14: Evergreen Needleleaf Forest
+ ! 15: Mixed Forest
+ ! 16: Water Bodies
+ ! 17: Herbaceous Wetland
+ ! 18: Wooded Wetland
+ ! 19: Barren or Sparsely Vegetated
+ ! 20: Herbaceous Tundra
+ ! 21: Wooded Tundra
+ ! 22: Mixed Tundra
+ ! 23: Bare Ground Tundra
+ ! 24: Snow or Ice
+ ! 25: Playa
+ ! 26: Lava
+ ! 27: White Sand
+
+ ISURBAN = 1
+ ISWATER = 16
+ ISBARREN = 19
+ ISICE = 24
+ ISCROP = 2
+ EBLFOREST = 13
+ NATURAL = 5
+ LCZ_1 = 31
+ LCZ_2 = 32
+ LCZ_3 = 33
+ LCZ_4 = 34
+ LCZ_5 = 35
+ LCZ_6 = 36
+ LCZ_7 = 37
+ LCZ_8 = 38
+ LCZ_9 = 39
+ LCZ_10 = 40
+ LCZ_11 = 41
+
+ !---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ ! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
+ !---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CH2OP = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1,
+ DLEAF = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04,
+ Z0MVT = 1.00, 0.15, 0.15, 0.15, 0.14, 0.50, 0.12, 0.06, 0.09, 0.50, 0.80, 0.85, 1.10, 1.09, 0.80, 0.00, 0.12, 0.50, 0.00, 0.10, 0.30, 0.20, 0.03, 0.00, 0.01, 0.00, 0.00,
+ HVT = 15.0, 2.00, 2.00, 2.00, 1.50, 8.00, 1.00, 1.10, 1.10, 10.0, 16.0, 18.0, 20.0, 20.0, 16.0, 0.00, 0.50, 10.0, 0.00, 0.50, 4.00, 2.00, 0.50, 0.00, 0.10, 0.00, 0.00,
+ HVB = 1.00, 0.10, 0.10, 0.10, 0.10, 0.15, 0.05, 0.10, 0.10, 0.10, 11.5, 7.00, 8.00, 8.50, 10.0, 0.00, 0.05, 0.10, 0.00, 0.10, 0.10, 0.10, 0.10, 0.00, 0.10, 0.00, 0.00,
+ DEN = 0.01, 25.0, 25.0, 25.0, 25.0, 25.0, 100., 10.0, 10.0, 0.02, 0.10, 0.28, 0.02, 0.28, 0.10, 0.01, 10.0, 0.10, 0.01, 1.00, 1.00, 1.00, 1.00, 0.00, 0.01, 0.01, 0.01,
+ RC = 1.00, 0.08, 0.08, 0.08, 0.08, 0.08, 0.03, 0.12, 0.12, 3.00, 1.40, 1.20, 3.60, 1.20, 1.40, 0.01, 0.10, 1.40, 0.01, 0.30, 0.30, 0.30, 0.30, 0.00, 0.01, 0.01, 0.01,
+MFSNO = 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50,
+! C. He 12/17/2020: optimized MFSNO values dependent on land type based on evaluation with SNOTEL SWE and MODIS SCF, surface albedo
+! MFSNO = 4.00, 3.00, 3.00, 3.00, 4.00, 4.00, 2.00, 2.00, 2.00, 2.00, 1.00, 1.00, 1.00, 1.00, 1.00, 3.00, 3.00, 3.00, 3.00, 3.50, 3.50, 3.50, 3.50, 2.50, 3.50, 3.50, 3.50,
+! C. He 12/17/2020: optimized snow cover factor (m) in SCF formulation to replace original constant 2.5*z0,z0=0.002m, based on evaluation with SNOTEL SWE and MODIS SCF, surface albedo
+ SCFFAC= 0.042, 0.014, 0.014, 0.014, 0.026, 0.026, 0.020, 0.018, 0.016, 0.020, 0.008, 0.008, 0.008, 0.008, 0.008, 0.030, 0.020, 0.020, 0.016, 0.030, 0.030, 0.030, 0.030, 0.030, 0.030, 0.030, 0.030,
+
+ ! Row 1: Vis
+ ! Row 2: Near IR
+ RHOL_VIS=0.00, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.07, 0.10, 0.10, 0.10, 0.07, 0.10, 0.07, 0.10, 0.00, 0.11, 0.10, 0.00, 0.10, 0.10, 0.10, 0.10, 0.00, 0.10, 0.00, 0.00,
+ RHOL_NIR=0.00, 0.58, 0.58, 0.58, 0.58, 0.58, 0.58, 0.35, 0.45, 0.45, 0.45, 0.35, 0.45, 0.35, 0.45, 0.00, 0.58, 0.45, 0.00, 0.45, 0.45, 0.45, 0.45, 0.00, 0.45, 0.00, 0.00,
+
+ ! Row 1: Vis
+ ! Row 2: Near IR
+ RHOS_VIS=0.00, 0.36, 0.36, 0.36, 0.36, 0.36, 0.36, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.00, 0.36, 0.16, 0.00, 0.16, 0.16, 0.16, 0.16, 0.00, 0.16, 0.00, 0.00,
+ RHOS_NIR=0.00, 0.58, 0.58, 0.58, 0.58, 0.58, 0.58, 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.00, 0.58, 0.39, 0.00, 0.39, 0.39, 0.39, 0.39, 0.00, 0.39, 0.00, 0.00,
+
+ ! Row 1: Vis
+ ! Row 2: Near IR
+ TAUL_VIS=0.00, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.00, 0.07, 0.05, 0.00, 0.05, 0.05, 0.05, 0.05, 0.00, 0.05, 0.00, 0.00,
+ TAUL_NIR=0.00, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.10, 0.10, 0.25, 0.25, 0.10, 0.25, 0.10, 0.25, 0.00, 0.25, 0.25, 0.00, 0.25, 0.25, 0.25, 0.25, 0.00, 0.25, 0.00, 0.00,
+
+ ! Row 1: Vis
+ ! Row 2: Near IR
+ TAUS_VIS=0.00, 0.220, 0.220, 0.220, 0.220, 0.220, 0.220, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.000, 0.220, 0.001, 0.000, 0.220, 0.001, 0.001, 0.001, 0.000, 0.001, 0.000, 0.000,
+ TAUS_NIR=0.00, 0.380, 0.380, 0.380, 0.380, 0.380, 0.380, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.000, 0.380, 0.001, 0.000, 0.380, 0.001, 0.001, 0.001, 0.000, 0.001, 0.000, 0.000,
+
+ XL = 0.000, -0.30, -0.30, -0.30, -0.30, -0.30, -0.30, 0.010, 0.250, 0.010, 0.250, 0.010, 0.010, 0.010, 0.250, 0.000, -0.30, 0.250, 0.000, -0.30, 0.250, 0.250, 0.250, 0.000, 0.250, 0.000, 0.000,
+ ! make CWPVT vegetation dependent according to J. Goudriaan, Crop Micrometeorology: A Simulation Study (Simulation monographs), 1977). C. He, 12/17/2020
+ CWPVT = 0.18, 1.67, 1.67, 1.67, 1.67, 0.5, 5.0, 1.0, 2.0, 1.0, 0.67, 0.18, 0.67, 0.18, 0.29, 0.18, 1.67, 0.67, 0.18, 1.67, 0.67, 1.00, 0.18, 0.18, 0.18, 0.18, 0.18,
+ C3PSN = 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
+ KC25 = 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0,
+ AKC = 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1,
+ KO25 = 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4,
+ AKO = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2,
+ AVCMX = 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4,
+ AQE = 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
+
+ LTOVRC= 0.0, 1.2, 1.2, 1.2, 1.2, 1.30, 0.50, 0.65, 0.70, 0.65, 0.55, 0.2, 0.55, 0.5, 0.5, 0.0, 1.4, 1.4, 0.0, 1.2, 1.3, 1.4, 1.0, 0.0, 1.0, 0.0, 0.0,
+ DILEFC= 0.00, 0.50, 0.50, 0.50, 0.35, 0.20, 0.20, 0.20, 0.50, 0.50, 0.60, 1.80, 0.50, 1.20, 0.80, 0.00, 0.40, 0.40, 0.00, 0.40, 0.30, 0.40, 0.30, 0.00, 0.30, 0.00, 0.00,
+ DILEFW= 0.00, 0.20, 0.20, 0.20, 0.20, 0.20, 0.10, 0.20, 0.20, 0.50, 0.20, 0.20, 4.00, 0.20, 0.20, 0.00, 0.20, 0.20, 0.00, 0.20, 0.20, 0.20, 0.20, 0.00, 0.20, 0.00, 0.00,
+ RMF25 = 0.00, 1.00, 1.40, 1.45, 1.45, 1.45, 1.80, 0.26, 0.26, 0.80, 3.00, 4.00, 0.65, 3.00, 3.00, 0.00, 3.20, 3.20, 0.00, 3.20, 3.00, 3.00, 3.00, 0.00, 3.00, 0.00, 0.00,
+ SLA = 60, 80, 80, 80, 80, 80, 60, 60, 60, 50, 80, 80, 80, 80, 80, 0, 80, 80, 0, 80, 80, 80, 80, 0, 80, 0, 0,
+ FRAGR = 0.00, 0.20, 0.20, 0.20, 0.20, 0.20, 0.20, 0.20, 0.20, 0.20, 0.20, 0.10, 0.20, 0.10, 0.10, 0.00, 0.10, 0.10, 0.10, 0.10, 0.10, 0.10, 0.10, 0.00, 0.10, 0.00, 0.00,
+ TMIN = 0, 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 268, 273, 265, 268, 0, 268, 268, 0, 268, 268, 268, 268, 0, 268, 0, 0,
+ VCMX25= 0.00, 80.0, 80.0, 80.0, 60.0, 70.0, 40.0, 40.0, 40.0, 40.0, 60.0, 60.0, 60.0, 50.0, 55.0, 0.00, 50.0, 50.0, 0.00, 50.0, 50.0, 50.0, 50.0, 0.00, 50.0, 0.00, 0.00,
+ TDLEF = 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 268, 278, 278, 268, 0, 268, 268, 0, 268, 268, 268, 268, 0, 268, 0, 0,
+ BP = 1.E15, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 1.E15, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 1.E15, 2.E3, 1.E15, 1.E15,
+ MP = 9., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9., 6., 9., 6., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9.,
+ QE25 = 0., 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.00, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.00, 0.06, 0.00, 0.00,
+ RMS25 = 0.00, 0.10, 0.10, 0.10, 0.10, 0.10, 0.10, 0.10, 0.10, 0.32, 0.10, 0.64, 0.30, 0.90, 0.80, 0.00, 0.10, 0.10, 0.00, 0.10, 0.10, 0.10, 0.00, 0.00, 0.00, 0.00, 0.00,
+ RMR25 = 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 1.20, 0.00, 0.00, 0.01, 0.01, 0.05, 0.05, 0.36, 0.03, 0.00, 0.00, 0.00, 0.00, 2.11, 2.11, 2.11, 0.00, 0.00, 0.00, 0.00, 0.00,
+ ARM = 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
+ FOLNMX= 0.00, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 0.00, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 0.00, 1.5, 0.00, 0.00,
+ WDPOOL= 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 0.00, 0.00, 1.00, 0.00, 0.00, 1.00, 1.00, 0.00, 0.00, 0.00, 0.00, 0.00,
+ WRRAT = 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 3.00, 3.00, 3.00, 30.0, 30.0, 30.0, 30.0, 30.0, 0.00, 0.00, 30.0, 0.00, 0.00, 3.00, 3.00, 0.00, 0.00, 0.00, 0.00, 0.00,
+ MRP = 0.00, 0.23, 0.23, 0.23, 0.23, 0.23, 0.17, 0.19, 0.19, 0.40, 0.40, 0.37, 0.23, 0.37, 0.30, 0.00, 0.17, 0.40, 0.00, 0.17, 0.23, 0.20, 0.00, 0.00, 0.20, 0.00, 0.00,
+! added (temporarly)
+ SHDFAC= 0.10, 0.80, 0.80, 0.80, 0.80, 0.80, 0.80, 0.70, 0.70, 0.50, 0.80, 0.70, 0.95, 0.70, 0.80, 0.00, 0.60, 0.60, 0.01, 0.60, 0.60, 0.60, 0.30, 0.00, 0.50, 0.00 0.00,
+ NROOT = 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 0, 2, 2, 1, 3, 3, 3, 2, 1, 1, 0, 0,
+ RGL = 999.0, 100.0, 100.0, 100.0, 100.0, 65.0, 100.0, 100.0, 100.0, 65.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 100.0, 30.0, 999.0, 100.0, 100.0, 100.0, 100.0, 999.0, 100.0, 999.0, 999.0,
+ RS = 200.0, 40.0, 40.0, 40.0, 40.0, 70.0, 40.0, 300.0, 170.0, 70.0, 100.0, 150.0, 150.0, 125.0, 125.0, 100.0, 40.0, 100.0, 999.0, 150.0, 150.0, 150.0, 200.0, 999.0, 40.0, 999.0, 999.0,
+ HS = 999.0, 36.25, 36.25, 36.25, 36.25, 44.14, 36.35, 42.00, 39.18, 54.53, 54.53, 47.35, 41.69, 47.35, 51.93, 51.75, 60.00, 51.93, 999.0, 42.00, 42.00, 42.00, 42.00, 999.0, 36.25, 999.0, 999.0,
+ TOPT = 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0,
+ RSMAX = 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000.,
+
+! Monthly values, one row for each month:
+ SAI_JAN = 0.0, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.2, 0.2, 0.3, 0.4, 0.3, 0.5, 0.4, 0.4, 0.0, 0.2, 0.3, 0.0, 0.1, 0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0,
+ SAI_FEB = 0.0, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.2, 0.2, 0.3, 0.4, 0.3, 0.5, 0.4, 0.4, 0.0, 0.2, 0.3, 0.0, 0.1, 0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0,
+ SAI_MAR = 0.0, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.2, 0.2, 0.3, 0.4, 0.3, 0.5, 0.4, 0.4, 0.0, 0.2, 0.3, 0.0, 0.1, 0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0,
+ SAI_APR = 0.0, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.2, 0.2, 0.3, 0.4, 0.4, 0.5, 0.3, 0.4, 0.0, 0.2, 0.3, 0.0, 0.1, 0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0,
+ SAI_MAY = 0.0, 0.2, 0.2, 0.2, 0.3, 0.3, 0.3, 0.2, 0.2, 0.3, 0.4, 0.4, 0.5, 0.4, 0.4, 0.0, 0.3, 0.3, 0.0, 0.1, 0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0,
+ SAI_JUN = 0.0, 0.3, 0.3, 0.3, 0.4, 0.4, 0.4, 0.2, 0.3, 0.4, 0.4, 0.7, 0.5, 0.5, 0.4, 0.0, 0.4, 0.4, 0.0, 0.2, 0.2, 0.2, 0.0, 0.0, 0.0, 0.0, 0.0,
+ SAI_JUL = 0.0, 0.4, 0.4, 0.4, 0.6, 0.6, 0.8, 0.4, 0.6, 0.8, 0.9, 1.3, 0.5, 0.5, 0.7, 0.0, 0.6, 0.6, 0.0, 0.4, 0.4, 0.4, 0.0, 0.0, 0.0, 0.0, 0.0,
+ SAI_AUG = 0.0, 0.5, 0.5, 0.5, 0.9, 0.9, 1.3, 0.6, 0.9, 1.2, 1.2, 1.2, 0.5, 0.6, 0.8, 0.0, 0.9, 0.9, 0.0, 0.6, 0.6, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0,
+ SAI_SEP = 0.0, 0.4, 0.4, 0.4, 0.7, 1.0, 1.1, 0.8, 1.0, 1.3, 1.6, 1.0, 0.5, 0.6, 1.0, 0.0, 0.7, 1.0, 0.0, 0.7, 0.8, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0,
+ SAI_OCT = 0.0, 0.3, 0.3, 0.3, 0.3, 0.8, 0.4, 0.7, 0.6, 0.7, 1.4, 0.8, 0.5, 0.7, 1.0, 0.0, 0.3, 0.8, 0.0, 0.5, 0.7, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0,
+ SAI_NOV = 0.0, 0.3, 0.3, 0.3, 0.3, 0.4, 0.4, 0.3, 0.3, 0.4, 0.6, 0.6, 0.5, 0.6, 0.5, 0.0, 0.3, 0.4, 0.0, 0.3, 0.3, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0,
+ SAI_DEC = 0.0, 0.3, 0.3, 0.3, 0.3, 0.3, 0.4, 0.2, 0.3, 0.4, 0.4, 0.5, 0.5, 0.5, 0.4, 0.0, 0.3, 0.4, 0.0, 0.2, 0.2, 0.2, 0.0, 0.0, 0.0, 0.0, 0.0,
+
+ LAI_JAN = 0.0, 0.0, 0.0, 0.0, 0.2, 0.0, 0.4, 0.0, 0.2, 0.3, 0.0, 0.0, 4.5, 4.0, 2.0, 0.0, 0.2, 0.2, 0.0, 0.2, 1.0, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0,
+ LAI_FEB = 0.0, 0.0, 0.0, 0.0, 0.3, 0.0, 0.5, 0.0, 0.3, 0.3, 0.0, 0.0, 4.5, 4.0, 2.0, 0.0, 0.3, 0.3, 0.0, 0.3, 1.0, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0,
+ LAI_MAR = 0.0, 0.0, 0.0, 0.0, 0.3, 0.2, 0.6, 0.2, 0.4, 0.5, 0.3, 0.0, 4.5, 4.0, 2.2, 0.0, 0.3, 0.3, 0.0, 0.3, 1.1, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0,
+ LAI_APR = 0.0, 0.0, 0.0, 0.0, 0.4, 0.6, 0.7, 0.6, 0.7, 0.8, 1.2, 0.6, 4.5, 4.0, 2.6, 0.0, 0.4, 0.6, 0.0, 0.4, 1.3, 0.8, 0.0, 0.0, 0.0, 0.0, 0.0,
+ LAI_MAY = 0.0, 1.0, 1.0, 1.0, 1.1, 2.0, 1.2, 1.5, 1.4, 1.8, 3.0, 1.2, 4.5, 4.0, 3.5, 0.0, 1.1, 2.0, 0.0, 0.6, 1.7, 1.2, 0.0, 0.0, 0.0, 0.0, 0.0,
+ LAI_JUN = 0.0, 2.0, 2.0, 2.0, 2.5, 3.3, 3.0, 2.3, 2.6, 3.6, 4.7, 2.0, 4.5, 4.0, 4.3, 0.0, 2.5, 3.3, 0.0, 1.5, 2.1, 1.8, 0.0, 0.0, 0.0, 0.0, 0.0,
+ LAI_JUL = 0.0, 3.0, 3.0, 3.0, 3.2, 3.7, 3.5, 2.3, 2.9, 3.8, 4.5, 2.6, 4.5, 4.0, 4.3, 0.0, 3.2, 3.7, 0.0, 1.7, 2.1, 1.8, 0.0, 0.0, 0.0, 0.0, 0.0,
+ LAI_AUG = 0.0, 3.0, 3.0, 3.0, 2.2, 3.2, 1.5, 1.7, 1.6, 2.1, 3.4, 1.7, 4.5, 4.0, 3.7, 0.0, 2.2, 3.2, 0.0, 0.8, 1.8, 1.3, 0.0, 0.0, 0.0, 0.0, 0.0,
+ LAI_SEP = 0.0, 1.5, 1.5, 1.5, 1.1, 1.3, 0.7, 0.6, 0.7, 0.9, 1.2, 1.0, 4.5, 4.0, 2.6, 0.0, 1.1, 1.3, 0.0, 0.4, 1.3, 0.8, 0.0, 0.0, 0.0, 0.0, 0.0,
+ LAI_OCT = 0.0, 0.0, 0.0, 0.0, 0.3, 0.2, 0.6, 0.2, 0.4, 0.5, 0.3, 0.5, 4.5, 4.0, 2.2, 0.0, 0.3, 0.3, 0.0, 0.3, 1.1, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0,
+ LAI_NOV = 0.0, 0.0, 0.0, 0.0, 0.3, 0.0, 0.5, 0.0, 0.3, 0.3, 0.0, 0.2, 4.5, 4.0, 2.0, 0.0, 0.3, 0.3, 0.0, 0.2, 1.0, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0,
+ LAI_DEC = 0.0, 0.0, 0.0, 0.0, 0.2, 0.0, 0.4, 0.0, 0.2, 0.3, 0.0, 0.0, 4.5, 4.0, 2.0, 0.0, 0.2, 0.2, 0.0, 0.2, 1.0, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0,
+
+ SLAREA=0.0228,0.0200,0.0200,0.0295,0.0223,0.0277,0.0060,0.0227,0.0188,0.0236,0.0258,0.0200,0.0200,0.0090,0.0223,0.0422,0.0390, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02,
+
+! Five types, one row for each type (BVOC currently not active).
+ EPS1 = 41.87, 0.00, 0.00, 2.52, 0.04, 17.11, 0.02, 21.62, 0.11, 22.80, 46.86, 0.00, 0.00, 0.46, 30.98, 2.31, 1.63, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+ EPS2 = 0.98, 0.00, 0.00, 0.16, 0.09, 0.28, 0.05, 0.92, 0.22, 0.59, 0.38, 0.00, 0.00, 3.34, 0.96, 1.47, 1.07, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+ EPS3 = 1.82, 0.00, 0.00, 0.23, 0.05, 0.81, 0.03, 1.73, 1.26, 1.37, 1.84, 0.00, 0.00, 1.85, 1.84, 1.70, 1.21, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+ EPS4 = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+ EPS5 = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+/
+
+&modis_veg_categories
+ VEG_DATASET_DESCRIPTION = "modified igbp modis noah"
+ NVEG = 20
+/
+
+&modis_veg_parameters
+! 1 'Evergreen Needleleaf Forest' -> USGS 14
+! 2, 'Evergreen Broadleaf Forest' -> USGS 13
+! 3, 'Deciduous Needleleaf Forest' -> USGS 12
+! 4, 'Deciduous Broadleaf Forest' -> USGS 11
+! 5, 'Mixed Forests' -> USGS 15
+! 6, 'Closed Shrublands' -> USGS 8 "shrubland"
+! 7, 'Open Shrublands' -> USGS 9 "shrubland/grassland"
+! 8, 'Woody Savannas' -> USGS 8 "shrubland"
+! 9, 'Savannas' -> USGS 10
+! 10, 'Grasslands' -> USGS 7
+! 11 'Permanent wetlands' -> avg of USGS 17 and 18 (herb. wooded wetland)
+! 12, 'Croplands' -> USGS 2 "dryland cropland"
+! 13, 'Urban and Built-Up' -> USGS 1
+! 14 'cropland/natural vegetation mosaic' -> USGS 5 "cropland/grassland"
+! 15, 'Snow and Ice' -> USGS 24
+! 16, 'Barren or Sparsely Vegetated' -> USGS 19
+! 17, 'Water' -> USGS 16
+! 18, 'Wooded Tundra' -> USGS 21
+! 19, 'Mixed Tundra' -> USGS 22
+! 20, 'Barren Tundra' -> USGS 23
+
+ ISURBAN = 13
+ ISWATER = 17
+ ISBARREN = 16
+ ISICE = 15
+ ISCROP = 12
+ EBLFOREST = 2
+ NATURAL = 14
+ LCZ_1 = 31
+ LCZ_2 = 32
+ LCZ_3 = 33
+ LCZ_4 = 34
+ LCZ_5 = 35
+ LCZ_6 = 36
+ LCZ_7 = 37
+ LCZ_8 = 38
+ LCZ_9 = 39
+ LCZ_10 = 40
+ LCZ_11 = 41
+ !---------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ ! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+ !---------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CH2OP = 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1,
+ DLEAF = 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04,
+ Z0MVT = 1.09, 1.10, 0.85, 0.80, 0.80, 0.20, 0.06, 0.60, 0.50, 0.12, 0.30, 0.15, 1.00, 0.14, 0.00, 0.00, 0.00, 0.30, 0.20, 0.03,
+ HVT = 20.0, 20.0, 18.0, 16.0, 16.0, 1.10, 1.10, 13.0, 10.0, 1.00, 5.00, 2.00, 15.0, 1.50, 0.00, 0.00, 0.00, 4.00, 2.00, 0.50,
+ HVB = 8.50, 8.00, 7.00, 11.5, 10.0, 0.10, 0.10, 0.10, 0.10, 0.05, 0.10, 0.10, 1.00, 0.10, 0.00, 0.00, 0.00, 0.30, 0.20, 0.10,
+ DEN = 0.28, 0.02, 0.28, 0.10, 0.10, 10.0, 10.0, 10.0, 0.02, 100., 5.05, 25.0, 0.01, 25.0, 0.00, 0.01, 0.01, 1.00, 1.00, 1.00,
+ RC = 1.20, 3.60, 1.20, 1.40, 1.40, 0.12, 0.12, 0.12, 3.00, 0.03, 0.75, 0.08, 1.00, 0.08, 0.00, 0.01, 0.01, 0.30, 0.30, 0.30,
+MFSNO = 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50, 2.50,
+! C. He 12/17/2020: optimized MFSNO values dependent on land type based on evaluation with SNOTEL SWE and MODIS SCF, surface albedo
+! MFSNO = 1.00, 1.00, 1.00, 1.00, 1.00, 2.00, 2.00, 2.00, 2.00, 2.00, 3.00, 3.00, 4.00, 4.00, 2.50, 3.00, 3.00, 3.50, 3.50, 3.50,
+! C. He 12/17/2020: optimized snow cover factor (m) in SCF formulation to replace original constant 2.5*z0,z0=0.002m, based on evaluation with SNOTEL SWE and MODIS SCF, surface albedo
+ SCFFAC = 0.008, 0.008, 0.008, 0.008, 0.008, 0.016, 0.016, 0.020, 0.020, 0.020, 0.020, 0.014, 0.042, 0.026, 0.030, 0.016, 0.030, 0.030, 0.030, 0.030,
+
+ ! Row 1: Vis
+ ! Row 2: Near IR
+ RHOL_VIS=0.07, 0.10, 0.07, 0.10, 0.10, 0.07, 0.07, 0.07, 0.10, 0.11, 0.105, 0.11, 0.00, 0.11, 0.00, 0.00, 0.00, 0.10, 0.10, 0.10,
+ RHOL_NIR=0.35, 0.45, 0.35, 0.45, 0.45, 0.35, 0.35, 0.35, 0.45, 0.58, 0.515, 0.58, 0.00, 0.58, 0.00, 0.00, 0.00, 0.45, 0.45, 0.45,
+
+ ! Row 1: Vis
+ ! Row 2: Near IR
+ RHOS_VIS=0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.16, 0.36, 0.26, 0.36, 0.00, 0.36, 0.00, 0.00, 0.00, 0.16, 0.16, 0.16,
+ RHOS_NIR=0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.39, 0.58, 0.485, 0.58, 0.00, 0.58, 0.00, 0.00, 0.00, 0.39, 0.39, 0.39,
+
+ ! Row 1: Vis
+ ! Row 2: Near IR
+ TAUL_VIS=0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.07, 0.06, 0.07, 0.00, 0.07, 0.00, 0.00, 0.00, 0.05, 0.05, 0.05,
+ TAUL_NIR=0.10, 0.25, 0.10, 0.25, 0.25, 0.10, 0.10, 0.10, 0.25, 0.25, 0.25, 0.25, 0.00, 0.25, 0.00, 0.00, 0.00, 0.25, 0.25, 0.25,
+
+ ! Row 1: Vis
+ ! Row 2: Near IR
+ TAUS_VIS=0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.220, 0.1105, 0.220, 0.000, 0.220, 0.000, 0.000, 0.000, 0.001, 0.001, 0.001,
+ TAUS_NIR=0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.380, 0.1905, 0.380, 0.000, 0.380, 0.000, 0.000, 0.000, 0.001, 0.001, 0.001,
+
+ XL = 0.010, 0.010, 0.010, 0.250, 0.250, 0.010, 0.010, 0.010, 0.010, -0.30, -0.025, -0.30, 0.000, -0.30, 0.000, 0.000, 0.000, 0.250, 0.250, 0.250,
+! make CWPVT vegetation dependent according to J. Goudriaan, Crop Micrometeorology: A Simulation Study (Simulation monographs), 1977). C. He, 12/17/2020
+ CWPVT = 0.18, 0.67, 0.18, 0.67, 0.29, 1.0, 2.0, 1.3, 1.0, 5.0, 1.17, 1.67, 1.67, 1.67, 0.18, 0.18, 0.18, 0.67, 1.0, 0.18,
+ C3PSN = 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
+ KC25 = 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0,
+ AKC = 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1, 2.1,
+ KO25 = 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, 3.E4,
+ AKO = 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2,
+ AVCMX = 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4, 2.4,
+ AQE = 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
+
+ LTOVRC= 0.5, 0.55, 0.2, 0.55, 0.5, 0.65, 0.65, 0.65, 0.65, 0.50, 1.4, 1.6, 0.0, 1.2, 0.0, 0.0, 0.0, 1.3, 1.4, 1.0,
+ DILEFC= 1.20, 0.50, 1.80, 0.60, 0.80, 0.20, 0.20, 0.20, 0.50, 0.20, 0.4, 0.50, 0.00, 0.35, 0.00, 0.00, 0.00, 0.30, 0.40, 0.30,
+ DILEFW= 0.20, 4.00, 0.20, 0.20, 0.20, 0.20, 0.20, 0.20, 0.50, 0.10, 0.2, 0.20, 0.00, 0.20, 0.00, 0.00, 0.00, 0.20, 0.20, 0.20,
+ RMF25 = 3.00, 0.65, 4.00, 3.00, 3.00, 0.26, 0.26, 0.26, 0.80, 1.80, 3.2, 1.00, 0.00, 1.45, 0.00, 0.00, 0.00, 3.00, 3.00, 3.00,
+ SLA = 80, 80, 80, 80, 80, 60, 60, 60, 50, 60, 80, 80, 60, 80, 0, 0, 0, 80, 80, 80,
+ FRAGR = 0.10, 0.20, 0.10, 0.20, 0.10, 0.20, 0.20, 0.20, 0.20, 0.20, 0.1, 0.20, 0.00, 0.20, 0.00, 0.10, 0.00, 0.10, 0.10, 0.10,
+ TMIN = 265, 273, 268, 273, 268, 273, 273, 273, 273, 273, 268, 273, 0, 273, 0, 0, 0, 268, 268, 268,
+ VCMX25= 50.0, 60.0, 60.0, 60.0, 55.0, 40.0, 40.0, 40.0, 40.0, 40.0, 50.0, 80.0, 0.00, 60.0, 0.00, 0.00, 0.00, 50.0, 50.0, 50.0,
+ TDLEF = 278, 278, 268, 278, 268, 278, 278, 278, 278, 278, 268, 278, 278, 278, 0, 0, 0, 268, 268, 268,
+ BP = 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 2.E3, 1.E15, 2.E3, 1.E15, 2.E3, 1.E15, 2.E3, 2.E3, 2.E3,
+ MP = 6., 9., 6., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9., 9.,
+ QE25 = 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.00, 0.06, 0.00, 0.06, 0.00, 0.06, 0.06, 0.06,
+ RMS25 = 0.90, 0.30, 0.64, 0.10, 0.80, 0.10, 0.10, 0.10, 0.32, 0.10, 0.10, 0.10, 0.00, 0.10, 0.00, 0.00, 0.00, 0.10, 0.10, 0.00,
+ RMR25 = 0.36, 0.05, 0.05, 0.01, 0.03, 0.00, 0.00, 0.00, 0.01, 1.20, 0.0, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 2.11, 2.11, 0.00,
+ ARM = 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0,
+ FOLNMX= 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 0.00, 1.5, 0.00, 1.5, 0.00, 1.5, 1.5, 1.5,
+ WDPOOL= 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 0.00, 0.5, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 1.00, 1.00, 0.00,
+ WRRAT = 30.0, 30.0, 30.0, 30.0, 30.0, 3.00, 3.00, 3.00, 3.00, 0.00, 15.0, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 3.00, 3.00, 0.00,
+ MRP = 0.37, 0.23, 0.37, 0.40, 0.30, 0.19, 0.19, 0.19, 0.40, 0.17, 0.285, 0.23, 0.00, 0.23, 0.00, 0.00, 0.00, 0.23, 0.20, 0.00,
+! added (temporarly)
+ SHDFAC= 0.70, 0.95, 0.70, 0.80, 0.80, 0.70, 0.70, 0.70, 0.50, 0.80, 0.60, 0.80, 0.10, 0.80, 0.00, 0.01, 0.00, 0.60, 0.60, 0.30,
+ NROOT = 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 2, 3, 1, 3, 1, 1, 0, 3, 3, 2,
+ RGL = 30.0, 30.0, 30.0, 30.0, 30.0, 100.0, 100.0, 100.0, 65.0, 100.0, 65.0, 100.0, 999.0, 100.0, 999.0, 999.0, 30.0, 100.0, 100.0, 100.0,
+ RS = 125.0, 150.0, 150.0, 100.0, 125.0, 300.0, 170.0, 300.0, 70.0, 40.0, 70.0, 40.0, 200.0, 40.0, 999.0, 999.0, 100.0, 150.0, 150.0, 200.0,
+ HS = 47.35, 41.69, 47.35, 54.53, 51.93, 42.00, 39.18, 42.00, 54.53, 36.35, 55.97, 36.25, 999.0, 36.25, 999.0, 999.0, 51.75, 42.00, 42.00, 42.00,
+ TOPT = 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0, 298.0,
+ RSMAX = 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000., 5000.,
+
+! Monthly values, one row for each month:
+ SAI_JAN = 0.4, 0.5, 0.3, 0.4, 0.4, 0.3, 0.2, 0.4, 0.3, 0.3, 0.3, 0.3, 0.0, 0.3, 0.0, 0.0, 0.0, 0.2, 0.1, 0.0,
+ SAI_FEB = 0.4, 0.5, 0.3, 0.4, 0.4, 0.3, 0.2, 0.4, 0.3, 0.3, 0.3, 0.3, 0.0, 0.3, 0.0, 0.0, 0.0, 0.2, 0.1, 0.0,
+ SAI_MAR = 0.4, 0.5, 0.3, 0.4, 0.4, 0.3, 0.2, 0.4, 0.3, 0.3, 0.3, 0.3, 0.0, 0.3, 0.0, 0.0, 0.0, 0.2, 0.1, 0.0,
+ SAI_APR = 0.3, 0.5, 0.4, 0.4, 0.4, 0.3, 0.2, 0.4, 0.3, 0.3, 0.3, 0.3, 0.0, 0.3, 0.0, 0.0, 0.0, 0.2, 0.1, 0.0,
+ SAI_MAY = 0.4, 0.5, 0.4, 0.4, 0.4, 0.3, 0.2, 0.4, 0.3, 0.3, 0.3, 0.3, 0.0, 0.3, 0.0, 0.0, 0.0, 0.2, 0.1, 0.0,
+ SAI_JUN = 0.5, 0.5, 0.7, 0.4, 0.4, 0.3, 0.2, 0.4, 0.4, 0.4, 0.4, 0.3, 0.0, 0.4, 0.0, 0.0, 0.0, 0.2, 0.2, 0.0,
+ SAI_JUL = 0.5, 0.5, 1.3, 0.9, 0.7, 0.6, 0.4, 0.7, 0.8, 0.8, 0.6, 0.4, 0.0, 0.6, 0.0, 0.0, 0.0, 0.4, 0.4, 0.0,
+ SAI_AUG = 0.6, 0.5, 1.2, 1.2, 0.8, 0.9, 0.6, 1.2, 1.2, 1.3, 0.9, 0.5, 0.0, 0.9, 0.0, 0.0, 0.0, 0.6, 0.6, 0.0,
+ SAI_SEP = 0.6, 0.5, 1.0, 1.6, 1.0, 1.2, 0.8, 1.4, 1.3, 1.1, 0.9, 0.4, 0.0, 0.7, 0.0, 0.0, 0.0, 0.8, 0.7, 0.0,
+ SAI_OCT = 0.7, 0.5, 0.8, 1.4, 1.0, 0.9, 0.7, 1.1, 0.7, 0.4, 0.6, 0.3, 0.0, 0.3, 0.0, 0.0, 0.0, 0.7, 0.5, 0.0,
+ SAI_NOV = 0.6, 0.5, 0.6, 0.6, 0.5, 0.4, 0.3, 0.5, 0.4, 0.4, 0.4, 0.3, 0.0, 0.3, 0.0, 0.0, 0.0, 0.3, 0.3, 0.0,
+ SAI_DEC = 0.5, 0.5, 0.5, 0.4, 0.4, 0.3, 0.2, 0.4, 0.4, 0.4, 0.3, 0.3, 0.0, 0.3, 0.0, 0.0, 0.0, 0.2, 0.2, 0.0,
+
+ LAI_JAN = 4.0, 4.5, 0.0, 0.0, 2.0, 0.0, 0.0, 0.2, 0.3, 0.4, 0.2, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 1.0, 0.6, 0.0,
+ LAI_FEB = 4.0, 4.5, 0.0, 0.0, 2.0, 0.0, 0.0, 0.2, 0.3, 0.5, 0.3, 0.0, 0.0, 0.3, 0.0, 0.0, 0.0, 1.0, 0.6, 0.0,
+ LAI_MAR = 4.0, 4.5, 0.0, 0.3, 2.2, 0.3, 0.2, 0.4, 0.5, 0.6, 0.3, 0.0, 0.0, 0.3, 0.0, 0.0, 0.0, 1.1, 0.7, 0.0,
+ LAI_APR = 4.0, 4.5, 0.6, 1.2, 2.6, 0.9, 0.6, 1.0, 0.8, 0.7, 0.5, 0.0, 0.0, 0.4, 0.0, 0.0, 0.0, 1.3, 0.8, 0.0,
+ LAI_MAY = 4.0, 4.5, 1.2, 3.0, 3.5, 2.2, 1.5, 2.4, 1.8, 1.2, 1.5, 1.0, 0.0, 1.1, 0.0, 0.0, 0.0, 1.7, 1.2, 0.0,
+ LAI_JUN = 4.0, 4.5, 2.0, 4.7, 4.3, 3.5, 2.3, 4.1, 3.6, 3.0, 2.9, 2.0, 0.0, 2.5, 0.0, 0.0, 0.0, 2.1, 1.8, 0.0,
+ LAI_JUL = 4.0, 4.5, 2.6, 4.5, 4.3, 3.5, 2.3, 4.1, 3.8, 3.5, 3.5, 3.0, 0.0, 3.2, 0.0, 0.0, 0.0, 2.1, 1.8, 0.0,
+ LAI_AUG = 4.0, 4.5, 1.7, 3.4, 3.7, 2.5, 1.7, 2.7, 2.1, 1.5, 2.7, 3.0, 0.0, 2.2, 0.0, 0.0, 0.0, 1.8, 1.3, 0.0,
+ LAI_SEP = 4.0, 4.5, 1.0, 1.2, 2.6, 0.9, 0.6, 1.0, 0.9, 0.7, 1.2, 1.5, 0.0, 1.1, 0.0, 0.0, 0.0, 1.3, 0.8, 0.0,
+ LAI_OCT = 4.0, 4.5, 0.5, 0.3, 2.2, 0.3, 0.2, 0.4, 0.5, 0.6, 0.3, 0.0, 0.0, 0.3, 0.0, 0.0, 0.0, 1.1, 0.7, 0.0,
+ LAI_NOV = 4.0, 4.5, 0.2, 0.0, 2.0, 0.0, 0.0, 0.2, 0.3, 0.5, 0.3, 0.0, 0.0, 0.3, 0.0, 0.0, 0.0, 1.0, 0.6, 0.0,
+ LAI_DEC = 4.0, 4.5, 0.0, 0.0, 2.0, 0.0, 0.0, 0.2, 0.3, 0.4, 0.2, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 1.0, 0.6, 0.0,
+
+ SLAREA=0.0090, 0.0200, 0.0200, 0.0258, 0.0223, 0.0227, 0.0188, 0.0227, 0.0236, 0.0060, 0.0295, 0.0200, 0.0228, 0.0223, 0.02, 0.02, 0.0422, 0.02, 0.02, 0.02,
+
+! Five types, one row for each type (BVOC currently not active).
+ EPS1 = 0.46, 0.00, 0.00, 46.86, 30.98, 21.62, 0.11, 21.62, 22.80, 0.02, 0.815, 0.00, 41.87, 0.04, 0.0, 0.0, 2.31, 0.0, 0.0, 0.0,
+ EPS2 = 3.34, 0.00, 0.00, 0.38, 0.96, 0.92, 0.22, 0.92, 0.59, 0.05, 0.535, 0.00, 0.98, 0.09, 0.0, 0.0, 1.47, 0.0, 0.0, 0.0,
+ EPS3 = 1.85, 0.00, 0.00, 1.84, 1.84, 1.73, 1.26, 1.73, 1.37, 0.03, 0.605, 0.00, 1.82, 0.05, 0.0, 0.0, 1.70, 0.0, 0.0, 0.0,
+ EPS4 = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+ EPS5 = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+
+/
+
+&rad_parameters
+ !------------------------------------------------------------------------------
+ ! 1 2 3 4 5 6 7 8 soil color index for soil albedo
+ !------------------------------------------------------------------------------
+ ALBSAT_VIS = 0.15, 0.11, 0.10, 0.09, 0.08, 0.07, 0.06, 0.05 ! saturated soil albedos
+ ALBSAT_NIR = 0.30, 0.22, 0.20, 0.18, 0.16, 0.14, 0.12, 0.10 ! saturated soil albedos
+ ALBDRY_VIS = 0.27, 0.22, 0.20, 0.18, 0.16, 0.14, 0.12, 0.10 ! dry soil albedos
+ ALBDRY_NIR = 0.54, 0.44, 0.40, 0.36, 0.32, 0.28, 0.24, 0.20 ! dry soil albedos
+ ALBICE = 0.80, 0.55 ! albedo land ice: 1=vis, 2=nir
+ ALBLAK = 0.60, 0.40 ! albedo frozen lakes: 1=vis, 2=nir
+ OMEGAS = 0.8 , 0.4 ! two-stream parameter omega for snow
+ BETADS = 0.5 ! two-stream parameter betad for snow
+ BETAIS = 0.5 ! two-stream parameter betaI for snow
+ EG = 0.97, 0.98 ! emissivity soil surface 1-soil;2-lake
+
+/
+
+&global_parameters
+
+! atmospheric constituants
+
+ CO2 = 395.e-06 !co2 partial pressure
+ O2 = 0.209 !o2 partial pressure
+
+! runoff parameters used for SIMTOP and SIMGM:
+
+ TIMEAN = 10.5 !gridcell mean topgraphic index (global mean)
+ FSATMX = 0.38 !maximum surface saturated fraction (global mean)
+
+! adjustable parameters for snow processes
+
+ Z0SNO = 0.002 !snow surface roughness length (m) (0.002)
+ SSI = 0.03 !liquid water holding capacity for snowpack (m3/m3) (0.03)
+ SNOW_RET_FAC = 5.e-5 !snowpack water release timescale factor (1/s)
+ SNOW_EMIS = 0.95 !snow emissivity (bring from hard-coded value of 1.0 to here)
+ SWEMX = 1.00 !new snow mass to fully cover old snow (mm)
+ !equivalent to 10mm depth (density = 100 kg/m3)
+ TAU0 = 1.e6 !tau0 from Yang97 eqn. 10a
+ GRAIN_GROWTH = 5000. !growth from vapor diffusion Yang97 eqn. 10b
+ EXTRA_GROWTH = 10. !extra growth near freezing Yang97 eqn. 10c
+ DIRT_SOOT = 0.3 !dirt and soot term Yang97 eqn. 10d
+ BATS_COSZ = 2.0 !zenith angle snow albedo adjustment; b in Yang97 eqn. 15
+ BATS_VIS_NEW = 0.95 !new snow visible albedo
+ BATS_NIR_NEW = 0.65 !new snow NIR albedo
+ BATS_VIS_AGE = 0.2 !age factor for diffuse visible snow albedo Yang97 eqn. 17
+ BATS_NIR_AGE = 0.5 !age factor for diffuse NIR snow albedo Yang97 eqn. 18
+ BATS_VIS_DIR = 0.4 !cosz factor for direct visible snow albedo Yang97 eqn. 15
+ BATS_NIR_DIR = 0.4 !cosz factor for direct NIR snow albedo Yang97 eqn. 16
+ RSURF_SNOW = 50.0 !surface resistence for snow [s/m]
+ RSURF_EXP = 5.0 !exponent in the shape parameter for soil resistance option 1
+
+/
+
+&irrigation_parameters
+IRR_FRAC = 0.10 ! irrigation Fraction
+IRR_HAR = 20 ! number of days before harvest date to stop irrigation
+IRR_LAI = 0.50 ! Minimum lai to trigger irrigation
+IRR_MAD = 0.60 ! management allowable deficit (0-1)
+FILOSS = 0.10 ! fraction of flood irrigation loss (0-1)
+SPRIR_RATE = 6.40 ! mm/h, sprinkler irrigation rate
+MICIR_RATE = 1.38 ! mm/h, micro irrigation rate
+FIRTFAC = 1.00 ! flood application rate factor
+IR_RAIN = 1.00 ! maximum precipitation to stop irrigation trigger
+/
+
+&crop_parameters
+
+ ! NCROP = 5
+ ! 1: Corn
+ ! 2: Soybean
+ ! 3: Sorghum
+ ! 4: Rice
+ ! 5: Winter wheat
+
+DEFAULT_CROP = 0 ! The default crop type(1-5); if zero, use generic dynamic vegetation
+
+!----------------------------------------------------------
+! 1 2 3 4 5
+!----------------------------------------------------------
+
+PLTDAY = 111, 131, 111, 111, 111, ! Planting date
+HSDAY = 300, 280, 300, 300, 300, ! Harvest date
+PLANTPOP = 78.0, 78.0, 78.0, 78.0, 78.0, ! Plant density [per ha] - used?
+IRRI = 0.0, 0.0, 0.0, 0.0, 0.0, ! Irrigation strategy 0= non-irrigation 1=irrigation (no water-stress)
+
+GDDTBASE = 10.0, 10.0, 10.0, 10.0, 10.0, ! Base temperature for GDD accumulation [C]
+GDDTCUT = 30.0, 30.0, 30.0, 30.0, 30.0, ! Upper temperature for GDD accumulation [C]
+GDDS1 = 50.0, 60.0, 50.0, 50.0, 50.0, ! GDD from seeding to emergence
+GDDS2 = 625.0, 675.0, 718.0, 718.0, 718.0, ! GDD from seeding to initial vegetative
+GDDS3 = 933.0, 1183.0, 933.0, 933.0, 933.0, ! GDD from seeding to post vegetative
+GDDS4 = 1103.0, 1253.0, 1103.0, 1103.0, 1103.0, ! GDD from seeding to intial reproductive
+GDDS5 = 1555.0, 1605.0, 1555.0, 1555.0, 1555.0, ! GDD from seeding to pysical maturity
+C3PSN = 0.0, 1.0, 1.0, 1.0, 1.0, ! transfer crop-specific photosynthetic parameters
+KC25 = 30.0, 30.0, 30.0, 30.0, 30.0, ! Zhe Zhang
+AKC = 2.1, 2.1, 2.1, 2.1, 2.1, ! 2020-02-05
+KO25 = 3.E4, 3.E4, 3.E4, 3.E4, 3.E4, !
+AKO = 1.2, 1.2, 1.2, 1.2, 1.2, !
+AVCMX = 2.4, 2.4, 2.4, 2.4, 2.4, !
+VCMX25 = 60.0, 80.0, 60.0, 60.0, 55.0, !
+BP = 4.E4, 1.E4, 2.E3, 2.E3, 2.E3, !
+MP = 4., 9., 6., 9., 9., !
+FOLNMX = 1.5, 1.5, 1.5, 1.5, 1.5, !
+QE25 = 0.05, 0.06, 0.06, 0.06, 0.06, !
+C3C4 = 2, 1, 2, 2, 2, ! photosynthetic pathway: 1. = c3 2. = c4
+Aref = 7.0, 7.0, 7.0, 7.0, 7.0, ! reference maximum CO2 assimulation rate
+PSNRF = 0.85, 0.85, 0.85, 0.85, 0.85, ! CO2 assimulation reduction factor(0-1) (caused by non-modeling part,e.g.pest,weeds)
+I2PAR = 0.5, 0.5, 0.5, 0.5, 0.5, ! Fraction of incoming solar radiation to photosynthetically active radiation
+TASSIM0 = 8.0, 8.0, 8.0, 8.0, 8.0, ! Minimum temperature for CO2 assimulation [C]
+TASSIM1 = 18.0, 18.0, 18.0, 18.0, 18.0, ! CO2 assimulation linearly increasing until temperature reaches T1 [C]
+TASSIM2 = 30.0, 30.0, 30.0, 30.0, 30.0, ! CO2 assmilation rate remain at Aref until temperature reaches T2 [C]
+K = 0.55, 0.55, 0.55, 0.55, 0.55, ! light extinction coefficient
+EPSI = 12.5, 12.5, 12.5, 12.5, 12.5, ! initial light use efficiency
+
+Q10MR = 2.0, 2.0, 2.0, 2.0, 2.0, ! q10 for maintainance respiration
+FOLN_MX = 1.5, 1.5, 1.5, 1.5, 1.5, ! foliage nitrogen concentration when f(n)=1 (%)
+LEFREEZ = 268, 268, 268, 268, 268, ! characteristic T for leaf freezing [K]
+
+DILE_FC_S1 = 0.0, 0.0, 0.0, 0.0, 0.0, ! coeficient for temperature leaf stress death [1/s]
+DILE_FC_S2 = 0.0, 0.0, 0.0, 0.0, 0.0, ! One row for each of 8 stages
+DILE_FC_S3 = 0.0, 0.0, 0.0, 0.0, 0.0,
+DILE_FC_S4 = 0.0, 0.0, 0.0, 0.0, 0.0,
+DILE_FC_S5 = 0.5, 0.5, 0.5, 0.5, 0.5,
+DILE_FC_S6 = 0.5, 0.5, 0.5, 0.5, 0.5,
+DILE_FC_S7 = 0.0, 0.0, 0.0, 0.0, 0.0,
+DILE_FC_S8 = 0.0, 0.0, 0.0, 0.0, 0.0,
+
+DILE_FW_S1 = 0.0, 0.0, 0.0, 0.0, 0.0, ! coeficient for water leaf stress death [1/s]
+DILE_FW_S2 = 0.0, 0.0, 0.0, 0.0, 0.0, ! One row for each of 8 stages
+DILE_FW_S3 = 0.0, 0.0, 0.0, 0.0, 0.0,
+DILE_FW_S4 = 0.0, 0.0, 0.0, 0.0, 0.0,
+DILE_FW_S5 = 0.2, 0.2, 0.2, 0.2, 0.2,
+DILE_FW_S6 = 0.2, 0.2, 0.2, 0.2, 0.2,
+DILE_FW_S7 = 0.0, 0.0, 0.0, 0.0, 0.0,
+DILE_FW_S8 = 0.0, 0.0, 0.0, 0.0, 0.0,
+
+FRA_GR = 0.2, 0.2, 0.2, 0.2, 0.2, ! fraction of growth respiration
+
+LF_OVRC_S1 = 0.0, 0.0, 0.0, 0.0, 0.0, ! fraction of leaf turnover [1/s]
+LF_OVRC_S2 = 0.0, 0.0, 0.0, 0.0, 0.0, ! One row for each of 8 stages
+LF_OVRC_S3 = 0.0, 0.0, 0.0, 0.0, 0.0,
+LF_OVRC_S4 = 0.0, 0.0, 0.0, 0.0, 0.0,
+LF_OVRC_S5 = 0.2, 0.2, 0.48, 0.48, 0.48,
+LF_OVRC_S6 = 0.3, 0.3, 0.48, 0.48, 0.48,
+LF_OVRC_S7 = 0.0, 0.0, 0.0, 0.0, 0.0,
+LF_OVRC_S8 = 0.0, 0.0, 0.0, 0.0, 0.0,
+
+ST_OVRC_S1 = 0.0, 0.0, 0.0, 0.0, 0.0, ! fraction of stem turnover [1/s]
+ST_OVRC_S2 = 0.0, 0.0, 0.0, 0.0, 0.0, ! One row for each of 8 stages
+ST_OVRC_S3 = 0.0, 0.0, 0.0, 0.0, 0.0,
+ST_OVRC_S4 = 0.0, 0.0, 0.0, 0.0, 0.0,
+ST_OVRC_S5 = 0.2, 0.12, 0.12, 0.12, 0.12,
+ST_OVRC_S6 = 0.3, 0.06, 0.06, 0.06, 0.06,
+ST_OVRC_S7 = 0.0, 0.0, 0.0, 0.0, 0.0,
+ST_OVRC_S8 = 0.0, 0.0, 0.0, 0.0, 0.0,
+
+RT_OVRC_S1 = 0.0, 0.0, 0.0, 0.0, 0.0, ! fraction of root tunrover [1/s]
+RT_OVRC_S2 = 0.0, 0.0, 0.0, 0.0, 0.0, ! One row for each of 8 stages
+RT_OVRC_S3 = 0.0, 0.0, 0.0, 0.0, 0.0,
+RT_OVRC_S4 = 0.0, 0.0, 0.0, 0.0, 0.0,
+RT_OVRC_S5 = 0.12, 0.12, 0.12, 0.12, 0.12,
+RT_OVRC_S6 = 0.06, 0.06, 0.06, 0.06, 0.06,
+RT_OVRC_S7 = 0.0, 0.0, 0.0, 0.0, 0.0,
+RT_OVRC_S8 = 0.0, 0.0, 0.0, 0.0, 0.0,
+
+LFMR25 = 0.8, 1.0, 1.0, 1.0, 1.0, ! leaf maintenance respiration at 25C [umol CO2/m**2 /s]
+STMR25 = 0.05, 0.05, 0.1, 0.1, 0.1, ! stem maintenance respiration at 25C [umol CO2/kg bio/s]
+RTMR25 = 0.05, 0.05, 0.0, 0.0, 0.0, ! root maintenance respiration at 25C [umol CO2/kg bio/s]
+GRAINMR25 = 0.0, 0.0, 0.1, 0.1, 0.1, ! grain maintenance respiration at 25C [umol CO2/kg bio/s]
+
+LFPT_S1 = 0.0, 0.0, 0.0, 0.0, 0.0, ! fraction of carbohydrate flux to leaf
+LFPT_S2 = 0.0, 0.0, 0.0, 0.0, 0.0, ! One row for each of 8 stages
+LFPT_S3 = 0.36, 0.4, 0.4, 0.4, 0.4,
+LFPT_S4 = 0.1, 0.2, 0.2, 0.2, 0.2,
+LFPT_S5 = 0.0, 0.0, 0.0, 0.0, 0.0,
+LFPT_S6 = 0.0, 0.0, 0.0, 0.0, 0.0,
+LFPT_S7 = 0.0, 0.0, 0.0, 0.0, 0.0,
+LFPT_S8 = 0.0, 0.0, 0.0, 0.0, 0.0,
+
+STPT_S1 = 0.0, 0.0, 0.0, 0.0, 0.0, ! fraction of carbohydrate flux to stem
+STPT_S2 = 0.0, 0.0, 0.0, 0.0, 0.0, ! One row for each of 8 stages
+STPT_S3 = 0.24, 0.2, 0.2, 0.2, 0.2,
+STPT_S4 = 0.6, 0.5, 0.5, 0.5, 0.5,
+STPT_S5 = 0.0, 0.0, 0.15, 0.15, 0.15,
+STPT_S6 = 0.0, 0.0, 0.05, 0.05, 0.05,
+STPT_S7 = 0.0, 0.0, 0.0, 0.0, 0.0,
+STPT_S8 = 0.0, 0.0, 0.0, 0.0, 0.0,
+
+RTPT_S1 = 0.0, 0.0, 0.0, 0.0, 0.0, ! fraction of carbohydrate flux to root
+RTPT_S2 = 0.0, 0.0, 0.0, 0.0, 0.0, ! One row for each of 8 stages
+RTPT_S3 = 0.4, 0.4, 0.4, 0.4, 0.4,
+RTPT_S4 = 0.3, 0.3, 0.3, 0.3, 0.3,
+RTPT_S5 = 0.05, 0.05, 0.05, 0.05, 0.05,
+RTPT_S6 = 0.0, 0.0, 0.05, 0.05, 0.05,
+RTPT_S7 = 0.0, 0.0, 0.0, 0.0, 0.0,
+RTPT_S8 = 0.0, 0.0, 0.0, 0.0, 0.0,
+
+GRAINPT_S1 = 0.0, 0.0, 0.0, 0.0, 0.0, ! fraction of carbohydrate flux to grain
+GRAINPT_S2 = 0.0, 0.0, 0.0, 0.0, 0.0, ! One row for each of 8 stages
+GRAINPT_S3 = 0.0, 0.0, 0.0, 0.0, 0.0,
+GRAINPT_S4 = 0.0, 0.0, 0.0, 0.0, 0.0,
+GRAINPT_S5 = 0.95, 0.95, 0.8, 0.8, 0.8,
+GRAINPT_S6 = 1.0, 1.0, 0.9, 0.9, 0.9,
+GRAINPT_S7 = 0.0, 0.0, 0.0, 0.0, 0.0,
+GRAINPT_S8 = 0.0, 0.0, 0.0, 0.0, 0.0,
+
+LFCT_S1 = 0.0, 0.0, 0.0, 0.0, 0.0, ! carbohydrate translocation
+LFCT_S2 = 0.0, 0.0, 0.0, 0.0, 0.0,
+LFCT_S3 = 0.0, 0.0, 0.4, 0.4, 0.4,
+LFCT_S4 = 0.0, 0.0, 0.3, 0.3, 0.3,
+LFCT_S5 = 0.0, 0.0, 0.05, 0.05, 0.05,
+LFCT_S6 = 0.0, 0.0, 0.05, 0.05, 0.05,
+LFCT_S7 = 0.0, 0.0, 0.0, 0.0, 0.0,
+LFCT_S8 = 0.0, 0.0, 0.0, 0.0, 0.0,
+
+STCT_S1 = 0.0, 0.0, 0.0, 0.0, 0.0, ! carbohydrate translocation
+STCT_S2 = 0.0, 0.0, 0.0, 0.0, 0.0,
+STCT_S3 = 0.0, 0.0, 0.4, 0.4, 0.4,
+STCT_S4 = 0.0, 0.0, 0.3, 0.3, 0.3,
+STCT_S5 = 0.0, 0.0, 0.05, 0.05, 0.05,
+STCT_S6 = 0.0, 0.0, 0.05, 0.05, 0.05,
+STCT_S7 = 0.0, 0.0, 0.0, 0.0, 0.0,
+STCT_S8 = 0.0, 0.0, 0.0, 0.0, 0.0,
+
+RTCT_S1 = 0.0, 0.0, 0.0, 0.0, 0.0, ! carbohydrate translocation
+RTCT_S2 = 0.0, 0.0, 0.0, 0.0, 0.0,
+RTCT_S3 = 0.0, 0.0, 0.4, 0.4, 0.4,
+RTCT_S4 = 0.0, 0.0, 0.3, 0.3, 0.3,
+RTCT_S5 = 0.0, 0.0, 0.05, 0.05, 0.05,
+RTCT_S6 = 0.0, 0.0, 0.05, 0.05, 0.05,
+RTCT_S7 = 0.0, 0.0, 0.0, 0.0, 0.0,
+RTCT_S8 = 0.0, 0.0, 0.0, 0.0, 0.0,
+
+BIO2LAI = 0.015, 0.030, 0.015, 0.015, 0.015, ! leaf are per living leaf biomass [m^2/kg]
+
+/
+
+&tiledrain_parameters
+!-----------------------------------!
+! For simple drainage model !
+!-----------------------------------!
+DRAIN_LAYER_OPT = 4
+ ! 0 - from one specified layer by TD_DEPTH,
+ ! 1 - from layers 1 & 2,
+ ! 2 - from layer layers 1, 2, and 3
+ ! 3 - from layer 2 and 3
+ ! 4 - from layer layers 3, 4
+ ! 5 - from all the four layers
+!-------------------------------------------------------------------------------------------------------------------------------------------------------------------- !
+! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 !
+!-------------------------------------------------------------------------------------------------------------------------------------------------------------------- !
+TDSMC_FAC = 0.90, 0.90, 0.90, 0.90, 0.90, 1.25, 0.90, 1.0, 0.90, 0.90, 0.90, 0.90, 0.90, 0.90, 0.90, 0.90, 0.90, 0.90, 0.90 ! corresponds to number of soil types SOILPARAM.TBL
+TD_DEPTH = 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ! depth of drain tube from the soil surface
+TD_DC = 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20., 20. ! drainage coefficient (mm d^-1)
+!-------------------------------------------------------------------------------------------------------------------------------------------------------------------- !
+!
+!-------------------------------------!
+! For Hooghoudt tile drain model !
+!-------------------------------------!
+!--------------------------------------------------------------------------------------------------------------------------------------------------------------------
+TD_DCOEF = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07 ! m d^-1, drainage coefficent
+TD_D = 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 ! m, depth to impe layer from drain water level (D)
+TD_ADEPTH = 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00 ! m, actual depth of imp layer from land surface
+TD_RADI = 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07 ! m, effective radius of drains (ro)
+TD_SPAC = 60.0, 55.0, 45.0, 20.0, 25.0, 30.0, 40.0, 16.0, 18.0, 50.0, 15.0, 10.0, 35.0, 10.0, 60.0, 60.0, 10.0, 60.0, 60.0 ! m, distance between two drain tubes or tiles (L)
+TD_DDRAIN = 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20, 1.20 ! m, Depth of drain
+KLAT_FAC = 1.30, 1.80, 2.10, 2.60, 2.90, 2.50, 2.30, 3.00, 2.70, 2.00, 3.10, 3.30, 2.50, 1.00, 1.00, 1.80, 4.00, 1.00, 1.30 ! multiplication factor to lateral hyd.cond
+!--------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+/
+
+&optional_parameters
+
+ !------------------------------------------------------------------------------
+ ! Saxton and Rawls 2006 Pedo-transfer function coefficients
+ !------------------------------------------------------------------------------
+
+ sr2006_theta_1500t_a = -0.024 ! sand coefficient
+ sr2006_theta_1500t_b = 0.487 ! clay coefficient
+ sr2006_theta_1500t_c = 0.006 ! orgm coefficient
+ sr2006_theta_1500t_d = 0.005 ! sand*orgm coefficient
+ sr2006_theta_1500t_e = -0.013 ! clay*orgm coefficient
+ sr2006_theta_1500t_f = 0.068 ! sand*clay coefficient
+ sr2006_theta_1500t_g = 0.031 ! constant adjustment
+
+ sr2006_theta_1500_a = 0.14 ! theta_1500t coefficient
+ sr2006_theta_1500_b = -0.02 ! constant adjustment
+
+ sr2006_theta_33t_a = -0.251 ! sand coefficient
+ sr2006_theta_33t_b = 0.195 ! clay coefficient
+ sr2006_theta_33t_c = 0.011 ! orgm coefficient
+ sr2006_theta_33t_d = 0.006 ! sand*orgm coefficient
+ sr2006_theta_33t_e = -0.027 ! clay*orgm coefficient
+ sr2006_theta_33t_f = 0.452 ! sand*clay coefficient
+ sr2006_theta_33t_g = 0.299 ! constant adjustment
+
+ sr2006_theta_33_a = 1.283 ! theta_33t*theta_33t coefficient
+ sr2006_theta_33_b = -0.374 ! theta_33t coefficient
+ sr2006_theta_33_c = -0.015 ! constant adjustment
+
+ sr2006_theta_s33t_a = 0.278 ! sand coefficient
+ sr2006_theta_s33t_b = 0.034 ! clay coefficient
+ sr2006_theta_s33t_c = 0.022 ! orgm coefficient
+ sr2006_theta_s33t_d = -0.018 ! sand*orgm coefficient
+ sr2006_theta_s33t_e = -0.027 ! clay*orgm coefficient
+ sr2006_theta_s33t_f = -0.584 ! sand*clay coefficient
+ sr2006_theta_s33t_g = 0.078 ! constant adjustment
+
+ sr2006_theta_s33_a = 0.636 ! theta_s33t coefficient
+ sr2006_theta_s33_b = -0.107 ! constant adjustment
+
+ sr2006_psi_et_a = -21.67 ! sand coefficient
+ sr2006_psi_et_b = -27.93 ! clay coefficient
+ sr2006_psi_et_c = -81.97 ! theta_s33 coefficient
+ sr2006_psi_et_d = 71.12 ! sand*theta_s33 coefficient
+ sr2006_psi_et_e = 8.29 ! clay*theta_s33 coefficient
+ sr2006_psi_et_f = 14.05 ! sand*clay coefficient
+ sr2006_psi_et_g = 27.16 ! constant adjustment
+
+ sr2006_psi_e_a = 0.02 ! psi_et*psi_et coefficient
+ sr2006_psi_e_b = -0.113 ! psi_et coefficient
+ sr2006_psi_e_c = -0.7 ! constant adjustment
+
+ sr2006_smcmax_a = -0.097 ! sand adjustment
+ sr2006_smcmax_b = 0.043 ! constant adjustment
+
+/
+
diff --git a/python/runCalibValid/ngen_conf/tests/data/NOAH/parameters/SOILPARM.TBL b/python/runCalibValid/ngen_conf/tests/data/NOAH/parameters/SOILPARM.TBL
new file mode 100644
index 00000000..c5a97c95
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/data/NOAH/parameters/SOILPARM.TBL
@@ -0,0 +1,45 @@
+Soil Parameters
+STAS
+19,1 'BB DRYSMC F11 MAXSMC REFSMC SATPSI SATDK SATDW WLTSMC QTZ BVIC AXAJ BXAJ XXAJ BDVIC BBVIC GDVIC '
+1, 2.79, 0.010, -0.472, 0.339, 0.192, 0.069, 4.66E-5, 2.65E-5, 0.010, 0.92, 0.05, 0.009, 0.05, 0.05, 0.05, 1.000, 0.050, 'SAND'
+2, 4.26, 0.028, -1.044, 0.421, 0.283, 0.036, 1.41E-5, 5.14E-6, 0.028, 0.82, 0.08, 0.010, 0.08, 0.08, 0.08, 1.010, 0.070, 'LOAMY SAND'
+3, 4.74, 0.047, -0.569, 0.434, 0.312, 0.141, 5.23E-6, 8.05E-6, 0.047, 0.60, 0.09, 0.009, 0.09, 0.09, 0.09, 1.020, 0.130, 'SANDY LOAM'
+4, 5.33, 0.084, 0.162, 0.476, 0.360, 0.759, 2.81E-6, 2.39E-5, 0.084, 0.25, 0.25, 0.010, 0.25, 0.25, 0.25, 1.025, 0.200, 'SILT LOAM'
+5, 3.86, 0.061, 0.162, 0.484, 0.347, 0.955, 2.18E-6, 1.66E-5, 0.061, 0.10, 0.15, 0.012, 0.15, 0.15, 0.15, 1.000, 0.170, 'SILT'
+6, 5.25, 0.066, -0.327, 0.439, 0.329, 0.355, 3.38E-6, 1.43E-5, 0.066, 0.40, 0.18, 0.013, 0.18, 0.18, 0.18, 1.000, 0.110, 'LOAM'
+7, 6.77, 0.069, -1.491, 0.404, 0.315, 0.135, 4.45E-6, 1.01E-5, 0.069, 0.60, 0.20, 0.014, 0.20, 0.20, 0.20, 1.032, 0.260, 'SANDY CLAY LOAM'
+8, 8.72, 0.120, -1.118, 0.464, 0.387, 0.617, 2.03E-6, 2.35E-5, 0.120, 0.10, 0.22, 0.015, 0.22, 0.22, 0.22, 1.035, 0.350, 'SILTY CLAY LOAM'
+9, 8.17, 0.103, -1.297, 0.465, 0.382, 0.263, 2.45E-6, 1.13E-5, 0.103, 0.35, 0.23, 0.016, 0.23, 0.23, 0.23, 1.040, 0.260, 'CLAY LOAM'
+10, 10.73, 0.100, -3.209, 0.406, 0.338, 0.098, 7.22E-6, 1.87E-5, 0.100, 0.52, 0.25, 0.015, 0.25, 0.25, 0.25, 1.042, 0.300, 'SANDY CLAY'
+11, 10.39, 0.126, -1.916, 0.468, 0.404, 0.324, 1.34E-6, 9.64E-6, 0.126, 0.10, 0.28, 0.016, 0.28, 0.28, 0.28, 1.045, 0.380, 'SILTY CLAY'
+12, 11.55, 0.138, -2.138, 0.468, 0.412, 0.468, 9.74E-7, 1.12E-5, 0.138, 0.25, 0.30, 0.017, 0.30, 0.30, 0.30, 1.000, 0.410, 'CLAY'
+13, 5.25, 0.066, -0.327, 0.439, 0.329, 0.355, 3.38E-6, 1.43E-5, 0.066, 0.05, 0.26, 0.012, 0.26, 0.26, 0.26, 1.000, 0.500, 'ORGANIC MATERIAL'
+14, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.60, 0.00, 0.001, 0.00, 0.00, 0.00, 1.000, 0.001, 'WATER'
+15, 2.79, 0.006, -1.111, 0.20, 0.17, 0.069, 1.41E-4, 1.36E-4, 0.006, 0.07, 1.00, 0.017, 1.00, 1.00, 1.00, 1.000, 0.010, 'BEDROCK'
+16, 4.26, 0.028, -1.044, 0.421, 0.283, 0.036, 1.41E-5, 5.14E-6, 0.028, 0.25, 1.00, 0.017, 1.00, 1.00, 1.00, 1.000, 0.001, 'OTHER(land-ice)'
+17, 11.55, 0.030, -10.472, 0.468, 0.454, 0.468, 9.74E-7, 1.12E-5, 0.030, 0.60, 1.00, 0.017, 1.00, 1.00, 1.00, 1.000, 0.001, 'PLAYA'
+18, 2.79, 0.006, -0.472, 0.200, 0.17, 0.069, 1.41E-4, 1.36E-4, 0.006, 0.52, 0.35, 0.015, 0.35, 0.35, 0.35, 1.000, 0.050, 'LAVA'
+19, 2.79, 0.01, -0.472, 0.339, 0.192, 0.069, 4.66E-5, 2.65E-5, 0.01, 0.92, 0.15, 0.009, 0.15, 0.15, 0.15, 1.000, 0.020, 'WHITE SAND'
+Soil Parameters
+STAS-RUC
+19,1 'BB DRYSMC HC MAXSMC REFSMC SATPSI SATDK SATDW WLTSMC QTZ BVIC AXAJ BXAJ XXAJ BDVIC BBVIC GDVIC '
+1, 4.05, 0.002, 1.47, 0.395, 0.174, 0.121, 1.76E-4, 0.608E-6, 0.033, 0.92, 0.05, 0.009, 0.05, 0.05, 0.05, 1.000, 0.050, 'SAND'
+2, 4.38, 0.035, 1.41, 0.410, 0.179, 0.090, 1.56E-4, 0.514E-5, 0.055, 0.82, 0.08, 0.010, 0.08, 0.08, 0.08, 1.010, 0.070, 'LOAMY SAND'
+3, 4.90, 0.041, 1.34, 0.435, 0.249, 0.218, 3.47E-5, 0.805E-5, 0.095, 0.60, 0.09, 0.009, 0.09, 0.09, 0.09, 1.020, 0.130, 'SANDY LOAM'
+4, 5.30, 0.034, 1.27, 0.485, 0.369, 0.786, 7.20E-6, 0.239E-4, 0.143, 0.25, 0.10, 0.010, 0.25, 0.25, 0.10, 1.025, 0.200, 'SILT LOAM'
+5, 5.30, 0.034, 1.27, 0.485, 0.369, 0.786, 7.20E-6, 0.239E-4, 0.143, 0.10, 0.15, 0.012, 0.15, 0.15, 0.15, 1.000, 0.170, 'SILT'
+6, 5.39, 0.050, 1.21, 0.451, 0.314, 0.478, 6.95E-6, 0.143E-4, 0.137, 0.40, 0.18, 0.013, 0.18, 0.18, 0.18, 1.000, 0.110, 'LOAM'
+7, 7.12, 0.068, 1.18, 0.420, 0.299, 0.299, 6.30E-6, 0.990E-5, 0.148, 0.60, 0.20, 0.014, 0.20, 0.20, 0.20, 1.032, 0.260, 'SANDY CLAY LOAM'
+8, 7.75, 0.060, 1.32, 0.477, 0.357, 0.356, 1.70E-6, 0.237E-4, 0.170, 0.10, 0.22, 0.015, 0.22, 0.22, 0.22, 1.035, 0.350, 'SILTY CLAY LOAM'
+9, 5.39, 0.050, 1.21, 0.451, 0.314, 0.478, 6.95E-6, 0.143E-4, 0.137, 0.40, 0.23, 0.016, 0.23, 0.23, 0.23, 1.040, 0.260, 'CLAY LOAM'
+10, 10.40, 0.070, 1.18, 0.426, 0.316, 0.153, 2.17E-6, 0.187E-4, 0.158, 0.52, 0.25, 0.015, 0.25, 0.25, 0.25, 1.042, 0.300, 'SANDY CLAY'
+11, 10.40, 0.070, 1.15, 0.492, 0.409, 0.490, 1.03E-6, 0.964E-5, 0.190, 0.10, 0.28, 0.016, 0.28, 0.28, 0.28, 1.045, 0.380, 'SILTY CLAY'
+12, 11.40, 0.068, 1.09, 0.482, 0.400, 0.405, 1.28E-6, 0.112E-4, 0.198, 0.25, 0.30, 0.017, 0.30, 0.30, 0.30, 1.000, 0.410, 'CLAY'
+13, 5.39, 0.027, 1.21, 0.451, 0.314, 0.478, 6.95E-6, 0.143E-4, 0.117, 0.05, 0.26, 0.012, 0.26, 0.26, 0.26, 1.000, 0.500, 'ORGANIC MATERIAL'
+14, 0.0, 0.0, 4.18, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.00, 0.00, 0.001, 0.00, 0.00, 0.00, 1.000, 0.001, 'WATER'
+15, 4.05, 0.004, 2.03, 0.200, 0.10 , 0.121, 1.41E-4, 0.136E-3, 0.006, 0.60, 1.00, 0.017, 1.00, 1.00, 1.00, 1.000, 0.010, 'BEDROCK'
+16, 4.90, 0.065, 2.10, 0.435, 0.249, 0.218, 3.47E-5, 0.514E-5, 0.114, 0.05, 1.00, 0.017, 1.00, 1.00, 1.00, 1.000, 0.001, 'OTHER(land-ice)'
+17, 11.40, 0.030, 1.41, 0.468, 0.454, 0.468, 9.74E-7, 0.112E-4, 0.030, 0.60, 1.00, 0.017, 1.00, 1.00, 1.00, 1.000, 0.001, 'PLAYA'
+18, 4.05, 0.006, 1.41, 0.200, 0.17, 0.069, 1.41E-4, 0.136E-3, 0.006, 0.52, 0.35, 0.015, 0.35, 0.35, 0.35, 1.000, 0.050, 'LAVA'
+19, 4.05, 0.01, 1.47, 0.339, 0.236, 0.069, 1.76E-4, 0.608E-6, 0.060, 0.92, 0.15, 0.009, 0.15, 0.15, 0.15, 1.000, 0.020, 'WHITE SAND'
+
diff --git a/python/runCalibValid/ngen_conf/tests/data/forcing/cat-1.csv b/python/runCalibValid/ngen_conf/tests/data/forcing/cat-1.csv
new file mode 100644
index 00000000..a6357816
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/data/forcing/cat-1.csv
@@ -0,0 +1,169 @@
+Time,RAINRATE,T2D,Q2D,U2D,V2D,PSFC,SWDOWN,LWDOWN
+2019-06-01 00:00:00,0.00000000,301.89,0.00281,-0.049, 3.728, 92201.1,519.42,302.01
+2019-06-01 01:00:00,0.00000000,300.89,0.00318, 0.944, 3.393, 92218.6,318.18,309.26
+2019-06-01 02:00:00,0.00000000,298.85,0.00447, 1.938, 3.061, 92240.3,137.51,317.38
+2019-06-01 03:00:00,0.00000000,296.80,0.00506, 2.932, 2.728, 92264.6, 0.00,296.68
+2019-06-01 04:00:00,0.00000000,295.30,0.00610, 3.581, 2.401, 92313.1, 0.00,298.80
+2019-06-01 05:00:00,0.00000000,295.22,0.00440, 4.229, 2.086, 92324.2, 0.00,295.99
+2019-06-01 06:00:00,0.00000000,294.69,0.00436, 4.886, 1.755, 92288.0, 0.00,288.11
+2019-06-01 07:00:00,0.00000000,294.19,0.00483, 4.088, 1.265, 92284.4, 0.00,292.50
+2019-06-01 08:00:00,0.00000000,293.33,0.00459, 3.292, 0.774, 92237.2, 0.00,292.23
+2019-06-01 09:00:00,0.00000000,292.93,0.00506, 2.493, 0.285, 92202.7, 0.00,288.17
+2019-06-01 10:00:00,0.00000000,292.54,0.00490, 2.518, 0.217, 92206.6, 0.00,288.35
+2019-06-01 11:00:00,0.00000000,291.70,0.00561, 2.543, 0.142, 92204.8, 0.00,290.44
+2019-06-01 12:00:00,0.00000000,290.51,0.00584, 2.570, 0.070, 92244.0, 0.00,279.73
+2019-06-01 13:00:00,0.00000000,290.57,0.00615, 2.142, 0.221, 92248.0, 45.87,274.55
+2019-06-01 14:00:00,0.00000000,292.98,0.00612, 1.713, 0.371, 92308.7,195.64,277.51
+2019-06-01 15:00:00,0.00000000,294.24,0.00669, 1.290, 0.520, 92345.0,384.45,307.54
+2019-06-01 16:00:00,0.00000000,295.37,0.00738, 0.731, 0.398, 92382.3,570.34,306.45
+2019-06-01 17:00:00,0.00000000,297.06,0.00593, 0.171, 0.267, 92365.3,747.92,301.30
+2019-06-01 18:00:00,0.00000000,298.30,0.00528,-0.389, 0.139, 92358.0,880.00,322.18
+2019-06-01 19:00:00,0.00000000,299.13,0.00617,-0.450, 1.021, 92379.0,988.98,325.55
+2019-06-01 20:00:00,0.00000000,299.50,0.00669,-0.511, 1.903, 92366.5,1022.28,325.23
+2019-06-01 21:00:00,0.00000000,299.91,0.00679,-0.575, 2.791, 92298.2,987.22,328.95
+2019-06-01 22:00:00,0.00000000,300.04,0.00666,-0.306, 2.838, 92230.6,892.13,329.78
+2019-06-01 23:00:00,0.00000000,299.89,0.00658,-0.032, 2.888, 92224.3,727.44,329.67
+2019-06-02 00:00:00,0.00000000,299.58,0.00681, 0.236, 2.937, 92156.4,519.86,317.48
+2019-06-02 01:00:00,0.00000000,300.04,0.00705, 1.235, 2.555, 92092.9,319.06,328.52
+2019-06-02 02:00:00,0.00000000,298.06,0.00700, 2.236, 2.166, 92115.4,138.90,327.49
+2019-06-02 03:00:00,0.00000000,296.26,0.00702, 3.237, 1.784, 92207.8, 0.00,306.25
+2019-06-02 04:00:00,0.00000000,295.59,0.00641, 3.882, 1.507, 92222.4, 0.00,305.42
+2019-06-02 05:00:00,0.00000000,294.59,0.00585, 4.525, 1.223, 92252.2, 0.00,303.09
+2019-06-02 06:00:00,0.00000000,294.30,0.00500, 5.171, 0.941, 92230.2, 0.00,294.71
+2019-06-02 07:00:00,0.00000000,293.54,0.00455, 4.588, 0.697, 92211.1, 0.00,292.55
+2019-06-02 08:00:00,0.00000000,293.18,0.00457, 4.006, 0.453, 92178.0, 0.00,294.17
+2019-06-02 09:00:00,0.00000000,292.59,0.00491, 3.423, 0.209, 92145.4, 0.00,289.94
+2019-06-02 10:00:00,0.00000000,292.24,0.00493, 3.136, 0.158, 92150.9, 0.00,291.61
+2019-06-02 11:00:00,0.00000000,291.40,0.00523, 2.847, 0.105, 92203.5, 0.00,292.21
+2019-06-02 12:00:00,0.00000000,291.51,0.00554, 2.561, 0.045, 92241.5, 0.00,301.41
+2019-06-02 13:00:00,0.00000000,290.73,0.00559, 1.870, 0.221, 92238.4, 45.43,290.34
+2019-06-02 14:00:00,0.00000000,292.86,0.00609, 1.185, 0.393, 92314.7,191.36,293.19
+2019-06-02 15:00:00,0.00000000,294.68,0.00645, 0.494, 0.560, 92387.2,377.66,329.65
+2019-06-02 16:00:00,0.00000000,295.51,0.00763,-0.009, 0.741, 92371.1,560.06,327.18
+2019-06-02 17:00:00,0.00000000,297.15,0.00733,-0.515, 0.923, 92393.3,734.21,323.99
+2019-06-02 18:00:00,0.00000000,298.64,0.00613,-1.015, 1.106, 92351.6,865.65,341.23
+2019-06-02 19:00:00,0.00000000,300.10,0.00599,-0.816, 1.568, 92447.7,972.97,343.28
+2019-06-02 20:00:00,0.00000000,299.93,0.00738,-0.615, 2.034, 92415.0,1005.84,342.91
+2019-06-02 21:00:00,0.00000000,300.32,0.00778,-0.406, 2.495, 92346.1,972.08,346.49
+2019-06-02 22:00:00,0.00000000,301.07,0.00644,-0.220, 2.667, 92306.4,878.70,346.94
+2019-06-02 23:00:00,0.00000000,300.72,0.00616,-0.024, 2.833, 92254.2,716.88,345.44
+2019-06-03 00:00:00,0.00000000,300.50,0.00591, 0.164, 3.003, 92233.3,510.83,331.55
+2019-06-03 01:00:00,0.00000000,300.29,0.00684, 0.767, 2.499, 92244.9,314.15,342.32
+2019-06-03 02:00:00,0.00000000,299.34,0.00676, 1.382, 1.993, 92277.4,137.73,346.08
+2019-06-03 03:00:00,0.00000000,296.64,0.00696, 1.987, 1.494, 92312.8, 0.00,316.86
+2019-06-03 04:00:00,0.00000000,296.87,0.00494, 2.722, 1.347, 92295.8, 0.00,314.01
+2019-06-03 05:00:00,0.00000000,295.32,0.00493, 3.453, 1.204, 92392.2, 0.00,310.93
+2019-06-03 06:00:00,0.00000000,294.78,0.00499, 4.191, 1.059, 92303.1, 0.00,307.06
+2019-06-03 07:00:00,0.00000000,294.76,0.00517, 4.096, 0.766, 92291.9, 0.00,309.87
+2019-06-03 08:00:00,0.00000000,294.46,0.00516, 4.000, 0.472, 92297.1, 0.00,310.79
+2019-06-03 09:00:00,0.00000000,293.86,0.00508, 3.909, 0.181, 92275.9, 0.00,306.59
+2019-06-03 10:00:00,0.00000000,293.56,0.00490, 3.366,-0.068, 92323.2, 0.00,307.26
+2019-06-03 11:00:00,0.00000000,292.58,0.00517, 2.823,-0.317, 92374.8, 0.00,306.95
+2019-06-03 12:00:00,0.00000000,292.19,0.00531, 2.283,-0.571, 92396.6, 0.00,311.04
+2019-06-03 13:00:00,0.00000000,292.18,0.00540, 1.770,-0.555, 92371.7, 45.45,301.92
+2019-06-03 14:00:00,0.00000000,294.35,0.00577, 1.257,-0.541, 92425.2,189.48,303.53
+2019-06-03 15:00:00,0.00000000,295.43,0.00603, 0.746,-0.528, 92479.7,376.94,327.30
+2019-06-03 16:00:00,0.00000000,296.35,0.00745,-0.183,-0.536, 92512.2,558.77,326.79
+2019-06-03 17:00:00,0.00000000,298.15,0.00747,-1.120,-0.539, 92486.4,732.32,325.81
+2019-06-03 18:00:00,0.00000000,299.86,0.00734,-2.051,-0.542, 92516.6,865.04,346.78
+2019-06-03 19:00:00,0.00000000,301.74,0.00636,-1.795,-0.275, 92537.2,972.19,350.26
+2019-06-03 20:00:00,0.00000000,302.51,0.00687,-1.531,-0.005, 92460.6,1005.24,353.66
+2019-06-03 21:00:00,0.00000000,303.16,0.00695,-1.271, 0.260, 92388.3,974.56,351.99
+2019-06-03 22:00:00,0.00000000,303.00,0.00650,-0.754, 0.497, 92337.0,881.26,351.16
+2019-06-03 23:00:00,0.00000000,303.11,0.00646,-0.229, 0.738, 92290.9,719.29,353.15
+2019-06-04 00:00:00,0.00000000,303.23,0.00624, 0.296, 0.973, 92235.7,512.36,344.49
+2019-06-04 01:00:00,0.00000000,302.83,0.00644, 0.756, 1.235, 92243.2,315.63,351.89
+2019-06-04 02:00:00,0.00000000,301.58,0.00628, 1.217, 1.490, 92276.8,139.30,354.04
+2019-06-04 03:00:00,0.00000000,299.39,0.00550, 1.677, 1.749, 92306.7, 0.00,321.11
+2019-06-04 04:00:00,0.00000000,299.44,0.00576, 2.255, 1.365, 92304.9, 0.00,326.38
+2019-06-04 05:00:00,0.00000000,298.54,0.00526, 2.826, 0.989, 92382.8, 0.00,323.55
+2019-06-04 06:00:00,0.00000000,298.19,0.00499, 3.401, 0.613, 92376.0, 0.00,318.50
+2019-06-04 07:00:00,0.00000000,296.91,0.00480, 3.962, 0.398, 92394.8, 0.00,314.42
+2019-06-04 08:00:00,0.00000000,296.67,0.00464, 4.529, 0.190, 92405.0, 0.00,315.04
+2019-06-04 09:00:00,0.00000000,296.15,0.00443, 5.095,-0.024, 92377.3, 0.00,308.75
+2019-06-04 10:00:00,0.00000000,295.27,0.00435, 4.281,-0.235, 92345.8, 0.00,307.20
+2019-06-04 11:00:00,0.00000000,293.85,0.00517, 3.472,-0.455, 92409.2, 0.00,307.16
+2019-06-04 12:00:00,0.00000000,294.75,0.00483, 2.660,-0.668, 92407.5, 0.00,311.50
+2019-06-04 13:00:00,0.00000000,293.99,0.00485, 2.442,-0.749, 92454.9, 46.36,299.50
+2019-06-04 14:00:00,0.00000000,297.17,0.00506, 2.229,-0.837, 92523.4,191.58,305.34
+2019-06-04 15:00:00,0.00000000,297.11,0.00638, 2.010,-0.924, 92641.0,379.05,331.82
+2019-06-04 16:00:00,0.00000000,299.29,0.00733, 1.070,-0.983, 92649.9,561.64,335.32
+2019-06-04 17:00:00,0.00000000,301.12,0.00765, 0.133,-1.038, 92647.2,736.13,335.09
+2019-06-04 18:00:00,0.00000000,302.20,0.00850,-0.808,-1.098, 92684.2,869.66,354.30
+2019-06-04 19:00:00,0.00000000,304.16,0.00729,-0.824,-1.059, 92653.2,977.47,356.66
+2019-06-04 20:00:00,0.00000000,304.81,0.00631,-0.840,-1.021, 92592.2,1010.84,353.47
+2019-06-04 21:00:00,0.00000000,305.58,0.00624,-0.856,-0.983, 92464.7,979.86,355.54
+2019-06-04 22:00:00,0.00000000,306.28,0.00584,-0.115,-0.662, 92470.5,886.32,358.35
+2019-06-04 23:00:00,0.00000000,305.78,0.00576, 0.632,-0.347, 92378.6,723.82,356.45
+2019-06-05 00:00:00,0.00000000,305.21,0.00562, 1.375,-0.027, 92380.1,514.15,346.50
+2019-06-05 01:00:00,0.00000000,305.36,0.00709, 1.789, 0.442, 92338.6,317.33,362.04
+2019-06-05 02:00:00,0.00000000,303.65,0.00704, 2.197, 0.916, 92427.2,140.95,362.97
+2019-06-05 03:00:00,0.00000000,301.28,0.00557, 2.616, 1.387, 92412.2, 0.00,329.36
+2019-06-05 04:00:00,0.00000000,301.00,0.00537, 2.727, 1.105, 92506.0, 0.00,331.02
+2019-06-05 05:00:00,0.00000000,301.12,0.00401, 2.841, 0.819, 92564.4, 0.00,328.63
+2019-06-05 06:00:00,0.00000000,299.90,0.00457, 2.953, 0.536, 92531.3, 0.00,327.52
+2019-06-05 07:00:00,0.00000000,299.28,0.00459, 3.414, 0.459, 92528.5, 0.00,325.82
+2019-06-05 08:00:00,0.00000000,298.37,0.00494, 3.875, 0.378, 92519.9, 0.00,324.36
+2019-06-05 09:00:00,0.00000000,297.64,0.00505, 4.337, 0.297, 92460.5, 0.00,322.02
+2019-06-05 10:00:00,0.00000000,298.08,0.00501, 3.605, 0.131, 92416.8, 0.00,325.76
+2019-06-05 11:00:00,0.00000000,296.83,0.00544, 2.874,-0.033, 92480.9, 0.00,323.95
+2019-06-05 12:00:00,0.00000000,295.84,0.00514, 2.143,-0.208, 92492.3, 0.00,321.98
+2019-06-05 13:00:00,0.00000000,296.31,0.00479, 1.963,-0.347, 92557.6, 46.35,312.56
+2019-06-05 14:00:00,0.00000000,298.61,0.00497, 1.786,-0.486, 92583.2,189.94,313.91
+2019-06-05 15:00:00,0.00000000,299.73,0.00566, 1.605,-0.626, 92656.0,376.90,342.81
+2019-06-05 16:00:00,0.00000000,301.35,0.00710, 0.819,-0.348, 92702.5,558.33,345.67
+2019-06-05 17:00:00,0.00000000,302.63,0.00758, 0.026,-0.067, 92665.6,731.63,342.85
+2019-06-05 18:00:00,0.00000000,304.74,0.00678,-0.763, 0.220, 92644.2,863.56,360.58
+2019-06-05 19:00:00,0.00000000,305.32,0.00903,-0.467, 0.736, 92687.8,970.76,369.29
+2019-06-05 20:00:00,0.00000000,306.66,0.00976,-0.176, 1.257, 92618.7,1004.02,376.72
+2019-06-05 21:00:00,0.00000000,307.53,0.00820, 0.117, 1.775, 92605.9,971.83,374.93
+2019-06-05 22:00:00,0.00000000,306.64,0.00883, 0.660, 2.160, 92559.0,879.35,374.34
+2019-06-05 23:00:00,0.00000000,307.26,0.00751, 1.201, 2.549, 92522.5,718.49,375.52
+2019-06-06 00:00:00,0.00000000,307.31,0.00745, 1.742, 2.937, 92465.7,513.69,358.78
+2019-06-06 01:00:00,0.00000000,305.96,0.00757, 2.833, 2.844, 92459.2,317.65,362.26
+2019-06-06 02:00:00,0.00000000,304.51,0.00752, 3.917, 2.749, 92469.0,141.93,364.91
+2019-06-06 03:00:00,0.00000000,301.72,0.00751, 5.007, 2.649, 92555.2, 0.00,334.46
+2019-06-06 04:00:00,0.00000000,300.04,0.00692, 5.042, 2.335, 92532.5, 0.00,329.70
+2019-06-06 05:00:00,0.00000000,299.69,0.00659, 5.077, 2.021, 92549.4, 0.00,331.38
+2019-06-06 06:00:00,0.00000000,299.46,0.00605, 5.111, 1.710, 92569.9, 0.00,324.98
+2019-06-06 07:00:00,0.00000000,299.12,0.00576, 4.493, 1.259, 92506.1, 0.00,325.24
+2019-06-06 08:00:00,0.00000000,297.02,0.00588, 3.878, 0.806, 92541.6, 0.00,319.04
+2019-06-06 09:00:00,0.00000000,296.82,0.00551, 3.254, 0.361, 92491.9, 0.00,312.77
+2019-06-06 10:00:00,0.00000000,295.36,0.00568, 2.903, 0.379, 92506.7, 0.00,309.95
+2019-06-06 11:00:00,0.00000000,294.90,0.00560, 2.550, 0.390, 92563.2, 0.00,310.38
+2019-06-06 12:00:00,0.00000000,293.98,0.00568, 2.192, 0.409, 92537.1, 0.00,312.21
+2019-06-06 13:00:00,0.00000000,293.50,0.00557, 1.768, 0.553, 92535.4, 47.14,301.00
+2019-06-06 14:00:00,0.00000000,296.28,0.00592, 1.356, 0.687, 92633.3,191.89,305.61
+2019-06-06 15:00:00,0.00000000,297.48,0.00624, 0.937, 0.827, 92695.5,372.49,332.90
+2019-06-06 16:00:00,0.00000000,299.38,0.00688, 0.853, 1.273, 92622.4,551.60,335.36
+2019-06-06 17:00:00,0.00000000,301.04,0.00690, 0.763, 1.721, 92633.5,722.80,334.42
+2019-06-06 18:00:00,0.00000000,302.62,0.00724, 0.679, 2.164, 92630.1,840.41,357.14
+2019-06-06 19:00:00,0.00000000,303.87,0.00802, 1.283, 2.794, 92668.4,944.77,363.22
+2019-06-06 20:00:00,0.00000000,305.03,0.00808, 1.895, 3.428, 92554.3,977.32,366.82
+2019-06-06 21:00:00,0.00000000,305.42,0.00809, 2.503, 4.060, 92545.0,916.93,369.05
+2019-06-06 22:00:00,0.00000000,305.33,0.00766, 3.190, 4.076, 92510.2,829.96,369.53
+2019-06-06 23:00:00,0.00000000,306.10,0.00801, 3.875, 4.090, 92452.5,678.42,377.22
+2019-06-07 00:00:00,0.00000000,305.04,0.00781, 4.560, 4.109, 92454.3,521.00,353.33
+2019-06-07 01:00:00,0.00000000,305.67,0.00541, 4.011, 3.552, 92399.4,322.71,355.80
+2019-06-07 02:00:00,0.00000000,303.41,0.00588, 3.464, 2.994, 92454.8,145.05,355.47
+2019-06-07 03:00:00,0.00000000,301.07,0.00507, 2.915, 2.429, 92398.9, 0.00,320.44
+2019-06-07 04:00:00,0.00000000,298.18,0.00698, 3.443, 2.347, 92510.0, 0.00,319.52
+2019-06-07 05:00:00,0.00000000,298.01,0.00597, 3.969, 2.256, 92534.1, 0.00,319.80
+2019-06-07 06:00:00,0.00000000,297.61,0.00508, 4.497, 2.167, 92509.1, 0.00,307.16
+2019-06-07 07:00:00,0.00000000,296.83,0.00498, 4.658, 2.173, 92464.8, 0.00,306.42
+2019-06-07 08:00:00,0.00000000,295.46,0.00523, 4.817, 2.180, 92466.9, 0.00,304.61
+2019-06-07 09:00:00,0.00000000,294.99,0.00524, 4.979, 2.193, 92425.8, 0.00,297.73
+2019-06-07 10:00:00,0.00000000,295.03,0.00491, 4.263, 1.680, 92367.8, 0.00,300.25
+2019-06-07 11:00:00,0.00000000,293.65,0.00505, 3.554, 1.172, 92415.8, 0.00,299.16
+2019-06-07 12:00:00,0.00000000,293.28,0.00484, 2.849, 0.670, 92451.4, 0.00,295.71
+2019-06-07 13:00:00,0.00000000,292.87,0.00530, 2.286, 1.106, 92425.6, 47.66,289.47
+2019-06-07 14:00:00,0.00000000,295.36,0.00572, 1.724, 1.544, 92458.7,192.77,295.10
+2019-06-07 15:00:00,0.00000000,296.67,0.00615, 1.168, 1.981, 92527.8,379.41,322.01
+2019-06-07 16:00:00,0.00000000,298.32,0.00690, 1.540, 2.752, 92529.4,561.71,325.69
+2019-06-07 17:00:00,0.00000000,299.63,0.00694, 1.923, 3.533, 92492.8,736.01,325.61
+2019-06-07 18:00:00,0.00000000,301.48,0.00683, 2.300, 4.304, 92491.9,868.81,349.59
+2019-06-07 19:00:00,0.00000000,302.33,0.00705, 2.502, 4.545, 92528.4,976.85,350.43
+2019-06-07 20:00:00,0.00000000,303.19,0.00696, 2.701, 4.782, 92429.4,1010.65,350.27
+2019-06-07 21:00:00,0.00000000,304.07,0.00707, 2.898, 5.022, 92333.3,979.72,356.28
+2019-06-07 22:00:00,0.00000000,304.89,0.00653, 3.370, 5.027, 92265.4,887.01,359.04
+2019-06-07 23:00:00,0.00000000,305.07,0.00424, 3.840, 5.041, 92250.7,725.47,349.66
diff --git a/python/runCalibValid/ngen_conf/tests/data/routing/fake_config.yaml b/python/runCalibValid/ngen_conf/tests/data/routing/fake_config.yaml
new file mode 100644
index 00000000..e69de29b
diff --git a/python/runCalibValid/ngen_conf/tests/data/sloth/config.txt b/python/runCalibValid/ngen_conf/tests/data/sloth/config.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/python/runCalibValid/ngen_conf/tests/data/sloth/libfakesloth.dylib b/python/runCalibValid/ngen_conf/tests/data/sloth/libfakesloth.dylib
new file mode 100644
index 00000000..e69de29b
diff --git a/python/runCalibValid/ngen_conf/tests/test_cfe.py b/python/runCalibValid/ngen_conf/tests/test_cfe.py
new file mode 100644
index 00000000..32439099
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/test_cfe.py
@@ -0,0 +1,31 @@
+import pytest
+from ngen.config.formulation import Formulation
+from ngen.config.cfe import CFE
+
+def test_init(cfe_params):
+ cfe = CFE(**cfe_params)
+
+def test_name_map_default(cfe_params):
+ cfe = CFE(**cfe_params)
+ assert cfe.name_map["atmosphere_water__liquid_equivalent_precipitation_rate"] == 'QINSUR'
+
+def test_name_map_override(cfe_params):
+ cfe_params['name_map'] = {"atmosphere_water__liquid_equivalent_precipitation_rate":"RAINRATE"}
+ cfe = CFE(**cfe_params)
+ assert cfe.name_map["atmosphere_water__liquid_equivalent_precipitation_rate"] == 'RAINRATE'
+
+
+@pytest.mark.parametrize("forcing",["csv", "netcdf"], indirect=True )
+def test_cfe_formulation(cfe_params, forcing):
+ cfe = CFE(**cfe_params)
+ f = {"params":cfe, "name":"bmi_c"}
+ cfe_formulation = Formulation( **f )
+ _cfe = cfe_formulation.params
+ assert _cfe.name == 'bmi_c'
+ assert _cfe.model_name == 'CFE'
+
+def test_cfe_model_params(cfe_params):
+ cfe = CFE(**cfe_params)
+ assert cfe.model_params
+ assert cfe.model_params.expon == 42
+ assert cfe.model_params.slope == 0.42
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_conf/tests/test_cfe_sloth.py b/python/runCalibValid/ngen_conf/tests/test_cfe_sloth.py
new file mode 100644
index 00000000..51e5c3a7
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/test_cfe_sloth.py
@@ -0,0 +1,21 @@
+import json
+import pytest
+from pathlib import Path
+from ngen.config.realization import Realization, NgenRealization
+
+@pytest.fixture()
+def data():
+ test_dir = Path(__file__).parent
+ test_file = test_dir/'test_config.json'
+ with open(test_file) as fp:
+ data = json.load(fp)
+ data['routing']['t_route_config_file_with_path'] = test_dir/data['routing']['t_route_config_file_with_path']
+ data['global']['forcing']['path'] = test_dir/data['global']['forcing']['path']
+ return data
+
+def test_ngen_global_realization(data):
+ g = NgenRealization(**data)
+ """ TODO write a test of serializing to json and then reading the result back and validating???
+ with open("generated.json", 'w') as fp:
+ fp.write( g.json(by_alias=True, exclude_none=True, indent=4))
+ """
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_conf/tests/test_config.json b/python/runCalibValid/ngen_conf/tests/test_config.json
new file mode 100644
index 00000000..27655cfa
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/test_config.json
@@ -0,0 +1,97 @@
+
+{
+ "global": {
+ "formulations": [
+ {
+ "name": "bmi_multi",
+ "params": {
+ "name": "bmi_multi",
+ "model_type_name": "NoahOWP_CFE",
+ "main_output_variable": "Q_OUT",
+ "init_config": "",
+ "allow_exceed_end_time": false,
+ "fixed_time_step": false,
+ "uses_forcing_file": false,
+ "modules": [
+ {
+ "name": "bmi_fortran",
+ "params": {
+ "name": "bmi_fortran",
+ "model_type_name": "NoahOWP",
+ "main_output_variable": "QINSUR",
+ "init_config": "data/NOAH/cat-1.input",
+ "allow_exceed_end_time": true,
+ "fixed_time_step": false,
+ "uses_forcing_file": false,
+ "variables_names_map": {
+ "PRCPNONC": "atmosphere_water__liquid_equivalent_precipitation_rate",
+ "Q2": "atmosphere_air_water~vapor__relative_saturation",
+ "SFCTMP": "land_surface_air__temperature",
+ "UU": "land_surface_wind__x_component_of_velocity",
+ "VV": "land_surface_wind__y_component_of_velocity",
+ "LWDN": "land_surface_radiation~incoming~longwave__energy_flux",
+ "SOLDN": "land_surface_radiation~incoming~shortwave__energy_flux",
+ "SFCPRS": "land_surface_air__pressure"
+ },
+ "library_file": "data/NOAH/libfackenoah.dylib"
+ }
+ },
+ {
+ "name": "bmi_c",
+ "params": {
+ "name": "bmi_c",
+ "model_type_name": "CFE",
+ "main_output_variable": "Q_OUT",
+ "init_config": "data/cfe/config.txt",
+ "allow_exceed_end_time": true,
+ "fixed_time_step": false,
+ "uses_forcing_file": false,
+ "variables_names_map": {
+ "atmosphere_water__liquid_equivalent_precipitation_rate": "QINSUR",
+ "water_potential_evaporation_flux": "EVAPOTRANS",
+ "ice_fraction_schaake": "sloth_ice_fraction_schaake",
+ "ice_fraction_xinan": "sloth_ice_fraction_xinan",
+ "soil_moisture_profile": "sloth_smp"
+ },
+ "library_file": "data/CFE/libfakecfe.so",
+ "registration_function": "register_bmi_cfe"
+ }
+ },
+ {
+ "name": "bmi_c++",
+ "params": {
+ "name": "bmi_c++",
+ "model_type_name": "SLOTH",
+ "main_output_variable": "z",
+ "library_file": "data/sloth/libfakesloth.dylib",
+ "init_config": "/dev/null",
+ "allow_exceed_end_time": true,
+ "fixed_time_step": false,
+ "uses_forcing_file": false,
+ "model_params": {
+ "sloth_ice_fraction_schaake(1,double,m,node)": 0.0,
+ "sloth_ice_fraction_xinan(1,double,1,node)": 0.0,
+ "sloth_smp(1,double,1,node)": 0.0
+ }
+ }
+ }
+ ]
+ }
+ }
+ ],
+ "forcing": {
+ "file_pattern": "cat-*.csv",
+ "path": "data/forcing",
+ "provider": "CsvPerFeature"
+ }
+ },
+ "time": {
+ "start_time": "2019-06-01 00:00:00",
+ "end_time": "2019-06-07 23:00:00",
+ "output_interval": 3600
+ },
+ "routing": {
+ "t_route_connection_path": "/local/ngen/workdir/extern/t-route/src/ngen_routing",
+ "t_route_config_file_with_path": "data/routing/fake_config.yaml"
+ }
+}
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_conf/tests/test_lstm.py b/python/runCalibValid/ngen_conf/tests/test_lstm.py
new file mode 100644
index 00000000..21f51521
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/test_lstm.py
@@ -0,0 +1,26 @@
+import pytest
+from ngen.config.formulation import Formulation
+from ngen.config.lstm import LSTM
+
+def test_init(lstm_params):
+ lstm = LSTM(**lstm_params)
+
+def test_name_map(lstm_params):
+ lstm = LSTM(**lstm_params)
+ _t = lstm.name_map["atmosphere_water__time_integral_of_precipitation_mass_flux"]
+ assert _t == "RAINRATE"
+
+def test_no_lib(lstm_params):
+ lstm = LSTM(**lstm_params)
+ assert "library" not in lstm.dict().keys()
+
+@pytest.mark.parametrize("forcing",["csv", "netcdf"], indirect=True )
+def test_lstm_formulation(lstm_params, forcing):
+ lstm = LSTM(**lstm_params)
+ f = {"params":lstm, "name":"bmi_python"}
+ lstm_formulation = Formulation( **f )
+ _lstm = lstm_formulation.params
+ assert _lstm.name == 'bmi_python'
+ assert _lstm.model_name == 'LSTM'
+ serialized = _lstm.dict(by_alias=True)
+ assert serialized['model_type_name'] == 'LSTM'
diff --git a/python/runCalibValid/ngen_conf/tests/test_multi.py b/python/runCalibValid/ngen_conf/tests/test_multi.py
new file mode 100644
index 00000000..0d179942
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/test_multi.py
@@ -0,0 +1,33 @@
+import pytest
+from ngen.config.formulation import Formulation
+from ngen.config.multi import MultiBMI
+
+def test_init(multi_params):
+ multi = MultiBMI(**multi_params)
+
+def test_name_map(multi_params):
+ multi = MultiBMI(**multi_params)
+ _t = multi.modules[-1].params.name_map["atmosphere_water__liquid_equivalent_precipitation_rate"]
+ assert _t == "QINSUR"
+ _t = multi.modules[0].params.name_map["UU"]
+ assert _t == 'land_surface_wind__x_component_of_velocity'
+
+def test_name_map_override(multi_params):
+ multi_params['modules'][-1]['params']['name_map'].update( {"atmosphere_water__liquid_equivalent_precipitation_rate":"RAINRATE"} )
+ multi_params['modules'][0]['params']['name_map'].update( {"UU":"WIND_U"} )
+ multi = MultiBMI(**multi_params)
+ _t = multi.modules[-1].params.name_map["atmosphere_water__liquid_equivalent_precipitation_rate"]
+ assert _t == "RAINRATE"
+ _t = multi.modules[0].params.name_map["UU"]
+ assert _t == "WIND_U"
+
+def test_no_lib(multi_params):
+ multi = MultiBMI(**multi_params)
+ assert "library" not in multi.dict().keys()
+
+def test_multi_formulation(multi_params):
+ multi = MultiBMI(**multi_params)
+ multi_formulation = Formulation( name=multi.name, params=multi )
+ _multi = multi_formulation.params
+ assert _multi.name == 'bmi_multi'
+ assert _multi.model_name == 'NoahOWP_CFE'
diff --git a/python/runCalibValid/ngen_conf/tests/test_noahowp.py b/python/runCalibValid/ngen_conf/tests/test_noahowp.py
new file mode 100644
index 00000000..0cf6db8f
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/test_noahowp.py
@@ -0,0 +1,23 @@
+import pytest
+from ngen.config.formulation import Formulation
+from ngen.config.noahowp import NoahOWP
+
+def test_init(noahowp_params):
+ noahowp = NoahOWP(**noahowp_params)
+
+def test_name_map_default(noahowp_params):
+ noahowp = NoahOWP(**noahowp_params)
+ assert noahowp.name_map["UU"] == 'land_surface_wind__x_component_of_velocity'
+
+def test_name_map_override(noahowp_params):
+ noahowp_params['name_map'] = {"atmosphere_water__liquid_equivalent_precipitation_rate":"RAINRATE"}
+ noahowp = NoahOWP(**noahowp_params)
+ assert noahowp.name_map["atmosphere_water__liquid_equivalent_precipitation_rate"] == 'RAINRATE'
+
+def test_noahowp_formulation(noahowp_params):
+ noahowp = NoahOWP(**noahowp_params)
+ f = {"params":noahowp, "name":"bmi_fortran"}
+ noahowp_formulation = Formulation( **f )
+ _noahowp = noahowp_formulation.params
+ assert _noahowp.name == 'bmi_fortran'
+ assert _noahowp.model_name == 'NoahOWP'
diff --git a/python/runCalibValid/ngen_conf/tests/test_realization.py b/python/runCalibValid/ngen_conf/tests/test_realization.py
new file mode 100644
index 00000000..0c49da2d
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/test_realization.py
@@ -0,0 +1,30 @@
+import pytest
+from ngen.config.realization import Realization, NgenRealization
+from ngen.config.formulation import Formulation
+
+import json
+
+@pytest.mark.parametrize("forcing",["csv", "netcdf"], indirect=True )
+def test_realization(forcing, time, cfe):
+ f = Formulation(name=cfe.name, params=cfe)
+ r = Realization(forcing=forcing, formulations=[f])
+
+@pytest.mark.parametrize("forcing",["csv", "netcdf"], indirect=True )
+def test_ngen_global_realization(forcing, time, cfe):
+ f = Formulation(name=cfe.name, params=cfe)
+ r = Realization(formulations=[f], forcing=forcing)
+ g = NgenRealization(global_config=r, time=time)
+ # This can essentially be used at this point for an ngen integration test
+ # by writing the realization and then running `ngen` with it...
+ # with open("test_realization.json", 'w') as fp:
+ # fp.write( g.json(by_alias=True, exclude_none=True, indent=4))
+
+@pytest.mark.parametrize("forcing",["csv", "netcdf"], indirect=True )
+def test_ngen_global_multi_realization(forcing, time, multi):
+ f = Formulation(name=multi.name, params=multi)
+ r = Realization(formulations=[f], forcing=forcing)
+ g = NgenRealization(global_config=r, time=time)
+ # This can essentially be used at this point for an ngen integration test
+ # by writing the realization and then running `ngen` with it...
+ # with open("test_realization_multi.json", 'w') as fp:
+ # fp.write( g.json(by_alias=True, exclude_none=True, indent=4))
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_conf/tests/test_sloth.py b/python/runCalibValid/ngen_conf/tests/test_sloth.py
new file mode 100644
index 00000000..b90ec13a
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/test_sloth.py
@@ -0,0 +1,21 @@
+import pytest
+from ngen.config.formulation import Formulation
+from ngen.config.sloth import SLOTH
+
+def test_init(sloth_params):
+ cfe = SLOTH(**sloth_params)
+
+
+@pytest.mark.parametrize("forcing",["csv", "netcdf"], indirect=True )
+def test_sloth_formulation(sloth_params, forcing):
+ sloth = SLOTH(**sloth_params)
+ f = {"params":sloth, "name":"bmi_cxx"}
+ sloth_formulation = Formulation( **f )
+ _sloth = sloth_formulation.params
+ assert _sloth.name == 'bmi_c++'
+ assert _sloth.model_name == 'SLOTH'
+ assert _sloth.main_output_variable == 'TEST'
+
+def test_sloth_model_params(sloth_params):
+ sloth = SLOTH(**sloth_params)
+ assert sloth.model_params == None
\ No newline at end of file
diff --git a/python/runCalibValid/ngen_conf/tests/test_topmod.py b/python/runCalibValid/ngen_conf/tests/test_topmod.py
new file mode 100644
index 00000000..8e7ad480
--- /dev/null
+++ b/python/runCalibValid/ngen_conf/tests/test_topmod.py
@@ -0,0 +1,30 @@
+import pytest
+from ngen.config.formulation import Formulation
+from ngen.config.topmod import Topmod
+
+def test_init(topmod_params):
+ topmod = Topmod(**topmod_params)
+
+def test_name_map_default(topmod_params):
+ topmod = Topmod(**topmod_params)
+ assert topmod.name_map["atmosphere_water__liquid_equivalent_precipitation_rate"] == 'QINSUR'
+
+def test_name_map_override(topmod_params):
+ topmod_params['name_map'] = {"atmosphere_water__liquid_equivalent_precipitation_rate":"RAINRATE"}
+ topmod = Topmod(**topmod_params)
+ assert topmod.name_map["atmosphere_water__liquid_equivalent_precipitation_rate"] == 'RAINRATE'
+
+@pytest.mark.parametrize("forcing",["csv", "netcdf"], indirect=True )
+def test_topmodformulation(topmod_params, forcing):
+ topmod = Topmod(**topmod_params)
+ f = {"params":topmod, "name":"bmi_c"}
+ topmodformulation = Formulation( **f )
+ _topmod = topmodformulation.params
+ assert _topmod.name == 'bmi_c'
+ assert _topmod.model_name == 'TOPMODEL'
+
+def test_topmodmodel_params(topmod_params):
+ topmod = Topmod(**topmod_params)
+ assert topmod.model_params
+ assert topmod.model_params.szm == 42
+ assert topmod.model_params.t0 == 0.42
diff --git a/python/runCalibValid/validation.py b/python/runCalibValid/validation.py
new file mode 100644
index 00000000..5d6a5f5b
--- /dev/null
+++ b/python/runCalibValid/validation.py
@@ -0,0 +1,53 @@
+"""
+This is main script to execute validation control run using the default model
+parameter set and validation best run using the best calibrated parameter set.
+
+@author: Xia Feng
+"""
+
+import argparse
+from os import chdir
+from pathlib import Path
+
+import yaml
+
+from ngen.cal.agent import Agent
+from ngen.cal.configuration import General
+from ngen.cal.validation_run import run_valid_ctrl_best
+
+def main(general: General, model_conf):
+
+ # Seed the random number generators if requested
+ if( general.random_seed is not None):
+ import random
+ random.seed(general.random_seed)
+ import numpy as np
+ np.random.seed(general.random_seed)
+
+ print("Starting Validation Run")
+
+ # Initialize agent
+ agent = Agent(model_conf, general.valid_path, general, general.log, general.restart)
+
+ # Execcute validation control and best simulation
+ run_valid_ctrl_best(agent)
+
+
+if __name__ == "__main__":
+
+ # Create command line parser
+ parser = argparse.ArgumentParser(description='Run Validation in NGEN architecture.')
+ parser.add_argument('config_file', type=Path,
+ help='The configuration yaml file for catchments to be operated on')
+
+ args = parser.parse_args()
+
+ with open(args.config_file) as file:
+ conf = yaml.safe_load(file)
+
+ general = General(**conf['general'])
+
+ # Change directory to workdir
+ chdir(general.workdir)
+
+ main(general, conf['model'])