# BornAgain/Tests/Examples/CMakeLists.txt
#
# For the Python scripts in directory BornAgain/Examples:
# - test against reference, with mini detectors
# - under target 'figures', generate high-resolution figures for hugo
# - under target 'excopy', copy example sources to hugo

set(OUTPUT_DIR ${TEST_OUTPUT_DIR}/MiniExamples)
file(MAKE_DIRECTORY ${OUTPUT_DIR})

set(FIG_DIR ${CMAKE_SOURCE_DIR}/hugo/static/img/auto)

add_custom_target(figures) # generate high-resolution figures and store them in FIG_DIR
add_custom_target(manualtest)

file(MAKE_DIRECTORY ${FIG_DIR})
foreach(subdir ff fq offspec scatter2d specular varia)
    file(MAKE_DIRECTORY ${OUTPUT_DIR}/${subdir})
    file(MAKE_DIRECTORY ${FIG_DIR}/${subdir})
endforeach()

add_custom_target(excopy
    COMMAND ${CMAKE_COMMAND} -E copy_directory ${EXAMPLES_PUBL_DIR}
       ${CMAKE_SOURCE_DIR}/hugo/static/py/auto/Examples)

####################################################################################################
#  Test functions
####################################################################################################

macro(parse_example example)
    cmake_path(SET MINI_SCRIPT NORMALIZE ${EXAMPLES_TEST_DIR}/${example}.py)
    cmake_path(SET PUBL_SCRIPT NORMALIZE ${EXAMPLES_FIGURES_DIR}/${example}.py)
    get_filename_component(EXAMPLE_NAME ${MINI_SCRIPT} NAME_WE)
    get_filename_component(EXAMPLE_SUBDIR ${example} DIRECTORY)
endmacro()

set(launch_env COMMAND ${CMAKE_COMMAND} -E env)
set(launch_py
    BA_DATA_DIR=${EXAMPLES_DATA_DIR}
    PYTHONPATH=${BA_PY_SOURCE_OUTPUT_DIR}
    ${Python3_EXECUTABLE})

# Register example that plots but has no persistence test.
function(run_example example)
    parse_example(${example})
    string(REPLACE "/" "." TARGET_NAME Example.${example}.fig)
    add_test(NAME Example.run.${EXAMPLE_NAME}
        ${launch_env} ${launch_py} ${MINI_SCRIPT})
    add_custom_target(${TARGET_NAME}
        ${launch_env} ${launch_py} ${PUBL_SCRIPT}
           figfile=${FIG_DIR}/${EXAMPLE_SUBDIR}/${EXAMPLE_NAME}.png)
    add_dependencies(figures ${TARGET_NAME})
endfunction()

# Register example that has no output but is tested for running through.
function(run_plotless example)
    parse_example(${example})
    string(REPLACE "/" "." TARGET_NAME Example.${example}.run)
    add_test(NAME ${TARGET_NAME}
        ${launch_env} ${launch_py} ${MINI_SCRIPT}
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
endfunction()

# Register example with target 'manualtest'.
function(run_manually example)
    parse_example(${example})
    string(REPLACE "/" "." TARGET_NAME Example.${example}.manualtest)
    add_custom_target(${TARGET_NAME}
        COMMAND echo "### MANUAL TEST: EXAMPLE ${EXAMPLE_NAME}"
        ${launch_env} ${launch_py} ${MINI_SCRIPT}
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
    add_dependencies(manualtest ${TARGET_NAME})
endfunction()

# Register example that plots and has persistence test.
function(test_equality example reference tolerance)
    parse_example(${example})
    string(REPLACE "/" "." TARGET_NAME Example.${example}.persist)
    cmake_path(SET outfile NORMALIZE ${OUTPUT_DIR}/${example})
    cmake_path(SET reffile NORMALIZE ${REFERENCE_DIR_MINIEXAMPLES}/${reference})
    add_custom_target(${TARGET_NAME}
        ${launch_env} ${launch_py} ${PUBL_SCRIPT}
            figfile=${FIG_DIR}/${EXAMPLE_SUBDIR}/${EXAMPLE_NAME}.png)
    add_dependencies(figures ${TARGET_NAME})
    add_test(NAME ${TARGET_NAME}
        ${launch_env} ${launch_py} ${MINI_SCRIPT} datfile=${outfile}
            tolerance=${tolerance} reference=${reffile}
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
endfunction()

# Python persistence test: run modified example, and compare with reference data.
function(test_example example tolerance)
    test_equality(${example} ${example} ${tolerance})
endfunction()

####################################################################################################
#  Test collection
####################################################################################################

# Relatively high tolerance is not a problem for the tests involving Monte Carlo integration
# because of its probabilistic nature.
# The more integration points, the less the dispersion of the results.
# But unlike other types of examples, MC integration over detector pixels is very
# unstable if bins are too large and intensity within a pixel varies
# by many orders of magnitudes.
# If the test fails too frequently and the discrepancy is too high, increase
# not just the number of integration points, but also the number of detector pixels
# and update the reference data.

run_plotless(bayesian/likelihood_sampling)

test_example(ff/BarLorentz 2e-10)
test_example(ff/Bipyramid4 2e-10)
test_example(ff/Box 2e-10)
test_example(ff/CantellatedCube 2e-10)
test_example(ff/Cone 2e-10)
test_example(ff/CosineRippleBox 2e-10)
test_example(ff/Cylinder 2e-10)
test_example(ff/Dodecahedron 2e-9) # reduced accuracy on i386
test_example(ff/EllipsoidalCylinder 2e-10)
test_example(ff/HemiEllipsoid 2e-10)
test_example(ff/HorizontalCylinder 2e-10)
test_example(ff/Icosahedron 2e-10)
test_example(ff/PlatonicOctahedron 2e-10)
test_example(ff/PlatonicTetrahedron 2e-10)
test_example(ff/Prism3 2e-10)
test_example(ff/Prism6 2e-10)
test_example(ff/Pyramid2 2e-10)
test_example(ff/Pyramid3 2e-10)
test_example(ff/Pyramid4 2e-10)
test_example(ff/Pyramid6 2e-10)
test_example(ff/SawtoothRippleBox 2e-10)
test_example(ff/Sphere 2e-10)
test_example(ff/Spheroid 2e-10)
test_example(ff/TruncatedCube 2e-10)
test_example(ff/SphericalSegment 2e-10)
test_example(ff/SpheroidalSegment 2e-10)

run_plotless(fit/algo/fit_rosenbrock)

run_plotless(fit/scatter2d/consecutive_fitting)
run_plotless(fit/scatter2d/custom_objective_function)
# run_plotless(fit/scatter2d/expfit_galaxi) issue #813
run_plotless(fit/scatter2d/find_background)
run_plotless(fit/scatter2d/fit2d)
run_plotless(fit/scatter2d/fit_along_slices)
run_plotless(fit/scatter2d/fit_gisas)
run_plotless(fit/scatter2d/fit_with_masks)
run_plotless(fit/scatter2d/lmfit_basics)
run_plotless(fit/scatter2d/lmfit_with_plotting)
run_plotless(fit/scatter2d/minimizer_settings)
run_plotless(fit/scatter2d/multiple_datasets)

if (Python3_VERSION_MINOR GREATER 8)
    run_plotless(fit/specular/Honeycomb_fit)
    run_plotless(fit/specular/Pt_layer_fit)
endif()
run_plotless(fit/specular/PolarizedSpinAsymmetryFit)
run_plotless(fit/specular/TREFF_Ni_film)
run_example(fit/specular/Specular1Par)

run_example(fq/Sphere)

test_example(offspec/Offspec1 2e-10)
test_example(offspec/OffspecLambda 2e-10) # issue #711
test_example(offspec/OffspecResolved 2e-10) # issue #711

test_example(scatter2d/ApproximationDA 2e-10)
test_example(scatter2d/ApproximationLMA 2e-10)
test_example(scatter2d/ApproximationSSCA 2e-10)
# run_example(scatter2d/AxesInDifferentUnits) issue #815
test_example(scatter2d/BeamDivergence 2e-10)
test_example(scatter2d/BiMaterialCylinders 2e-10)
test_example(scatter2d/BoxesWithSpecularPeak 2e-10)
test_example(scatter2d/ConstantBackground 2e-10)
test_example(scatter2d/CoreShellNanoparticles 2e-10)
test_example(scatter2d/CoreShellNanoparticles2 2e-10)
test_example(scatter2d/CorrelatedRoughness 2e-10)
test_example(scatter2d/CosineRipplesAtRectLattice 2e-10)
test_example(scatter2d/CustomFormfactor 2e-10)
test_example(scatter2d/Cylinders 2e-10)
test_example(scatter2d/CylindersAndPrisms 2e-10)
test_example(scatter2d/CylindersInAverageLayer 2e-10)
test_example(scatter2d/CylindersInBA 2e-10)
test_example(scatter2d/DodecahedraSAS 2e-10)
test_example(scatter2d/FindPeaks 0.08) # MC integration ==> high tolerance is ok
test_example(scatter2d/HalfSpheresInAverageTopLayer 2e-10)
test_example(scatter2d/HexagonalLatticesWithBasis 2e-10)
test_example(scatter2d/Interference1DLattice 0.1) # MC integration ==> high tolerance is ok
test_example(scatter2d/Interference1DRadialParacrystal 2e-10)
test_example(scatter2d/Interference2DCenteredSquareLattice 2e-10)
test_example(scatter2d/Interference2DParacrystal 2e-10)
test_example(scatter2d/Interference2DRotatedSquareLattice 2e-10)
test_example(scatter2d/Interference2DSquareFiniteLattice 2e-10)
test_example(scatter2d/LargeParticles 0.05) # MC integration ==> high tolerance is ok
test_example(scatter2d/LatticeOrientationDistribution 2e-10)
test_example(scatter2d/MagneticCylinders1 2e-10)
test_example(scatter2d/MagneticCylinders2 2e-10)
test_example(scatter2d/MagneticSpheres 2e-10)
test_example(scatter2d/Mesocrystal 2e-10)
test_example(scatter2d/Mesocrystal2 2e-10)
test_example(scatter2d/Mesocrystal3 2e-10)
test_example(scatter2d/Mesocrystal4 2e-10)
test_example(scatter2d/ParticleAcrossInterface 2e-10)
test_example(scatter2d/PolarizedSANS 2e-10)
test_example(scatter2d/PolydisperseCylinders 2e-10)
run_example(scatter2d/PositionVariance) # TODO: issue 1145
test_example(scatter2d/RectangularGrating 0.06) # MC integration ==> high tolerance is ok
test_example(scatter2d/Resolution 2e-10)
test_example(scatter2d/RotatedPyramids 2e-10)
# test_example(scatter2d/RoughAndSpecular 0.3) # TODO: issue 864
test_example(scatter2d/SlicedLayer 2e-10)
test_example(scatter2d/TriangularRipple 2e-10)

test_example(specular/AlternatingLayers1 2e-13)
test_equality(specular/AlternatingLayers2 specular/AlternatingLayers1 2e-13)
test_example(specular/BeamFullDivergence 2e-10)
test_example(specular/Distributions 2e-10)
test_example(specular/FootprintCorrection 2e-10)
# test_example(specular/GaussianBeams 1e-3) # TODO: issue 1132
test_example(specular/MagneticLayer 2e-10)
test_example(specular/MagneticLayerImperfect 2e-10)
run_example(specular/PolarizedSpinAsymmetry)
test_example(specular/RoughnessModel 2e-10)
test_example(specular/SpecularSimulationWithRoughness 2e-10)
test_example(specular/TOFRWithResolution 2e-10)
test_example(specular/TimeOfFlightReflectometry 2e-10)
test_example(specular/VsGenx 2e-10)

test_example(varia/Depthprobe1 2e-10)
run_example(varia/MaterialProfile)
run_example(varia/MaterialProfileWithParticles)
test_example(varia/Resonator 2e-10)
test_example(varia/RoughSurface 2e-10)
test_example(varia/TransmittedModulus 2e-10)
