From e9a2a580af6c00c6499af0867fe14d014d35e709 Mon Sep 17 00:00:00 2001 From: "Joachim Wuttke (l)" <j.wuttke@fz-juelich.de> Date: Fri, 5 Aug 2016 10:10:06 +0200 Subject: [PATCH] Start PyPersistenceTest, to resolve #1440 --- Tests/Functional/CMakeLists.txt | 5 +- Tests/Functional/Core/CoreTest.h | 6 +- Tests/Functional/Fit/FitTest.cpp | 2 +- .../PyCore/{suite => export}/CMakeLists.txt | 0 .../PyExportStandardTest.cpp | 2 +- .../PyCore/{suite => export}/PyExportTest.cpp | 0 .../PyCore/{suite => export}/PyExportTest.h | 0 .../PyCore/{scripts => legacy}/CMakeLists.txt | 0 .../PyCore/{scripts => legacy}/README | 0 .../{scripts => legacy}/customformfactor.py | 0 .../cylinders_ba_dwba_size.py | 0 .../detector_resolution.py | 0 .../{scripts => legacy}/intensitydata.py | 0 .../{scripts => legacy}/intensitydata_io.py | 0 .../intensitydata_io_tiff.py | 0 .../{scripts => legacy}/layerwithroughness.py | 0 .../{scripts => legacy}/mesocrystal1.py | 0 .../montecarlo_integration.py | 0 .../{scripts => legacy}/polmagcylinders1.py | 0 .../{scripts => legacy}/polmagcylinders2.py | 0 .../PyCore/{scripts => legacy}/ripple1.py | 0 .../{scripts => legacy}/ripple2_asym.py | 0 .../PyCore/{scripts => legacy}/ripple2_sym.py | 0 .../transform_BoxComposition.py | 0 .../transform_CoreShellBox.py | 0 .../{scripts => legacy}/transform_box.py | 0 .../{scripts => legacy}/transform_cube.py | 0 .../PyCore/{scripts => legacy}/utils.py | 0 .../PyCore/persistence/CMakeLists.txt | 29 +++++ .../PyCore/persistence/PyPersistenceTest.cpp | 108 ++++++++++++++++++ .../PyCore/persistence/PyPersistenceTest.h | 53 +++++++++ .../persistence/RunPyPersistenceTest.cpp | 31 +++++ 32 files changed, 229 insertions(+), 7 deletions(-) rename Tests/Functional/PyCore/{suite => export}/CMakeLists.txt (100%) rename Tests/Functional/PyCore/{suite => export}/PyExportStandardTest.cpp (95%) rename Tests/Functional/PyCore/{suite => export}/PyExportTest.cpp (100%) rename Tests/Functional/PyCore/{suite => export}/PyExportTest.h (100%) rename Tests/Functional/PyCore/{scripts => legacy}/CMakeLists.txt (100%) rename Tests/Functional/PyCore/{scripts => legacy}/README (100%) rename Tests/Functional/PyCore/{scripts => legacy}/customformfactor.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/cylinders_ba_dwba_size.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/detector_resolution.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/intensitydata.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/intensitydata_io.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/intensitydata_io_tiff.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/layerwithroughness.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/mesocrystal1.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/montecarlo_integration.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/polmagcylinders1.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/polmagcylinders2.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/ripple1.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/ripple2_asym.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/ripple2_sym.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/transform_BoxComposition.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/transform_CoreShellBox.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/transform_box.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/transform_cube.py (100%) rename Tests/Functional/PyCore/{scripts => legacy}/utils.py (100%) create mode 100644 Tests/Functional/PyCore/persistence/CMakeLists.txt create mode 100644 Tests/Functional/PyCore/persistence/PyPersistenceTest.cpp create mode 100644 Tests/Functional/PyCore/persistence/PyPersistenceTest.h create mode 100644 Tests/Functional/PyCore/persistence/RunPyPersistenceTest.cpp diff --git a/Tests/Functional/CMakeLists.txt b/Tests/Functional/CMakeLists.txt index 29bb06feecc..c1e4b81de32 100644 --- a/Tests/Functional/CMakeLists.txt +++ b/Tests/Functional/CMakeLists.txt @@ -7,8 +7,9 @@ add_subdirectory(Core) add_subdirectory(Fit) if(BORNAGAIN_PYTHON) - add_subdirectory(PyCore/scripts) - add_subdirectory(PyCore/suite) + add_subdirectory(PyCore/legacy) + add_subdirectory(PyCore/export) + add_subdirectory(PyCore/persistence) add_subdirectory(PyFit) endif() diff --git a/Tests/Functional/Core/CoreTest.h b/Tests/Functional/Core/CoreTest.h index 78e2d67b705..7c73328db97 100644 --- a/Tests/Functional/Core/CoreTest.h +++ b/Tests/Functional/Core/CoreTest.h @@ -33,10 +33,10 @@ public: CoreTest( const std::string& name, const std::string& description, GISASSimulation* simulation, double threshold); - virtual ~CoreTest(); + ~CoreTest() final; - virtual void runTest(); - virtual void printResults(std::ostream& ostr) const; + void runTest() final; + void printResults(std::ostream& ostr) const final; private: std::string getSimulationResultsFileNameAndPath() const; diff --git a/Tests/Functional/Fit/FitTest.cpp b/Tests/Functional/Fit/FitTest.cpp index a66a0385170..51568db3407 100644 --- a/Tests/Functional/Fit/FitTest.cpp +++ b/Tests/Functional/Fit/FitTest.cpp @@ -13,7 +13,7 @@ // // ************************************************************************** // -#include "IMinimizerTest.h" +#include "IFunctionalTest.h" #include "StandardFitsFactory.h" #include <memory> #include <iostream> diff --git a/Tests/Functional/PyCore/suite/CMakeLists.txt b/Tests/Functional/PyCore/export/CMakeLists.txt similarity index 100% rename from Tests/Functional/PyCore/suite/CMakeLists.txt rename to Tests/Functional/PyCore/export/CMakeLists.txt diff --git a/Tests/Functional/PyCore/suite/PyExportStandardTest.cpp b/Tests/Functional/PyCore/export/PyExportStandardTest.cpp similarity index 95% rename from Tests/Functional/PyCore/suite/PyExportStandardTest.cpp rename to Tests/Functional/PyCore/export/PyExportStandardTest.cpp index 867de4df912..73b44d9ace8 100644 --- a/Tests/Functional/PyCore/suite/PyExportStandardTest.cpp +++ b/Tests/Functional/PyCore/export/PyExportStandardTest.cpp @@ -20,7 +20,7 @@ class PyExportStandardTest : public IStandardTest { public: - PyExportStandardTest() : IStandardTest("PySuite") {} + PyExportStandardTest() : IStandardTest("PyExport") {} IFunctionalTest* getTest() const { return new PyExportTest( getTestName(), getTestDescription(), getSimulation(), getTestThreshold()); } }; diff --git a/Tests/Functional/PyCore/suite/PyExportTest.cpp b/Tests/Functional/PyCore/export/PyExportTest.cpp similarity index 100% rename from Tests/Functional/PyCore/suite/PyExportTest.cpp rename to Tests/Functional/PyCore/export/PyExportTest.cpp diff --git a/Tests/Functional/PyCore/suite/PyExportTest.h b/Tests/Functional/PyCore/export/PyExportTest.h similarity index 100% rename from Tests/Functional/PyCore/suite/PyExportTest.h rename to Tests/Functional/PyCore/export/PyExportTest.h diff --git a/Tests/Functional/PyCore/scripts/CMakeLists.txt b/Tests/Functional/PyCore/legacy/CMakeLists.txt similarity index 100% rename from Tests/Functional/PyCore/scripts/CMakeLists.txt rename to Tests/Functional/PyCore/legacy/CMakeLists.txt diff --git a/Tests/Functional/PyCore/scripts/README b/Tests/Functional/PyCore/legacy/README similarity index 100% rename from Tests/Functional/PyCore/scripts/README rename to Tests/Functional/PyCore/legacy/README diff --git a/Tests/Functional/PyCore/scripts/customformfactor.py b/Tests/Functional/PyCore/legacy/customformfactor.py similarity index 100% rename from Tests/Functional/PyCore/scripts/customformfactor.py rename to Tests/Functional/PyCore/legacy/customformfactor.py diff --git a/Tests/Functional/PyCore/scripts/cylinders_ba_dwba_size.py b/Tests/Functional/PyCore/legacy/cylinders_ba_dwba_size.py similarity index 100% rename from Tests/Functional/PyCore/scripts/cylinders_ba_dwba_size.py rename to Tests/Functional/PyCore/legacy/cylinders_ba_dwba_size.py diff --git a/Tests/Functional/PyCore/scripts/detector_resolution.py b/Tests/Functional/PyCore/legacy/detector_resolution.py similarity index 100% rename from Tests/Functional/PyCore/scripts/detector_resolution.py rename to Tests/Functional/PyCore/legacy/detector_resolution.py diff --git a/Tests/Functional/PyCore/scripts/intensitydata.py b/Tests/Functional/PyCore/legacy/intensitydata.py similarity index 100% rename from Tests/Functional/PyCore/scripts/intensitydata.py rename to Tests/Functional/PyCore/legacy/intensitydata.py diff --git a/Tests/Functional/PyCore/scripts/intensitydata_io.py b/Tests/Functional/PyCore/legacy/intensitydata_io.py similarity index 100% rename from Tests/Functional/PyCore/scripts/intensitydata_io.py rename to Tests/Functional/PyCore/legacy/intensitydata_io.py diff --git a/Tests/Functional/PyCore/scripts/intensitydata_io_tiff.py b/Tests/Functional/PyCore/legacy/intensitydata_io_tiff.py similarity index 100% rename from Tests/Functional/PyCore/scripts/intensitydata_io_tiff.py rename to Tests/Functional/PyCore/legacy/intensitydata_io_tiff.py diff --git a/Tests/Functional/PyCore/scripts/layerwithroughness.py b/Tests/Functional/PyCore/legacy/layerwithroughness.py similarity index 100% rename from Tests/Functional/PyCore/scripts/layerwithroughness.py rename to Tests/Functional/PyCore/legacy/layerwithroughness.py diff --git a/Tests/Functional/PyCore/scripts/mesocrystal1.py b/Tests/Functional/PyCore/legacy/mesocrystal1.py similarity index 100% rename from Tests/Functional/PyCore/scripts/mesocrystal1.py rename to Tests/Functional/PyCore/legacy/mesocrystal1.py diff --git a/Tests/Functional/PyCore/scripts/montecarlo_integration.py b/Tests/Functional/PyCore/legacy/montecarlo_integration.py similarity index 100% rename from Tests/Functional/PyCore/scripts/montecarlo_integration.py rename to Tests/Functional/PyCore/legacy/montecarlo_integration.py diff --git a/Tests/Functional/PyCore/scripts/polmagcylinders1.py b/Tests/Functional/PyCore/legacy/polmagcylinders1.py similarity index 100% rename from Tests/Functional/PyCore/scripts/polmagcylinders1.py rename to Tests/Functional/PyCore/legacy/polmagcylinders1.py diff --git a/Tests/Functional/PyCore/scripts/polmagcylinders2.py b/Tests/Functional/PyCore/legacy/polmagcylinders2.py similarity index 100% rename from Tests/Functional/PyCore/scripts/polmagcylinders2.py rename to Tests/Functional/PyCore/legacy/polmagcylinders2.py diff --git a/Tests/Functional/PyCore/scripts/ripple1.py b/Tests/Functional/PyCore/legacy/ripple1.py similarity index 100% rename from Tests/Functional/PyCore/scripts/ripple1.py rename to Tests/Functional/PyCore/legacy/ripple1.py diff --git a/Tests/Functional/PyCore/scripts/ripple2_asym.py b/Tests/Functional/PyCore/legacy/ripple2_asym.py similarity index 100% rename from Tests/Functional/PyCore/scripts/ripple2_asym.py rename to Tests/Functional/PyCore/legacy/ripple2_asym.py diff --git a/Tests/Functional/PyCore/scripts/ripple2_sym.py b/Tests/Functional/PyCore/legacy/ripple2_sym.py similarity index 100% rename from Tests/Functional/PyCore/scripts/ripple2_sym.py rename to Tests/Functional/PyCore/legacy/ripple2_sym.py diff --git a/Tests/Functional/PyCore/scripts/transform_BoxComposition.py b/Tests/Functional/PyCore/legacy/transform_BoxComposition.py similarity index 100% rename from Tests/Functional/PyCore/scripts/transform_BoxComposition.py rename to Tests/Functional/PyCore/legacy/transform_BoxComposition.py diff --git a/Tests/Functional/PyCore/scripts/transform_CoreShellBox.py b/Tests/Functional/PyCore/legacy/transform_CoreShellBox.py similarity index 100% rename from Tests/Functional/PyCore/scripts/transform_CoreShellBox.py rename to Tests/Functional/PyCore/legacy/transform_CoreShellBox.py diff --git a/Tests/Functional/PyCore/scripts/transform_box.py b/Tests/Functional/PyCore/legacy/transform_box.py similarity index 100% rename from Tests/Functional/PyCore/scripts/transform_box.py rename to Tests/Functional/PyCore/legacy/transform_box.py diff --git a/Tests/Functional/PyCore/scripts/transform_cube.py b/Tests/Functional/PyCore/legacy/transform_cube.py similarity index 100% rename from Tests/Functional/PyCore/scripts/transform_cube.py rename to Tests/Functional/PyCore/legacy/transform_cube.py diff --git a/Tests/Functional/PyCore/scripts/utils.py b/Tests/Functional/PyCore/legacy/utils.py similarity index 100% rename from Tests/Functional/PyCore/scripts/utils.py rename to Tests/Functional/PyCore/legacy/utils.py diff --git a/Tests/Functional/PyCore/persistence/CMakeLists.txt b/Tests/Functional/PyCore/persistence/CMakeLists.txt new file mode 100644 index 00000000000..dceb4ae996c --- /dev/null +++ b/Tests/Functional/PyCore/persistence/CMakeLists.txt @@ -0,0 +1,29 @@ +############################################################################ +# Tests/Functional/PyCore/suite/CMakeLists.txt +############################################################################ + +set(test_cases + ApproximationDA + ApproximationLMA + ToBeReplacedByGlob +) + +# for some reason these flags doesn't propagated here by SetUpWindows.cmake +if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc ") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /EHsc ") +endif() + +include_directories( + ${BornAgainCore_INCLUDE_DIRS} + ${EIGEN3_INCLUDE_DIR} + ${CMAKE_SOURCE_DIR}/Core/Simulation + ${CMAKE_CURRENT_SOURCE_DIR}/../../TestMachinery +) + +add_executable(PyPersistenceTest RunPyPersistenceTest.cpp PyPersistenceTest.h PyPersistenceTest.cpp) +target_link_libraries(PyPersistenceTest BornAgainCore BornAgainTestMachinery) +foreach(test_case ${test_cases}) + add_test(PyPersistenceTest/${test_case} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/PyPersistenceTest ${test_case}) +endforeach() diff --git a/Tests/Functional/PyCore/persistence/PyPersistenceTest.cpp b/Tests/Functional/PyCore/persistence/PyPersistenceTest.cpp new file mode 100644 index 00000000000..80aead66d91 --- /dev/null +++ b/Tests/Functional/PyCore/persistence/PyPersistenceTest.cpp @@ -0,0 +1,108 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file Tests/Functional/PyCore/suite/PyPersistenceTest.cpp +//! @brief Implements class PyPersistenceTest +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "PyPersistenceTest.h" +#include "BAPython.h" +#include "FileSystem.h" +#include "GISASSimulation.h" +#include "IntensityDataFunctions.h" +#include "IntensityDataIOFactory.h" +#include "PythonFormatting.h" +#include "SimulationFactory.h" +#include "TestConfig.h" +#include "Utils.h" +#include <cstdio> +#include <cstdlib> +#include <fstream> + +PyPersistenceTest::PyPersistenceTest(const std::string& name) + : IFunctionalTest(name, "persistence test on script "+name) + , m_reference_simulation(nullptr) + , m_domain_simulation(0) + , m_threshold(2e-10) + , m_difference(0) + , m_pyscript_filename( BUILD_TMP_DIR + "/pysuite_" + name + ".py" ) + , m_output_filename( BUILD_TMP_DIR + "/pysuite_" + name + ".int" ) +{ +} + +PyPersistenceTest::~PyPersistenceTest() +{ + delete m_reference_simulation; + delete m_domain_simulation; +} + +void PyPersistenceTest::runTest() +{ + // Generate Python script + std::ostringstream ostr; + ostr << "# Functional test settings, generated by PyPersistenceTest::runTest():\n" + << "import sys, os\n" + << "sys.path.append('" << BUILD_LIB_DIR << "')\n\n" + << "# Simulation script, generated by PythonFormatting::simulationToPython(..):\n" + << PythonFormatting::simulationToPython(m_reference_simulation); + std::ofstream pythonFile(m_pyscript_filename); + pythonFile << ostr.str(); + pythonFile.close(); + std::cout << "Generated Python script " << m_pyscript_filename <<"." << std::endl/*sic*/; + // Here we are using std::endl instead of "\n" in order to flush because otherwise + // the system calls 'remove' and 'system' may break the order of output lines. + + // Run Python script + std::remove( m_output_filename.c_str() ); + std::cout << "Removed old data set " << m_output_filename << "." << std::endl/*sic*/; + std::string command = std::string(BORNAGAIN_PYTHON_EXE) + " " + m_pyscript_filename + + " " + m_output_filename; + std::cout << "Now running command '" << command << "'." << std::endl/*sic*/; + int ret = std::system(command.c_str()); // run python script + if (ret!=0) { + std::cerr << "Command returned non-zero value " << ret << ".\n"; + m_result = FAILED; + return; + } + + // Run direct simulation + std::cout << + "Now going to directly run the simulation, and to compare with result from Py script.\n"; + assert(m_reference_simulation); + m_reference_simulation->runSimulation(); + const std::unique_ptr<OutputData<double> > P_reference_data( + m_reference_simulation->getDetectorIntensity()); + + // Compare results + const std::unique_ptr<OutputData<double> > P_domain_data( + IntensityDataIOFactory::readOutputData(m_output_filename)); + m_difference = IntensityDataFunctions::getRelativeDifference(*P_domain_data, *P_reference_data); + m_result = m_difference > m_threshold ? FAILED_DIFF : SUCCESS; + if (m_result != SUCCESS) { + // Move failed Python script to failed tests directory + Utils::FileSystem::CreateDirectory(FAILED_TESTS_DIR); + std::rename( m_pyscript_filename.c_str(), getPySuiteFileNameAndPath().c_str()); + } +} + +void PyPersistenceTest::printResults(std::ostream& ostr) const +{ + ostr << getFormattedInfoString(); + ostr << Utils::String::getScientificDoubleString(m_difference); + if (m_result != SUCCESS) + ostr << "--> " << getPySuiteFileNameAndPath(); +} + +std::string PyPersistenceTest::getPySuiteFileNameAndPath() const +{ + std::string result = Utils::FileSystem::GetJoinPath(FAILED_TESTS_DIR, m_pyscript_filename); + return result; +} diff --git a/Tests/Functional/PyCore/persistence/PyPersistenceTest.h b/Tests/Functional/PyCore/persistence/PyPersistenceTest.h new file mode 100644 index 00000000000..5fb12070b8f --- /dev/null +++ b/Tests/Functional/PyCore/persistence/PyPersistenceTest.h @@ -0,0 +1,53 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file Tests/Functional/PyCore/suite/PyPersistenceTest.h +//! @brief Declares class PyPersistenceTest +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#ifndef PYSUITETEST_H +#define PYSUITETEST_H + +#include "IFunctionalTest.h" // inheriting from +#include "OutputData.h" + +//! @class PyPersistenceTest +//! @ingroup standard_samples +//! @brief A functional test of PyCore (the Python wrapper of BornAgain/Core). +//! Performs a given standard simulation, both directly and from a Python dump. +//! Invoked from PyPersistenceStandardTest. + +class PyPersistenceTest : public IFunctionalTest +{ +public: + PyPersistenceTest(const std::string& name); + ~PyPersistenceTest() final; + + void runTest() final; + + const OutputData<double>* getOutputData() const; + + double getDifference() const { return m_difference; } + + void printResults(std::ostream& ostr) const final; + +private: + std::string getPySuiteFileNameAndPath() const; + + class GISASSimulation* m_reference_simulation; + class GISASSimulation* m_domain_simulation; + double m_threshold; + double m_difference; + std::string m_pyscript_filename; + std::string m_output_filename; +}; + +#endif // PYSUITETEST_H diff --git a/Tests/Functional/PyCore/persistence/RunPyPersistenceTest.cpp b/Tests/Functional/PyCore/persistence/RunPyPersistenceTest.cpp new file mode 100644 index 00000000000..4fb9d9aef33 --- /dev/null +++ b/Tests/Functional/PyCore/persistence/RunPyPersistenceTest.cpp @@ -0,0 +1,31 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file Tests/Functional/PyCore/suite/PyPersistenceStandardTest.cpp +//! @brief Implements program PyPersistenceStandardTest, to run functional tests +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2015 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "PyPersistenceTest.h" +#include <cstdlib> +#include <iostream> + +//! Runs PyPersistenceTest on a standard simulation indicated by argv[1]. +int main(int argc, char** argv) +{ + if(argc<3){ + std::cout << "Usage: " << argv[0] << " <scriptname [without extension .py]>\n"; + std::exit(1); + } + PyPersistenceTest test(argv[1]); + test.runTest(); + std::cout << test << "\n"; + return test.getTestResult(); +} -- GitLab