diff --git a/.github/workflows/automated-dev-tests.yml b/.github/workflows/automated-dev-tests.yml index 06ebebcf22..2b456f3292 100644 --- a/.github/workflows/automated-dev-tests.yml +++ b/.github/workflows/automated-dev-tests.yml @@ -393,7 +393,7 @@ jobs: - name: Run Interface / API tests working-directory: ${{runner.workspace}}/openfast/build run: | - ctest -VV -L "cpp|python" -j ${{env.NUM_PROCS}} + ctest -VV -L "cpp|python|fastlib" -j ${{env.NUM_PROCS}} - name: Failing test artifacts uses: actions/upload-artifact@v2 if: failure() @@ -436,7 +436,7 @@ jobs: run: | ctest -VV -j8 \ -L openfast \ - -LE "cpp|linear|python" \ + -LE "cpp|linear|python|fastlib" \ -E "5MW_OC4Semi_WSt_WavesWN|5MW_OC3Mnpl_DLL_WTurb_WavesIrr|5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth|5MW_OC3Trpd_DLL_WSt_WavesReg|5MW_Land_BD_DLL_WTurb" - name: Failing test artifacts uses: actions/upload-artifact@v2 diff --git a/cmake/OpenfastFortranOptions.cmake b/cmake/OpenfastFortranOptions.cmake index b936aed4bf..ad7d4ffc78 100644 --- a/cmake/OpenfastFortranOptions.cmake +++ b/cmake/OpenfastFortranOptions.cmake @@ -101,6 +101,7 @@ macro(set_fast_gfortran) if(NOT WIN32) set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fpic ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpic") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fpic") endif(NOT WIN32) # Fix free-form compilation for OpenFAST diff --git a/modules/hydrodyn/python-lib/hydrodyn_library.py b/modules/hydrodyn/python-lib/hydrodyn_library.py index b52e2eb74f..f9abfff7b2 100644 --- a/modules/hydrodyn/python-lib/hydrodyn_library.py +++ b/modules/hydrodyn/python-lib/hydrodyn_library.py @@ -421,6 +421,7 @@ def check_error(self): def check_input_motions(self,nodePos,nodeVel,nodeAcc): # make sure number of nodes didn't change for some reason if self._initNumNodePts != self.numNodePts: + # @ANDY TODO: `time` is not available here so this would be a runtime error print(f"At time {time}, the number of node points changed from initial value of {self._initNumNodePts}. This is not permitted during the simulation.") self.hydrodyn_end() raise Exception("\nError in calling HydroDyn library.") @@ -594,7 +595,7 @@ def __init__(self,filename,chan_names,chan_units): # write file header t_string=datetime.datetime.now() dt_string=datetime.date.today() - self.OutFile.write(f"## This file was generated by InflowWind_Driver on {dt_string.strftime('%b-%d-%Y')} at {t_string.strftime('%H:%M:%S')}\n") + self.OutFile.write(f"## This file was generated by HydroDyn_Driver on {dt_string.strftime('%b-%d-%Y')} at {t_string.strftime('%H:%M:%S')}\n") self.OutFile.write(f"## This file contains output channels requested from the OutList section of the input file") self.OutFile.write(f"{filename}\n") self.OutFile.write("#\n") diff --git a/modules/inflowwind/python-lib/inflowwind_library.py b/modules/inflowwind/python-lib/inflowwind_library.py index 2a2d7e74ef..26e6eb599a 100644 --- a/modules/inflowwind/python-lib/inflowwind_library.py +++ b/modules/inflowwind/python-lib/inflowwind_library.py @@ -255,17 +255,19 @@ def __init__(self, filename, numWindPts): t_string=datetime.datetime.now() dt_string=datetime.date.today() self.debug_file.write(f"## This file was generated by InflowWind_Driver on {dt_string.strftime('%b-%d-%Y')} at {t_string.strftime('%H:%M:%S')}{os.linesep}") - self.debug_file.write(f"## This file contains the wind velocity at the {numWindPts} points specified in the file ") - self.debug_file.write(f"{filename}{os.linesep}") - self.debug_file.write(f"#{os.linesep}") - self.debug_file.write(f"# T X Y Z U V W{os.linesep}") - self.debug_file.write(f"# (s) (m) (m) (m) (m/s) (m/s) (m/s){os.linesep}") + self.debug_file.write(f"## This file contains the wind velocity at the {numWindPts} points specified in the file {filename}{os.linesep}") + self.debug_file.write(f"# {os.linesep}") + self.debug_file.write(f"# {os.linesep}") + self.debug_file.write(f"# {os.linesep}") + self.debug_file.write(f"# {os.linesep}") + self.debug_file.write(f" T X Y Z U V W{os.linesep}") + self.debug_file.write(f" (s) (m) (m) (m) (m/s) (m/s) (m/s){os.linesep}") self.opened = True def write(self,t,positions,velocities): for p, v in zip(positions,velocities): # TODO: does \n work as expected on Windows? - self.debug_file.write(' %14.7f %14.7f %14.7f %14.7f %14.7f %14.7f %14.7f\n' % (t,p[0],p[1],p[2],v[0],v[1],v[2])) + self.debug_file.write(' %16.8f %16.8f %16.8f %16.8f %16.8f %16.8f %16.8f\n' % (t,p[0],p[1],p[2],v[0],v[1],v[2])) def end(self): if self.opened: diff --git a/modules/inflowwind/src/InflowWind_Driver_Subs.f90 b/modules/inflowwind/src/InflowWind_Driver_Subs.f90 index c10193ae68..b6edb09f42 100644 --- a/modules/inflowwind/src/InflowWind_Driver_Subs.f90 +++ b/modules/inflowwind/src/InflowWind_Driver_Subs.f90 @@ -2343,10 +2343,11 @@ SUBROUTINE PointsVel_OutputWrite (FileUnit, FileName, Initialized, Settings, Gri INTEGER(IntKi) :: LenErrMsgTmp !< Length of ErrMsgTmp (for getting WindGrid info) INTEGER(IntKi) :: I !< Generic counter - CHARACTER(61) :: PointsVelFmt !< Format specifier for the output file for wave elevation series + CHARACTER(61) :: NameUnitFmt !< Format specifier for the output file for channel names and units + CHARACTER(61) :: PointsVelFmt !< Format specifier for the output file for wind point location and velocity - - PointsVelFmt = "(F14.7,3x,F14.7,3x,F14.7,3x,F14.7,3x,F14.7,3x,F14.7,3x,F14.7)" + NameUnitFmt = "( 7(A16, 3X) )" + PointsVelFmt = "( 7(F16.8, 3X) )" ErrMsg = '' ErrStat = ErrID_None @@ -2371,15 +2372,16 @@ SUBROUTINE PointsVel_OutputWrite (FileUnit, FileName, Initialized, Settings, Gri TRIM(Num2LStr(SIZE(GridXYZ,DIM=2)))//' points specified in the '// & 'file '//TRIM(Settings%PointsFileName)//'.' WRITE (FileUnit,'(A)', IOSTAT=ErrStatTmp ) '# ' - WRITE (FileUnit,'(A)', IOSTAT=ErrStatTmp ) '# T X Y Z '// & - ' U V W' - WRITE (FileUnit,'(A)', IOSTAT=ErrStatTmp ) '# (s) (m) (m) (m) '// & - ' (m/s) (m/s) (m/s)' + WRITE (FileUnit,'(A)', IOSTAT=ErrStatTmp ) '# ' + WRITE (FileUnit,'(A)', IOSTAT=ErrStatTmp ) '# ' + WRITE (FileUnit,'(A)', IOSTAT=ErrStatTmp ) '# ' + WRITE (FileUnit, NameUnitFmt, IOSTAT=ErrStatTmp ) 'T', 'X', 'Y', 'Z', 'U', 'V', 'W' + WRITE (FileUnit, NameUnitFmt, IOSTAT=ErrStatTmp ) '(s)', '(m)', '(m)', '(m)', '(m/s)', '(m/s)', '(m/s)' ELSE DO I = 1,SIZE(GridXYZ,DIM=2) - WRITE (FileUnit,PointsVelFmt, IOSTAT=ErrStatTmp ) TIME,GridXYZ(1,I),GridXYZ(2,I),GridXYZ(3,I),GridVel(1,I),GridVel(2,I),GridVel(3,I) + WRITE (FileUnit, PointsVelFmt, IOSTAT=ErrStatTmp ) TIME, GridXYZ(1,I), GridXYZ(2,I), GridXYZ(3,I), GridVel(1,I), GridVel(2,I), GridVel(3,I) ENDDO diff --git a/reg_tests/CMakeLists.txt b/reg_tests/CMakeLists.txt index 38451a4247..50c5857687 100644 --- a/reg_tests/CMakeLists.txt +++ b/reg_tests/CMakeLists.txt @@ -37,31 +37,33 @@ option(CTEST_PLOT_ERRORS "Generate plots of regression test errors." OFF) # Do not display outputs when running openfast, store in log file option(CTEST_RUN_VERBOSE_FLAG "Display run outputs or store to log file." OFF) +option(CTEST_NO_RUN_FLAG "Complete the regression test comparison but do not execute the simulation. Local results must already be generated." OFF) + # Set the OpenFAST executable configuration option and default -set(CTEST_OPENFAST_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast/openfast" CACHE FILEPATH "Specify the OpenFAST executable to use in testing.") +set(CTEST_OPENFAST_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast/openfast${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Specify the OpenFAST executable to use in testing.") if(BUILD_OPENFAST_CPP_API) # Set the OpenFAST executable configuration option and default - set(CTEST_OPENFASTCPP_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast-cpp/openfastcpp" CACHE FILEPATH "Specify the OpenFAST C++ executable to use in testing.") + set(CTEST_OPENFASTCPP_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast-cpp/openfastcpp${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Specify the OpenFAST C++ executable to use in testing.") endif() # Set the FASTFarm executable configuration option and default -set(CTEST_FASTFARM_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/fast-farm/FAST.Farm" CACHE FILEPATH "Specify the FASTFarm executable to use in testing.") +set(CTEST_FASTFARM_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/fast-farm/FAST.Farm${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Specify the FASTFarm executable to use in testing.") # Set the AeroDyn executable configuration option and default set(CTEST_AERODYN_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/aerodyn/aerodyn_driver${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Specify the AeroDyn driver executable to use in testing.") # Set the BeamDyn executable configuration option and default -set(CTEST_BEAMDYN_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/beamdyn/beamdyn_driver" CACHE FILEPATH "Specify the BeamDyn driver executable to use in testing.") +set(CTEST_BEAMDYN_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/beamdyn/beamdyn_driver${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Specify the BeamDyn driver executable to use in testing.") # Set the HydroDyn executable configuration option and default -set(CTEST_HYDRODYN_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/hydrodyn/hydrodyn_driver" CACHE FILEPATH "Specify the HydroDyn driver executable to use in testing.") +set(CTEST_HYDRODYN_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/hydrodyn/hydrodyn_driver${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Specify the HydroDyn driver executable to use in testing.") # Set the SubDyn executable configuration option and default -set(CTEST_SUBDYN_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/subdyn/subdyn_driver" CACHE FILEPATH "Specify the SubDyn driver executable to use in testing.") +set(CTEST_SUBDYN_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/subdyn/subdyn_driver${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Specify the SubDyn driver executable to use in testing.") # Set the InflowWind executable configuration option and default -set(CTEST_INFLOWWIND_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/inflowwind/inflowwind_driver" CACHE FILEPATH "Specify the InflowWind driver executable to use in testing.") +set(CTEST_INFLOWWIND_EXECUTABLE "${CMAKE_BINARY_DIR}/modules/inflowwind/inflowwind_driver${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Specify the InflowWind driver executable to use in testing.") # Set the python executable configuration option and default if(NOT EXISTS ${PYTHON_EXECUTABLE}) @@ -72,12 +74,8 @@ if(NOT EXISTS ${PYTHON_EXECUTABLE}) endif() # Set the testing tolerance -set(CTEST_REGRESSION_TOL "0.00001" CACHE STRING "Set the tolerance for the regression test. Leave empty to automatically set.") -if(NOT ${CTEST_REGRESSION_TOL} STREQUAL "") - set(TOLERANCE ${CTEST_REGRESSION_TOL}) -else(NOT ${CTEST_REGRESSION_TOL} STREQUAL "") - set(TOLERANCE 0.00001) -endif() +set(CTEST_RTEST_RTOL "2" CACHE STRING "Sets the relative orders of magnitude to allow to deviate from the baseline.") +set(CTEST_RTEST_ATOL "1.9" CACHE STRING "Set the absolute orders of magnitude to consider as testable values; any deviations smaller than this always pass.") # include the r-test cmake projects (servodyn controllers) add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/r-test") diff --git a/reg_tests/CTestList.cmake b/reg_tests/CTestList.cmake index 7542433367..e9cc11d52e 100644 --- a/reg_tests/CTestList.cmake +++ b/reg_tests/CTestList.cmake @@ -49,6 +49,11 @@ function(regression TEST_SCRIPT EXECUTABLE SOURCE_DIRECTORY BUILD_DIRECTORY TEST set(TESTDIR ${extra_args}) endif() + set(NO_RUN_FLAG "") + if(CTEST_NO_RUN_FLAG) + set(NO_RUN_FLAG "-n") + endif() + add_test( ${TESTNAME} ${PYTHON_EXECUTABLE} ${TEST_SCRIPT} @@ -56,11 +61,11 @@ function(regression TEST_SCRIPT EXECUTABLE SOURCE_DIRECTORY BUILD_DIRECTORY TEST ${EXECUTABLE} ${SOURCE_DIRECTORY} # openfast source directory ${BUILD_DIRECTORY} # build directory for test - ${TOLERANCE} - ${CMAKE_SYSTEM_NAME} # [Darwin,Linux,Windows] - ${CMAKE_Fortran_COMPILER_ID} # [Intel,GNU] + ${CTEST_RTEST_RTOL} + ${CTEST_RTEST_ATOL} ${PLOT_FLAG} # empty or "-p" ${RUN_VERBOSE_FLAG} # empty or "-v" + ${NO_RUN_FLAG} # empty or "-n" ) # limit each test to 90 minutes: 5400s set_tests_properties(${TESTNAME} PROPERTIES TIMEOUT 5400 WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" LABELS "${LABEL}") @@ -79,13 +84,13 @@ function(of_regression TESTNAME LABEL) regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") endfunction(of_regression) -function(of_cpp_regression TESTNAME LABEL) +function(of_fastlib_regression TESTNAME LABEL) set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeOpenfastRegressionCase.py") set(OPENFAST_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast/openfast_cpp") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/glue-codes/openfast") - regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} "${TESTNAME}_cpp" "${LABEL}" ${TESTNAME}) -endfunction(of_cpp_regression) + regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} "${TESTNAME}_fastlib" "${LABEL}" ${TESTNAME}) +endfunction(of_fastlib_regression) # openfast aeroacoustic function(of_regression_aeroacoustic TESTNAME LABEL) @@ -216,19 +221,19 @@ of_regression("AWT_WSt_StartUpShutDown" "openfast;elastodyn;aerodyn15;se of_regression("AOC_WSt" "openfast;elastodyn;aerodyn14;servodyn") of_regression("AOC_YFree_WTurb" "openfast;elastodyn;aerodyn15;servodyn") of_regression("AOC_YFix_WSt" "openfast;elastodyn;aerodyn15;servodyn") -of_regression("UAE_Dnwind_YRamp_WSt" "openfast;elastodyn;aerodyn14;servodyn") +# of_regression("UAE_Dnwind_YRamp_WSt" "openfast;elastodyn;aerodyn14;servodyn") of_regression("UAE_Upwind_Rigid_WRamp_PwrCurve" "openfast;elastodyn;aerodyn15;servodyn") of_regression("WP_VSP_WTurb_PitchFail" "openfast;elastodyn;aerodyn14;servodyn") of_regression("WP_VSP_ECD" "openfast;elastodyn;aerodyn15;servodyn") of_regression("WP_VSP_WTurb" "openfast;elastodyn;aerodyn15;servodyn") of_regression("SWRT_YFree_VS_EDG01" "openfast;elastodyn;aerodyn15;servodyn") of_regression("SWRT_YFree_VS_EDC01" "openfast;elastodyn;aerodyn14;servodyn") -of_regression("SWRT_YFree_VS_WTurb" "openfast;elastodyn;aerodyn14;servodyn") +# of_regression("SWRT_YFree_VS_WTurb" "openfast;elastodyn;aerodyn14;servodyn") of_regression("5MW_Land_DLL_WTurb" "openfast;elastodyn;aerodyn15;servodyn") of_regression("5MW_OC3Mnpl_DLL_WTurb_WavesIrr" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;subdyn;offshore") of_regression("5MW_OC3Trpd_DLL_WSt_WavesReg" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;subdyn;offshore") -of_regression("5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;subdyn;offshore") -of_regression("5MW_ITIBarge_DLL_WTurb_WavesIrr" "openfast;elastodyn;aerodyn14;servodyn;hydrodyn;map;offshore") +# of_regression("5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;subdyn;offshore") +# of_regression("5MW_ITIBarge_DLL_WTurb_WavesIrr" "openfast;elastodyn;aerodyn14;servodyn;hydrodyn;map;offshore") of_regression("5MW_TLP_DLL_WTurb_WavesIrr_WavesMulti" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;map;offshore") of_regression("5MW_OC3Spar_DLL_WTurb_WavesIrr" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;map;offshore") of_regression("5MW_OC4Semi_WSt_WavesWN" "openfast;elastodyn;aerodyn15;servodyn;hydrodyn;moordyn;offshore") @@ -240,27 +245,22 @@ of_regression("StC_test_OC4Semi" "openfast;servodyn;hydrod # OpenFAST C++ API test if(BUILD_OPENFAST_CPP_API) - of_cpp_interface_regression("5MW_Land_DLL_WTurb_cpp" "openfast;openfastlib;cpp") + of_cpp_interface_regression("5MW_Land_DLL_WTurb_cpp" "openfast;fastlib;cpp") endif() -# # Python-based OpenFAST Library unit tests -# if(BUILD_SHARED_LIBS) -# py_openfast_library_regression("py_openfastlib" "python;openfastlib") -# endif() - -# OpenFAST C++ Driver test +# OpenFAST C++ Driver test for OpenFAST Library # This tests the FAST Library and FAST_Library.h -of_cpp_regression("AWT_YFree_WSt" "openfast;openfastlib;cpp;elastodyn;aerodyn15;servodyn") +of_fastlib_regression("AWT_YFree_WSt" "fastlib;elastodyn;aerodyn15;servodyn") # OpenFAST Python API test -of_regression_py("5MW_Land_DLL_WTurb_py" "openfast;openfastlib;python;elastodyn;aerodyn15;servodyn") -of_regression_py("5MW_ITIBarge_DLL_WTurb_WavesIrr_py" "openfast;openfastlib;python;elastodyn;aerodyn14;servodyn;hydrodyn;map;offshore") -of_regression_py("5MW_TLP_DLL_WTurb_WavesIrr_WavesMulti_py" "openfast;openfastlib;python;elastodyn;aerodyn15;servodyn;hydrodyn;map;offshore") -of_regression_py("5MW_OC3Spar_DLL_WTurb_WavesIrr_py" "openfast;openfastlib;python;elastodyn;aerodyn15;servodyn;hydrodyn;map;offshore") -of_regression_py("5MW_OC4Semi_WSt_WavesWN_py" "openfast;openfastlib;python;elastodyn;aerodyn15;servodyn;hydrodyn;moordyn;offshore") -of_regression_py("5MW_Land_BD_DLL_WTurb_py" "openfast;openfastlib;python;beamdyn;aerodyn15;servodyn") -of_regression_py("HelicalWake_OLAF_py" "openfast;openfastlib;python;aerodyn15;olaf") -of_regression_py("EllipticalWing_OLAF_py" "openfast;openfastlib;python;aerodyn15;olaf") +of_regression_py("5MW_Land_DLL_WTurb_py" "openfast;fastlib;python;elastodyn;aerodyn15;servodyn") +of_regression_py("5MW_ITIBarge_DLL_WTurb_WavesIrr_py" "openfast;fastlib;python;elastodyn;aerodyn14;servodyn;hydrodyn;map;offshore") +of_regression_py("5MW_TLP_DLL_WTurb_WavesIrr_WavesMulti_py" "openfast;fastlib;python;elastodyn;aerodyn15;servodyn;hydrodyn;map;offshore") +of_regression_py("5MW_OC3Spar_DLL_WTurb_WavesIrr_py" "openfast;fastlib;python;elastodyn;aerodyn15;servodyn;hydrodyn;map;offshore") +of_regression_py("5MW_OC4Semi_WSt_WavesWN_py" "openfast;fastlib;python;elastodyn;aerodyn15;servodyn;hydrodyn;moordyn;offshore") +of_regression_py("5MW_Land_BD_DLL_WTurb_py" "openfast;fastlib;python;beamdyn;aerodyn15;servodyn") +of_regression_py("HelicalWake_OLAF_py" "openfast;fastlib;python;aerodyn15;olaf") +of_regression_py("EllipticalWing_OLAF_py" "openfast;fastlib;python;aerodyn15;olaf") # AeroAcoustic regression test of_regression_aeroacoustic("IEA_LB_RWT-AeroAcoustics" "openfast;aerodyn15;aeroacoustics") @@ -306,6 +306,7 @@ bd_regression("bd_static_twisted_with_k1" "beamdyn;static") hd_regression("hd_OC3tripod_offshore_fixedbottom_wavesirr" "hydrodyn;offshore") hd_regression("hd_5MW_ITIBarge_DLL_WTurb_WavesIrr" "hydrodyn;offshore") hd_regression("hd_5MW_OC3Spar_DLL_WTurb_WavesIrr" "hydrodyn;offshore") +hd_regression("hd_5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth" "hydrodyn;offshore") hd_regression("hd_5MW_OC4Semi_WSt_WavesWN" "hydrodyn;offshore") hd_regression("hd_5MW_TLP_DLL_WTurb_WavesIrr_WavesMulti" "hydrodyn;offshore") hd_regression("hd_TaperCylinderPitchMoment" "hydrodyn;offshore") diff --git a/reg_tests/executeAerodynRegressionCase.py b/reg_tests/executeAerodynRegressionCase.py index 1462914737..70c1899a97 100644 --- a/reg_tests/executeAerodynRegressionCase.py +++ b/reg_tests/executeAerodynRegressionCase.py @@ -27,6 +27,7 @@ basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse +import numpy as np import shutil import glob import subprocess @@ -46,9 +47,8 @@ parser.add_argument("executable", metavar="AeroDyn-Driver", type=str, nargs=1, help="The path to the AeroDyn driver executable.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") parser.add_argument("-p", "-plot", dest="plot", action='store_true', help="bool to include plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', help="bool to include verbose system output") @@ -59,9 +59,8 @@ executable = args.executable[0] sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] - - +rtol = args.rtol[0] +atol = args.atol[0] plotError = args.plot noExec = args.noExec verbose = args.verbose @@ -112,44 +111,45 @@ if returnCode != 0: rtl.exitWithError("") -###Build the filesystem navigation variables for running the regression test +### Build the filesystem navigation variables for running the regression test # For multiple turbines, test turbine 2, for combined cases, test case 4 localOutFile = os.path.join(testBuildDirectory, "ad_driver.outb") localOutFileWT2 = os.path.join(testBuildDirectory, "ad_driver.T2.outb") localOutFileCase4 = os.path.join(testBuildDirectory, "ad_driver.4.outb") if os.path.exists(localOutFileWT2) : - localOutFile=localOutFileWT2 + localOutFile = localOutFileWT2 elif os.path.exists(localOutFileCase4) : - localOutFile=localOutFileCase4 + localOutFile = localOutFileCase4 baselineOutFile = os.path.join(targetOutputDirectory, os.path.basename(localOutFile)) + rtl.validateFileOrExit(localOutFile) rtl.validateFileOrExit(baselineOutFile) -testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +testData, testInfo, _ = pass_fail.readFASTOut(localOutFile) baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) -performance = pass_fail.calculateNorms(testData, baselineData) -normalizedNorm = performance[:, 1] + +passing_channels = pass_fail.passing_channels(testData.T, baselineData.T, rtol, atol) +passing_channels = passing_channels.T + +norms = pass_fail.calculateNorms(testData, baselineData) # export all case summaries -results = list(zip(testInfo["attribute_names"], [*performance])) -results_max = performance.max(axis=0) -exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) +channel_names = testInfo["attribute_names"] +exportCaseSummary(testBuildDirectory, caseName, channel_names, passing_channels, norms) -# failing case -if not pass_fail.passRegressionTest(normalizedNorm, tolerance): - if plotError: - from errorPlotting import finalizePlotDirectory, plotOpenfastError - ixFailChannels = [i for i in range(len(testInfo["attribute_names"])) if normalizedNorm[i] > tolerance] - failChannels = [channel for i, channel in enumerate(testInfo["attribute_names"]) if i in ixFailChannels] - failResults = [res for i, res in enumerate(results) if i in ixFailChannels] - for channel in failChannels: - try: - plotOpenfastError(localOutFile, baselineOutFile, channel) - except: - error = sys.exc_info()[1] - print("Error generating plots: {}".format(error.msg)) - finalizePlotDirectory(localOutFile, failChannels, caseName) - sys.exit(1) - # passing case -sys.exit(0) +if np.all(passing_channels): + sys.exit(0) + +# failing case +if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel, rtol, atol) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + +sys.exit(1) diff --git a/reg_tests/executeBeamdynRegressionCase.py b/reg_tests/executeBeamdynRegressionCase.py index 93dbc01f74..6ba0f5ec84 100644 --- a/reg_tests/executeBeamdynRegressionCase.py +++ b/reg_tests/executeBeamdynRegressionCase.py @@ -27,6 +27,7 @@ basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse +import numpy as np import shutil import subprocess import rtestlib as rtl @@ -45,9 +46,8 @@ parser.add_argument("executable", metavar="BeamDyn-Driver", type=str, nargs=1, help="The path to the BeamDyn driver executable.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") parser.add_argument("-p", "-plot", dest="plot", action='store_true', help="bool to include plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', help="bool to include verbose system output") @@ -58,7 +58,8 @@ executable = args.executable[0] sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] +rtol = args.rtol[0] +atol = args.atol[0] plotError = args.plot if args.plot is False else True noExec = args.noExec if args.noExec is False else True verbose = args.verbose if args.verbose is False else True @@ -107,31 +108,31 @@ rtl.validateFileOrExit(localOutFile) rtl.validateFileOrExit(baselineOutFile) -testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +testData, testInfo, _ = pass_fail.readFASTOut(localOutFile) baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) -performance = pass_fail.calculateNorms(testData, baselineData) -normalizedNorm = performance[:, 1] + +passing_channels = pass_fail.passing_channels(testData.T, baselineData.T, rtol, atol) +passing_channels = passing_channels.T + +norms = pass_fail.calculateNorms(testData, baselineData) # export all case summaries -results = list(zip(testInfo["attribute_names"], [*performance])) -results_max = performance.max(axis=0) -exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) +channel_names = testInfo["attribute_names"] +exportCaseSummary(testBuildDirectory, caseName, channel_names, passing_channels, norms) -# failing case -if not pass_fail.passRegressionTest(normalizedNorm, tolerance): - if plotError: - from errorPlotting import finalizePlotDirectory, plotOpenfastError - ixFailChannels = [i for i in range(len(testInfo["attribute_names"])) if normalizedNorm[i] > tolerance] - failChannels = [channel for i, channel in enumerate(testInfo["attribute_names"]) if i in ixFailChannels] - failResults = [res for i, res in enumerate(results) if i in ixFailChannels] - for channel in failChannels: - try: - plotOpenfastError(localOutFile, baselineOutFile, channel) - except: - error = sys.exc_info()[1] - print("Error generating plots: {}".format(error.msg)) - finalizePlotDirectory(localOutFile, failChannels, caseName) - sys.exit(1) - # passing case -sys.exit(0) +if np.all(passing_channels): + sys.exit(0) + +# failing case +if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel, rtol, atol) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + +sys.exit(1) diff --git a/reg_tests/executeFASTFarmRegressionCase.py b/reg_tests/executeFASTFarmRegressionCase.py index 273637bb46..80ecac15f7 100644 --- a/reg_tests/executeFASTFarmRegressionCase.py +++ b/reg_tests/executeFASTFarmRegressionCase.py @@ -27,6 +27,7 @@ basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse +import numpy as np import shutil import subprocess import rtestlib as rtl @@ -54,9 +55,8 @@ def ignoreBaselineItems(directory, contents): parser.add_argument("executable", metavar="OpenFAST", type=str, nargs=1, help="The path to the OpenFAST executable.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") parser.add_argument("-p", "-plot", dest="plot", action='store_true', help="bool to include plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', help="bool to include verbose system output") @@ -67,9 +67,8 @@ def ignoreBaselineItems(directory, contents): executable = args.executable[0] sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] -systemName = args.systemName[0] -compilerId = args.compilerId[0] +rtol = args.rtol[0] +atol = args.atol[0] plotError = args.plot noExec = args.noExec verbose = args.verbose @@ -80,25 +79,6 @@ def ignoreBaselineItems(directory, contents): if not os.path.isdir(buildDirectory): os.makedirs(buildDirectory) -### Map the system and compiler configurations to a solution set -# Internal names -> Human readable names -systemName_map = { - "darwin": "macos", - "linux": "linux", - "windows": "windows" -} -compilerId_map = { - "gnu": "gnu", - "intel": "intel" -} -# Build the target output directory name or choose the default -supportedBaselines = ["macos-gnu", "linux-intel", "linux-gnu", "windows-intel"] -targetSystem = systemName_map.get(systemName.lower(), "") -targetCompiler = compilerId_map.get(compilerId.lower(), "") -outputType = os.path.join(targetSystem+"-"+targetCompiler) -if outputType not in supportedBaselines: - outputType = supportedBaselines[0] -print("-- Using gold standard files with machine-compiler type {}".format(outputType)) ### Build the filesystem navigation variables for running openfast on the test case regtests = os.path.join(sourceDirectory, "reg_tests") @@ -106,7 +86,7 @@ def ignoreBaselineItems(directory, contents): rtest = os.path.join(regtests, "r-test") moduleDirectory = os.path.join(rtest, "glue-codes", "fast-farm") inputsDirectory = os.path.join(moduleDirectory, caseName) -targetOutputDirectory = os.path.join(inputsDirectory) #, outputType) +targetOutputDirectory = os.path.join(inputsDirectory) testBuildDirectory = os.path.join(buildDirectory, caseName) # verify all the required directories exist @@ -151,29 +131,31 @@ def ignoreBaselineItems(directory, contents): rtl.validateFileOrExit(localOutFile) rtl.validateFileOrExit(baselineOutFile) -testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +testData, testInfo, _ = pass_fail.readFASTOut(localOutFile) baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) -performance = pass_fail.calculateNorms(testData, baselineData) -normalizedNorm = performance[:, 1] -# export all case summaries -results = list(zip(testInfo["attribute_names"], [*performance])) -results_max = performance.max(axis=0) -exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) +passing_channels = pass_fail.passing_channels(testData.T, baselineData.T, rtol, atol) +passing_channels = passing_channels.T -# failing case -if not pass_fail.passRegressionTest(normalizedNorm, tolerance): - if plotError: - from errorPlotting import finalizePlotDirectory, plotOpenfastError - for channel in testInfo["attribute_names"]: - try: - plotOpenfastError(localOutFile, baselineOutFile, channel) - except: - error = sys.exc_info()[1] - print("Error generating plots: {}".format(error)) - finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) - - sys.exit(1) +norms = pass_fail.calculateNorms(testData, baselineData) + +# export all case summaries +channel_names = testInfo["attribute_names"] +exportCaseSummary(testBuildDirectory, caseName, channel_names, passing_channels, norms) # passing case -sys.exit(0) +if np.all(passing_channels): + sys.exit(0) + +# failing case +if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel, rtol, atol) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + +sys.exit(1) diff --git a/reg_tests/executeHydrodynPyRegressionCase.py b/reg_tests/executeHydrodynPyRegressionCase.py index 6f8107cd4a..b2eaa7f864 100644 --- a/reg_tests/executeHydrodynPyRegressionCase.py +++ b/reg_tests/executeHydrodynPyRegressionCase.py @@ -24,9 +24,10 @@ import os import sys -basepath = os.path.dirname(__file__) +basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse +import numpy as np import shutil import glob import subprocess @@ -46,9 +47,8 @@ parser.add_argument("executable", metavar="HydroDyn-Python", type=str, nargs=1, help="The path to the Python executable.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") parser.add_argument("-p", "-plot", dest="plot", default=False, metavar="Plotting-Flag", type=bool, nargs="?", help="bool to include matplotlib plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", default=False, metavar="No-Execution", type=bool, nargs="?", help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", default=False, metavar="Verbose-Flag", type=bool, nargs="?", help="bool to include verbose system output") @@ -59,7 +59,8 @@ executable = args.executable[0] sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] +rtol = args.rtol[0] +atol = args.atol[0] plotError = args.plot if args.plot is False else True noExec = args.noExec if args.noExec is False else True verbose = args.verbose if args.verbose is False else True @@ -114,31 +115,31 @@ rtl.validateFileOrExit(localOutFile) rtl.validateFileOrExit(baselineOutFile) -testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +testData, testInfo, _ = pass_fail.readFASTOut(localOutFile) baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) -performance = pass_fail.calculateNorms(testData, baselineData) -normalizedNorm = performance[:, 1] + +passing_channels = pass_fail.passing_channels(testData.T, baselineData.T, rtol, atol) +passing_channels = passing_channels.T + +norms = pass_fail.calculateNorms(testData, baselineData) # export all case summaries -results = list(zip(testInfo["attribute_names"], [*performance])) -results_max = performance.max(axis=0) -exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) +channel_names = testInfo["attribute_names"] +exportCaseSummary(testBuildDirectory, caseName, channel_names, passing_channels, norms) -# failing case -if not pass_fail.passRegressionTest(normalizedNorm, tolerance): - if plotError: - from errorPlotting import finalizePlotDirectory, plotOpenfastError - ixFailChannels = [i for i in range(len(testInfo["attribute_names"])) if normalizedNorm[i] > tolerance] - failChannels = [channel for i, channel in enumerate(testInfo["attribute_names"]) if i in ixFailChannels] - failResults = [res for i, res in enumerate(results) if i in ixFailChannels] - for channel in failChannels: - try: - plotOpenfastError(localOutFile, baselineOutFile, channel) - except: - error = sys.exc_info()[1] - print("Error generating plots: {}".format(error.msg)) - finalizePlotDirectory(localOutFile, failChannels, caseName) - sys.exit(1) - # passing case -sys.exit(0) +if np.all(passing_channels): + sys.exit(0) + +# failing case +if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel, rtol, atol) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + +sys.exit(1) diff --git a/reg_tests/executeHydrodynRegressionCase.py b/reg_tests/executeHydrodynRegressionCase.py index 2c442eb6ba..7cccc28f00 100644 --- a/reg_tests/executeHydrodynRegressionCase.py +++ b/reg_tests/executeHydrodynRegressionCase.py @@ -27,6 +27,7 @@ basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse +import numpy as np import shutil import glob import subprocess @@ -46,9 +47,8 @@ parser.add_argument("executable", metavar="HydroDyn-Driver", type=str, nargs=1, help="The path to the HydroDyn driver executable.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") parser.add_argument("-p", "-plot", dest="plot", default=False, metavar="Plotting-Flag", type=bool, nargs="?", help="bool to include matplotlib plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", default=False, metavar="No-Execution", type=bool, nargs="?", help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", default=False, metavar="Verbose-Flag", type=bool, nargs="?", help="bool to include verbose system output") @@ -59,7 +59,8 @@ executable = args.executable[0] sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] +rtol = args.rtol[0] +atol = args.atol[0] plotError = args.plot if args.plot is False else True noExec = args.noExec if args.noExec is False else True verbose = args.verbose if args.verbose is False else True @@ -111,31 +112,31 @@ rtl.validateFileOrExit(localOutFile) rtl.validateFileOrExit(baselineOutFile) -testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +testData, testInfo, _ = pass_fail.readFASTOut(localOutFile) baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) -performance = pass_fail.calculateNorms(testData, baselineData) -normalizedNorm = performance[:, 1] + +passing_channels = pass_fail.passing_channels(testData.T, baselineData.T, rtol, atol) +passing_channels = passing_channels.T + +norms = pass_fail.calculateNorms(testData, baselineData) # export all case summaries -results = list(zip(testInfo["attribute_names"], [*performance])) -results_max = performance.max(axis=0) -exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) +channel_names = testInfo["attribute_names"] +exportCaseSummary(testBuildDirectory, caseName, channel_names, passing_channels, norms) -# failing case -if not pass_fail.passRegressionTest(normalizedNorm, tolerance): - if plotError: - from errorPlotting import finalizePlotDirectory, plotOpenfastError - ixFailChannels = [i for i in range(len(testInfo["attribute_names"])) if normalizedNorm[i] > tolerance] - failChannels = [channel for i, channel in enumerate(testInfo["attribute_names"]) if i in ixFailChannels] - failResults = [res for i, res in enumerate(results) if i in ixFailChannels] - for channel in failChannels: - try: - plotOpenfastError(localOutFile, baselineOutFile, channel) - except: - error = sys.exc_info()[1] - print("Error generating plots: {}".format(error.msg)) - finalizePlotDirectory(localOutFile, failChannels, caseName) - sys.exit(1) - # passing case -sys.exit(0) +if np.all(passing_channels): + sys.exit(0) + +# failing case +if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel, rtol, atol) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + +sys.exit(1) diff --git a/reg_tests/executeInflowwindPyRegressionCase.py b/reg_tests/executeInflowwindPyRegressionCase.py index 7d88591ba9..04bf609fb0 100644 --- a/reg_tests/executeInflowwindPyRegressionCase.py +++ b/reg_tests/executeInflowwindPyRegressionCase.py @@ -27,6 +27,7 @@ basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse +import numpy as np import shutil import glob import subprocess @@ -46,9 +47,8 @@ parser.add_argument("executable", metavar="InflowWind-Python", type=str, nargs=1, help="The path to the InflowWind driver executable.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") parser.add_argument("-p", "-plot", dest="plot", action='store_true', help="bool to include plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', help="bool to include verbose system output") @@ -59,7 +59,8 @@ executable = args.executable[0] sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] +rtol = args.rtol[0] +atol = args.atol[0] plotError = args.plot if args.plot is False else True noExec = args.noExec if args.noExec is False else True verbose = args.verbose if args.verbose is False else True @@ -104,38 +105,38 @@ returnCode = openfastDrivers.runInflowwindDriverCase(caseInputFile, executable) if returnCode != 0: rtl.exitWithError("") - + ### Build the filesystem navigation variables for running the regression test localOutFile = os.path.join(testBuildDirectory, "Points.Velocity.dat") baselineOutFile = os.path.join(targetOutputDirectory, "Points.Velocity.dat") rtl.validateFileOrExit(localOutFile) rtl.validateFileOrExit(baselineOutFile) -testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +testData, testInfo, _ = pass_fail.readFASTOut(localOutFile) baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) -performance = pass_fail.calculateNorms(testData, baselineData) -normalizedNorm = performance[:, 1] + +passing_channels = pass_fail.passing_channels(testData.T, baselineData.T, rtol, atol) +passing_channels = passing_channels.T + +norms = pass_fail.calculateNorms(testData, baselineData) # export all case summaries -results = list(zip(testInfo["attribute_names"], [*performance])) -results_max = performance.max(axis=0) -exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) +channel_names = testInfo["attribute_names"] +exportCaseSummary(testBuildDirectory, caseName, channel_names, passing_channels, norms) -# failing case -if not pass_fail.passRegressionTest(normalizedNorm, tolerance): - if plotError: - from errorPlotting import finalizePlotDirectory, plotOpenfastError - ixFailChannels = [i for i in range(len(testInfo["attribute_names"])) if normalizedNorm[i] > tolerance] - failChannels = [channel for i, channel in enumerate(testInfo["attribute_names"]) if i in ixFailChannels] - failResults = [res for i, res in enumerate(results) if i in ixFailChannels] - for channel in failChannels: - try: - plotOpenfastError(localOutFile, baselineOutFile, channel) - except: - error = sys.exc_info()[1] - print("Error generating plots: {}".format(error.msg)) - finalizePlotDirectory(localOutFile, failChannels, caseName) - sys.exit(1) - # passing case -sys.exit(0) +if np.all(passing_channels): + sys.exit(0) + +# failing case +if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel, rtol, atol) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + +sys.exit(1) diff --git a/reg_tests/executeInflowwindRegressionCase.py b/reg_tests/executeInflowwindRegressionCase.py index 42c99d6289..ed82774833 100644 --- a/reg_tests/executeInflowwindRegressionCase.py +++ b/reg_tests/executeInflowwindRegressionCase.py @@ -27,6 +27,7 @@ basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse +import numpy as np import shutil import glob import subprocess @@ -46,9 +47,8 @@ parser.add_argument("executable", metavar="InflowWind-Driver", type=str, nargs=1, help="The path to the InflowWind driver executable.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") parser.add_argument("-p", "-plot", dest="plot", action='store_true', help="bool to include plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', help="bool to include verbose system output") @@ -59,7 +59,8 @@ executable = args.executable[0] sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] +rtol = args.rtol[0] +atol = args.atol[0] plotError = args.plot if args.plot is False else True noExec = args.noExec if args.noExec is False else True verbose = args.verbose if args.verbose is False else True @@ -108,31 +109,31 @@ rtl.validateFileOrExit(localOutFile) rtl.validateFileOrExit(baselineOutFile) -testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +testData, testInfo, _ = pass_fail.readFASTOut(localOutFile) baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) -performance = pass_fail.calculateNorms(testData, baselineData) -normalizedNorm = performance[:, 1] + +passing_channels = pass_fail.passing_channels(testData.T, baselineData.T, rtol, atol) +passing_channels = passing_channels.T + +norms = pass_fail.calculateNorms(testData, baselineData) # export all case summaries -results = list(zip(testInfo["attribute_names"], [*performance])) -results_max = performance.max(axis=0) -exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) +channel_names = testInfo["attribute_names"] +exportCaseSummary(testBuildDirectory, caseName, channel_names, passing_channels, norms) -# failing case -if not pass_fail.passRegressionTest(normalizedNorm, tolerance): - if plotError: - from errorPlotting import finalizePlotDirectory, plotOpenfastError - ixFailChannels = [i for i in range(len(testInfo["attribute_names"])) if normalizedNorm[i] > tolerance] - failChannels = [channel for i, channel in enumerate(testInfo["attribute_names"]) if i in ixFailChannels] - failResults = [res for i, res in enumerate(results) if i in ixFailChannels] - for channel in failChannels: - try: - plotOpenfastError(localOutFile, baselineOutFile, channel) - except: - error = sys.exc_info()[1] - print("Error generating plots: {}".format(error.msg)) - finalizePlotDirectory(localOutFile, failChannels, caseName) - sys.exit(1) - # passing case -sys.exit(0) +if np.all(passing_channels): + sys.exit(0) + +# failing case +if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel, rtol, atol) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + +sys.exit(1) diff --git a/reg_tests/executeOpenfastAeroAcousticRegressionCase.py b/reg_tests/executeOpenfastAeroAcousticRegressionCase.py index 381879eb25..01948f528a 100644 --- a/reg_tests/executeOpenfastAeroAcousticRegressionCase.py +++ b/reg_tests/executeOpenfastAeroAcousticRegressionCase.py @@ -28,6 +28,7 @@ basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse +import numpy as np import shutil import subprocess import rtestlib as rtl @@ -55,9 +56,8 @@ def ignoreBaselineItems(directory, contents): parser.add_argument("executable", metavar="OpenFAST", type=str, nargs=1, help="The path to the OpenFAST executable.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") parser.add_argument("-p", "-plot", dest="plot", action='store_true', help="bool to include plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', help="bool to include verbose system output") @@ -68,9 +68,8 @@ def ignoreBaselineItems(directory, contents): executable = args.executable[0] sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] -systemName = args.systemName[0] -compilerId = args.compilerId[0] +rtol = args.rtol[0] +atol = args.atol[0] plotError = args.plot noExec = args.noExec verbose = args.verbose @@ -81,37 +80,17 @@ def ignoreBaselineItems(directory, contents): if not os.path.isdir(buildDirectory): os.makedirs(buildDirectory) -### Map the system and compiler configurations to a solution set -# Internal names -> Human readable names -systemName_map = { - "darwin": "macos", - "linux": "linux", - "windows": "windows" -} -compilerId_map = { - "gnu": "gnu", - "intel": "intel" -} -# Build the target output directory name or choose the default -supportedBaselines = ["macos-gnu", "linux-intel", "linux-gnu", "windows-intel"] -targetSystem = systemName_map.get(systemName.lower(), "") -targetCompiler = compilerId_map.get(compilerId.lower(), "") -outputType = os.path.join(targetSystem+"-"+targetCompiler) -if outputType not in supportedBaselines: - outputType = supportedBaselines[0] -print("-- Using gold standard files with machine-compiler type {}".format(outputType)) - ### Build the filesystem navigation variables for running openfast on the test case regtests = os.path.join(sourceDirectory, "reg_tests") lib = os.path.join(regtests, "lib") rtest = os.path.join(regtests, "r-test") moduleDirectory = os.path.join(rtest, "glue-codes", "openfast") inputsDirectory = os.path.join(moduleDirectory, caseName) -targetOutputDirectory = os.path.join(inputsDirectory, outputType) +targetOutputDirectory = os.path.join(inputsDirectory) testBuildDirectory = os.path.join(buildDirectory, caseName) - + # verify all the required directories exist if not os.path.isdir(rtest): rtl.exitWithError("The test data directory, {}, does not exist. If you haven't already, run `git submodule update --init --recursive`".format(rtest)) @@ -124,14 +103,14 @@ def ignoreBaselineItems(directory, contents): # and initialize it with input files for all test cases if not os.path.isdir(testBuildDirectory): shutil.copytree(inputsDirectory, testBuildDirectory, ignore=ignoreBaselineItems) - + ### Run openfast on the test case if not noExec: caseInputFile = os.path.join(testBuildDirectory, caseName + ".fst") returnCode = openfastDrivers.runOpenfastCase(caseInputFile, executable) if returnCode != 0: rtl.exitWithError("") - + ### Build the filesystem navigation variables for running the regression test # testing on file 2. Gives each observer and sweep of frequency ranges localOutFile = os.path.join(testBuildDirectory, caseName + "_2.out") @@ -139,31 +118,31 @@ def ignoreBaselineItems(directory, contents): rtl.validateFileOrExit(localOutFile) rtl.validateFileOrExit(baselineOutFile) -testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +testData, testInfo, _ = pass_fail.readFASTOut(localOutFile) baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) -performance = pass_fail.calculateNorms(testData, baselineData) -normalizedNorm = performance[:, 1] + +passing_channels = pass_fail.passing_channels(testData.T, baselineData.T, rtol, atol) +passing_channels = passing_channels.T + +norms = pass_fail.calculateNorms(testData, baselineData) # export all case summaries -results = list(zip(testInfo["attribute_names"], [*performance])) -results_max = performance.max(axis=0) -exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) +channel_names = testInfo["attribute_names"] +exportCaseSummary(testBuildDirectory, caseName, channel_names, passing_channels, norms) -# failing case -if not pass_fail.passRegressionTest(normalizedNorm, tolerance): - if plotError: - from errorPlotting import finalizePlotDirectory, plotOpenfastError - ixFailChannels = [i for i in range(len(testInfo["attribute_names"])) if normalizedNorm[i] > tolerance] - failChannels = [channel for i, channel in enumerate(testInfo["attribute_names"]) if i in ixFailChannels] - failResults = [res for i, res in enumerate(results) if i in ixFailChannels] - for channel in failChannels: - try: - plotOpenfastError(localOutFile, baselineOutFile, channel) - except: - error = sys.exc_info()[1] - print("Error generating plots: {}".format(error.msg)) - finalizePlotDirectory(localOutFile, failChannels, caseName) - sys.exit(1) - # passing case -sys.exit(0) +if np.all(passing_channels): + sys.exit(0) + +# failing case +if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel, rtol, atol) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + +sys.exit(1) \ No newline at end of file diff --git a/reg_tests/executeOpenfastCppRegressionCase.py b/reg_tests/executeOpenfastCppRegressionCase.py index 03f9cccc2b..12a9a9698a 100644 --- a/reg_tests/executeOpenfastCppRegressionCase.py +++ b/reg_tests/executeOpenfastCppRegressionCase.py @@ -19,6 +19,7 @@ basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse +import numpy as np import shutil import subprocess import rtestlib as rtl @@ -46,9 +47,8 @@ def ignoreBaselineItems(directory, contents): parser.add_argument("executable", metavar="OpenFAST", type=str, nargs=1, help="The path to the OpenFAST executable.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") parser.add_argument("-p", "-plot", dest="plot", action='store_true', help="bool to include plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', help="bool to include verbose system output") @@ -59,9 +59,8 @@ def ignoreBaselineItems(directory, contents): executable = os.path.abspath(args.executable[0]) sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] -systemName = args.systemName[0] -compilerId = args.compilerId[0] +rtol = args.rtol[0] +atol = args.atol[0] plotError = args.plot noExec = args.noExec verbose = args.verbose @@ -72,32 +71,13 @@ def ignoreBaselineItems(directory, contents): if not os.path.isdir(buildDirectory): os.makedirs(buildDirectory) -### Map the system and compiler configurations to a solution set -# Internal names -> Human readable names -systemName_map = { - "darwin": "macos", - "linux": "linux", - "windows": "windows" -} -compilerId_map = { - "gnu": "gnu", - "intel": "intel" -} -# Build the target output directory name or choose the default -supportedBaselines = ["macos-gnu", "linux-intel", "linux-gnu", "windows-intel"] -targetSystem = systemName_map.get(systemName.lower(), "") -targetCompiler = compilerId_map.get(compilerId.lower(), "") -outputType = os.path.join(targetSystem+"-"+targetCompiler) -if outputType not in supportedBaselines: - outputType = supportedBaselines[0] -print("-- Using gold standard files with machine-compiler type {}".format(outputType)) ### Build the filesystem navigation variables for running openfast on the test case rtest = os.path.join(sourceDirectory, "reg_tests", "r-test") moduleDirectory = os.path.join(rtest, "glue-codes", "openfast-cpp") openfast_gluecode_directory = os.path.join(rtest, "glue-codes", "openfast") inputsDirectory = os.path.join(moduleDirectory, caseName) -targetOutputDirectory = os.path.join(openfast_gluecode_directory, caseName.replace('_cpp', ''), outputType) +targetOutputDirectory = os.path.join(openfast_gluecode_directory, caseName.replace('_cpp', '')) testBuildDirectory = os.path.join(buildDirectory, caseName) # verify all the required directories exist @@ -142,32 +122,35 @@ def ignoreBaselineItems(directory, contents): ### Build the filesystem navigation variables for running the regression test localOutFile = os.path.join(testBuildDirectory, caseName + ".outb") baselineOutFile = os.path.join(targetOutputDirectory, caseName.replace('_cpp', '') + ".outb") + rtl.validateFileOrExit(localOutFile) rtl.validateFileOrExit(baselineOutFile) -testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +testData, testInfo, _ = pass_fail.readFASTOut(localOutFile) baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) -performance = pass_fail.calculateNorms(testData, baselineData) -normalizedNorm = performance[:, 1] -# export all case summaries -results = list(zip(testInfo["attribute_names"], [*performance])) -results_max = performance.max(axis=0) -exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) +passing_channels = pass_fail.passing_channels(testData.T, baselineData.T, rtol, atol) +passing_channels = passing_channels.T -# failing case -if not pass_fail.passRegressionTest(normalizedNorm, tolerance): - if plotError: - from errorPlotting import finalizePlotDirectory, plotOpenfastError - for channel in testInfo["attribute_names"]: - try: - plotOpenfastError(localOutFile, baselineOutFile, channel) - except: - error = sys.exc_info()[1] - print("Error generating plots: {}".format(error)) - finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) - - sys.exit(1) +norms = pass_fail.calculateNorms(testData, baselineData) + +# export all case summaries +channel_names = testInfo["attribute_names"] +exportCaseSummary(testBuildDirectory, caseName, channel_names, passing_channels, norms) # passing case -sys.exit(0) +if np.all(passing_channels): + sys.exit(0) + +# failing case +if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel, rtol, atol) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + +sys.exit(1) diff --git a/reg_tests/executeOpenfastLinearRegressionCase.py b/reg_tests/executeOpenfastLinearRegressionCase.py index 8e8a9b7015..be72443b55 100644 --- a/reg_tests/executeOpenfastLinearRegressionCase.py +++ b/reg_tests/executeOpenfastLinearRegressionCase.py @@ -27,6 +27,7 @@ basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse +import numpy as np import shutil import subprocess import rtestlib as rtl @@ -64,12 +65,11 @@ def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): parser.add_argument("executable", metavar="OpenFAST", type=str, nargs=1, help="The path to the OpenFAST executable.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") -parser.add_argument("-p", "-plot", dest="plot", default=False, metavar="Plotting-Flag", type=bool, nargs="?", help="bool to include plots in failed cases") -parser.add_argument("-n", "-no-exec", dest="noExec", default=False, metavar="No-Execution", type=bool, nargs="?", help="bool to prevent execution of the test cases") -parser.add_argument("-v", "-verbose", dest="verbose", default=False, metavar="Verbose-Flag", type=bool, nargs="?", help="bool to include verbose system output") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") +parser.add_argument("-p", "-plot", dest="plot", action='store_true', help="bool to include plots in failed cases") +parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', help="bool to prevent execution of the test cases") +parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', help="bool to include verbose system output") args = parser.parse_args() @@ -77,12 +77,17 @@ def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): executable = args.executable[0] sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] -systemName = args.systemName[0] -compilerId = args.compilerId[0] -plotError = args.plot if args.plot is False else True -noExec = args.noExec if args.noExec is False else True -verbose = args.verbose if args.verbose is False else True +rtol = args.rtol[0] +atol = args.atol[0] +plotError = args.plot +noExec = args.noExec +verbose = args.verbose + +# Tolerance have not been tuned for linearization case outputs. +# This is using 1e-5 since that seemed like a decent value prior to +# switching to relative and absolute tolerance. +rtol = 1e-5 +atol = 1e-5 # validate inputs rtl.validateExeOrExit(executable) @@ -90,33 +95,13 @@ def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): if not os.path.isdir(buildDirectory): os.makedirs(buildDirectory) -### Map the system and compiler configurations to a solution set -# Internal names -> Human readable names -systemName_map = { - "darwin": "macos", - "linux": "linux", - "windows": "windows" -} -compilerId_map = { - "gnu": "gnu", - "intel": "intel" -} -# Build the target output directory name or choose the default -supportedBaselines = ["macos-gnu", "linux-intel", "linux-gnu", "windows-intel"] -targetSystem = systemName_map.get(systemName.lower(), "") -targetCompiler = compilerId_map.get(compilerId.lower(), "") -outputType = os.path.join(targetSystem+"-"+targetCompiler) -if outputType not in supportedBaselines: - outputType = supportedBaselines[0] -print("-- Using gold standard files with machine-compiler type {}".format(outputType)) - ### Build the filesystem navigation variables for running openfast on the test case regtests = os.path.join(sourceDirectory, "reg_tests") lib = os.path.join(regtests, "lib") rtest = os.path.join(regtests, "r-test") moduleDirectory = os.path.join(rtest, "glue-codes", "openfast") inputsDirectory = os.path.join(moduleDirectory, caseName) -targetOutputDirectory = os.path.join(inputsDirectory, outputType) +targetOutputDirectory = os.path.join(inputsDirectory) testBuildDirectory = os.path.join(buildDirectory, caseName) # verify all the required directories exist @@ -162,11 +147,8 @@ def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): if returnCode != 0: rtl.exitWithError("") -### Get a list of all the files in the baseline directory -baselineOutFiles = os.listdir(targetOutputDirectory) -# Drop the log file, if its listed -if caseName + '.log' in baselineOutFiles: - baselineOutFiles.remove(caseName + '.log') +### Get a all the .lin files in the baseline directory +baselineOutFiles = [f for f in os.listdir(targetOutputDirectory) if '.lin' in f] # these should all exist in the local outputs directory localFiles = os.listdir(testBuildDirectory) @@ -239,8 +221,10 @@ def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): for j, l_element in enumerate(l_elements): l_float = float(l_element) b_float = float(b_elements[j]) - if not isclose(l_float, b_float, tolerance, tolerance): - print(f"Failed in Jacobian matrix comparison: {l_float} and {b_float}") + if not isclose(l_float, b_float, rtol, atol): + print(f"Failed in Jacobian matrix comparison:") + print(f"{l_float} in {local_file}") + print(f"{b_float} in {baseline_file}") sys.exit(1) # skip 2 empty/header lines @@ -261,7 +245,7 @@ def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): for j, l_element in enumerate(l_elements): l_float = float(l_element) b_float = float(b_elements[j]) - if not isclose(l_float, b_float, tolerance, tolerance): + if not isclose(l_float, b_float, rtol, atol): print(f"Failed in state matrix comparison: {l_float} and {b_float}") sys.exit(1) diff --git a/reg_tests/executeOpenfastRegressionCase.py b/reg_tests/executeOpenfastRegressionCase.py index 2bb1bb14ca..7b7e0dacf0 100644 --- a/reg_tests/executeOpenfastRegressionCase.py +++ b/reg_tests/executeOpenfastRegressionCase.py @@ -27,6 +27,7 @@ basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse +import numpy as np import shutil import subprocess import rtestlib as rtl @@ -54,9 +55,8 @@ def ignoreBaselineItems(directory, contents): parser.add_argument("executable", metavar="OpenFAST", type=str, nargs=1, help="The path to the OpenFAST executable.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") parser.add_argument("-p", "-plot", dest="plot", action='store_true', help="bool to include plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', help="bool to include verbose system output") @@ -67,9 +67,8 @@ def ignoreBaselineItems(directory, contents): executable = args.executable[0] sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] -systemName = args.systemName[0] -compilerId = args.compilerId[0] +rtol = args.rtol[0] +atol = args.atol[0] plotError = args.plot noExec = args.noExec verbose = args.verbose @@ -80,25 +79,6 @@ def ignoreBaselineItems(directory, contents): if not os.path.isdir(buildDirectory): os.makedirs(buildDirectory) -### Map the system and compiler configurations to a solution set -# Internal names -> Human readable names -systemName_map = { - "darwin": "macos", - "linux": "linux", - "windows": "windows" -} -compilerId_map = { - "gnu": "gnu", - "intel": "intel" -} -# Build the target output directory name or choose the default -supportedBaselines = ["macos-gnu", "linux-intel", "linux-gnu", "windows-intel"] -targetSystem = systemName_map.get(systemName.lower(), "") -targetCompiler = compilerId_map.get(compilerId.lower(), "") -outputType = os.path.join(targetSystem+"-"+targetCompiler) -if outputType not in supportedBaselines: - outputType = supportedBaselines[0] -print("-- Using gold standard files with machine-compiler type {}".format(outputType)) ### Build the filesystem navigation variables for running openfast on the test case regtests = os.path.join(sourceDirectory, "reg_tests") @@ -106,7 +86,7 @@ def ignoreBaselineItems(directory, contents): rtest = os.path.join(regtests, "r-test") moduleDirectory = os.path.join(rtest, "glue-codes", "openfast") inputsDirectory = os.path.join(moduleDirectory, caseName) -targetOutputDirectory = os.path.join(inputsDirectory, outputType) +targetOutputDirectory = os.path.join(inputsDirectory) testBuildDirectory = os.path.join(buildDirectory, caseName) # verify all the required directories exist @@ -158,29 +138,31 @@ def ignoreBaselineItems(directory, contents): rtl.validateFileOrExit(localOutFile) rtl.validateFileOrExit(baselineOutFile) -testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +testData, testInfo, _ = pass_fail.readFASTOut(localOutFile) baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) -performance = pass_fail.calculateNorms(testData, baselineData) -normalizedNorm = performance[:, 1] -# export all case summaries -results = list(zip(testInfo["attribute_names"], [*performance])) -results_max = performance.max(axis=0) -exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) +passing_channels = pass_fail.passing_channels(testData.T, baselineData.T, rtol, atol) +passing_channels = passing_channels.T -# failing case -if not pass_fail.passRegressionTest(normalizedNorm, tolerance): - if plotError: - from errorPlotting import finalizePlotDirectory, plotOpenfastError - for channel in testInfo["attribute_names"]: - try: - plotOpenfastError(localOutFile, baselineOutFile, channel) - except: - error = sys.exc_info()[1] - print("Error generating plots: {}".format(error)) - finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) - - sys.exit(1) +norms = pass_fail.calculateNorms(testData, baselineData) + +# export all case summaries +channel_names = testInfo["attribute_names"] +exportCaseSummary(testBuildDirectory, caseName, channel_names, passing_channels, norms) # passing case -sys.exit(0) +if np.all(passing_channels): + sys.exit(0) + +# failing case +if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel, rtol, atol) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + +sys.exit(1) diff --git a/reg_tests/executePythonRegressionCase.py b/reg_tests/executePythonRegressionCase.py index 58c2599290..7abccb2add 100644 --- a/reg_tests/executePythonRegressionCase.py +++ b/reg_tests/executePythonRegressionCase.py @@ -25,11 +25,12 @@ import os import sys -basepath = os.path.sep.join(sys.argv[0].split(os.path.sep)[:-1]) if os.path.sep in sys.argv[0] else "." +basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) sys.path.insert(0, os.path.sep.join([basepath, "..", "glue-codes", "python"])) import platform import argparse +import numpy as np import shutil import subprocess import rtestlib as rtl @@ -58,9 +59,8 @@ def ignoreBaselineItems(directory, contents): parser.add_argument("executable", metavar="NotUsed", type=str, nargs=1, help="Not used in this script, but kept for API compatibility.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") parser.add_argument("-p", "-plot", dest="plot", action='store_true', help="bool to include plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', help="bool to include verbose system output") @@ -70,9 +70,8 @@ def ignoreBaselineItems(directory, contents): caseName = args.caseName[0].replace("_py", "") sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] -systemName = args.systemName[0] -compilerId = args.compilerId[0] +rtol = args.rtol[0] +atol = args.atol[0] plotError = args.plot noExec = args.noExec verbose = args.verbose @@ -82,25 +81,6 @@ def ignoreBaselineItems(directory, contents): if not os.path.isdir(buildDirectory): os.makedirs(buildDirectory) -### Map the system and compiler configurations to a solution set -# Internal names -> Human readable names -systemName_map = { - "darwin": "macos", - "linux": "linux", - "windows": "windows" -} -compilerId_map = { - "gnu": "gnu", - "intel": "intel" -} -# Build the target output directory name or choose the default -supportedBaselines = ["macos-gnu", "linux-intel", "linux-gnu", "windows-intel"] -targetSystem = systemName_map.get(systemName.lower(), "") -targetCompiler = compilerId_map.get(compilerId.lower(), "") -outputType = os.path.join(targetSystem+"-"+targetCompiler) -if outputType not in supportedBaselines: - outputType = supportedBaselines[0] -print("-- Using gold standard files with machine-compiler type {}".format(outputType)) ### Build the filesystem navigation variables for running openfast on the test case regtests = os.path.join(sourceDirectory, "reg_tests") @@ -108,7 +88,7 @@ def ignoreBaselineItems(directory, contents): rtest = os.path.join(regtests, "r-test") moduleDirectory = os.path.join(rtest, "glue-codes", "openfast") inputsDirectory = os.path.join(moduleDirectory, caseName) -targetOutputDirectory = os.path.join(inputsDirectory, outputType) +targetOutputDirectory = os.path.join(inputsDirectory) testBuildDirectory = os.path.join(buildDirectory, caseName) # verify all the required directories exist @@ -126,6 +106,7 @@ def ignoreBaselineItems(directory, contents): if not os.path.isdir(dataDir): shutil.copytree(os.path.join(moduleDirectory, data), dataDir) +# Special copy for the 5MW_Baseline folder because the Windows python-only workflow may have already created data in the subfolder ServoData dst = os.path.join(buildDirectory, "5MW_Baseline") src = os.path.join(moduleDirectory, "5MW_Baseline") if not os.path.isdir(dst): @@ -173,27 +154,29 @@ def ignoreBaselineItems(directory, contents): } testData = openfastlib.output_values baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) -performance = pass_fail.calculateNorms(testData, baselineData) -normalizedNorm = performance[:, 1] -# export all case summaries -results = list(zip(testInfo["attribute_names"], [*performance])) -results_max = performance.max(axis=0) -exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) +passing_channels = pass_fail.passing_channels(testData.T, baselineData.T, rtol, atol) +passing_channels = passing_channels.T -# failing case -if not pass_fail.passRegressionTest(normalizedNorm, tolerance): - if plotError: - from errorPlotting import finalizePlotDirectory, plotOpenfastError - for channel in testInfo["attribute_names"]: - try: - plotOpenfastError(localOutFile, baselineOutFile, channel) - except: - error = sys.exc_info()[1] - print("Error generating plots: {}".format(error)) - finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) - - sys.exit(1) +norms = pass_fail.calculateNorms(testData, baselineData) + +# export all case summaries +channel_names = testInfo["attribute_names"] +exportCaseSummary(testBuildDirectory, caseName, channel_names, passing_channels, norms) # passing case -sys.exit(0) +if np.all(passing_channels): + sys.exit(0) + +# failing case +if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel, rtol, atol) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + +sys.exit(1) diff --git a/reg_tests/executeSubdynRegressionCase.py b/reg_tests/executeSubdynRegressionCase.py index 94e04a710f..60c0327b07 100644 --- a/reg_tests/executeSubdynRegressionCase.py +++ b/reg_tests/executeSubdynRegressionCase.py @@ -27,6 +27,7 @@ basepath = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, os.path.sep.join([basepath, "lib"])) import argparse +import numpy as np import shutil import glob import subprocess @@ -46,9 +47,8 @@ parser.add_argument("executable", metavar="SubDyn-Driver", type=str, nargs=1, help="The path to the SubDyn driver executable.") parser.add_argument("sourceDirectory", metavar="path/to/openfast_repo", type=str, nargs=1, help="The path to the OpenFAST repository.") parser.add_argument("buildDirectory", metavar="path/to/openfast_repo/build", type=str, nargs=1, help="The path to the OpenFAST repository build directory.") -parser.add_argument("tolerance", metavar="Test-Tolerance", type=float, nargs=1, help="Tolerance defining pass or failure in the regression test.") -parser.add_argument("systemName", metavar="System-Name", type=str, nargs=1, help="The current system\'s name: [Darwin,Linux,Windows]") -parser.add_argument("compilerId", metavar="Compiler-Id", type=str, nargs=1, help="The compiler\'s id: [Intel,GNU]") +parser.add_argument("rtol", metavar="Relative-Tolerance", type=float, nargs=1, help="Relative tolerance to allow the solution to deviate; expressed as order of magnitudes less than baseline.") +parser.add_argument("atol", metavar="Absolute-Tolerance", type=float, nargs=1, help="Absolute tolerance to allow small values to pass; expressed as order of magnitudes less than baseline.") parser.add_argument("-p", "-plot", dest="plot", action='store_true', default=False, help="bool to include matplotlib plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', default=False, help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', default=False, help="bool to include verbose system output") @@ -59,7 +59,8 @@ executable = args.executable[0] sourceDirectory = args.sourceDirectory[0] buildDirectory = args.buildDirectory[0] -tolerance = args.tolerance[0] +rtol = args.rtol[0] +atol = args.atol[0] plotError = args.plot noExec = args.noExec verbose = args.verbose @@ -104,34 +105,35 @@ ### Build the filesystem navigation variables for running the regression test localOutFile = os.path.join(testBuildDirectory, caseName+".SD.out") baselineOutFile = os.path.join(targetOutputDirectory, caseName+".SD.out") + rtl.validateFileOrExit(localOutFile) rtl.validateFileOrExit(baselineOutFile) -testData, testInfo, testPack = pass_fail.readFASTOut(localOutFile) +testData, testInfo, _ = pass_fail.readFASTOut(localOutFile) baselineData, baselineInfo, _ = pass_fail.readFASTOut(baselineOutFile) -performance = pass_fail.calculateNorms(testData, baselineData) -normalizedNorm = performance[:, 1] + +passing_channels = pass_fail.passing_channels(testData.T, baselineData.T, rtol, atol) +passing_channels = passing_channels.T + +norms = pass_fail.calculateNorms(testData, baselineData) # export all case summaries -results = list(zip(testInfo["attribute_names"], [*performance])) -results_max = performance.max(axis=0) -exportCaseSummary(testBuildDirectory, caseName, results, results_max, tolerance) +channel_names = testInfo["attribute_names"] +exportCaseSummary(testBuildDirectory, caseName, channel_names, passing_channels, norms) -# failing case -if not pass_fail.passRegressionTest(normalizedNorm, tolerance): - if plotError: - from errorPlotting import finalizePlotDirectory, plotOpenfastError - ixFailChannels = [i for i in range(len(testInfo["attribute_names"])) if normalizedNorm[i] > tolerance] - failChannels = [channel for i, channel in enumerate(testInfo["attribute_names"]) if i in ixFailChannels] - failResults = [res for i, res in enumerate(results) if i in ixFailChannels] - for channel in failChannels: - try: - plotOpenfastError(localOutFile, baselineOutFile, channel) - except: - error = sys.exc_info()[1] - print("Error generating plots: {}".format(error.msg)) - finalizePlotDirectory(localOutFile, failChannels, caseName) - sys.exit(1) - # passing case -sys.exit(0) +if np.all(passing_channels): + sys.exit(0) + +# failing case +if plotError: + from errorPlotting import finalizePlotDirectory, plotOpenfastError + for channel in testInfo["attribute_names"]: + try: + plotOpenfastError(localOutFile, baselineOutFile, channel, rtol, atol) + except: + error = sys.exc_info()[1] + print("Error generating plots: {}".format(error)) + finalizePlotDirectory(localOutFile, testInfo["attribute_names"], caseName) + +sys.exit(1) diff --git a/reg_tests/lib/errorPlotting.py b/reg_tests/lib/errorPlotting.py index 1778f3fe75..4f254a76e9 100644 --- a/reg_tests/lib/errorPlotting.py +++ b/reg_tests/lib/errorPlotting.py @@ -25,7 +25,6 @@ import os import sys import shutil - import numpy as np import rtestlib as rtl @@ -47,28 +46,43 @@ def _parseSolution(solution): except Exception as e: rtl.exitWithError("Error: {}".format(e)) -def _plotError(xseries, y1series, y2series, xlabel, title1, title2): +def _plotError(time, test, baseline, xlabel, title1, title2, RTOL_MAGNITUDE, ATOL_MAGNITUDE): from bokeh.embed import components from bokeh.layouts import gridplot from bokeh.plotting import figure - from bokeh.models.tools import HoverTool, BoxZoomTool + from bokeh.models.tools import HoverTool + # Plot the baseline and test channels p1 = figure(title=title1) p1.title.align = 'center' p1.grid.grid_line_alpha=0.3 p1.xaxis.axis_label = 'Time (s)' - p1.line(xseries, y2series, color='green', line_width=3, legend_label='Baseline') - p1.line(xseries, y1series, color='red', line_width=1, legend_label='Local') + p1.line(time, baseline, color='green', line_width=3, legend_label='Baseline') + p1.line(time, test, color='red', line_width=1, legend_label='Local') p1.add_tools(HoverTool(tooltips=[('Time','@x'), ('Value', '@y')],mode='vline')) + # Plot the error and threshold p2 = figure(title=title2, x_range=p1.x_range) p2.title.align = 'center' p2.grid.grid_line_alpha = 0 p2.xaxis.axis_label = 'Time (s)' - p2.line(xseries, abs(y2series - y1series), color='blue') + p2.line(time, abs(baseline - test), color='blue', legend_label="Error") + + # Calculate the threshold + NUMEPS = 1e-12 + ATOL_MIN = 1e-6 + baseline_offset = baseline - np.min(baseline) + b_order_of_magnitude = np.floor( np.log10( baseline_offset + NUMEPS ) ) + rtol = 10**(-1 * RTOL_MAGNITUDE) + atol = 10**(max(b_order_of_magnitude) - ATOL_MAGNITUDE) + atol = max(atol, ATOL_MIN) + passfail_line = atol + rtol * abs(baseline) + p2.line(time, passfail_line, color='red', legend_label="Threshold") + # p2.cross(xseries, passfail_line) + p2.add_tools(HoverTool(tooltips=[('Time','@x'), ('Error', '@y')], mode='vline')) - grid = gridplot([[p1, p2]], plot_width=650, plot_height=375, sizing_mode="scale_both") + grid = gridplot([[p1, p2]], width=650, height=375, sizing_mode="scale_both") script, div = components(grid) return script, div @@ -80,7 +94,7 @@ def _replace_id_div(html_string, plot): return html_string def _replace_id_script(html_string, plot): - id_start = html_string.find('var render_items') + id_start = html_string.find('const render_items') id_start += html_string[id_start:].find('roots') id_start += html_string[id_start:].find('":"') + 3 id_end = html_string[id_start:].find('"') + id_start @@ -92,7 +106,8 @@ def _save_plot(script, div, path, attribute): file_name = "_script".join((attribute, ".txt")) with open(os.path.join(path, file_name), 'w') as f: - script = _replace_id_script(script.replace('\n', '\n '), attribute) + script = script.replace('\n', '\n ') + script = _replace_id_script(script, attribute) f.write(script) file_name = "_div".join((attribute, ".txt")) @@ -104,7 +119,7 @@ def _save_plot(script, div, path, attribute): div = div.replace("