# 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 fq offspec sas 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()

# Register one SAS form-factor example, with and without absorption.
function(test_ff geometry label relative_absorption tolerance)
    set(EXAMPLE sas/sas-ff)
    parse_example(${EXAMPLE})
    set(TARGET_NAME Example.sas.FF${geometry}.${label}.persist)
    cmake_path(SET outfile NORMALIZE ${OUTPUT_DIR}/sas/FF${geometry}.${label})
    cmake_path(SET reffile
        NORMALIZE ${REFERENCE_DIR_MINIEXAMPLES}/sas/FF${geometry}.${label})
    add_custom_target(${TARGET_NAME}.fig
        ${launch_env} ${launch_py} ${PUBL_SCRIPT}
            particle_geometry=${geometry}
            relative_absorption=${relative_absorption}
            figfile=${FIG_DIR}/sas/FF${geometry}.${label}.png)
    add_dependencies(figures ${TARGET_NAME}.fig)
    add_test(NAME ${TARGET_NAME}
        ${launch_env} ${launch_py} ${MINI_SCRIPT}
            particle_geometry=${geometry}
            relative_absorption=${relative_absorption}
            datfile=${outfile}
            tolerance=${tolerance}
            reference=${reffile}
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
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)

foreach(geometry
    BarLorentz
    Bipyramid4
    Box
    CantellatedCube
    Cone
    CosineRippleBox
    Cylinder
    Ellipsoid
    EllipsoidalCylinder
    EllipsoidalSegment
    HorizontalCylinder
    Icosahedron
    PlatonicOctahedron
    PlatonicTetrahedron
    Prism3
    Prism6
    Pyramid2
    Pyramid3
    Pyramid4
    Pyramid6
    SawtoothRippleBox
    Sphere
    SphericalSegment
    Spheroid
    SpheroidalSegment
    TruncatedCube)
    test_ff(${geometry} noabs 0   2e-10)
    test_ff(${geometry} absor 0.1 2e-10)
endforeach()
test_ff(Dodecahedron noabs 0   2e-9) # reduced accuracy on i386
test_ff(Dodecahedron absor 0.1 2e-9) # reduced accuracy on i386

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/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)
test_example(offspec/OffspecResolved 2e-10)
test_example(offspec/OffspecResonator 2e-10)
test_example(offspec/YonedaBA 2e-10)

test_example(scatter2d/Approximations 2e-10)
test_example(scatter2d/AttachAboveSubstrate 2e-10)
test_equality(scatter2d/AttachBelowVacuum scatter2d/AttachAboveSubstrate 2e-10)
test_example(scatter2d/Background 2e-10)
test_example(scatter2d/BeamDivergence 2e-10)
test_example(scatter2d/BiMaterialCylinders 2e-10)
test_example(scatter2d/BoxesWithSpecularPeak 2e-10)
test_example(scatter2d/BoxCompositionRotateX 2e-10)
test_example(scatter2d/BoxCompositionRotateY 2e-10)
test_example(scatter2d/BoxCompositionRotateZ 2e-10)
test_example(scatter2d/BoxCompositionRotateZandY 2e-10)
test_example(scatter2d/BoxStackComposition 2e-10)
test_example(scatter2d/CenteredSquareLattice2D 2e-10)
test_example(scatter2d/Compound 2e-10)
test_example(scatter2d/CompoundPlus 2e-10)
test_example(scatter2d/CosineRipple 2e-10)
test_example(scatter2d/CoreShellBoxRotateZandY 2e-10)
test_example(scatter2d/CoreShellNanoparticles 2e-10)
test_example(scatter2d/CoreShellNanoparticles2 2e-10)
test_example(scatter2d/CorrelatedRoughness 2e-10)
test_example(scatter2d/CustomFormfactor 2e-10)
test_example(scatter2d/CustomMorphology 2e-10)
test_example(scatter2d/DetectorWithRoi 2e-10)
test_example(scatter2d/Cylinders 2e-10)
test_example(scatter2d/CylindersAndSpecular 2e-10)
test_example(scatter2d/CylindersSlices 2e-10)
test_example(scatter2d/CylindersAndPrisms 2e-10)
test_example(scatter2d/CylindersInAverageLayer 2e-10)
test_example(scatter2d/CylindersInBA 2e-10)
test_example(scatter2d/CylindersInBABeamFromBelow 2e-10)
test_example(scatter2d/CylindersInBATransmission 2e-10)
test_example(scatter2d/DiluteFilm 2e-10)
test_example(scatter2d/Disordered 2e-10)
test_example(scatter2d/DodecahedraSAS 2e-10)
test_example(scatter2d/FilmVsDensity 2e-10)
test_example(scatter2d/FilmVsMonolayer 2e-10)
test_example(scatter2d/FilmVsThickness 2e-10)
test_example(scatter2d/FindPeaks 0.08) # MC integration ==> high tolerance is ok
test_example(scatter2d/FiniteSquareLattice 2e-10)
test_example(scatter2d/GISASAbsorptiveSLDLayers 2e-10)
test_example(scatter2d/HalfSpheresInAverageTopLayer 2e-10)
test_example(scatter2d/HalfSpheresSlices 2e-10)
test_example(scatter2d/HardDisk 2e-10)
test_example(scatter2d/HexParacrystal 2e-10)
test_example(scatter2d/HolesLattice 2e-10)
test_equality(scatter2d/HolesLatticeRef scatter2d/HolesLattice 2e-10)
test_example(scatter2d/Interference1DLattice 0.1) # MC integration ==> high tolerance is ok
test_example(scatter2d/LargeParticles 0.05) # MC integration ==> high tolerance is ok
test_example(scatter2d/Lattice2dWithBasis 2e-10)
test_example(scatter2d/LatticeOrientationDistribution 2e-10)
test_example(scatter2d/MagneticCylinders 2e-10)
test_example(scatter2d/MagneticCylindersUnpol 2e-10)
test_example(scatter2d/MagneticParticleZeroField 2e-10)
test_example(scatter2d/MagneticRotationUnpol 2e-10)
test_example(scatter2d/MagneticRotationZPM 2e-10)
test_example(scatter2d/MagneticSpheres 2e-10)
test_example(scatter2d/MagneticSpheresInMagLayer 2e-10)
test_example(scatter2d/MagneticSpheresTransmission 5e-10)
test_example(scatter2d/MagneticSubstrateZeroField 2e-10)
test_example(scatter2d/Mesocone 2e-10)
test_example(scatter2d/Mesocrystal 2e-10)
test_example(scatter2d/MesocrystalEvanescent 2e-10)
test_example(scatter2d/MesocrystalSlices 2e-10)
run_example(scatter2d/MesocrystalWithBasisSlices)
test_equality(scatter2d/MesocrystalPlus scatter2d/CompoundPlus 2e-10)
test_example(scatter2d/MesocrystalWithBasis 2e-10)
test_example(scatter2d/MultiLayerWithLinearGrowth 2e-10)
test_example(scatter2d/MultiLayerWithRoughness 2e-10)
test_example(scatter2d/MultipleLayout 2e-10)
test_example(scatter2d/Paracrystal 2e-10)
test_example(scatter2d/ParticleAcrossInterface 2e-10)
test_example(scatter2d/PolarizedSANS 2e-10)
test_example(scatter2d/PolydisperseCylinders 2e-10)
test_example(scatter2d/PositionVariance 2e-10)
test_example(scatter2d/RadialParacrystal 2e-10)
test_example(scatter2d/RectangularGrating 0.06) # MC integration ==> high tolerance is ok
test_example(scatter2d/RectParacrystal 2e-10)
test_example(scatter2d/Resolution 2e-10)
test_example(scatter2d/RotatedPyramids 2e-10)
test_example(scatter2d/RotatedSquareLattice2D 2e-10)
# test_example(scatter2d/RoughAndSpecular 0.3) # TODO: issue 864
test_example(scatter2d/SawtoothRipple 2e-10)
test_example(scatter2d/SlicedComposition 2e-10)
test_example(scatter2d/SlicedLayer 2e-10)
test_example(scatter2d/SoftSpheres 2e-10)
test_example(scatter2d/SoftSpheresFilm 2e-10)
test_example(scatter2d/SquareLattice 2e-10)
test_example(scatter2d/SquareLattice2D 2e-10)
test_example(scatter2d/LatticeWithSpecular 2e-10)
test_example(scatter2d/ThickAbsorptiveSampleWithRoughness 2e-10)
test_example(scatter2d/TriangularRipple 2e-10)
test_example(scatter2d/TriangularRipplePC 2e-10)
test_example(scatter2d/TwoLayerLattice 2e-10)
test_example(scatter2d/VsQ 2e-10)

test_example(specular/AlternatingLayers1 2e-13)
test_equality(specular/AlternatingLayers2 specular/AlternatingLayers1 2e-13)
test_example(specular/SpecularWithSlicing2 2e-10)
test_example(specular/SpecularWithSlicing2Q 2e-10)
test_equality(specular/SpecularWithSlicing1 specular/SpecularWithSlicing2 2e-12)
test_equality(specular/SpecularWithSlicing3 specular/SpecularWithSlicing2 2e-10)
test_example(specular/Background 2e-10)
test_example(specular/BasicSpecular 2e-10)
test_example(specular/BeamFullDivergence 2e-10)
test_example(specular/Distributions 2e-10)
test_example(specular/FootprintCorrection 2e-10)
test_example(specular/GaussianBeams 1e-3)
test_example(specular/HomogeneousTiNiSampleWithAbsorption 2e-10)
test_example(specular/InstrumentDefinitionComparison 2e-10)
test_example(specular/MagneticFieldMinusZ 2e-10)
test_example(specular/MagneticLayer 2e-10)
test_example(specular/MagneticLayerImperfect 2e-10)
test_example(specular/MagneticRotationReflectivity 1e-7)
test_example(specular/NCRoughnessInSpecular 2e-10)
test_example(specular/PolarizedFeNiBilayer 1e-7)
test_example(specular/PolarizedFeNiBilayerNC 1e-7)
test_example(specular/PolarizedFeNiBilayerNCQ 1e-7)
test_example(specular/PolarizedFeNiBilayerQ 1e-7)
test_example(specular/PolarizedFeNiBilayerSpinFlip 1e-7)
test_example(specular/PolarizedFeNiBilayerSpinFlipNC 1e-7)
test_example(specular/PolarizedFeNiBilayerSpinFlipNCQ 1e-7)
test_example(specular/PolarizedFeNiBilayerSpinFlipQ 1e-7)
test_example(specular/PolarizedFeNiBilayerSpinFlipTanh 1e-7)
test_example(specular/PolarizedFeNiBilayerSpinFlipTanhQ 1e-7)
test_example(specular/PolarizedFeNiBilayerTanh 1e-7)
test_example(specular/PolarizedFeNiBilayerTanhQ 1e-7)
test_example(specular/PolarizedQAngleReflectivity 2e-10)
test_example(specular/PolarizedSpinAsymmetry 2e-10)
test_example(specular/RoughnessModel 2e-10)
test_example(specular/SpecularSimulationWithRoughness 2e-10)
test_example(specular/TOFRWithResolution 2e-10)
test_equality(specular/TOFRelativeResolution specular/TOFRWithResolution 2e-10)
test_example(specular/TimeOfFlightReflectometry 2e-10)
test_example(specular/VsGenx 2e-10)

test_example(varia/Depthprobe 2e-10)
test_example(varia/Depthprobe1 2e-10)
run_example(varia/MaterialProfile)
run_example(varia/MaterialProfileWithParticles)
test_example(varia/Opaque2D 2e-9)
test_example(varia/OpaqueVsAlpha 2e-9)
test_example(varia/OpaqueVsDepth 2e-9)
test_example(varia/Resonator 2e-10)
run_example(varia/RoughSurface 2e-10)
test_example(varia/TransmittedModulus 2e-10)
test_example(varia/Transmission 2e-10)
