diff --git a/Makefile b/Makefile
index 237d8e6ba9..43064ff439 100644
--- a/Makefile
+++ b/Makefile
@@ -1,65 +1,12 @@
-###############################################################################
-################### MOOSE Application Standard Makefile #######################
-###############################################################################
-#
-# Optional Environment variables
-# MOOSE_DIR - Root directory of the MOOSE project
-# HERD_TRUNK_DIR - Location of the HERD repository
-# FRAMEWORK_DIR - Location of the MOOSE framework
-#
-###############################################################################
-MOOSE_SUBMODULE := $(CURDIR)/moose
-RELAP7_SUBMODULE := $(CURDIR)/relap-7
-ifneq ($(wildcard $(MOOSE_SUBMODULE)/framework/Makefile),)
- MOOSE_DIR ?= $(MOOSE_SUBMODULE)
-else
-RELAP7_MOOSE_SUBMODULE := $(RELAP7_SUBMODULE)/moose
-ifneq ($(wildcard $(RELAP7_MOOSE_SUBMODULE)/framework/Makefile),)
- MOOSE_DIR ?= $(RELAP7_MOOSE_SUBMODULE)
-else
- MOOSE_DIR ?= $(shell dirname `pwd`)/moose
-endif
-endif
-
-HERD_TRUNK_DIR ?= $(shell dirname `pwd`)
-FRAMEWORK_DIR ?= $(MOOSE_DIR)/framework
-ifneq ($(wildcard $(RELAP7_SUBMODULE)/Makefile),)
- RELAP7_DIR ?= $(RELAP7_SUBMODULE)
-else
- RELAP7_DIR ?= $(HERD_TRUNK_DIR)/relap-7
-endif
-###############################################################################
CURR_DIR := $(CURDIR)
-# touch hit.cpp to make sure its time stamp is different than hit.pyx
-## this is not a clean solution, but hopefully it prevents asking to use cython
-CYTHON_AVOIDANCE_ACTION=$(shell touch $(MOOSE_DIR)/framework/contrib/hit/hit.cpp)
-
-
-# framework
-#include $(FRAMEWORK_DIR)/build.mk
-#include $(FRAMEWORK_DIR)/moose.mk
-
-################################## MODULES ####################################
-#HEAT_CONDUCTION := yes
-#MISC := yes
-#FLUID_PROPERTIES := yes
-#include $(MOOSE_DIR)/modules/modules.mk
-###############################################################################
-
-# RELAP-7
-#APPLICATION_DIR := $(RELAP7_DIR)
-#APPLICATION_NAME := relap-7
-#DEP_APPS := $(shell $(FRAMEWORK_DIR)/scripts/find_dep_apps.py $(APPLICATION_NAME))
-#include $(FRAMEWORK_DIR)/app.mk
-
# CROW
CROW_SUBMODULE := $(CURR_DIR)/crow
ifneq ($(wildcard $(CROW_SUBMODULE)/Makefile),)
CROW_DIR ?= $(CROW_SUBMODULE)
else
- CROW_DIR ?= $(HERD_TRUNK_DIR)/crow
+ $(warning CROW_DIR not found)
endif
all::
diff --git a/backend_run_tests b/backend_run_tests
deleted file mode 100755
index 790ced42b3..0000000000
--- a/backend_run_tests
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/usr/bin/env python
-from __future__ import print_function
-import sys, os, subprocess, re
-
-# Set the current working directory to the directory where this script is located
-os.chdir(os.path.abspath(os.path.dirname(sys.argv[0])))
-
-#### Set the name of the application here and moose directory relative to the application
-app_name = 'RAVEN'
-
-MOOSE_DIR = os.path.abspath(os.path.join('..', 'moose'))
-#### See if a submodule is available
-if os.path.exists(os.path.abspath(os.path.join('moose', 'python'))):
- MOOSE_DIR = os.path.abspath('moose')
-#### See if MOOSE_DIR is already in the environment instead
-if "MOOSE_DIR" in os.environ:
- MOOSE_DIR = os.environ['MOOSE_DIR']
-
-sys.path.append(os.path.join(MOOSE_DIR, 'python'))
-import path_tool
-path_tool.activate_module('TestHarness')
-
-#Try to import the raven libs dir into the PYTHONPATH
-
-# try:
-# if os.environ.get("CHECK_PYTHON3","0") == "1":
-# raven_libs_dir = subprocess.check_output("ls -d $HOME/raven_libs/pylibs3/*/python*/site-packages",shell=True,stderr=subprocess.STDOUT)
-# else:
-# raven_libs_dir = subprocess.check_output("ls -d $HOME/raven_libs/pylibs/*/python*/site-packages",shell=True,stderr=subprocess.STDOUT)
-# raven_libs_dir = raven_libs_dir.decode().strip()
-# os.environ["PYTHONPATH"] = raven_libs_dir + os.pathsep + os.environ.get("PYTHONPATH","")
-# sys.path.append(raven_libs_dir)
-# except:
-# sys.path.append(os.path.join("scripts","TestHarness","testers"))
-# import RavenUtils
-# missing,too_old = RavenUtils.checkForMissingModules()
-# if len(missing) > 0:
-# print("No raven_libs found and missing modules "+",".join(missing))
-# if len(too_old) > 0:
-# print("No raven_libs found and old version modules "+",".join(too_old))
-
-#add framework contrib path
-RAVEN_DIR = os.path.dirname(os.path.realpath(__file__))
-os.environ["PYTHONPATH"] = os.path.join(RAVEN_DIR,'framework','contrib') + os.pathsep + os.environ.get("PYTHONPATH","")
-
-coverage = False
-library_report = False
-for i in sys.argv:
- if i == "--check_coverage":
- coverage = True
- elif i == "--library_report" or i == "--library-report":
- library_report = True
-if coverage:
- from subprocess import call
- call(["./check_py_coverage.sh"])
-elif library_report:
- print("PYTHONPATH="+os.environ.get("PYTHONPATH",""))
- path = os.environ.get("PATH","")
- print("PATH="+path)
- print("Python Executable: ",sys.executable)
- print("Possible Python Executables on System:")
- for pathPart in path.split(os.pathsep):
- if os.path.isdir(pathPart):
- for directoryEntry in os.listdir(pathPart):
- lower = directoryEntry.lower()
- #match things like python, python2, python2.7, python.exe
- if re.match("python(\\d*(\\.\\d+)?)(\\.exe)?$",lower):
- print(pathPart+os.sep+directoryEntry)
- import platform
- print("OS:",platform.platform())
- print("Python:",sys.version)
- try:
- if os.path.exists(".git"):
- print("Git information:")
- os.system('git log -1 --format="%H %aD"')
- os.system('git describe')
- os.system('git submodule')
- elif os.path.exists("Version.txt"):
- print("Version.txt:")
- print(open("Version.txt","r").read())
- else:
- print("Could not find RAVEN version info")
- except:
- print("Failed to find git version")
- sys.path.append(os.path.join("scripts","TestHarness","testers"))
- sys.path.insert(0,os.path.join("framework","utils"))
- import RavenUtils,utils
- #missing,too_old = RavenUtils.checkForMissingModules()
- #print(missing,too_old)
- report_list = RavenUtils.modulesReport()
- amsc_report = RavenUtils.moduleReport('AMSC')
- report_list.append(('AMSC',amsc_report[0],amsc_report[1],""))
- print("\nLibraries report:\n")
- for module, found, message, version in report_list:
- if found:
- print(module,version,"\n",message,"\n")
- else:
- print(module+' not found\n')
- framework_dir = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]),"framework"))
- utils.find_crow(framework_dir)
- try:
- distribution1D = utils.findCrowModule('distribution1D')
- print("distribution1D","\n",distribution1D)
- print()
- except ImportError:
- print("distribution1D not found\n")
- try:
- interpolationND = utils.findCrowModule('interpolationND')
- print("interpolationND","\n",interpolationND)
- except ImportError:
- print("interpolationND not found\n")
- try:
- randomENG = utils.findCrowModule('randomENG')
- print("randomENG","\n",randomENG)
- except ImportError:
- print("randomENG not found\n")
-else:
- from TestHarness import TestHarness
- sys.path.append(os.path.join("scripts","TestHarness","testers"))
- import RavenUtils
- missing,outOfRange,notQA = RavenUtils.checkForMissingModules()
- if len(missing) + len(outOfRange) > 0 and RavenUtils.checkVersions():
- print("ERROR: too old, too new, or missing raven libraries, not running:")
- for error in missing + outOfRange + notQA:
- print(error)
- sys.exit(-1)
- else:
- if len(missing) + len(outOfRange) > 0:
- print("WARNING: not using tested versions of the libraries:")
- for warning in notQA + missing + outOfRange:
- print(warning)
- # Run the tests!
- TestHarness.buildAndRun(sys.argv, app_name, MOOSE_DIR)
-
-
diff --git a/build_raven b/build_raven
index 61b7705fb0..63c93d7765 100755
--- a/build_raven
+++ b/build_raven
@@ -61,8 +61,6 @@ if [[ $LIBS_MODE == 0 ]]; then
echo Cleaning old build ...
make clean
- # set up hit.cpp so that it has a newer timestamp than hit.pyx
- touch moose/framework/contrib/hit/hit.cpp
else
echo Establishing Python libraries ...
. scripts/establish_conda_env.sh --load ${ECE_ARGS}
diff --git a/developer_tools/get_coverage_tests.py b/developer_tools/get_coverage_tests.py
index 220159f62c..a9ad0b04b5 100644
--- a/developer_tools/get_coverage_tests.py
+++ b/developer_tools/get_coverage_tests.py
@@ -54,7 +54,8 @@ def getRegressionTests(whichTests=1,skipExpectedFails=True):
startReading = False
if startReading:
splitted = line.strip().split('=')
- testSpecs[splitted[0].strip()] = splitted[1].replace("'","").replace('"','').strip()
+ if len(splitted) == 2:
+ testSpecs[splitted[0].strip()] = splitted[1].replace("'","").replace('"','').strip()
if line.strip().startswith("[./"):
startReading = True
collectSpecs = False
@@ -70,6 +71,8 @@ def getRegressionTests(whichTests=1,skipExpectedFails=True):
# check if test is skipped or an executable is required
if "required_executable" in spec or "skip" in spec:
continue
+ if "input" not in spec:
+ continue
testType = spec.get('type',"notfound").strip()
newTest = spec['input'].strip()
testInterfaceOnly = False
diff --git a/developer_tools/pylint_check b/developer_tools/pylint_check
index a998013506..f01ad47c7a 100755
--- a/developer_tools/pylint_check
+++ b/developer_tools/pylint_check
@@ -11,4 +11,8 @@ cd $SCRIPT_DIR/..
# activate raven libraries
source $SCRIPT_DIR/../scripts/establish_conda_env.sh --load --quiet
+echo Framework
pylint --disable=all --enable=missing-docstring --enable=no-absolute-import --enable=old-division --enable=print-statement --enable=file-builtin --enable=multiple-statements framework/
+
+echo Rook
+pylint --disable=fixme,too-few-public-methods,len-as-condition,too-many-locals,too-many-return-statements,too-many-branches,too-many-statements,too-many-instance-attributes,too-many-arguments,no-self-use,similarities,broad-except,consider-using-enumerate,no-member,import-error,old-style-class,not-an-iterable,unexpected-keyword-arg --const-rgx '(([A-Za-z_][A-Za-z0-9_]*)|(__.*__))$' --module-rgx '(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$' --indent-string " " rook/*.py scripts/TestHarness/testers/*.py
diff --git a/developer_tools/pylint_list b/developer_tools/pylint_list
index a82bdd023e..1d90bf09e1 100755
--- a/developer_tools/pylint_list
+++ b/developer_tools/pylint_list
@@ -11,4 +11,4 @@ cd $SCRIPT_DIR/..
RGX="[a-zA-Z_]{1,2}[a-zA-Z0-9]{0,50}$"
METHOD_RGX="[a-zA-Z_]{1,2}[a-zA-Z0-9]{2,50}(__)?$"
-pylint --indent-string=" " --variable-rgx="$RGX" --attr-rgx="$RGX" --function-rgx="$RGX" --method-rgx="$METHOD_RGX" --const-rgx="$RGX" --argument-rgx="$RGX" --disable=bad-whitespace --disable=line-too-long --disable=multiple-imports --disable=import-error --disable=wrong-import-position --disable=unused-import --disable=wrong-import-order --disable=attribute-defined-outside-init --disable=too-many-branches --disable=too-many-locals --disable=too-many-statements --disable=too-many-nested-blocks --disable=too-many-instance-attributes --enable=missing-docstring --enable=no-absolute-import --enable=old-division --enable=print-statement --enable=file-builtin framework/
+pylint --indent-string=" " --variable-rgx="$RGX" --attr-rgx="$RGX" --function-rgx="$RGX" --method-rgx="$METHOD_RGX" --const-rgx="$RGX" --argument-rgx="$RGX" --disable=bad-whitespace --disable=line-too-long --disable=multiple-imports --disable=import-error --disable=wrong-import-position --disable=unused-import --disable=wrong-import-order --disable=attribute-defined-outside-init --disable=too-many-branches --disable=too-many-locals --disable=too-many-statements --disable=too-many-nested-blocks --disable=too-many-instance-attributes --enable=missing-docstring --enable=no-absolute-import --enable=old-division --enable=print-statement --enable=file-builtin --enable=bare-except framework/
diff --git a/developer_tools/rook_check b/developer_tools/rook_check
new file mode 100755
index 0000000000..2de9b7c5d8
--- /dev/null
+++ b/developer_tools/rook_check
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+pylint --disable=fixme,too-few-public-methods,len-as-condition,too-many-locals,too-many-return-statements,too-many-branches,too-many-statements,too-many-instance-attributes,too-many-arguments,no-self-use,similarities,broad-except,consider-using-enumerate --const-rgx '(([A-Za-z_][A-Za-z0-9_]*)|(__.*__))$' --indent-string " " rook/*.py scripts/TestHarness/testers/*.py
diff --git a/framework/Driver.py b/framework/Driver.py
index 0255982dd4..21e5257e17 100755
--- a/framework/Driver.py
+++ b/framework/Driver.py
@@ -108,8 +108,8 @@ def checkVersions():
sys.path.append(os.path.join(os.path.dirname(frameworkDir),"scripts","TestHarness","testers"))
import RavenUtils
sys.path.pop() #remove testers path
- missing,outOfRange,notQA = RavenUtils.checkForMissingModules(False)
- if len(missing) + len(outOfRange) > 0 and RavenUtils.checkVersions():
+ missing,outOfRange,notQA = RavenUtils.check_for_missing_modules(False)
+ if len(missing) + len(outOfRange) > 0 and RavenUtils.check_versions():
print("ERROR: too old, too new, or missing raven libraries, not running:")
for error in missing + outOfRange + notQA:
print(error)
diff --git a/raven.mk b/raven.mk
index 3b2ea677e3..99f22269aa 100644
--- a/raven.mk
+++ b/raven.mk
@@ -7,15 +7,9 @@ SHELL := /bin/bash
include $(RAVEN_DIR)/amsc.mk
###############################################################################
-################################################################################
-## Build system for "hit", required by moose regression test system
-hit $(MOOSE_DIR)/python/hit.so:: $(FRAMEWORK_DIR)/contrib/hit/hit.cpp $(FRAMEWORK_DIR)/contrib/hit/lex.cc $(FRAMEWORK_DIR)/contrib/hit/parse.cc
- bash -c 'cd scripts/TestHarness/hit-windows && ./build_hit.sh'
-###############################################################################
-
-framework_modules:: amsc python_crow_modules hit
+framework_modules:: amsc python_crow_modules
-all:: amsc python_crow_modules hit
+all:: amsc python_crow_modules
####################################################################################
# find and remove all the *.pyc files (better safe then sorry) #
@@ -41,7 +35,6 @@ clean::
$(MOOSE_DIR)/python/hit.pyd
@rm -Rf $(RAVEN_DIR)/build $(FRAMEWORK_DIR)/contrib/hit/build
@find $(RAVEN_DIR)/framework -name '*.pyc' -exec rm '{}' \;
- $(MAKE) -C $(FRAMEWORK_DIR)/contrib/hit clean
cleanall::
make -C $(RAVEN_DIR) clean
diff --git a/rook/GenericExecutable.py b/rook/GenericExecutable.py
new file mode 100644
index 0000000000..7ad63df9a5
--- /dev/null
+++ b/rook/GenericExecutable.py
@@ -0,0 +1,63 @@
+# Copyright 2017 Battelle Energy Alliance, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#from util import *
+"""
+Tests by running an executable.
+"""
+from Tester import Tester
+
+class GenericExecutable(Tester):
+ """
+ A generic executable test interface.
+ """
+
+ @staticmethod
+ def get_valid_params():
+ """
+ Return a list of valid parameters and their descriptions for this type
+ of test.
+ @ In, None
+ @ Out, params, _ValidParameters, the parameters for this class.
+ """
+ params = Tester.get_valid_params()
+ params.add_required_param('executable', "The executable to use")
+ params.add_param('parameters', '', "arguments to the executable")
+ return params
+
+ def get_command(self):
+ """
+ Return the command this test will run.
+ @ In, None
+ @ Out, get_command, string, command to run
+ """
+ return self.specs["executable"]+" "+self.specs["parameters"]
+
+ def __init__(self, name, params):
+ """
+ Constructor that will setup this test with a name and a list of
+ parameters.
+ @ In, name: the name of this test case.
+ @ In, params, a dictionary of parameters and their values to use.
+ """
+ Tester.__init__(self, name, params)
+
+ def process_results(self, output):
+ """ Handle the results of test case.
+ @ In, output, string, the output from the test case.
+ @ Out, None
+ """
+ if self.results.exit_code != 0:
+ self.set_fail(str(self.results.exit_code))
+ return
+ self.set_success()
diff --git a/rook/Tester.py b/rook/Tester.py
new file mode 100644
index 0000000000..d0728cc4fe
--- /dev/null
+++ b/rook/Tester.py
@@ -0,0 +1,551 @@
+# Copyright 2017 Battelle Energy Alliance, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+This module implements classes for running tests.
+"""
+from __future__ import division, print_function, absolute_import
+import warnings
+
+import subprocess
+import sys
+import os
+import time
+import threading
+import platform
+from distutils import spawn
+
+warnings.simplefilter('default', DeprecationWarning)
+
+class _Parameter:
+ """
+ Stores a single parameter for the input.
+ """
+
+ def __init__(self, name, help_text, default=None):
+ """
+ Initializes the class
+ @ In, name, string, the name of the parameter
+ @ In, help_text, string, some help text for the user
+ @ In, default, optional, if not None this is the default value
+ @ Out, None
+ """
+ self.name = name
+ self.help_text = help_text
+ self.default = default
+
+ def __str__(self):
+ """
+ Converts the class to a string.
+ @ In, None
+ @ Out, str, string, the class as a string.
+ """
+ if self.default is None:
+ required = "Required"
+ else:
+ required = "Optional with default: "+str(self.default)
+ return self.name + " " +\
+ required + "\n" +\
+ self.help_text
+
+class _ValidParameters:
+ """
+ Contains the valid parameters that a tester or a differ can use.
+ """
+
+ def __init__(self):
+ """
+ Initializes the valid parameters class.
+ @ In, None
+ @ Out, None
+ """
+ self.__parameters = {}
+
+ def __str__(self):
+ """
+ Converts the class to a string.
+ @ In, None
+ @ Out, str, string, the class as a string.
+ """
+ return "\n\n".join([str(x) for x in self.__parameters.values()])
+
+ def add_param(self, name, default, help_text):
+ """
+ Adds an optional parameter.
+ @ In, name, string, parameter name
+ @ In, default, the default value for the parameter
+ @ In, help_text, string, Description of the parameter
+ @ Out, None
+ """
+ self.__parameters[name] = _Parameter(name, help_text, default)
+
+ def add_required_param(self, name, help_text):
+ """
+ Adds a mandatory parameter.
+ @ In, name, string parameter name
+ @ In, help_text, string, Description of the parameter
+ @ Out, None
+ """
+ self.__parameters[name] = _Parameter(name, help_text)
+
+ def get_filled_dict(self, partial_dict):
+ """
+ Returns a dictionary where default values are filled in for everything
+ that is not in the partial_dict
+ @ In, partial_dict, dictionary, a dictionary with some parameters.
+ @ Out, ret_dict, dictionary, a dictionary where all the parameters that
+ are not in partial_dict but have default values have been added.
+ """
+ ret_dict = dict(partial_dict)
+ for param in self.__parameters.values():
+ if param.default is not None and param.name not in ret_dict:
+ ret_dict[param.name] = param.default
+ return ret_dict
+
+ def check_for_required(self, check_dict):
+ """
+ Returns True if all the required parameters are present
+ @ In, check_dict, dictionary, dictionary to check
+ @ Out, all_required, boolean, True if all required parameters are in
+ check_dict.
+ """
+ all_required = True
+ for param in self.__parameters.values():
+ if param.default is None and param.name not in check_dict:
+ print("Missing:", param.name)
+ all_required = False
+ return all_required
+
+ def check_for_all_known(self, check_dict):
+ """
+ Returns True if all the parameters are known
+ @ In, check_dict, dictionary, dictionary to check
+ @ Out, no_unknown, boolean, True if all the parameters are known.
+ """
+ no_unknown = True
+ for param_name in check_dict:
+ if param_name not in self.__parameters:
+ print("Unknown:", param_name)
+ no_unknown = False
+ return no_unknown
+
+class TestResult:
+ """
+ Class to store results of the test data
+ """
+
+ def __init__(self):
+ """
+ Initializes the class
+ @ In, None
+ @ Out, None
+ """
+ self.group = Tester.group_not_set
+ self.exit_code = None
+ self.message = None
+ self.output = None
+ self.runtime = None
+
+
+class Differ:
+ """
+ Subclass are intended to check something, such as that some
+ files exist and match the gold files.
+ """
+
+ @staticmethod
+ def get_valid_params():
+ """
+ Generates the allowed parameters for this class.
+ @ In, None
+ @ Out, params, _ValidParameters, the allowed parameters for this class.
+ """
+ params = _ValidParameters()
+ params.add_required_param('type', 'The type of this differ')
+ params.add_required_param('output', 'Output files to check')
+ params.add_param('gold_files', '', 'Gold filenames')
+ return params
+
+ def __init__(self, name, params, test_dir):
+ """
+ Initializer for the class.
+ @ In, name, string, name of class
+ @ In, params, dictionary, dictionary of parameters
+ @ In, test_dir, string, path to test directory
+ @ Out, None
+ """
+ self.__name = name
+ self.__test_dir = test_dir
+ valid_params = self.get_valid_params()
+ self.specs = valid_params.get_filled_dict(params)
+ self.__output_files = self.specs['output'].split()
+
+ def get_remove_files(self):
+ """
+ Returns a list of files to remove before running test.
+ @ In, None
+ @ Out, get_remove_files, returns List(Strings)
+ """
+ return self._get_test_files()
+
+ def _get_test_files(self):
+ """
+ returns a list of the full path of the test files
+ @ In, None
+ @ Out, _get_test_files, List(Strings), the path of the test files.
+ """
+ return [os.path.join(self.__test_dir, f) for f in self.__output_files]
+
+ def _get_gold_files(self):
+ """
+ returns a list of the full path to the gold files
+ @ In, None
+ @ Out, _get_gold_files, List(Strings), the path of the gold files.
+ """
+ if len(self.specs['gold_files']) > 0:
+ gold_files = self.specs['gold_files'].split()
+ return [os.path.join(self.__test_dir, f) for f in gold_files]
+ return [os.path.join(self.__test_dir, "gold", f) for f in self.__output_files]
+
+ def check_output(self):
+ """
+ Checks that the output matches the gold.
+ Should return (same, message) where same is true if the
+ test passes, or false if the test failes. message should
+ give a human readable explaination of the differences.
+ @ In, None
+ @ Out, check_output, (same, message), same is True if checks pass.
+ """
+ assert False, "Must override check_output "+str(self)
+
+class _TimeoutThread(threading.Thread):
+ """
+ This class will kill a process after a certain amount of time
+ """
+
+ def __init__(self, process, timeout):
+ """
+ Initializes this class.
+ @ In, process, process, A process that can be killed
+ @ In, timeout, float, time in seconds to wait before killing the process.
+ @ Out, None
+ """
+ self.__process = process
+ self.__timeout = timeout
+ self.__killed = False
+ threading.Thread.__init__(self)
+
+ def run(self):
+ """
+ Runs and waits for timeout, then kills process
+ @ In, None
+ @ Out, None
+ """
+ start = time.time()
+ end = start + self.__timeout
+ while True:
+ if self.__process.poll() is not None:
+ #Process finished
+ break
+ if time.time() > end:
+ #Time over
+ #If we are on windows, process.kill() is insufficient, so using
+ # taskkill instead.
+ if os.name == "nt" and spawn.find_executable("taskkill"):
+ subprocess.call(['taskkill', '/f', '/t', '/pid', str(self.__process.pid)])
+ else:
+ self.__process.kill()
+ self.__killed = True
+ break
+ time.sleep(1.0)
+
+ def killed(self):
+ """
+ Returns if the process was killed. Notice this will be false at the
+ start.
+ @ In, None
+ @ Out, __killed, boolean, true if process killed.
+ """
+ return self.__killed
+
+class Tester:
+ """
+ This is the base class for something that can run tests.
+ """
+
+ #Various possible status groups.
+ group_skip = 0
+ group_fail = 1
+ group_diff = 2
+ group_success = 3
+ group_timed_out = 4
+ group_not_set = 5
+
+ success_message = "SUCCESS"
+
+ @staticmethod
+ def get_valid_params():
+ """
+ This generates the parameters for this class.
+ @ In, None
+ @ Out, params, _ValidParameters, the parameters for this class.
+ """
+ params = _ValidParameters()
+ params.add_required_param('type', 'The type of this test')
+ params.add_param('skip', False, 'If true skip test')
+ params.add_param('prereq', '', 'list of tests to run before running this one')
+ params.add_param('max_time', 300, 'Maximum time that test is allowed to run')
+ params.add_param('os_max_time', '', 'Maximum time by os. '+
+ ' Example: Linux 20 Windows 300 OpenVMS 1000')
+ params.add_param('method', False, 'Method is ignored, but kept for compatibility')
+ params.add_param('heavy', False, 'If true, run only with heavy tests')
+ params.add_param('output', '', 'Output of the test')
+ params.add_param('expected_fail', False,
+ 'if true, then the test should fails, and if it passes, it fails.')
+ return params
+
+ def __init__(self, name, params):
+ """
+ Initializer for the class. Takes a String name and a dictionary params
+ @ In, name, string, name of the class
+ @ In, params, dictionary, the parameters for this class to use.
+ @ Out, None
+ """
+ self.__name = name
+ valid_params = self.get_valid_params()
+ self.specs = valid_params.get_filled_dict(params)
+ self.results = TestResult()
+ self.__differs = []
+ self.__run_heavy = False
+
+ def get_differ_remove_files(self):
+ """
+ Returns the files that need to be removed for testing.
+ @ In, None
+ @ Out, remove_files, List(String), files to be removed
+ """
+ remove_files = []
+ for differ in self.__differs:
+ remove_files.extend(differ.get_remove_files())
+ return remove_files
+
+ def add_differ(self, differ):
+ """
+ Adds a differ to run after the test completes.
+ @ In, differ, Differ, A subclass of Differ that tests a file produced by the run.
+ @ Out, None
+ """
+ self.__differs.append(differ)
+
+ def get_test_dir(self):
+ """
+ Returns the test directory
+ @ In, None
+ @ Out, test_dir, string, the path to the test directory.
+ """
+ return self.specs['test_dir']
+
+ def run_heavy(self):
+ """
+ If called, run the heavy tests and not the light. Note that
+ run still needs to be called.
+ @ In, None
+ @ Out, None
+ """
+ self.__run_heavy = True
+
+
+ def run(self, data):
+ """
+ Runs the tester.
+ @ In, data, ignored, but required by pool.MultiRun
+ @ Out, results, TestResult, the results of the test.
+ """
+ expected_fail = bool(self.specs['expected_fail'])
+ results = self.run_backend(data)
+ if not expected_fail:
+ return results
+ if results.group == self.group_success:
+ results.group = self.group_fail
+ results.message = "Unexpected Success"
+ else:
+ results.group = self.group_success
+ return results
+
+ def __get_timeout(self):
+ """
+ Returns the timeout
+ @ In, None
+ @ Out, timeout, int, The maximum time for the test.
+ """
+ timeout = int(self.specs['max_time'])
+ if len(self.specs['os_max_time']) > 0:
+ time_list = self.specs['os_max_time'].lower().split()
+ system = platform.system().lower()
+ if system in time_list:
+ timeout = int(time_list[time_list.index(system)+1])
+ return timeout
+
+ def run_backend(self, _):
+ """
+ Runs this tester. This does the main work,
+ but is separate to allow run to invert the result if expected_fail
+ @ In, None
+ @ Out, results, TestResult, the results of the test.
+ """
+ if self.specs['skip'] is not False:
+ self.results.group = self.group_skip
+ self.results.message = self.specs['skip']
+ return self.results
+ if self.specs['heavy'] is not False and not self.__run_heavy:
+ self.results.group = self.group_skip
+ self.results.message = "SKIPPED (Heavy)"
+ return self.results
+ if self.specs['heavy'] is False and self.__run_heavy:
+ self.results.group = self.group_skip
+ self.results.message = "SKIPPED (not Heavy)"
+ return self.results
+ if not self.check_runnable():
+ return self.results
+
+ self.prepare()
+
+ command = self.get_command()
+
+ timeout = self.__get_timeout()
+ directory = self.specs['test_dir']
+ start_time = time.time() #Change to monotonic when min python raised to 3.3
+ try:
+ process = subprocess.Popen(command, shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ cwd=directory,
+ universal_newlines=True)
+ except IOError as ioe:
+ self.results.group = self.group_fail
+ self.results.message = "FAILED "+str(ioe)
+ return self.results
+ timed_out = False
+ if sys.version_info >= (3, 3):
+ #New timeout interface available starting in Python 3.3
+ try:
+ output = process.communicate(timeout=timeout)[0]
+ except subprocess.TimeoutExpired:
+ process.kill()
+ output = process.communicate()[0]
+ timed_out = True
+ else:
+ timeout_killer = _TimeoutThread(process, timeout)
+ timeout_killer.start()
+ output = process.communicate()[0]
+ if timeout_killer.killed():
+ timed_out = True
+ end_time = time.time()
+ process_time = end_time - start_time
+ self.results.exit_code = process.returncode
+ self.results.runtime = process_time
+ self.results.output = output
+ if timed_out:
+ self.results.group = self.group_timed_out
+ self.results.message = "Timed Out"
+ return self.results
+ self.process_results(output)
+ for differ in self.__differs:
+ same, message = differ.check_output()
+ if not same:
+ if self.results.group == self.group_success:
+ self.results.group = self.group_diff
+ self.results.message = "" #remove success message.
+ self.results.message += "\n" + message
+ return self.results
+
+ @staticmethod
+ def get_group_name(group):
+ """
+ Returns the name of this group
+ @ In, group, int, group constant
+ @ Out, get_group_name, string, name of group constant
+ """
+ names = ["Skipped", "Failed", "Diff", "Success", "Timeout", "NOT_SET"]
+ if 0 <= group < len(names):
+ return names[group]
+ return "UNKNOWN GROUP"
+
+ def check_runnable(self):
+ """
+ Checks if this test case can run
+ @ In, None
+ @ Out, check_runnable, boolean, True if this can run.
+ """
+ return True
+
+ def set_success(self):
+ """
+ Called by subclasses if this was a success.
+ @ In, None
+ @ Out, None
+ """
+ self.results.group = self.group_success
+ self.results.message = Tester.get_group_name(self.results.group)
+
+ def set_fail(self, message):
+ """
+ Sets the message string when failing
+ @ In, message, string, string description of the failure
+ @ Out, None
+ """
+ self.results.message = message
+ self.results.group = self.group_fail
+
+ def set_skip(self, message):
+ """
+ Sets the message string when skipping
+ @ In, message, string, string description of the reason to skip
+ @ Out, None
+ """
+ self.results.message = message
+ self.results.group = self.group_skip
+
+ def set_diff(self, message):
+ """
+ Sets the message string when failing for a diff
+ @ In, message, string, string description of the difference
+ @ Out, None
+ """
+ self.results.message = message
+ self.results.group = self.group_diff
+
+ def process_results(self, output):
+ """
+ Handle the results of the test case.
+ @ In, output, string, the output of the test case.
+ @ Out, None
+ """
+ assert False, "process_results not implemented "+output
+
+ def get_command(self):
+ """
+ returns the command used to run the test
+ @ In, None
+ @ Out, get_command, string, string command to run.
+ """
+ assert False, "getCommand not implemented"
+ return "none"
+
+ def prepare(self):
+ """
+ gets the test ready to run.
+ @ In, None,
+ @ Out, None
+ """
+ return
diff --git a/rook/main.py b/rook/main.py
new file mode 100644
index 0000000000..18fbdb58e9
--- /dev/null
+++ b/rook/main.py
@@ -0,0 +1,265 @@
+# Copyright 2017 Battelle Energy Alliance, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+This module is the main program for running tests.
+"""
+from __future__ import division, print_function, absolute_import
+import warnings
+
+import os
+import sys
+import argparse
+import re
+import inspect
+import time
+
+import pool
+import trees.TreeStructure
+from Tester import Tester, Differ
+
+warnings.simplefilter('default', DeprecationWarning)
+
+parser = argparse.ArgumentParser(description="Test Runner")
+parser.add_argument('-j', '--jobs', dest='number_jobs', type=int, default=1,
+ help='Specifies number of tests to run simultaneously (default: 1)')
+parser.add_argument('--re', dest='test_re_raw', default='.*',
+ help='Only tests with this regular expression inside will be run')
+parser.add_argument('-l', dest='load_average', type=float, default=-1.0,
+ help='wait until load average is below the number before starting a new test')
+parser.add_argument('--heavy', action='store_true',
+ help='Run only heavy tests')
+
+parser.add_argument('--list-testers', action='store_true', dest='list_testers',
+ help='Print out the possible testers')
+
+args = parser.parse_args()
+
+if args.load_average > 0 and hasattr(os, "getloadavg"):
+ #Note that this is also done before starting each test
+ while os.getloadavg()[0] > args.load_average:
+ print("Load Average too high, waiting ", os.getloadavg()[0])
+ time.sleep(1.0)
+
+def load_average_adapter(function):
+ """
+ Adapts function to not start until load average is low enough
+ @ In, function, function, function to call
+ @ Out, new_func, function, function that checks load average before running
+ """
+ def new_func(data):
+ """
+ function that waits until load average is lower.
+ @ In, data, Any, data to pass to function
+ @ Out, result, result of running function on data
+ """
+ while os.getloadavg()[0] > args.load_average:
+ time.sleep(1.0)
+ return function(data)
+ return new_func
+
+def get_test_lists(directory):
+ """
+ Returns a list of all the files named tests under the directory
+ @ In, directory, string, the directory to start at
+ @ Out, dir_test_list, list, the files named tests
+ """
+ dir_test_list = []
+ for root, _, files in os.walk(directory):
+ if 'tests' in files:
+ dir_test_list.append((root, os.path.join(root, 'tests')))
+ return dir_test_list
+
+def get_testers_and_differs(directory):
+ """
+ imports all the testers and differs in a directory
+ @ In, directory, string, directory to search
+ @ Out, (tester_dict, differ_dict), tuple of dictionaries
+ returns dictionaries with all the subclasses of Tester and Differ.
+ """
+ tester_dict = {}
+ differ_dict = {}
+ os.sys.path.append(directory)
+ for filename in os.listdir(directory):
+ if filename.endswith(".py") and not filename.startswith("__"):
+ module = __import__(filename[:-3]) #[:-3] to remove .py
+ for name, value in module.__dict__.items():
+ #print("Unknown", name, value)
+ if inspect.isclass(value) and value is not Tester\
+ and issubclass(value, Tester):
+ tester_dict[name] = value
+ if inspect.isclass(value) and value is not Differ\
+ and issubclass(value, Differ):
+ differ_dict[name] = value
+
+ return tester_dict, differ_dict
+
+def sec_format(runtime):
+ """
+ Formats the runtime into a string of the number seconds.
+ If runtime is none, format as None!
+ @ In, runtime, float or None, runtime to be formated.
+ @ Out, sec_format, string of runtime.
+ """
+ if isinstance(runtime, float):
+ return "{:6.2f}sec".format(runtime)
+ return " None! "
+
+def process_result(index, _input_data, output_data):
+ """
+ This is a callback function that Processes the result of a test.
+ @ In, index, int, Index into functions list.
+ @ In, _input_data, ignored, the input data passed to the function
+ @ In, output_data, Tester.TestResult the output data passed to the function
+ @ Out, None
+ """
+ group = output_data.group
+ process_test_name = test_name_list[index]
+ if group == Tester.group_success:
+ results["pass"] += 1
+ for postreq in function_postreq.get(process_test_name, []):
+ if postreq in name_to_id:
+ job_id = name_to_id[postreq]
+ print("Enabling", postreq, job_id)
+ run_pool.enable_job(job_id)
+ elif group == Tester.group_skip:
+ results["skipped"] += 1
+ print(output_data.message)
+ else:
+ results["fail"] += 1
+ failed_list.append(process_test_name)
+ print(output_data.output)
+ print(output_data.message)
+ number_done = sum(results.values())
+ print("({}/{}) {:7s} ({}) {}".format(number_done, len(function_list),
+ Tester.get_group_name(group),
+ sec_format(output_data.runtime),
+ process_test_name))
+if __name__ == "__main__":
+
+ test_re = re.compile(args.test_re_raw)
+
+ #XXX fixme to find a better way to the tests directory
+
+ this_dir = os.path.abspath(os.path.dirname(__file__))
+ up_one_dir = os.path.dirname(this_dir)
+ base_test_dir = os.path.join(up_one_dir, "tests")
+
+
+ test_list = get_test_lists(base_test_dir)
+
+ base_testers, base_differs = get_testers_and_differs(this_dir)
+ testers, differs = get_testers_and_differs(os.path.join(up_one_dir, "scripts",
+ "TestHarness", "testers"))
+ testers.update(base_testers)
+ differs.update(base_differs)
+
+ if args.list_testers:
+ print("Testers:")
+ for tester_name, tester in testers.items():
+ print("Tester:", tester_name)
+ print(tester.get_valid_params())
+ print()
+ print("Differs:")
+ for differ_name, differ in differs.items():
+ print("Differ:", differ_name)
+ print(differ.get_valid_params())
+ print()
+
+ tester_params = {}
+ for tester in testers:
+ tester_params[tester] = testers[tester].get_valid_params()
+
+ function_list = [] #Store the data for the pool runner
+ test_name_list = []
+ ready_to_run = []
+ function_postreq = {} #If this is non-empty for a key, enable the postreq's
+ name_to_id = {}
+
+ for test_dir, test_file in test_list:
+ #print(test_file)
+ tree = trees.TreeStructure.getpot_to_input_node(open(test_file, 'r'))
+ for node in tree:
+ #print(node.tag)
+ #print(node.attrib)
+ param_handler = tester_params[node.attrib['type']]
+ if not param_handler.check_for_required(node.attrib):
+ print("Missing Parameters in:", node.tag)
+ if not param_handler.check_for_all_known(node.attrib):
+ print("Unknown Parameters in:", node.tag, test_file)
+ rel_test_dir = test_dir[len(base_test_dir)+1:]
+ test_name = rel_test_dir+os.sep+node.tag
+ if "prereq" in node.attrib:
+ prereq = node.attrib['prereq']
+ prereq_name = rel_test_dir+os.sep+prereq
+ l = function_postreq.get(prereq_name, [])
+ l.append(test_name)
+ function_postreq[prereq_name] = l
+ has_prereq = True
+ else:
+ has_prereq = False
+ if test_re.search(test_name):
+ params = dict(node.attrib)
+ params['test_dir'] = test_dir
+ tester = testers[node.attrib['type']](test_name, params)
+ if args.heavy:
+ tester.run_heavy()
+ for child in node.children:
+ #print(test_name,"child",child)
+ child_type = child.attrib['type']
+ child_param_handler = differs[child_type].get_valid_params()
+ if not child_param_handler.check_for_required(child.attrib):
+ print("Missing Parameters in:", child.tag, node.tag, test_file)
+ if not child_param_handler.check_for_all_known(child.attrib):
+ print("Unknown Parameters in:", child.tag, node.tag, test_file)
+ differ = differs[child_type](child.tag, dict(child.attrib), test_dir)
+ tester.add_differ(differ)
+ id_num = len(function_list)
+ #input_filename = node.attrib['input']
+ func = tester.run
+ if args.load_average > 0 and hasattr(os, "getloadavg"):
+ func = load_average_adapter(func)
+ function_list.append((func, (test_dir)))
+ test_name_list.append(test_name)
+ ready_to_run.append(not has_prereq)
+ name_to_id[test_name] = id_num
+
+ run_pool = pool.MultiRun(function_list, args.number_jobs, ready_to_run)
+
+ run_pool.run()
+
+ results = {"pass":0, "fail":0, "skipped":0}
+ failed_list = []
+
+ output_list = run_pool.process_results(process_result)
+ run_pool.wait()
+
+ if results["fail"] > 0:
+ print("FAILED:")
+ for path in failed_list:
+ print(path)
+
+ csv_report = open("test_report.csv", "w")
+ csv_report.write(",".join(["name", "passed", "group", "time"])+"\n")
+ for result, test_name in zip(output_list, test_name_list):
+ if result is not None:
+ group_name = Tester.get_group_name(result.group)
+ out_line = ",".join([test_name, str(result.group == Tester.group_success),
+ group_name, str(result.runtime)])
+ else:
+ out_line = ",".join([test_name, str(False), "NO_PREREQ", str(0.0)])
+ csv_report.write(out_line+"\n")
+ csv_report.close()
+
+ print("PASSED:", results["pass"], "FAILED:", results["fail"], "SKIPPED", results["skipped"])
+ sys.exit(results["fail"])
diff --git a/rook/pool.py b/rook/pool.py
new file mode 100644
index 0000000000..fc7c43aebc
--- /dev/null
+++ b/rook/pool.py
@@ -0,0 +1,198 @@
+# Copyright 2017 Battelle Energy Alliance, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+This module implements a thread pool for running tasks.
+"""
+from __future__ import division, print_function, absolute_import
+import warnings
+
+import threading
+try:
+ import queue
+except ImportError:
+ import Queue as queue
+import time
+
+warnings.simplefilter('default', DeprecationWarning)
+
+class RunnerThread(threading.Thread):
+ """
+ This class runs functions in the input queue and puts the results in
+ the output queue
+ """
+
+ def __init__(self, input_queue, output_queue):
+ """
+ Initializes with an input queue and an output queue
+ Functions and ids in the input_queue will be run and the output
+ put into the output queue
+ @ In, input_queueo, queue.Queue, queue with the input data and functions to run
+ @ In, output_queue, queue.Queue, queue to put result data
+ @ Out, None
+ """
+ self.__input_queue = input_queue
+ self.__output_queue = output_queue
+ self.__done = False
+ threading.Thread.__init__(self)
+
+ def run(self):
+ """
+ Runs the functions until the queue is empty.
+ @ In, None
+ @ Out, None
+ """
+ try:
+ #Keep going as long as there are items in the queue
+ while True:
+ id_num, function, data = self.__input_queue.get(block=False)
+ output = function(data)
+ self.__output_queue.put((id_num, output))
+ self.__input_queue.task_done()
+ except queue.Empty:
+ self.__done = True
+ return
+
+ def is_done(self):
+ """
+ Returns true if this is done running. Also should check is_alive to
+ find out if it failed to successfully finish.
+ @ In, None
+ @ Out, __done, boolean, true if this successfully finished running.
+ """
+ return self.__done
+
+class MultiRun:
+ """
+ This creates queues and runner threads to process the functions.
+ """
+ def __init__(self, function_list, number_jobs, ready_to_run=None):
+ """
+ Initializes the class
+ @ In, function_list, list, list of functions and data to run
+ @ In, number_jobs, int, number of functions to run simultaneously.
+ @ In, ready_to_run, list, optional, list of if functions are ready to run
+ @ Out, None
+ """
+ self.__function_list = function_list
+ self.__runners = [None]*number_jobs
+ self.__input_queue = queue.Queue()
+ self.__output_queue = queue.Queue()
+ if ready_to_run is not None:
+ assert len(ready_to_run) == len(self.__function_list)
+ self.__ready_to_run = ready_to_run[:]
+ else:
+ self.__ready_to_run = [True]*len(self.__function_list)
+ self.__not_ready = 0
+
+
+ def run(self):
+ """
+ Starts running all the tests
+ @ In, None
+ @ Out, None
+ """
+ self.__not_ready = 0
+ for id_num, (function, data) in enumerate(self.__function_list):
+ if self.__ready_to_run[id_num]:
+ self.__input_queue.put((id_num, function, data))
+ else:
+ self.__not_ready += 1
+ for i in range(len(self.__runners)):
+ self.__runners[i] = RunnerThread(self.__input_queue, self.__output_queue)
+ for runner in self.__runners:
+ runner.start()
+
+ def enable_job(self, id_num):
+ """
+ Enables the previously not ready job
+ @ In, id_num, int, id (index in function_list) to enable
+ @ Out, None
+ """
+ assert not self.__ready_to_run[id_num]
+ self.__not_ready -= 1
+ self.__ready_to_run[id_num] = True
+ function, data = self.__function_list[id_num]
+ self.__input_queue.put((id_num, function, data))
+ self.__restart_runners()
+
+ def __restart_runners(self):
+ """
+ Restarts any dead runners
+ @ In, None
+ @ Out, None
+ """
+ for i in range(len(self.__runners)):
+ if self.__runners[i].is_done() or not self.__runners[i].is_alive():
+ #Restart since it is done. Otherwise might not be any runners still
+ # running
+ self.__runners[i] = RunnerThread(self.__input_queue, self.__output_queue)
+ self.__runners[i].start()
+
+ def __runner_count(self):
+ """
+ Returns how many runners are not done.
+ @ In, None
+ @ Out, runner_count, int, alive runners
+ """
+ runner_count = 0
+ for i in range(len(self.__runners)):
+ if self.__runners[i].is_alive():
+ runner_count += 1
+ return runner_count
+
+ def process_results(self, process_function=None):
+ """
+ Process results and return the output in an array.
+ If a process_function is passed in, it will be called with
+ process_function(index, input, output) after the output is created.
+ @ In, process_function, function, optional, function called after each input finishes.
+ @ Out, return_array, list, includes the outputs of the functions.
+ """
+ return_array = [None]*len(self.__function_list)
+ output_count = 0
+ count_down = 10
+ while output_count < len(return_array):
+ while output_count + self.__not_ready < len(return_array):
+ #This is debug information meant to help if the test system deadlocks
+ # It could be commented out, but probably should not be deleted.
+ print("debug numbers oc", output_count, "nr", self.__not_ready,
+ "lra", len(return_array), "rc", self.__runner_count(), "ie",
+ self.__input_queue.empty(), "oe", self.__output_queue.empty())
+ if self.__runner_count() == 0 and not self.__input_queue.empty():
+ print("restarting runners")
+ self.__restart_runners()
+ id_num, output = self.__output_queue.get()
+ count_down = 10
+ return_array[id_num] = output
+ output_count += 1
+ if process_function is not None:
+ _, data = self.__function_list[id_num]
+ process_function(id_num, data, output)
+ time.sleep(0.1)
+ if count_down <= 0:
+ #Check and see if any runners are still running
+ runner_count = self.__runner_count()
+ if runner_count == 0:
+ break
+ count_down -= 1
+ assert self.__output_queue.empty(), "Output queue not empty"
+ return return_array
+
+ def wait(self):
+ """
+ wait for all the tasks to be finished
+ @ In, None
+ @ Out, None
+ """
+ self.__input_queue.join()
diff --git a/rook/trees/TreeStructure.py b/rook/trees/TreeStructure.py
new file mode 100644
index 0000000000..d36b3656d6
--- /dev/null
+++ b/rook/trees/TreeStructure.py
@@ -0,0 +1,310 @@
+# Copyright 2017 Battelle Energy Alliance, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Created on Jan 28, 2014
+@ author: alfoa
+This is a simplified version of Raven framework/utils/TreeStructure.py
+"""
+
+#for future compatibility with Python 3--------------------------------------------------------------
+from __future__ import division, print_function, unicode_literals, absolute_import
+import warnings
+warnings.simplefilter('default',DeprecationWarning)
+#End compatibility block for Python 3----------------------------------------------------------------
+
+#message handler
+import os, sys
+#import MessageHandler
+
+##################
+# MODULE METHODS #
+##################
+
+
+def getpot_to_input_node(getpot):
+ """
+ Converts a getpot file into an InputNode object.
+ @ In, getpot, file, file object with getpot syntax
+ @ Out, tree, InputNode, node with sorted information
+ """
+ #root = Node()
+ parentNodes = []#root]
+ currentNode = None
+ global comment
+ comment = None
+ def addComment(node):
+ """
+ If comment is not None, adds it to node
+ @ In, node, Node, node
+ @ Out, None
+ """
+ global comment
+ if comment is not None:
+ node.addComment(comment)
+ comment = None
+ #end addComment
+ for line in getpot:
+ line = line.strip()
+ #if comment in line, store it for now
+ if '#' in line:
+ if comment is not None:
+ #need to stash comments, attributes for node
+ comment += "\n"+'#'.join(line.split('#')[1:])
+ comment = '#'.join(line.split('#')[1:])
+ line = line.split('#')[0].strip()
+ #if starting new node
+ if line.startswith('[./') and line.endswith(']'):
+ #if child node, stash the parent for now
+ if currentNode is not None:
+ parentNodes.append(currentNode)
+ currentNode = InputNode(tag=line[3:-1])#,attrib={})
+ addComment(currentNode)
+ #if at end of node
+ elif line == '[../]':
+ #FIXME what if parentNodes is empty, i.e., back to the beginning? Simulation node wrapper?
+ #add currently-building node to its parent
+ if len(parentNodes)>0:
+ parentNodes[-1].append(currentNode)
+ #make parent the active node
+ currentNode = parentNodes.pop()
+ else:
+ #this is the root
+ root = currentNode
+ addComment(currentNode) #FIXME should belong to next child? Hard to say.
+ #empty line
+ elif line == '':
+ if currentNode is not None:
+ currentNode.addComment(comment)
+ #attribute setting line
+ elif '=' in line:
+ #TODO FIXME add attribute comment!
+ attribute,value = list(i.strip() for i in line.split('='))
+ value = value.strip("'")
+ if attribute in currentNode.attrib.keys():
+ raise IOError('Multiple attributes defined with same name! "'+attribute+'" = "'+value+'"')
+ #special keywords: "name" and "value"
+ elif attribute == 'value':
+ currentNode.text = value
+ #TODO default lists: spaces, commas, or ??? (might just work anyway?)
+ # -> getpot uses spaces surrounded by apostrophes, '1 2 3'
+ # -> raven sometimes does spaces 1 2 3> and sometimes commas 1,2,3
+ else:
+ currentNode.attrib[attribute] = value
+ #[]
+ elif line == "[]":
+ assert parentNodes == [], line
+ root = currentNode
+ currentNode = None
+ #[something]
+ elif line.startswith('[') and line.endswith(']'):
+ assert currentNode is None, line
+ currentNode = InputNode(tag=line[1:-1])
+ addComment(currentNode)
+ else:
+ addComment(currentNode)
+ raise IOError('Unrecognized line syntax:',line)
+ return root
+
+
+#########
+# NODES #
+#########
+class InputNode:
+ """
+ Node in an input tree. Simulates all the behavior of an XML node.
+ """
+ #built-in functions
+ def __init__(self,tag='',attrib=None,text='',comment=None):
+ """
+ Constructor.
+ @ In, tag, string, node name
+ @ In, attrib, dict, attributes
+ @ In, text, string, text of node
+ @ Out, None
+ """
+ if attrib is None:
+ self.attrib = {}
+ else:
+ self.attrib = attrib #structure: {name: {value='',comment=''}}
+
+ self.tag = tag #node name, in XML known as "tag"
+ self.text = text #node text, same in XML
+ self.children = [] #branches off of this node
+ self.comments = [comment] if comment is not None else [] #allow for multiple comments
+
+ def __eq__(self,other):
+ """
+ Determines if this object is NOT the same as "other".
+ @ In, other, the object to compare to
+ @ Out, same, boolan, true if same
+ """
+ if isinstance(other,self.__class__):
+ same = True
+ if self.tag != other.tag or \
+ self.text != other.text or \
+ self.attrib != other.attrib:
+ same = False
+ #else: TODO compare children!
+ #TODO use XML differ for this whole thing?
+ return same
+ return False
+
+ def __ne__(self,other):
+ """
+ Determines if this object is NOT the same as "other".
+ @ In, other, the object to compare to
+ @ Out, same, boolan, true if not same
+ """
+ return not self.__eq__(other)
+
+ def __hash__(self):
+ """
+ Overrides the default hash.
+ @ In, None
+ @ Out, hash, tuple, name and values and text
+ """
+ return hash(tuple((self.tag,tuple(sorted(self.attrib.items())),self.text)))
+
+ def __iter__(self):
+ """
+ Provides a method to iterate over the child nodes of this node.
+ @ In, None
+ @ Out, __iter__, iterator, generator for the children
+ """
+ i = 0
+ while i < len(self):
+ yield self.children[i]
+ i += 1
+
+ def __len__(self):
+ """
+ Returns the number of child nodes for this node.
+ @ In, None
+ @ Out, __len__, int, number of children
+ """
+ return len(self.children)
+
+ def __getitem__(self, index):
+ """
+ Returns a specific child node.
+ @ In, index, int, the index for the child
+ @ Out, __getitem__, InputNode, the child
+ """
+ return self.children[index]
+
+ def __setitem__(self,index,value):
+ """
+ Sets a specific child node.
+ @ In, index, int, the index for the child
+ @ In, value, Node, the child itself
+ @ Out, None
+ """
+ self.children[index] = value
+
+ def __repr__(self):
+ """
+ String representation.
+ @ In, None
+ @ Out, __repr__, string, representation of the object
+ """
+ return "" %(repr(self.tag),str(self.attrib),id(self),repr(len(self)))
+
+ #methods
+ def add(self, key, value):
+ """
+ Method to add a new value into this node
+ If the key is already present, the corresponding value gets updated
+ @ In, key, string, id name of this value
+ @ In, value, whatever type, the newer value
+ """
+ self.attrib[key] = value
+
+ def addComment(self,comment):
+ """
+ Adds comment to node.
+ @ In, comment, string, comment to add
+ @ Out, None
+ """
+ if comment is not None:
+ self.comments.append(comment)
+
+ def append(self,node):
+ """
+ Add a new child node to this node.
+ @ In, node, Node, node to append to children
+ @ Out, None
+ """
+ self.children.append(node)
+
+ def find(self,nodeName):
+ """
+ Searches children for node with name matching nodeName.
+ @ In, nodeName, string, name to match
+ @ Out, node, InputNode, match is present else None
+ """
+ for child in self:
+ if child.tag == nodeName:
+ return child
+ return None
+
+ def findall(self,nodeName):
+ """
+ Searches children for node with name matching nodeName.
+ @ In, nodeName, string, name to match
+ @ Out, nodes, [InputNode], all the matches
+ """
+ nodes = []
+ for child in self:
+ if child.tag == nodeName:
+ nodes.append(child)
+ return nodes
+
+ def get(self,attr):
+ """
+ Obtains attribute value for "attr"
+ @ In, attr, string, name of attribute to obtain
+ @ Out, get, string, value if present else None
+ """
+ return self.attrib.get(attr,None)
+
+ def iter(self, name=None):
+ """
+ Creates a tree iterator. The iterator loops over this node
+ and all subnodes and returns all nodes with a matching name.
+ @ In, name, string, optional, name of the branch wanted
+ @ Out, e, iterator, the iterator
+ """
+ if name == "*":
+ name = None
+ if name is None or self.name == name:
+ yield self
+ for e in self.children:
+ for e in e.iter(name):
+ yield e
+
+ def remove(self,node):
+ """
+ Removes a child from the tree.
+ @ In, node, InputNode, node to remove
+ @ Out, None
+ """
+ self.children.remove(node)
+
+ def items(self):
+ """
+ Gets all the children in the tree.
+ @ In, None
+ @ Out, children, list, list of all the children.
+ """
+ return self.children
diff --git a/rook/trees/__init__.py b/rook/trees/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/run_framework_tests b/run_framework_tests
index e622171e11..385221da01 100755
--- a/run_framework_tests
+++ b/run_framework_tests
@@ -1,4 +1,3 @@
#!/bin/bash
cd `dirname $0`
-source scripts/establish_conda_env.sh --quiet --load
-./backend_run_tests --re=framework --skip-config-check "$@"
+./run_tests --re=framework "$@"
diff --git a/run_tests b/run_tests
index 15510a57f3..a56fbb19e4 100755
--- a/run_tests
+++ b/run_tests
@@ -13,15 +13,30 @@ SCRIPT_DIR=`(cd $SCRIPT_DIRNAME; pwd)`
echo 'Loading libraries ...'
source $SCRIPT_DIR/scripts/establish_conda_env.sh --load
+if test -n "$CHECK_PYTHON3"; then
+ PYTHON=python3
+else
+ PYTHON=python
+fi
+
+for A in "$@"; do
+ case $A in
+ --library_report | --library-report)
+ $PYTHON $SCRIPT_DIR/scripts/library_report
+ exit
+ ;;
+ esac
+done
+
# this copy the plugins tests into raven tests
echo 'Loading plugin tests ...'
-python $SCRIPT_DIR/scripts/copy_plugins_tests.py
+$PYTHON $SCRIPT_DIR/scripts/copy_plugins_tests.py
# run the tests
echo 'Running tests ...'
-python backend_run_tests --skip-config-check "$@"
+$PYTHON $SCRIPT_DIR/rook/main.py "$@"
# grep return code
rc=$?
# this copy back the plugins and remove them from the source folder
-python $SCRIPT_DIR/scripts/copy_back_plugins_results.py
+$PYTHON $SCRIPT_DIR/scripts/copy_back_plugins_results.py
# return code
if [[ $rc != 0 ]]; then exit $rc; fi
diff --git a/scripts/TestHarness/hit-windows/build_hit.sh b/scripts/TestHarness/hit-windows/build_hit.sh
deleted file mode 100755
index 847515d1ad..0000000000
--- a/scripts/TestHarness/hit-windows/build_hit.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-HIT_DIR=../../../moose/framework/contrib/hit
-MOOSE_PYTHON_DIR=../../../moose/python
-if [[ $VS90COMNTOOLS ]]
-then
- cp setup.py $HIT_DIR
- pushd $HIT_DIR
- python setup.py build_ext --inplace --compiler=msvc
- EXIT_CODE=$?
- popd
- cp ${HIT_DIR}/hit.pyd $MOOSE_PYTHON_DIR
- touch ${MOOSE_PYTHON_DIR}/hit.so
-else
- make -C $HIT_DIR bindings
- EXIT_CODE=$?
- cp ${HIT_DIR}/hit.so $MOOSE_PYTHON_DIR
-fi
-echo ls -l $MOOSE_PYTHON_DIR
-ls -l $MOOSE_PYTHON_DIR
-exit $EXIT_CODE
diff --git a/scripts/TestHarness/hit-windows/setup.py b/scripts/TestHarness/hit-windows/setup.py
deleted file mode 100644
index 55369dc3f3..0000000000
--- a/scripts/TestHarness/hit-windows/setup.py
+++ /dev/null
@@ -1,16 +0,0 @@
-try:
- from setuptools import setup
- from setuptools import Extension
-except ImportError:
- from distutils.core import setup
- from distutils.extension import Extension
-
-setup(
- ext_modules=[
- Extension(
- "hit",
- ["hit.cpp", "lex.cc", "parse.cc"],
- extra_compile_args=['-std=c++11'],
- )
- ]
-)
diff --git a/scripts/TestHarness/testers/CrowPython.py b/scripts/TestHarness/testers/CrowPython.py
index 5a7a9c5527..613db2d8e7 100644
--- a/scripts/TestHarness/testers/CrowPython.py
+++ b/scripts/TestHarness/testers/CrowPython.py
@@ -11,35 +11,47 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-from util import *
+#from util import *
+"""
+Tests by running a python program.
+"""
+import os
+import subprocess
from Tester import Tester
-import os, subprocess
class CrowPython(Tester):
""" A python test interface for Crow """
try:
- output_swig = subprocess.Popen(["swig","-version"],stdout=subprocess.PIPE).communicate()[0]
+ output_swig = subprocess.Popen(["swig", "-version"], stdout=subprocess.PIPE,
+ universal_newlines=True).communicate()[0]
except OSError:
output_swig = "Failed"
has_swig2 = "Version 2.0" in output_swig or "Version 3.0" in output_swig
@staticmethod
- def validParams():
- """ Return a list of valid parameters and their descriptions for this type
- of test.
+ def get_valid_params():
"""
- params = Tester.validParams()
- params.addRequiredParam('input',"The python file to use for this test.")
- if os.environ.get("CHECK_PYTHON3","0") == "1":
- params.addParam('python_command','python3','The command to use to run python')
+ Return a list of valid parameters and their descriptions for this type
+ of test.
+ @ In, None
+ @ Out, params, _ValidParameters, return the parameters.
+ """
+ params = Tester.get_valid_params()
+ params.add_required_param('input', "The python file to use for this test.")
+ if os.environ.get("CHECK_PYTHON3", "0") == "1":
+ params.add_param('python_command', ' python3', 'The command to use to run python')
else:
- params.addParam('python_command','python','The command to use to run python')
- params.addParam('requires_swig2', False, "Requires swig2 for test")
+ params.add_param('python_command', 'python', 'The command to use to run python')
+ params.add_param('requires_swig2', False, "Requires swig2 for test")
return params
- def getCommand(self, options):
- """ Return the command this test will run. """
+ def get_command(self):
+ """
+ Return the command this test will run.
+ @ In, None
+ @ Out, get_command, string, string command to use.
+ """
return self.specs["python_command"]+" "+self.specs["input"]
def __init__(self, name, params):
@@ -51,23 +63,18 @@ def __init__(self, name, params):
Tester.__init__(self, name, params)
self.specs['scale_refine'] = False
- def __init__(self, name, params):
- """ Constructor that will setup this test with a name and a list of
- parameters.
- @ In, name: the name of this test case.
- @ In, params, a dictionary of parameters and their values to use.
+ def check_runnable(self):
+ """
+ Checks if a test case is capable of being run on the current system.
+ @ In, None
+ @ Out, check_runnable, boolean, True if this test can run.
"""
- Tester.__init__(self, name, params)
- self.specs['scale_refine'] = False
-
- def checkRunnable(self, option):
- """ Checks if a test case is capable of being run on the current system. """
if self.specs['requires_swig2'] and not CrowPython.has_swig2:
- self.setStatus('skipped (No swig 2.0 found)', self.bucket_skip)
+ self.set_skip('skipped (No swig 2.0 found)')
return False
return True
- def processResults(self, moose_dir, options, output):
+ def process_results(self, output):
""" Handle the results of test case.
@ In, moose_dir: the root directory where MOOSE resides on the current
system.
@@ -75,8 +82,8 @@ def processResults(self, moose_dir, options, output):
@ In, output: the output from the test case.
@ Out: a tuple with the error return code and the output passed in.
"""
- if self.exit_code != 0:
- self.setStatus(str(self.exit_code), self.bucket_fail)
+ if self.results.exit_code != 0:
+ self.set_fail(str(self.results.exit_code))
return output
- self.setStatus(self.success_message, self.bucket_success)
+ self.set_success()
return output
diff --git a/scripts/TestHarness/testers/DiffUtils.py b/scripts/TestHarness/testers/DiffUtils.py
new file mode 100644
index 0000000000..2cb0c82187
--- /dev/null
+++ b/scripts/TestHarness/testers/DiffUtils.py
@@ -0,0 +1,166 @@
+# Copyright 2017 Battelle Energy Alliance, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Utilities for comparing strings.
+"""
+import re
+import sys
+
+#A float consists of possibly a + or -, followed possibly by some digits
+# followed by one of ( digit. | .digit | or digit) possibly followed by some
+# more digits possibly followed by an exponent
+floatRe = re.compile("([-+]?\\d*(?:(?:\\d[.])|(?:[.]\\d)|(?:\\d))\\d*(?:[eE][+-]\\d+)?)")
+
+def split_into_parts(s_var):
+ """
+ Splits the string into floating parts and not float parts
+ @ In, s_var, string, the string to split
+ @ Out, split_into_parts, string, a list where the even indexs are
+ string and the odd indexs are floating point number strings.
+ """
+ return floatRe.split(s_var)
+
+def short_text(a_str, b_str):
+ """
+ Returns a short portion of the text that shows the first difference
+ @ In, a_str, string, the first text element
+ @ In, b_str, string, the second text element
+ @ Out, short_text, string, resulting shortened diff
+ """
+ a_str = repr(a_str)
+ b_str = repr(b_str)
+ display_len = 20
+ half_display = display_len//2
+ if len(a_str)+len(b_str) < display_len:
+ return a_str+" "+b_str
+ first_diff = -1
+ i = 0
+ while i < len(a_str) and i < len(b_str):
+ if a_str[i] == b_str[i]:
+ i += 1
+ else:
+ first_diff = i
+ break
+ if first_diff >= 0:
+ #diff in content
+ start = max(0, first_diff - half_display)
+ else:
+ #diff in length
+ first_diff = min(len(a_str), len(b_str))
+ start = max(0, first_diff - half_display)
+ if start > 0:
+ prefix = "..."
+ else:
+ prefix = ""
+ return prefix+a_str[start:first_diff+half_display]+" "+prefix+\
+ b_str[start:first_diff+half_display]
+
+def set_default_options(options):
+ """
+ sets all the options to defaults
+ @ In, options, dict, dictionary to add default options to
+ @ Out, None
+ """
+ options["rel_err"] = float(options.get("rel_err", 1.e-10))
+ options["zero_threshold"] = float(options.get("zero_threshold", sys.float_info.min*4.0))
+ options["remove_whitespace"] = options.get("remove_whitespace", False)
+ options["remove_unicode_identifier"] = options.get("remove_unicode_identifier", False)
+
+def remove_whitespace_chars(s_var):
+ """
+ Removes whitespace characters
+ @ In, s, string, to remove characters from
+ @ Out, s, string, removed whitespace string
+ """
+ s_var = s_var.replace(" ", "")
+ s_var = s_var.replace("\t", "")
+ s_var = s_var.replace("\n", "")
+ #if this were python3 this would work:
+ #remove_whitespaceTrans = "".maketrans("",""," \t\n")
+ #s = s.translate(remove_whitespaceTrans)
+ return s_var
+
+def remove_unicode_identifiers(s_var):
+ """
+ Removes the u infrount of a unicode string: u'string' -> 'string'
+ Note that this also removes a u at the end of string 'stru' -> 'str'
+ which is not intended.
+ @ In, s_var, string, string to remove characters from
+ @ Out, s_var, string, cleaned string
+ """
+ s_var = s_var.replace("u'", "'")
+ return s_var
+
+def compare_strings_with_floats(a_str, b_str, num_tol=1e-10,
+ zero_threshold=sys.float_info.min*4.0,
+ remove_whitespace=False,
+ remove_unicode_identifier=False):
+ """
+ Compares two strings that have floats inside them.
+ This searches for floating point numbers, and compares them with a
+ numeric tolerance.
+ @ In, a_str, string, first string to use
+ @ In, b_str, string, second string to use
+ @ In, num_tol, float, the numerical tolerance.
+ @ In, zeroThershold, float, it represents the value below which a float
+ is considered zero (XML comparison only). For example, if
+ zeroThershold = 0.1, a float = 0.01 will be considered as it was 0.0
+ @ In, remove_whitespace, bool, if True, remove all whitespace before comparing.
+ @ Out, compareStringWithFloats, (bool,string), (succeeded, note) where
+ succeeded is a boolean that is true if the strings match, and note is
+ a comment on the comparison.
+ """
+ if a_str == b_str:
+ return (True, "Strings Match")
+ if a_str is None or b_str is None:
+ return (False, "One of the strings contain a None")
+ if remove_whitespace:
+ a_str = remove_whitespace_chars(a_str)
+ b_str = remove_whitespace_chars(b_str)
+ if remove_unicode_identifier:
+ a_str = remove_unicode_identifiers(a_str)
+ b_str = remove_unicode_identifiers(b_str)
+ a_list = split_into_parts(a_str)
+ b_list = split_into_parts(b_str)
+ if len(a_list) != len(b_list):
+ return (False, "Different numbers of float point numbers")
+ for i in range(len(a_list)):
+ a_part = a_list[i].strip()
+ b_part = b_list[i].strip()
+ if i % 2 == 0:
+ #In string
+ if a_part != b_part:
+ return (False, "Mismatch of "+short_text(a_part, b_part))
+ else:
+ #In number
+ a_float = float(a_part)
+ b_float = float(b_part)
+ a_float = a_float if abs(a_float) > zero_threshold else 0.0
+ b_float = b_float if abs(b_float) > zero_threshold else 0.0
+ if abs(a_float - b_float) > num_tol:
+ return (False, "Numeric Mismatch of '"+a_part+"' and '"+b_part+"'")
+
+ return (True, "Strings Match Floatwise")
+
+def is_a_number(x_var):
+ """
+ Checks if x_var can be converted to a float.
+ @ In, x_var, object, a variable or value
+ @ Out, is_a_number, bool, True if x can be converted to a float.
+ """
+ try:
+ float(x_var)
+ return True
+ except ValueError:
+ return False
diff --git a/scripts/TestHarness/testers/OrderedCSVDiffer.py b/scripts/TestHarness/testers/OrderedCSVDiffer.py
new file mode 100644
index 0000000000..95c78243f2
--- /dev/null
+++ b/scripts/TestHarness/testers/OrderedCSVDiffer.py
@@ -0,0 +1,254 @@
+# Copyright 2017 Battelle Energy Alliance, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+This implements comparing CSV files in order.
+"""
+from __future__ import division, print_function, unicode_literals, absolute_import
+import sys
+import csv
+
+from Tester import Differ
+
+whoAmI = False # enable to show test dir and out files
+debug = False # enable to increase printing
+
+def to_float(s_val):
+ """
+ Converts s to a float if possible.
+ @ In, s_val, any, value to convert
+ @ Out, s_val, float or any
+ """
+ try:
+ return float(s_val)
+ except ValueError:
+ return s_val
+
+class OrderedCSVDiffer:
+ """
+ Used for comparing two CSV files without regard for column, row orders
+ """
+ def __init__(self, out_files, gold_files, relative_error=1e-10,
+ absolute_check=False, zero_threshold=None, ignore_sign=False):
+ """
+ Create an UnorderedCSVDiffer class
+ Note naming conventions are out of our control due to MOOSE test harness standards.
+ @ In, out_files, the files to be compared. They will be in test_dir + out_files
+ @ In, gold_files, the files to be compared to the out_files.
+ @ In, relative_error, float, optional, relative error
+ @ In, absolute_check, bool, optional, if True then check absolute
+ differences in the values instead of relative differences
+ @ In, ignore_sign, bool, optional, if True then the sign will be ignored during the comparison
+ @ Out, None.
+ """
+ assert len(out_files) == len(gold_files)
+ self.__out_files = out_files
+ self.__gold_files = gold_files
+ self.__message = ""
+ self.__same = True
+ self.__check_absolute_values = absolute_check
+ self.__rel_err = relative_error
+ self.__zero_threshold = float(zero_threshold) if zero_threshold is not None else 0.0
+ self.__ignore_sign = ignore_sign
+ if debug or whoAmI:
+ print('gold files:', self.__gold_files)
+ print('out files:', self.__out_files)
+ if debug:
+ print('err :', self.__rel_err)
+ print('abs check:', self.__check_absolute_values)
+ print('zero thr :', self.__zero_threshold)
+
+ def finalize_message(self, same, msg, filename):
+ """
+ Compiles useful messages to print, prepending with file paths.
+ @ In, same, bool, True if files are the same
+ @ In, msg, list(str), messages that explain differences
+ @ In, filename, str, test filename/path
+ @ Out, None
+ """
+ if not same:
+ self.__same = False
+ self.__message += '\nDIFF in {}: \n {}'.format(filename, '\n '.join(msg))
+
+ def matches(self, a_obj, b_obj, is_number, tol):
+ """
+ Determines if two objects match within tolerance.
+ @ In, a_obj, object, first object ("measured")
+ @ In, b_obj, object, second object ("actual")
+ @ In, is_number, bool, if True then treat as float with tolerance (else check equivalence)
+ @ In, tol, float, tolerance at which to hold match (if float)
+ @ Out, matches, bool, True if matching
+ """
+ if not is_number:
+ return a_obj == b_obj
+ if self.__ignore_sign:
+ a_obj = abs(a_obj)
+ b_obj = abs(b_obj)
+ if abs(a_obj) < self.__zero_threshold:
+ a_obj = 0.0
+ if abs(b_obj) < self.__zero_threshold:
+ b_obj = 0.0
+ if self.__check_absolute_values:
+ return abs(a_obj-b_obj) < tol
+ # otherwise, relative error
+ scale = abs(b_obj) if b_obj != 0 else 1.0
+ return abs(a_obj-b_obj) < scale*tol
+
+ def diff(self):
+ """
+ Run the comparison.
+ @ In, None
+ @ Out, same, bool, if True then files are the same
+ @ Out, messages, str, messages to print on fail
+ """
+ # read in files
+ for test_filename, gold_filename in zip(self.__out_files, self.__gold_files):
+ # local "same" and message list
+ same = True
+ msg = []
+ # load test file
+ try:
+ try:
+ test_csv_file = open(test_filename, newline='')
+ except TypeError:
+ #We must be in Python 2
+ test_csv_file = open(test_filename, 'rb')
+ # if file doesn't exist, that's another problem
+ except IOError:
+ msg.append('Test file does not exist!')
+ same = False
+ # load gold file
+ try:
+ try:
+ gold_csv_file = open(gold_filename, newline='')
+ except TypeError:
+ #We must be in Python 2
+ gold_csv_file = open(gold_filename, 'rb')
+ # if file doesn't exist, that's another problem
+ except IOError:
+ msg.append('Gold file does not exist!')
+ same = False
+ # if either file did not exist, clean up and go to next outfile
+ if not same:
+ self.finalize_message(same, msg, test_filename)
+ continue
+ # at this point, we've loaded both files (even if they're empty), so compare them.
+ ## first, cover the case when both files are empty.
+ gold_rows = list(csv.reader(gold_csv_file))
+ test_rows = list(csv.reader(test_csv_file))
+ ## at this point, both files have data loaded
+ ## check columns using symmetric difference
+ gold_headers = gold_rows[0]
+ test_headers = test_rows[0]
+ diff_columns = set(gold_headers)^set(test_headers)
+ if len(diff_columns) > 0:
+ same = False
+ msg.append('Columns are not the same! Different: {}'.format(', '.join(diff_columns)))
+ self.finalize_message(same, msg, test_filename)
+ continue
+ ## check index length
+ if len(gold_rows) != len(test_rows):
+ same = False
+ msg.append('Different number of entires in Gold ({}) versus Test ({})!'
+ .format(len(gold_rows), len(test_rows)))
+ self.finalize_message(same, msg, test_filename)
+ continue
+ ## at this point both CSVs have the same shape, with the same header contents.
+ ## figure out column indexs
+ if gold_headers == test_headers:
+ test_indexes = range(len(gold_headers))
+ else:
+ test_indexes = [test_headers.index(s) for s in gold_headers]
+ # So now for a test row:
+ # gold_row[x][y] should match test_row[x][test_indexes[y]]
+ ## check for matching rows
+ for idx in range(1, len(gold_rows)):
+ gold_row = gold_rows[idx]
+ test_row = test_rows[idx]
+ for column in range(len(gold_row)):
+ gold_value = to_float(gold_row[column])
+ test_value = to_float(test_row[test_indexes[column]])
+ match_is_number = isinstance(gold_value, float)
+ val_is_number = isinstance(test_value, float)
+ if match_is_number != val_is_number:
+ same = False
+ msg.append("Different types in "+gold_headers[column]+" for "
+ +str(gold_value)+" and "
+ +str(test_value))
+ else:
+ if not self.matches(gold_value, test_value, match_is_number,
+ self.__rel_err):
+ same = False
+ msg.append("Different values in "+gold_headers[column]+" for "
+ +str(gold_value)+" and "
+ +str(test_value))
+ self.finalize_message(same, msg, test_filename)
+ return self.__same, self.__message
+
+
+class OrderedCSV(Differ):
+ """
+ This is the class to use for handling the parameters block.
+ """
+
+ @staticmethod
+ def get_valid_params():
+ """
+ Returns the valid parameters for this class.
+ @ In, None
+ @ Out, params, _ValidParameters, return the parameters.
+ """
+ params = Differ.get_valid_params()
+ params.add_param('rel_err', '', 'Relative Error for csv files')
+ params.add_param('zero_threshold', sys.float_info.min*4.0, 'it represents '+
+ 'the value below which a float is considered zero (XML comparison only)')
+ params.add_param('ignore_sign', False, 'if true, then only compare the absolute values')
+ params.add_param('check_absolute_value', False, 'if true the values are '+
+ 'compared to the tolerance directectly, instead of relatively.')
+ return params
+
+ def __init__(self, name, params, test_dir):
+ """
+ Initializer for the class. Takes a String name and a dictionary params
+ @ In, name, string, name of the test.
+ @ In, params, dictionary, parameters for the class
+ @ In, test_dir, string, path to the test.
+ @ Out, None.
+ """
+ Differ.__init__(self, name, params, test_dir)
+ self.__zero_threshold = self.specs['zero_threshold']
+ self.__ignore_sign = bool(self.specs['ignore_sign'])
+ if len(self.specs['rel_err']) > 0:
+ self.__rel_err = float(self.specs['rel_err'])
+ else:
+ self.__rel_err = 1e-10
+ self.__check_absolute_value = self.specs["check_absolute_value"]
+
+ def check_output(self):
+ """
+ Checks that the output matches the gold.
+ returns (same, message) where same is true if the
+ test passes, or false if the test failes. message should
+ gives a human readable explaination of the differences.
+ @ In, None
+ @ Out, (same, message), same is true if the tests passes.
+ """
+ csv_files = self._get_test_files()
+ gold_files = self._get_gold_files()
+ csv_diff = OrderedCSVDiffer(csv_files,
+ gold_files,
+ relative_error=self.__rel_err,
+ zero_threshold=self.__zero_threshold,
+ ignore_sign=self.__ignore_sign,
+ absolute_check=self.__check_absolute_value)
+ return csv_diff.diff()
diff --git a/scripts/TestHarness/testers/RAVENImageDiff.py b/scripts/TestHarness/testers/RAVENImageDiff.py
index 92b90e99b8..7a7995d492 100644
--- a/scripts/TestHarness/testers/RAVENImageDiff.py
+++ b/scripts/TestHarness/testers/RAVENImageDiff.py
@@ -11,8 +11,11 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+"""
+This tests images against a expected image.
+"""
from __future__ import division, print_function, unicode_literals, absolute_import
-import sys,os,re
+import os
try:
from scipy.misc import imread
@@ -20,27 +23,26 @@
except ImportError:
import scipy
correctImport = False
-import numpy as np
-import diffUtils as DU
+import DiffUtils as DU
class ImageDiff:
"""
ImageDiff is used for comparing two image files.
"""
- def __init__(self, testDir, outFile,**kwargs):
+ def __init__(self, test_dir, out_file, **kwargs):
"""
- Create an XMLDiff class
- testDir: the directory where the test takes place
- outFile: the files to be compared. They will be in testDir + outFile
- and testDir + gold + outFile
- args: other arguments that may be included:
+ Create an ImageDiff class
+ @ In, test_dir, string, the directory where the test takes place
+ @ In, out_file, the files to be compared.
+ They will be in test_dir + out_file and test_dir + gold + out_file
+ @ In, args, other arguments that may be included:
"""
- self.__outFile = outFile
+ self.__out_file = out_file
self.__messages = ""
self.__same = True
- self.__testDir = testDir
+ self.__test_dir = test_dir
self.__options = kwargs
def diff(self):
@@ -53,55 +55,61 @@ def diff(self):
Out, None
"""
# read in files
- filesRead = False
- for outfile in self.__outFile:
- testFilename = os.path.join(self.__testDir,outfile)
- goldFilename = os.path.join(self.__testDir, 'gold', outfile)
- if not os.path.exists(testFilename):
+ files_read = False
+ for outfile in self.__out_file:
+ test_filename = os.path.join(self.__test_dir, outfile)
+ gold_filename = os.path.join(self.__test_dir, 'gold', outfile)
+ if not os.path.exists(test_filename):
self.__same = False
- self.__messages += 'Test file does not exist: '+testFilename
- elif not os.path.exists(goldFilename):
+ self.__messages += 'Test file does not exist: '+test_filename
+ elif not os.path.exists(gold_filename):
self.__same = False
- self.__messages += 'Gold file does not exist: '+goldFilename
+ self.__messages += 'Gold file does not exist: '+gold_filename
else:
- filesRead = True
+ files_read = True
#read in files
- if filesRead:
+ if files_read:
if not correctImport:
- self.__messages+='ImageDiff cannot run with scipy version less than 0.15.0, and requires the PIL installed; scipy version is '+str(scipy.__version__)
+ self.__messages += 'ImageDiff cannot run with scipy version less '+\
+ 'than 0.15.0, and requires the PIL installed; scipy version is '+\
+ str(scipy.__version__)
self.__same = False
- return(self.__same,self.__messages)
+ return(self.__same, self.__messages)
try:
# RAK - The original line...
- # testImage = imread(open(testFilename,'r'))
+ # test_image = imread(open(test_filename,'r'))
# ...didn't work on Windows Python because it couldn't sense the file type
- testImage = imread(testFilename)
- except IOError as e:
- self.__messages += 'Unrecognized file type for test image in scipy.imread: '+testFilename
- filesRead = False
+ test_image = imread(test_filename)
+ except IOError:
+ self.__messages += 'Unrecognized file type for test image in scipy.imread: '+test_filename
+ files_read = False
return (False, self.__messages)
try:
# RAK - The original line...
- # goldImage = imread(open(goldFilename,'r'))
+ # gold_image = imread(open(gold_filename,'r'))
# ...didn't work on Windows Python because it couldn't sense the file type
- goldImage = imread(goldFilename)
- except IOError as e:
- filesRead = False
- self.__messages += 'Unrecognized file type for test image in scipy.imread: '+goldFilename
+ gold_image = imread(gold_filename)
+ except IOError:
+ files_read = False
+ self.__messages += 'Unrecognized file type for test image in scipy.imread: '+gold_filename
return (False, self.__messages)
#first check dimensionality
- if goldImage.shape != testImage.shape:
- self.__messages += 'Gold and test image are not the same shape: '+str(goldImage.shape)+', '+str(testImage.shape)
+ if gold_image.shape != test_image.shape:
+ self.__messages += 'Gold and test image are not the same shape: '+\
+ str(gold_image.shape)+', '+str(test_image.shape)
self.__same = False
return (self.__same, self.__messages)
#set default options
- DU.setDefaultOptions(self.__options)
+ DU.set_default_options(self.__options)
#pixelwise comparison
- #TODO in the future we can add greyscale, normalized coloring, etc. For now just do raw comparison of right/wrong pixels
- diff = goldImage - testImage
- onlyDiffs = diff[abs(diff)>self.__options['zero_threshold']]
- pctNumDiff = onlyDiffs.size/float(diff.size)
- if pctNumDiff > self.__options['rel_err']:
- self.__messages += 'Difference between images is too large: %2.2f pct (allowable: %2.2f)' %(100*pctNumDiff,100*self.__options['rel_err'])
+ #TODO in the future we can add greyscale, normalized coloring, etc.
+ # For now just do raw comparison of right/wrong pixels
+ diff = gold_image - test_image
+ only_diffs = diff[abs(diff) > self.__options['zero_threshold']]
+ pct_num_diff = only_diffs.size/float(diff.size)
+ if pct_num_diff > self.__options['rel_err']:
+ self.__messages += 'Difference between images is too large:'+\
+ ' %2.2f pct (allowable: %2.2f)' %(100*pct_num_diff,
+ 100*self.__options['rel_err'])
self.__same = False
- return (self.__same,self.__messages)
+ return (self.__same, self.__messages)
diff --git a/scripts/TestHarness/testers/RavenErrors.py b/scripts/TestHarness/testers/RavenErrors.py
index cd2346a61a..9c3959e2de 100644
--- a/scripts/TestHarness/testers/RavenErrors.py
+++ b/scripts/TestHarness/testers/RavenErrors.py
@@ -11,65 +11,85 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-from Tester import Tester
-from CSVDiffer import CSVDiffer
-import RavenUtils
+"""
+This tests for expected errors in a program
+"""
import os
import subprocess
import platform
+from Tester import Tester
+import RavenUtils
fileDir = os.path.dirname(os.path.realpath(__file__))
-raven = os.path.abspath(os.path.join(fileDir,'..','..','..','framework','Driver.py'))
+raven = os.path.abspath(os.path.join(fileDir, '..', '..', '..', 'framework',
+ 'Driver.py'))
class RavenErrors(Tester):
"""
This class tests if the expected error messages are generated or not.
"""
@staticmethod
- def validParams():
- """This method add defines the valid parameters for the tester. The expected error message shuld be unique..."""
- params = Tester.validParams()
- params.addRequiredParam('input',"The input file to use for this test.")
- params.addRequiredParam('expect_err',"All or part of the expected error message (unique keyword)")
- params.addParam('required_executable','','Skip test if this executable is not found')
- params.addParam('required_libraries','','Skip test if any of these libraries are not found')
- params.addParam('skip_if_env','','Skip test if this environmental variable is defined')
- params.addParam('test_interface_only','False','Test the interface only (without running the driven code')
+ def get_valid_params():
+ """
+ This method add defines the valid parameters for the tester.
+ The expected error message shuld be unique...
+ @ In, None
+ @ Out, params, _ValidParameters, return the parameters.
+ """
+ params = Tester.get_valid_params()
+ params.add_required_param('input', "The input file to use for this test.")
+ params.add_required_param('expect_err',
+ "All or part of the expected error message (unique keyword)")
+ params.add_param('required_executable', '', 'Skip test if this executable is not found')
+ params.add_param('required_libraries', '', 'Skip test if any of these libraries are not found')
+ params.add_param('skip_if_env', '', 'Skip test if this environmental variable is defined')
+ params.add_param('test_interface_only', 'False',
+ 'Test the interface only (without running the driven code')
return params
- def getCommand(self, options):
+ def get_command(self):
"""
This method returns the command to execute for the test
- @ In, options, argparse.Namespace, functionally a dictionary of options from the input
+ @ In, None
@ Out, getCommand, string, the command to run
"""
ravenflag = ''
- if self.specs['test_interface_only'].lower() == 'true': ravenflag = 'interfaceCheck '
- if RavenUtils.inPython3():
- return ' '.join(["python3",raven,ravenflag,self.specs["input"]])
- else:
- return ' '.join(["python",raven,ravenflag,self.specs["input"]])
+ if self.specs['test_interface_only'].lower() == 'true':
+ ravenflag = 'interfaceCheck '
+ if RavenUtils.in_python_3():
+ return ' '.join(["python3", raven, ravenflag, self.specs["input"]])
+ return ' '.join(["python", raven, ravenflag, self.specs["input"]])
def __init__(self, name, params):
+ """
+ Initializer for the class. Takes a String name and a dictionary params
+ @ In, name, string, name of the test.
+ @ In, params, dictionary, parameters for the class
+ @ Out, None.
+ """
Tester.__init__(self, name, params)
- self.required_libraries = self.specs['required_libraries'].split(' ') if len(self.specs['required_libraries']) > 0 else []
+ self.required_libraries = self.specs['required_libraries'].split(' ') \
+ if len(self.specs['required_libraries']) > 0 else []
self.required_executable = self.specs['required_executable']
- self.required_executable = self.required_executable.replace("%METHOD%",os.environ.get("METHOD","opt"))
+ self.required_executable = self.required_executable.replace("%METHOD%",
+ os.environ.get("METHOD", "opt"))
self.specs['scale_refine'] = False
- def checkRunnable(self, option):
- """This method checks if the the test is runnable within the current settings"""
- missing,too_old,notQA = RavenUtils.checkForMissingModules()
+ def check_runnable(self):
+ """
+ This method checks if the the test is runnable within the current settings
+ @ In, None
+ @ Out, check_runnable, boolean, If True this test can run.
+ """
+ missing, too_old, _ = RavenUtils.check_for_missing_modules()
if len(missing) > 0:
- self.setStatus('skipped (Missing python modules: '+" ".join(missing)+
- " PYTHONPATH="+os.environ.get("PYTHONPATH","")+')',
- self.bucket_skip)
+ self.set_skip('skipped (Missing python modules: '+" ".join(missing)+
+ " PYTHONPATH="+os.environ.get("PYTHONPATH", "")+')')
return False
if len(too_old) > 0:
- self.setStatus('skipped (Old version python modules: '+" ".join(too_old)+
- " PYTHONPATH="+os.environ.get("PYTHONPATH","")+')',
- self.bucket_skip)
+ self.set_skip('skipped (Old version python modules: '+" ".join(too_old)+
+ " PYTHONPATH="+os.environ.get("PYTHONPATH", "")+')')
return False
for lib in self.required_libraries:
if platform.system() == 'Windows':
@@ -77,37 +97,36 @@ def checkRunnable(self, option):
else:
lib += '.so'
if not os.path.exists(lib):
- self.setStatus('skipped (Missing library: "'+lib+'")', self.bucket_skip)
+ self.set_skip('skipped (Missing library: "'+lib+'")')
return False
if len(self.required_executable) > 0 and \
not os.path.exists(self.required_executable):
- self.setStatus('skipped (Missing executable: "'+self.required_executable+'")',
- self.bucket_skip)
+ self.set_skip('skipped (Missing executable: "'+self.required_executable+'")')
return False
try:
if len(self.required_executable) > 0 and \
- subprocess.call([self.required_executable],stdout=subprocess.PIPE) != 0:
- self.setStatus('skipped (Failing executable: "'+self.required_executable+'")',
- self.bucket_skip)
+ subprocess.call([self.required_executable], stdout=subprocess.PIPE) != 0:
+ self.set_skip('skipped (Failing executable: "'+self.required_executable+'")')
return False
- except:
- self.setStatus('skipped (Error when trying executable: "'+self.required_executable+'")',
- self.bucket_skip)
+ except Exception:
+ self.set_skip('skipped (Error when trying executable: "'+self.required_executable+'")')
return False
if len(self.specs['skip_if_env']) > 0:
env_var = self.specs['skip_if_env']
if env_var in os.environ:
- self.setStatus('skipped (found environmental variable "'+env_var+'")',
- self.bucket_skip)
+ self.set_skip('skipped (found environmental variable "'+env_var+'")')
return False
return True
- def processResults(self, moose_dir, options, output):
- """This method processes results. It checks if the expected error messgae keyword exists in the output stream."""
+ def process_results(self, output):
+ """
+ This method processes results.
+ It checks if the expected error messgae keyword exists in the output stream.
+ @ In, output, string, output of the run.
+ @ Out, None
+ """
for line in output.split('\n'):
if self.specs['expect_err'] in line:
- self.setStatus(self.success_message, self.bucket_success)
- return output
- self.setStatus('The expected Error: ' +self.specs['expect_err']+' is not raised!', self.bucket_fail)
- return output
-
+ self.set_success()
+ return
+ self.set_fail('The expected Error: ' +self.specs['expect_err']+' is not raised!')
diff --git a/scripts/TestHarness/testers/RavenExodiff.py b/scripts/TestHarness/testers/RavenExodiff.py
deleted file mode 100644
index 7fe0e4d742..0000000000
--- a/scripts/TestHarness/testers/RavenExodiff.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# Copyright 2017 Battelle Energy Alliance, LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-from Exodiff import Exodiff
-from util import *
-import os
-import subprocess
-
-class RavenExodiff(Exodiff):
- try:
- py3_output = subprocess.Popen(["python3","-c","print('HELLO')"],stdout=subprocess.PIPE).communicate()[0]
- except OSError:
- py3_output = "Failed"
-
- has_python3 = py3_output.startswith("HELLO")
-
- try:
- py2_output = subprocess.Popen(["python","-c","print 'HELLO'"],stdout=subprocess.PIPE).communicate()[0]
- except OSError:
- py2_output = "Failed"
-
- has_python2 = py2_output.startswith("HELLO")
-
- try:
- py_cfg_output = subprocess.Popen(["python-config","--help"],stdout=subprocess.PIPE,stderr=subprocess.STDOUT).communicate()[0]
- except OSError:
- py_cfg_output = "Failed"
-
- has_python_config = py_cfg_output.startswith("Usage:")
-
- try:
- output_swig = subprocess.Popen(["swig","-version"],stdout=subprocess.PIPE).communicate()[0]
- except OSError:
- output_swig = "Failed"
-
- has_swig2 = "Version 2.0" in output_swig or "Version 3.0" in output_swig
-
- module_dir = os.path.join(os.path.dirname(os.getcwd()),"crow","control_modules")
- has_distributions = os.path.exists(os.path.join(module_dir,"_distribution1D.so"))
- if not has_distributions:
- module_dir = os.path.join(os.getcwd(),"crow","control_modules")
- has_distributions = os.path.exists(os.path.join(module_dir,"_distribution1D.so"))
-
- def __init__(self, name, params):
- Exodiff.__init__(self, name, params)
-
- @staticmethod
- def validParams():
- params = Exodiff.validParams()
- params.addParam('requires_python3', False, "Requires python3 for test")
- params.addParam('requires_swig2', False, "Requires swig2 for test")
- params.addParam('requires_python2', False, "Requires python2 for test")
- params.addParam('requires_python_config', False, "Requires python-config for test")
- params.addParam('requires_distributions_module', False, "Requires distributions module to be built")
- return params
-
- def checkRunnable(self, options):
- if self.specs['requires_python3'] and not RavenExodiff.has_python3:
- return (False, 'skipped (No python3 found)')
- if self.specs['requires_swig2'] and not RavenExodiff.has_swig2:
- return (False, 'skipped (No swig 2.0 found)')
- if self.specs['requires_python2'] and not RavenExodiff.has_python2:
- return (False, 'skipped (No python2 found)')
- if self.specs['requires_python_config'] and \
- not RavenExodiff.has_python_config:
- return (False, 'skipped (No python-config found)')
- if self.specs['requires_distributions_module'] and \
- not RavenExodiff.has_distributions:
- return (False, 'skipped (Distributions not built)')
- return (True, '')
diff --git a/scripts/TestHarness/testers/RavenFramework.py b/scripts/TestHarness/testers/RavenFramework.py
index 89717ca5e7..8d04a3cd34 100644
--- a/scripts/TestHarness/testers/RavenFramework.py
+++ b/scripts/TestHarness/testers/RavenFramework.py
@@ -11,18 +11,21 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-from Tester import Tester
-from CSVDiffer import CSVDiffer
-from UnorderedCSVDiffer import UnorderedCSVDiffer
-from XMLDiff import XMLDiff
-from TextDiff import TextDiff
-from RAVENImageDiff import ImageDiff
-import RavenUtils
+"""
+RavenFramework is a tool to test raven inputs.
+"""
import os
import subprocess
import sys
import distutils.version
import platform
+from Tester import Tester
+import OrderedCSVDiffer
+import UnorderedCSVDiffer
+import XMLDiff
+import TextDiff
+from RAVENImageDiff import ImageDiff
+import RavenUtils
# Set this outside the class because the framework directory is constant for
# each instance of this Tester, and in addition, there is a problem with the
@@ -33,41 +36,70 @@
myDir = os.path.dirname(os.path.realpath(__file__))
RAVEN_DIR = os.path.abspath(os.path.join(myDir, '..', '..', '..', 'framework'))
-_missing_modules, _too_old_modules, _notQAModules = RavenUtils.checkForMissingModules()
+#Need to add the directory for AMSC for doing module checks.
+os.environ["PYTHONPATH"] = os.path.join(RAVEN_DIR, 'contrib') +\
+ os.pathsep + os.environ.get("PYTHONPATH", "")
+
+
+_missing_modules, _too_old_modules, _notQAModules = RavenUtils.check_for_missing_modules()
class RavenFramework(Tester):
+ """
+ RavenFramework is the class to use for testing standard raven inputs.
+ """
@staticmethod
- def validParams():
- params = Tester.validParams()
- params.addRequiredParam('input',"The input file to use for this test.")
- params.addParam('output','',"List of output files that the input should create.")
- params.addParam('csv','',"List of csv files to check")
- params.addParam('UnorderedCsv','',"List of unordered csv files to check")
- params.addParam('xml','',"List of xml files to check")
- params.addParam('UnorderedXml','',"List of unordered xml files to check")
- params.addParam('xmlopts','',"Options for xml checking")
- params.addParam('text','',"List of generic text files to check")
- params.addParam('comment','-20021986',"Character or string denoting comments, all text to the right of the symbol will be ignored in the diff of text files")
- params.addParam('image','',"List of image files to check")
- params.addParam('rel_err','','Relative Error for csv files or floats in xml ones')
- params.addParam('required_executable','','Skip test if this executable is not found')
- params.addParam('required_libraries','','Skip test if any of these libraries are not found')
- params.addParam('minimum_library_versions','','Skip test if the library listed is below the supplied version (e.g. minimum_library_versions = \"name1 version1 name2 version2\")')
- params.addParam('skip_if_env','','Skip test if this environmental variable is defined')
- params.addParam('skip_if_OS','','Skip test if the operating system defined')
- params.addParam('test_interface_only',False,'Test the interface only (without running the driven code')
- params.addParam('check_absolute_value',False,'if true the values are compared in absolute value (abs(trueValue)-abs(testValue)')
- params.addParam('zero_threshold',sys.float_info.min*4.0,'it represents the value below which a float is considered zero (XML comparison only)')
- params.addParam('remove_whitespace',False,'Removes whitespace before comparing xml node text if True')
- params.addParam('expected_fail', False, 'if true, then the test should fails, and if it passes, it fails.')
- params.addParam('remove_unicode_identifier', False, 'if true, then remove u infront of a single quote')
- params.addParam('interactive', False, 'if true, then RAVEN will be run with interactivity enabled.')
- params.addParam('python3_only', False, 'if true, then only use with Python3')
- params.addParam('ignore_sign', False, 'if true, then only compare the absolute values')
+ def get_valid_params():
+ """
+ Returns the parameters that can be used for this class.
+ @ In, None
+ @ Out, params, _ValidParameters, return the parameters.
+ """
+ params = Tester.get_valid_params()
+ params.add_required_param('input', "The input file to use for this test.")
+ params.add_param('output', '', "List of output files that the input should create.")
+ params.add_param('csv', '', "List of csv files to check")
+ params.add_param('UnorderedCsv', '', "List of unordered csv files to check")
+ params.add_param('xml', '', "List of xml files to check")
+ params.add_param('UnorderedXml', '', "List of unordered xml files to check")
+ params.add_param('xmlopts', '', "Options for xml checking")
+ params.add_param('text', '', "List of generic text files to check")
+ params.add_param('comment', '-20021986', "Character or string denoting "+
+ "comments, all text to the right of the symbol will be "+
+ "ignored in the diff of text files")
+ params.add_param('image', '', "List of image files to check")
+ params.add_param('rel_err', '', 'Relative Error for csv files or floats in xml ones')
+ params.add_param('required_executable', '', 'Skip test if this executable is not found')
+ params.add_param('required_libraries', '', 'Skip test if any of these libraries are not found')
+ params.add_param('minimum_library_versions', '',
+ 'Skip test if the library listed is below the supplied'+
+ ' version (e.g. minimum_library_versions = \"name1 version1 name2 version2\")')
+ params.add_param('skip_if_env', '', 'Skip test if this environmental variable is defined')
+ params.add_param('skip_if_OS', '', 'Skip test if the operating system defined')
+ params.add_param('test_interface_only', False,
+ 'Test the interface only (without running the driven code')
+ params.add_param('check_absolute_value', False,
+ 'if true the values are compared to the tolerance '+
+ 'directectly, instead of relatively.')
+ params.add_param('zero_threshold', sys.float_info.min*4.0,
+ 'it represents the value below which a float is'+
+ 'considered zero (XML comparison only)')
+ params.add_param('remove_whitespace', False,
+ 'Removes whitespace before comparing xml node text if True')
+ params.add_param('remove_unicode_identifier', False,
+ 'if true, then remove u infront of a single quote')
+ params.add_param('interactive', False,
+ 'if true, then RAVEN will be run with interactivity enabled.')
+ params.add_param('python3_only', False, 'if true, then only use with Python3')
+ params.add_param('ignore_sign', False, 'if true, then only compare the absolute values')
return params
- def getCommand(self, options):
+ def get_command(self):
+ """
+ Gets the raven command to run this test.
+ @ In, None
+ @ Out, get_command, string, command to run.
+ """
ravenflag = ''
if self.specs['test_interface_only']:
ravenflag += ' interfaceCheck '
@@ -75,234 +107,191 @@ def getCommand(self, options):
if self.specs['interactive']:
ravenflag += ' interactiveCheck '
- if RavenUtils.inPython3():
+ if RavenUtils.in_python_3():
return "python3 " + self.driver + " " + ravenflag + self.specs["input"]
- else:
- return "python " + self.driver + " " + ravenflag + self.specs["input"]
+ return "python " + self.driver + " " + ravenflag + self.specs["input"]
+ def __make_differ(self, spec_name, differ_class, extra=None):
+ """
+ This adds a differ if the spec_name has files.
+ @ In, spec_name, string of the list of files to use with the differ.
+ @ In, differ_class, subclass of Differ, for use with the files.
+ @ In, extra, dictionary, extra parameters
+ @ Out, None
+ """
+ if len(self.specs[spec_name]) == 0:
+ #No files, so quit
+ return
+ differ_params = dict(self.specs)
+ differ_params["output"] = self.specs[spec_name]
+ differ_params["type"] = differ_class.__name__
+ if extra is not None:
+ differ_params.update(extra)
+ self.add_differ(differ_class(spec_name, differ_params, self.get_test_dir()))
def __init__(self, name, params):
Tester.__init__(self, name, params)
- self.check_files = self.specs['output' ].split(" ") if len(self.specs['output' ]) > 0 else []
- self.csv_files = self.specs['csv' ].split(" ") if len(self.specs['csv' ]) > 0 else []
- self.xml_files = self.specs['xml' ].split(" ") if len(self.specs['xml' ]) > 0 else []
- self.ucsv_files = self.specs['UnorderedCsv'].split(" ") if len(self.specs['UnorderedCsv']) > 0 else []
- self.uxml_files = self.specs['UnorderedXml'].split(" ") if len(self.specs['UnorderedXml']) > 0 else []
- self.text_files = self.specs['text' ].split(" ") if len(self.specs['text' ]) > 0 else []
- self.img_files = self.specs['image' ].split(" ") if len(self.specs['image' ]) > 0 else []
- self.all_files = self.check_files + self.csv_files + self.xml_files + self.ucsv_files + self.uxml_files + self.text_files + self.img_files
+ self.check_files = self.specs['output'].split(" ") if len(self.specs['output']) > 0 else []
+ self.img_files = self.specs['image'].split(" ") if len(self.specs['image']) > 0 else []
+ self.all_files = self.check_files + self.img_files
+ self.__make_differ('csv', OrderedCSVDiffer.OrderedCSV)
+ self.__make_differ('UnorderedCsv', UnorderedCSVDiffer.UnorderedCSV)
+ self.__make_differ('xml', XMLDiff.XML, {"unordered":False})
+ self.__make_differ('UnorderedXml', XMLDiff.XML, {"unordered":True})
+ self.__make_differ('text', TextDiff.Text)
self.required_executable = self.specs['required_executable']
- self.required_libraries = self.specs['required_libraries'].split(' ') if len(self.specs['required_libraries']) > 0 else []
- self.minimum_libraries = self.specs['minimum_library_versions'].split(' ') if len(self.specs['minimum_library_versions']) > 0 else []
+ self.required_libraries = self.specs['required_libraries'].split(' ')\
+ if len(self.specs['required_libraries']) > 0 else []
+ self.minimum_libraries = self.specs['minimum_library_versions'].split(' ')\
+ if len(self.specs['minimum_library_versions']) > 0 else []
#for image tests, minimum library is always scipy 0.15.0
- if len(self.img_files)>0:
- self.minimum_libraries += ['scipy','0.15.0']
- self.required_executable = self.required_executable.replace("%METHOD%",os.environ.get("METHOD","opt"))
+ if len(self.img_files) > 0:
+ self.minimum_libraries += ['scipy', '0.15.0']
+ self.required_executable = self.required_executable.replace("%METHOD%",
+ os.environ.get("METHOD", "opt"))
self.specs['scale_refine'] = False
- self.driver = os.path.join(RAVEN_DIR,'Driver.py')
+ self.driver = os.path.join(RAVEN_DIR, 'Driver.py')
- def checkRunnable(self, option):
+ def check_runnable(self):
+ """
+ Checks if this test can run.
+ @ In, None
+ @ Out, check_runnable, boolean, if True can run this test.
+ """
missing = _missing_modules
too_old = _too_old_modules
# remove tests based on skipping criteria
## required module is missing
if len(missing) > 0:
- self.setStatus('skipped (Missing python modules: '+" ".join(missing)+
- " PYTHONPATH="+os.environ.get("PYTHONPATH","")+')',
- self.bucket_skip)
+ self.set_skip('skipped (Missing python modules: '+" ".join(missing)+
+ " PYTHONPATH="+os.environ.get("PYTHONPATH", "")+')')
return False
## required module is present, but too old
- if len(too_old) > 0 and RavenUtils.checkVersions():
- self.setStatus('skipped (Old version python modules: '+" ".join(too_old)+
- " PYTHONPATH="+os.environ.get("PYTHONPATH","")+')',
- self.bucket_skip)
+ if len(too_old) > 0 and RavenUtils.check_versions():
+ self.set_skip('skipped (Old version python modules: '+" ".join(too_old)+
+ " PYTHONPATH="+os.environ.get("PYTHONPATH", "")+')')
return False
## an environment varible value causes a skip
if len(self.specs['skip_if_env']) > 0:
env_var = self.specs['skip_if_env']
if env_var in os.environ:
- self.setStatus('skipped (found environmental variable "'+env_var+'")',
- self.bucket_skip)
+ self.set_skip('skipped (found environmental variable "'+env_var+'")')
return False
## OS
if len(self.specs['skip_if_OS']) > 0:
skip_os = [x.strip().lower() for x in self.specs['skip_if_OS'].split(',')]
# get simple-name platform (options are Linux, Windows, Darwin, or SunOS that I've seen)
- currentOS = platform.system().lower()
+ current_os = platform.system().lower()
# replace Darwin with more expected "mac"
- if currentOS == 'darwin':
- currentOS = 'mac'
- if currentOS in skip_os:
- self.setStatus('skipped (OS is "{}")'.format(currentOS),
- self.bucket_skip)
+ if current_os == 'darwin':
+ current_os = 'mac'
+ if current_os in skip_os:
+ self.set_skip('skipped (OS is "{}")'.format(current_os))
return False
for lib in self.required_libraries:
- found, message, version = RavenUtils.moduleReport(lib,'')
+ found, _, _ = RavenUtils.module_report(lib, '')
if not found:
- self.setStatus('skipped (Unable to import library: "'+lib+'")',
- self.bucket_skip)
+ self.set_skip('skipped (Unable to import library: "'+lib+'")')
return False
- if self.specs['python3_only'] and not RavenUtils.inPython3():
- self.setStatus('Python 3 only',
- self.bucket_skip)
+ if self.specs['python3_only'] and not RavenUtils.in_python_3():
+ self.set_skip('Python 3 only')
return False
i = 0
if len(self.minimum_libraries) % 2:
- self.setStatus('skipped (libraries are not matched to versions numbers: '+str(self.minimum_libraries)+')',
- self.bucket_skip)
+ self.set_skip('skipped (libraries are not matched to versions numbers: '
+ +str(self.minimum_libraries)+')')
return False
while i < len(self.minimum_libraries):
- libraryName = self.minimum_libraries[i]
- libraryVersion = self.minimum_libraries[i+1]
- found, message, actualVersion = RavenUtils.moduleReport(libraryName,libraryName+'.__version__')
+ library_name = self.minimum_libraries[i]
+ library_version = self.minimum_libraries[i+1]
+ found, _, actual_version = RavenUtils.module_report(library_name, library_name+'.__version__')
if not found:
- self.setStatus('skipped (Unable to import library: "'+libraryName+'")',
- self.bucket_skip)
+ self.set_skip('skipped (Unable to import library: "'+library_name+'")')
return False
- if distutils.version.LooseVersion(actualVersion) < distutils.version.LooseVersion(libraryVersion):
- self.setStatus('skipped (Outdated library: "'+libraryName+'")',
- self.bucket_skip)
+ if distutils.version.LooseVersion(actual_version) < \
+ distutils.version.LooseVersion(library_version):
+ self.set_skip('skipped (Outdated library: "'+library_name+'")')
return False
- i+=2
+ i += 2
if len(self.required_executable) > 0 and \
not os.path.exists(self.required_executable):
- self.setStatus('skipped (Missing executable: "'+self.required_executable+'")',
- self.bucket_skip)
+ self.set_skip('skipped (Missing executable: "'+self.required_executable+'")')
return False
try:
if len(self.required_executable) > 0 and \
- subprocess.call([self.required_executable],stdout=subprocess.PIPE) != 0:
- self.setStatus('skipped (Failing executable: "'+self.required_executable+'")',
- self.bucket_skip)
+ subprocess.call([self.required_executable], stdout=subprocess.PIPE) != 0:
+ self.set_skip('skipped (Failing executable: "'+self.required_executable+'")')
return False
- except:
- self.setStatus('skipped (Error when trying executable: "'+self.required_executable+'")',
- self.bucket_skip)
+ except Exception as exp:
+ self.set_skip('skipped (Error when trying executable: "'
+ +self.required_executable+'")'+str(exp))
return False
- filenameSet = set()
- duplicateFiles = []
- for filename in self.__getCreatedFiles():
- if filename not in filenameSet:
- filenameSet.add(filename)
+ filename_set = set()
+ duplicate_files = []
+ for filename in self.__get_created_files():
+ if filename not in filename_set:
+ filename_set.add(filename)
else:
- duplicateFiles.append(filename)
- if len(duplicateFiles) > 0:
- self.setStatus('[incorrect test] duplicated files specified: '+
- " ".join(duplicateFiles),
- self.bucket_skip)
+ duplicate_files.append(filename)
+ if len(duplicate_files) > 0:
+ self.set_skip('[incorrect test] duplicated files specified: '+
+ " ".join(duplicate_files))
return False
return True
- def __getCreatedFiles(self):
+ def __get_created_files(self):
"""
Returns all the files used by this test that need to be created
by the test. Note that they will be deleted at the start of running
the test.
+ @ In, None
@ Out, createdFiles, [str], list of files created by the test.
"""
- runpath = self.getTestDir()
- return list(os.path.join(runpath,file) for file in self.all_files)
+ runpath = self.get_test_dir()
+ remove_files = self.get_differ_remove_files()
+ return remove_files+list(os.path.join(runpath, file) for file in self.all_files)
- def prepare(self, options = None):
- self.check_files = [os.path.join(self.specs['test_dir'],filename) for filename in self.check_files]
- for filename in self.__getCreatedFiles():
+ def prepare(self):
+ """
+ Get the test ready to run by removing files that should be created.
+ @ In, None
+ @ Out, None
+ """
+ self.check_files = [os.path.join(self.specs['test_dir'], filename)
+ for filename in self.check_files]
+ for filename in self.__get_created_files():
if os.path.exists(filename):
os.remove(filename)
- def processResults(self, moose_dir, options, output):
- expectedFail = self.specs['expected_fail']
- if not expectedFail:
- return self.rawProcessResults(moose_dir, options, output)
- else:
- output = self.rawProcessResults(moose_dir, options, output)
- if self.didPass():
- self.setStatus('Unexpected success',self.bucket_fail)
- return output
- else:
- self.setStatus(self.success_message, self.bucket_success)
- return output
-
- def rawProcessResults(self, moose_dir, options, output):
+ def process_results(self, output):
+ """
+ Check to see if the test has passed.
+ @ In, output, string, output of test.
+ @ Out, None
+ """
missing = []
for filename in self.check_files:
if not os.path.exists(filename):
missing.append(filename)
if len(missing) > 0:
- self.setStatus('CWD '+os.getcwd()+' METHOD '+os.environ.get("METHOD","?")+' Expected files not created '+" ".join(missing),self.bucket_fail)
- return output
-
- #csv
- if len(self.specs["rel_err"]) > 0:
- csv_diff = CSVDiffer(self.specs['test_dir'],self.csv_files,relative_error=float(self.specs["rel_err"]))
- else:
- csv_diff = CSVDiffer(self.specs['test_dir'],self.csv_files)
- message = csv_diff.diff()
- if csv_diff.getNumErrors() > 0:
- self.setStatus(message,self.bucket_diff)
- return output
-
- #unordered csv
- checkAbsoluteValue = self.specs["check_absolute_value"]
- zeroThreshold = self.specs["zero_threshold"]
- if len(self.specs["rel_err"]) > 0:
- ucsv_diff = UnorderedCSVDiffer(self.specs['test_dir'],
- self.ucsv_files,
- relative_error = float(self.specs["rel_err"]),
- absolute_check = checkAbsoluteValue,
- zeroThreshold = zeroThreshold, ignore_sign=self.specs["ignore_sign"])
- else:
- ucsv_diff = UnorderedCSVDiffer(self.specs['test_dir'],
- self.ucsv_files,
- absolute_check = checkAbsoluteValue,
- zeroThreshold = zeroThreshold, ignore_sign=self.specs["ignore_sign"])
-
- ucsv_same,ucsv_messages = ucsv_diff.diff()
- if not ucsv_same:
- self.setStatus(ucsv_messages, self.bucket_diff)
- return output
-
- #xml
- xmlopts = {}
- if len(self.specs["rel_err"]) > 0: xmlopts['rel_err'] = float(self.specs["rel_err"])
- xmlopts['zero_threshold'] = float(self.specs["zero_threshold"])
- xmlopts['unordered' ] = False
- xmlopts['remove_whitespace'] = self.specs['remove_whitespace'] == True
- xmlopts['remove_unicode_identifier'] = self.specs['remove_unicode_identifier']
- if len(self.specs['xmlopts'])>0: xmlopts['xmlopts'] = self.specs['xmlopts'].split(' ')
- xml_diff = XMLDiff(self.specs['test_dir'],self.xml_files,**xmlopts)
- (xml_same,xml_messages) = xml_diff.diff()
- if not xml_same:
- self.setStatus(xml_messages, self.bucket_diff)
- return output
-
- #unordered xml
- xmlopts['unordered'] = True
- uxml_diff = XMLDiff(self.specs['test_dir'],self.uxml_files,**xmlopts)
- (uxml_same,uxml_messages) = uxml_diff.diff()
- if not uxml_same:
- self.setStatus(uxml_messages, self.bucket_diff)
- return output
-
- #text
- textOpts = {'comment': self.specs['comment']}
- textDiff = TextDiff(self.specs['test_dir'],self.text_files,**textOpts)
- (textSame,textMessages) = textDiff.diff()
- if not textSame:
- self.setStatus(textMessages, self.bucket_diff)
- return output
+ self.set_fail('CWD '+os.getcwd()+' METHOD '+
+ os.environ.get("METHOD", "?")+
+ ' Expected files not created '+" ".join(missing))
+ return
#image
- imageOpts = {}
- if 'rel_err' in self.specs.keys(): imageOpts['rel_err' ] = self.specs['rel_err' ]
- if 'zero_threshold' in self.specs.keys(): imageOpts['zero_threshold'] = self.specs['zero_threshold']
- imgDiff = ImageDiff(self.specs['test_dir'],self.img_files,**imageOpts)
- (imgSame,imgMessages) = imgDiff.diff()
- if not imgSame:
- self.setStatus(imgMessages, self.bucket_diff)
- return output
+ image_opts = {}
+ if 'rel_err' in self.specs.keys():
+ image_opts['rel_err'] = self.specs['rel_err']
+ if 'zero_threshold' in self.specs.keys():
+ image_opts['zero_threshold'] = self.specs['zero_threshold']
+ img_diff = ImageDiff(self.specs['test_dir'], self.img_files, **image_opts)
+ (img_same, img_messages) = img_diff.diff()
+ if not img_same:
+ self.set_diff(img_messages)
+ return
- self.setStatus(self.success_message, self.bucket_success)
- return output
+ self.set_success()
diff --git a/scripts/TestHarness/testers/RavenPython.py b/scripts/TestHarness/testers/RavenPython.py
index 2510654d08..44634d533a 100644
--- a/scripts/TestHarness/testers/RavenPython.py
+++ b/scripts/TestHarness/testers/RavenPython.py
@@ -11,16 +11,23 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-from util import *
+#from util import *
+"""
+This tests programs by running a python command.
+"""
+import os
+import subprocess
+import distutils.version
from Tester import Tester
-from CSVDiffer import CSVDiffer
import RavenUtils
-import os, subprocess
-import distutils.version
class RavenPython(Tester):
+ """
+ This class runs a python program to test something.
+ """
try:
- output_swig = subprocess.Popen(["swig","-version"],stdout=subprocess.PIPE).communicate()[0]
+ output_swig = subprocess.Popen(["swig", "-version"], stdout=subprocess.PIPE,
+ universal_newlines=True).communicate()[0]
except OSError:
output_swig = "Failed"
@@ -28,110 +35,143 @@ class RavenPython(Tester):
@staticmethod
- def validParams():
- params = Tester.validParams()
- params.addRequiredParam('input',"The python file to use for this test.")
- params.addParam('output','',"List of output files that this input should create.")
- if os.environ.get("CHECK_PYTHON3","0") == "1":
- params.addParam('python_command','python3','The command to use to run python')
+ def get_valid_params():
+ """
+ Returns the valid parameters.
+ @ In, None
+ @ Out, params, _ValidParameters, return the parameters.
+ """
+ params = Tester.get_valid_params()
+ params.add_required_param('input', "The python file to use for this test.")
+ params.add_param('output', '', "List of output files that this input should create.")
+ if os.environ.get("CHECK_PYTHON3", "0") == "1":
+ params.add_param('python_command', 'python3', 'The command to use to run python')
else:
- params.addParam('python_command','python','The command to use to run python')
- params.addParam('requires_swig2', False, "Requires swig2 for test")
- params.addParam('required_executable','','Skip test if this executable is not found')
- params.addParam('required_libraries','','Skip test if any of these libraries are not found')
- params.addParam('required_executable_check_flags','','Flags to add to the required executable to make sure it runs without fail when testing its existence on the machine')
- params.addParam('minimum_library_versions','','Skip test if the library listed is below the supplied version (e.g. minimum_library_versions = \"name1 version1 name2 version2\")')
- params.addParam('python3_only', False, 'if true, then only use with Python3')
+ params.add_param('python_command', 'python', 'The command to use to run python')
+ params.add_param('requires_swig2', False, "Requires swig2 for test")
+ params.add_param('required_executable', '', 'Skip test if this executable is not found')
+ params.add_param('required_libraries', '', 'Skip test if any of these libraries are not found')
+ params.add_param('required_executable_check_flags', '', 'Flags to add to '+
+ 'the required executable to make sure it runs without '+
+ 'fail when testing its existence on the machine')
+ params.add_param('minimum_library_versions', '', 'Skip test if the library'+
+ ' listed is below the supplied version (e.g. '+
+ 'minimum_library_versions = \"name1 version1 name2 version2\")')
+ params.add_param('python3_only', False, 'if true, then only use with Python3')
return params
- def prepare(self, options = None):
+ def prepare(self):
"""
Copied from RavenFramework since we should still clean out test files
before running an external tester, though we will not test if they
are created later (for now), so it may behoove us to not save
check_files for later use.
+ @ In, None
+ @ Out, None
"""
- if self.specs['output'].strip() != '':
- self.check_files = [os.path.join(self.specs['test_dir'],filename) for filename in self.specs['output'].split(" ")]
- else:
- self.check_files = []
for filename in self.check_files:
if os.path.exists(filename):
os.remove(filename)
- def getCommand(self, options):
+ def get_command(self):
+ """
+ returns the command used by this tester.
+ @ In, None
+ @ Out, get_command, string, command to run.
+ """
return self.specs["python_command"]+" "+self.specs["input"]
def __init__(self, name, params):
+ """
+ Initializer for the class. Takes a String name and a dictionary params
+ @ In, name, string, name of the test.
+ @ In, params, dictionary, parameters for the class
+ @ Out, None.
+ """
Tester.__init__(self, name, params)
self.specs['scale_refine'] = False
self.required_executable = self.specs['required_executable']
- self.required_executable = self.required_executable.replace("%METHOD%",os.environ.get("METHOD","opt"))
- self.required_libraries = self.specs['required_libraries'].split(' ') if len(self.specs['required_libraries']) > 0 else []
+ self.required_executable = self.required_executable.replace("%METHOD%",
+ os.environ.get("METHOD", "opt"))
+ self.required_libraries = self.specs['required_libraries'].split(' ') \
+ if len(self.specs['required_libraries']) > 0 else []
self.required_executable_check_flags = self.specs['required_executable_check_flags'].split(' ')
- self.minimum_libraries = self.specs['minimum_library_versions'].split(' ') if len(self.specs['minimum_library_versions']) > 0 else []
+ self.minimum_libraries = self.specs['minimum_library_versions'].split(' ')\
+ if len(self.specs['minimum_library_versions']) > 0 else []
+ if self.specs['output'].strip() != '':
+ self.check_files = [os.path.join(self.specs['test_dir'], filename)
+ for filename in self.specs['output'].split(" ")]
+ else:
+ self.check_files = []
- def checkRunnable(self, option):
+ def check_runnable(self):
+ """
+ Checks if this test can be run.
+ @ In, None
+ @ Out, check_runnable, boolean, If True can run this test.
+ """
i = 0
if len(self.minimum_libraries) % 2:
- self.setStatus('skipped (libraries are not matched to versions numbers: '+str(self.minimum_libraries)+')', self.bucket_skip)
+ self.set_skip('skipped (libraries are not matched to versions numbers: '
+ +str(self.minimum_libraries)+')')
return False
while i < len(self.minimum_libraries):
- libraryName = self.minimum_libraries[i]
- libraryVersion = self.minimum_libraries[i+1]
- found, message, actualVersion = RavenUtils.moduleReport(libraryName,libraryName+'.__version__')
+ library_name = self.minimum_libraries[i]
+ library_version = self.minimum_libraries[i+1]
+ found, _, actual_version = RavenUtils.module_report(library_name, library_name+'.__version__')
if not found:
- self.setStatus('skipped (Unable to import library: "'+libraryName+'")',
- self.bucket_skip)
+ self.set_skip('skipped (Unable to import library: "'+library_name+'")')
return False
- if distutils.version.LooseVersion(actualVersion) < distutils.version.LooseVersion(libraryVersion):
- self.setStatus('skipped (Outdated library: "'+libraryName+'")',
- self.bucket_skip)
+ if distutils.version.LooseVersion(actual_version) < \
+ distutils.version.LooseVersion(library_version):
+ self.set_skip('skipped (Outdated library: "'+library_name+'")')
return False
- i+=2
+ i += 2
if len(self.required_executable) > 0:
try:
- argsList = [self.required_executable]
- argsList.extend(self.required_executable_check_flags)
- retValue = subprocess.call(argsList,stdout=subprocess.PIPE)
- if retValue != 0:
- self.setStatus('skipped (Failing executable: "'+self.required_executable+'")', self.bucket_skip)
+ args_list = [self.required_executable]
+ args_list.extend(self.required_executable_check_flags)
+ ret_value = subprocess.call(args_list, stdout=subprocess.PIPE)
+ if ret_value != 0:
+ self.set_skip('skipped (Failing executable: "'
+ +self.required_executable+'")')
return False
- except:
- self.setStatus('skipped (Error when trying executable: "'+self.required_executable+'")', self.bucket_skip)
+ except Exception:
+ self.set_skip('skipped (Error when trying executable: "'
+ +self.required_executable+'")')
return False
if self.specs['requires_swig2'] and not RavenPython.has_swig2:
- self.setStatus('skipped (No swig 2.0 found)', self.bucket_skip)
+ self.set_skip('skipped (No swig 2.0 found)')
return False
- missing,too_old, notQA = RavenUtils.checkForMissingModules()
+ missing, too_old, _ = RavenUtils.check_for_missing_modules()
if len(missing) > 0:
- self.setStatus('skipped (Missing python modules: '+" ".join(missing)+
- " PYTHONPATH="+os.environ.get("PYTHONPATH","")+')',
- self.bucket_skip)
+ self.set_skip('skipped (Missing python modules: '+" ".join(missing)+
+ " PYTHONPATH="+os.environ.get("PYTHONPATH", "")+')')
return False
- if len(too_old) > 0 and RavenUtils.checkVersions():
- self.setStatus('skipped (Old version python modules: '+" ".join(too_old)+
- " PYTHONPATH="+os.environ.get("PYTHONPATH","")+')',
- self.bucket_skip)
+ if len(too_old) > 0 and RavenUtils.check_versions():
+ self.set_skip('skipped (Old version python modules: '+" ".join(too_old)+
+ " PYTHONPATH="+os.environ.get("PYTHONPATH", "")+')')
return False
for lib in self.required_libraries:
- found, message, version = RavenUtils.moduleReport(lib,'')
+ found, _, _ = RavenUtils.module_report(lib, '')
if not found:
- self.setStatus('skipped (Unable to import library: "'+lib+'")',
- self.bucket_skip)
+ self.set_skip('skipped (Unable to import library: "'+lib+'")')
return False
- if self.specs['python3_only'] and not RavenUtils.inPython3():
- self.setStatus('Python 3 only',
- self.bucket_skip)
+ if self.specs['python3_only'] and not RavenUtils.in_python_3():
+ self.set_skip('Python 3 only')
return False
return True
- def processResults(self, moose_dir, options, output):
- if self.exit_code != 0:
- self.setStatus(str(self.exit_code), self.bucket_fail)
- return output
- self.setStatus(self.success_message, self.bucket_success)
- return output
+ def process_results(self, output):
+ """
+ Sets the status of this test.
+ @ In, output, string, output of running the test.
+ @ Out, None
+ """
+ if self.results.exit_code != 0:
+ self.set_fail(str(self.results.exit_code))
+ return
+ self.set_success()
diff --git a/scripts/TestHarness/testers/RavenUtils.py b/scripts/TestHarness/testers/RavenUtils.py
index f66f41efb9..5b7e4630b4 100644
--- a/scripts/TestHarness/testers/RavenUtils.py
+++ b/scripts/TestHarness/testers/RavenUtils.py
@@ -11,303 +11,326 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+"""
+Various utilities to find the correct library versions.
+"""
from __future__ import print_function
-import os, sys
+import os
+import sys
import subprocess
import distutils.version
import importlib
-def checkVersions():
+def check_versions():
"""
- Returns true if versions should be checked.
- @Out, checkVersions, bool, if true versions should be checked.
+ Returns true if versions should be checked.
+ @ In, None
+ @ Out, check_versions, bool, if true versions should be checked.
"""
- return not os.environ.get("RAVEN_IGNORE_VERSIONS","0") == "1"
+ return os.environ.get("RAVEN_IGNORE_VERSIONS", "0") != "1"
-def inPython3():
- """returns true if raven should be using python3
+def in_python_3():
"""
- return os.environ.get("CHECK_PYTHON3","0") == "1"
+ returns true if raven should be using python3
+ @ In, None
+ @ Out, in_python_3, boolean, True if should be using python3.
+ """
+ return os.environ.get("CHECK_PYTHON3", "0") == "1"
#This list is made of (module, how to check the version, minimum version,
# quality assurance module version, maximum version)
# Deep learning requires Scikit-Learn version at least 0.18
## working Conda 4.5.4, May 2018
-modules_to_try = [("h5py" ,'h5py.__version__' ,'2.4.0' ,'2.7.1' ,None ), # 2.6.0
- ("numpy" ,'numpy.__version__' ,"1.8.0" ,"1.12.1",None ),
- ("scipy" ,'scipy.__version__' ,"1.1.0" ,"1.1.0" ,None ),
- ("sklearn" ,'sklearn.__version__' ,"0.19.1","0.19.1",None ),
- ("pandas" ,'pandas.__version__' ,"0.20.0","0.20.3",None ),
- ("xarray" ,'xarray.__version__' ,"0.9.5" ,"0.10.3",None ),
- ("netCDF4" ,'netCDF4.__version__' ,"1.2.3" ,"1.4.0" ,None ), # 1.2.4
- ## NOTE there is a known bug in netCDF4 prior to 1.3.1 where having a path length
- # of exactly 88 characters can create a seg fault. However, h5py has no new libraries
- # after 2.7 and is not compatible with hdf5 greater than 1.8.17, while netCDF4 requires
- # hdf5 of at least 1.10.1. For now, we avoid using netCDF until we transition from
+modules_to_try = [("h5py", 'h5py.__version__', '2.4.0', '2.7.1', None), # 2.6.0
+ ("numpy", 'numpy.__version__', "1.8.0", "1.12.1", None),
+ ("scipy", 'scipy.__version__', "1.1.0", "1.1.0", None),
+ ("sklearn", 'sklearn.__version__', "0.19.1", "0.19.1", None),
+ ("pandas", 'pandas.__version__', "0.20.0", "0.20.3", None),
+ ("xarray", 'xarray.__version__', "0.9.5", "0.10.3", None),
+ ("netCDF4", 'netCDF4.__version__', "1.2.3", "1.4.0", None), # 1.2.4
+ ## NOTE there is a known bug in netCDF4 prior to 1.3.1 where
+ # having a path length of exactly 88 characters can create a
+ # seg fault. However, h5py has no new libraries
+ # after 2.7 and is not compatible with hdf5 greater than
+ # 1.8.17, while netCDF4 requires hdf5 of at least 1.10.1.
+ # For now, we avoid using netCDF
+ # until we transition from
# HDF5 databases and drop them like hot rocks.
#
#("tensorflow",'tensorflow.__version__',"1.1.0" ,"1.1.0" ,None ),
- # On Windows conda, there are no Python 2.7-compatible versions of TensorFlow, although
+ # On Windows conda, there are no Python 2.7-compatible
+ ## versions of TensorFlow, although
## these exist on Mac and Linux condas. Darn.
- ("statsmodels",'statsmodels.__version__',"0.8.0","0.8.0" ,None ),
- ("matplotlib",'matplotlib.__version__' ,"1.3.1","2.1.1" ,None )]
+ ("statsmodels", 'statsmodels.__version__', "0.8.0", "0.8.0", None),
+ ("matplotlib", 'matplotlib.__version__', "1.3.1", "2.1.1", None)]
-optional_test_libraries = [ ('pillow','PIL.__version__',"5.0.0","5.1.0",None) ]
+optional_test_libraries = [('pillow', 'PIL.__version__', "5.0.0", "5.1.0", None)]
-def __lookUpPreferredVersion(name,optional=False):
+def __lookup_preferred_version(name, optional=False):
"""
Look up the preferred version in the modules.
@In, name, string, the name of the module
@Out, result, string, returns the version as a string or "" if unknown
"""
index = modules_to_try if not optional else optional_test_libraries
- for i,fv,ev,qa,mv in index:
- if name == i:
- return qa
+ for mod_name, _, _, qa_ver, _ in index:
+ if name == mod_name:
+ return qa_ver
return ""
# libraries to install with Conda
-__condaList = [("h5py" ,__lookUpPreferredVersion("h5py" )),
- ("numpy" ,__lookUpPreferredVersion("numpy" )),
- ("scipy" ,__lookUpPreferredVersion("scipy" )),
- ("scikit-learn",__lookUpPreferredVersion("sklearn" )),
- ("pandas" ,__lookUpPreferredVersion("pandas" )),
- ("xarray" ,__lookUpPreferredVersion("xarray" )),
- ("netcdf4" ,__lookUpPreferredVersion("netCDF4" )),
- ("matplotlib" ,__lookUpPreferredVersion("matplotlib")),
- ("statsmodels" ,__lookUpPreferredVersion("statsmodels")),
- #("tensorflow" ,__lookUpPreferredVersion("tensorflow")),
- ("python" ,"2.7"),
- ("hdf5" ,"1.8.18"),
- ("swig" ,""),
- ("pylint" ,""),
- ("coverage" ,""),
- ("lxml" ,""),
- #("nomkl" ,""),
- #("numexpr" ,"")
- ]
+__condaList = [("h5py", __lookup_preferred_version("h5py")),
+ ("numpy", __lookup_preferred_version("numpy")),
+ ("scipy", __lookup_preferred_version("scipy")),
+ ("scikit-learn", __lookup_preferred_version("sklearn")),
+ ("pandas", __lookup_preferred_version("pandas")),
+ ("xarray", __lookup_preferred_version("xarray")),
+ ("netcdf4", __lookup_preferred_version("netCDF4")),
+ ("matplotlib", __lookup_preferred_version("matplotlib")),
+ ("statsmodels", __lookup_preferred_version("statsmodels")),
+ #("tensorflow", __lookup_preferred_version("tensorflow")),
+ ("python", "2.7"),
+ ("hdf5", "1.8.18"),
+ ("swig", ""),
+ ("pylint", ""),
+ ("coverage", ""),
+ ("lxml", "")]
+
# libraries to install with conda-forge
-__condaForgeList = [("pyside",""),
- ]
+__condaForgeList = [("pyside", ""),]
# optional conda libraries
-__condaOptional = [ ('pillow',__lookUpPreferredVersion("pillow")) ]
+__condaOptional = [('pillow', __lookup_preferred_version("pillow"))]
-__pipList = [("numpy",__lookUpPreferredVersion("numpy")),
- ("h5py",__lookUpPreferredVersion("h5py")),
- ("scipy",__lookUpPreferredVersion("scipy")),
- ("scikit-learn",__lookUpPreferredVersion("sklearn")),
- ("matplotlib",__lookUpPreferredVersion("matplotlib")),
- ("xarray",__lookUpPreferredVersion("xarray")),
- ("netCDF4",__lookUpPreferredVersion("netCDF4")),
- ("statsmodels",__lookUpPreferredVersion("statsmodels")),
- #("tensorflow",__lookUpPreferredVersion("tensorflow")),
- ("pandas",__lookUpPreferredVersion("pandas")) ]
+__pipList = [("numpy", __lookup_preferred_version("numpy")),
+ ("h5py", __lookup_preferred_version("h5py")),
+ ("scipy", __lookup_preferred_version("scipy")),
+ ("scikit-learn", __lookup_preferred_version("sklearn")),
+ ("matplotlib", __lookup_preferred_version("matplotlib")),
+ ("xarray", __lookup_preferred_version("xarray")),
+ ("netCDF4", __lookup_preferred_version("netCDF4")),
+ ("statsmodels", __lookup_preferred_version("statsmodels")),
+ #("tensorflow", __lookup_preferred_version("tensorflow")),
+ ("pandas", __lookup_preferred_version("pandas"))]
-def moduleReport(module,version=''):
- """Checks if the module exists.
- Returns (found_boolean,message,version)
- The found_boolean is true if the module is found.
- The message will be the result of print(module)
- The version is the version number or "NA" if not known.
+def module_report(module, version=''):
"""
- if inPython3():
+ Checks if the module exists.
+ @ In, module, string, module name
+ @ In, version, string, optional, if here use this to get the version.
+ @ Out, (found_boolean,message,version)
+ The found_boolean is true if the module is found.
+ The message will be the result of print(module)
+ The version is the version number or "NA" if not known.
+ """
+ if in_python_3():
python = 'python3'
else:
python = 'python'
try:
command = 'import '+module+';print('+module+')'
- output = subprocess.check_output([python,'-c',command])
+ output = subprocess.check_output([python, '-c', command],
+ universal_newlines=True)
if len(version) > 0:
try:
- command = 'import '+module+';print('+version+')'
- foundVersion = subprocess.check_output([python,'-c',command]).strip()
- except:
- foundVersion = "NA"
+ command = 'import '+module+';print('+version+')'
+ found_version = subprocess.check_output([python, '-c', command],
+ universal_newlines=True).strip()
+ except Exception:
+ found_version = "NA"
else:
- foundVersion = "NA"
- return (True,output,foundVersion)
- except:
- return (False,'Failed to find module '+module,"NA")
+ found_version = "NA"
+ return (True, output, found_version)
+ except Exception:
+ return (False, 'Failed to find module '+module, "NA")
-def __importReport(module):
- """ Directly checks the module version.
- Returns (found_boolean,message,version)
- The found_boolean is true if the module is found.
- The message will be the result of print(module)
- The version is the version number or "NA" if not known.
+def __import_report(module):
+ """
+ Directly checks the module version.
+ @ In, module, string, the module name
+ @ Out,(found_boolean,message,version)
+ The found_boolean is true if the module is found.
+ The message will be the result of print(module)
+ The version is the version number or "NA" if not known.
"""
try:
loaded = importlib.import_module(module)
- foundVersion = loaded.__version__
+ found_version = loaded.__version__
output = str(loaded)
- return (True, output, foundVersion)
+ return (True, output, found_version)
except ImportError:
return (False, 'Failed to find module '+module, "NA")
-def modulesReport():
- """Return a report on the modules.
- Returns a list of [(module_name,found_boolean,message,version)]
+def modules_report():
+ """
+ Return a report on the modules.
+ @ In, None
+ @ Out, modules_report, a list of [(module_name,found_boolean,message,version)]
"""
report_list = []
- for i,fv,ev,qa,mv in modules_to_try:
- found, message, version = moduleReport(i,fv)
+ for mod_name, find_ver, min_ver, qa_ver, max_ver in modules_to_try:
+ found, message, version = module_report(mod_name, find_ver)
if found:
- missing, outOfRange, notQA = __checkVersion(i, ev, qa, mv, found, version)
- if len(outOfRange) > 0:
- message += " ".join(outOfRange)
- elif len(notQA) > 0:
- message += " ".join(notQA)
- report_list.append((i,found,message, version))
+ _, out_of_range, not_qa = __check_version(mod_name, min_ver, qa_ver, max_ver, found, version)
+ if len(out_of_range) > 0:
+ message += " ".join(out_of_range)
+ elif len(not_qa) > 0:
+ message += " ".join(not_qa)
+ report_list.append((mod_name, found, message, version))
return report_list
-def __checkVersion(i, ev, qa, mv, found, version):
+def __check_version(mod_name, min_ver, qa_ver, max_ver, found, version):
"""
Checks that the version found is new enough, and also if it matches the
tested version
- @In, i, string, module name
- @In, ev, string, minimum version
- @In, qa, string, tested version
- @In, mv, string, maximum allowed version
+ @In, mod_name, string, module name
+ @In, min_ver, string, minimum version
+ @In, qa_ver, string, tested version
+ @In, max_ver, string, maximum allowed version
@In, found, bool, if true module was found
@In, version, string, found version
- @Out, result, tuple, returns (missing, outOfRange, notQA)
+ @Out, result, tuple, returns (missing, out_of_range, not_qa)
"""
missing = []
- outOfRange = []
- notQA = []
+ out_of_range = []
+ not_qa = []
if not found:
- missing.append(i)
- elif distutils.version.LooseVersion(version) < distutils.version.LooseVersion(ev):
- outOfRange.append(i+" should be at least version "+ev+" but is "+version)
- elif mv is not None and distutils.version.LooseVersion(version) > distutils.version.LooseVersion(mv):
- outOfRange.append(i+" should not be more than version "+mv+" but is "+version)
+ missing.append(mod_name)
+ elif distutils.version.LooseVersion(version) < distutils.version.LooseVersion(min_ver):
+ out_of_range.append(mod_name+" should be at least version "+min_ver+" but is "+version)
+ elif max_ver is not None and distutils.version.LooseVersion(version) > \
+ distutils.version.LooseVersion(max_ver):
+ out_of_range.append(mod_name+" should not be more than version "+max_ver+" but is "+version)
else:
try:
- if distutils.version.StrictVersion(version) != distutils.version.StrictVersion(qa):
- notQA.append(i + " has version " + version + " but tested version is " + qa)
+ if distutils.version.StrictVersion(version) != distutils.version.StrictVersion(qa_ver):
+ not_qa.append(mod_name + " has version " + version + " but tested version is " + qa_ver)
except ValueError:
- notQA.append(i + " has version " + version + " but tested version is " + qa + " and unable to parse version")
- return missing, outOfRange, notQA
+ not_qa.append(mod_name + " has version " + version +
+ " but tested version is " + qa_ver +
+ " and unable to parse version")
+ return missing, out_of_range, not_qa
-def checkForMissingModules(subprocessCheck = True):
+def check_for_missing_modules(subprocess_check=True):
"""
Looks for a list of modules, and the version numbers.
- returns (missing, outOfRange, notQA) where if they are all found is
+ returns (missing, out_of_range, not_qa) where if they are all found is
([], [], []), but if they are missing or too old or too new will put a
error message in the result for each missing or too old module or not on
the quality assurance version.
- @In, subprocessCheck, bool, if true use a subprocess to check
- @Out, result, tuple, returns (missing, outOfRange, notQA)
+ @In, subprocess_check, bool, if true use a subprocess to check
+ @Out, result, tuple, returns (missing, out_of_range, not_qa)
"""
missing = []
- outOfRange = []
- notQA = []
- for i,fv,ev, qa, mv in modules_to_try:
- if subprocessCheck:
- found, message, version = moduleReport(i, fv)
+ out_of_range = []
+ not_qa = []
+ for mod_name, find_ver, min_ver, qa_ver, max_ver in modules_to_try:
+ if subprocess_check:
+ found, _, version = module_report(mod_name, find_ver)
else:
- found, message, version = __importReport(i)
- moduleMissing, moduleOutOfRange, moduleNotQA = __checkVersion(i, ev, qa, mv, found, version)
- missing.extend(moduleMissing)
- outOfRange.extend(moduleOutOfRange)
- notQA.extend(moduleNotQA)
- return missing, outOfRange, notQA
+ found, _, version = __import_report(mod_name)
+ module_missing, module_out_of_range, module_not_qa = \
+ __check_version(mod_name, min_ver, qa_ver, max_ver, found, version)
+ missing.extend(module_missing)
+ out_of_range.extend(module_out_of_range)
+ not_qa.extend(module_not_qa)
+ return missing, out_of_range, not_qa
-def __condaString(includeOptionals=False,opSys=None):
+def __conda_string(include_optionals=False, op_sys=None):
"""
Generates a string with version ids that can be passed to conda.
returns s, string, a list of packages for conda to install
- @ In, includeOptionals, bool, optional, if True then add optional testing libraries to install list
- @ In, opSys, string, optional, if included then parse conda list according to request
- @ Out, s, str, message that could be pasted into a bash command to install libraries
+ @ In, include_optionals, bool, optional, if True then add optional testing
+ libraries to install list
+ @ In, op_sys, string, optional, if included then parse conda list according to request
+ @ Out, conda_s, str, message that could be pasted into a bash command to install libraries
"""
- s = ""
- libList = __condaList + ([] if not includeOptionals else __condaOptional)
- if opSys is not None:
- libList = parseCondaForOS(libList,opSys)
- for name, version in libList:
+ conda_s = ""
+ lib_list = __condaList + ([] if not include_optionals else __condaOptional)
+ if op_sys is not None:
+ lib_list = parse_conda_for_os(lib_list, op_sys)
+ for name, version in lib_list:
# no conda-forge
if len(version) == 0:
- s += name+" "
+ conda_s += name+" "
else:
- s += name+"="+version+" "
- return s
+ conda_s += name+"="+version+" "
+ return conda_s
-def __condaForgeString(opSys=None):
+def __conda_forge_string(op_sys=None):
"""
Generates a string with version ids that can be passed to conda (conda-forge).
- returns s, string, a list of packages for conda to install
- @ In, opSys, string, optional, if included then parse conda list according to request
- @ Out, s, str, message that could be pasted into a bash command to install libraries
+ returns cfs, string, a list of packages for conda to install
+ @ In, op_sys, string, optional, if included then parse conda list according to request
+ @ Out, cfs, str, message that could be pasted into a bash command to install libraries
"""
- s = ""
- libList = __condaForgeList
- if opSys is not None:
- libList = parseCondaForOS(libList,opSys)
- for name, version in libList:
+ cfs = ""
+ lib_list = __condaForgeList
+ if op_sys is not None:
+ lib_list = parse_conda_for_os(lib_list, op_sys)
+ for name, version in lib_list:
# conda-forge
if len(version) == 0:
- s += name+" "
+ cfs += name+" "
else:
- s += name+"="+version+" "
- return s
+ cfs += name+"="+version+" "
+ return cfs
-def parseCondaForOS(libs,opSys):
+def parse_conda_for_os(libs, op_sys):
"""
Modifies the list of Conda for a particular operating system.
@ In, libs, list, list of libraries as (lib,version)
- @ In, opSys, string, name of operating system (mac, windows, linux)
+ @ In, op_sys, string, name of operating system (mac, windows, linux)
@ Out, libs, updated libs list
"""
- if opSys == 'windows':
+ if op_sys == 'windows':
pass # nothing special to do currently
- elif opSys == 'mac':
+ elif op_sys == 'mac':
pass # nothing special to do currently
- elif opSys == 'linux':
+ elif op_sys == 'linux':
# add noMKL libraries to prevent Intel crash errors
- libs.append( ('nomkl' ,'') )
- libs.append( ('numexpr','') )
+ libs.append(('nomkl', ''))
+ libs.append(('numexpr', ''))
return libs
if __name__ == '__main__':
# allow the operating system to be specified
- opSys = None
+ op_sys_arg = None
condaForge = False
if '--windows' in sys.argv:
- opSys = 'windows'
+ op_sys_arg = 'windows'
elif '--mac' in sys.argv:
- opSys = 'mac'
+ op_sys_arg = 'mac'
elif '--linux' in sys.argv:
- opSys = 'linux'
+ op_sys_arg = 'linux'
if '--conda-forge' in sys.argv:
# just install command is generated
condaForge = True
if '--py3' in sys.argv:
- pythonIndex = __condaList.index(("python","2.7"))
- __condaList[pythonIndex] = ("python","3")
- __condaForgeList.append(("matplotlib",""))
+ pythonIndex = __condaList.index(("python", "2.7"))
+ __condaList[pythonIndex] = ("python", "3")
+ __condaForgeList.append(("matplotlib", ""))
# check for environemnt definition of raven libs
- libName = os.getenv('RAVEN_LIBS_NAME','raven_libraries')
+ libName = os.getenv('RAVEN_LIBS_NAME', 'raven_libraries')
# what did the caller ask to do?
if '--conda-create' in sys.argv and not condaForge:
print("conda create --name {} -y ".format(libName), end="")
- print(__condaString(includeOptionals = ('--optional' in sys.argv), opSys = opSys))
+ print(__conda_string(include_optionals=('--optional' in sys.argv), op_sys=op_sys_arg))
elif '--conda-install' in sys.argv:
print("conda install --name {} -y ".format(libName), end=" ")
if not condaForge:
- print(__condaString(includeOptionals = ('--optional' in sys.argv), opSys = opSys))
+ print(__conda_string(include_optionals=('--optional' in sys.argv), op_sys=op_sys_arg))
else:
- print("-c conda-forge "+ __condaForgeString(opSys = opSys))
+ print("-c conda-forge "+ __conda_forge_string(op_sys=op_sys_arg))
elif '--pip-install' in sys.argv:
- print("pip install",end=" ")
- for i,qa in __pipList:
- print(i+"=="+qa,end=" ")
+ print("pip install", end=" ")
+ for k, qa_version in __pipList:
+ print(k+"=="+qa_version, end=" ")
print()
elif '--manual-list' in sys.argv:
print('\\begin{itemize}')
- for i,qa in __condaList+__condaForgeList+__condaOptional:
- print(" \item",i+ (("-"+qa) if len(qa.strip())>0 else ""))
- print("\end{itemize}")
+ for k, qa_version in __condaList+__condaForgeList+__condaOptional:
+ print(" \\item", k+ (("-"+qa_version) if len(qa_version.strip()) > 0 else ""))
+ print("\\end{itemize}")
diff --git a/scripts/TestHarness/testers/TestUnorderedCSV.py b/scripts/TestHarness/testers/TestUnorderedCSV.py
new file mode 100644
index 0000000000..614b24f76e
--- /dev/null
+++ b/scripts/TestHarness/testers/TestUnorderedCSV.py
@@ -0,0 +1,75 @@
+# Copyright 2017 Battelle Energy Alliance, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+ Unit test for the UnorderedCSV differ
+"""
+from __future__ import division, print_function, absolute_import
+import warnings
+
+import sys
+from UnorderedCSVDiffer import UnorderedCSVDiffer as UCSV
+
+warnings.simplefilter('default', DeprecationWarning)
+
+def check_same(comment, first, second, local_msg, local_results):
+ """
+ checks that the first and second are the same.
+ @ In, comment, string, comment if failed.
+ @ In, first, Any, first thing to compare
+ @ In, second, Any, second thing to compare
+ @ In, local_msg, printable, extra thing to print if failed
+ @ In, local_results, dictionary, dictionary of results
+ """
+ if first == second:
+ local_results['pass'] += 1
+ else:
+ local_results['fail'] += 1
+ print('FAILED '+comment)
+ print(local_msg)
+ print('')
+
+def test_a_file(fname):
+ """
+ Tests the file
+ @ In, fname, string, filename string
+ @ Out, test_a_file, (same, message), (bool, str) result of test.
+ """
+ differ = UCSV('.', [fname], zeroThreshold=5e-14)
+ differ.diff()
+ return differ.__dict__['_UnorderedCSVDiffer__same'],\
+ differ.__dict__['_UnorderedCSVDiffer__message']
+
+if __name__ == '__main__':
+ results = {'pass':0, 'fail':0}
+ # passes
+ ok, msg = test_a_file('okay.csv')
+ check_same('Okay', ok, True, msg, results)
+ # mismatch
+ ok, msg = test_a_file('mismatch.csv')
+ check_same('Mismatch', ok, False, msg, results)
+ # matching with inf, nan
+ ok, msg = test_a_file('inf.csv')
+ check_same('Infinity', ok, True, msg, results)
+ # zero threshold
+ ok, msg = test_a_file('nearzero.csv')
+ check_same('Near zero', ok, True, msg, results)
+ # sorting
+ ok, msg = test_a_file('sort.csv')
+ check_same('sort', ok, True, msg, results)
+
+
+
+
+ print('Passed:', results['pass'], '| Failed:', results['fail'])
+ sys.exit(results['fail'])
diff --git a/scripts/TestHarness/testers/TextDiff.py b/scripts/TestHarness/testers/TextDiff.py
index 17a27c9fb0..e3c280d151 100644
--- a/scripts/TestHarness/testers/TextDiff.py
+++ b/scripts/TestHarness/testers/TextDiff.py
@@ -11,74 +11,130 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+"""
+This implements a text differ.
+"""
from __future__ import division, print_function, unicode_literals, absolute_import
-import sys,os,re
+import os
import difflib
+from Tester import Differ
+
class TextDiff:
""" TextDiff is used for comparing a bunch of xml files.
"""
- def __init__(self, testDir, outFile,**kwargs):
- """ Create a TextDiff class
- testDir: the directory where the test takes place
- outFile: the files to be compared. They will be in testDir + outFile
- and testDir + gold + outFile
- args: other arguments that may be included:
- - 'comment': indicates the character or string that should be used to denote a comment line
+ def __init__(self, out_files, gold_files, **kwargs):
+ """
+ Create a TextDiff class
+ @ In, out_files, string list, the files to be compared.
+ @ In, gold_files, string list, the gold files to compare to the outfiles
+ @ In, kwargs, dictionary, other arguments that may be included:
+ - 'comment': indicates the character or string that should be used to denote a comment line
+ @ Out, None
"""
- self.__outFile = outFile
+ assert len(out_files) == len(gold_files)
+ self.__out_files = out_files
+ self.__gold_files = gold_files
self.__messages = ""
self.__same = True
- self.__testDir = testDir
self.__options = kwargs
def diff(self):
- """ Run the comparison.
- returns (same,messages) where same is true if all the txt files are the
- same, and messages is a string with all the differences.
+ """
+ Run the comparison.
+ @ In, None
+ @ Out, (same,messages), (boolean, string), where same is true if all
+ the txt files are the same, and messages is a string with all
+ the differences.
"""
# read in files
- commentSymbol = self.__options['comment']
- for outfile in self.__outFile:
- testFilename = os.path.join(self.__testDir,outfile)
- goldFilename = os.path.join(self.__testDir, 'gold', outfile)
- if not os.path.exists(testFilename):
+ comment_symbol = self.__options['comment']
+ for test_filename, gold_filename in zip(self.__out_files, self.__gold_files):
+ if not os.path.exists(test_filename):
self.__same = False
- self.__messages += 'Test file does not exist: '+testFilename
- elif not os.path.exists(goldFilename):
+ self.__messages += 'Test file does not exist: '+test_filename
+ elif not os.path.exists(gold_filename):
self.__same = False
- self.__messages += 'Gold file does not exist: '+goldFilename
+ self.__messages += 'Gold file does not exist: '+gold_filename
else:
- filesRead = True
+ files_read = True
try:
- testFile = open(testFilename)
- testLines = [line.split(commentSymbol,1)[0].strip() if len(commentSymbol) > 0 else line for line in testFile]
- testLines = [line for line in testLines if len(line) > 0]
- testFile.close()
- except Exception as e:
+ test_file = open(test_filename)
+ test_lines = [line.split(comment_symbol, 1)[0].strip()
+ if len(comment_symbol) > 0
+ else line for line in test_file]
+ test_lines = [line for line in test_lines if len(line) > 0]
+ test_file.close()
+ except Exception as exp:
self.__same = False
- self.__messages += "Error reading " + testFilename + ":" + str(e) + " "
- filesRead = False
+ self.__messages += "Error reading " + test_filename + ":" + str(exp) + " "
+ files_read = False
try:
- goldFile = open(goldFilename)
- goldLines = [line.split(commentSymbol,1)[0].strip() if len(commentSymbol) > 0 else line for line in goldFile]
- goldLines = [line for line in goldLines if len(line) > 0]
- goldFile.close()
- except Exception as e:
+ gold_file = open(gold_filename)
+ gold_lines = [line.split(comment_symbol, 1)[0].strip()
+ if len(comment_symbol) > 0
+ else line for line in gold_file]
+ gold_lines = [line for line in gold_lines if len(line) > 0]
+ gold_file.close()
+ except Exception as exp:
self.__same = False
- self.__messages += "Error reading " + goldFilename + ":" + str(e) + " "
- filesRead = False
+ self.__messages += "Error reading " + gold_filename + ":" + str(exp) + " "
+ files_read = False
- if filesRead:
- diff = list(difflib.unified_diff(testLines,goldLines))
+ if files_read:
+ diff = list(difflib.unified_diff(test_lines, gold_lines))
# deletions = [ line for line in diff if line.startswith('-')]
# additions = [ line for line in diff if line.startswith('+')]
if len(diff):
self.__same = False
separator = "\n"+" "*4
- self.__messages += "Mismatch between "+testFilename+" and "+goldFilename+separator
- self.__messages += separator.join(diff[2:8]) + separator+'...' + "\n" #truncation prevents too much output
+ self.__messages += "Mismatch between "+test_filename+" and "+gold_filename+separator
+ #truncation prevents too much output
+ self.__messages += separator.join(diff[2:8]) + separator+'...' + "\n"
if '[' in self.__messages or ']' in self.__messages:
- self.__messages = self.__messages.replace('[','(')
- self.__messages = self.__messages.replace(']',')')
- return (self.__same,self.__messages)
+ self.__messages = self.__messages.replace('[', '(')
+ self.__messages = self.__messages.replace(']', ')')
+ return (self.__same, self.__messages)
+
+class Text(Differ):
+ """
+ This is the class to use for handling the Text block.
+ """
+ @staticmethod
+ def get_valid_params():
+ """
+ Returns the parameters that this class can use.
+ @ In, None
+ @ Out, params, _ValidParameters, return the parameters.
+ """
+ params = Differ.get_valid_params()
+ params.add_param('comment', '-20021986', "Character or string denoting "+
+ "comments, all text to the right of the symbol will be "+
+ "ignored in the diff of text files")
+ return params
+
+ def __init__(self, name, params, test_dir):
+ """
+ Initializer for the class. Takes a String name and a dictionary params
+ @ In, name, string, name of the test.
+ @ In, params, dictionary, parameters for the class
+ @ In, test_dir, string, path to the test.
+ @ Out, None.
+ """
+ Differ.__init__(self, name, params, test_dir)
+ self.__text_opts = {'comment': self.specs['comment']}
+ #self.__text_files = self.specs['output'].split()
+
+ def check_output(self):
+ """
+ Checks that the output matches the gold.
+ returns (same, message) where same is true if the
+ test passes, or false if the test failes. message should
+ gives a human readable explaination of the differences.
+ @ In, None
+ @ Out, (same, message), same is true if the tests passes.
+ """
+ text_files = self._get_test_files()
+ gold_files = self._get_gold_files()
+ text_diff = TextDiff(text_files, gold_files, **self.__text_opts)
+ return text_diff.diff()
diff --git a/scripts/TestHarness/testers/UnorderedCSVDiffer.py b/scripts/TestHarness/testers/UnorderedCSVDiffer.py
index 1b72e1c3f9..57e4180b32 100644
--- a/scripts/TestHarness/testers/UnorderedCSVDiffer.py
+++ b/scripts/TestHarness/testers/UnorderedCSVDiffer.py
@@ -11,16 +11,23 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+"""
+This module implements a unordered csv differ.
+"""
from __future__ import division, print_function, unicode_literals, absolute_import
-import sys,os
+import sys
+import os
import numpy as np
import pandas as pd
+from Tester import Differ
+
# get access to math tools from RAVEN
try:
from utils import mathUtils
except ImportError:
- new = os.path.realpath(os.path.join(os.path.realpath(__file__),'..','..','..','..','framework'))
+ new = os.path.realpath(os.path.join(os.path.realpath(__file__), '..', '..',
+ '..', '..', 'framework'))
sys.path.append(new)
from utils import mathUtils
@@ -31,34 +38,38 @@ class UnorderedCSVDiffer:
"""
Used for comparing two CSV files without regard for column, row orders
"""
- def __init__(self, test_dir, out_files,relative_error=1e-10,absolute_check=False,zeroThreshold=None,ignore_sign=False):
+ def __init__(self, out_files, gold_files, relative_error=1e-10,
+ absolute_check=False, zero_threshold=None, ignore_sign=False):
"""
Create an UnorderedCSVDiffer class
Note naming conventions are out of our control due to MOOSE test harness standards.
@ In, test_dir, the directory where the test takes place
@ In, out_files, the files to be compared. They will be in test_dir + out_files
+ @ In, gold_files, the files to be compared to the out_files.
@ In, relative_error, float, optional, relative error
- @ In, absolute_check, bool, optional, if True then check absolute differences in the values instead of relative differences
+ @ In, absolute_check, bool, optional, if True then check absolute
+ differences in the values instead of relative differences
@ In, ignore_sign, bool, optional, if True then the sign will be ignored during the comparison
@ Out, None.
"""
+ assert len(out_files) == len(gold_files)
self.__out_files = out_files
+ self.__gold_files = gold_files
self.__message = ""
self.__same = True
- self.__test_dir = test_dir
self.__check_absolute_values = absolute_check
self.__rel_err = relative_error
- self.__zero_threshold = float(zeroThreshold) if zeroThreshold is not None else 0.0
+ self.__zero_threshold = float(zero_threshold) if zero_threshold is not None else 0.0
self.__ignore_sign = ignore_sign
if debug or whoAmI:
- print('test dir :',self.__test_dir)
- print('out files:',self.__out_files)
+ print('out files:', self.__out_files)
+ print('gold files:', self.__gold_files)
if debug:
- print('err :',self.__rel_err)
- print('abs check:',self.__check_absolute_values)
- print('zero thr :',self.__zero_threshold)
+ print('err :', self.__rel_err)
+ print('abs check:', self.__check_absolute_values)
+ print('zero thr :', self.__zero_threshold)
- def finalizeMessage(self,same,msg,filename):
+ def finalize_message(self, same, msg, filename):
"""
Compiles useful messages to print, prepending with file paths.
@ In, same, bool, True if files are the same
@@ -68,9 +79,9 @@ def finalizeMessage(self,same,msg,filename):
"""
if not same:
self.__same = False
- self.__message += '\nDIFF in {}: \n {}'.format(filename,'\n '.join(msg))
+ self.__message += '\nDIFF in {}: \n {}'.format(filename, '\n '.join(msg))
- def findRow(self,row,csv):
+ def find_row(self, row, csv):
"""
Searches for "row" in "csv"
@ In, row, pd.Series, row of data
@@ -79,78 +90,80 @@ def findRow(self,row,csv):
"""
if debug:
print('')
- print('Looking for:\n',row)
- print('Looking in:\n',csv)
+ print('Looking for:\n', row)
+ print('Looking in:\n', csv)
match = csv.copy()
# TODO can I do this as a single search, using binomial on floats +- rel_err?
for idx, val in row.iteritems():
if debug:
- print(' checking index',idx,'value',val)
+ print(' checking index', idx, 'value', val)
# Due to relative matches in floats, we may not be sorted with respect to this index.
## In an ideal world with perfect matches, we would be. Unfortunately, we have to sort again.
match = match.sort_values(idx)
# check type consistency
## get a sample from the matching CSV column
### TODO could check indices ONCE and re-use instead of checking each time
- matchVal = match[idx].values.item(0) if match[idx].values.shape[0] != 0 else None
+ match_val = match[idx].values.item(0) if match[idx].values.shape[0] != 0 else None
## find out if match[idx] and/or "val" are numbers
- matchIsNumber = mathUtils.isAFloatOrInt(matchVal)
- valIsNumber = mathUtils.isAFloatOrInt(val)
+ match_is_number = mathUtils.isAFloatOrInt(match_val)
+ val_is_number = mathUtils.isAFloatOrInt(val)
## if one is a number and the other is not, consider it a non-match.
- if matchIsNumber != valIsNumber:
+ if match_is_number != val_is_number:
if debug:
- print(' Not same type (number)! lfor: "{}" lin: "{}"'.format(valIsNumber,matchIsNumber))
+ print(' Not same type (number)! lfor: "{}" lin: "{}"'
+ .format(val_is_number, match_is_number))
return []
# find index of lowest and highest possible matches
- ## if values are floats, then matches could be as low as val(1-rel_err) and as high as val(1+rel_err)
- if matchIsNumber:
+ ## if values are floats, then matches could be as low as val(1-rel_err)
+ ## and as high as val(1+rel_err)
+ if match_is_number:
pval = abs(val) if self.__ignore_sign else val
pmatch = abs(match[idx].values) if self.__ignore_sign else match[idx].values
# adjust for negative values
sign = np.sign(pval)
- lowest = np.searchsorted(pmatch,pval*(1.0-sign*self.__rel_err))
- highest = np.searchsorted(pmatch,pval*(1.0+sign*self.__rel_err),side='right')-1
+ lowest = np.searchsorted(pmatch, pval*(1.0-sign*self.__rel_err))
+ highest = np.searchsorted(pmatch, pval*(1.0+sign*self.__rel_err), side='right')-1
## if not floats, then check exact matches
else:
- lowest = np.searchsorted(match[idx].values,val)
- highest = np.searchsorted(match[idx].values,val,side='right')-1
+ lowest = np.searchsorted(match[idx].values, val)
+ highest = np.searchsorted(match[idx].values, val, side='right')-1
if debug:
- print(' low/hi match index:',lowest,highest)
+ print(' low/hi match index:', lowest, highest)
## if lowest is past end of array, no match found
if lowest == len(match[idx]):
if debug:
print(' Match is past end of sort list!')
return []
## if entry at lowest index doesn't match entry, then it's not to be found
- if not self.matches(match[idx].values[lowest],val,matchIsNumber,self.__rel_err):
+ if not self.matches(match[idx].values[lowest], val, match_is_number, self.__rel_err):
if debug:
print(' Match is not equal to insert point!')
return []
## otherwise, we have some range of matches
- match = match[slice(lowest,highest+1)]
+ match = match[slice(lowest, highest+1)]
if debug:
- print(' After searching for {}={}, remaining matches:\n'.format(idx,val),match)
+ print(' After searching for {}={}, remaining matches:\n'.format(idx, val), match)
return match
- def matches(self,a,b,isNumber,tol):
+ def matches(self, a_obj, b_obj, is_number, tol):
"""
Determines if two objects match within tolerance.
@ In, a, object, first object ("measured")
@ In, b, object, second object ("actual")
- @ In, isNumber, bool, if True then treat as float with tolerance (else check equivalence)
+ @ In, is_number, bool, if True then treat as float with tolerance (else check equivalence)
@ In, tol, float, tolerance at which to hold match (if float)
@ Out, matches, bool, True if matching
"""
- if not isNumber:
- return a == b
+ if not is_number:
+ return a_obj == b_obj
if self.__ignore_sign:
- a = abs(a)
- b = abs(b)
+ a_obj = abs(a_obj)
+ b_obj = abs(b_obj)
if self.__check_absolute_values:
- return abs(a-b) < tol
+ return abs(a_obj-b_obj) < tol
# otherwise, relative error
- scale = abs(b) if b != 0 else 1.0
- return abs(a-b) < scale*tol
+ scale = abs(b_obj) if b_obj != 0 else 1.0
+ return abs(a_obj-b_obj) < scale*tol
def diff(self):
"""
@@ -160,83 +173,83 @@ def diff(self):
@ Out, messages, str, messages to print on fail
"""
# read in files
- for outFile in self.__out_files:
+ for test_filename, gold_filename in zip(self.__out_files, self.__gold_files):
# local "same" and message list
same = True
msg = []
# load test file
- testFilename = os.path.join(self.__test_dir,outFile)
try:
- testCSV = pd.read_csv(testFilename,sep=',')
+ test_csv = pd.read_csv(test_filename, sep=',')
# if file is empty, we can check that's consistent, too
except pd.errors.EmptyDataError:
- testCSV = None
+ test_csv = None
# if file doesn't exist, that's another problem
except IOError:
msg.append('Test file does not exist!')
same = False
# load gold file
- goldFilename = os.path.join(self.__test_dir, 'gold', outFile)
try:
- goldCSV = pd.read_csv(goldFilename,sep=',')
+ gold_csv = pd.read_csv(gold_filename, sep=',')
# if file is empty, we can check that's consistent, too
except pd.errors.EmptyDataError:
- goldCSV = None
+ gold_csv = None
# if file doesn't exist, that's another problem
except IOError:
msg.append('Gold file does not exist!')
same = False
# if either file did not exist, clean up and go to next outfile
if not same:
- self.finalizeMessage(same,msg,testFilename)
+ self.finalize_message(same, msg, test_filename)
continue
# at this point, we've loaded both files (even if they're empty), so compare them.
## first, cover the case when both files are empty.
- if testCSV is None or goldCSV is None:
- if not (testCSV is None and goldCSV is None):
+ if test_csv is None or gold_csv is None:
+ if not (test_csv is None and gold_csv is None):
same = False
- if testCSV is None:
+ if test_csv is None:
msg.append('Test file is empty, but Gold is not!')
else:
msg.append('Gold file is empty, but Test is not!')
# either way, move on to the next file, as no more comparison is needed
- self.finalizeMessage(same,msg,testFilename)
+ self.finalize_message(same, msg, test_filename)
continue
## at this point, both files have data loaded
## check columns using symmetric difference
- diffColumns = set(goldCSV.columns)^set(testCSV.columns)
- if len(diffColumns) > 0:
+ diff_columns = set(gold_csv.columns)^set(test_csv.columns)
+ if len(diff_columns) > 0:
same = False
- msg.append('Columns are not the same! Different: {}'.format(', '.join(diffColumns)))
- self.finalizeMessage(same,msg,testFilename)
+ msg.append('Columns are not the same! Different: {}'.format(', '.join(diff_columns)))
+ self.finalize_message(same, msg, test_filename)
continue
## check index length
- if len(goldCSV.index) != len(testCSV.index):
+ if len(gold_csv.index) != len(test_csv.index):
same = False
- msg.append('Different number of entires in Gold ({}) versus Test ({})!'.format(len(goldCSV.index),len(testCSV.index)))
- self.finalizeMessage(same,msg,testFilename)
+ msg.append(('Different number of entires in Gold ({}) versus'+
+ ' Test ({})!').format(len(gold_csv.index), len(test_csv.index)))
+ self.finalize_message(same, msg, test_filename)
continue
## at this point both CSVs have the same shape, with the same header contents.
## align columns
- testCSV = testCSV[goldCSV.columns.tolist()]
+ test_csv = test_csv[gold_csv.columns.tolist()]
## set marginal values to zero, fix infinites
- testCSV = self.prepDataframe(testCSV,self.__zero_threshold)
- goldCSV = self.prepDataframe(goldCSV,self.__zero_threshold)
+ test_csv = self.prep_data_frame(test_csv, self.__zero_threshold)
+ gold_csv = self.prep_data_frame(gold_csv, self.__zero_threshold)
## check for matching rows
- for idx in goldCSV.index:
- find = goldCSV.iloc[idx].rename(None)
- match = self.findRow(find,testCSV)
+ for idx in gold_csv.index:
+ find = gold_csv.iloc[idx].rename(None)
+ match = self.find_row(find, test_csv)
if len(match) == 0:
same = False
- msg.append('Could not find match for row "{}" in Gold:\n{}'.format(idx+1,find)) #+1 because of header row
+ msg.append(('Could not find match for row "{}" in '+
+ 'Gold:\n{}').format(idx+1, find)) #+1 because of header row
msg.append('The Test output csv is:')
- msg.append(str(testCSV))
+ msg.append(str(test_csv))
# stop looking once a mismatch is found
break
- self.finalizeMessage(same,msg,testFilename)
+ self.finalize_message(same, msg, test_filename)
return self.__same, self.__message
- def prepDataframe(self,csv,tol):
+ def prep_data_frame(self, csv, tol):
"""
Does several prep actions:
- For any columns that contain numbers, drop near-zero numbers to zero
@@ -248,15 +261,73 @@ def prepDataframe(self,csv,tol):
# use absolute or relative?
key = {'atol':tol} if self.__check_absolute_values else {'rtol':tol}
# take care of infinites
- csv = csv.replace(np.inf,-sys.maxint)
- csv = csv.replace(np.nan,sys.maxint)
+ csv = csv.replace(np.inf, -sys.float_info.max)
+ csv = csv.replace(np.nan, sys.float_info.max)
for col in csv.columns:
example = csv[col].values.item(0) if csv[col].values.shape[0] != 0 else None
# skip columns that aren't numbers TODO might skip float columns with "None" early on
if not mathUtils.isAFloatOrInt(example):
continue
# flatten near-zeros
- csv[col].values[np.isclose(csv[col].values,0,**key)] = 0
- # TODO would like to sort here, but due to relative errors it doesn't do enough good. Instead, sort in findRow.
+ csv[col].values[np.isclose(csv[col].values, 0, **key)] = 0
+ # TODO would like to sort here, but due to relative errors it doesn't do
+ # enough good. Instead, sort in find_row.
return csv
+class UnorderedCSV(Differ):
+ """
+ This is the class to use for handling the parameters block.
+ """
+
+ @staticmethod
+ def get_valid_params():
+ """
+ Returns the valid parameters for this class.
+ @ In, None
+ @ Out, params, _ValidParameters, return the parameters.
+ """
+ params = Differ.get_valid_params()
+ params.add_param('rel_err', '', 'Relative Error for csv files')
+ params.add_param('zero_threshold', sys.float_info.min*4.0,
+ 'it represents the value below which a float is '+
+ 'considered zero (XML comparison only)')
+ params.add_param('ignore_sign', False, 'if true, then only compare the absolute values')
+ params.add_param('check_absolute_value', False, 'if true the values are '+
+ 'compared to the tolerance directectly, instead of relatively.')
+ return params
+
+ def __init__(self, name, params, test_dir):
+ """
+ Initializer for the class. Takes a String name and a dictionary params
+ @ In, name, string, name of the test.
+ @ In, params, dictionary, parameters for the class
+ @ In, test_dir, string, path to the test.
+ @ Out, None.
+ """
+ Differ.__init__(self, name, params, test_dir)
+ self.__zero_threshold = self.specs['zero_threshold']
+ self.__ignore_sign = bool(self.specs['ignore_sign'])
+ if len(self.specs['rel_err']) > 0:
+ self.__rel_err = float(self.specs['rel_err'])
+ else:
+ self.__rel_err = 1e-10
+ self.__check_absolute_value = self.specs["check_absolute_value"]
+
+ def check_output(self):
+ """
+ Checks that the output matches the gold.
+ returns (same, message) where same is true if the
+ test passes, or false if the test failes. message should
+ gives a human readable explaination of the differences.
+ @ In, None
+ @ Out, (same, message), same is true if the tests passes.
+ """
+ csv_files = self._get_test_files()
+ gold_files = self._get_gold_files()
+ csv_diff = UnorderedCSVDiffer(csv_files,
+ gold_files,
+ relative_error=self.__rel_err,
+ zero_threshold=self.__zero_threshold,
+ ignore_sign=self.__ignore_sign,
+ absolute_check=self.__check_absolute_value)
+ return csv_diff.diff()
diff --git a/scripts/TestHarness/testers/XMLDiff.py b/scripts/TestHarness/testers/XMLDiff.py
index 64cdf5a8c3..fff3c0a37d 100644
--- a/scripts/TestHarness/testers/XMLDiff.py
+++ b/scripts/TestHarness/testers/XMLDiff.py
@@ -11,14 +11,20 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+"""
+This implements a test to compare two XML files.
+"""
from __future__ import division, print_function, unicode_literals, absolute_import
-import sys,os,re
+import sys
+import os
import xml.etree.ElementTree as ET
-import diffUtils as DU
+import DiffUtils as DU
+
+from Tester import Differ
numTol = 1e-10 #effectively zero for our purposes
-def findBranches(node,path,finished):
+def find_branches(node, path, finished):
"""
Iterative process to convert XML tree into list of entries
@ In, node, ET.Element, whose children need sorting
@@ -28,200 +34,225 @@ def findBranches(node,path,finished):
"""
for child in node:
npath = path[:]+[child]
- if len(child)==0:
+ if len(child) == 0:
finished.append(npath)
else:
- finished = findBranches(child,npath,finished)
+ finished = find_branches(child, npath, finished)
return finished
-def treeToList(node):
+def tree_to_list(node):
"""
Converts XML tree to list of entries. Useful to start recursive search.
@ In, node, ET.Element, the xml tree root node to convert
- @ Out, treeToList, list(list(ET.Element)), of full paths to entries in xml tree
+ @ Out, tree_to_list, list(list(ET.Element)), of full paths to entries in xml tree
"""
- flattened = findBranches(node,[node],[])
+ flattened = find_branches(node, [node], [])
return list(tuple(f) for f in flattened)
-def compareListEntry(aList,bList,**kwargs):
+def compare_list_entry(a_list, b_list, **kwargs):
"""
Comparse flattened XML entries for equality
return bool is True if all tag, text, and attributes match, False otherwise
return qual is percent of matching terms
- @ In, aList, list(ET.Element), first set
- @ In, bList, list(ET.Element), second set
- @ Out, compareListEntry, (bool,val), results
+ @ In, a_list, list(ET.Element), first set
+ @ In, b_list, list(ET.Element), second set
+ @ Out, compare_list_entry, (bool,val), results
"""
- numMatch = 0 #number of matching points between entries
- totalMatchable = 0 #total tag, text, and attributes available to match
+ num_match = 0 #number of matching points between entries
+ total_matchable = 0 #total tag, text, and attributes available to match
match = True #True if entries match
diff = [] #tuple of (element, diff code, correct (a) value, test (b) value)
options = kwargs
- for i in range(len(aList)):
- if i > len(bList) - 1:
+ for i in range(len(a_list)):
+ if i > len(b_list) - 1:
match = False
- diff.append((bList[-1],XMLDiff.missingChildNode,aList[i].tag,None))
+ diff.append((b_list[-1], XMLDiff.missingChildNode, a_list[i].tag, None))
#could have matched the tag and attributes
- totalMatchable += 1 + len(aList[i].attrib.keys())
+ total_matchable += 1 + len(a_list[i].attrib.keys())
#if text isn't empty, could have matched text, too
- if aList[i].text is not None and len(aList[i].text.strip())>0: totalMatchable+=1
+ if a_list[i].text is not None and len(a_list[i].text.strip()) > 0:
+ total_matchable += 1
continue
- a = aList[i]
- b = bList[i]
+ a_item = a_list[i]
+ b_item = b_list[i]
#match tag
- same,note = DU.compareStringsWithFloats(a.tag,b.tag,options["rel_err"], options["zero_threshold"], options["remove_whitespace"], options["remove_unicode_identifier"])
- totalMatchable += 1
+ same, _ = DU.compare_strings_with_floats(a_item.tag, b_item.tag,
+ options["rel_err"],
+ options["zero_threshold"],
+ options["remove_whitespace"],
+ options["remove_unicode_identifier"])
+ total_matchable += 1
if not same:
match = False
- diff.append((b,XMLDiff.notMatchTag,a.tag,b.tag))
+ diff.append((b_item, XMLDiff.notMatchTag, a_item.tag, b_item.tag))
else:
- numMatch += 1
+ num_match += 1
#match text
- #if (a.text is None or len(a.text)>0) and (b.text is None or len(b.text)>0):
- same,note = DU.compareStringsWithFloats(a.text,b.text,options["rel_err"], options["zero_threshold"], options["remove_whitespace"], options["remove_unicode_identifier"])
+ #if (a_item.text is None or len(a_item.text)>0) and (b_item.text is None or len(b_item.text)>0):
+ same, _ = DU.compare_strings_with_floats(a_item.text,
+ b_item.text,
+ options["rel_err"],
+ options["zero_threshold"],
+ options["remove_whitespace"],
+ options["remove_unicode_identifier"])
if not same:
match = False
- diff.append((b,XMLDiff.notMatchText,str(a.text),str(b.text)))
- totalMatchable += 1
+ diff.append((b_item, XMLDiff.notMatchText, str(a_item.text), str(b_item.text)))
+ total_matchable += 1
else:
- if not(a.text is None or a.text.strip()!=''):
- numMatch += 1
- totalMatchable += 1
+ if not(a_item.text is None or a_item.text.strip() != ''):
+ num_match += 1
+ total_matchable += 1
#match attributes
- for attrib in a.attrib.keys():
- totalMatchable += 1
- if attrib not in b.attrib.keys():
+ for attrib in a_item.attrib.keys():
+ total_matchable += 1
+ if attrib not in b_item.attrib.keys():
match = False
- diff.append((b,XMLDiff.missingAttribute,attrib,None))
+ diff.append((b_item, XMLDiff.missingAttribute, attrib, None))
continue
- same,note = DU.compareStringsWithFloats(a.attrib[attrib],b.attrib[attrib],options["rel_err"], options["zero_threshold"], options["remove_whitespace"], options["remove_unicode_identifier"])
+ same, _ = DU.compare_strings_with_floats(a_item.attrib[attrib],
+ b_item.attrib[attrib],
+ options["rel_err"],
+ options["zero_threshold"],
+ options["remove_whitespace"],
+ options["remove_unicode_identifier"])
if not same:
match = False
- diff.append((b,XMLDiff.notMatchAttribute,(a,attrib),(b,attrib)))
+ diff.append((b_item, XMLDiff.notMatchAttribute, (a_item, attrib), (b_item, attrib)))
else:
- numMatch += 1
- #note attributes in b not in a
- for attrib in b.attrib.keys():
- if attrib not in a.attrib.keys():
+ num_match += 1
+ #note attributes in b_item not in a_item
+ for attrib in b_item.attrib.keys():
+ if attrib not in a_item.attrib.keys():
match = False
- diff.append((b,XMLDiff.extraAttribute,attrib,None))
- totalMatchable += 1
+ diff.append((b_item, XMLDiff.extraAttribute, attrib, None))
+ total_matchable += 1
# note elements in b not in a
- if len(bList) > len(aList):
+ if len(b_list) > len(a_list):
match = False
- for j in range(i,len(bList)):
- diff.append((aList[-1],XMLDiff.extraChildNode,bList[j].tag,None))
+ i = len(a_list) - 1
+ for j in range(i, len(b_list)):
+ diff.append((a_list[-1], XMLDiff.extraChildNode, b_list[j].tag, None))
#count tag and attributes
- totalMatchable += 1 + len(bList[j].attrib.keys())
+ total_matchable += 1 + len(b_list[j].attrib.keys())
#if text isn't empty, count text, too
- if bList[i].text is not None and len(bList[i].text.strip())>0: totalMatchable+=1
- return (match,float(numMatch)/float(totalMatchable),diff)
+ if b_list[i].text is not None and len(b_list[i].text.strip()) > 0:
+ total_matchable += 1
+ return (match, float(num_match)/float(total_matchable), diff)
-def compareUnorderedElement(a,b,*args,**kwargs):
+def compare_unordered_element(a_element, b_element, **kwargs):
"""
Compares two element trees and returns (same,message)
where same is true if they are the same,
and message is a list of the differences.
Uses list of tree entries to find best match, instead of climbing the tree
- @ In, a, ET.Element, the first element
- @ In, b, ET.Element, the second element
- @ Out, compareUnorderedElement, (bool,[string]), results of comparison
+ @ In, a_element, ET.Element, the first element
+ @ In, b_element, ET.Element, the second element
+ @ Out, compare_unordered_element, (bool,[string]), results of comparison
"""
same = True
message = []
options = kwargs
matchvals = {}
diffs = {}
- DU.setDefaultOptions(options)
+ DU.set_default_options(options)
- def failMessage(*args):
+ def fail_message(*args):
"""
adds the fail message to the list
@ In, args, list, The arguments to the fail message (will be converted with str())
- @ Out, failMessage, (bool,string), results
+ @ Out, fail_message, (bool,string), results
"""
- printArgs = []
- printArgs.extend(args)
- argsExpanded = " ".join([str(x) for x in printArgs])
- message.append(argsExpanded)
- if a.text != b.text:
- succeeded, note = DU.compareStringsWithFloats(a.text, b.text, options["rel_err"], options["zero_threshold"], options["remove_whitespace"], options["remove_unicode_identifier"])
+ print_args = []
+ print_args.extend(args)
+ args_expanded = " ".join([str(x) for x in print_args])
+ message.append(args_expanded)
+ if a_element.text != b_element.text:
+ succeeded, note = DU.compare_strings_with_floats(a_element.text,
+ b_element.text,
+ options["rel_err"],
+ options["zero_threshold"],
+ options["remove_whitespace"],
+ options["remove_unicode_identifier"])
if not succeeded:
same = False
- failMessage(note)
+ fail_message(note)
return (same, message)
- aList = treeToList(a)
- bList = treeToList(b)
+ a_list = tree_to_list(a_element)
+ b_list = tree_to_list(b_element)
#search a for matches in b
- for aEntry in aList:
- matchvals[aEntry] = {}
- diffs[aEntry] = {}
- for bEntry in bList:
- same,matchval,diff = compareListEntry(aEntry,bEntry,**options)
+ for a_entry in a_list:
+ matchvals[a_entry] = {}
+ diffs[a_entry] = {}
+ for b_entry in b_list:
+ same, matchval, diff = compare_list_entry(a_entry, b_entry, **options)
if same:
- bList.remove(bEntry)
- del matchvals[aEntry]
- del diffs[aEntry]
+ b_list.remove(b_entry)
+ del matchvals[a_entry]
+ del diffs[a_entry]
#since we found the match, remove from other near matches
- for closeKey in diffs.keys():
- if bEntry in diffs[closeKey].keys():
- del diffs[closeKey][bEntry]
- del matchvals[closeKey][bEntry]
+ for close_key in diffs:
+ if b_entry in diffs[close_key].keys():
+ del diffs[close_key][b_entry]
+ del matchvals[close_key][b_entry]
break
else:
- matchvals[aEntry][bEntry] = matchval
- diffs[aEntry][bEntry] = diff
- if len(matchvals)==0: #all matches found
- return (True,'')
- else:
- note = ''
- for unmatched,close in matchvals.items():
- #print the path without a match
- note+='No match for '+'/'.join(list(m.tag for m in unmatched))+'\n'
- #print the tree of the nearest match
- note+=' Nearest unused match: '
- close = sorted(list(close.items()),key=lambda x:x[1],reverse=True)
- if len(close) > 1:
- closest = '/'.join(list(c.tag for c in close[0][0]))
- else:
- closest = '-none found-'
- note+=' '+ closest +'\n'
- #print what was different between them
- if len(close) > 1:
- diff = diffs[unmatched][close[0][0]]
- for b,code,right,miss in diff:
- if b is None:
- b = str(b)
- if code is None:
- code = str(code)
- if right is None:
- right = str(right)
- if miss is None:
- miss = str(miss)
- if code == XMLDiff.missingChildNode:
- note+=' <'+b.tag+'> is missing child node: <'+right+'> vs <'+miss+'>\n'
- elif code == XMLDiff.missingAttribute:
- note+=' <'+b.tag+'> is missing attribute: "'+right+'"\n'
- elif code == XMLDiff.extraChildNode:
- note+=' <'+b.tag+'> has extra child node: <'+right+'>\n'
- elif code == XMLDiff.extraAttribute:
- note+=' <'+b.tag+'> has extra attribute: "'+right+'" = "'+b.attrib[right]+'"\n'
- elif code == XMLDiff.notMatchTag:
- note+=' <'+b.tag+'> tag does not match: <'+right+'> vs <'+miss+'>\n'
- elif code == XMLDiff.notMatchAttribute:
- note+=' <'+b.tag+'> attribute does not match: "'+right[1]+'" = "'+right[0].attrib[right[1]]+'" vs "'+miss[0].attrib[miss[1]]+'"\n'
- elif code == XMLDiff.notMatchText:
- note+=' <'+b.tag+'> text does not match: "'+right+'" vs "'+miss+'"\n'
- else:
- note+=' UNRECOGNIZED OPTION: "'+b.tag+'" "'+str(code)+'": "'+str(right)+'" vs "'+str(miss)+'"\n'
+ matchvals[a_entry][b_entry] = matchval
+ diffs[a_entry][b_entry] = diff
+ if len(matchvals) == 0: #all matches found
+ return (True, '')
+ note = ''
+ for unmatched, close in matchvals.items():
+ #print the path without a match
+ note += 'No match for '+'/'.join(list(m.tag for m in unmatched))+'\n'
+ #print the tree of the nearest match
+ note += ' Nearest unused match: '
+ close = sorted(list(close.items()), key=lambda x: x[1], reverse=True)
+ if len(close) > 1:
+ closest = '/'.join(list(c.tag for c in close[0][0]))
+ else:
+ closest = '-none found-'
+ note += ' '+ closest +'\n'
+ #print what was different between them
+ if len(close) > 1:
+ diff = diffs[unmatched][close[0][0]]
+ for b_diff, code, right, miss in diff:
+ if b_diff is None:
+ b_diff = str(b_diff)
+ if code is None:
+ code = str(code)
+ if right is None:
+ right = str(right)
+ if miss is None:
+ miss = str(miss)
+ if code == XMLDiff.missingChildNode:
+ note += ' <'+b_diff.tag+'> is missing child node: <'+right+'> vs <'+miss+'>\n'
+ elif code == XMLDiff.missingAttribute:
+ note += ' <'+b_diff.tag+'> is missing attribute: "'+right+'"\n'
+ elif code == XMLDiff.extraChildNode:
+ note += ' <'+b_diff.tag+'> has extra child node: <'+right+'>\n'
+ elif code == XMLDiff.extraAttribute:
+ note += ' <'+b_diff.tag+'> has extra attribute: "'+right+\
+ '" = "'+b_diff.attrib[right]+'"\n'
+ elif code == XMLDiff.notMatchTag:
+ note += ' <'+b_diff.tag+'> tag does not match: <'+right+'> vs <'+miss+'>\n'
+ elif code == XMLDiff.notMatchAttribute:
+ note += ' <'+b_diff.tag+'> attribute does not match: "'+right[1]+\
+ '" = "'+right[0].attrib[right[1]]+'" vs "'+miss[0].attrib[miss[1]]+'"\n'
+ elif code == XMLDiff.notMatchText:
+ note += ' <'+b_diff.tag+'> text does not match: "'+right+'" vs "'+miss+'"\n'
+ else:
+ note += ' UNRECOGNIZED OPTION: "'+b_diff.tag+'" "'+str(code)+\
+ '": "'+str(right)+'" vs "'+str(miss)+'"\n'
- return (False,[note])
+ return (False, [note])
-def compareOrderedElement(a,b,*args,**kwargs):
+def compare_ordered_element(a_element, b_element, *args, **kwargs):
"""
- Compares two element trees and returns (same,message) where same is true if they are the same, and message is a list of the differences
- @ In, a, ET.Element, the first element tree
- @ In, b, ET.Element, the second element tree
+ Compares two element trees and returns (same,message) where same is true
+ if they are the same, and message is a list of the differences
+ @ In, a_element, ET.Element, the first element tree
+ @ In, b_element, ET.Element, the second element tree
@ In, args, dict, arguments
@ In, kwargs, dict, keyword arguments
accepted args:
@@ -229,151 +260,215 @@ def compareOrderedElement(a,b,*args,**kwargs):
accepted kwargs:
path: a string to describe where the element trees are located (mainly
used recursively)
- @ Out, compareOrderedElement, (bool,[string]), results of comparison
+ @ Out, compare_ordered_element, (bool,[string]), results of comparison
"""
same = True
message = []
options = kwargs
- path = kwargs.get('path','')
- counter = kwargs.get('counter',0)
- DU.setDefaultOptions(options)
+ path = kwargs.get('path', '')
+ counter = kwargs.get('counter', 0)
+ DU.set_default_options(options)
- def failMessage(*args):
+ def fail_message(*args):
"""
adds the fail message to the list
@ In, args, list, The arguments to the fail message (will be converted with str())
- @ Out, failMessage, (bool,string), results
+ @ Out, fail_message, (bool,string), results
"""
- printArgs = [path]
- printArgs.extend(args)
- argsExpanded = " ".join([str(x) for x in printArgs])
- message.append(argsExpanded)
+ print_args = [path]
+ print_args.extend(args)
+ args_expanded = " ".join([str(x) for x in print_args])
+ message.append(args_expanded)
- if a.tag != b.tag:
+ if a_element.tag != b_element.tag:
same = False
- failMessage("mismatch tags ",a.tag,b.tag)
+ fail_message("mismatch tags ", a_element.tag, b_element.tag)
else:
- path += a.tag + "/"
- if a.text != b.text:
- succeeded, note = DU.compareStringsWithFloats(a.text, b.text, options["rel_err"], options["zero_threshold"], options["remove_whitespace"], options["remove_unicode_identifier"])
+ path += a_element.tag + "/"
+ if a_element.text != b_element.text:
+ succeeded, note = DU.compare_strings_with_floats(a_element.text,
+ b_element.text,
+ options["rel_err"],
+ options["zero_threshold"],
+ options["remove_whitespace"],
+ options["remove_unicode_identifier"])
if not succeeded:
same = False
- failMessage(note)
+ fail_message(note)
return (same, message)
- differentKeys = set(a.keys()).symmetric_difference(set(b.keys()))
- sameKeys = set(a.keys()).intersection(set(b.keys()))
- if len(differentKeys) != 0:
+ different_keys = set(a_element.keys()).symmetric_difference(set(b_element.keys()))
+ same_keys = set(a_element.keys()).intersection(set(b_element.keys()))
+ if len(different_keys) != 0:
same = False
- failMessage("mismatch attribute keys ",differentKeys)
- for key in sameKeys:
- if a.attrib[key] != b.attrib[key]:
+ fail_message("mismatch attribute keys ", different_keys)
+ for key in same_keys:
+ if a_element.attrib[key] != b_element.attrib[key]:
same = False
- failMessage("mismatch attribute ",key,a.attrib[key],b.attrib[key])
- if len(a) != len(b):
+ fail_message("mismatch attribute ", key, a_element.attrib[key], b_element.attrib[key])
+ if len(a_element) != len(b_element):
same = False
- failMessage("mismatch number of children ",len(a),len(b))
+ fail_message("mismatch number of children ", len(a_element), len(b_element))
else:
- if a.tag == b.tag:
+ if a_element.tag == b_element.tag:
#find all matching XML paths
#WARNING: this will mangle the XML, so other testing should happen above this!
- found=[]
- for i in range(len(a)):
- subOptions = dict(options)
- subOptions["path"] = path
- (sameChild,messageChild) = compareOrderedElement(a[i],b[i],*args,**subOptions)
- if sameChild: found.append((a[i],b[i]))
- same = same and sameChild
+ found = []
+ for i in range(len(a_element)):
+ sub_options = dict(options)
+ sub_options["path"] = path
+ (same_child, _) = compare_ordered_element(a_element[i], b_element[i], *args, **sub_options)
+ if same_child:
+ found.append((a_element[i], b_element[i]))
+ same = same and same_child
#prune matches from trees
for children in found:
- a.remove(children[0])
- b.remove(children[1])
+ a_element.remove(children[0])
+ b_element.remove(children[1])
#once all pruning done, error on any remaining structure
- if counter==0: #on head now, recursion is finished
- if len(a)>0:
- aString = ET.tostring(a)
- if len(aString) > 80:
+ if counter == 0: #on head now, recursion is finished
+ if len(a_element) > 0:
+ a_string = ET.tostring(a_element)
+ if len(a_string) > 80:
message.append('Branches in gold not matching test...\n'+path)
else:
message.append('Branches in gold not matching test...\n'+path+
- " "+aString)
- if len(b)>0:
- bString = ET.tostring(b)
- if len(bString) > 80:
+ " "+a_string)
+ if len(b_element) > 0:
+ b_string = ET.tostring(b_element)
+ if len(b_string) > 80:
message.append('Branches in test not matching gold...\n'+path)
else:
message.append('Branches in test not matching gold...\n'+path+
- " "+bString)
- return (same,message)
+ " "+b_string)
+ return (same, message)
class XMLDiff:
"""
XMLDiff is used for comparing xml files.
"""
#static codes for differences
- missingChildNode = 0
- missingAttribute = 1
- extraChildNode = 2
- extraAttribute = 3
- notMatchTag = 4
+ missingChildNode = 0
+ missingAttribute = 1
+ extraChildNode = 2
+ extraAttribute = 3
+ notMatchTag = 4
notMatchAttribute = 5
- notMatchText = 6
+ notMatchText = 6
- def __init__(self, testDir, outFile,**kwargs):
+ def __init__(self, out_files, gold_files, **kwargs):
"""
Create an XMLDiff class
@ In, testDir, string, the directory where the test takes place
- @ In, outFile, string, the files to be compared. They will be in testDir + outFile and testDir + gold + outFile
+ @ In, out_files, List(string), the files to be compared.
+ @ In, gold_files, List(String), the gold files to be compared.
@ In, kwargs, dict, other arguments that may be included:
- 'unordered': indicates unordered sorting
@ Out, None
"""
- self.__outFile = outFile
+ assert len(out_files) == len(gold_files)
+ self.__out_files = out_files
+ self.__gold_files = gold_files
self.__messages = ""
self.__same = True
- self.__testDir = testDir
self.__options = kwargs
def diff(self):
"""
Run the comparison.
@ In, None
- @ Out, diff, (bool,string), (same,messages) where same is true if all the xml files are the same, and messages is a string with all the differences.
+ @ Out, diff, (bool,string), (same,messages) where same is true if all
+ the xml files are the same, and messages is a string with all the
+ differences.
"""
# read in files
- for outfile in self.__outFile:
- testFilename = os.path.join(self.__testDir,outfile)
- goldFilename = os.path.join(self.__testDir, 'gold', outfile)
- if not os.path.exists(testFilename):
+ for test_filename, gold_filename in zip(self.__out_files, self.__gold_files):
+ if not os.path.exists(test_filename):
self.__same = False
- self.__messages += 'Test file does not exist: '+testFilename
- elif not os.path.exists(goldFilename):
+ self.__messages += 'Test file does not exist: '+test_filename
+ elif not os.path.exists(gold_filename):
self.__same = False
- self.__messages += 'Gold file does not exist: '+goldFilename
+ self.__messages += 'Gold file does not exist: '+gold_filename
else:
- filesRead = True
+ files_read = True
try:
- testRoot = ET.parse( testFilename ).getroot()
- except Exception as e:
- filesRead = False
- self.__messages += 'Exception reading file '+testFilename+': '+str(e.args)
+ test_root = ET.parse(test_filename).getroot()
+ except Exception as exp:
+ files_read = False
+ self.__messages += 'Exception reading file '+test_filename+': '+str(exp.args)
try:
- goldRoot = ET.parse( goldFilename ).getroot()
- except Exception as e:
- filesRead = False
- self.__messages += 'Exception reading file '+goldFilename+': '+str(e.args)
- if filesRead:
+ gold_root = ET.parse(gold_filename).getroot()
+ except Exception as exp:
+ files_read = False
+ self.__messages += 'Exception reading file '+gold_filename+': '+str(exp.args)
+ if files_read:
if 'unordered' in self.__options.keys() and self.__options['unordered']:
- same,messages = compareUnorderedElement(goldRoot,testRoot,**self.__options)
+ same, messages = compare_unordered_element(gold_root, test_root, **self.__options)
else:
- same,messages = compareOrderedElement(testRoot, goldRoot,**self.__options)
+ same, messages = compare_ordered_element(test_root, gold_root, **self.__options)
if not same:
self.__same = False
separator = "\n"+" "*4
- self.__messages += "Mismatch between "+testFilename+" and "+goldFilename+separator
+ self.__messages += "Mismatch between "+test_filename+" and "+gold_filename+separator
self.__messages += separator.join(messages) + "\n"
else:
self.__same = False
if '[' in self.__messages or ']' in self.__messages:
- self.__messages = self.__messages.replace('[','(')
- self.__messages = self.__messages.replace(']',')')
- return (self.__same,self.__messages)
+ self.__messages = self.__messages.replace('[', '(')
+ self.__messages = self.__messages.replace(']', ')')
+ return (self.__same, self.__messages)
+
+class XML(Differ):
+ """
+ This is the class to use for handling the XML block.
+ """
+ @staticmethod
+ def get_valid_params():
+ """
+ Return the valid parameters for this class.
+ @ In, None
+ @ Out, params, _ValidParameters, return the parameters.
+ """
+ params = Differ.get_valid_params()
+ params.add_param('unordered', False, 'if true allow the tags in any order')
+ params.add_param('zero_threshold', sys.float_info.min*4.0, 'it represents '
+ +'the value below which a float is considered zero (XML comparison only)')
+ params.add_param('remove_whitespace', False,
+ 'Removes whitespace before comparing xml node text if True')
+ params.add_param('remove_unicode_identifier', False,
+ 'if true, then remove u infront of a single quote')
+ params.add_param('xmlopts', '', "Options for xml checking")
+ params.add_param('rel_err', '', 'Relative Error for csv files or floats in xml ones')
+ return params
+
+ def __init__(self, name, params, test_dir):
+ """
+ Initializer for the class. Takes a String name and a dictionary params
+ @ In, name, string, name of the test.
+ @ In, params, dictionary, parameters for the class
+ @ In, test_dir, string, path to the test.
+ @ Out, None.
+ """
+ Differ.__init__(self, name, params, test_dir)
+ self.__xmlopts = {}
+ if len(self.specs["rel_err"]) > 0:
+ self.__xmlopts['rel_err'] = float(self.specs["rel_err"])
+ self.__xmlopts['zero_threshold'] = float(self.specs["zero_threshold"])
+ self.__xmlopts['unordered'] = bool(self.specs["unordered"])
+ self.__xmlopts['remove_whitespace'] = bool(self.specs['remove_whitespace'])
+ self.__xmlopts['remove_unicode_identifier'] = self.specs['remove_unicode_identifier']
+ if len(self.specs['xmlopts']) > 0:
+ self.__xmlopts['xmlopts'] = self.specs['xmlopts'].split(' ')
+
+ def check_output(self):
+ """
+ Checks that the output matches the gold.
+ returns (same, message) where same is true if the
+ test passes, or false if the test failes. message should
+ gives a human readable explaination of the differences.
+ @ In, None
+ @ Out, (same, message), same is true if the tests passes.
+ """
+ xml_files = self._get_test_files()
+ gold_files = self._get_gold_files()
+ xml_diff = XMLDiff(xml_files, gold_files, **self.__xmlopts)
+ return xml_diff.diff()
diff --git a/scripts/TestHarness/testers/diffUtils.py b/scripts/TestHarness/testers/diffUtils.py
deleted file mode 100644
index 44fb83b1d5..0000000000
--- a/scripts/TestHarness/testers/diffUtils.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# Copyright 2017 Battelle Energy Alliance, LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-import re,sys
-
-#A float consists of possibly a + or -, followed possibly by some digits
-# followed by one of ( digit. | .digit | or digit) possibly followed by some
-# more digits possibly followed by an exponent
-floatRe = re.compile("([-+]?\d*(?:(?:\d[.])|(?:[.]\d)|(?:\d))\d*(?:[eE][+-]\d+)?)")
-
-def splitIntoParts(s):
- """
- Splits the string into floating parts and not float parts
- @ In, s, string, the string to split
- @ Out, splitIntoParts, string, a list where the even indexs are string and the odd indexs are floating point number strings.
- """
- return floatRe.split(s)
-
-def shortText(a,b):
- """
- Returns a short portion of the text that shows the first difference
- @ In, a, string, the first text element
- @ In, b, string, the second text element
- @ Out, shortText, string, resulting shortened diff
- """
- a = repr(a)
- b = repr(b)
- displayLen = 20
- halfDisplay = displayLen//2
- if len(a)+len(b) < displayLen:
- return a+" "+b
- firstDiff = -1
- i = 0
- while i < len(a) and i < len(b):
- if a[i] == b[i]:
- i += 1
- else:
- firstDiff = i
- break
- if firstDiff >= 0:
- #diff in content
- start = max(0,firstDiff - halfDisplay)
- else:
- #diff in length
- firstDiff = min(len(a),len(b))
- start = max(0,firstDiff - halfDisplay)
- if start > 0:
- prefix = "..."
- else:
- prefix = ""
- return prefix+a[start:firstDiff+halfDisplay]+" "+prefix+b[start:firstDiff+halfDisplay]
-
-def setDefaultOptions(options):
- """
- sets all the options to defaults
- @ In, options, dict, dictionary to add default options to
- @ Out, None
- """
- options["rel_err"] = float(options.get("rel_err",1.e-10))
- options["zero_threshold"] = float(options.get("zero_threshold",sys.float_info.min*4.0))
- options["remove_whitespace"] = options.get("remove_whitespace",False)
- options["remove_unicode_identifier"] = options.get("remove_unicode_identifier",False)
-
-def removeWhitespaceChars(s):
- """
- Removes whitespace characters
- @ In, s, string, to remove characters from
- @ Out, s, string, removed whitespace string
- """
- s = s.replace(" ","")
- s = s.replace("\t","")
- s = s.replace("\n","")
- #if this were python3 this would work:
- #removeWhitespaceTrans = "".maketrans("",""," \t\n")
- #s = s.translate(removeWhitespaceTrans)
- return s
-
-def removeUnicodeIdentifiers(s):
- """
- Removes the u infrount of a unicode string: u'string' -> 'string'
- Note that this also removes a u at the end of string 'stru' -> 'str'
- which is not intended.
- @ In, s, string, string to remove characters from
- @ Out, s, string, cleaned string
- """
- s = s.replace("u'","'")
- return s
-
-def compareStringsWithFloats(a,b,numTol = 1e-10, zeroThreshold = sys.float_info.min*4.0, removeWhitespace = False, removeUnicodeIdentifier = False):
- """
- Compares two strings that have floats inside them. This searches for floating point numbers, and compares them with a numeric tolerance.
- @ In, a, string, first string to use
- @ In, b, string, second string to use
- @ In, numTol, float, the numerical tolerance.
- @ In, zeroThershold, float, it represents the value below which a float is considered zero (XML comparison only). For example, if zeroThershold = 0.1, a float = 0.01 will be considered as it was 0.0
- @ In, removeWhitespace, bool, if True, remove all whitespace before comparing.
- @ Out, compareStringWithFloats, (bool,string), (succeeded, note) where succeeded is a boolean that is true if the strings match, and note is a comment on the comparison.
- """
- if a == b:
- return (True,"Strings Match")
- if a is None or b is None: return (False,"One of the strings contain a None")
- if removeWhitespace:
- a = removeWhitespaceChars(a)
- b = removeWhitespaceChars(b)
- if removeUnicodeIdentifier:
- a = removeUnicodeIdentifiers(a)
- b = removeUnicodeIdentifiers(b)
- aList = splitIntoParts(a)
- bList = splitIntoParts(b)
- if len(aList) != len(bList):
- return (False,"Different numbers of float point numbers")
- for i in range(len(aList)):
- aPart = aList[i].strip()
- bPart = bList[i].strip()
- if i % 2 == 0:
- #In string
- if aPart != bPart:
- return (False,"Mismatch of "+shortText(aPart,bPart))
- else:
- #In number
- aFloat = float(aPart)
- bFloat = float(bPart)
- aFloat = aFloat if abs(aFloat) > zeroThreshold else 0.0
- bFloat = bFloat if abs(bFloat) > zeroThreshold else 0.0
- if abs(aFloat - bFloat) > numTol:
- return (False,"Numeric Mismatch of '"+aPart+"' and '"+bPart+"'")
-
- return (True, "Strings Match Floatwise")
-
-def isANumber(x):
- """
- Checks if x can be converted to a float.
- @ In, x, object, a variable or value
- @ Out, isANumber, bool, True if x can be converted to a float.
- """
- try:
- float(x)
- return True
- except ValueError:
- return False
diff --git a/scripts/TestHarness/testers/testUnorderedCSV.py b/scripts/TestHarness/testers/testUnorderedCSV.py
deleted file mode 100644
index 31e28ed81c..0000000000
--- a/scripts/TestHarness/testers/testUnorderedCSV.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2017 Battelle Energy Alliance, LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""
- Unit test for the UnorderedCSV differ
-"""
-
-import sys
-from UnorderedCSVDiffer import UnorderedCSVDiffer as UCSV
-
-def checkSame(comment,first,second,msg,results=None):
- if results is None:
- results = {'pass':0,'fail':0}
- if first == second:
- results['pass'] += 1
- else:
- results['fail'] += 1
- print 'FAILED '+comment
- print msg
- print ''
- return results
-
-def testAFile(fname):
- differ = UCSV('.',[fname],zeroThreshold=5e-14)
- differ.diff()
- return differ.__dict__['_UnorderedCSVDiffer__same'], differ.__dict__['_UnorderedCSVDiffer__message']
-
-if __name__ == '__main__':
- results = {'pass':0,'fail':0}
- # passes
- ok,msg = testAFile('okay.csv')
- checkSame('Okay',ok,True,msg,results)
- # mismatch
- ok,msg = testAFile('mismatch.csv')
- checkSame('Mismatch',ok,False,msg,results)
- # matching with inf, nan
- ok,msg = testAFile('inf.csv')
- checkSame('Infinity',ok,True,msg,results)
- # zero threshold
- ok,msg = testAFile('nearzero.csv')
- checkSame('Near zero',ok,True,msg,results)
- # sorting
- ok,msg = testAFile('sort.csv')
- checkSame('sort',ok,True,msg,results)
-
-
-
-
- print 'Passed:',results['pass'],'| Failed:',results['fail']
- sys.exit(results['fail'])
diff --git a/scripts/library_report b/scripts/library_report
new file mode 100755
index 0000000000..51dcbe3b91
--- /dev/null
+++ b/scripts/library_report
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+from __future__ import print_function
+import sys, os, subprocess, re
+
+# Set the current working directory to the directory where this script is located
+os.chdir(os.path.abspath(os.path.dirname(os.path.dirname(sys.argv[0]))))
+
+#add framework contrib path
+RAVEN_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+os.environ["PYTHONPATH"] = os.path.join(RAVEN_DIR,'framework','contrib') + os.pathsep + os.environ.get("PYTHONPATH","")
+
+print("PYTHONPATH="+os.environ.get("PYTHONPATH",""))
+path = os.environ.get("PATH","")
+print("PATH="+path)
+print("Python Executable: ",sys.executable)
+print("Possible Python Executables on System:")
+for pathPart in path.split(os.pathsep):
+ if os.path.isdir(pathPart):
+ for directoryEntry in os.listdir(pathPart):
+ lower = directoryEntry.lower()
+ #match things like python, python2, python2.7, python.exe
+ if re.match("python(\\d*(\\.\\d+)?)(\\.exe)?$",lower):
+ print(pathPart+os.sep+directoryEntry)
+import platform
+print("OS:",platform.platform())
+print("Python:",sys.version)
+try:
+ if os.path.exists(".git"):
+ print("Git information:")
+ os.system('git log -1 --format="%H %aD"')
+ os.system('git describe')
+ os.system('git submodule')
+ elif os.path.exists("Version.txt"):
+ print("Version.txt:")
+ print(open("Version.txt","r").read())
+ else:
+ print("Could not find RAVEN version info")
+except:
+ print("Failed to find git version")
+sys.path.append(os.path.join(RAVEN_DIR,"scripts","TestHarness","testers"))
+sys.path.insert(0,os.path.join(RAVEN_DIR,"framework","utils"))
+import RavenUtils,utils
+#missing,too_old = RavenUtils.checkForMissingModules()
+#print(missing,too_old)
+report_list = RavenUtils.modules_report()
+amsc_report = RavenUtils.module_report('AMSC')
+report_list.append(('AMSC',amsc_report[0],amsc_report[1],""))
+print("\nLibraries report:\n")
+for module, found, message, version in report_list:
+ if found:
+ print(module,version,"\n",message,"\n")
+ else:
+ print(module+' not found\n')
+framework_dir = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]),"framework"))
+utils.find_crow(framework_dir)
+try:
+ distribution1D = utils.findCrowModule('distribution1D')
+ print("distribution1D","\n",distribution1D)
+ print()
+except ImportError:
+ print("distribution1D not found\n")
+try:
+ interpolationND = utils.findCrowModule('interpolationND')
+ print("interpolationND","\n",interpolationND)
+except ImportError:
+ print("interpolationND not found\n")
+try:
+ randomENG = utils.findCrowModule('randomENG')
+ print("randomENG","\n",randomENG)
+except ImportError:
+ print("randomENG not found\n")
+
+
diff --git a/tests/framework/AnalyticModels/AnalyticCodes/variable_time.py b/tests/framework/AnalyticModels/AnalyticCodes/variable_time.py
index 604cfd7a1c..5bca93ed92 100644
--- a/tests/framework/AnalyticModels/AnalyticCodes/variable_time.py
+++ b/tests/framework/AnalyticModels/AnalyticCodes/variable_time.py
@@ -82,7 +82,7 @@ def write(xs,ys,zs,ts,a,b,c,outname):
@ In, Outname, string, name of output file
@ Out, None
"""
- out = file(outname+'.csv','w')
+ out = open(outname+'.csv','w')
out.writelines('t,x,y,z,xt,yt,zt,a,b,c\n')
for i in range(len(ts)):
out.writelines(','.join('%1.15e' %s for s in [ts[i],xs[0],ys[0],zs[0],xs[i],ys[i],zs[i],a[i],b[i],c[i]])+'\n')
@@ -95,7 +95,7 @@ def write(xs,ys,zs,ts,a,b,c,outname):
raise IOError('No output file was specified with "-o"!')
if len(sys.argv)<5:
raise IOError('Insufficient arguments! Need -i Input -o Output')
- inFile = file(sys.argv[2],'r')
+ inFile = open(sys.argv[2],'r')
x,y,z = readInput(inFile)
xs,ys,zs,a,b,c,ts = run(x,y,z)
write(xs,ys,zs,ts,a,b,c,sys.argv[4])
diff --git a/tests/framework/CodeInterfaceTests/GenericInterfaceIO/poly_inp_io.py b/tests/framework/CodeInterfaceTests/GenericInterfaceIO/poly_inp_io.py
index 04c5371a35..9f68ac57b6 100644
--- a/tests/framework/CodeInterfaceTests/GenericInterfaceIO/poly_inp_io.py
+++ b/tests/framework/CodeInterfaceTests/GenericInterfaceIO/poly_inp_io.py
@@ -23,7 +23,7 @@ def eval(x,y):
return dat
def run(xin):
- inx = file(xin,'r')
+ inx = open(xin,'r')
for line in inx:
if line.startswith('x =' ):
x=float(line.split('=')[1])
@@ -31,14 +31,14 @@ def run(xin):
case=line.split('=')[1].strip()
elif line.startswith('auxfile ='):
aux=line.split('=')[1].strip()
- iny = file(aux,'r')
+ iny = open(aux,'r')
for line in iny:
if line.startswith('y ='):
y=float(line.split('=')[1])
dat = eval(x,y)
- outf = file(case+'.csv','w')
+ outf = open(case+'.csv','w')
outf.writelines('step,i,j,x,y,poly\n')
for e in dat:
outf.writelines(','.join(str(i) for i in e)+'\n')
diff --git a/tests/framework/CodeInterfaceTests/GenericInterfaceIOCustomOutput/poly_inp_io.py b/tests/framework/CodeInterfaceTests/GenericInterfaceIOCustomOutput/poly_inp_io.py
index 526eb6dc42..bd54a44d04 100644
--- a/tests/framework/CodeInterfaceTests/GenericInterfaceIOCustomOutput/poly_inp_io.py
+++ b/tests/framework/CodeInterfaceTests/GenericInterfaceIOCustomOutput/poly_inp_io.py
@@ -23,7 +23,7 @@ def eval(x,y):
return dat
def run(xin):
- inx = file(xin,'r')
+ inx = open(xin,'r')
for line in inx:
if line.startswith('x =' ):
x=float(line.split('=')[1])
@@ -31,14 +31,14 @@ def run(xin):
case=line.split('=')[1].strip()
elif line.startswith('auxfile ='):
aux=line.split('=')[1].strip()
- iny = file(aux,'r')
+ iny = open(aux,'r')
for line in iny:
if line.startswith('y ='):
y=float(line.split('=')[1])
dat = eval(x,y)
# here we simulate the hardcoded output file
- outf = file('fixed_output'+'.csv','w')
+ outf = open('fixed_output'+'.csv','w')
outf.writelines('step,i,j,x,y,poly\n')
for e in dat:
outf.writelines(','.join(str(i) for i in e)+'\n')
diff --git a/tests/framework/OutStreams/gold/IO_ROM_PICKLE/PrintData.csv b/tests/framework/OutStreams/IO_ROM_PICKLE_gold/PrintData.csv
similarity index 100%
rename from tests/framework/OutStreams/gold/IO_ROM_PICKLE/PrintData.csv
rename to tests/framework/OutStreams/IO_ROM_PICKLE_gold/PrintData.csv
diff --git a/tests/framework/OutStreams/gold/IO_ROM_PICKLE/PrintData_Pickle.csv b/tests/framework/OutStreams/IO_ROM_PICKLE_gold/PrintData_Pickle.csv
similarity index 100%
rename from tests/framework/OutStreams/gold/IO_ROM_PICKLE/PrintData_Pickle.csv
rename to tests/framework/OutStreams/IO_ROM_PICKLE_gold/PrintData_Pickle.csv
diff --git a/tests/framework/OutStreams/tests b/tests/framework/OutStreams/tests
index 8e538f2eb8..6169d9ec05 100644
--- a/tests/framework/OutStreams/tests
+++ b/tests/framework/OutStreams/tests
@@ -3,8 +3,11 @@
type = 'RavenFramework'
input = 'imageGeneration_ps.xml'
output = 'plot/1-test_scatter.ps'
- text = 'plot/1-test_scatter.ps'
- comment = '%'
+ [./text_test]
+ type = Text
+ output = 'plot/1-test_scatter.ps'
+ comment = '%'
+ [../]
minimum_library_versions = 'matplotlib 2.0'
[../]
@@ -50,7 +53,11 @@
[./io_ROM_pickle]
type = 'RavenFramework'
input = 'test_io_ROM_pickle.xml'
- csv = 'IO_ROM_PICKLE/PrintData_Pickle.csv IO_ROM_PICKLE/PrintData.csv'
+ [./csv]
+ type = OrderedCSV
+ output = 'IO_ROM_PICKLE/PrintData_Pickle.csv IO_ROM_PICKLE/PrintData.csv'
+ gold_files = 'IO_ROM_PICKLE_gold/PrintData_Pickle.csv IO_ROM_PICKLE_gold/PrintData.csv'
+ [../]
[../]
[./legend]
diff --git a/tests/framework/PostProcessors/DataMiningPostProcessor/DimensionalityReduction/tests b/tests/framework/PostProcessors/DataMiningPostProcessor/DimensionalityReduction/tests
index 42cd0168b5..8bfe9fb7b6 100644
--- a/tests/framework/PostProcessors/DataMiningPostProcessor/DimensionalityReduction/tests
+++ b/tests/framework/PostProcessors/DataMiningPostProcessor/DimensionalityReduction/tests
@@ -20,12 +20,14 @@
type = 'RavenFramework'
input = 'test_dataMiningRandomizedPCA.xml'
csv = 'RandomizedPCA/dummy.csv'
+ rel_err = 1.0e-7
output = 'RandomizedPCA/1-PlotIris_dataMining.png'
[../]
[./KernelPCA]
type = 'RavenFramework'
input = 'test_dataMiningKernelPCA.xml'
csv = 'KernelPCA/dummy.csv'
+ rel_err = 1.0e-7
output = 'KernelPCA/1-PlotIris_dataMining.png'
[../]
[./SparsePCA]
@@ -48,6 +50,7 @@
type = 'RavenFramework'
input = 'test_dataMiningTruncatedSVD.xml'
csv = 'TruncatedSVD/dummy.csv'
+ rel_err = 1.0e-7
output = 'TruncatedSVD/1-PlotIris_dataMining.png'
[../]
[./FastICA]
diff --git a/tests/framework/PostProcessors/LimitSurface/tests b/tests/framework/PostProcessors/LimitSurface/tests
index 31d7c49f68..cadc0c504e 100644
--- a/tests/framework/PostProcessors/LimitSurface/tests
+++ b/tests/framework/PostProcessors/LimitSurface/tests
@@ -6,7 +6,7 @@
csv = 'limitSurface/LimitSurfaceNegative_dump.csv limitSurface/LimitSurfacePositiveNegative_dump.csv limitSurface/LimitSurfacePositive_dump.csv'
max_time = 300
rel_err = 0.0001
- #skip = ‘need to be fixed’
+ #skip = 'need to be fixed'
[../]
[./testLimitSurfaceIntegralPP]
@@ -16,7 +16,7 @@
csv = 'limitSurface_integral/LimitSurfaceWeightedPb_dump.csv limitSurface_integral/LimitSurfaceUnWeightedPb_dump.csv'
max_time = 300
rel_err = 0.001
- #skip = ‘need to be fixed’
+ #skip = 'need to be fixed'
[../]
[./testLimitSurfacePostProcessorWithRegressor]
diff --git a/tests/framework/PostProcessors/TopologicalPostProcessor/tests b/tests/framework/PostProcessors/TopologicalPostProcessor/tests
index fbcf2c805b..d8488ef203 100644
--- a/tests/framework/PostProcessors/TopologicalPostProcessor/tests
+++ b/tests/framework/PostProcessors/TopologicalPostProcessor/tests
@@ -5,6 +5,7 @@
csv = 'data/myDump1.csv data/myDump2.csv data/myDump3.csv data/myDump4.csv'
output = 'data/myDump1.xml data/myDump2.xml data/myDump3.xml data/myDump4.xml'
required_libraries = 'AMSC'
+ rel_err = 1.0e-5
python3_only = true
[../]
diff --git a/tests/framework/ROM/SKLearn/tests b/tests/framework/ROM/SKLearn/tests
index e39381d6ac..5a2613001a 100644
--- a/tests/framework/ROM/SKLearn/tests
+++ b/tests/framework/ROM/SKLearn/tests
@@ -147,6 +147,7 @@
input = 'gp.xml'
csv = 'data/outGP.csv'
output = 'data/outGP.xml'
+ rel_err = 1.0e-6
[../]
[./linearARD]
type = 'RavenFramework'
@@ -285,6 +286,7 @@
input = 'mlpRegressor.xml'
csv = 'data/outMLPRegressor.csv'
output = 'data/outMLPRegressor.xml'
+ rel_err = 1.0e-8
[../]
##############################################################################
## Inconsistent Results
diff --git a/tests/framework/ROM/TimeSeries/ARMA/gold/SingleFourier/synthetic_0.csv b/tests/framework/ROM/TimeSeries/ARMA/gold/SingleFourier/synthetic_0.csv
index 93a1f91db4..f09fff107f 100644
--- a/tests/framework/ROM/TimeSeries/ARMA/gold/SingleFourier/synthetic_0.csv
+++ b/tests/framework/ROM/TimeSeries/ARMA/gold/SingleFourier/synthetic_0.csv
@@ -1,2018 +1,2018 @@
Time,Speed
-0.0,9.00612724586
-600.0,9.33657454279
-1200.0,8.90299811297
-1800.0,9.57394849506
-2400.0,9.54820099652
-3000.0,9.36682318291
-3600.0,9.56623964673
-4200.0,9.28295661818
-4800.0,9.51254926225
-5400.0,10.1624814781
-6000.0,10.3254732019
-6600.0,10.895546294
-7200.0,10.8166654199
-7800.0,11.1260981425
-8400.0,11.4878779464
-9000.0,11.4577836279
-9600.0,12.7486094696
-10200.0,12.8217322411
-10800.0,14.6926217594
-11400.0,15.2246032978
-12000.0,16.0564317465
-12600.0,15.276040021
-13200.0,15.6281544126
-13800.0,15.9092381225
-14400.0,15.7484557954
-15000.0,15.5527512271
-15600.0,14.9301078757
-16200.0,14.4257081483
-16800.0,14.0056834361
-17400.0,13.1452132307
-18000.0,14.2050755135
-18600.0,14.1455848123
-19200.0,14.43092749
-19800.0,14.891552566
-20400.0,15.008790285
-21000.0,15.7691541958
-21600.0,14.9865391832
-22200.0,15.3024851415
-22800.0,15.0901924473
-23400.0,15.489868355
-24000.0,14.9512127692
-24600.0,14.8530399944
-25200.0,16.8236537257
-25800.0,16.9856083792
-26400.0,17.0609314578
-27000.0,16.9297457084
-27600.0,15.963538533
-28200.0,15.8888072523
-28800.0,16.3284405068
-29400.0,16.9052081752
-30000.0,16.8770419848
-30600.0,16.7990863786
-31200.0,17.0744999137
-31800.0,16.8291992955
-32400.0,16.797016816
-33000.0,16.5785447039
-33600.0,16.5560500976
-34200.0,16.4421811638
-34800.0,16.2695422788
-35400.0,16.5781655107
-36000.0,16.6570438889
-36600.0,16.5254535154
-37200.0,16.5328872477
-37800.0,16.3148273933
-38400.0,16.1302256466
-39000.0,15.7352029468
-39600.0,15.8068954988
-40200.0,15.3462491685
-40800.0,15.4857558399
-41400.0,15.7592200041
-42000.0,15.0125662922
-42600.0,14.930844742
-43200.0,14.030773239
-43800.0,14.1805242359
-44400.0,13.9598792024
-45000.0,14.3540212692
-45600.0,14.1372757826
-46200.0,13.9162196534
-46800.0,13.5198276679
-47400.0,13.3638255363
-48000.0,12.3803404713
-48600.0,11.0330961917
-49200.0,10.9731033174
-49800.0,10.6940477534
-50400.0,11.1534623264
-51000.0,11.3725698397
-51600.0,10.5373846387
-52200.0,10.8615249725
-52800.0,10.2423519604
-53400.0,10.1842390247
-54000.0,9.52335684065
-54600.0,8.44230006783
-55200.0,7.88361202398
-55800.0,8.03100598126
-56400.0,9.00729979746
-57000.0,9.10307453195
-57600.0,9.23200872354
-58200.0,9.52890257432
-58800.0,9.38941291572
-59400.0,9.05936333959
-60000.0,9.68125909878
-60600.0,9.61554679703
-61200.0,8.93408018532
-61800.0,9.52545296913
-62400.0,9.39684133261
-63000.0,9.10911883816
-63600.0,8.84723901952
-64200.0,8.19847680232
-64800.0,8.08260468001
-65400.0,8.64244952958
-66000.0,9.0888149786
-66600.0,8.36075241322
-67200.0,9.09619472573
-67800.0,8.39385033655
-68400.0,8.50657624061
-69000.0,9.01761552483
-69600.0,9.25230956955
-70200.0,10.3491262868
-70800.0,10.496817908
-71400.0,11.3732140458
-72000.0,11.7617277245
-72600.0,11.7028036718
-73200.0,11.9043071299
-73800.0,11.8212160939
-74400.0,12.6360197307
-75000.0,12.7280427039
-75600.0,12.8489563485
-76200.0,12.4881203064
-76800.0,11.9813346023
-77400.0,12.0961848613
-78000.0,12.6168612328
-78600.0,12.022476579
-79200.0,12.0098894607
-79800.0,12.170529263
-80400.0,12.0218431569
-81000.0,12.8012259105
-81600.0,12.4923535302
-82200.0,11.7567491447
-82800.0,11.5722245105
-83400.0,10.2304581127
-84000.0,12.3091265243
-84600.0,12.153872922
-85200.0,13.1708372782
-85800.0,12.4714371082
-86400.0,12.101241895
-87000.0,12.6335036321
-87600.0,12.772673056
-88200.0,13.6082452402
-88800.0,14.1893432874
-89400.0,13.9768344167
-90000.0,14.0348599606
-90600.0,12.9958938407
-91200.0,13.7229743438
-91800.0,12.8890256046
-92400.0,12.9919548036
-93000.0,13.0946199407
-93600.0,13.2771596666
-94200.0,12.4955543822
-94800.0,12.5326934128
-95400.0,11.3147467198
-96000.0,11.7451581156
-96600.0,10.7652671861
-97200.0,11.2644135857
-97800.0,10.7781510654
-98400.0,11.6644362888
-99000.0,12.3040187394
-99600.0,12.2143324053
-100200.0,12.4809010644
-100800.0,12.3174768672
-101400.0,12.3590289715
-102000.0,11.9220524806
-102600.0,11.5622457416
-103200.0,12.144824474
-103800.0,11.6140526013
-104400.0,12.393096879
-105000.0,11.3214073589
-105600.0,11.8375126603
-106200.0,11.0787387699
-106800.0,11.2660186941
-107400.0,11.8464267087
-108000.0,11.8485690085
-108600.0,12.1660258884
-109200.0,12.4933041196
-109800.0,13.4705171081
-110400.0,11.3580543301
-111000.0,11.5647588413
-111600.0,10.7430375323
-112200.0,10.4261234907
-112800.0,11.0911650109
-113400.0,11.1390884552
-114000.0,11.7428854612
-114600.0,11.3322619125
-115200.0,11.4899660626
-115800.0,11.8034522008
-116400.0,11.4337235209
-117000.0,11.356809653
-117600.0,10.2881826588
-118200.0,10.9452732937
-118800.0,9.95688857516
-119400.0,11.1093349812
-120000.0,10.9200302314
-120600.0,10.5429435815
-121200.0,10.4171436227
-121800.0,10.253067427
-122400.0,9.46206457608
-123000.0,8.95245022614
-123600.0,8.30721621972
-124200.0,8.03156189816
-124800.0,6.08835732336
-125400.0,6.08462243664
-126000.0,7.01678743002
-126600.0,6.17432773517
-127200.0,6.49198833962
-127800.0,6.07108241996
-128400.0,6.04419091657
-129000.0,4.86476110075
-129600.0,5.88015779988
-130200.0,6.10849275347
-130800.0,5.68972033629
-131400.0,6.66577012322
-132000.0,7.85348502512
-132600.0,7.82182905717
-133200.0,7.60997738624
-133800.0,6.6083149115
-134400.0,6.6127516645
-135000.0,7.43031669039
-135600.0,7.49371498827
-136200.0,6.44753688815
-136800.0,6.96944503086
-137400.0,8.2548549579
-138000.0,9.10754741328
-138600.0,9.54667012065
-139200.0,9.5665864485
-139800.0,8.76003772553
-140400.0,9.51197998183
-141000.0,8.96003231487
-141600.0,8.4292006755
-142200.0,7.69097801013
-142800.0,6.95222428227
-143400.0,6.83008348964
-144000.0,6.48866530082
-144600.0,7.29228899494
-145200.0,7.68043297245
-145800.0,7.56033521096
-146400.0,9.83307947378
-147000.0,9.33228964248
-147600.0,9.03472622008
-148200.0,7.8074767136
-148800.0,7.13309812814
-149400.0,7.54424589946
-150000.0,7.72886313536
-150600.0,8.81533548231
-151200.0,8.86002592911
-151800.0,9.64308134171
-152400.0,9.18947069838
-153000.0,9.0207152114
-153600.0,9.89028984343
-154200.0,10.1759758532
-154800.0,9.57832578235
-155400.0,8.81280631819
-156000.0,8.45748411177
-156600.0,7.8749317422
-157200.0,8.38046157249
-157800.0,8.47517603257
-158400.0,7.96163256343
-159000.0,7.81882964595
-159600.0,7.74664299929
-160200.0,8.31817175663
-160800.0,8.4085983305
-161400.0,7.83810977822
-162000.0,7.99861022007
-162600.0,7.91615833236
-163200.0,8.9607558754
-163800.0,8.56670815251
-164400.0,8.97896981509
-165000.0,9.68300177967
-165600.0,9.39960944516
-166200.0,8.72726745032
-166800.0,9.03252108793
-167400.0,8.57647364585
-168000.0,8.85622962481
-168600.0,9.11381281236
-169200.0,8.83467510834
-169800.0,9.41297670208
-170400.0,9.4072690533
-171000.0,8.54145828568
-171600.0,9.23232791302
-172200.0,8.65685170571
-172800.0,9.06087484777
-173400.0,9.17495996553
-174000.0,9.49295913411
-174600.0,10.6185292616
-175200.0,9.91864784556
-175800.0,10.9759194917
-176400.0,10.9637500598
-177000.0,11.1346811592
-177600.0,12.6180109248
-178200.0,12.9476730034
-178800.0,11.1739246847
-179400.0,13.289370682
-180000.0,13.3562413083
-180600.0,13.3879343947
-181200.0,12.9683448795
-181800.0,13.6107241338
-182400.0,13.1980096259
-183000.0,13.4261587976
-183600.0,12.8442331672
-184200.0,12.199442834
-184800.0,11.6075409761
-185400.0,11.9457743543
-186000.0,12.2474468918
-186600.0,13.9510681624
-187200.0,14.7439966116
-187800.0,13.3009872361
-188400.0,13.3429156249
-189000.0,12.5274985413
-189600.0,14.0228979742
-190200.0,13.9584950689
-190800.0,14.6469943376
-191400.0,13.8901504316
-192000.0,14.4345279109
-192600.0,15.4983712547
-193200.0,15.5328033876
-193800.0,15.111992466
-194400.0,15.104458913
-195000.0,15.7563898809
-195600.0,14.8937943961
-196200.0,14.5409324374
-196800.0,14.8674618602
-197400.0,15.1296532269
-198000.0,15.4407051341
-198600.0,14.9243030408
-199200.0,14.2353211726
-199800.0,14.7901418533
-200400.0,15.4155845931
-201000.0,15.2967782459
-201600.0,14.6195629875
-202200.0,15.5320764079
-202800.0,14.919674352
-203400.0,14.1603433357
-204000.0,13.8633745367
-204600.0,13.7025565921
-205200.0,13.702154177
-205800.0,12.0395423078
-206400.0,12.7507811884
-207000.0,11.6463173378
-207600.0,11.2268260351
-208200.0,10.4141732973
-208800.0,10.9371525805
-209400.0,10.8508254017
-210000.0,11.5674138447
-210600.0,11.3414011718
-211200.0,13.5680288596
-211800.0,12.5985484822
-212400.0,11.7972398984
-213000.0,12.665889193
-213600.0,12.8327421607
-214200.0,12.5030202101
-214800.0,12.8036267129
-215400.0,11.2330613398
-216000.0,12.0782780149
-216600.0,10.6321381124
-217200.0,10.6388304883
-217800.0,10.4748253961
-218400.0,10.9243591977
-219000.0,10.8643687186
-219600.0,10.9810747806
-220200.0,10.1265704715
-220800.0,10.814370109
-221400.0,11.1936228768
-222000.0,11.6900310003
-222600.0,11.8066393795
-223200.0,13.0003333277
-223800.0,12.8335172833
-224400.0,11.5698817578
-225000.0,10.4838314121
-225600.0,9.9868145095
-226200.0,9.53958536078
-226800.0,9.54559242254
-227400.0,9.76217304886
-228000.0,9.71273187986
-228600.0,7.83938260861
-229200.0,7.90630521906
-229800.0,8.05224159361
-230400.0,7.44105239578
-231000.0,6.94762274096
-231600.0,7.4584123698
-232200.0,6.15990775721
-232800.0,5.74628130482
-233400.0,5.61906288434
-234000.0,5.91122754163
-234600.0,5.38748466563
-235200.0,4.54068989216
-235800.0,3.92940487476
-236400.0,4.16077746334
-237000.0,3.3868535384
-237600.0,2.70816190908
-238200.0,1.78009766564
-238800.0,2.13599706748
-239400.0,2.19023017178
-240000.0,2.42095912246
-240600.0,2.75086759739
-241200.0,3.77607424135
-241800.0,3.75651178408
-242400.0,4.08335427114
-243000.0,3.7019646155
-243600.0,3.69782483449
-244200.0,4.21035319742
-244800.0,2.50559053327
-245400.0,3.82290880484
-246000.0,2.45258805383
-246600.0,2.77412328538
-247200.0,2.2877721619
-247800.0,1.62147100078
-248400.0,1.45900135756
-249000.0,1.51686366609
-249600.0,2.02650603317
-250200.0,1.84652261399
-250800.0,2.36938925609
-251400.0,2.24785339115
-252000.0,2.9293380369
-252600.0,3.93223350976
-253200.0,3.41475213652
-253800.0,3.750911517
-254400.0,4.16907639624
-255000.0,4.68286142133
-255600.0,4.25009739035
-256200.0,5.24046289088
-256800.0,5.04670623499
-257400.0,3.99096945722
-258000.0,4.88004227338
-258600.0,5.51132994243
-259200.0,5.26353560518
-259800.0,5.11848366144
-260400.0,5.10352199249
-261000.0,4.91800878554
-261600.0,5.09310497857
-262200.0,5.02765522193
-262800.0,5.9535212579
-263400.0,5.80743005246
-264000.0,6.13115708609
-264600.0,4.82271915297
-265200.0,5.39558388882
-265800.0,4.45538711659
-266400.0,5.2725745739
-267000.0,5.25473338408
-267600.0,5.26738106031
-268200.0,6.54767710807
-268800.0,7.30005124436
-269400.0,8.08521515232
-270000.0,8.05270441003
-270600.0,9.04344387081
-271200.0,9.73205823018
-271800.0,10.2100115464
-272400.0,9.22413625667
-273000.0,8.99907617799
-273600.0,9.66504262486
-274200.0,8.67756588585
-274800.0,9.98742659829
-275400.0,10.8777987991
-276000.0,10.8232203196
-276600.0,10.7702162151
-277200.0,10.2605742908
-277800.0,9.30666967385
-278400.0,9.19213433893
-279000.0,9.29509879993
-279600.0,9.39343608496
-280200.0,10.2245784021
-280800.0,10.157027357
-281400.0,10.1612896636
-282000.0,9.39195847363
-282600.0,8.92602874475
-283200.0,8.52950099428
-283800.0,7.01971646348
-284400.0,8.29299612075
-285000.0,8.52128436449
-285600.0,8.05808161798
-286200.0,6.6313776709
-286800.0,7.2277861459
-287400.0,7.39973642802
-288000.0,7.18314407586
-288600.0,6.46024225204
-289200.0,6.25552953697
-289800.0,5.31556329292
-290400.0,5.45629848293
-291000.0,5.43230510988
-291600.0,5.0359567784
-292200.0,5.46260496996
-292800.0,4.66739585927
-293400.0,4.46294907599
-294000.0,4.16203425595
-294600.0,4.23602344748
-295200.0,4.24255859786
-295800.0,5.62430020291
-296400.0,5.90661529213
-297000.0,6.92559677053
-297600.0,6.75798060001
-298200.0,6.71026831232
-298800.0,6.22898255789
-299400.0,5.95383157086
-300000.0,6.89290494222
-300600.0,8.57007714391
-301200.0,7.45056998475
-301800.0,6.42136600785
-302400.0,6.75322664464
-303000.0,5.49953240075
-303600.0,4.95929557615
-304200.0,6.33333972605
-304800.0,5.02192728297
-305400.0,4.78461505163
-306000.0,5.39459088477
-306600.0,5.52422938111
-307200.0,5.8491085534
-307800.0,6.31153585314
-308400.0,6.72539047035
-309000.0,6.97666843152
-309600.0,8.07810344603
-310200.0,7.91249105378
-310800.0,9.53741405078
-311400.0,9.02588686114
-312000.0,9.15861469028
-312600.0,9.37456884273
-313200.0,9.44275492603
-313800.0,9.94651207633
-314400.0,9.9511633505
-315000.0,10.1200082053
-315600.0,10.3073898154
-316200.0,10.1255411313
-316800.0,10.859805702
-317400.0,11.473912889
-318000.0,13.0323598102
-318600.0,12.7414376118
-319200.0,13.533169425
-319800.0,14.0306758794
-320400.0,14.2355656463
-321000.0,13.2568016914
-321600.0,13.5063663703
-322200.0,12.3465096277
-322800.0,12.5342819015
-323400.0,10.7358838886
-324000.0,10.5315398556
-324600.0,10.9204604464
-325200.0,9.9559140322
-325800.0,8.9864816291
-326400.0,10.2518363723
-327000.0,10.0795890243
-327600.0,11.497377622
-328200.0,11.5386863453
-328800.0,12.2933581687
-329400.0,12.2455148204
-330000.0,11.6752445402
-330600.0,11.714780724
-331200.0,12.5058817027
-331800.0,12.3530030702
-332400.0,11.842814871
-333000.0,11.5686050515
-333600.0,11.8636581139
-334200.0,11.5085598819
-334800.0,11.7861920284
-335400.0,11.6632943929
-336000.0,12.2679037565
-336600.0,12.7896819967
-337200.0,13.2533209673
-337800.0,14.1886788208
-338400.0,14.3112901291
-339000.0,14.3331121218
-339600.0,13.9516113075
-340200.0,13.4057749336
-340800.0,12.6226328313
-341400.0,12.2194786914
-342000.0,11.3450574418
-342600.0,11.1240545587
-343200.0,9.39962116782
-343800.0,9.49534887494
-344400.0,9.58984787271
-345000.0,8.99887918709
-345600.0,8.75606236268
-346200.0,8.75011526401
-346800.0,9.4236564395
-347400.0,9.55517098077
-348000.0,10.0807529087
-348600.0,10.786775138
-349200.0,10.5352533122
-349800.0,10.9999118142
-350400.0,11.691489715
-351000.0,11.6445852283
-351600.0,10.8693760392
-352200.0,12.0114480851
-352800.0,10.5003916293
-353400.0,9.64419452337
-354000.0,9.32092848442
-354600.0,8.85760729347
-355200.0,9.42594721473
-355800.0,10.3039854466
-356400.0,9.55597517698
-357000.0,9.12568540718
-357600.0,9.35334512019
-358200.0,9.82245247029
-358800.0,9.27656197475
-359400.0,9.12246148852
-360000.0,11.0947434394
-360600.0,11.2379041975
-361200.0,12.132213369
-361800.0,12.4045556887
-362400.0,11.9465370773
-363000.0,13.5412259557
-363600.0,12.6834689632
-364200.0,11.3185715531
-364800.0,11.4499344272
-365400.0,11.8469276022
-366000.0,11.8970721991
-366600.0,11.6095148323
-367200.0,11.3190868877
-367800.0,11.3516521289
-368400.0,11.3089715782
-369000.0,11.5213453792
-369600.0,11.1801332374
-370200.0,10.5676646301
-370800.0,10.5660511661
-371400.0,10.8215151212
-372000.0,10.2045400218
-372600.0,11.0897096605
-373200.0,11.3062250311
-373800.0,10.1243265743
-374400.0,9.11212112556
-375000.0,9.4756367342
-375600.0,9.54157868357
-376200.0,8.82786833372
-376800.0,10.3982994775
-377400.0,9.89786086449
-378000.0,9.77400127275
-378600.0,9.61696821833
-379200.0,10.6514635933
-379800.0,9.42291402955
-380400.0,10.0441610327
-381000.0,8.80210949273
-381600.0,7.09299802327
-382200.0,6.19324091944
-382800.0,7.37963508187
-383400.0,7.16690272372
-384000.0,7.708035301
-384600.0,7.53582314413
-385200.0,6.89784748993
-385800.0,6.67381108959
-386400.0,6.22953471395
-387000.0,5.66977646712
-387600.0,6.70561773895
-388200.0,6.04108838562
-388800.0,5.81124302995
-389400.0,5.48099821399
-390000.0,5.68473887842
-390600.0,5.13954011616
-391200.0,4.29800538156
-391800.0,4.3621103847
-392400.0,4.78969014753
-393000.0,4.79407016574
-393600.0,5.35759692764
-394200.0,4.22882977311
-394800.0,4.65135141024
-395400.0,6.34674662625
-396000.0,5.49557025046
-396600.0,4.17232717408
-397200.0,4.7356873883
-397800.0,5.47181855639
-398400.0,5.63919658827
-399000.0,5.64721608511
-399600.0,5.76544612159
-400200.0,7.00241335678
-400800.0,7.28493997652
-401400.0,7.07751814909
-402000.0,7.76208837484
-402600.0,7.23173166208
-403200.0,8.05791361883
-403800.0,7.69356006203
-404400.0,7.67974838965
-405000.0,7.57981617156
-405600.0,6.53372115461
-406200.0,7.33425031293
-406800.0,6.48393678029
-407400.0,6.43608644522
-408000.0,6.09078565433
-408600.0,5.83443188935
-409200.0,6.63079251696
-409800.0,7.4653002743
-410400.0,6.80636455387
-411000.0,7.79213471258
-411600.0,7.39788095678
-412200.0,7.15036720607
-412800.0,6.33956909195
-413400.0,6.54655810961
-414000.0,4.82431484625
-414600.0,4.16222659031
-415200.0,4.79159203792
-415800.0,5.86808137788
-416400.0,6.02703643682
-417000.0,6.76450267993
-417600.0,6.7007669881
-418200.0,7.45037675992
-418800.0,8.07506882031
-419400.0,7.3508226133
-420000.0,8.64305351464
-420600.0,7.61192518859
-421200.0,7.78559233398
-421800.0,6.79979972614
-422400.0,7.29331333243
-423000.0,6.39958201493
-423600.0,5.961466139
-424200.0,5.92222230043
-424800.0,6.77802080394
-425400.0,6.2538033894
-426000.0,6.22470742975
-426600.0,7.01809542768
-427200.0,7.86776680082
-427800.0,8.75563949593
-428400.0,9.26971906179
-429000.0,8.81681080733
-429600.0,9.46087761602
-430200.0,9.22543046479
-430800.0,8.80405841161
-431400.0,9.50444408304
-432000.0,9.77364435172
-432600.0,9.55833889001
-433200.0,8.83307259554
-433800.0,8.70660274132
-434400.0,9.41736635433
-435000.0,9.58123644187
-435600.0,9.48846149833
-436200.0,9.54687392372
-436800.0,8.65165040781
-437400.0,8.96035141313
-438000.0,9.79859501129
-438600.0,9.56946824477
-439200.0,9.42418073864
-439800.0,9.70645040712
-440400.0,9.85300548562
-441000.0,9.75529664492
-441600.0,9.72314810043
-442200.0,9.94423622455
-442800.0,10.0612601569
-443400.0,8.91630014503
-444000.0,9.2865840159
-444600.0,9.24000907351
-445200.0,9.39639821812
-445800.0,10.1526302603
-446400.0,9.66472111445
-447000.0,9.93460785007
-447600.0,10.9426503616
-448200.0,9.45500972472
-448800.0,10.7179406118
-449400.0,12.0048446139
-450000.0,12.9761796531
-450600.0,12.6757172563
-451200.0,12.1295251587
-451800.0,11.4416507787
-452400.0,12.502011615
-453000.0,12.8698017776
-453600.0,13.0343910401
-454200.0,14.0919909321
-454800.0,14.4761566014
-455400.0,15.6156358507
-456000.0,14.7070052802
-456600.0,14.0843192803
-457200.0,14.2265484783
-457800.0,14.4958771671
-458400.0,15.2915599435
-459000.0,15.4016408592
-459600.0,14.2916776536
-460200.0,14.1614661982
-460800.0,12.6183374999
-461400.0,14.2176955698
-462000.0,14.1904974956
-462600.0,14.4085386249
-463200.0,15.2548007245
-463800.0,14.1241134248
-464400.0,13.780159685
-465000.0,14.0557795633
-465600.0,14.5007666909
-466200.0,14.3799875951
-466800.0,15.458481905
-467400.0,15.102780033
-468000.0,15.6980740701
-468600.0,14.4739356573
-469200.0,14.9905952341
-469800.0,15.0885333041
-470400.0,15.0437460355
-471000.0,15.0856066998
-471600.0,15.4171600191
-472200.0,15.894754231
-472800.0,16.4854121743
-473400.0,16.4966312216
-474000.0,16.4847587605
-474600.0,16.4569609755
-475200.0,16.3782949811
-475800.0,16.3506169253
-476400.0,15.2799086464
-477000.0,15.5781288741
-477600.0,16.1232248807
-478200.0,16.112548987
-478800.0,16.0686772735
-479400.0,16.3257971395
-480000.0,16.2530712104
-480600.0,16.0399824819
-481200.0,16.0211546869
-481800.0,15.9187085466
-482400.0,15.7274729312
-483000.0,15.2157415654
-483600.0,15.762596783
-484200.0,16.0596138374
-484800.0,16.0434923894
-485400.0,15.8907261903
-486000.0,15.7713380545
-486600.0,15.1665174475
-487200.0,15.5306696774
-487800.0,15.5613398853
-488400.0,14.8426324728
-489000.0,14.6503163528
-489600.0,15.0787314657
-490200.0,14.7585205469
-490800.0,15.4593107409
-491400.0,15.3987930742
-492000.0,15.1003779975
-492600.0,14.4683910724
-493200.0,14.1831235626
-493800.0,14.7672358181
-494400.0,14.8448838173
-495000.0,14.7286300335
-495600.0,13.9732261545
-496200.0,14.4450158052
-496800.0,14.2731595349
-497400.0,13.9928038483
-498000.0,12.8698290525
-498600.0,13.3488288447
-499200.0,13.7268888798
-499800.0,14.0139369671
-500400.0,12.3961666613
-501000.0,13.0210532091
-501600.0,13.0679532175
-502200.0,12.7225172141
-502800.0,11.3455212535
-503400.0,11.6289814161
-504000.0,11.4681742255
-504600.0,11.7189760072
-505200.0,12.0686457068
-505800.0,11.5698032862
-506400.0,12.2611538163
-507000.0,11.8563850155
-507600.0,12.8462314793
-508200.0,12.8064031694
-508800.0,11.9136107551
-509400.0,12.09587013
-510000.0,13.0436024821
-510600.0,12.7994745584
-511200.0,12.6384336815
-511800.0,13.2607381951
-512400.0,12.9447009131
-513000.0,13.7010559891
-513600.0,13.4814293325
-514200.0,13.5834691806
-514800.0,13.4920658267
-515400.0,13.4268249056
-516000.0,12.0804843355
-516600.0,11.1070343035
-517200.0,9.63642990177
-517800.0,10.1843931376
-518400.0,10.0908059068
-519000.0,10.4464657912
-519600.0,12.1814875744
-520200.0,12.5771652423
-520800.0,12.6174286978
-521400.0,11.5868272315
-522000.0,12.7817340296
-522600.0,12.5173080815
-523200.0,12.1660671043
-523800.0,10.5677994758
-524400.0,11.6014732614
-525000.0,11.166355081
-525600.0,10.7545142594
-526200.0,9.81426496881
-526800.0,9.01912646931
-527400.0,8.85798023106
-528000.0,8.36790101956
-528600.0,8.26422447143
-529200.0,9.08630003299
-529800.0,8.302537386
-530400.0,8.42600124114
-531000.0,8.44748876183
-531600.0,7.60916635804
-532200.0,7.65343274431
-532800.0,8.86245771415
-533400.0,9.02371319857
-534000.0,9.29027014328
-534600.0,9.16510325056
-535200.0,9.93837967311
-535800.0,10.4610466714
-536400.0,10.1198077057
-537000.0,10.4200629785
-537600.0,10.9029085258
-538200.0,10.8865098079
-538800.0,10.5916858962
-539400.0,10.692012269
-540000.0,11.0149361015
-540600.0,10.6770517502
-541200.0,10.6665749543
-541800.0,10.7748449969
-542400.0,11.6534414163
-543000.0,12.0944683406
-543600.0,11.8275553785
-544200.0,12.0112064546
-544800.0,11.5952556811
-545400.0,11.5161948297
-546000.0,11.3156012701
-546600.0,11.1705241255
-547200.0,10.6412328812
-547800.0,11.1220089374
-548400.0,10.7935938232
-549000.0,11.1046885395
-549600.0,10.649358977
-550200.0,10.4728236215
-550800.0,11.484937674
-551400.0,11.6910717244
-552000.0,11.6942560973
-552600.0,12.4206311794
-553200.0,11.158736714
-553800.0,10.8986908413
-554400.0,10.3351233205
-555000.0,10.5760792428
-555600.0,10.7157941511
-556200.0,11.2781024793
-556800.0,10.8731905599
-557400.0,10.929339041
-558000.0,10.838154547
-558600.0,12.1831565396
-559200.0,11.5072865978
-559800.0,11.6998328278
-560400.0,11.8526709462
-561000.0,11.1757345709
-561600.0,11.1983982898
-562200.0,11.845458097
-562800.0,11.1100472055
-563400.0,10.7519029672
-564000.0,10.9834273944
-564600.0,11.7717317016
-565200.0,12.4482737367
-565800.0,12.9052563754
-566400.0,13.0359391155
-567000.0,13.2958390148
-567600.0,13.1771127993
-568200.0,12.619949701
-568800.0,13.3552108533
-569400.0,13.4176850765
-570000.0,13.3894506131
-570600.0,12.7384153361
-571200.0,12.6931445401
-571800.0,12.3729448581
-572400.0,10.9396829371
-573000.0,11.3887053816
-573600.0,12.7002938491
-574200.0,10.7609664681
-574800.0,11.3092082798
-575400.0,11.6025511204
-576000.0,11.1360396547
-576600.0,12.6453286008
-577200.0,12.3747122597
-577800.0,10.1926417946
-578400.0,10.0640711492
-579000.0,9.22066283035
-579600.0,9.03081092986
-580200.0,9.05940208838
-580800.0,7.83524963351
-581400.0,8.95845074403
-582000.0,9.81552111055
-582600.0,10.419252145
-583200.0,9.8178175555
-583800.0,10.7797339733
-584400.0,9.96482486314
-585000.0,9.33058557312
-585600.0,9.17700924697
-586200.0,9.05176867009
-586800.0,9.2823843013
-587400.0,8.73659145725
-588000.0,8.52841985153
-588600.0,8.56389682186
-589200.0,8.67216218766
-589800.0,8.65208087358
-590400.0,8.85155953624
-591000.0,9.0524389999
-591600.0,9.20281304206
-592200.0,9.11620538365
-592800.0,8.95082584434
-593400.0,8.58300939602
-594000.0,8.98030008537
-594600.0,9.50669180024
-595200.0,9.21527252003
-595800.0,8.69342066958
-596400.0,8.67296505861
-597000.0,8.12437735349
-597600.0,8.94151199317
-598200.0,8.04742932806
-598800.0,7.76273001052
-599400.0,7.38448343927
-600000.0,7.87968886746
-600600.0,7.54395440939
-601200.0,7.08984587709
-601800.0,6.60420852309
-602400.0,7.14727580591
-603000.0,6.61770020402
-603600.0,6.9930646266
-604200.0,7.5500206219
-604800.0,7.7565637956
-605400.0,8.34996597329
-606000.0,7.64852787489
-606600.0,7.62947021992
-607200.0,7.37571063878
-607800.0,8.01535416072
-608400.0,6.78828528582
-609000.0,7.16975563497
-609600.0,7.00897789672
-610200.0,7.20754011797
-610800.0,8.2528134162
-611400.0,9.3319061625
-612000.0,8.77788094565
-612600.0,8.71300116868
-613200.0,8.14103524124
-613800.0,9.07850655184
-614400.0,8.44869355425
-615000.0,7.88201289554
-615600.0,9.23482504831
-616200.0,8.46890778522
-616800.0,8.92028446355
-617400.0,7.83486199861
-618000.0,8.39339226514
-618600.0,8.64958136327
-619200.0,8.40360204429
-619800.0,8.63457421904
-620400.0,9.61192077479
-621000.0,9.05323336233
-621600.0,8.68715601418
-622200.0,7.5016278959
-622800.0,6.99249812032
-623400.0,7.1294516309
-624000.0,7.32200403193
-624600.0,6.59862604735
-625200.0,5.29918452365
-625800.0,5.29014631233
-626400.0,5.36562853683
-627000.0,5.75601730029
-627600.0,5.80616702455
-628200.0,6.40101239697
-628800.0,7.08252970718
-629400.0,6.99923129249
-630000.0,6.18434309782
-630600.0,7.08036063647
-631200.0,7.14230350454
-631800.0,7.07212096879
-632400.0,7.24438855351
-633000.0,7.43387326176
-633600.0,7.51992721628
-634200.0,7.38742977395
-634800.0,7.77462416862
-635400.0,7.37681990054
-636000.0,7.17479409223
-636600.0,7.15207238687
-637200.0,7.04709492739
-637800.0,7.15077896506
-638400.0,7.53971420791
-639000.0,7.93197256236
-639600.0,7.67562720312
-640200.0,7.94741934773
-640800.0,8.63800959848
-641400.0,8.11539091416
-642000.0,8.10282995729
-642600.0,7.0319746955
-643200.0,6.95252791921
-643800.0,6.62031694894
-644400.0,6.5440877403
-645000.0,6.73141708188
-645600.0,6.19470329953
-646200.0,6.88292036989
-646800.0,7.75581592954
-647400.0,8.11768754912
-648000.0,8.56264702707
-648600.0,9.53701921025
-649200.0,9.88881935429
-649800.0,9.80954795414
-650400.0,10.6070475261
-651000.0,9.91863186957
-651600.0,9.99613757206
-652200.0,10.7187778689
-652800.0,9.72553174845
-653400.0,9.94941385419
-654000.0,10.7710226434
-654600.0,11.385723131
-655200.0,10.4843117595
-655800.0,10.8678228233
-656400.0,9.9078166365
-657000.0,9.81051885385
-657600.0,9.47468644405
-658200.0,10.4725466738
-658800.0,11.1618815845
-659400.0,11.3512240736
-660000.0,12.8458013606
-660600.0,11.4357584903
-661200.0,11.6306799461
-661800.0,10.5411053683
-662400.0,10.6404719075
-663000.0,10.9666168497
-663600.0,10.9006261344
-664200.0,11.7436691585
-664800.0,11.355034501
-665400.0,12.7494303633
-666000.0,12.2792841363
-666600.0,12.3659575753
-667200.0,13.2083344373
-667800.0,12.7376670965
-668400.0,13.9780871014
-669000.0,14.3418648508
-669600.0,14.7356911475
-670200.0,14.7509175682
-670800.0,14.5310053477
-671400.0,14.7903444696
-672000.0,14.7454631488
-672600.0,14.6871588941
-673200.0,14.6137146699
-673800.0,14.1469628671
-674400.0,14.4420430196
-675000.0,14.2133804408
-675600.0,14.1409033495
-676200.0,13.9271481105
-676800.0,14.0171555654
-677400.0,13.7076496491
-678000.0,13.1430585425
-678600.0,13.0025460357
-679200.0,13.0345292222
-679800.0,12.7274196324
-680400.0,11.8822006173
-681000.0,12.0066927743
-681600.0,12.1879310488
-682200.0,12.6300515982
-682800.0,11.8747363989
-683400.0,11.8340181795
-684000.0,11.4580023359
-684600.0,10.9348308092
-685200.0,10.1606047787
-685800.0,10.2232122347
-686400.0,9.88997818466
-687000.0,10.3010100119
-687600.0,10.0810274498
-688200.0,10.0015608124
-688800.0,9.8008484956
-689400.0,9.52815176748
-690000.0,9.76264592977
-690600.0,9.21772815386
-691200.0,10.8522712347
-691800.0,10.5418542211
-692400.0,10.9990121511
-693000.0,12.1341772191
-693600.0,12.8911792767
-694200.0,12.72532231
-694800.0,13.2637605195
-695400.0,11.669737743
-696000.0,11.2910950843
-696600.0,12.263895729
-697200.0,12.8253182823
-697800.0,13.2309681045
-698400.0,13.6750830794
-699000.0,13.4480505208
-699600.0,13.3850265455
-700200.0,13.8365151532
-700800.0,13.7204606014
-701400.0,14.0157053263
-702000.0,13.8348586854
-702600.0,14.8586850802
-703200.0,14.3761829735
-703800.0,15.0940384644
-704400.0,15.7803609048
-705000.0,16.4193904441
-705600.0,15.9635240383
-706200.0,16.5119082369
-706800.0,16.1583159295
-707400.0,16.1917265486
-708000.0,15.9115562349
-708600.0,15.4054188881
-709200.0,15.2520283602
-709800.0,16.3974719845
-710400.0,16.7086434784
-711000.0,16.0056143212
-711600.0,16.6013680335
-712200.0,16.6907309994
-712800.0,17.0714202657
-713400.0,16.8622730612
-714000.0,16.8306407174
-714600.0,16.8716245316
-715200.0,17.0242499951
-715800.0,17.1192321683
-716400.0,17.1048994052
-717000.0,16.756106761
-717600.0,16.7838411445
-718200.0,16.2169635297
-718800.0,16.5663808479
-719400.0,16.6330861098
-720000.0,16.5315086076
-720600.0,16.834613638
-721200.0,16.7161900397
-721800.0,16.869101996
-722400.0,16.9196337202
-723000.0,17.0474781225
-723600.0,16.7691566671
-724200.0,17.0785723353
-724800.0,17.0506084601
-725400.0,16.7922117652
-726000.0,16.7693303101
-726600.0,16.9798759307
-727200.0,16.7245988199
-727800.0,16.6050539832
-728400.0,16.5170400364
-729000.0,16.402583676
-729600.0,16.6478291845
-730200.0,16.5338305364
-730800.0,16.5184035996
-731400.0,16.5276974397
-732000.0,16.4283882792
-732600.0,16.4191269116
-733200.0,16.3758747612
-733800.0,16.2749783996
-734400.0,16.3447214682
-735000.0,16.4468817539
-735600.0,16.0791769183
-736200.0,16.318994008
-736800.0,16.0795019757
-737400.0,16.2890813114
-738000.0,16.0938235571
-738600.0,15.7853919106
-739200.0,15.5151612456
-739800.0,15.2181029964
-740400.0,14.137075182
-741000.0,13.7849741723
-741600.0,13.4455133912
-742200.0,13.6108816245
-742800.0,15.1619329882
-743400.0,15.882983264
-744000.0,15.6421072642
-744600.0,14.9600501275
-745200.0,14.6388440128
-745800.0,14.4798442102
-746400.0,13.6737304205
-747000.0,13.5431158932
-747600.0,13.0653469649
-748200.0,14.2193569407
-748800.0,14.1947017061
-749400.0,14.1631578265
-750000.0,14.6033477496
-750600.0,14.1207046212
-751200.0,14.7114968653
-751800.0,14.0651024509
-752400.0,13.7405310654
-753000.0,13.7432880137
-753600.0,13.025153761
-754200.0,13.1420953084
-754800.0,11.7212843406
-755400.0,12.2015106318
-756000.0,11.3727936826
-756600.0,12.189669269
-757200.0,11.4920218446
-757800.0,10.6791695373
-758400.0,11.5818073588
-759000.0,10.5375087373
-759600.0,10.9256911968
-760200.0,10.0117420455
-760800.0,10.5908509278
-761400.0,10.7403539923
-762000.0,10.3278805986
-762600.0,10.1709461689
-763200.0,11.0419296784
-763800.0,12.0729287793
-764400.0,11.9956237722
-765000.0,11.8222059082
-765600.0,11.3645752268
-766200.0,11.6223956128
-766800.0,12.1970445424
-767400.0,10.8670978738
-768000.0,9.06655603025
-768600.0,10.1269991455
-769200.0,10.3349102676
-769800.0,11.3752028415
-770400.0,10.5796803813
-771000.0,9.99774883627
-771600.0,9.70886794868
-772200.0,8.87954528481
-772800.0,8.42072998502
-773400.0,7.81277661503
-774000.0,7.42699014407
-774600.0,8.22545080322
-775200.0,8.94492094618
-775800.0,7.90707586253
-776400.0,7.70169984645
-777000.0,6.78571134054
-777600.0,7.44133086468
-778200.0,5.62994518723
-778800.0,6.10709512631
-779400.0,5.86307426584
-780000.0,6.76701478464
-780600.0,5.86361479173
-781200.0,6.66111309331
-781800.0,5.85236345317
-782400.0,6.48197825622
-783000.0,6.3086125226
-783600.0,7.23031431038
-784200.0,8.39058364381
-784800.0,6.2689692618
-785400.0,6.94056526061
-786000.0,6.9251228146
-786600.0,7.00376010119
-787200.0,7.24194575829
-787800.0,6.95549207595
-788400.0,8.096625522
-789000.0,9.2825519114
-789600.0,8.9737420114
-790200.0,7.43969526007
-790800.0,7.62485267107
-791400.0,7.708334985
-792000.0,7.64978433037
-792600.0,7.97492894864
-793200.0,7.57197887757
-793800.0,6.48018452672
-794400.0,6.18186813051
-795000.0,7.27354531027
-795600.0,7.40966388351
-796200.0,7.8765510714
-796800.0,6.99076432931
-797400.0,5.66075589485
-798000.0,6.73959383142
-798600.0,6.40071821323
-799200.0,6.42241296918
-799800.0,6.22272816268
-800400.0,5.313511683
-801000.0,5.95793350723
-801600.0,5.60253630966
-802200.0,5.52613861653
-802800.0,6.45164546848
-803400.0,6.5239292075
-804000.0,6.19094990126
-804600.0,6.02597777838
-805200.0,6.27464153395
-805800.0,6.51669156401
-806400.0,7.02842746175
-807000.0,6.20368217603
-807600.0,6.16005988581
-808200.0,6.06355079618
-808800.0,5.46680976489
-809400.0,4.9811260443
-810000.0,4.56583972826
-810600.0,4.83405383043
-811200.0,5.08383685377
-811800.0,5.85469275201
-812400.0,6.1344013111
-813000.0,6.54196016323
-813600.0,7.14170478441
-814200.0,6.7554891868
-814800.0,6.9964044282
-815400.0,6.39404565591
-816000.0,5.60728974939
-816600.0,4.64019459997
-817200.0,5.16095458283
-817800.0,5.11598144582
-818400.0,4.64482303324
-819000.0,4.35085533086
-819600.0,5.85715143139
-820200.0,5.67427986658
-820800.0,5.7102376133
-821400.0,6.39100058835
-822000.0,5.73125636168
-822600.0,4.96540951408
-823200.0,4.07067571847
-823800.0,4.52803229427
-824400.0,3.80482103801
-825000.0,4.69505057089
-825600.0,4.10232471848
-826200.0,3.37008732772
-826800.0,4.00256112335
-827400.0,4.30770173327
-828000.0,5.39861025926
-828600.0,4.59467728006
-829200.0,6.15488984
-829800.0,6.20177359654
-830400.0,6.71801175151
-831000.0,7.94750444147
-831600.0,7.38584393193
-832200.0,7.3436136923
-832800.0,6.93606546814
-833400.0,7.49258992871
-834000.0,7.8782096497
-834600.0,7.40646650126
-835200.0,8.05780380096
-835800.0,8.06304103748
-836400.0,9.09071225171
-837000.0,8.73738144136
-837600.0,8.33971174291
-838200.0,8.27915863119
-838800.0,8.34698206938
-839400.0,8.92754403162
-840000.0,8.66042832137
-840600.0,8.65799856754
-841200.0,8.67619094614
-841800.0,7.56246324937
-842400.0,7.94658051855
-843000.0,6.87138111635
-843600.0,7.68408961685
-844200.0,7.96084546666
-844800.0,7.30821701311
-845400.0,7.05750228572
-846000.0,7.18794391134
-846600.0,7.48849830711
-847200.0,6.52274695872
-847800.0,5.8982224214
-848400.0,6.77161079048
-849000.0,5.64678658893
-849600.0,5.49897688385
-850200.0,5.73275441335
-850800.0,5.04808577998
-851400.0,5.02088687748
-852000.0,5.6816470873
-852600.0,5.33775430803
-853200.0,4.49814071799
-853800.0,4.50067018255
-854400.0,4.7558398335
-855000.0,4.74510991766
-855600.0,4.10877044699
-856200.0,5.62896969819
-856800.0,6.04785187001
-857400.0,7.30127463738
-858000.0,6.64698644815
-858600.0,7.3237511281
-859200.0,7.93311582297
-859800.0,7.82211640608
-860400.0,7.60550646287
-861000.0,7.58508843302
-861600.0,6.614634381
-862200.0,7.50838992135
-862800.0,8.72356198389
-863400.0,9.16900330371
-864000.0,9.6086762372
-864600.0,11.4173163334
-865200.0,10.7071012183
-865800.0,10.7968817734
-866400.0,11.8326494508
-867000.0,11.7696657979
-867600.0,11.9591835094
-868200.0,12.6256545816
-868800.0,12.3337423725
-869400.0,13.1168608501
-870000.0,13.1465085612
-870600.0,12.1676293671
-871200.0,13.157144251
-871800.0,14.1728690628
-872400.0,15.09353603
-873000.0,14.1768763286
-873600.0,14.3242563139
-874200.0,14.8689750699
-874800.0,14.9563899037
-875400.0,14.541357209
-876000.0,13.0115325791
-876600.0,14.0541457645
-877200.0,14.5364184696
-877800.0,14.8757784412
-878400.0,15.1494265579
-879000.0,14.2654834083
-879600.0,14.3125714639
-880200.0,14.1823251458
-880800.0,14.7481564835
-881400.0,14.8479231576
-882000.0,15.4269221061
-882600.0,14.8231366278
-883200.0,14.9025698751
-883800.0,14.1457279485
-884400.0,14.545904463
-885000.0,14.1524390611
-885600.0,15.5526007611
-886200.0,14.6967506943
-886800.0,14.8880189051
-887400.0,15.8586869188
-888000.0,14.7927225058
-888600.0,14.1168470637
-889200.0,12.7838686845
-889800.0,12.5537716257
-890400.0,12.5802627151
-891000.0,12.4212989925
-891600.0,11.6665899715
-892200.0,9.99592443423
-892800.0,10.8824561201
-893400.0,10.792558381
-894000.0,10.9512176969
-894600.0,10.530005414
-895200.0,10.1192163735
-895800.0,10.2958386502
-896400.0,9.96157700406
-897000.0,9.78492804812
-897600.0,9.33394846775
-898200.0,10.1799218609
-898800.0,10.1234536624
-899400.0,10.8448526139
-900000.0,10.1695208049
-900600.0,10.7562613099
-901200.0,10.9273471671
-901800.0,11.5886526551
-902400.0,12.1492547528
-903000.0,12.3199212923
-903600.0,12.0486793888
-904200.0,11.1612448563
-904800.0,11.7021418248
-905400.0,11.1738189582
-906000.0,10.9276878567
-906600.0,11.9766794082
-907200.0,11.9271975839
-907800.0,12.8966227808
-908400.0,12.6862984949
-909000.0,11.7622466413
-909600.0,11.7687103232
-910200.0,12.0896348015
-910800.0,13.6504169561
-911400.0,13.0763562976
-912000.0,13.6173031621
-912600.0,13.5937457096
-913200.0,13.707410689
-913800.0,13.9033097321
-914400.0,13.7897899076
-915000.0,14.0354401928
-915600.0,14.0324636779
-916200.0,13.8175130383
-916800.0,14.5792393621
-917400.0,13.8377808878
-918000.0,14.4758460337
-918600.0,15.3216553183
-919200.0,15.685168118
-919800.0,15.7244873516
-920400.0,15.540532057
-921000.0,15.7214688904
-921600.0,14.9219285465
-922200.0,14.6096577043
-922800.0,14.4714936652
-923400.0,14.4245127282
-924000.0,15.0522843502
-924600.0,15.0394189632
-925200.0,13.9654306792
-925800.0,13.9297543526
-926400.0,14.1731191538
-927000.0,14.0300879332
-927600.0,13.5307327495
-928200.0,14.0503120637
-928800.0,14.1898837608
-929400.0,14.3166846718
-930000.0,13.406426627
-930600.0,14.1880252997
-931200.0,14.071405649
-931800.0,13.295067885
-932400.0,13.0687534178
-933000.0,12.5312229088
-933600.0,11.6327802346
-934200.0,12.2419587865
-934800.0,12.1565307661
-935400.0,12.3210371328
-936000.0,13.3389262898
-936600.0,13.8163231329
-937200.0,13.574488851
-937800.0,13.1051221803
-938400.0,13.2722288726
-939000.0,13.0228645747
-939600.0,12.8459168847
-940200.0,11.8421770342
-940800.0,12.2680002758
-941400.0,12.6281717117
-942000.0,11.5589830999
-942600.0,11.8339166
-943200.0,12.2593090062
-943800.0,10.5082455484
-944400.0,9.73252876005
-945000.0,8.20674227854
-945600.0,8.78260666403
-946200.0,8.6537161483
-946800.0,9.5266678548
-947400.0,9.174865113
-948000.0,9.09302835142
-948600.0,9.57630601318
-949200.0,8.30676505537
-949800.0,9.31332926285
-950400.0,8.87260276624
-951000.0,9.48969277365
-951600.0,9.45547942446
-952200.0,9.51557338325
-952800.0,9.43592932622
-953400.0,9.74916571981
-954000.0,9.27851985852
-954600.0,9.81595722226
-955200.0,9.87283818325
-955800.0,10.8085001617
-956400.0,10.1695882525
-957000.0,10.0135161938
-957600.0,10.3553607395
-958200.0,10.2206676759
-958800.0,10.368633731
-959400.0,9.92413069971
-960000.0,10.9283090424
-960600.0,10.5733731276
-961200.0,11.1974804092
-961800.0,11.304636103
-962400.0,11.7670179324
-963000.0,11.6919534417
-963600.0,11.1816264799
-964200.0,11.0492809031
-964800.0,11.9886919179
-965400.0,11.6800728587
-966000.0,12.3569930756
-966600.0,11.5533321284
-967200.0,10.6996780049
-967800.0,9.98896483252
-968400.0,8.57668639503
-969000.0,9.03908616986
-969600.0,9.09647315909
-970200.0,10.4489187121
-970800.0,10.1860022358
-971400.0,11.5404561505
-972000.0,11.7073204363
-972600.0,11.8499473771
-973200.0,11.7982056163
-973800.0,11.5713282946
-974400.0,11.0554840877
-975000.0,11.1820385098
-975600.0,11.5828189351
-976200.0,11.1856701889
-976800.0,11.163995482
-977400.0,10.378005084
-978000.0,9.69582669987
-978600.0,10.1503091157
-979200.0,10.3844518557
-979800.0,10.0621692132
-980400.0,9.23012346213
-981000.0,8.80447092359
-981600.0,9.32105390477
-982200.0,8.637961208
-982800.0,8.92402068899
-983400.0,9.14251101784
-984000.0,8.48059716066
-984600.0,7.26801468166
-985200.0,7.11164620301
-985800.0,6.93012388005
-986400.0,5.90090298582
-987000.0,5.79734331399
-987600.0,4.62707924486
-988200.0,4.85532772546
-988800.0,5.06329450476
-989400.0,5.9800685167
-990000.0,5.74711598989
-990600.0,4.93369409999
-991200.0,6.29846968105
-991800.0,6.50202199996
-992400.0,6.25846563839
-993000.0,6.0337731183
-993600.0,6.10738953649
-994200.0,6.0006734013
-994800.0,6.34725519222
-995400.0,8.32396130253
-996000.0,8.23907468438
-996600.0,8.85174671297
-997200.0,8.67192822148
-997800.0,9.78360198955
-998400.0,10.0390390947
-999000.0,9.94579521881
-999600.0,10.666023488
-1000200.0,10.362604163
-1000800.0,9.84008437872
-1001400.0,8.91583998115
-1002000.0,9.5577604843
-1002600.0,8.19924177695
-1003200.0,8.04851393433
-1003800.0,7.62248239914
-1004400.0,7.63373780969
-1005000.0,7.587629032
-1005600.0,6.59430312864
-1006200.0,7.05110106635
-1006800.0,7.28588813067
-1007400.0,6.98999407286
-1008000.0,6.42429914978
-1008600.0,7.29472305175
-1009200.0,7.06645897418
-1009800.0,5.77845597735
-1010400.0,5.3796477202
-1011000.0,5.8499105628
-1011600.0,6.93900694285
-1012200.0,7.22052649222
-1012800.0,6.41472123267
-1013400.0,4.70145469203
-1014000.0,5.44239513802
-1014600.0,4.9113177106
-1015200.0,4.178116789
-1015800.0,5.19495162425
-1016400.0,5.60904896181
-1017000.0,5.84407122387
-1017600.0,6.52589329644
-1018200.0,7.28603165841
-1018800.0,6.65503803618
-1019400.0,6.06921667855
-1020000.0,6.1020528989
-1020600.0,6.1119873387
-1021200.0,5.81684417231
-1021800.0,6.44472168912
-1022400.0,6.60916855185
-1023000.0,6.52111017114
-1023600.0,6.1434309794
-1024200.0,5.49241971661
-1024800.0,5.43452881567
-1025400.0,6.41589989171
-1026000.0,6.2960561243
-1026600.0,4.81754947868
-1027200.0,4.55764093957
-1027800.0,4.63072007637
-1028400.0,4.49439075554
-1029000.0,4.11408679568
-1029600.0,3.54553220014
-1030200.0,3.29000715726
-1030800.0,2.44899181074
-1031400.0,1.90820568681
-1032000.0,2.19489971681
-1032600.0,2.23079174026
-1033200.0,2.46093124082
-1033800.0,2.52644067317
-1034400.0,2.10600055139
-1035000.0,2.79706698579
-1035600.0,2.44864147463
-1036200.0,3.53919531017
-1036800.0,2.76721862382
-1037400.0,3.93841756748
-1038000.0,3.3891170444
-1038600.0,4.40646818695
-1039200.0,3.91412303365
-1039800.0,3.79624260495
-1040400.0,3.89398161416
-1041000.0,3.30803786226
-1041600.0,3.64066952593
-1042200.0,4.07398583432
-1042800.0,3.44288855906
-1043400.0,3.21775168303
-1044000.0,3.13301833787
-1044600.0,2.05775113674
-1045200.0,3.43336402084
-1045800.0,3.85729582433
-1046400.0,4.49612910487
-1047000.0,4.88943680456
-1047600.0,5.55645521399
-1048200.0,5.03465757615
-1048800.0,3.89052942245
-1049400.0,4.04103465883
-1050000.0,4.23102068471
-1050600.0,4.74070799493
-1051200.0,4.78410784917
-1051800.0,4.23779806983
-1052400.0,4.38138086702
-1053000.0,3.56718953882
-1053600.0,4.45182318229
-1054200.0,4.72760444773
-1054800.0,4.64349331675
-1055400.0,6.79353034574
-1056000.0,6.58755968393
-1056600.0,7.38283274375
-1057200.0,6.40858146869
-1057800.0,6.51371224217
-1058400.0,6.92438250406
-1059000.0,7.53444162562
-1059600.0,8.26269211745
-1060200.0,8.32030723032
-1060800.0,8.46834406733
-1061400.0,7.89791634913
-1062000.0,8.51718723118
-1062600.0,8.46366123619
-1063200.0,8.49632169013
-1063800.0,8.49651236902
-1064400.0,8.4285560542
-1065000.0,8.26925938409
-1065600.0,8.73943482031
-1066200.0,9.59401381811
-1066800.0,8.61409287881
-1067400.0,8.71399359786
-1068000.0,8.9439028736
-1068600.0,9.62331629493
-1069200.0,9.33000922494
-1069800.0,10.285447478
-1070400.0,10.8942712879
-1071000.0,10.1161218364
-1071600.0,11.1100827107
-1072200.0,10.860804456
-1072800.0,10.5599677278
-1073400.0,10.3838815593
-1074000.0,10.9078275123
-1074600.0,10.874647681
-1075200.0,11.3838943626
-1075800.0,9.9607161193
-1076400.0,9.7934490368
-1077000.0,8.82398890687
-1077600.0,9.27465940554
-1078200.0,10.0417855154
-1078800.0,9.77109331121
-1079400.0,9.36198934094
-1080000.0,8.69445723992
-1080600.0,9.12726748054
-1081200.0,8.55272178396
-1081800.0,8.22065091368
-1082400.0,8.5836266295
-1083000.0,9.92882390038
-1083600.0,10.4612608887
-1084200.0,10.5442954642
-1084800.0,11.0745265862
-1085400.0,10.7556394188
-1086000.0,10.5555613884
-1086600.0,11.3433168628
-1087200.0,12.2421657504
-1087800.0,12.8664588779
-1088400.0,13.367513188
-1089000.0,13.4679274154
-1089600.0,12.5757574898
-1090200.0,12.1740820295
-1090800.0,12.0694065844
-1091400.0,11.4488602071
-1092000.0,11.230235988
-1092600.0,11.940846768
-1093200.0,12.3177567157
-1093800.0,12.1448446307
-1094400.0,11.1477658186
-1095000.0,10.8048589081
-1095600.0,11.1791851318
-1096200.0,10.3947349183
-1096800.0,10.2804934393
-1097400.0,9.51379109898
-1098000.0,9.6879591403
-1098600.0,10.0207681435
-1099200.0,9.25957998309
-1099800.0,9.32252676305
-1100400.0,9.66354039793
-1101000.0,9.32259946183
-1101600.0,9.81347439118
-1102200.0,9.26336358347
-1102800.0,9.20191258642
-1103400.0,8.99060023592
-1104000.0,8.9246229102
-1104600.0,7.75697390683
-1105200.0,8.68303944776
-1105800.0,7.80371088588
-1106400.0,8.04267958713
-1107000.0,7.69303981919
-1107600.0,6.38846739078
-1108200.0,7.12445231297
-1108800.0,7.84099711426
-1109400.0,8.7838640046
-1110000.0,8.04850071055
-1110600.0,7.78920106355
-1111200.0,8.7166012315
-1111800.0,7.84504559624
-1112400.0,8.43914785769
-1113000.0,8.43631346677
-1113600.0,8.35323038642
-1114200.0,8.41212390118
-1114800.0,8.67648959698
-1115400.0,8.94336754627
-1116000.0,9.03092572141
-1116600.0,9.07878653519
-1117200.0,8.78547134503
-1117800.0,8.82554855914
-1118400.0,8.86613682711
-1119000.0,8.92126662067
-1119600.0,10.1139314083
-1120200.0,9.46455855097
-1120800.0,10.3752439803
-1121400.0,10.8293776967
-1122000.0,10.2244393165
-1122600.0,11.2227908057
-1123200.0,10.4195320225
-1123800.0,10.7283516495
-1124400.0,11.0133002079
-1125000.0,12.4661281738
-1125600.0,12.5110245177
-1126200.0,13.2009600424
-1126800.0,14.0391207971
-1127400.0,14.4764538099
-1128000.0,14.6734761815
-1128600.0,15.126791835
-1129200.0,15.5768385179
-1129800.0,15.1513078437
-1130400.0,15.3887175617
-1131000.0,15.9676992943
-1131600.0,16.1547526491
-1132200.0,16.0521451481
-1132800.0,16.4812978214
-1133400.0,16.4703452374
-1134000.0,16.4772191543
-1134600.0,16.5460962072
-1135200.0,16.5806884584
-1135800.0,16.7229983528
-1136400.0,16.7988083121
-1137000.0,16.8507921055
-1137600.0,16.9150439816
-1138200.0,17.1800798376
-1138800.0,17.309636597
-1139400.0,17.3457010834
-1140000.0,17.2926583066
-1140600.0,17.4038603686
-1141200.0,17.4236656909
-1141800.0,17.4424182309
-1142400.0,17.461123377
-1143000.0,17.3864058855
-1143600.0,17.2415675005
-1144200.0,17.1474202231
-1144800.0,17.3948950062
-1145400.0,17.4713858587
-1146000.0,17.2317117874
-1146600.0,17.3704667577
-1147200.0,17.4426998773
-1147800.0,17.4296444663
-1148400.0,17.4091873536
-1149000.0,17.6613564862
-1149600.0,17.6408875518
-1150200.0,17.6181605783
-1150800.0,17.5928416086
-1151400.0,17.5683157264
-1152000.0,17.5422030893
-1152600.0,17.516023398
-1153200.0,17.4880887776
-1153800.0,17.4609143337
-1154400.0,17.433074055
-1155000.0,17.4060653055
-1155600.0,17.3782488009
-1156200.0,17.3534024725
-1156800.0,17.3271358223
-1157400.0,17.3025801589
-1158000.0,17.2757417484
-1158600.0,16.9840257698
-1159200.0,16.9615897516
-1159800.0,16.9382213946
-1160400.0,16.8351378886
-1161000.0,16.5964840533
-1161600.0,16.1323549383
-1162200.0,15.3879597627
-1162800.0,15.3073538238
-1163400.0,14.9803383376
-1164000.0,15.0407368955
-1164600.0,15.4475205311
-1165200.0,14.884951439
-1165800.0,15.2508138201
-1166400.0,14.6943976696
-1167000.0,15.0411033005
-1167600.0,14.9021980569
-1168200.0,14.4199877284
-1168800.0,14.90260417
-1169400.0,15.2345712127
-1170000.0,14.9589497367
-1170600.0,14.2936712234
-1171200.0,14.8373881755
-1171800.0,15.2885116356
-1172400.0,14.753476201
-1173000.0,14.7684543252
-1173600.0,13.6416109544
-1174200.0,13.461515598
-1174800.0,14.9063884932
-1175400.0,14.1469747166
-1176000.0,14.1128035994
-1176600.0,14.3225878089
-1177200.0,13.4156947657
-1177800.0,13.7322909729
-1178400.0,13.7193205009
-1179000.0,12.949098597
-1179600.0,12.9597299378
-1180200.0,13.0997316784
-1180800.0,13.0421736036
-1181400.0,14.0175648118
-1182000.0,13.0141630098
-1182600.0,13.8260407826
-1183200.0,13.8443477445
-1183800.0,13.9649305206
-1184400.0,13.0855480597
-1185000.0,12.3231313935
-1185600.0,12.3808351865
-1186200.0,10.4638146461
-1186800.0,10.9047967063
-1187400.0,10.8386326163
-1188000.0,10.7762200738
-1188600.0,9.74691576237
-1189200.0,10.7050935302
-1189800.0,11.3926057193
-1190400.0,12.1373720271
-1191000.0,11.944731403
-1191600.0,11.7713433299
-1192200.0,12.4357384143
-1192800.0,12.9075090057
-1193400.0,12.8319417417
-1194000.0,12.1978339341
-1194600.0,12.8104994261
-1195200.0,12.124543826
-1195800.0,11.6164448826
-1196400.0,11.6253533699
-1197000.0,12.0008339565
-1197600.0,12.0025084597
-1198200.0,10.3164922535
-1198800.0,11.1315779248
-1199400.0,10.9922346381
-1200000.0,11.1361768746
-1200600.0,11.1908753019
-1201200.0,10.733827754
-1201800.0,9.64464696922
-1202400.0,9.11478619974
-1203000.0,9.88264993416
-1203600.0,8.63740626698
-1204200.0,8.16507231678
-1204800.0,8.03114737262
-1205400.0,8.95786065316
-1206000.0,8.98154402668
-1206600.0,8.37118703164
-1207200.0,7.92008838408
-1207800.0,8.02261320418
-1208400.0,7.99975509549
-1209000.0,7.53832935273
-1209600.0,8.34574153633
+0.0,9.20913464100489
+600.0,9.462409489690058
+1200.0,8.899322568935972
+1800.0,9.80130647321988
+2400.0,9.599599695534156
+3000.0,9.384464608834875
+3600.0,9.634070759716918
+4200.0,9.290813814103624
+4800.0,9.656379721517576
+5400.0,10.386623274422234
+6000.0,10.472036118966761
+6600.0,11.161483287302353
+7200.0,10.94505583570898
+7800.0,11.32790609543186
+8400.0,11.675068566361626
+9000.0,11.582720249401016
+9600.0,13.187104433078343
+10200.0,13.044063178602041
+10800.0,15.261805331577843
+11400.0,15.65319450131354
+12000.0,16.3160925609169
+12600.0,15.356540314924782
+13200.0,15.843702194496467
+13800.0,16.252509621244815
+14400.0,15.906222164075883
+15000.0,15.78553907942906
+15600.0,14.969279089479604
+16200.0,14.542833866298928
+16800.0,13.850917490843168
+17400.0,12.928212809171166
+18000.0,14.398297247024276
+18600.0,14.123616515359513
+19200.0,14.604165689285363
+19800.0,15.092576859348654
+20400.0,15.135124401353002
+21000.0,16.08831501045159
+21600.0,14.901189962026974
+22200.0,15.374025151284258
+22800.0,15.151776081925957
+23400.0,15.496144786920366
+24000.0,14.909304309067624
+24600.0,14.84917179187213
+25200.0,17.18426345578617
+25800.0,17.17924827437467
+26400.0,17.396758828242582
+27000.0,16.981895730677316
+27600.0,15.785547238917028
+28200.0,15.963655159054923
+28800.0,16.37336291631842
+29400.0,17.169945444413585
+30000.0,17.03359901268554
+30600.0,16.973741524773203
+31200.0,17.297853324538917
+31800.0,17.11847237114432
+32400.0,17.040683255682364
+33000.0,16.55328908026167
+33600.0,16.618001834144785
+34200.0,16.41925867884609
+34800.0,16.164256577123904
+35400.0,16.711725143554848
+36000.0,16.985218000343604
+36600.0,16.45543861585532
+37200.0,16.691912844403742
+37800.0,16.231186173733928
+38400.0,15.880456936591603
+39000.0,15.555005082731748
+39600.0,15.643412128666572
+40200.0,15.033872875848655
+40800.0,15.452853787880938
+41400.0,15.596767113709813
+42000.0,14.578564705004379
+42600.0,14.611954182073221
+43200.0,13.658823135775679
+43800.0,13.959159981717177
+44400.0,13.658788280206096
+45000.0,14.124946748884275
+45600.0,13.862531173196023
+46200.0,13.576501593377186
+46800.0,13.077599030426386
+47400.0,12.839555197092334
+48000.0,11.559877743094221
+48600.0,10.489261500308615
+49200.0,10.557442083219623
+49800.0,10.278611592520338
+50400.0,10.87485861253601
+51000.0,10.99247449038895
+51600.0,9.988629535158916
+52200.0,10.56501692496298
+52800.0,9.65337129910746
+53400.0,9.71454084110034
+54000.0,8.792791484978766
+54600.0,7.645052041770934
+55200.0,7.202029819164951
+55800.0,7.484681315852581
+56400.0,8.578685420665654
+57000.0,8.476437226641758
+57600.0,8.717234189013602
+58200.0,9.219351333021988
+58800.0,8.931248197771009
+59400.0,8.458500195420958
+60000.0,9.430994953879024
+60600.0,9.242301020057463
+61200.0,8.275391435277399
+61800.0,9.292172493598367
+62400.0,9.032790858168402
+63000.0,8.666982380200695
+63600.0,8.388070889633521
+64200.0,7.529743526879694
+64800.0,7.5689034385188005
+65400.0,8.354048583344007
+66000.0,8.854431623546407
+66600.0,7.746023621990726
+67200.0,8.969623897774625
+67800.0,7.839345485706273
+68400.0,8.209170578931293
+69000.0,8.910155877873189
+69600.0,9.073571434399053
+70200.0,10.255523301860656
+70800.0,10.110440692611089
+71400.0,11.21836919002397
+72000.0,11.840762247318459
+72600.0,11.627255283727447
+73200.0,11.876530757949006
+73800.0,11.722784150897455
+74400.0,12.528804861383351
+75000.0,12.645244245189454
+75600.0,12.865448009538348
+76200.0,12.115230250212058
+76800.0,11.777660542516847
+77400.0,11.985035847046543
+78000.0,12.375415215122885
+78600.0,11.79198817969773
+79200.0,11.85533032841644
+79800.0,12.03343717585828
+80400.0,11.8513826735584
+81000.0,12.61803118332799
+81600.0,12.259627976175864
+82200.0,11.302266435693664
+82800.0,11.158170350505193
+83400.0,9.64308978030864
+84000.0,12.442016829419638
+84600.0,11.989109141161274
+85200.0,12.90965018256
+85800.0,12.244027601321548
+86400.0,11.594461132910657
+87000.0,12.605203169894864
+87600.0,12.618976595260364
+88200.0,13.340208319090177
+88800.0,14.145095153943183
+89400.0,13.725018674269013
+90000.0,13.78394204802663
+90600.0,12.636139222062825
+91200.0,13.567077514404524
+91800.0,12.277110951974038
+92400.0,12.616647070513531
+93000.0,12.807604065606675
+93600.0,12.971207173537927
+94200.0,11.711666258955697
+94800.0,11.879002889804232
+95400.0,10.865735503410034
+96000.0,11.291020923888137
+96600.0,10.196432447974797
+97200.0,11.009747604164016
+97800.0,10.258923926205062
+98400.0,11.499070904222018
+99000.0,12.032898217812656
+99600.0,11.71709143622699
+100200.0,12.120829770784217
+100800.0,11.842071096467537
+101400.0,11.90869619002305
+102000.0,11.561582102527035
+102600.0,11.16881236950051
+103200.0,11.908409231957396
+103800.0,11.206485946335595
+104400.0,12.079122796980473
+105000.0,10.737308503418587
+105600.0,11.616189730986138
+106200.0,10.496908115258643
+106800.0,10.884901461103928
+107400.0,11.671473975302947
+108000.0,11.502957557601531
+108600.0,11.964098294788569
+109200.0,12.09423477813315
+109800.0,13.177060140550825
+110400.0,10.661064670920222
+111000.0,11.347393433418791
+111600.0,10.083038376393175
+112200.0,9.72105560175972
+112800.0,10.85954449757802
+113400.0,10.795219262837442
+114000.0,11.647022717239771
+114600.0,10.969518103003239
+115200.0,11.244582549264338
+115800.0,11.64301788471436
+116400.0,11.097133394356215
+117000.0,11.099291274230252
+117600.0,9.517734139436365
+118200.0,10.7321557835494
+118800.0,9.24810117386752
+119400.0,11.014366244321803
+120000.0,10.578921001631915
+120600.0,10.113294935030973
+121200.0,10.051662234733472
+121800.0,9.778503835403145
+122400.0,8.848171668032176
+123000.0,8.398728394785122
+123600.0,7.740983183213453
+124200.0,7.51767011689546
+124800.0,5.0273104191403375
+125400.0,5.480382044179341
+126000.0,6.744793667475028
+126600.0,5.431169997931075
+127200.0,5.974930435286512
+127800.0,5.486718971911659
+128400.0,5.490129731326716
+129000.0,4.123990478662419
+129600.0,5.4820932157408935
+130200.0,5.71980803172647
+130800.0,4.9704255277478815
+131400.0,6.474146641391831
+132000.0,7.779632842546704
+132600.0,7.4792187237588355
+133200.0,7.200530480805735
+133800.0,6.038695849193483
+134400.0,6.254669570276271
+135000.0,7.262232946984917
+135600.0,7.177091614850009
+136200.0,5.8294036340675515
+136800.0,6.763063136201321
+137400.0,8.361116577888634
+138000.0,9.03754157999767
+138600.0,9.417531733922287
+139200.0,9.41024072476884
+139800.0,8.451112420512912
+140400.0,9.503088502158834
+141000.0,8.686733504438562
+141600.0,8.153164128746901
+142200.0,7.346539381822601
+142800.0,6.522821014062637
+143400.0,6.546957299516572
+144000.0,6.158948896983884
+144600.0,7.248947531719667
+145200.0,7.63607303584727
+145800.0,7.366390533674595
+146400.0,10.155305261524303
+147000.0,9.201603785687194
+147600.0,8.840310507546377
+148200.0,7.500895720797169
+148800.0,6.803760746228944
+149400.0,7.502483634202075
+150000.0,7.677970502348913
+150600.0,8.944592203736947
+151200.0,8.839977728913263
+151800.0,9.808328612497265
+152400.0,9.081049150016787
+153000.0,8.909755900653662
+153600.0,10.196951668722013
+154200.0,10.25055483839648
+154800.0,9.510323439443937
+155400.0,8.592457935969309
+156000.0,8.329957392377853
+156600.0,7.560037960101021
+157200.0,8.409943745289652
+157800.0,8.399259091395086
+158400.0,7.720207207295404
+159000.0,7.6740290809930904
+159600.0,7.582684989578873
+160200.0,8.297794042247597
+160800.0,8.329516898592496
+161400.0,7.560489103438583
+162000.0,7.993438200592094
+162600.0,7.790023785835841
+163200.0,9.144158348423257
+163800.0,8.419105762666423
+164400.0,9.0276253800357
+165000.0,9.850919427640887
+165600.0,9.27772640491338
+166200.0,8.54008737429744
+166800.0,9.052259905309937
+167400.0,8.35854579222622
+168000.0,8.828450342060485
+168600.0,9.134375806851322
+169200.0,8.633892412329335
+169800.0,9.536696852216092
+170400.0,9.358315875848437
+171000.0,8.226993347736926
+171600.0,9.278294707865083
+172200.0,8.381652399328601
+172800.0,8.94158154723437
+173400.0,9.069502912375938
+174000.0,9.430327917054711
+174600.0,10.802255518871132
+175200.0,9.724218230025441
+175800.0,11.155079785778193
+176400.0,10.90887108417877
+177000.0,11.048803257933264
+177600.0,12.722828431116941
+178200.0,13.03929881465803
+178800.0,10.754618292818595
+179400.0,13.68288741590648
+180000.0,13.431375825201286
+180600.0,13.316349740034484
+181200.0,12.730461718600933
+181800.0,13.796272948430332
+182400.0,12.908819663156606
+183000.0,13.301719656602714
+183600.0,12.55790608425083
+184200.0,11.984153066230604
+184800.0,11.425832901351802
+185400.0,11.76879911860899
+186000.0,12.1510260185481
+186600.0,14.085570453530812
+187200.0,14.959871726972432
+187800.0,12.639441491337104
+188400.0,13.195070633365658
+189000.0,12.224032574288788
+189600.0,14.043582522797477
+190200.0,13.704967164851661
+190800.0,14.752237251584276
+191400.0,13.462899417877642
+192000.0,14.555287271489505
+192600.0,15.555828717515642
+193200.0,15.3644566195488
+193800.0,15.013680144125694
+194400.0,15.02629407001976
+195000.0,15.914419125222095
+195600.0,14.702407961781953
+196200.0,14.478427401169506
+196800.0,14.85665813677072
+197400.0,15.117711951281697
+198000.0,15.25572702146287
+198600.0,14.783999620301033
+199200.0,13.912455752535521
+199800.0,14.807384718957534
+200400.0,15.405662572277475
+201000.0,14.943170079124743
+201600.0,14.450786858876004
+202200.0,15.702542578986947
+202800.0,14.670717523247324
+203400.0,13.867680865428142
+204000.0,13.514068806471235
+204600.0,13.24981667128739
+205200.0,13.338364485531356
+205800.0,11.488771831985568
+206400.0,12.40024092039796
+207000.0,11.285628572509122
+207600.0,10.863756603912751
+208200.0,9.855123569206354
+208800.0,10.703250269121472
+209400.0,10.512238978881784
+210000.0,11.45512147324517
+210600.0,11.09920952845854
+211200.0,13.605705963554291
+211800.0,11.985407752961372
+212400.0,11.328150170024047
+213000.0,12.484128662748844
+213600.0,12.376647604041414
+214200.0,11.991346375664392
+214800.0,12.40052882517586
+215400.0,10.823533506312495
+216000.0,11.936539058726527
+216600.0,10.057974291899251
+217200.0,10.289460195524967
+217800.0,10.116245688527085
+218400.0,10.742375227080645
+219000.0,10.622875130990252
+219600.0,10.724843499120448
+220200.0,9.603146693225487
+220800.0,10.6982886527348
+221400.0,11.053031833160555
+222000.0,11.397238305731921
+222600.0,11.556047981355924
+223200.0,12.82728662547717
+223800.0,12.419401798047895
+224400.0,11.06924879807779
+225000.0,10.057538177856372
+225600.0,9.554880604967408
+226200.0,8.982724184612032
+226800.0,9.10917118772212
+227400.0,9.530885834095113
+228000.0,9.392945304467107
+228600.0,7.0559862465225
+229200.0,7.508891711063505
+229800.0,7.650156925198944
+230400.0,6.858020068761749
+231000.0,6.357606445331988
+231600.0,7.137221681150589
+232200.0,5.4172624348755924
+232800.0,5.078602897221231
+233400.0,5.070278035929824
+234000.0,5.5324304036262095
+234600.0,4.7326944478965025
+235200.0,3.7209310495924734
+235800.0,3.1514813040392013
+236400.0,3.446306962088641
+237000.0,2.7758246285261015
+237600.0,2.038696073504074
+238200.0,0.9650910412197137
+238800.0,1.6369789516932127
+239400.0,1.7304698122368505
+240000.0,1.9672562157629223
+240600.0,2.4379843316432535
+241200.0,3.4268848003217665
+241800.0,3.2451314864403074
+242400.0,3.790572002985684
+243000.0,3.196098961414659
+243600.0,3.285018629950659
+244200.0,4.06227264742743
+244800.0,1.921123964115005
+245400.0,3.7215320715379088
+246000.0,1.970098630170011
+246600.0,2.3721292870963477
+247200.0,1.9651928290837175
+247800.0,1.0894439527572102
+248400.0,0.9435902148509361
+249000.0,1.1235051060455412
+249600.0,1.834019432904389
+250200.0,1.525415189284374
+250800.0,2.2232759541387597
+251400.0,1.9490406314037043
+252000.0,2.7658408713801172
+252600.0,3.9914980953892965
+253200.0,2.8883272450469146
+253800.0,3.6230524803710833
+254400.0,4.155729479511143
+255000.0,4.624695382705483
+255600.0,4.0574212138080465
+256200.0,5.348677330412302
+256800.0,4.966091997026521
+257400.0,3.516520204375012
+258000.0,4.969886545384565
+258600.0,5.5969501984109105
+259200.0,5.122710217633448
+259800.0,4.972221945960198
+260400.0,5.028450348994957
+261000.0,4.792526525090458
+261600.0,5.058792655079803
+262200.0,4.939876425394294
+262800.0,6.080459477760286
+263400.0,5.706732318304684
+264000.0,6.151369820348349
+264600.0,4.224260912280049
+265200.0,5.405402450703993
+265800.0,4.133739469894812
+266400.0,5.171004500475394
+267000.0,5.081615670267023
+267600.0,5.013307777299951
+268200.0,6.775510801376635
+268800.0,7.421170815998559
+269400.0,8.325218346748038
+270000.0,8.128130379352553
+270600.0,9.422372386354544
+271200.0,10.047338494578844
+271800.0,10.427200652240495
+272400.0,9.198084882051617
+273000.0,9.092679019566216
+273600.0,10.000117397909872
+274200.0,8.54191381066143
+274800.0,10.39210226370216
+275400.0,11.19511855100465
+276000.0,10.978707414051248
+276600.0,10.898711727346434
+277200.0,10.286587495639148
+277800.0,9.241247900618328
+278400.0,9.292993637042905
+279000.0,9.42881808867257
+279600.0,9.470269432031051
+280200.0,10.510932110900207
+280800.0,10.2612827646884
+281400.0,10.27456290285466
+282000.0,9.324630688859624
+282600.0,8.86009905955025
+283200.0,8.470302528075612
+283800.0,6.618338685586365
+284400.0,8.493810158874203
+285000.0,8.600419451303786
+285600.0,7.886018247993306
+286200.0,6.298028299290272
+286800.0,7.257606016623477
+287400.0,7.431418798676452
+288000.0,7.055730432394344
+288600.0,6.237491699719617
+289200.0,6.098113933164259
+289800.0,4.970391039782815
+290400.0,5.312148878848324
+291000.0,5.295042401605142
+291600.0,4.825672007269879
+292200.0,5.407825349064562
+292800.0,4.38667984141767
+293400.0,4.251496057175551
+294000.0,4.005762274342938
+294600.0,4.126258296245175
+295200.0,4.121017954655433
+295800.0,5.670740962158968
+296400.0,5.924529090473514
+297000.0,7.168531496122592
+297600.0,6.765821420638232
+298200.0,6.717670074220506
+298800.0,6.21015140272097
+299400.0,5.855672195459978
+300000.0,7.134593473500992
+300600.0,9.1980270788072
+301200.0,7.285744307662585
+301800.0,6.221241243833059
+302400.0,6.914592582401912
+303000.0,5.0742429415965775
+303600.0,4.8034212176852975
+304200.0,6.677856008026364
+304800.0,4.672542904418606
+305400.0,4.691821983380049
+306000.0,5.378201974855253
+306600.0,5.442964004880411
+307200.0,5.965276313829594
+307800.0,6.466969190052019
+308400.0,6.9049440402810935
+309000.0,7.111974266955427
+309600.0,8.486460139587567
+310200.0,8.066054266769983
+310800.0,9.987072542361435
+311400.0,9.228536217588886
+312000.0,9.429695047596372
+312600.0,9.656293219824505
+313200.0,9.674947501701515
+313800.0,10.258829952929949
+314400.0,10.139620392567265
+315000.0,10.341596747455839
+315600.0,10.6413559468492
+316200.0,10.30311949485869
+316800.0,11.44929321793036
+317400.0,12.161508709289476
+318000.0,13.7988499582444
+318600.0,13.063564787542154
+319200.0,14.1805420756889
+319800.0,14.551289537800011
+320400.0,14.566477431882808
+321000.0,13.534257632400145
+321600.0,13.841912210899956
+322200.0,12.476884289866673
+322800.0,12.919170525837233
+323400.0,10.661481001637766
+324000.0,10.68910668034076
+324600.0,11.308010584444053
+325200.0,9.893537664174186
+325800.0,8.823163217773056
+326400.0,10.88764275422486
+327000.0,10.203764267097526
+327600.0,11.707775489745814
+328200.0,11.690188530134941
+328800.0,12.793487561575194
+329400.0,12.554431059309598
+330000.0,11.698138879352921
+330600.0,12.021406033317954
+331200.0,12.837108324042738
+331800.0,12.627145088684747
+332400.0,11.92565671554956
+333000.0,11.694972354999466
+333600.0,12.081031663801744
+334200.0,11.563566881353355
+334800.0,11.977753715643559
+335400.0,11.84306657023029
+336000.0,12.578462833896973
+336600.0,13.015913814507876
+337200.0,13.518585176344132
+337800.0,14.444763465576681
+338400.0,14.617470044684207
+339000.0,14.583112767442014
+339600.0,13.85544767269005
+340200.0,13.429809522498381
+340800.0,12.400153967728954
+341400.0,12.162935294593204
+342000.0,10.89854471096278
+342600.0,10.912651475938107
+343200.0,9.013697171090302
+343800.0,9.358965594405397
+344400.0,9.510012485766879
+345000.0,8.581043995129443
+345600.0,8.476972921205121
+346200.0,8.44556602720438
+346800.0,9.30192619332806
+347400.0,9.361853000175806
+348000.0,10.047568136685532
+348600.0,10.6524588123076
+349200.0,10.361273142166542
+349800.0,10.824285487130814
+350400.0,11.546278076582963
+351000.0,11.406637636495084
+351600.0,10.625849234132254
+352200.0,11.968678231232724
+352800.0,10.129215574301599
+353400.0,9.041119695712329
+354000.0,8.921738577997713
+354600.0,8.401102186533175
+355200.0,9.17494020100422
+355800.0,10.246294192545268
+356400.0,8.993955060638852
+357000.0,8.693264325336596
+357600.0,9.084898381487662
+358200.0,9.552447933376127
+358800.0,8.853104425210457
+359400.0,8.730227984083452
+360000.0,11.161886925777436
+360600.0,11.06892993850298
+361200.0,12.152915879165713
+361800.0,12.268718436432936
+362400.0,11.751586989620279
+363000.0,13.701027195722956
+363600.0,12.425166771151043
+364200.0,10.837336031490478
+364800.0,11.314047554624963
+365400.0,11.81011830835684
+366000.0,11.808107630958713
+366600.0,11.41279678221388
+367200.0,11.037520745836977
+367800.0,11.15668838261702
+368400.0,11.093314288425953
+369000.0,11.40722090889768
+369600.0,10.868819305684584
+370200.0,10.10942756432837
+370800.0,10.292026490081335
+371400.0,10.701691405875817
+372000.0,9.728548784656317
+372600.0,11.006828463477891
+373200.0,11.184728682662048
+373800.0,9.48105037969123
+374400.0,8.651860093835401
+375000.0,9.274052985558145
+375600.0,9.26722883243796
+376200.0,8.38979106086199
+376800.0,10.45777276198559
+377400.0,9.523992986333305
+378000.0,9.413835907626563
+378600.0,9.342055201318239
+379200.0,10.637548102702539
+379800.0,8.922203287535197
+380400.0,9.806949346877227
+381000.0,8.368051569854046
+381600.0,6.3303004035641495
+382200.0,5.617900514858674
+382800.0,7.236576442022366
+383400.0,6.81619359235386
+384000.0,7.449993330792733
+384600.0,7.195475188735565
+385200.0,6.40746592932785
+385800.0,6.237709026549601
+386400.0,5.797033731679081
+387000.0,4.991821647691882
+387600.0,6.5921163980146735
+388200.0,5.572522459965538
+388800.0,5.3633410189794075
+389400.0,4.86421656365008
+390000.0,5.318718672226587
+390600.0,4.5516469366388375
+391200.0,3.7934999223823453
+391800.0,4.0471437238574675
+392400.0,4.497012849245278
+393000.0,4.400185601247015
+393600.0,4.98506664908421
+394200.0,3.7623473821924693
+394800.0,4.396651081223233
+395400.0,6.453719325601149
+396000.0,5.009197749967886
+396600.0,3.7071938426324658
+397200.0,4.557594541871834
+397800.0,5.363479338140612
+398400.0,5.464718712663551
+399000.0,5.483255044846608
+399600.0,5.656795405601068
+400200.0,7.12176485761142
+400800.0,7.263487684726345
+401400.0,6.932573677109439
+402000.0,7.903811291896453
+402600.0,7.097316280133988
+403200.0,8.259859365157086
+403800.0,7.68906661537422
+404400.0,7.70634134668629
+405000.0,7.622223019553409
+405600.0,6.231175453306986
+406200.0,7.508216456548355
+406800.0,6.251570351984986
+407400.0,6.322509751262374
+408000.0,5.992450959680505
+408600.0,5.697749613557815
+409200.0,6.804507285104901
+409800.0,7.715087927296511
+410400.0,6.662496418712055
+411000.0,8.078101102047226
+411600.0,7.439631169770979
+412200.0,7.113245713604445
+412800.0,6.193510894434944
+413400.0,6.579229444869328
+414000.0,4.354395334120961
+414600.0,3.906393185161876
+415200.0,4.8683976708028425
+415800.0,6.012038410124132
+416400.0,6.045160409473344
+417000.0,6.981143637331698
+417600.0,6.751457819233255
+418200.0,7.639994382102852
+418800.0,8.33353476914712
+419400.0,7.248850382174029
+420000.0,9.001931990865078
+420600.0,7.38176560716474
+421200.0,7.886664098069948
+421800.0,6.745029847427866
+422400.0,7.406720551348907
+423000.0,6.310962786940835
+423600.0,5.808036302412475
+424200.0,5.9094059117171875
+424800.0,7.00320549086493
+425400.0,6.120238490266132
+426000.0,6.160715693778024
+426600.0,7.290453871244219
+427200.0,7.993620354923009
+427800.0,8.950411872161249
+428400.0,9.474637874706678
+429000.0,8.739997611686896
+429600.0,9.739924256600965
+430200.0,9.294388167392846
+430800.0,8.7455056139502
+431400.0,9.764190019005278
+432000.0,9.956942395218492
+432600.0,9.60989906901122
+433200.0,8.661405285527502
+433800.0,8.656447249302397
+434400.0,9.519464382299349
+435000.0,9.589689231407167
+435600.0,9.48441578906711
+436200.0,9.553204463784507
+436800.0,8.382273397405642
+437400.0,8.960559947118488
+438000.0,9.941760845021479
+438600.0,9.46478546997383
+439200.0,9.272008064900385
+439800.0,9.762152279863464
+440400.0,9.850321091991427
+441000.0,9.660362112382812
+441600.0,9.600732299844392
+442200.0,9.944910669582821
+442800.0,10.04377423758412
+443400.0,8.601093580429541
+444000.0,9.337124554892071
+444600.0,9.17958848523187
+445200.0,9.375668906052063
+445800.0,10.188903168401
+446400.0,9.522840557927326
+447000.0,9.898149090307315
+447600.0,11.11045137052588
+448200.0,9.072851796107871
+448800.0,10.874621079465452
+449400.0,12.470395536587333
+450000.0,13.334755020213402
+450600.0,12.76643496168303
+451200.0,12.111685645998623
+451800.0,11.28418418833123
+452400.0,12.784357046124496
+453000.0,13.123760059872751
+453600.0,13.18741875209364
+454200.0,14.257458347116458
+454800.0,14.826200724059733
+455400.0,15.96509196000268
+456000.0,14.740992697203586
+456600.0,13.92316540170363
+457200.0,14.37281991420524
+457800.0,14.754818476283429
+458400.0,15.476896551382644
+459000.0,15.456761421377108
+459600.0,14.223334383550764
+460200.0,14.178169542622882
+460800.0,12.331399504765475
+461400.0,14.566668379799495
+462000.0,14.331067105455908
+462600.0,14.47932200367146
+463200.0,15.493281197706912
+463800.0,14.011810690713938
+464400.0,13.599432144608825
+465000.0,14.240431919381654
+465600.0,14.636788963324058
+466200.0,14.386566941307601
+466800.0,15.632338237228192
+467400.0,15.047868333654405
+468000.0,15.89108172323595
+468600.0,14.272935895529063
+469200.0,14.943375615568002
+469800.0,15.149845994482071
+470400.0,14.987605648713709
+471000.0,15.126848666184253
+471600.0,15.530344544990385
+472200.0,15.934627378646589
+472800.0,16.76553806490769
+473400.0,16.784036413199196
+474000.0,16.765648882747122
+474600.0,16.664036653752806
+475200.0,16.53454120368075
+475800.0,16.4477745398374
+476400.0,14.96580874876227
+477000.0,15.553794808207362
+477600.0,16.219290300476988
+478200.0,16.16843564078249
+478800.0,16.03317230608164
+479400.0,16.50536432740368
+480000.0,16.3470042080115
+480600.0,15.99893080009031
+481200.0,16.09313415958825
+481800.0,15.743327432188073
+482400.0,15.488086842427887
+483000.0,15.090601192983073
+483600.0,15.753063038336139
+484200.0,16.133777672927575
+484800.0,16.15520567273117
+485400.0,15.794085528180108
+486000.0,15.724571023879006
+486600.0,14.86686891941584
+487200.0,15.421114596842534
+487800.0,15.38366560999712
+488400.0,14.605074149824755
+489000.0,14.387657741647232
+489600.0,14.929868368708632
+490200.0,14.607475440370797
+490800.0,15.52314342748367
+491400.0,15.34998882978436
+492000.0,14.780922117643566
+492600.0,14.250641120811267
+493200.0,13.800992513124456
+493800.0,14.550436920005886
+494400.0,14.673919593646453
+495000.0,14.380848561988218
+495600.0,13.511870414915826
+496200.0,14.23839118275698
+496800.0,13.990667882037318
+497400.0,13.77322839234642
+498000.0,12.294984658549977
+498600.0,13.101940575540027
+499200.0,13.589357839263691
+499800.0,13.768350964709482
+500400.0,11.750937644482967
+501000.0,12.686080556042858
+501600.0,12.765661467009036
+502200.0,12.090160975076042
+502800.0,10.151407769196574
+503400.0,11.221019650429321
+504000.0,10.935219668579052
+504600.0,11.428266933832365
+505200.0,11.835143648954938
+505800.0,11.0401788795209
+506400.0,11.976467094013085
+507000.0,11.472182114442372
+507600.0,12.719009831963714
+508200.0,12.443021573618246
+508800.0,11.367120802311169
+509400.0,11.791590752197182
+510000.0,12.833259139086397
+510600.0,12.29407463437547
+511200.0,11.995084043809948
+511800.0,13.170105295250702
+512400.0,12.439026329734485
+513000.0,13.521211219120081
+513600.0,13.267291049014618
+514200.0,13.375608859633678
+514800.0,13.198379329366055
+515400.0,12.972116476777753
+516000.0,11.447434326024311
+516600.0,9.98109995616414
+517200.0,9.020717158660494
+517800.0,9.664946959576536
+518400.0,9.572571903827372
+519000.0,9.864642152225722
+519600.0,11.87743976281585
+520200.0,12.31266697539526
+520800.0,12.139703712959683
+521400.0,10.575491614250971
+522000.0,12.530155280686191
+522600.0,11.646238915836452
+523200.0,11.245906141719503
+523800.0,9.968583446906104
+524400.0,11.138292571526959
+525000.0,10.608810607085628
+525600.0,10.174840502986479
+526200.0,8.865173521322959
+526800.0,8.116889630824627
+527400.0,8.121084888203567
+528000.0,7.5852526261512745
+528600.0,7.522493944266554
+529200.0,8.55736441213347
+529800.0,7.467941527549981
+530400.0,7.75166893299443
+531000.0,7.810957192111409
+531600.0,6.702215224363673
+532200.0,6.972319996377007
+532800.0,8.514727903535674
+533400.0,8.46766600889473
+534000.0,8.709368930249916
+534600.0,8.591482841267386
+535200.0,9.460107035178511
+535800.0,9.930541380449881
+536400.0,9.468438814110712
+537000.0,9.871032454361023
+537600.0,10.647396208317227
+538200.0,10.445213782082533
+538800.0,9.979729722621268
+539400.0,10.258342663945399
+540000.0,10.743295622445762
+540600.0,10.124423073723191
+541200.0,10.201681179444671
+541800.0,10.362536092807527
+542400.0,11.574610724178843
+543000.0,11.958484416399504
+543600.0,11.551803237114365
+544200.0,11.832649177873556
+544800.0,11.29055359053836
+545400.0,11.266102193749726
+546000.0,11.004417103973504
+546600.0,10.816772278251612
+547200.0,10.137229457109601
+547800.0,10.913505083470604
+548400.0,10.429514981942964
+549000.0,10.855499699891105
+549600.0,10.28694997437132
+550200.0,10.02412341388012
+550800.0,11.49280866590909
+551400.0,11.53422372133038
+552000.0,11.486248394936641
+552600.0,12.305272798698008
+553200.0,10.77927094751742
+553800.0,10.548695444681462
+554400.0,9.871637150720883
+555000.0,10.351719165476208
+555600.0,10.47667904948069
+556200.0,11.182425527169327
+556800.0,10.544710474404795
+557400.0,10.70841498856467
+558000.0,10.581460939794365
+558600.0,12.273326906892244
+559200.0,11.25140519321553
+559800.0,11.424865112291966
+560400.0,11.598004088760264
+561000.0,10.860301947973861
+561600.0,11.056997285168187
+562200.0,11.71213597168952
+562800.0,10.759191892814341
+563400.0,10.458209310237242
+564000.0,10.844115461523817
+564600.0,11.673921433246244
+565200.0,12.276015471168424
+565800.0,12.658291088339436
+566400.0,12.726561288924671
+567000.0,13.13040876462345
+567600.0,12.844844196895664
+568200.0,12.22817768881769
+568800.0,13.337135489310146
+569400.0,13.292326186780157
+570000.0,13.233320614965876
+570600.0,12.203713952978436
+571200.0,12.317262561198573
+571800.0,11.931192054308278
+572400.0,10.555951282756514
+573000.0,11.161227125741656
+573600.0,12.588963794452185
+574200.0,10.316537399565998
+574800.0,11.119005917665172
+575400.0,11.37041653735338
+576000.0,10.700193813138396
+576600.0,12.578741828063508
+577200.0,11.965239651929961
+577800.0,9.68488641417523
+578400.0,9.831135958834206
+579000.0,8.728348030938148
+579600.0,8.552473826260988
+580200.0,8.753634683618127
+580800.0,7.172778209737722
+581400.0,8.880539503796415
+582000.0,9.761533524482056
+582600.0,10.164238301006664
+583200.0,9.582725588369781
+583800.0,10.656206803707857
+584400.0,9.64936782697371
+585000.0,8.994166499255064
+585600.0,8.950671002946903
+586200.0,8.801920932902316
+586800.0,9.113472434191909
+587400.0,8.337223669928036
+588000.0,8.202717017865544
+588600.0,8.29499191590789
+589200.0,8.422175410401172
+589800.0,8.385538210999337
+590400.0,8.70334474991931
+591000.0,8.917066421594463
+591600.0,9.04750970900501
+592200.0,8.956557518607386
+592800.0,8.69232364561006
+593400.0,8.301872999082851
+594000.0,8.909742594683927
+594600.0,9.288600963661938
+595200.0,8.99465562965567
+595800.0,8.403198530752416
+596400.0,8.45923790400495
+597000.0,7.743251839874771
+597600.0,8.903197656273994
+598200.0,7.480304728211262
+598800.0,7.192224204711795
+599400.0,6.927860651964841
+600000.0,7.540978403775285
+600600.0,7.090101071879503
+601200.0,6.601069655613568
+601800.0,6.139168516319507
+602400.0,6.858732025743262
+603000.0,6.101332302457633
+603600.0,6.696442065659573
+604200.0,7.321298139689812
+604800.0,7.416325121646148
+605400.0,8.041363623396508
+606000.0,7.191167431740916
+606600.0,7.257677187099659
+607200.0,7.0103338446823065
+607800.0,7.808588311713642
+608400.0,6.145968800331806
+609000.0,6.866124057987657
+609600.0,6.6057950005579045
+610200.0,6.862411987362798
+610800.0,8.145399783336558
+611400.0,9.162232062568224
+612000.0,8.402999929231363
+612600.0,8.41543407304879
+613200.0,7.711134858158158
+613800.0,9.000499360546685
+614400.0,8.090487500734723
+615000.0,7.426306147633372
+615600.0,9.318751576554256
+616200.0,8.015313387876079
+616800.0,8.702121511316141
+617400.0,7.301411187681279
+618000.0,8.198026321495234
+618600.0,8.444233045845532
+619200.0,8.064598302751072
+619800.0,8.412215443515946
+620400.0,9.63229294161455
+621000.0,8.739590591235936
+621600.0,8.352139230124502
+622200.0,6.956230854156247
+622800.0,6.52705570652977
+623400.0,6.79153457421429
+624000.0,6.990798338550846
+624600.0,6.065809014247567
+625200.0,4.756151707653188
+625800.0,4.941037569012811
+626400.0,5.038616499297575
+627000.0,5.348215783696017
+627600.0,5.3859670465299505
+628200.0,6.128564336909143
+628800.0,6.95851650111279
+629400.0,6.735482966896173
+630000.0,5.533632333725032
+630600.0,7.037922153284053
+631200.0,6.919387071834178
+631800.0,6.789482269955292
+632400.0,7.119983865613903
+633000.0,7.325891283025186
+633600.0,7.400462521422881
+634200.0,7.227265515189814
+634800.0,7.697836713304513
+635400.0,7.189707528043049
+636000.0,7.01808933830518
+636600.0,7.053193699337666
+637200.0,6.898796844591499
+637800.0,7.050837680551118
+638400.0,7.50063454375066
+639000.0,7.896730076356221
+639600.0,7.521107144704233
+640200.0,7.901031980300834
+640800.0,8.81633731005456
+641400.0,7.9657236229786825
+642000.0,8.06279053395482
+642600.0,6.754236316934816
+643200.0,6.829564497637153
+643800.0,6.407791039385328
+644400.0,6.365761927205223
+645000.0,6.670499491318315
+645600.0,5.9766367763471555
+646200.0,6.919614586985683
+646800.0,7.861399273738736
+647400.0,8.188760632992592
+648000.0,8.699599689714416
+648600.0,9.794206082451236
+649200.0,10.030809692118048
+649800.0,9.841637262711556
+650400.0,10.829406157619273
+651000.0,9.864357828782518
+651600.0,10.0643958582587
+652200.0,11.007038112578767
+652800.0,9.4868606995786
+653400.0,10.05762317104904
+654000.0,11.113162332683686
+654600.0,11.711578834123285
+655200.0,10.363483707917409
+655800.0,11.064652866198305
+656400.0,9.790956249807842
+657000.0,9.823072553040445
+657600.0,9.401817495711986
+658200.0,10.749698518519358
+658800.0,11.522837192869806
+659400.0,11.476085868054128
+660000.0,13.1608781924852
+660600.0,11.390400640318003
+661200.0,11.855424529652755
+661800.0,10.531393929116119
+662400.0,10.718267597554847
+663000.0,11.153243051105997
+663600.0,10.933791587908885
+664200.0,12.09708107299153
+664800.0,11.420811583970693
+665400.0,13.165532399993825
+666000.0,12.171986103422883
+666600.0,12.4602029741036
+667200.0,13.69944889807897
+667800.0,12.812891008715724
+668400.0,14.345011207607069
+669000.0,14.581789122023297
+669600.0,15.035522128133696
+670200.0,14.950152559088384
+670800.0,14.587689983151193
+671400.0,15.086463046906104
+672000.0,15.049220457660143
+672600.0,14.972947729740607
+673200.0,14.812645842363123
+673800.0,14.057805879683663
+674400.0,14.679473457108122
+675000.0,14.300313386159662
+675600.0,14.180552774065344
+676200.0,13.878408548902172
+676800.0,14.046676942132343
+677400.0,13.628214731343826
+678000.0,13.030664766755711
+678600.0,12.957221767477721
+679200.0,12.992072312469956
+679800.0,12.590935246719381
+680400.0,11.705421351841194
+681000.0,11.974287730849712
+681600.0,12.08849869501417
+682200.0,12.461250538854364
+682800.0,11.724314914350142
+683400.0,11.74873078451085
+684000.0,11.17961209564027
+684600.0,10.340400341189746
+685200.0,9.713822309303769
+685800.0,9.875097910018724
+686400.0,9.475205434859427
+687000.0,10.008612279697436
+687600.0,9.662201381225536
+688200.0,9.595116478518666
+688800.0,9.506692577814597
+689400.0,9.253292655215656
+690000.0,9.556380077570022
+690600.0,8.783122461229064
+691200.0,10.908454452121717
+691800.0,10.136426708669498
+692400.0,10.647834307437748
+693000.0,11.934585698772459
+693600.0,12.924920595635689
+694200.0,12.515796199318887
+694800.0,13.199801550833538
+695400.0,10.843185512809447
+696000.0,10.888740522916999
+696600.0,12.097937907846585
+697200.0,12.511475942749211
+697800.0,13.110532766046145
+698400.0,13.65949802133828
+699000.0,13.266563165968762
+699600.0,13.126301073500555
+700200.0,13.77432590070568
+700800.0,13.618839717105098
+701400.0,13.911889655505595
+702000.0,13.61086036701135
+702600.0,14.748086961175796
+703200.0,14.160648271157925
+703800.0,14.881368324834666
+704400.0,15.864895155252817
+705000.0,16.370212075271457
+705600.0,15.871951365463042
+706200.0,16.42768807550952
+706800.0,15.992098633147512
+707400.0,16.04542915973629
+708000.0,15.759008669435252
+708600.0,14.829848270674118
+709200.0,14.893079496867218
+709800.0,16.395407105457938
+710400.0,16.609790572637248
+711000.0,15.695271955886058
+711600.0,16.508944085450725
+712200.0,16.49601493603033
+712800.0,17.139377469459134
+713400.0,16.72497698976561
+714000.0,16.643418627284085
+714600.0,16.880739206857715
+715200.0,16.97526948181341
+715800.0,17.3750662293461
+716400.0,17.352477953242
+717000.0,16.36569866065237
+717600.0,16.7610411674477
+718200.0,15.90765311576895
+718800.0,16.34025964442726
+719400.0,16.44681888009401
+720000.0,16.289702512190583
+720600.0,16.835661026165447
+721200.0,16.64739623041824
+721800.0,17.07088703095692
+722400.0,17.11508768866255
+723000.0,17.190846758299017
+723600.0,16.672569090704254
+724200.0,17.250844935331443
+724800.0,17.155624835071798
+725400.0,16.93904617908498
+726000.0,16.985578904511353
+726600.0,17.110726389266524
+727200.0,16.89072433950717
+727800.0,16.518203655746042
+728400.0,16.414405986728656
+729000.0,16.264457960761014
+729600.0,16.915683866861436
+730200.0,16.47521158987398
+730800.0,16.52858703957499
+731400.0,16.705456398793103
+732000.0,16.293764059453505
+732600.0,16.405353549554707
+733200.0,16.18230295866435
+733800.0,16.05235816517199
+734400.0,16.14948745028457
+735000.0,16.66020771169304
+735600.0,15.514351122586937
+736200.0,16.223598015725873
+736800.0,15.69423935548436
+737400.0,16.166914287142422
+738000.0,15.826681284087046
+738600.0,15.248320247827875
+739200.0,15.125941766042025
+739800.0,14.755528876221545
+740400.0,13.440230843767129
+741000.0,13.177906646587314
+741600.0,12.712867944836992
+742200.0,13.17763812677943
+742800.0,15.09898179985413
+743400.0,15.847755661802493
+744000.0,15.103716831792239
+744600.0,14.40476651653553
+745200.0,14.086984712904579
+745800.0,13.804281539770399
+746400.0,13.013671453999851
+747000.0,13.027603090811935
+747600.0,12.296848921378496
+748200.0,13.825068635951109
+748800.0,13.561216119901232
+749400.0,13.485208886890193
+750000.0,14.36379632800505
+750600.0,13.43735568638036
+751200.0,14.482639511255371
+751800.0,13.478341507311798
+752400.0,12.938118039791206
+753000.0,13.153256361326578
+753600.0,12.420037524084114
+754200.0,12.676118744796465
+754800.0,10.358238951435984
+755400.0,11.649977916769508
+756000.0,10.3258958114331
+756600.0,11.739766015125356
+757200.0,10.346662925554396
+757800.0,9.744218816966846
+758400.0,10.83428866252659
+759000.0,9.609834803623666
+759600.0,10.02690571788163
+760200.0,9.276685607145506
+760800.0,9.801753617916823
+761400.0,9.855726197660086
+762000.0,9.465910820555914
+762600.0,9.38414598119872
+763200.0,10.262158749446865
+763800.0,11.879998863283689
+764400.0,11.555312907766957
+765000.0,11.372131234303737
+765600.0,10.640080852393403
+766200.0,11.297511147402012
+766800.0,11.89980439290894
+767400.0,9.580682888749669
+768000.0,8.397217327201346
+768600.0,9.637040580715624
+769200.0,9.557365449574132
+769800.0,10.908150442950584
+770400.0,9.566942668985652
+771000.0,9.276171401614764
+771600.0,9.07088166190145
+772200.0,8.279354655167088
+772800.0,7.661186332854047
+773400.0,6.772155762242421
+774000.0,6.571553855134776
+774600.0,7.636478587917969
+775200.0,8.541605312911305
+775800.0,6.8514956524699375
+776400.0,6.897461708240771
+777000.0,5.926813444732908
+777600.0,6.847830623715014
+778200.0,4.476840936342661
+778800.0,5.417882877845497
+779400.0,5.109878877407218
+780000.0,6.230167402125395
+780600.0,4.945925693883651
+781200.0,6.07966549827498
+781800.0,4.92970979447906
+782400.0,5.900016710973494
+783000.0,5.632315576349726
+783600.0,6.756534035021921
+784200.0,8.077541818831742
+784800.0,5.084547054515996
+785400.0,6.4543389408356315
+786000.0,6.367580429741306
+786600.0,6.384750383888226
+787200.0,6.752397066776261
+787800.0,6.298903035502752
+788400.0,7.8232237041329125
+789000.0,9.091771127758097
+789600.0,8.423905637615489
+790200.0,6.591119701724969
+790800.0,7.175850960576459
+791400.0,7.253628825541248
+792000.0,7.13067679496212
+792600.0,7.566635977046073
+793200.0,7.043232223523335
+793800.0,5.6616029162075385
+794400.0,5.354640475581057
+795000.0,7.006748338264454
+795600.0,6.974155345875648
+796200.0,7.533050924762982
+796800.0,6.356090200322364
+797400.0,4.855853987316618
+798000.0,6.5188991596390355
+798600.0,5.756840822543663
+799200.0,5.888291418354473
+799800.0,5.552051728897223
+800400.0,4.78206021310038
+801000.0,5.465827910818204
+801600.0,5.074807341766328
+802200.0,5.038171743777276
+802800.0,6.231800726218777
+803400.0,6.148453763520564
+804000.0,5.578203664524923
+804600.0,5.415876425050896
+805200.0,5.950363074190817
+805800.0,6.252529038997017
+806400.0,6.813851766200325
+807000.0,5.700001156534662
+807600.0,5.789792869919167
+808200.0,5.682972372932541
+808800.0,4.958223700422845
+809400.0,4.636939334497657
+810000.0,4.188099492152448
+810600.0,4.627114717704453
+811200.0,4.793554501750589
+811800.0,5.614413776467435
+812400.0,5.962954662607613
+813000.0,6.441405034978885
+813600.0,7.143498655700786
+814200.0,6.483897849983428
+814800.0,6.930554862673522
+815400.0,6.156792861813224
+816000.0,5.04563212943546
+816600.0,4.32445035152223
+817200.0,5.02461960755643
+817800.0,4.847678202250836
+818400.0,4.3774789499442175
+819000.0,4.02696510382664
+819600.0,6.024201015098399
+820200.0,5.416816829927461
+820800.0,5.504614482345149
+821400.0,6.484309843493579
+822000.0,5.440920925240201
+822600.0,4.600640097105975
+823200.0,3.7272255362012165
+823800.0,4.519932001830556
+824400.0,3.5133216994856635
+825000.0,4.750188825559913
+825600.0,3.8535187465146326
+826200.0,2.914981502967209
+826800.0,3.9845543978122557
+827400.0,4.289010560123339
+828000.0,5.395982733490155
+828600.0,4.3790128896439855
+829200.0,6.4347154998895
+829800.0,6.250567898193498
+830400.0,6.859915283801001
+831000.0,8.384674617697037
+831600.0,7.354935169287338
+832200.0,7.422990234936364
+832800.0,6.937617105743793
+833400.0,7.7258681555675714
+834000.0,8.177778387740943
+834600.0,7.43188471511015
+835200.0,8.410767237964485
+835800.0,8.28506393888899
+836400.0,9.432523127184416
+837000.0,8.8943828355988
+837600.0,8.484411356750096
+838200.0,8.520261084124892
+838800.0,8.552213604091655
+839400.0,9.20646534103407
+840000.0,8.75433685195341
+840600.0,8.840914803705914
+841200.0,8.878252874711071
+841800.0,7.527700378405103
+842400.0,8.181544181907237
+843000.0,6.8170794856192165
+843600.0,8.011960245059752
+844200.0,8.183863222076095
+844800.0,7.34973389076745
+845400.0,7.1535362080711105
+846000.0,7.400165723119901
+846600.0,7.675184612102701
+847200.0,6.461302863672086
+847800.0,5.796701011427376
+848400.0,7.095319100462507
+849000.0,5.403982113835719
+849600.0,5.4248385649232995
+850200.0,5.831283709803375
+850800.0,4.857999940733022
+851400.0,4.985225332727518
+852000.0,5.841615947335904
+852600.0,5.2257646525582775
+853200.0,4.285692390266316
+853800.0,4.489549769432212
+854400.0,4.793515979380051
+855000.0,4.714789217026308
+855600.0,3.9296248293383607
+856200.0,5.915660784362029
+856800.0,6.194987843245394
+857400.0,7.6439409092864
+858000.0,6.62902129959634
+858600.0,7.539125620604889
+859200.0,8.18249209352741
+859800.0,7.852873145634651
+860400.0,7.718166246816228
+861000.0,7.681754299260056
+861600.0,6.472974943344269
+862200.0,7.84259006400511
+862800.0,9.030593339084371
+863400.0,9.309502760217239
+864000.0,9.878021743268787
+864600.0,12.015636350201119
+865200.0,10.873252272498142
+865800.0,11.097029097834634
+866400.0,12.280760449932297
+867000.0,11.99939867261219
+867600.0,12.241819344162634
+868200.0,12.926421084783925
+868800.0,12.42294786922228
+869400.0,13.563736283108778
+870000.0,13.37708088732434
+870600.0,12.10692733329256
+871200.0,13.455716438601423
+871800.0,14.734974353583812
+872400.0,15.439881710454143
+873000.0,14.277987860476761
+873600.0,14.60085429738998
+874200.0,15.11587581399647
+874800.0,15.127476584335376
+875400.0,14.69224768739337
+876000.0,12.568412383865121
+876600.0,14.420445173296658
+877200.0,14.790001462060474
+877800.0,15.1289568293372
+878400.0,15.263570914620018
+879000.0,14.304611291901725
+879600.0,14.514132843932298
+880200.0,14.196074282780334
+880800.0,14.912471275089745
+881400.0,14.978337332593352
+882000.0,15.445365141301714
+882600.0,14.818761235824354
+883200.0,14.946038762252401
+883800.0,13.902956918937415
+884400.0,14.731787322151176
+885000.0,13.964630046386658
+885600.0,15.773191473979434
+886200.0,14.637022920309118
+886800.0,14.891741625021043
+887400.0,16.056376637709196
+888000.0,14.626689405449072
+888600.0,13.813453225666647
+889200.0,12.420812609006187
+889800.0,12.293523365369522
+890400.0,12.415987255655436
+891000.0,12.149795628153347
+891600.0,11.371780761546198
+892200.0,9.20769193420426
+892800.0,10.816512561501332
+893400.0,10.581656788676659
+894000.0,10.68613402622127
+894600.0,10.171138477121525
+895200.0,9.60019452860931
+895800.0,10.047892308886128
+896400.0,9.537978529945887
+897000.0,9.412342549852594
+897600.0,8.947808799111744
+898200.0,10.004406894642496
+898800.0,9.790717012200231
+899400.0,10.74032388161002
+900000.0,9.747778283211439
+900600.0,10.638503156001642
+901200.0,10.82569788424767
+901800.0,11.578606891846663
+902400.0,12.16470124817397
+903000.0,12.128749402634993
+903600.0,11.839963699927951
+904200.0,10.867820623291427
+904800.0,11.608999711984826
+905400.0,10.932884058632458
+906000.0,10.747360642735682
+906600.0,12.06788971535482
+907200.0,11.712817972259607
+907800.0,12.896974609928472
+908400.0,12.39405981742982
+909000.0,11.367896990092232
+909600.0,11.548057366504544
+910200.0,11.988577585377168
+910800.0,13.864014616241414
+911400.0,12.653170343852986
+912000.0,13.726991294254006
+912600.0,13.574616443413763
+913200.0,13.76093562462175
+913800.0,13.934297760225164
+914400.0,13.759397751187873
+915000.0,14.008400409335405
+915600.0,13.976593703704557
+916200.0,13.738871894959164
+916800.0,14.641959444633857
+917400.0,13.668485464438263
+918000.0,14.484659052257317
+918600.0,15.45509715773936
+919200.0,15.800512221947317
+919800.0,15.809611040779284
+920400.0,15.448498262608142
+921000.0,15.880225134430672
+921600.0,14.674454061253108
+922200.0,14.532928584283956
+922800.0,14.360059039718037
+923400.0,14.336442692328085
+924000.0,15.051766507549997
+924600.0,14.991219409186415
+925200.0,13.594255998100062
+925800.0,13.84564370408509
+926400.0,14.162451802779325
+927000.0,13.834063157618353
+927600.0,13.109871658861037
+928200.0,14.129754241405674
+928800.0,14.100582068773289
+929400.0,14.149658766178398
+930000.0,12.967476852265138
+930600.0,14.142766849556324
+931200.0,13.892073562774284
+931800.0,12.963800100029934
+932400.0,12.713440716457136
+933000.0,12.225307300683
+933600.0,11.038687360492446
+934200.0,12.13046596877215
+934800.0,11.899013589942962
+935400.0,12.066352618164775
+936000.0,13.372543410676911
+936600.0,13.633672297059414
+937200.0,13.332212785403948
+937800.0,12.732232811135654
+938400.0,13.242440976694716
+939000.0,12.661718087265692
+939600.0,12.61349032842923
+940200.0,11.420551788563118
+940800.0,12.020879049788421
+941400.0,12.193226778709445
+942000.0,11.027013149512232
+942600.0,11.634498836172602
+943200.0,12.013434591375093
+943800.0,9.383732783001792
+944400.0,9.10088165455506
+945000.0,7.324061270406382
+945600.0,8.416561745213244
+946200.0,8.150859653323332
+946800.0,9.297367905043062
+947400.0,8.73260229307661
+948000.0,8.63836556664233
+948600.0,9.345230714880579
+949200.0,7.244484536455254
+949800.0,9.097541972793575
+950400.0,8.279261736242605
+951000.0,9.186739969604002
+951600.0,9.02058401391533
+952200.0,9.06264271962865
+952800.0,8.973662623604893
+953400.0,9.400526140144597
+954000.0,8.676186897395066
+954600.0,9.47377902014452
+955200.0,9.469565987456102
+955800.0,10.661357730371419
+956400.0,9.629947560504775
+957000.0,9.488811591378244
+957600.0,10.05878790747005
+958200.0,9.727822897312345
+958800.0,9.99833676084469
+959400.0,9.29783135939441
+960000.0,10.802363029389161
+960600.0,10.093353811299552
+961200.0,10.983341258594299
+961800.0,11.023062916001045
+962400.0,11.50792610626928
+963000.0,11.427879759253159
+963600.0,10.75711994284643
+964200.0,10.657336789513273
+964800.0,11.859653877781366
+965400.0,11.365754511731637
+966000.0,12.023095288088513
+966600.0,11.168672492493592
+967200.0,9.972827751977546
+967800.0,9.31226423626185
+968400.0,7.836934149241587
+969000.0,8.607587587441428
+969600.0,8.644603733375947
+970200.0,10.15562286654188
+970800.0,9.684490017040071
+971400.0,11.476402992054602
+972000.0,11.532727286451538
+972600.0,11.612443893781611
+973200.0,11.561926225623036
+973800.0,11.304231292312677
+974400.0,10.636110016653681
+975000.0,10.893021710077274
+975600.0,11.471464067321428
+976200.0,10.804388311967962
+976800.0,10.87781481307608
+977400.0,9.707540055872835
+978000.0,9.167383783446875
+978600.0,9.822270991277856
+979200.0,10.005378163928201
+979800.0,9.570958687273148
+980400.0,8.671789784425961
+981000.0,8.332093434015329
+981600.0,9.051684061405926
+982200.0,8.10187476018469
+982800.0,8.603679033066763
+983400.0,8.829365945875216
+984000.0,7.942365873057696
+984600.0,6.580984016133765
+985200.0,6.64477273549157
+985800.0,6.441828967439615
+986400.0,5.013230426081194
+987000.0,5.087906733232987
+987600.0,4.049320058130273
+988200.0,4.388595427784469
+988800.0,4.536008626958059
+989400.0,5.61740938129396
+990000.0,5.156737958245149
+990600.0,4.309233849582696
+991200.0,6.199262834597514
+991800.0,6.134005287860158
+992400.0,5.836912609840399
+993000.0,5.636221015206972
+993600.0,5.769213193599116
+994200.0,5.614490850578007
+994800.0,6.084305833208932
+995400.0,8.540411297506491
+996000.0,8.01279323781328
+996600.0,8.833625194062469
+997200.0,8.504363834206945
+997800.0,9.84564094028731
+998400.0,10.045522431049239
+999000.0,9.823968938184532
+999600.0,10.811803824552463
+1000200.0,10.226270666839289
+1000800.0,9.636464404714808
+1001400.0,8.664754187731553
+1002000.0,9.487275857126429
+1002600.0,7.868694843988993
+1003200.0,7.849668441863604
+1003800.0,7.381962068429058
+1004400.0,7.448526689191452
+1005000.0,7.410967861797091
+1005600.0,6.1741281527959435
+1006200.0,6.917108852791193
+1006800.0,7.181018539133614
+1007400.0,6.701023406750645
+1008000.0,6.112157679260188
+1008600.0,7.336078678641655
+1009200.0,6.872829689169212
+1009800.0,5.226436329994988
+1010400.0,5.086545992890114
+1011000.0,5.753298791966246
+1011600.0,7.024536621772063
+1012200.0,7.1562536221071
+1012800.0,6.071417168818236
+1013400.0,4.096406705640812
+1014000.0,5.430032736651351
+1014600.0,4.625895405993227
+1015200.0,3.6044253496546106
+1015800.0,5.270517836973343
+1016400.0,5.535146076442721
+1017000.0,5.74105064809262
+1017600.0,6.606830747889695
+1018200.0,7.498552801944904
+1018800.0,6.517508270030604
+1019400.0,5.882455471902402
+1020000.0,6.0419891204773135
+1020600.0,6.053563813946599
+1021200.0,5.654456264756217
+1021800.0,6.586797188828292
+1022400.0,6.606795854567086
+1023000.0,6.4805349403575825
+1023600.0,6.010039351195243
+1024200.0,5.240552684079364
+1024800.0,5.308303351433237
+1025400.0,6.6478475519362945
+1026000.0,6.276789254454243
+1026600.0,4.414868769822224
+1027200.0,4.406782353387884
+1027800.0,4.5404007746736434
+1028400.0,4.284864404814891
+1029000.0,3.9098008491856264
+1029600.0,3.1531475148774524
+1030200.0,2.862907870942028
+1030800.0,2.1355243001211366
+1031400.0,1.5618811477351344
+1032000.0,1.9908644591215117
+1032600.0,1.97978896661514
+1033200.0,2.224156971786639
+1033800.0,2.287138744229511
+1034400.0,1.803895768046234
+1035000.0,2.7642583281224913
+1035600.0,2.2007861371556188
+1036200.0,3.607247391647269
+1036800.0,2.472229574564864
+1037400.0,3.932122801862988
+1038000.0,3.2215796059974235
+1038600.0,4.325233013248267
+1039200.0,3.705058051576741
+1039800.0,3.606315929953251
+1040400.0,3.818895574053217
+1041000.0,3.0134261944322653
+1041600.0,3.5560607290840722
+1042200.0,4.118121427403148
+1042800.0,3.214477774188692
+1043400.0,2.8711809063172633
+1044000.0,2.893263759097042
+1044600.0,1.6906777494715102
+1045200.0,3.394714681165026
+1045800.0,3.9003361752288797
+1046400.0,4.577680105049797
+1047000.0,4.9762728149846325
+1047600.0,5.505737362485383
+1048200.0,4.973512160539525
+1048800.0,3.4128969324637453
+1049400.0,3.9530319756829386
+1050000.0,4.245608179946527
+1050600.0,4.73216930083559
+1051200.0,4.70377127616099
+1051800.0,3.9733426396771945
+1052400.0,4.406808369143771
+1053000.0,3.2943428148480973
+1053600.0,4.582953628380393
+1054200.0,4.735130141944035
+1054800.0,4.6218673929244405
+1055400.0,7.412840205963901
+1056000.0,6.647201263295163
+1056600.0,7.65523947067688
+1057200.0,6.306448388834565
+1057800.0,6.637863452197436
+1058400.0,7.2656582191529075
+1059000.0,7.810201329059311
+1059600.0,8.596161576646304
+1060200.0,8.522076989531461
+1060800.0,8.719915853124869
+1061400.0,7.973766474760548
+1062000.0,8.895254462741097
+1062600.0,8.695003302832324
+1063200.0,8.725920423204114
+1063800.0,8.77982945225196
+1064400.0,8.636019878783392
+1065000.0,8.420780214626392
+1065600.0,9.09883619823333
+1066200.0,10.173512050930075
+1066800.0,8.659293886434403
+1067400.0,8.969375404621799
+1068000.0,9.353121533242167
+1068600.0,10.089749457135344
+1069200.0,9.63921333747763
+1069800.0,10.700167044915258
+1070400.0,11.250963842549282
+1071000.0,10.196187766058658
+1071600.0,11.605572571672166
+1072200.0,11.032628025346378
+1072800.0,10.717062762835125
+1073400.0,10.654064791203815
+1074000.0,11.228974927652654
+1074600.0,11.090996359293976
+1075200.0,11.912564802558421
+1075800.0,9.816585015275878
+1076400.0,9.906976301153271
+1077000.0,8.874744023061298
+1077600.0,9.565035303339545
+1078200.0,10.366590620669685
+1078800.0,9.835839963174198
+1079400.0,9.466834850942163
+1080000.0,8.712397901801417
+1080600.0,9.440861988104192
+1081200.0,8.584090594268732
+1081800.0,8.22511378053306
+1082400.0,8.828158382247205
+1083000.0,10.282215460469374
+1083600.0,10.662041258368742
+1084200.0,10.67555699253398
+1084800.0,11.467450851534489
+1085400.0,10.905427374586175
+1086000.0,10.605492109262222
+1086600.0,11.869265589039028
+1087200.0,12.784986606653858
+1087800.0,13.17418471898112
+1088400.0,13.767286575917842
+1089000.0,13.887407624703208
+1089600.0,12.641417152785005
+1090200.0,12.472764978349806
+1090800.0,12.351987689670773
+1091400.0,11.572385953425709
+1092000.0,11.342057931234573
+1092600.0,12.348145697843496
+1093200.0,12.588012381932117
+1093800.0,12.334039128491094
+1094400.0,11.145879052954166
+1095000.0,10.866922814498055
+1095600.0,11.474397307337032
+1096200.0,10.396477388083644
+1096800.0,10.371293816976612
+1097400.0,9.325482110949078
+1098000.0,9.711224306589969
+1098600.0,10.161025752465036
+1099200.0,9.065590174950643
+1099800.0,9.312543079251194
+1100400.0,9.818206605781512
+1101000.0,9.208418493048667
+1101600.0,9.993960055346923
+1102200.0,9.167403412997277
+1102800.0,9.176654908603028
+1103400.0,8.90917010107683
+1104000.0,8.846741119726483
+1104600.0,7.404739432017859
+1105200.0,8.74068770927118
+1105800.0,7.5006208520061355
+1106400.0,7.979852804717954
+1107000.0,7.533188852389999
+1107600.0,5.99520071534562
+1108200.0,7.217487357762586
+1108800.0,7.894212727045975
+1109400.0,9.004532850655869
+1110000.0,7.851716505512993
+1110600.0,7.610492984413143
+1111200.0,8.971137390219603
+1111800.0,7.51224779065155
+1112400.0,8.46272343295736
+1113000.0,8.386676805228218
+1113600.0,8.24140061354962
+1114200.0,8.357652407055582
+1114800.0,8.723667310966283
+1115400.0,8.986061079557372
+1116000.0,9.052393467028688
+1116600.0,9.112396925194918
+1117200.0,8.685417687915843
+1117800.0,8.788214769776413
+1118400.0,8.827380376726385
+1119000.0,8.873080585797332
+1119600.0,10.45582604094841
+1120200.0,9.397757841113833
+1120800.0,10.594466324861655
+1121400.0,10.903147552200098
+1122000.0,10.010736655147907
+1122600.0,11.399780859518305
+1123200.0,10.244516815107156
+1123800.0,10.758708517676366
+1124400.0,11.038991783073303
+1125000.0,12.696377572892041
+1125600.0,12.57104463672429
+1126200.0,13.424384190255376
+1126800.0,14.282809698610263
+1127400.0,14.665523646624113
+1128000.0,14.817476407059203
+1128600.0,15.260301312784655
+1129200.0,15.709132817277553
+1129800.0,15.111233094674288
+1130400.0,15.426639899747576
+1131000.0,16.17345467834072
+1131600.0,16.35837416024256
+1132200.0,16.11619680200569
+1132800.0,16.851743256494107
+1133400.0,16.67864670689518
+1134000.0,16.65297771361609
+1134600.0,16.75927701443672
+1135200.0,16.587845121358356
+1135800.0,16.903266514718492
+1136400.0,17.05755097594353
+1137000.0,17.065679432605315
+1137600.0,17.212573328529256
+1138200.0,17.372412939743683
+1138800.0,17.52941873106373
+1139400.0,17.551165949506867
+1140000.0,17.472788059694086
+1140600.0,17.608813557723696
+1141200.0,17.58018308688986
+1141800.0,17.60163056264338
+1142400.0,17.667584753387107
+1143000.0,17.54594544492788
+1143600.0,17.504720585711837
+1144200.0,17.222848214996738
+1144800.0,17.603905930399662
+1145400.0,17.623616344116936
+1146000.0,17.455603380780865
+1146600.0,17.52206210568339
+1147200.0,17.616271513890556
+1147800.0,17.619085351952833
+1148400.0,17.55712435209666
+1149000.0,17.64122322324324
+1149600.0,17.627112022330778
+1150200.0,17.60709883163123
+1150800.0,17.56940211915248
+1151400.0,17.558450192820118
+1152000.0,17.533073678063353
+1152600.0,17.514044337376568
+1153200.0,17.474580561614218
+1153800.0,17.45255122840787
+1154400.0,17.417355503836962
+1155000.0,17.39194363325453
+1155600.0,17.347264716869553
+1156200.0,17.343655899506555
+1156800.0,17.303789406025153
+1157400.0,17.28345363033048
+1158000.0,17.20485365281727
+1158600.0,17.108966617212126
+1159200.0,17.099508589660488
+1159800.0,17.029745154576172
+1160400.0,16.89036861269749
+1161000.0,16.681649250651667
+1161600.0,15.449635102551506
+1162200.0,14.577563918482108
+1162800.0,14.66897331661215
+1163400.0,14.190404382447733
+1164000.0,14.391516850173632
+1164600.0,15.059877577045889
+1165200.0,14.040995095526135
+1165800.0,14.742842832320067
+1166400.0,13.881548598402091
+1167000.0,14.579065068326369
+1167600.0,14.177138930043617
+1168200.0,13.74628719013691
+1168800.0,14.32247970287915
+1169400.0,14.831593385012276
+1170000.0,14.278087659770492
+1170600.0,13.620035565840295
+1171200.0,14.28069954350085
+1171800.0,15.012201034636343
+1172400.0,13.941407489453011
+1173000.0,14.070731730372742
+1173600.0,12.930200311851905
+1174200.0,12.694392078164537
+1174800.0,14.66102175194708
+1175400.0,13.450190858048948
+1176000.0,13.53542237142084
+1176600.0,13.681869350074903
+1177200.0,12.713200189660006
+1177800.0,13.256099413336472
+1178400.0,13.260054905726138
+1179000.0,11.78982807164552
+1179600.0,12.224923377925235
+1180200.0,12.620475375425261
+1180800.0,12.427027587045904
+1181400.0,13.430644826623588
+1182000.0,12.353486844779214
+1182600.0,13.268813119256247
+1183200.0,13.165661037901385
+1183800.0,13.375453074989142
+1184400.0,12.44359915038493
+1185000.0,11.196090354541997
+1185600.0,11.77024056024681
+1186200.0,9.539074217054136
+1186800.0,10.131520758513776
+1187400.0,10.035522891712688
+1188000.0,9.944936808569015
+1188600.0,9.099284593964876
+1189200.0,10.043626811757417
+1189800.0,10.52658860708917
+1190400.0,11.858566884321265
+1191000.0,11.357541910437538
+1191600.0,11.10604960986275
+1192200.0,12.195537902320531
+1192800.0,12.308296975506085
+1193400.0,12.184451313430351
+1194000.0,11.696578183314491
+1194600.0,12.376871751824645
+1195200.0,11.630928377738009
+1195800.0,10.981792361581222
+1196400.0,11.280226504987331
+1197000.0,11.622226061226938
+1197600.0,11.585806816829002
+1198200.0,9.158888154565132
+1198800.0,10.422348721335126
+1199400.0,10.078157774912277
+1200000.0,10.260542747916935
+1200600.0,10.429437232727047
+1201200.0,9.787361507179325
+1201800.0,8.887920005018008
+1202400.0,8.571849313730242
+1203000.0,9.346384889952038
+1203600.0,7.779947018886678
+1204200.0,7.3151789197099335
+1204800.0,7.258534561634375
+1205400.0,8.643080353972813
+1206000.0,8.498210844925028
+1206600.0,7.475276896168824
+1207200.0,7.0002423411962
+1207800.0,7.211126425551335
+1208400.0,7.196902002837794
+1209000.0,6.751891467437805
+1209600.0,7.682066378052298
diff --git a/tests/framework/ROM/TimeSeries/ARMA/tests b/tests/framework/ROM/TimeSeries/ARMA/tests
index cb2c7e1795..f92aec46df 100644
--- a/tests/framework/ROM/TimeSeries/ARMA/tests
+++ b/tests/framework/ROM/TimeSeries/ARMA/tests
@@ -55,6 +55,7 @@
input = 'multiple_fourier.xml'
output = 'MultipleFourier/samples.csv'
csv = 'MultipleFourier/samples_0.csv'
+ zero_threshold = 1.0e-11
[../]
[./VARMA]
@@ -81,7 +82,7 @@
output = 'Segmented/synthetic.csv Segmented/synthetic_0.csv Segmented/synthetic.xml Segmented/stats.xml'
csv = 'Segmented/stats.csv'
rel_err = 1e-2
- max_time = 500 # ONLY due to 2018 Windows VDI test machine
+ os_max_time = 'Windows 500' # ONLY due to 2018 Windows VDI test machine
[../]
[]
diff --git a/tests/framework/RedundantInputs/simp_imp.py b/tests/framework/RedundantInputs/simp_imp.py
index 42b4f317e4..cc290b10d1 100644
--- a/tests/framework/RedundantInputs/simp_imp.py
+++ b/tests/framework/RedundantInputs/simp_imp.py
@@ -11,7 +11,9 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+from __future__ import division, print_function, absolute_import
import csv
+import sys
import argparse
# Build Parser
@@ -40,11 +42,14 @@
# Print to csv file
out_file_name = args.output_file + '.csv'
-print "Output will be printed to", out_file_name
-with open(out_file_name, 'wb') as wf:
- writer = csv.writer(wf, delimiter=',')
- var_name = ['a','b','c','d','e','f','g','h']
- data = [a,b,c,d,e,f,g,h]
- writer.writerow(var_name)
- writer.writerow(data)
+print("Output will be printed to", out_file_name)
+if sys.version_info[0] > 2:
+ wf = open(out_file_name, 'w', newline='')
+else:
+ wf = open(out_file_name, 'wb')
+writer = csv.writer(wf, delimiter=',')
+var_name = ['a','b','c','d','e','f','g','h']
+data = [a,b,c,d,e,f,g,h]
+writer.writerow(var_name)
+writer.writerow(data)
wf.close()
diff --git a/tests/framework/RunFailures/codeFailer.py b/tests/framework/RunFailures/codeFailer.py
index 618739e2e0..33bb26860f 100644
--- a/tests/framework/RunFailures/codeFailer.py
+++ b/tests/framework/RunFailures/codeFailer.py
@@ -15,7 +15,7 @@
infile = sys.argv[1]
-for line in file(infile,'r'):
+for line in open(infile,'r'):
if line.startswith('x ='):
x=float(line.split('=')[1])
if line.startswith('y ='):
@@ -27,7 +27,7 @@
if x+y>0:
raise RuntimeError('Answer is bigger than 0. Just a test error.')
-outfile = file(out+'.csv','w')
+outfile = open(out+'.csv','w')
outfile.writelines('x,y,ans\n')
outfile.writelines(','.join([str(x),str(y),str(x+y)]))
outfile.close()
diff --git a/tests/framework/Samplers/SparseGrid/tests b/tests/framework/Samplers/SparseGrid/tests
index 11c279b45f..1c13ef82b9 100644
--- a/tests/framework/Samplers/SparseGrid/tests
+++ b/tests/framework/Samplers/SparseGrid/tests
@@ -15,21 +15,25 @@
type = 'RavenFramework'
input = 'test_index_TP.xml'
csv = 'grid/TPdump.csv'
+ rel_err = 1.0e-7
[../]
[./totalDegreeGrid]
type = 'RavenFramework'
input = 'test_index_TD.xml'
csv = 'grid/TDdump.csv'
+ rel_err = 1.0e-7
[../]
[./hyperbolicCrossGrid]
type = 'RavenFramework'
input = 'test_index_HC.xml'
csv = 'grid/HCdump.csv'
+ rel_err = 1.0e-7
[../]
[./customGrid]
type = 'RavenFramework'
input = 'test_index_custom.xml'
csv = 'grid/Cdump.csv'
+ rel_err = 1.0e-7
[../]
[./anisotropicGrid]
type = 'RavenFramework'
diff --git a/tests/framework/TestDiffer/TestXMLDiffer.py b/tests/framework/TestDiffer/TestXMLDiffer.py
index 6dbbe09ea8..72bca5e891 100644
--- a/tests/framework/TestDiffer/TestXMLDiffer.py
+++ b/tests/framework/TestDiffer/TestXMLDiffer.py
@@ -27,6 +27,7 @@
ravenDir = os.path.dirname(os.path.dirname(os.path.dirname(scriptDir)))
sys.path.append(os.path.join(ravenDir,"scripts","TestHarness","testers"))
+sys.path.append(os.path.join(ravenDir,"rook"))
results = {"pass":0, "fail": 0}
@@ -48,31 +49,31 @@ def checkAnswer(comment,value,expected):
import xml.etree.ElementTree as ET
-same,message = XMLDiff.compareOrderedElement(ET.fromstring(""),
+same,message = XMLDiff.compare_ordered_element(ET.fromstring(""),
ET.fromstring(""))
checkAnswer("simple",same,True)
-same,message = XMLDiff.compareOrderedElement(ET.fromstring("Hello World"),
+same,message = XMLDiff.compare_ordered_element(ET.fromstring("Hello World"),
ET.fromstring("Hello World"))
checkAnswer("whitespace",same,False)
-same,message = XMLDiff.compareOrderedElement(ET.fromstring("Hello World"),
+same,message = XMLDiff.compare_ordered_element(ET.fromstring("Hello World"),
ET.fromstring("Hello World"),
remove_whitespace=True)
checkAnswer("whitespace with remove",same,True)
-same,message = XMLDiff.compareOrderedElement(ET.fromstring(""),
+same,message = XMLDiff.compare_ordered_element(ET.fromstring(""),
ET.fromstring(""))
checkAnswer("simple",same,True)
-same,message = XMLDiff.compareUnorderedElement(ET.fromstring("Hello World"),
+same,message = XMLDiff.compare_unordered_element(ET.fromstring("Hello World"),
ET.fromstring("Hello World"))
checkAnswer("whitespace unordered",same,False)
-same,message = XMLDiff.compareUnorderedElement(ET.fromstring("Hello World"),
+same,message = XMLDiff.compare_unordered_element(ET.fromstring("Hello World"),
ET.fromstring("Hello World"),
remove_whitespace=True)
diff --git a/tests/framework/hybridModel/runCode/poly_inp_io.py b/tests/framework/hybridModel/runCode/poly_inp_io.py
index 04c5371a35..9f68ac57b6 100644
--- a/tests/framework/hybridModel/runCode/poly_inp_io.py
+++ b/tests/framework/hybridModel/runCode/poly_inp_io.py
@@ -23,7 +23,7 @@ def eval(x,y):
return dat
def run(xin):
- inx = file(xin,'r')
+ inx = open(xin,'r')
for line in inx:
if line.startswith('x =' ):
x=float(line.split('=')[1])
@@ -31,14 +31,14 @@ def run(xin):
case=line.split('=')[1].strip()
elif line.startswith('auxfile ='):
aux=line.split('=')[1].strip()
- iny = file(aux,'r')
+ iny = open(aux,'r')
for line in iny:
if line.startswith('y ='):
y=float(line.split('=')[1])
dat = eval(x,y)
- outf = file(case+'.csv','w')
+ outf = open(case+'.csv','w')
outf.writelines('step,i,j,x,y,poly\n')
for e in dat:
outf.writelines(','.join(str(i) for i in e)+'\n')
diff --git a/tests/framework/tests b/tests/framework/tests
index 89acf72e29..4687cb24dc 100644
--- a/tests/framework/tests
+++ b/tests/framework/tests
@@ -2,9 +2,12 @@
[./pcaResponseSurface]
type = 'RavenFramework'
input = 'test_pca_responseSurface.xml'
- csv = 'responseSurfacePCA/BoxBehnkenRespDesign_dump.csv responseSurfacePCA/CentralCompositeRespDesign_dump.csv'
max_time = 500
- rel_err = 0.001
+ [./csv]
+ type = OrderedCSV
+ output = 'responseSurfacePCA/BoxBehnkenRespDesign_dump.csv responseSurfacePCA/CentralCompositeRespDesign_dump.csv'
+ rel_err = 0.001
+ [../]
[../]
[./simple_framework]
@@ -71,8 +74,11 @@
[./test_merge_2_databases]
type = 'RavenFramework'
input = 'test_merge_2_databases.xml'
- UnorderedCsv = 'test_merge_2_databases/Pointset_from_database_dump.csv test_merge_2_databases/Pointset_IN_database_dump.csv test_merge_2_databases/Historyset_from_database_dump_0.csv test_merge_2_databases/Historyset_from_database_dump_1.csv test_merge_2_databases/Historyset_IN_database_dump_0.csv test_merge_2_databases/Historyset_IN_database_dump_1.csv test_merge_2_databases/Historyset_IN_database_dump_2.csv test_merge_2_databases/Historyset_IN_database_dump_3.csv'
- rel_err = 0.000001
+ [./csv]
+ type = UnorderedCSV
+ output = 'test_merge_2_databases/Pointset_from_database_dump.csv test_merge_2_databases/Pointset_IN_database_dump.csv test_merge_2_databases/Historyset_from_database_dump_0.csv test_merge_2_databases/Historyset_from_database_dump_1.csv test_merge_2_databases/Historyset_IN_database_dump_0.csv test_merge_2_databases/Historyset_IN_database_dump_1.csv test_merge_2_databases/Historyset_IN_database_dump_2.csv test_merge_2_databases/Historyset_IN_database_dump_3.csv'
+ rel_err = 0.000001
+ [../]
[../]
[./test_rom_trainer_raven]
@@ -173,7 +179,12 @@
UnorderedXml = 'LHStest/outLHS_dump.xml LHStest/samples1D.xml'
max_time = 500
rel_err = 0.001
- remove_unicode_identifier = true
+ [./xml_data]
+ type = XML
+ output = 'LHStest/outLHS_dump.xml LHStest/samples1D.xml'
+ unordered = true
+ remove_unicode_identifier = true
+ [../]
[../]
[./testLHS_RELAP7]
diff --git a/tests/framework/user_guide/EnsembleModel/run_basic/ballistics.py b/tests/framework/user_guide/EnsembleModel/run_basic/ballistics.py
index 24bf715e3a..78330bc3a8 100644
--- a/tests/framework/user_guide/EnsembleModel/run_basic/ballistics.py
+++ b/tests/framework/user_guide/EnsembleModel/run_basic/ballistics.py
@@ -25,6 +25,7 @@
# (x,y) - vector positions of projectile in time
# t - corresponding time steps
#
+from __future__ import division, print_function, absolute_import
import numpy as np
def prange(v,th,y0=0,g=9.8):
@@ -117,10 +118,10 @@ def run(self,Input):
outFile = sys.argv[sys.argv.index('-o')+1]
#construct the input
Input = {}
- print ''
+ print()
for line in open(inFile,'r'):
arg,val = (a.strip() for a in line.split('='))
- print 'Setting',arg,val
+ print('Setting',arg,val)
Input[arg] = float(val)
#make a dummy class to hold values
class IO:
diff --git a/tests/reg_self_tests/col_swap.csv b/tests/reg_self_tests/col_swap.csv
new file mode 100644
index 0000000000..26755c3817
--- /dev/null
+++ b/tests/reg_self_tests/col_swap.csv
@@ -0,0 +1,3 @@
+"x","y","z"
+1.0,2.0,3.0
+3.0,2.0,5.0
diff --git a/tests/reg_self_tests/diff_col_word.csv b/tests/reg_self_tests/diff_col_word.csv
new file mode 100644
index 0000000000..e118e88e2f
--- /dev/null
+++ b/tests/reg_self_tests/diff_col_word.csv
@@ -0,0 +1,3 @@
+"x","y","z"
+1.0,2.0,"four"
+3.0,2.0,"five"
diff --git a/tests/reg_self_tests/diff_len.csv b/tests/reg_self_tests/diff_len.csv
new file mode 100644
index 0000000000..26755c3817
--- /dev/null
+++ b/tests/reg_self_tests/diff_len.csv
@@ -0,0 +1,3 @@
+"x","y","z"
+1.0,2.0,3.0
+3.0,2.0,5.0
diff --git a/tests/reg_self_tests/diff_num.csv b/tests/reg_self_tests/diff_num.csv
new file mode 100644
index 0000000000..26755c3817
--- /dev/null
+++ b/tests/reg_self_tests/diff_num.csv
@@ -0,0 +1,3 @@
+"x","y","z"
+1.0,2.0,3.0
+3.0,2.0,5.0
diff --git a/tests/reg_self_tests/diff_type.csv b/tests/reg_self_tests/diff_type.csv
new file mode 100644
index 0000000000..840935234b
--- /dev/null
+++ b/tests/reg_self_tests/diff_type.csv
@@ -0,0 +1,3 @@
+"x","y","z"
+1.0,2.0,3.0
+3.0,2.0,"five"
diff --git a/tests/reg_self_tests/diff_word.csv b/tests/reg_self_tests/diff_word.csv
new file mode 100644
index 0000000000..16618bd028
--- /dev/null
+++ b/tests/reg_self_tests/diff_word.csv
@@ -0,0 +1,3 @@
+"x","y","q"
+1.0,2.0,3.0
+3.0,2.0,5.0
diff --git a/tests/reg_self_tests/gold/col_swap.csv b/tests/reg_self_tests/gold/col_swap.csv
new file mode 100644
index 0000000000..d1055b995f
--- /dev/null
+++ b/tests/reg_self_tests/gold/col_swap.csv
@@ -0,0 +1,3 @@
+"y","x","z"
+2.0,1.0,3.0
+2.0,3.0,5.0
diff --git a/tests/reg_self_tests/gold/diff_col_word.csv b/tests/reg_self_tests/gold/diff_col_word.csv
new file mode 100644
index 0000000000..68c653b205
--- /dev/null
+++ b/tests/reg_self_tests/gold/diff_col_word.csv
@@ -0,0 +1,3 @@
+"x","y","z"
+1.0,2.0,"three"
+3.0,2.0,"five"
diff --git a/tests/reg_self_tests/gold/diff_len.csv b/tests/reg_self_tests/gold/diff_len.csv
new file mode 100644
index 0000000000..41f9e4fee7
--- /dev/null
+++ b/tests/reg_self_tests/gold/diff_len.csv
@@ -0,0 +1,4 @@
+"x","y","z"
+1.0,2.0,3.0
+3.0,2.0,5.0
+4.0,1.0,5.0
diff --git a/tests/reg_self_tests/gold/diff_num.csv b/tests/reg_self_tests/gold/diff_num.csv
new file mode 100644
index 0000000000..fc50bde61a
--- /dev/null
+++ b/tests/reg_self_tests/gold/diff_num.csv
@@ -0,0 +1,3 @@
+"x","y","z"
+1.0,2.0,3.0
+3.0,2.0,8.0
diff --git a/tests/reg_self_tests/gold/diff_type.csv b/tests/reg_self_tests/gold/diff_type.csv
new file mode 100644
index 0000000000..68c653b205
--- /dev/null
+++ b/tests/reg_self_tests/gold/diff_type.csv
@@ -0,0 +1,3 @@
+"x","y","z"
+1.0,2.0,"three"
+3.0,2.0,"five"
diff --git a/tests/reg_self_tests/gold/diff_word.csv b/tests/reg_self_tests/gold/diff_word.csv
new file mode 100644
index 0000000000..26755c3817
--- /dev/null
+++ b/tests/reg_self_tests/gold/diff_word.csv
@@ -0,0 +1,3 @@
+"x","y","z"
+1.0,2.0,3.0
+3.0,2.0,5.0
diff --git a/tests/reg_self_tests/gold/same.csv b/tests/reg_self_tests/gold/same.csv
new file mode 100644
index 0000000000..26755c3817
--- /dev/null
+++ b/tests/reg_self_tests/gold/same.csv
@@ -0,0 +1,3 @@
+"x","y","z"
+1.0,2.0,3.0
+3.0,2.0,5.0
diff --git a/tests/reg_self_tests/same.csv b/tests/reg_self_tests/same.csv
new file mode 100644
index 0000000000..4e2b83e4fd
--- /dev/null
+++ b/tests/reg_self_tests/same.csv
@@ -0,0 +1,3 @@
+"x","y","z"
+1.0,2.0,3.0
+3.0,2.0,5.000000000000001
diff --git a/tests/reg_self_tests/test_ordered_csv.py b/tests/reg_self_tests/test_ordered_csv.py
new file mode 100644
index 0000000000..a848dd94bf
--- /dev/null
+++ b/tests/reg_self_tests/test_ordered_csv.py
@@ -0,0 +1,48 @@
+"""
+This module performs unit tests for the OrderedCSVDiffer
+"""
+
+#For future compatibility with Python 3
+from __future__ import division, print_function, unicode_literals, absolute_import
+import warnings
+warnings.simplefilter('default',DeprecationWarning)
+
+import sys
+import os
+
+my_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
+base_dir = os.path.dirname(os.path.dirname(my_dir))
+
+test_system_dir = os.path.join(base_dir,"scripts","TestHarness","testers")
+print(test_system_dir)
+sys.path.append(test_system_dir)
+rook_system_dir = os.path.join(base_dir,"rook")
+sys.path.append(rook_system_dir)
+
+from OrderedCSVDiffer import OrderedCSVDiffer
+
+print(OrderedCSVDiffer)
+
+results = {"pass":0,"fail":0}
+
+for expected_same, filename in [(True,"same.csv"),
+ (True,"col_swap.csv"),
+ (False,"diff_len.csv"),
+ (False,"diff_num.csv"),
+ (False,"diff_word.csv"),
+ (False,"diff_col_word.csv"),
+ (False,"diff_type.csv")]:
+ orig = os.path.join(my_dir, filename)
+ gold = os.path.join(my_dir, "gold", filename)
+ differ = OrderedCSVDiffer([filename], [gold])
+ same, message = differ.diff()
+ print(message)
+ if expected_same != same:
+ print("Expected:",expected_same,"Got",same,"Message",message)
+ results["fail"] += 1
+ else:
+ results["pass"] += 1
+
+
+print(results)
+sys.exit(results["fail"])
diff --git a/tests/reg_self_tests/tests b/tests/reg_self_tests/tests
new file mode 100644
index 0000000000..118709a6ae
--- /dev/null
+++ b/tests/reg_self_tests/tests
@@ -0,0 +1,12 @@
+[Tests]
+ [./ordered_csv]
+ type = 'RavenPython'
+ input = 'test_ordered_csv.py'
+ [../]
+
+ [./simple_exec]
+ type = 'GenericExecutable'
+ executable = 'python'
+ parameters = '-c "print(1)"'
+ [../]
+[]