From 59cf50f9b5f0e9c0ebcc84c115cbbf727f8ca946 Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Tue, 26 Sep 2023 14:35:37 +0200 Subject: [PATCH 01/19] added setup interface and unit tests --- src/QEDprocesses.jl | 5 ++ src/interfaces/setup_interface.jl | 114 +++++++++++++++++++++++++++++ test/interfaces/setup_interface.jl | 90 +++++++++++++++++++++++ test/runtests.jl | 3 + 4 files changed, 212 insertions(+) create mode 100644 src/interfaces/setup_interface.jl create mode 100644 test/interfaces/setup_interface.jl diff --git a/src/QEDprocesses.jl b/src/QEDprocesses.jl index e9184bd..4520344 100644 --- a/src/QEDprocesses.jl +++ b/src/QEDprocesses.jl @@ -13,6 +13,10 @@ export initial_phasespace_dimension, final_phasespace_dimension export number_incoming_particles, number_outgoing_particles export differential_cross_section, total_cross_section +# Abstract setup interface +export AbstractComputationSetup, compute +export AbstractProcessSetup, scattering_process, compute_model + # particle types export AbstractParticleType export FermionLike, Fermion, AntiFermion, MajoranaFermion @@ -26,5 +30,6 @@ include("utils.jl") include("interfaces/particle_interface.jl") include("interfaces/model_interface.jl") include("interfaces/process_interface.jl") +include("interfaces/setup_interface.jl") include("particle_types.jl") end diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl new file mode 100644 index 0000000..2a555ff --- /dev/null +++ b/src/interfaces/setup_interface.jl @@ -0,0 +1,114 @@ +############### +# The process setup +# +# In this file, we define the interface for process setups. A `setup` means +# here, a collection of setup-data needed to evaluate a dedicated quantity on a given +# running data. Despite that, the decomposition into setup and running data is +# arbitrary, this will be used for cases where a subset of the variables a +# quantity depends on is kept constant. +# +# This file is part of `QEDprocesses.jl` which is by itself part of the `QED.jl` +# ecosystem. +# +############### + +# base type for any setup, will most properbly be defined somewhere else, +# e.g. QEDbase, therefore it is not exported +abstract type AbstractComputationSetup end + +""" + + _is_valid_input(stp::AbstractComputationSetup, input::Any) + +Interface function, which returns true, if the constraints of the `input` associated with the quantity of `stp` are met. +This function will be called to validate the input of [`compute`](@ref) before calling [`_compute`](@ref). + +!!! note "Default implementation" + + Since no input validation is equivalent to every input being valid, this functions returns `true` per default. + This behaviour needs to be overwritten, if this is not the case. + +""" +@inline function _input_validation(stp::AbstractComputationSetup, input) + return true +end + +""" + + function _post_computation(stp::AbstractComputationSetup, input::Any, result::Any) + +Interface functions which is called in [`compute`](@ref) after [`_compute`](@ref) was called. This function is dedicated to +finalize the result of a computation. + +!!! note "default implementation" + + Since in the case of no post computation, the result of [`_compute`](@ref) is not changed, this function returns `result` per default. + +""" +@inline function _post_computation(stp::AbstractComputationSetup, input, result) + return result +end + +""" + + _compute(stp::AbstractComputationSetup, input::Any) + +Interface function which returns the value of the associated quantity evaluated on `input`, which can be anything the associated quantity is defined to be feasable for. + +!!! note "unsafe implementation" + + This function should be implemented without any input validation or post computations (see [`_input_validation`](@ref) and [`_post_computation`](@ref)). The latter two are performed while calling + the safe version of this function [`compute`](@ref). + +""" +function _compute end + + + +function compute(stp::AbstractComputationSetup, input) + _input_validation(stp,input) || error("InvalidInputError: there is something wrong with the input!\n setup:$stp \n input:$input") + raw_result = _compute(stp,input) + return _post_computation(stp, input,raw_result) +end + +""" +Abstract base type for setups related to a combination scattering processes and compute models. +Every subtype of `AbstractProcessSetup` is expected to implement at least the following +interface functions + +```Julia +scattering_process(::AbstractProcessSetup) +compute_model(::AbstractProcessSetup) +``` +where `x` is the running input, i.e. a *single point* the quantity is evaluated on. + +Derived from the these interface functions, the following delegations are implemented + +```Julia +number_incoming_particles(::AbstractProcessSetup) +number_outgoing_particles(::AbstractProcessSetup) +``` +""" +abstract type AbstractProcessSetup <: AbstractComputationSetup end + +""" + + scattering_process(stp::AbstractProcessSetup) + +Interface function, which returns the scattering process associated with `stp`, +i.e. an object which is a subtype of `AbstractProcessDefinition`. +""" +function scattering_process end + +""" + + compute_model(stp::AbstractProcessSetup) + +Interface function, which returns the compute model associated with `stp`, i.e. +an object which is subtype of `AbstractModelDefinition` +""" +function compute_model end + +@inline number_incoming_particles(stp::AbstractProcessSetup) = number_incoming_particles(scattering_process(stp)) +@inline number_outgoing_particles(stp::AbstractProcessSetup) = number_outgoing_particles(scattering_process(stp)) + diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl new file mode 100644 index 0000000..0137ba7 --- /dev/null +++ b/test/interfaces/setup_interface.jl @@ -0,0 +1,90 @@ + +using Random +using QEDbase +using QEDprocesses + +RNG = MersenneTwister(137137) +ATOL = 0.0 +RTOL = sqrt(eps()) + + + +_groundthruth_compute(x) = x +_groundthruth_input_validation(x) = (x>0) +_transform_to_invalid(x) = -abs(x) +_groundtruth_post_computation(x,y) = x+y + +abstract type AbstractTestSetup <: AbstractComputationSetup end +QEDprocesses._compute(stp::AbstractTestSetup, x) = _groundthruth_compute(x) + +struct TestSetupDefault <: AbstractTestSetup end + +struct TestSetupCustomValidation <: AbstractTestSetup end +QEDprocesses._input_validation(::TestSetupCustomValidation, x) = _groundthruth_input_validation(x) + +struct TestSetupCustomPostComputation <: AbstractTestSetup end +QEDprocesses._post_computation(::TestSetupCustomPostComputation,x,y) = _groundtruth_post_computation(x,y) + +struct TestSetupCustom <: AbstractTestSetup end +QEDprocesses._input_validation(::TestSetupCustom, x) = _groundthruth_input_validation(x) +QEDprocesses._post_computation(::TestSetupCustom,x,y) = _groundtruth_post_computation(x,y) + +# setups which fail on computation +struct TestSetupFAIL <: AbstractComputationSetup end + +struct TestSetupCustomValidationFAIL <: AbstractComputationSetup end +QEDprocesses._input_validation(::TestSetupCustomValidationFAIL, x) = _groundthruth_input_validation(x) + +struct TestSetupCustomPostComputationFAIL <: AbstractComputationSetup end +QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _groundtruth_post_computation(x,y) + +@testset "interface fail" begin + @test_throws MethodError QEDprocesses._compute(TestSetupFAIL()) + @test_throws MethodError compute(TestSetupFAIL()) + + @test_throws MethodError QEDprocesses._compute(TestSetupCustomValidationFAIL()) + @test_throws MethodError compute(TestSetupCustomValidationFAIL()) + + @test_throws MethodError QEDprocesses._compute(TestSetupCustomPostComputationFAIL()) + @test_throws MethodError compute(TestSetupCustomPostComputationFAIL()) +end + +@testset "default interface" begin + stp = TestSetupDefault() + + rnd_input = rand(RNG) + rnd_output = rand(RNG) + @test QEDprocesses._input_validation(stp,rnd_input) + @test QEDprocesses._post_computation(stp,rnd_input,rnd_output) == rnd_output + @test isapprox(QEDprocesses._compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) + @test isapprox(compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) +end + +@testset "custom input validation" begin + stp = TestSetupCustomValidation() + rnd_input = rand(RNG) + @test QEDprocesses._input_validation(stp, _groundthruth_input_validation(rnd_input)) + @test !QEDprocesses._input_validation(stp, !_groundthruth_input_validation(rnd_input)) + @test isapprox(compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) + @test_throws ErrorException compute(stp, _transform_to_invalid(rnd_input)) +end + +@testset "custom post computation" begin + stp = TestSetupCustomPostComputation() + rnd_input = rand(RNG) + rnd_output = rand(RNG) + @test isapprox(QEDprocesses._post_computation(stp,rnd_input,rnd_output), _groundtruth_post_computation(rnd_input,rnd_output)) + @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundthruth_compute(rnd_input))) +end + +@testset "custom input validation and post computation" begin + stp = TestSetupCustom() + rnd_input = rand(RNG) + rnd_output = rand(RNG) + + @test QEDprocesses._input_validation(stp, _groundthruth_input_validation(rnd_input)) + @test !QEDprocesses._input_validation(stp, !_groundthruth_input_validation(rnd_input)) + @test_throws ErrorException compute(stp, _transform_to_invalid(rnd_input)) + @test isapprox(QEDprocesses._post_computation(stp,rnd_input,rnd_output), _groundtruth_post_computation(rnd_input,rnd_output)) + @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundthruth_compute(rnd_input))) +end diff --git a/test/runtests.jl b/test/runtests.jl index 9e647ff..b6bc916 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -13,6 +13,9 @@ begin @time @safetestset "process interface" begin include("interfaces/process_interface.jl") end + @time @safetestset "computation setup interface" begin + include("interfaces/setup_interface.jl") + end # modules @time @safetestset "particles types" begin From 1158e6dc80b48b50f57ab8fb69dd7b8d024f5776 Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Tue, 26 Sep 2023 15:18:58 +0200 Subject: [PATCH 02/19] fixed bug in process interface --- src/interfaces/process_interface.jl | 31 +++++++++------------------- test/interfaces/process_interface.jl | 5 +++++ 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/interfaces/process_interface.jl b/src/interfaces/process_interface.jl index 678f451..5fbf8fd 100644 --- a/src/interfaces/process_interface.jl +++ b/src/interfaces/process_interface.jl @@ -47,7 +47,7 @@ function outgoing_particles end Return the number of incoming particles of a given process. """ -@inline function number_incoming_pariticles(proc_def::AbstractProcessDefinition) +@inline function number_incoming_particles(proc_def::AbstractProcessDefinition) return length(incoming_particles(proc_def)) end @@ -57,7 +57,7 @@ end Return the number of outgoing particles of a given process. """ -@inline function number_outgoing_pariticles(proc_def::AbstractProcessDefinition) +@inline function number_outgoing_particles(proc_def::AbstractProcessDefinition) return length(outgoing_particles(proc_def)) end @@ -119,23 +119,14 @@ function differential_cross_section( model_def::AbstractModelDefinition, init_phasespace::Union{AbstractVector{T},AbstractMatrix{T}}, final_phasespace::Union{AbstractVector{T},AbstractMatrix{T}}, -) where {T<:QEDbase.AbstractFourMomentum} - size(init_phasespace, 1) == number_incoming_pariticles(proc_def) || throw( - DimensionMismatch( - "The number of momenta in the initial phasespace <{length(init_phasespace)}> does not match the number of incoming particles of the process <{number_incoming_pariticles(proc_def)}>.", - ), - ) - size(final_phasespace, 1) == number_outgoing_pariticles(proc_def) || throw( - DimensionMismatch( - "The number of momenta in the final phasespace <{length(final_phasespace)}> does not match the number of outgoing particles of the process <{number_outgoing_pariticles(proc_def)}>.", - ), + ) where {T<:QEDbase.AbstractFourMomentum} + size(init_phasespace, 1) == number_incoming_particles(proc_def) || throw( + DimensionMismatch("The number of momenta in the initial phasespace <{length(init_phasespace)}> does not match the number of incoming particles of the process <{number_incoming_pariticles(proc_def)}>."), ) - return _differential_cross_section( - proc_def, - model_def, - init_phasespace, - final_phasespace, + size(final_phasespace, 1) == number_outgoing_particles(proc_def) || throw( + DimensionMismatch("The number of momenta in the final phasespace <{length(final_phasespace)}> does not match the number of outgoing particles of the process <{number_outgoing_pariticles(proc_def)}>."), ) + return _differential_cross_section(proc_def, model_def, init_phasespace, final_phasespace) end # returns diffCS for single `initPS` and several `finalPS` points without input-check @@ -265,10 +256,8 @@ function total_cross_section( model_def::AbstractModelDefinition, init_phasespace::Union{AbstractVector{T},AbstractMatrix{T}}, ) where {T<:QEDbase.AbstractFourMomentum} - size(init_phasespace, 1) == number_incoming_pariticles(proc_def) || throw( - DimensionMismatch( - "The number of momenta in the initial phasespace <{length(init_phasespace)}> does not match the number of incoming particles of the process <{number_incoming_pariticles(proc_def)}>.", - ), + size(init_phasespace, 1) == number_incoming_particles(proc_def) || throw( + DimensionMismatch("The number of momenta in the initial phasespace <{length(init_phasespace)}> does not match the number of incoming particles of the process <{number_incoming_pariticles(proc_def)}>."), ) return _total_cross_section(proc_def, model_def, init_phasespace) end diff --git a/test/interfaces/process_interface.jl b/test/interfaces/process_interface.jl index b540907..8440b65 100644 --- a/test/interfaces/process_interface.jl +++ b/test/interfaces/process_interface.jl @@ -77,6 +77,11 @@ end @test outgoing_particles(TestProcess()) == OUTGOING_PARTICLES end + @testset "delegated functions" begin + @test number_incoming_particles(TestProcess()) == N_INCOMING + @test number_outgoing_particles(TestProcess()) == N_OUTGOING + end + @testset "cross section" begin From 9b89be96c3b2fe0c9192e9eb09f1f95f1eb2171f Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Tue, 26 Sep 2023 15:20:03 +0200 Subject: [PATCH 03/19] separated Computation setups and process setups; added post computation system and adjusted tests respectively --- src/interfaces/setup_interface.jl | 3 + test/interfaces/setup_interface.jl | 162 ++++++++++++++++++++--------- 2 files changed, 113 insertions(+), 52 deletions(-) diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index 2a555ff..2305e6a 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -16,6 +16,9 @@ # e.g. QEDbase, therefore it is not exported abstract type AbstractComputationSetup end +# convenience function to check if an object is a computation setup +_is_computation_setup(::AbstractComputationSetup) = true + """ _is_valid_input(stp::AbstractComputationSetup, input::Any) diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl index 0137ba7..7079e9c 100644 --- a/test/interfaces/setup_interface.jl +++ b/test/interfaces/setup_interface.jl @@ -7,84 +7,142 @@ RNG = MersenneTwister(137137) ATOL = 0.0 RTOL = sqrt(eps()) - - _groundthruth_compute(x) = x _groundthruth_input_validation(x) = (x>0) _transform_to_invalid(x) = -abs(x) _groundtruth_post_computation(x,y) = x+y +# setups for which the interface is implemented abstract type AbstractTestSetup <: AbstractComputationSetup end QEDprocesses._compute(stp::AbstractTestSetup, x) = _groundthruth_compute(x) +# setup with default implementations struct TestSetupDefault <: AbstractTestSetup end +# setup with custom input validation struct TestSetupCustomValidation <: AbstractTestSetup end QEDprocesses._input_validation(::TestSetupCustomValidation, x) = _groundthruth_input_validation(x) +# setup with custom post computation struct TestSetupCustomPostComputation <: AbstractTestSetup end QEDprocesses._post_computation(::TestSetupCustomPostComputation,x,y) = _groundtruth_post_computation(x,y) +# setup with custom input validation and post computation struct TestSetupCustom <: AbstractTestSetup end QEDprocesses._input_validation(::TestSetupCustom, x) = _groundthruth_input_validation(x) QEDprocesses._post_computation(::TestSetupCustom,x,y) = _groundtruth_post_computation(x,y) -# setups which fail on computation +# setup which fail on computation with default implementations struct TestSetupFAIL <: AbstractComputationSetup end +# setup which fail on computation with custom input validation struct TestSetupCustomValidationFAIL <: AbstractComputationSetup end QEDprocesses._input_validation(::TestSetupCustomValidationFAIL, x) = _groundthruth_input_validation(x) +# setup which fail on computation with custom post computation struct TestSetupCustomPostComputationFAIL <: AbstractComputationSetup end QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _groundtruth_post_computation(x,y) - -@testset "interface fail" begin - @test_throws MethodError QEDprocesses._compute(TestSetupFAIL()) - @test_throws MethodError compute(TestSetupFAIL()) - - @test_throws MethodError QEDprocesses._compute(TestSetupCustomValidationFAIL()) - @test_throws MethodError compute(TestSetupCustomValidationFAIL()) - - @test_throws MethodError QEDprocesses._compute(TestSetupCustomPostComputationFAIL()) - @test_throws MethodError compute(TestSetupCustomPostComputationFAIL()) -end - -@testset "default interface" begin - stp = TestSetupDefault() - - rnd_input = rand(RNG) - rnd_output = rand(RNG) - @test QEDprocesses._input_validation(stp,rnd_input) - @test QEDprocesses._post_computation(stp,rnd_input,rnd_output) == rnd_output - @test isapprox(QEDprocesses._compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) - @test isapprox(compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) -end - -@testset "custom input validation" begin - stp = TestSetupCustomValidation() - rnd_input = rand(RNG) - @test QEDprocesses._input_validation(stp, _groundthruth_input_validation(rnd_input)) - @test !QEDprocesses._input_validation(stp, !_groundthruth_input_validation(rnd_input)) - @test isapprox(compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) - @test_throws ErrorException compute(stp, _transform_to_invalid(rnd_input)) +@testset "general computation setup interface" begin + @testset "interface fail" begin + rnd_input = rand(RNG) + @test_throws MethodError QEDprocesses._compute(TestSetupFAIL(), rnd_input) + @test_throws MethodError compute(TestSetupFAIL(), rnd_input) + + @test_throws MethodError QEDprocesses._compute(TestSetupCustomValidationFAIL(), rnd_input) + @test_throws MethodError compute(TestSetupCustomValidationFAIL(), rnd_input) + # invalid input should be catched without throwing a MethodError + @test_throws ErrorException compute(TestSetupCustomValidationFAIL(), _transform_to_invalid(rnd_input)) + + @test_throws MethodError QEDprocesses._compute(TestSetupCustomPostComputationFAIL(), rnd_input) + @test_throws MethodError compute(TestSetupCustomPostComputationFAIL(), rnd_input) + end + + @testset "default interface" begin + stp = TestSetupDefault() + + rnd_input = rand(RNG) + rnd_output = rand(RNG) + @test QEDprocesses._input_validation(stp,rnd_input) + @test QEDprocesses._post_computation(stp,rnd_input,rnd_output) == rnd_output + @test isapprox(QEDprocesses._compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) + @test isapprox(compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) + end + + @testset "custom input validation" begin + stp = TestSetupCustomValidation() + rnd_input = rand(RNG) + @test QEDprocesses._input_validation(stp, _groundthruth_input_validation(rnd_input)) + @test !QEDprocesses._input_validation(stp, !_groundthruth_input_validation(rnd_input)) + @test isapprox(compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) + @test_throws ErrorException compute(stp, _transform_to_invalid(rnd_input)) + end + + @testset "custom post computation" begin + stp = TestSetupCustomPostComputation() + rnd_input = rand(RNG) + rnd_output = rand(RNG) + @test isapprox(QEDprocesses._post_computation(stp,rnd_input,rnd_output), _groundtruth_post_computation(rnd_input,rnd_output)) + @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundthruth_compute(rnd_input))) + end + + @testset "custom input validation and post computation" begin + stp = TestSetupCustom() + rnd_input = rand(RNG) + rnd_output = rand(RNG) + + @test QEDprocesses._input_validation(stp, _groundthruth_input_validation(rnd_input)) + @test !QEDprocesses._input_validation(stp, !_groundthruth_input_validation(rnd_input)) + @test_throws ErrorException compute(stp, _transform_to_invalid(rnd_input)) + @test isapprox(QEDprocesses._post_computation(stp,rnd_input,rnd_output), _groundtruth_post_computation(rnd_input,rnd_output)) + @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundthruth_compute(rnd_input))) + end end - -@testset "custom post computation" begin - stp = TestSetupCustomPostComputation() - rnd_input = rand(RNG) - rnd_output = rand(RNG) - @test isapprox(QEDprocesses._post_computation(stp,rnd_input,rnd_output), _groundtruth_post_computation(rnd_input,rnd_output)) - @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundthruth_compute(rnd_input))) -end - -@testset "custom input validation and post computation" begin - stp = TestSetupCustom() - rnd_input = rand(RNG) - rnd_output = rand(RNG) - - @test QEDprocesses._input_validation(stp, _groundthruth_input_validation(rnd_input)) - @test !QEDprocesses._input_validation(stp, !_groundthruth_input_validation(rnd_input)) - @test_throws ErrorException compute(stp, _transform_to_invalid(rnd_input)) - @test isapprox(QEDprocesses._post_computation(stp,rnd_input,rnd_output), _groundtruth_post_computation(rnd_input,rnd_output)) - @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundthruth_compute(rnd_input))) +# process setup + +struct TestParticle1 <: AbstractParticle end +struct TestParticle2 <: AbstractParticle end +struct TestParticle3 <: AbstractParticle end +struct TestParticle4 <: AbstractParticle end + +PARTICLE_SET = [TestParticle1(), TestParticle2(), TestParticle3(),TestParticle4()] + +struct TestProcess <: AbstractProcessDefinition end +struct TestModel <: AbstractModelDefinition end + +struct TestProcessSetup <: AbstractProcessSetup end +QEDprocesses.scattering_process(::TestProcessSetup) = TestProcess() +QEDprocesses.compute_model(::TestProcessSetup) = TestModel() + +struct TestProcessSetupFAIL <: AbstractProcessSetup end + +@testset "process setup interface" begin + @testset "interface fail" begin + @test_throws MethodError scattering_process(TestProcessSetupFAIL) + @test_throws MethodError compute_model(TestProcessSetupFAIL) + end + + @testset "hard interface" begin + stp = TestProcessSetup() + + @test QEDprocesses._is_computation_setup(stp) + @test scattering_process(stp) == TestProcess() + @test compute_model(stp) == TestModel() + end + + @testset "($N_INCOMING,$N_OUTGOING)" for (N_INCOMING,N_OUTGOING) in Iterators.product( + (1, rand(RNG, 2:8)), (1, rand(RNG, 2:8)) + ) + INCOMING_PARTICLES = rand(RNG,PARTICLE_SET,N_INCOMING) + OUTGOING_PARTICLES = rand(RNG,PARTICLE_SET,N_OUTGOING) + + QEDprocesses.incoming_particles(::TestProcess) = INCOMING_PARTICLES + QEDprocesses.outgoing_particles(::TestProcess) = OUTGOING_PARTICLES + + @testset "deligated functions" begin + stp = TestProcessSetup() + @test number_incoming_particles(stp) == N_INCOMING + @test number_outgoing_particles(stp) == N_OUTGOING + end + + end end From d8c3627b9c107232f246c431dbcc2ad01dca9209 Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Tue, 26 Sep 2023 15:48:58 +0200 Subject: [PATCH 04/19] added docstrings to the computation setup interface --- src/interfaces/setup_interface.jl | 70 +++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index 2305e6a..b14f9ec 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -1,19 +1,66 @@ ############### # The process setup # -# In this file, we define the interface for process setups. A `setup` means -# here, a collection of setup-data needed to evaluate a dedicated quantity on a given -# running data. Despite that, the decomposition into setup and running data is -# arbitrary, this will be used for cases where a subset of the variables a -# quantity depends on is kept constant. +# In this file, we define the interface for general computation and process setups. # # This file is part of `QEDprocesses.jl` which is by itself part of the `QED.jl` # ecosystem. # ############### -# base type for any setup, will most properbly be defined somewhere else, -# e.g. QEDbase, therefore it is not exported +""" +Abstract base type for computation setups. A *setup* means +here, a collection of setup-data needed to evaluate a dedicated quantity on given +running data. Therefore, each setup is associated to a single quantity, which one may compute using the setup data and the funning data. +Despite that, the decomposition into setup and running data is +arbitrary, and this can be used for cases where a subset of the variables a +quantity depends on is kept constant. + +!!! note "Computation setup interface" + + The computation performed using a computation setup is separated into three steps: + + 1. input validation, + 2. actual computation, + 3. post computation, + + where every step has its own interface function (see [`compute`](@ref) for details). + + ## input validation + + Every subtype of `AbstractComputationSetup` implements the interface function + + ```Julia + _input_validation(stp::AbstractComputationSetup, input) # default: true + ``` + + which returns true, if the `input` is valid for the computation of the associated quantity (see [`_input_validation`](@ref) for more details). + The default implementation returns always `true`; provide a custom implementation if a different behavior is required. + + ## Actual computation + + Every subtype of `AbstractComputationSetup` should at least implement the following required interface function + + ```Julia + _compute(stp::AbstractComputationSetup, input) + ``` + + which computes the value of the associated quantity for a given `input` (see [`_compute`](@ref) for more details). + + + ## Post computation + + Every subtype of `AbstractComputationSetup` implement the following interface function + + ```Julia + _post_computation(stp::AbstractComputationSetup, input) + ``` + + which performs *computations* after the actual computation, e.g. conversions or normalisations (see [`_post_computation`](@ref) for more details). + + + +""" abstract type AbstractComputationSetup end # convenience function to check if an object is a computation setup @@ -66,8 +113,15 @@ Interface function which returns the value of the associated quantity evaluated """ function _compute end +""" + compute(stp::AbstractComputationSetup, input::Any) +Return the value of the quantity associated with `stp` for a given `input`. +In addition to the actual call of the associated unsafe version [`_compute`](@ref), +input validation (using [`_input_validation`](@ref)) and post computation +(using [`_post_computation`](@ref)) are wrapped around the calculation (see [`AbstractComputationSetup`](@ref) for details). +""" function compute(stp::AbstractComputationSetup, input) _input_validation(stp,input) || error("InvalidInputError: there is something wrong with the input!\n setup:$stp \n input:$input") raw_result = _compute(stp,input) @@ -83,7 +137,6 @@ interface functions scattering_process(::AbstractProcessSetup) compute_model(::AbstractProcessSetup) ``` -where `x` is the running input, i.e. a *single point* the quantity is evaluated on. Derived from the these interface functions, the following delegations are implemented @@ -91,6 +144,7 @@ Derived from the these interface functions, the following delegations are implem number_incoming_particles(::AbstractProcessSetup) number_outgoing_particles(::AbstractProcessSetup) ``` + """ abstract type AbstractProcessSetup <: AbstractComputationSetup end From b33f5a9870ee93ce51a82818ab21205305f55c3b Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Wed, 27 Sep 2023 14:09:32 +0200 Subject: [PATCH 05/19] Apply suggestions from code review fixed bug caused by the pariticles typo Co-authored-by: Tom Jungnickel <140055258+tjungni@users.noreply.github.com> --- src/interfaces/process_interface.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/interfaces/process_interface.jl b/src/interfaces/process_interface.jl index 5fbf8fd..3d06c60 100644 --- a/src/interfaces/process_interface.jl +++ b/src/interfaces/process_interface.jl @@ -121,10 +121,10 @@ function differential_cross_section( final_phasespace::Union{AbstractVector{T},AbstractMatrix{T}}, ) where {T<:QEDbase.AbstractFourMomentum} size(init_phasespace, 1) == number_incoming_particles(proc_def) || throw( - DimensionMismatch("The number of momenta in the initial phasespace <{length(init_phasespace)}> does not match the number of incoming particles of the process <{number_incoming_pariticles(proc_def)}>."), + DimensionMismatch("The number of momenta in the initial phasespace <{length(init_phasespace)}> does not match the number of incoming particles of the process <{number_incoming_particles(proc_def)}>."), ) size(final_phasespace, 1) == number_outgoing_particles(proc_def) || throw( - DimensionMismatch("The number of momenta in the final phasespace <{length(final_phasespace)}> does not match the number of outgoing particles of the process <{number_outgoing_pariticles(proc_def)}>."), + DimensionMismatch("The number of momenta in the final phasespace <{length(final_phasespace)}> does not match the number of outgoing particles of the process <{number_outgoing_particles(proc_def)}>."), ) return _differential_cross_section(proc_def, model_def, init_phasespace, final_phasespace) end @@ -257,7 +257,7 @@ function total_cross_section( init_phasespace::Union{AbstractVector{T},AbstractMatrix{T}}, ) where {T<:QEDbase.AbstractFourMomentum} size(init_phasespace, 1) == number_incoming_particles(proc_def) || throw( - DimensionMismatch("The number of momenta in the initial phasespace <{length(init_phasespace)}> does not match the number of incoming particles of the process <{number_incoming_pariticles(proc_def)}>."), + DimensionMismatch("The number of momenta in the initial phasespace <{length(init_phasespace)}> does not match the number of incoming particles of the process <{number_incoming_particles(proc_def)}>."), ) return _total_cross_section(proc_def, model_def, init_phasespace) end From 508675f8b11bd1a30f42ea62a9d54d34b9a1e4a9 Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Wed, 27 Sep 2023 14:13:25 +0200 Subject: [PATCH 06/19] Apply suggestions from code review fixed typos and formulations flaws Co-authored-by: Anton Reinhard --- src/interfaces/setup_interface.jl | 52 +++++++++++++++--------------- test/interfaces/setup_interface.jl | 4 +-- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index b14f9ec..de92914 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -10,8 +10,8 @@ """ Abstract base type for computation setups. A *setup* means -here, a collection of setup-data needed to evaluate a dedicated quantity on given -running data. Therefore, each setup is associated to a single quantity, which one may compute using the setup data and the funning data. +a collection of setup data needed to evaluate a dedicated quantity of given +running data. Therefore, each setup is associated with a single quantity, which one may compute using the setup data and the running data. Despite that, the decomposition into setup and running data is arbitrary, and this can be used for cases where a subset of the variables a quantity depends on is kept constant. @@ -20,26 +20,26 @@ quantity depends on is kept constant. The computation performed using a computation setup is separated into three steps: - 1. input validation, - 2. actual computation, - 3. post computation, + 1. input validation + 2. actual computation + 3. post processing where every step has its own interface function (see [`compute`](@ref) for details). - ## input validation + ## Input validation - Every subtype of `AbstractComputationSetup` implements the interface function + Every subtype of `AbstractComputationSetup` should implement the interface function ```Julia _input_validation(stp::AbstractComputationSetup, input) # default: true ``` - which returns true, if the `input` is valid for the computation of the associated quantity (see [`_input_validation`](@ref) for more details). - The default implementation returns always `true`; provide a custom implementation if a different behavior is required. + which should return true iff the `input` is valid for the computation of the associated quantity (see [`_input_validation`](@ref) for more details). + The default implementation always returns `true`. Provide a custom implementation if a different behavior is required. ## Actual computation - Every subtype of `AbstractComputationSetup` should at least implement the following required interface function + Every subtype of `AbstractComputationSetup` must at least implement the required interface function ```Julia _compute(stp::AbstractComputationSetup, input) @@ -50,7 +50,7 @@ quantity depends on is kept constant. ## Post computation - Every subtype of `AbstractComputationSetup` implement the following interface function + Every subtype of `AbstractComputationSetup` should implement the interface function ```Julia _post_computation(stp::AbstractComputationSetup, input) @@ -70,13 +70,13 @@ _is_computation_setup(::AbstractComputationSetup) = true _is_valid_input(stp::AbstractComputationSetup, input::Any) -Interface function, which returns true, if the constraints of the `input` associated with the quantity of `stp` are met. -This function will be called to validate the input of [`compute`](@ref) before calling [`_compute`](@ref). +Interface function, which returns true if the constraints of the `input` associated with the quantity of `stp` are met. +This function is called to validate the input of [`compute`](@ref) before calling [`_compute`](@ref). !!! note "Default implementation" - Since no input validation is equivalent to every input being valid, this functions returns `true` per default. - This behaviour needs to be overwritten, if this is not the case. + Since no input validation is equivalent to every input being valid, this function returns `true` by default. + This behavior can be overwritten if actual validation is necessary. """ @inline function _input_validation(stp::AbstractComputationSetup, input) @@ -87,12 +87,12 @@ end function _post_computation(stp::AbstractComputationSetup, input::Any, result::Any) -Interface functions which is called in [`compute`](@ref) after [`_compute`](@ref) was called. This function is dedicated to +Interface function, which is called in [`compute`](@ref) after [`_compute`](@ref) has been called. This function is dedicated to finalize the result of a computation. !!! note "default implementation" - Since in the case of no post computation, the result of [`_compute`](@ref) is not changed, this function returns `result` per default. + Since in the case of no post computation the result of [`_compute`](@ref) is unchanged, this function returns `result` by default. """ @inline function _post_computation(stp::AbstractComputationSetup, input, result) @@ -103,11 +103,11 @@ end _compute(stp::AbstractComputationSetup, input::Any) -Interface function which returns the value of the associated quantity evaluated on `input`, which can be anything the associated quantity is defined to be feasable for. +Interface function that returns the value of the associated quantity evaluated on `input`, which can be anything the associated quantity is defined to be feasible for. !!! note "unsafe implementation" - This function should be implemented without any input validation or post computations (see [`_input_validation`](@ref) and [`_post_computation`](@ref)). The latter two are performed while calling + This function must be implemented for any subtype of [`AbstractComputationSetup`]. It should not do any input validation or post processing (see [`_input_validation`](@ref) and [`_post_computation`](@ref)), as those two are performed while calling the safe version of this function [`compute`](@ref). """ @@ -129,16 +129,16 @@ function compute(stp::AbstractComputationSetup, input) end """ -Abstract base type for setups related to a combination scattering processes and compute models. -Every subtype of `AbstractProcessSetup` is expected to implement at least the following -interface functions +Abstract base type for setups related to combining scattering processes and compute models. +Every subtype of `AbstractProcessSetup` must implement at least the following +interface functions: ```Julia scattering_process(::AbstractProcessSetup) compute_model(::AbstractProcessSetup) ``` -Derived from the these interface functions, the following delegations are implemented +Derived from these interface functions, the following delegations are provided: ```Julia number_incoming_particles(::AbstractProcessSetup) @@ -152,7 +152,7 @@ abstract type AbstractProcessSetup <: AbstractComputationSetup end scattering_process(stp::AbstractProcessSetup) -Interface function, which returns the scattering process associated with `stp`, +Interface function that returns the scattering process associated with `stp`, i.e. an object which is a subtype of `AbstractProcessDefinition`. """ function scattering_process end @@ -161,8 +161,8 @@ function scattering_process end compute_model(stp::AbstractProcessSetup) -Interface function, which returns the compute model associated with `stp`, i.e. -an object which is subtype of `AbstractModelDefinition` +Interface function that returns the compute model associated with `stp`, i.e. +an object which is a subtype of `AbstractModelDefinition`. """ function compute_model end diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl index 7079e9c..f705d8b 100644 --- a/test/interfaces/setup_interface.jl +++ b/test/interfaces/setup_interface.jl @@ -50,7 +50,7 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou @test_throws MethodError QEDprocesses._compute(TestSetupCustomValidationFAIL(), rnd_input) @test_throws MethodError compute(TestSetupCustomValidationFAIL(), rnd_input) - # invalid input should be catched without throwing a MethodError + # invalid input should be caught without throwing a MethodError @test_throws ErrorException compute(TestSetupCustomValidationFAIL(), _transform_to_invalid(rnd_input)) @test_throws MethodError QEDprocesses._compute(TestSetupCustomPostComputationFAIL(), rnd_input) @@ -138,7 +138,7 @@ struct TestProcessSetupFAIL <: AbstractProcessSetup end QEDprocesses.incoming_particles(::TestProcess) = INCOMING_PARTICLES QEDprocesses.outgoing_particles(::TestProcess) = OUTGOING_PARTICLES - @testset "deligated functions" begin + @testset "delegated functions" begin stp = TestProcessSetup() @test number_incoming_particles(stp) == N_INCOMING @test number_outgoing_particles(stp) == N_OUTGOING From b734cfb4656f743b9c1907d0c1bd68431045521d Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Wed, 27 Sep 2023 21:54:33 +0200 Subject: [PATCH 07/19] removed unnecessary comment at the beginning of each file --- src/interfaces/model_interface.jl | 4 ---- src/interfaces/particle_interface.jl | 4 ---- src/interfaces/process_interface.jl | 4 ---- src/interfaces/setup_interface.jl | 4 ---- src/particle_types.jl | 3 --- src/utils.jl | 3 --- 6 files changed, 22 deletions(-) diff --git a/src/interfaces/model_interface.jl b/src/interfaces/model_interface.jl index a99b3f4..ce8fb5b 100644 --- a/src/interfaces/model_interface.jl +++ b/src/interfaces/model_interface.jl @@ -3,10 +3,6 @@ # # In this file, we define the interface of working with compute models in # general. -# -# This file is part of `QEDprocesses.jl` which is by itself part of the `QED.jl` -# ecosystem. -# ############### # root type for models """ diff --git a/src/interfaces/particle_interface.jl b/src/interfaces/particle_interface.jl index 624e684..1f95ef7 100644 --- a/src/interfaces/particle_interface.jl +++ b/src/interfaces/particle_interface.jl @@ -3,10 +3,6 @@ # # In this file, we define the interface for working with particles in a general # sense. -# -# This file is part of `QEDprocesses.jl` which is by itself part of the `QED.jl` -# ecosystem. -# ############### diff --git a/src/interfaces/process_interface.jl b/src/interfaces/process_interface.jl index 3d06c60..aa239f7 100644 --- a/src/interfaces/process_interface.jl +++ b/src/interfaces/process_interface.jl @@ -3,10 +3,6 @@ # # In this file, we define the interface for working with scattering processes in # general. -# -# This file is part of `QEDprocesses.jl` which is by itself part of the `QED.jl` -# ecosystem. -# ############### """ diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index de92914..20f1b63 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -2,10 +2,6 @@ # The process setup # # In this file, we define the interface for general computation and process setups. -# -# This file is part of `QEDprocesses.jl` which is by itself part of the `QED.jl` -# ecosystem. -# ############### """ diff --git a/src/particle_types.jl b/src/particle_types.jl index c6f1d35..10580ef 100644 --- a/src/particle_types.jl +++ b/src/particle_types.jl @@ -3,9 +3,6 @@ # # In this file, we define the types of particles used in `QEDprocesses.jl` and # implement the abstact particle interface accordingly. -# -# This file is part of `QEDprocesses.jl` which is by itself part of the `QED.jl` -# ecosystem. ############### """ diff --git a/src/utils.jl b/src/utils.jl index b5e31eb..dde31e3 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -2,9 +2,6 @@ # utility functions # # This file contains small helper and utility functions used throughout the package. -# -# This file is part of `QEDprocesses.jl` which is by itself part of the `QED.jl` -# ecosystem. ############### From 27435b0c7f8b9a2aa334a2eb84418a6f6cb638bc Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Wed, 27 Sep 2023 22:05:45 +0200 Subject: [PATCH 08/19] renamed _input_validation to _is_valid_input --- src/interfaces/setup_interface.jl | 12 ++++++------ test/interfaces/setup_interface.jl | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index 20f1b63..bf1918e 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -27,10 +27,10 @@ quantity depends on is kept constant. Every subtype of `AbstractComputationSetup` should implement the interface function ```Julia - _input_validation(stp::AbstractComputationSetup, input) # default: true + _is_valid_input(stp::AbstractComputationSetup, input) # default: true ``` - which should return true iff the `input` is valid for the computation of the associated quantity (see [`_input_validation`](@ref) for more details). + which should return true iff the `input` is valid for the computation of the associated quantity (see [`_is_valid_input`](@ref) for more details). The default implementation always returns `true`. Provide a custom implementation if a different behavior is required. ## Actual computation @@ -75,7 +75,7 @@ This function is called to validate the input of [`compute`](@ref) before callin This behavior can be overwritten if actual validation is necessary. """ -@inline function _input_validation(stp::AbstractComputationSetup, input) +@inline function _is_valid_input(stp::AbstractComputationSetup, input) return true end @@ -103,7 +103,7 @@ Interface function that returns the value of the associated quantity evaluated o !!! note "unsafe implementation" - This function must be implemented for any subtype of [`AbstractComputationSetup`]. It should not do any input validation or post processing (see [`_input_validation`](@ref) and [`_post_computation`](@ref)), as those two are performed while calling + This function must be implemented for any subtype of [`AbstractComputationSetup`]. It should not do any input validation or post processing (see [`_is_valid_input`](@ref) and [`_post_computation`](@ref)), as those two are performed while calling the safe version of this function [`compute`](@ref). """ @@ -115,11 +115,11 @@ function _compute end Return the value of the quantity associated with `stp` for a given `input`. In addition to the actual call of the associated unsafe version [`_compute`](@ref), -input validation (using [`_input_validation`](@ref)) and post computation +input validation (using [`_is_valid_input`](@ref)) and post computation (using [`_post_computation`](@ref)) are wrapped around the calculation (see [`AbstractComputationSetup`](@ref) for details). """ function compute(stp::AbstractComputationSetup, input) - _input_validation(stp,input) || error("InvalidInputError: there is something wrong with the input!\n setup:$stp \n input:$input") + _is_valid_input(stp,input) || error("InvalidInputError: there is something wrong with the input!\n setup:$stp \n input:$input") raw_result = _compute(stp,input) return _post_computation(stp, input,raw_result) end diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl index f705d8b..f6f6fa3 100644 --- a/test/interfaces/setup_interface.jl +++ b/test/interfaces/setup_interface.jl @@ -21,7 +21,7 @@ struct TestSetupDefault <: AbstractTestSetup end # setup with custom input validation struct TestSetupCustomValidation <: AbstractTestSetup end -QEDprocesses._input_validation(::TestSetupCustomValidation, x) = _groundthruth_input_validation(x) +QEDprocesses._is_valid_input(::TestSetupCustomValidation, x) = _groundthruth_input_validation(x) # setup with custom post computation struct TestSetupCustomPostComputation <: AbstractTestSetup end @@ -29,7 +29,7 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputation,x,y) = _groundtr # setup with custom input validation and post computation struct TestSetupCustom <: AbstractTestSetup end -QEDprocesses._input_validation(::TestSetupCustom, x) = _groundthruth_input_validation(x) +QEDprocesses._is_valid_input(::TestSetupCustom, x) = _groundthruth_input_validation(x) QEDprocesses._post_computation(::TestSetupCustom,x,y) = _groundtruth_post_computation(x,y) # setup which fail on computation with default implementations @@ -37,7 +37,7 @@ struct TestSetupFAIL <: AbstractComputationSetup end # setup which fail on computation with custom input validation struct TestSetupCustomValidationFAIL <: AbstractComputationSetup end -QEDprocesses._input_validation(::TestSetupCustomValidationFAIL, x) = _groundthruth_input_validation(x) +QEDprocesses._is_valid_input(::TestSetupCustomValidationFAIL, x) = _groundthruth_input_validation(x) # setup which fail on computation with custom post computation struct TestSetupCustomPostComputationFAIL <: AbstractComputationSetup end @@ -62,7 +62,7 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou rnd_input = rand(RNG) rnd_output = rand(RNG) - @test QEDprocesses._input_validation(stp,rnd_input) + @test QEDprocesses._is_valid_input(stp,rnd_input) @test QEDprocesses._post_computation(stp,rnd_input,rnd_output) == rnd_output @test isapprox(QEDprocesses._compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) @test isapprox(compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) @@ -71,8 +71,8 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou @testset "custom input validation" begin stp = TestSetupCustomValidation() rnd_input = rand(RNG) - @test QEDprocesses._input_validation(stp, _groundthruth_input_validation(rnd_input)) - @test !QEDprocesses._input_validation(stp, !_groundthruth_input_validation(rnd_input)) + @test QEDprocesses._is_valid_input(stp, _groundthruth_input_validation(rnd_input)) + @test !QEDprocesses._is_valid_input(stp, !_groundthruth_input_validation(rnd_input)) @test isapprox(compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) @test_throws ErrorException compute(stp, _transform_to_invalid(rnd_input)) end @@ -90,8 +90,8 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou rnd_input = rand(RNG) rnd_output = rand(RNG) - @test QEDprocesses._input_validation(stp, _groundthruth_input_validation(rnd_input)) - @test !QEDprocesses._input_validation(stp, !_groundthruth_input_validation(rnd_input)) + @test QEDprocesses._is_valid_input(stp, _groundthruth_input_validation(rnd_input)) + @test !QEDprocesses._is_valid_input(stp, !_groundthruth_input_validation(rnd_input)) @test_throws ErrorException compute(stp, _transform_to_invalid(rnd_input)) @test isapprox(QEDprocesses._post_computation(stp,rnd_input,rnd_output), _groundtruth_post_computation(rnd_input,rnd_output)) @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundthruth_compute(rnd_input))) From 3374cf03c7f0992ccf74e57334924a805ffc8abc Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Wed, 27 Sep 2023 22:51:57 +0200 Subject: [PATCH 09/19] added _assert_valid_input and respective unittests --- src/interfaces/setup_interface.jl | 34 +++++++++++++++++++++++++++--- test/interfaces/setup_interface.jl | 25 ++++++++++++++++++---- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index bf1918e..375e6fa 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -30,7 +30,7 @@ quantity depends on is kept constant. _is_valid_input(stp::AbstractComputationSetup, input) # default: true ``` - which should return true iff the `input` is valid for the computation of the associated quantity (see [`_is_valid_input`](@ref) for more details). + which should return true iff the `input` is valid for the computation of the associated quantity (see [`_is_valid_input`](@ref) and [`_assert_valid_input`](@ref) for more details). The default implementation always returns `true`. Provide a custom implementation if a different behavior is required. ## Actual computation @@ -74,11 +74,39 @@ This function is called to validate the input of [`compute`](@ref) before callin Since no input validation is equivalent to every input being valid, this function returns `true` by default. This behavior can be overwritten if actual validation is necessary. + +An assert version of this function is given by [`_assert_valid_input`](@ref), which used directly the output of this function. + """ @inline function _is_valid_input(stp::AbstractComputationSetup, input) return true end +""" + + _assert_valid_input(stp::AbstractComputationSetup, input::Any) + +Interface function, which asserts that the given `input` is valid, and thows an error if not. + +!!! note "default implementation" + + The generic fallback uses the boolian value returned by `_is_valid_input(stp,input)` to check for validity, + i.e. if the returned value is `true` the assert does not trigger and nothing happens, but if the returned value is `false`, + an error with a generic error message will be thrown (see [`_is_valid_input`](@ref) for details). + To customize the error message, or use a custom assertion mechanism, just add your own implementation of + + ```Julia + _assert_valid_input(stp::YourCustomSetup,input) + ``` + However, it is highly recommented to also implement `_is_valid_input` for `CustomSetup`, because it might be used outside this assert function. + +""" +@inline function _assert_valid_input(stp::AbstractComputationSetup,input) + _is_valid_input(stp,input) || error("InvalidInputError: there is something wrong with the input!\n setup:$stp \n input:$input") + + return nothing +end + """ function _post_computation(stp::AbstractComputationSetup, input::Any, result::Any) @@ -115,11 +143,11 @@ function _compute end Return the value of the quantity associated with `stp` for a given `input`. In addition to the actual call of the associated unsafe version [`_compute`](@ref), -input validation (using [`_is_valid_input`](@ref)) and post computation +input validation ([`_assert_valid_input`]) and post computation (using [`_post_computation`](@ref)) are wrapped around the calculation (see [`AbstractComputationSetup`](@ref) for details). """ function compute(stp::AbstractComputationSetup, input) - _is_valid_input(stp,input) || error("InvalidInputError: there is something wrong with the input!\n setup:$stp \n input:$input") + _assert_valid_input(stp,input) raw_result = _compute(stp,input) return _post_computation(stp, input,raw_result) end diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl index f6f6fa3..afe9907 100644 --- a/test/interfaces/setup_interface.jl +++ b/test/interfaces/setup_interface.jl @@ -19,9 +19,18 @@ QEDprocesses._compute(stp::AbstractTestSetup, x) = _groundthruth_compute(x) # setup with default implementations struct TestSetupDefault <: AbstractTestSetup end -# setup with custom input validation -struct TestSetupCustomValidation <: AbstractTestSetup end -QEDprocesses._is_valid_input(::TestSetupCustomValidation, x) = _groundthruth_input_validation(x) +# setup with custom _is_valid_input +struct TestSetupCustomIsValidInput <: AbstractTestSetup end +QEDprocesses._is_valid_input(::TestSetupCustomIsValidInput, x) = _groundthruth_input_validation(x) + +# setup with custom _assert_valid_input +struct TestSetupCustomAssertValidInput<: AbstractTestSetup end +QEDprocesses._is_valid_input(::TestSetupCustomAssertValidInput, x) = _groundthruth_input_validation(x) +struct TestException <: Exception end +function QEDprocesses._assert_valid_input(stp::TestSetupCustomAssertValidInput, x) + QEDprocesses._is_valid_input(stp,x)||throw(TestException()) + return nothing +end # setup with custom post computation struct TestSetupCustomPostComputation <: AbstractTestSetup end @@ -69,12 +78,20 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou end @testset "custom input validation" begin - stp = TestSetupCustomValidation() + stp = TestSetupCustomIsValidInput() rnd_input = rand(RNG) @test QEDprocesses._is_valid_input(stp, _groundthruth_input_validation(rnd_input)) @test !QEDprocesses._is_valid_input(stp, !_groundthruth_input_validation(rnd_input)) @test isapprox(compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) + @test_throws ErrorException QEDprocesses._assert_valid_input(stp, _transform_to_invalid(rnd_input)) @test_throws ErrorException compute(stp, _transform_to_invalid(rnd_input)) + + stp2 = TestSetupCustomAssertValidInput() + rnd_input2 = rand(RNG) + @test QEDprocesses._assert_valid_input(stp2,rnd_input2)==nothing + @test_throws TestException QEDprocesses._assert_valid_input(stp2,_transform_to_invalid(rnd_input2)) + @test_throws TestException compute(stp2, _transform_to_invalid(rnd_input2)) + end @testset "custom post computation" begin From 5f1e281694fc18cd8bb1d690d46db79a871197b6 Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Wed, 27 Sep 2023 23:19:13 +0200 Subject: [PATCH 10/19] added a custom exception InvalidInputError dedicated to be thrown in _assert_valid_input --- src/QEDprocesses.jl | 2 +- src/interfaces/setup_interface.jl | 19 +++++++++++++++---- test/interfaces/setup_interface.jl | 10 +++++----- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/QEDprocesses.jl b/src/QEDprocesses.jl index 4520344..25ceb12 100644 --- a/src/QEDprocesses.jl +++ b/src/QEDprocesses.jl @@ -14,7 +14,7 @@ export number_incoming_particles, number_outgoing_particles export differential_cross_section, total_cross_section # Abstract setup interface -export AbstractComputationSetup, compute +export AbstractComputationSetup, InvalidInputError, compute export AbstractProcessSetup, scattering_process, compute_model # particle types diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index 375e6fa..73a57d7 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -81,12 +81,22 @@ An assert version of this function is given by [`_assert_valid_input`](@ref), wh @inline function _is_valid_input(stp::AbstractComputationSetup, input) return true end +""" + + InvalidInputError(msg::String) + +Exception which is thrown if a given input is invalid, e.g. passed to [`_assert_valid_input`](@ref). +""" +struct InvalidInputError <: Exception + msg::String +end +Base.showerror(io::IO, err::InvalidInputError) = println(io, "InvalidInputError: $(err.msg).") """ _assert_valid_input(stp::AbstractComputationSetup, input::Any) -Interface function, which asserts that the given `input` is valid, and thows an error if not. +Interface function, which asserts that the given `input` is valid, and throws an [`InvalidInputError`](@ref) if not. !!! note "default implementation" @@ -96,13 +106,14 @@ Interface function, which asserts that the given `input` is valid, and thows an To customize the error message, or use a custom assertion mechanism, just add your own implementation of ```Julia - _assert_valid_input(stp::YourCustomSetup,input) + _assert_valid_input(stp::YourCustomSetup,input) ``` - However, it is highly recommented to also implement `_is_valid_input` for `CustomSetup`, because it might be used outside this assert function. + which should throw an [`InvalidInputError`](@ref) if the input is invalid. + Dispite the presence of a custom `_assert_valid_input`, it is highly recommented to also implement `_is_valid_input` for `CustomSetup`, because it might be used outside the assert function. """ @inline function _assert_valid_input(stp::AbstractComputationSetup,input) - _is_valid_input(stp,input) || error("InvalidInputError: there is something wrong with the input!\n setup:$stp \n input:$input") + _is_valid_input(stp,input) || throw(InvalidInputError("Something wrong with the input!\n setup:$stp \n input:$input")) return nothing end diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl index afe9907..ecd4e55 100644 --- a/test/interfaces/setup_interface.jl +++ b/test/interfaces/setup_interface.jl @@ -60,7 +60,7 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou @test_throws MethodError QEDprocesses._compute(TestSetupCustomValidationFAIL(), rnd_input) @test_throws MethodError compute(TestSetupCustomValidationFAIL(), rnd_input) # invalid input should be caught without throwing a MethodError - @test_throws ErrorException compute(TestSetupCustomValidationFAIL(), _transform_to_invalid(rnd_input)) + @test_throws InvalidInputError compute(TestSetupCustomValidationFAIL(), _transform_to_invalid(rnd_input)) @test_throws MethodError QEDprocesses._compute(TestSetupCustomPostComputationFAIL(), rnd_input) @test_throws MethodError compute(TestSetupCustomPostComputationFAIL(), rnd_input) @@ -83,9 +83,9 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou @test QEDprocesses._is_valid_input(stp, _groundthruth_input_validation(rnd_input)) @test !QEDprocesses._is_valid_input(stp, !_groundthruth_input_validation(rnd_input)) @test isapprox(compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) - @test_throws ErrorException QEDprocesses._assert_valid_input(stp, _transform_to_invalid(rnd_input)) - @test_throws ErrorException compute(stp, _transform_to_invalid(rnd_input)) - + @test_throws InvalidInputError QEDprocesses._assert_valid_input(stp, _transform_to_invalid(rnd_input)) + @test_throws InvalidInputError compute(stp, _transform_to_invalid(rnd_input)) + stp2 = TestSetupCustomAssertValidInput() rnd_input2 = rand(RNG) @test QEDprocesses._assert_valid_input(stp2,rnd_input2)==nothing @@ -109,7 +109,7 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou @test QEDprocesses._is_valid_input(stp, _groundthruth_input_validation(rnd_input)) @test !QEDprocesses._is_valid_input(stp, !_groundthruth_input_validation(rnd_input)) - @test_throws ErrorException compute(stp, _transform_to_invalid(rnd_input)) + @test_throws InvalidInputError compute(stp, _transform_to_invalid(rnd_input)) @test isapprox(QEDprocesses._post_computation(stp,rnd_input,rnd_output), _groundtruth_post_computation(rnd_input,rnd_output)) @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundthruth_compute(rnd_input))) end From d698b56a0a188187f5fc6f91f6abaa9cc2fe2979 Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Wed, 27 Sep 2023 23:54:42 +0200 Subject: [PATCH 11/19] fixed typo in _groundtruth --- test/interfaces/setup_interface.jl | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl index ecd4e55..fe9d200 100644 --- a/test/interfaces/setup_interface.jl +++ b/test/interfaces/setup_interface.jl @@ -7,25 +7,25 @@ RNG = MersenneTwister(137137) ATOL = 0.0 RTOL = sqrt(eps()) -_groundthruth_compute(x) = x -_groundthruth_input_validation(x) = (x>0) +_groundtruth_compute(x) = x +_groundtruth_input_validation(x) = (x>0) _transform_to_invalid(x) = -abs(x) _groundtruth_post_computation(x,y) = x+y # setups for which the interface is implemented abstract type AbstractTestSetup <: AbstractComputationSetup end -QEDprocesses._compute(stp::AbstractTestSetup, x) = _groundthruth_compute(x) +QEDprocesses._compute(stp::AbstractTestSetup, x) = _groundtruth_compute(x) # setup with default implementations struct TestSetupDefault <: AbstractTestSetup end # setup with custom _is_valid_input struct TestSetupCustomIsValidInput <: AbstractTestSetup end -QEDprocesses._is_valid_input(::TestSetupCustomIsValidInput, x) = _groundthruth_input_validation(x) +QEDprocesses._is_valid_input(::TestSetupCustomIsValidInput, x) = _groundtruth_input_validation(x) # setup with custom _assert_valid_input struct TestSetupCustomAssertValidInput<: AbstractTestSetup end -QEDprocesses._is_valid_input(::TestSetupCustomAssertValidInput, x) = _groundthruth_input_validation(x) +QEDprocesses._is_valid_input(::TestSetupCustomAssertValidInput, x) = _groundtruth_input_validation(x) struct TestException <: Exception end function QEDprocesses._assert_valid_input(stp::TestSetupCustomAssertValidInput, x) QEDprocesses._is_valid_input(stp,x)||throw(TestException()) @@ -38,7 +38,7 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputation,x,y) = _groundtr # setup with custom input validation and post computation struct TestSetupCustom <: AbstractTestSetup end -QEDprocesses._is_valid_input(::TestSetupCustom, x) = _groundthruth_input_validation(x) +QEDprocesses._is_valid_input(::TestSetupCustom, x) = _groundtruth_input_validation(x) QEDprocesses._post_computation(::TestSetupCustom,x,y) = _groundtruth_post_computation(x,y) # setup which fail on computation with default implementations @@ -46,7 +46,7 @@ struct TestSetupFAIL <: AbstractComputationSetup end # setup which fail on computation with custom input validation struct TestSetupCustomValidationFAIL <: AbstractComputationSetup end -QEDprocesses._is_valid_input(::TestSetupCustomValidationFAIL, x) = _groundthruth_input_validation(x) +QEDprocesses._is_valid_input(::TestSetupCustomValidationFAIL, x) = _groundtruth_input_validation(x) # setup which fail on computation with custom post computation struct TestSetupCustomPostComputationFAIL <: AbstractComputationSetup end @@ -73,16 +73,16 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou rnd_output = rand(RNG) @test QEDprocesses._is_valid_input(stp,rnd_input) @test QEDprocesses._post_computation(stp,rnd_input,rnd_output) == rnd_output - @test isapprox(QEDprocesses._compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) - @test isapprox(compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) + @test isapprox(QEDprocesses._compute(stp, rnd_input), _groundtruth_compute(rnd_input), atol=ATOL,rtol=RTOL) + @test isapprox(compute(stp, rnd_input), _groundtruth_compute(rnd_input), atol=ATOL,rtol=RTOL) end @testset "custom input validation" begin stp = TestSetupCustomIsValidInput() rnd_input = rand(RNG) - @test QEDprocesses._is_valid_input(stp, _groundthruth_input_validation(rnd_input)) - @test !QEDprocesses._is_valid_input(stp, !_groundthruth_input_validation(rnd_input)) - @test isapprox(compute(stp, rnd_input), _groundthruth_compute(rnd_input), atol=ATOL,rtol=RTOL) + @test QEDprocesses._is_valid_input(stp, _groundtruth_input_validation(rnd_input)) + @test !QEDprocesses._is_valid_input(stp, !_groundtruth_input_validation(rnd_input)) + @test isapprox(compute(stp, rnd_input), _groundtruth_compute(rnd_input), atol=ATOL,rtol=RTOL) @test_throws InvalidInputError QEDprocesses._assert_valid_input(stp, _transform_to_invalid(rnd_input)) @test_throws InvalidInputError compute(stp, _transform_to_invalid(rnd_input)) @@ -99,7 +99,7 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou rnd_input = rand(RNG) rnd_output = rand(RNG) @test isapprox(QEDprocesses._post_computation(stp,rnd_input,rnd_output), _groundtruth_post_computation(rnd_input,rnd_output)) - @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundthruth_compute(rnd_input))) + @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundtruth_compute(rnd_input))) end @testset "custom input validation and post computation" begin @@ -107,11 +107,11 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou rnd_input = rand(RNG) rnd_output = rand(RNG) - @test QEDprocesses._is_valid_input(stp, _groundthruth_input_validation(rnd_input)) - @test !QEDprocesses._is_valid_input(stp, !_groundthruth_input_validation(rnd_input)) + @test QEDprocesses._is_valid_input(stp, _groundtruth_input_validation(rnd_input)) + @test !QEDprocesses._is_valid_input(stp, !_groundtruth_input_validation(rnd_input)) @test_throws InvalidInputError compute(stp, _transform_to_invalid(rnd_input)) @test isapprox(QEDprocesses._post_computation(stp,rnd_input,rnd_output), _groundtruth_post_computation(rnd_input,rnd_output)) - @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundthruth_compute(rnd_input))) + @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundtruth_compute(rnd_input))) end end # process setup From 944885f212ce03c81cce4acd50be92bc897fc7f8 Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Thu, 28 Sep 2023 00:04:59 +0200 Subject: [PATCH 12/19] added test for failed interface w.r.t. _compute on AbstractProcessSetup --- test/interfaces/setup_interface.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl index fe9d200..ea518eb 100644 --- a/test/interfaces/setup_interface.jl +++ b/test/interfaces/setup_interface.jl @@ -134,8 +134,10 @@ struct TestProcessSetupFAIL <: AbstractProcessSetup end @testset "process setup interface" begin @testset "interface fail" begin - @test_throws MethodError scattering_process(TestProcessSetupFAIL) - @test_throws MethodError compute_model(TestProcessSetupFAIL) + rnd_input = rand(RNG) + @test_throws MethodError scattering_process(TestProcessSetupFAIL()) + @test_throws MethodError compute_model(TestProcessSetupFAIL()) + @test_throws MethodError QEDprocesses._compute(TestProcessSetupFAIL(), rnd_input) end @testset "hard interface" begin From b4faf1f243f33eb964230c3f40ca2b2f79b6fbb9 Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Thu, 28 Sep 2023 15:21:47 +0200 Subject: [PATCH 13/19] Apply suggestions from code review Fixed typos in docstrings Co-authored-by: Tom Jungnickel <140055258+tjungni@users.noreply.github.com> --- src/interfaces/setup_interface.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index 73a57d7..7d1c1e1 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -52,7 +52,7 @@ quantity depends on is kept constant. _post_computation(stp::AbstractComputationSetup, input) ``` - which performs *computations* after the actual computation, e.g. conversions or normalisations (see [`_post_computation`](@ref) for more details). + which performs *computations* after the actual computation, e.g. conversions or normalizations (see [`_post_computation`](@ref) for more details). @@ -75,7 +75,7 @@ This function is called to validate the input of [`compute`](@ref) before callin This behavior can be overwritten if actual validation is necessary. -An assert version of this function is given by [`_assert_valid_input`](@ref), which used directly the output of this function. +An assert version of this function is given by [`_assert_valid_input`](@ref), which directly uses the output of this function. """ @inline function _is_valid_input(stp::AbstractComputationSetup, input) @@ -109,7 +109,7 @@ Interface function, which asserts that the given `input` is valid, and throws an _assert_valid_input(stp::YourCustomSetup,input) ``` which should throw an [`InvalidInputError`](@ref) if the input is invalid. - Dispite the presence of a custom `_assert_valid_input`, it is highly recommented to also implement `_is_valid_input` for `CustomSetup`, because it might be used outside the assert function. + Despite the presence of a custom `_assert_valid_input`, it is highly recommended to also implement `_is_valid_input` for `CustomSetup`, because it might be used outside of the assert function. """ @inline function _assert_valid_input(stp::AbstractComputationSetup,input) From 6dc2222498ebcb53216ce019308f86f9f7d33afc Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Fri, 29 Sep 2023 10:41:53 +0200 Subject: [PATCH 14/19] renamed _post_computation to _post_processing, and adjusted docstrings and unit tests accordingly --- src/interfaces/setup_interface.jl | 20 ++++++++-------- test/interfaces/setup_interface.jl | 38 +++++++++++++++--------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index 7d1c1e1..f07d6c8 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -44,15 +44,15 @@ quantity depends on is kept constant. which computes the value of the associated quantity for a given `input` (see [`_compute`](@ref) for more details). - ## Post computation + ## Post processing Every subtype of `AbstractComputationSetup` should implement the interface function ```Julia - _post_computation(stp::AbstractComputationSetup, input) + _post_processing(stp::AbstractComputationSetup, input, result) ``` - which performs *computations* after the actual computation, e.g. conversions or normalizations (see [`_post_computation`](@ref) for more details). + which performs task after the actual computation, e.g. conversions or normalizations (see [`_post_processing`](@ref) for more details). @@ -120,17 +120,17 @@ end """ - function _post_computation(stp::AbstractComputationSetup, input::Any, result::Any) + function _post_processing(stp::AbstractComputationSetup, input::Any, result::Any) Interface function, which is called in [`compute`](@ref) after [`_compute`](@ref) has been called. This function is dedicated to finalize the result of a computation. !!! note "default implementation" - Since in the case of no post computation the result of [`_compute`](@ref) is unchanged, this function returns `result` by default. + Since in the case of no post processing the result of [`_compute`](@ref) is unchanged, this function returns `result` by default. """ -@inline function _post_computation(stp::AbstractComputationSetup, input, result) +@inline function _post_processing(stp::AbstractComputationSetup, input, result) return result end @@ -142,7 +142,7 @@ Interface function that returns the value of the associated quantity evaluated o !!! note "unsafe implementation" - This function must be implemented for any subtype of [`AbstractComputationSetup`]. It should not do any input validation or post processing (see [`_is_valid_input`](@ref) and [`_post_computation`](@ref)), as those two are performed while calling + This function must be implemented for any subtype of [`AbstractComputationSetup`]. It should not do any input validation or post processing (see [`_is_valid_input`](@ref) and [`_post_processing`](@ref)), as those two are performed while calling the safe version of this function [`compute`](@ref). """ @@ -154,13 +154,13 @@ function _compute end Return the value of the quantity associated with `stp` for a given `input`. In addition to the actual call of the associated unsafe version [`_compute`](@ref), -input validation ([`_assert_valid_input`]) and post computation -(using [`_post_computation`](@ref)) are wrapped around the calculation (see [`AbstractComputationSetup`](@ref) for details). +input validation ([`_assert_valid_input`]) and post processing +(using [`_post_processing`](@ref)) are wrapped around the calculation (see [`AbstractComputationSetup`](@ref) for details). """ function compute(stp::AbstractComputationSetup, input) _assert_valid_input(stp,input) raw_result = _compute(stp,input) - return _post_computation(stp, input,raw_result) + return _post_processing(stp, input,raw_result) end """ diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl index ea518eb..f1ca845 100644 --- a/test/interfaces/setup_interface.jl +++ b/test/interfaces/setup_interface.jl @@ -10,7 +10,7 @@ RTOL = sqrt(eps()) _groundtruth_compute(x) = x _groundtruth_input_validation(x) = (x>0) _transform_to_invalid(x) = -abs(x) -_groundtruth_post_computation(x,y) = x+y +_groundtruth_post_processing(x,y) = x+y # setups for which the interface is implemented abstract type AbstractTestSetup <: AbstractComputationSetup end @@ -32,14 +32,14 @@ function QEDprocesses._assert_valid_input(stp::TestSetupCustomAssertValidInput, return nothing end -# setup with custom post computation -struct TestSetupCustomPostComputation <: AbstractTestSetup end -QEDprocesses._post_computation(::TestSetupCustomPostComputation,x,y) = _groundtruth_post_computation(x,y) +# setup with custom post processing +struct TestSetupCustomPostProcessing<: AbstractTestSetup end +QEDprocesses._post_processing(::TestSetupCustomPostProcessing,x,y) = _groundtruth_post_processing(x,y) -# setup with custom input validation and post computation +# setup with custom input validation and post processing struct TestSetupCustom <: AbstractTestSetup end QEDprocesses._is_valid_input(::TestSetupCustom, x) = _groundtruth_input_validation(x) -QEDprocesses._post_computation(::TestSetupCustom,x,y) = _groundtruth_post_computation(x,y) +QEDprocesses._post_processing(::TestSetupCustom,x,y) = _groundtruth_post_processing(x,y) # setup which fail on computation with default implementations struct TestSetupFAIL <: AbstractComputationSetup end @@ -48,9 +48,9 @@ struct TestSetupFAIL <: AbstractComputationSetup end struct TestSetupCustomValidationFAIL <: AbstractComputationSetup end QEDprocesses._is_valid_input(::TestSetupCustomValidationFAIL, x) = _groundtruth_input_validation(x) -# setup which fail on computation with custom post computation -struct TestSetupCustomPostComputationFAIL <: AbstractComputationSetup end -QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _groundtruth_post_computation(x,y) +# setup which fail on computation with custom post processing +struct TestSetupCustomPostProcessingFAIL <: AbstractComputationSetup end +QEDprocesses._post_processing(::TestSetupCustomPostProcessingFAIL,x,y) = _groundtruth_post_processing(x,y) @testset "general computation setup interface" begin @testset "interface fail" begin rnd_input = rand(RNG) @@ -62,8 +62,8 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou # invalid input should be caught without throwing a MethodError @test_throws InvalidInputError compute(TestSetupCustomValidationFAIL(), _transform_to_invalid(rnd_input)) - @test_throws MethodError QEDprocesses._compute(TestSetupCustomPostComputationFAIL(), rnd_input) - @test_throws MethodError compute(TestSetupCustomPostComputationFAIL(), rnd_input) + @test_throws MethodError QEDprocesses._compute(TestSetupCustomPostProcessingFAIL(), rnd_input) + @test_throws MethodError compute(TestSetupCustomPostProcessingFAIL(), rnd_input) end @testset "default interface" begin @@ -72,7 +72,7 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou rnd_input = rand(RNG) rnd_output = rand(RNG) @test QEDprocesses._is_valid_input(stp,rnd_input) - @test QEDprocesses._post_computation(stp,rnd_input,rnd_output) == rnd_output + @test QEDprocesses._post_processing(stp,rnd_input,rnd_output) == rnd_output @test isapprox(QEDprocesses._compute(stp, rnd_input), _groundtruth_compute(rnd_input), atol=ATOL,rtol=RTOL) @test isapprox(compute(stp, rnd_input), _groundtruth_compute(rnd_input), atol=ATOL,rtol=RTOL) end @@ -94,15 +94,15 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou end - @testset "custom post computation" begin - stp = TestSetupCustomPostComputation() + @testset "custom post processing" begin + stp = TestSetupCustomPostProcessing() rnd_input = rand(RNG) rnd_output = rand(RNG) - @test isapprox(QEDprocesses._post_computation(stp,rnd_input,rnd_output), _groundtruth_post_computation(rnd_input,rnd_output)) - @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundtruth_compute(rnd_input))) + @test isapprox(QEDprocesses._post_processing(stp,rnd_input,rnd_output), _groundtruth_post_processing(rnd_input,rnd_output)) + @test isapprox(compute(stp,rnd_input), _groundtruth_post_processing(rnd_input,_groundtruth_compute(rnd_input))) end - @testset "custom input validation and post computation" begin + @testset "custom input validation and post processing" begin stp = TestSetupCustom() rnd_input = rand(RNG) rnd_output = rand(RNG) @@ -110,8 +110,8 @@ QEDprocesses._post_computation(::TestSetupCustomPostComputationFAIL,x,y) = _grou @test QEDprocesses._is_valid_input(stp, _groundtruth_input_validation(rnd_input)) @test !QEDprocesses._is_valid_input(stp, !_groundtruth_input_validation(rnd_input)) @test_throws InvalidInputError compute(stp, _transform_to_invalid(rnd_input)) - @test isapprox(QEDprocesses._post_computation(stp,rnd_input,rnd_output), _groundtruth_post_computation(rnd_input,rnd_output)) - @test isapprox(compute(stp,rnd_input), _groundtruth_post_computation(rnd_input,_groundtruth_compute(rnd_input))) + @test isapprox(QEDprocesses._post_processing(stp,rnd_input,rnd_output), _groundtruth_post_processing(rnd_input,rnd_output)) + @test isapprox(compute(stp,rnd_input), _groundtruth_post_processing(rnd_input,_groundtruth_compute(rnd_input))) end end # process setup From 196df3cdc7e9d33fb7dfadc995ab2f163cf14f47 Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Fri, 29 Sep 2023 11:03:44 +0200 Subject: [PATCH 15/19] renamed compute_model to physical_model, and adjusted docstrings and unit tests accordingly --- src/QEDprocesses.jl | 2 +- src/interfaces/process_interface.jl | 8 ++++---- src/interfaces/setup_interface.jl | 16 +++++++--------- test/interfaces/setup_interface.jl | 6 +++--- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/QEDprocesses.jl b/src/QEDprocesses.jl index 25ceb12..4f7ffe6 100644 --- a/src/QEDprocesses.jl +++ b/src/QEDprocesses.jl @@ -15,7 +15,7 @@ export differential_cross_section, total_cross_section # Abstract setup interface export AbstractComputationSetup, InvalidInputError, compute -export AbstractProcessSetup, scattering_process, compute_model +export AbstractProcessSetup, scattering_process, physical_model # particle types export AbstractParticleType diff --git a/src/interfaces/process_interface.jl b/src/interfaces/process_interface.jl index aa239f7..589171b 100644 --- a/src/interfaces/process_interface.jl +++ b/src/interfaces/process_interface.jl @@ -66,8 +66,8 @@ end final_phasespace::AbstractVector{T}, ) where {T<:QEDbase.AbstractFourMomentum} -Interface function for the combination of scattering processes and models. Return the differential cross section of a -given process and model for a passed initial and final phase space. The elements of the `AbstractVector` representing the phase spaces +Interface function for the combination of scattering processes and physical models. Return the differential cross section of a +given process and physical model for a passed initial and final phase space. The elements of the `AbstractVector` representing the phase spaces are the momenta of the respective particles. The implementation of this function for a concrete process and model must not check if the length of the passed phase spaces match the respective number of particles. @@ -194,7 +194,7 @@ end init_phasespace::AbstractVector{T}, ) where {T<:QEDbase.AbstractFourMomentum} end -Interface function for the combination of scattering processes and models. Return the total cross section of a +Interface function for the combination of scattering processes and physical models. Return the total cross section of a given process and model for a passed initial phase space. The elements of the `AbstractVector` representing the initial phase space are the momenta of the respective particles. The implementation of this function for a concrete process and model must not check if the length of the passed initial phase spaces match number of incoming particles. @@ -242,7 +242,7 @@ end init_phasespace::Union{AbstractVector{T},AbstractMatrix{T}}, ) where {T<:QEDbase.AbstractFourMomentum} -Return the total cross section for a combination of a scattering process and a compute model evaluated on a given initial phase space. +Return the total cross section for a combination of a scattering process and a physical model evaluated on a given initial phase space. This function will eventually call the respective interface function [`_total_cross_section`](@ref). diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index f07d6c8..5798a6a 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -54,8 +54,6 @@ quantity depends on is kept constant. which performs task after the actual computation, e.g. conversions or normalizations (see [`_post_processing`](@ref) for more details). - - """ abstract type AbstractComputationSetup end @@ -164,13 +162,13 @@ function compute(stp::AbstractComputationSetup, input) end """ -Abstract base type for setups related to combining scattering processes and compute models. +Abstract base type for setups related to combining scattering processes and physical models. Every subtype of `AbstractProcessSetup` must implement at least the following interface functions: ```Julia scattering_process(::AbstractProcessSetup) -compute_model(::AbstractProcessSetup) +physical_model(::AbstractProcessSetup) ``` Derived from these interface functions, the following delegations are provided: @@ -188,18 +186,18 @@ abstract type AbstractProcessSetup <: AbstractComputationSetup end scattering_process(stp::AbstractProcessSetup) Interface function that returns the scattering process associated with `stp`, -i.e. an object which is a subtype of `AbstractProcessDefinition`. +i.e. an object which is a subtype of [`AbstractProcessDefinition`](@ref). """ function scattering_process end """ - compute_model(stp::AbstractProcessSetup) + physical_model(stp::AbstractProcessSetup) -Interface function that returns the compute model associated with `stp`, i.e. -an object which is a subtype of `AbstractModelDefinition`. +Interface function that returns the physical model associated with `stp`, i.e. +an object which is a subtype of [`AbstractModelDefinition`](@ref). """ -function compute_model end +function physical_model end @inline number_incoming_particles(stp::AbstractProcessSetup) = number_incoming_particles(scattering_process(stp)) @inline number_outgoing_particles(stp::AbstractProcessSetup) = number_outgoing_particles(scattering_process(stp)) diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl index f1ca845..a20a26a 100644 --- a/test/interfaces/setup_interface.jl +++ b/test/interfaces/setup_interface.jl @@ -128,7 +128,7 @@ struct TestModel <: AbstractModelDefinition end struct TestProcessSetup <: AbstractProcessSetup end QEDprocesses.scattering_process(::TestProcessSetup) = TestProcess() -QEDprocesses.compute_model(::TestProcessSetup) = TestModel() +QEDprocesses.physical_model(::TestProcessSetup) = TestModel() struct TestProcessSetupFAIL <: AbstractProcessSetup end @@ -136,7 +136,7 @@ struct TestProcessSetupFAIL <: AbstractProcessSetup end @testset "interface fail" begin rnd_input = rand(RNG) @test_throws MethodError scattering_process(TestProcessSetupFAIL()) - @test_throws MethodError compute_model(TestProcessSetupFAIL()) + @test_throws MethodError physical_model(TestProcessSetupFAIL()) @test_throws MethodError QEDprocesses._compute(TestProcessSetupFAIL(), rnd_input) end @@ -145,7 +145,7 @@ struct TestProcessSetupFAIL <: AbstractProcessSetup end @test QEDprocesses._is_computation_setup(stp) @test scattering_process(stp) == TestProcess() - @test compute_model(stp) == TestModel() + @test physical_model(stp) == TestModel() end @testset "($N_INCOMING,$N_OUTGOING)" for (N_INCOMING,N_OUTGOING) in Iterators.product( From c3d44564d413e7dd280fe7b64c5d7cc0410d5b7c Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Thu, 5 Oct 2023 00:01:13 +0200 Subject: [PATCH 16/19] made _assert_valid_input the actual interface function and _is_valid_input the derivation; adjusted the tests and docstrings accordingly --- src/interfaces/setup_interface.jl | 60 ++++++++++++++++++++---------- test/interfaces/setup_interface.jl | 45 ++++++++++------------ 2 files changed, 59 insertions(+), 46 deletions(-) diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index 5798a6a..da5e8e0 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -27,11 +27,11 @@ quantity depends on is kept constant. Every subtype of `AbstractComputationSetup` should implement the interface function ```Julia - _is_valid_input(stp::AbstractComputationSetup, input) # default: true + _assert_valid_input(stp::AbstractComputationSetup, input) ``` - which should return true iff the `input` is valid for the computation of the associated quantity (see [`_is_valid_input`](@ref) and [`_assert_valid_input`](@ref) for more details). - The default implementation always returns `true`. Provide a custom implementation if a different behavior is required. + which should throw and an exception subtyped from [`AbstractInvalidInputException`](@ref) if the `input` is not valid for the computation of the associated quantity (see [`_is_valid_input`](@ref) and [`_assert_valid_input`](@ref) for more details). + The default implementation does nothing, i.e. every input is valid by default. Provide a custom implementation if a different behavior is required. ## Actual computation @@ -61,31 +61,24 @@ abstract type AbstractComputationSetup end _is_computation_setup(::AbstractComputationSetup) = true """ +Abstract base type for exceptions indicating invalid input. See [`InvalidInputError`](@ref) for a simple concrete implementation. +Concrete implementations should at least implement - _is_valid_input(stp::AbstractComputationSetup, input::Any) - -Interface function, which returns true if the constraints of the `input` associated with the quantity of `stp` are met. -This function is called to validate the input of [`compute`](@ref) before calling [`_compute`](@ref). - -!!! note "Default implementation" - - Since no input validation is equivalent to every input being valid, this function returns `true` by default. - This behavior can be overwritten if actual validation is necessary. - +```Julia -An assert version of this function is given by [`_assert_valid_input`](@ref), which directly uses the output of this function. +Base.showerror(io::IO, err::CustomInvalidError) where {CustomInvalidError<:AbstractInvalidInputException} +``` """ -@inline function _is_valid_input(stp::AbstractComputationSetup, input) - return true -end +abstract type AbstractInvalidInputException <: Exception end + """ InvalidInputError(msg::String) Exception which is thrown if a given input is invalid, e.g. passed to [`_assert_valid_input`](@ref). """ -struct InvalidInputError <: Exception +struct InvalidInputError <: AbstractInvalidInputException msg::String end Base.showerror(io::IO, err::InvalidInputError) = println(io, "InvalidInputError: $(err.msg).") @@ -111,11 +104,38 @@ Interface function, which asserts that the given `input` is valid, and throws an """ @inline function _assert_valid_input(stp::AbstractComputationSetup,input) - _is_valid_input(stp,input) || throw(InvalidInputError("Something wrong with the input!\n setup:$stp \n input:$input")) - return nothing end +""" + + _is_valid_input(stp::AbstractComputationSetup, input::Any) + +Interface function, which returns true if the constraints of the `input` associated with the quantity of `stp` are met. +This function is called to validate the input of [`compute`](@ref) before calling [`_compute`](@ref). + +!!! note "Default implementation" + + Since no input validation is equivalent to every input being valid, this function returns `true` by default. + This behavior can be overwritten if actual validation is necessary. + + +An assert version of this function is given by [`_assert_valid_input`](@ref), which directly uses the output of this function. + +""" +@inline function _is_valid_input(stp::AbstractComputationSetup, input) + try + _assert_valid_input(stp,input) + catch e + if isa(e, AbstractInvalidInputException) + return false + end + @warn "The function _assert_valid_input throws an Exception, which is not an InvalidInputError! The Exception thrown is: " + throw(e) + end + return true +end + """ function _post_processing(stp::AbstractComputationSetup, input::Any, result::Any) diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl index a20a26a..c732b8f 100644 --- a/test/interfaces/setup_interface.jl +++ b/test/interfaces/setup_interface.jl @@ -9,6 +9,11 @@ RTOL = sqrt(eps()) _groundtruth_compute(x) = x _groundtruth_input_validation(x) = (x>0) +struct TestException <: QEDprocesses.AbstractInvalidInputException end +function _groundtruth_valid_input_assert(x) + _groundtruth_input_validation(x)||throw(TestException()) + nothing +end _transform_to_invalid(x) = -abs(x) _groundtruth_post_processing(x,y) = x+y @@ -19,18 +24,9 @@ QEDprocesses._compute(stp::AbstractTestSetup, x) = _groundtruth_compute(x) # setup with default implementations struct TestSetupDefault <: AbstractTestSetup end -# setup with custom _is_valid_input -struct TestSetupCustomIsValidInput <: AbstractTestSetup end -QEDprocesses._is_valid_input(::TestSetupCustomIsValidInput, x) = _groundtruth_input_validation(x) - # setup with custom _assert_valid_input struct TestSetupCustomAssertValidInput<: AbstractTestSetup end -QEDprocesses._is_valid_input(::TestSetupCustomAssertValidInput, x) = _groundtruth_input_validation(x) -struct TestException <: Exception end -function QEDprocesses._assert_valid_input(stp::TestSetupCustomAssertValidInput, x) - QEDprocesses._is_valid_input(stp,x)||throw(TestException()) - return nothing -end +QEDprocesses._assert_valid_input(stp::TestSetupCustomAssertValidInput, x) = _groundtruth_valid_input_assert(x) # setup with custom post processing struct TestSetupCustomPostProcessing<: AbstractTestSetup end @@ -38,15 +34,16 @@ QEDprocesses._post_processing(::TestSetupCustomPostProcessing,x,y) = _groundtrut # setup with custom input validation and post processing struct TestSetupCustom <: AbstractTestSetup end -QEDprocesses._is_valid_input(::TestSetupCustom, x) = _groundtruth_input_validation(x) +QEDprocesses._assert_valid_input(stp::TestSetupCustom, x) = _groundtruth_valid_input_assert(x) QEDprocesses._post_processing(::TestSetupCustom,x,y) = _groundtruth_post_processing(x,y) # setup which fail on computation with default implementations struct TestSetupFAIL <: AbstractComputationSetup end -# setup which fail on computation with custom input validation +# setup which fail on computation with custom input validation, where the +# invalid input will be caught before the computation. struct TestSetupCustomValidationFAIL <: AbstractComputationSetup end -QEDprocesses._is_valid_input(::TestSetupCustomValidationFAIL, x) = _groundtruth_input_validation(x) +QEDprocesses._assert_valid_input(stp::TestSetupCustomValidationFAIL, x) = _groundtruth_valid_input_assert(x) # setup which fail on computation with custom post processing struct TestSetupCustomPostProcessingFAIL <: AbstractComputationSetup end @@ -54,13 +51,15 @@ QEDprocesses._post_processing(::TestSetupCustomPostProcessingFAIL,x,y) = _ground @testset "general computation setup interface" begin @testset "interface fail" begin rnd_input = rand(RNG) + @test_throws MethodError QEDprocesses._compute(TestSetupFAIL(), rnd_input) @test_throws MethodError compute(TestSetupFAIL(), rnd_input) @test_throws MethodError QEDprocesses._compute(TestSetupCustomValidationFAIL(), rnd_input) @test_throws MethodError compute(TestSetupCustomValidationFAIL(), rnd_input) # invalid input should be caught without throwing a MethodError - @test_throws InvalidInputError compute(TestSetupCustomValidationFAIL(), _transform_to_invalid(rnd_input)) + @test_throws TestException compute(TestSetupCustomValidationFAIL(), _transform_to_invalid(rnd_input)) + @test_throws MethodError QEDprocesses._compute(TestSetupCustomPostProcessingFAIL(), rnd_input) @test_throws MethodError compute(TestSetupCustomPostProcessingFAIL(), rnd_input) @@ -78,19 +77,13 @@ QEDprocesses._post_processing(::TestSetupCustomPostProcessingFAIL,x,y) = _ground end @testset "custom input validation" begin - stp = TestSetupCustomIsValidInput() + stp = TestSetupCustomAssertValidInput() rnd_input = rand(RNG) @test QEDprocesses._is_valid_input(stp, _groundtruth_input_validation(rnd_input)) @test !QEDprocesses._is_valid_input(stp, !_groundtruth_input_validation(rnd_input)) - @test isapprox(compute(stp, rnd_input), _groundtruth_compute(rnd_input), atol=ATOL,rtol=RTOL) - @test_throws InvalidInputError QEDprocesses._assert_valid_input(stp, _transform_to_invalid(rnd_input)) - @test_throws InvalidInputError compute(stp, _transform_to_invalid(rnd_input)) - - stp2 = TestSetupCustomAssertValidInput() - rnd_input2 = rand(RNG) - @test QEDprocesses._assert_valid_input(stp2,rnd_input2)==nothing - @test_throws TestException QEDprocesses._assert_valid_input(stp2,_transform_to_invalid(rnd_input2)) - @test_throws TestException compute(stp2, _transform_to_invalid(rnd_input2)) + @test QEDprocesses._assert_valid_input(stp,rnd_input)==nothing + @test_throws TestException QEDprocesses._assert_valid_input(stp,_transform_to_invalid(rnd_input)) + @test_throws TestException compute(stp, _transform_to_invalid(rnd_input)) end @@ -106,10 +99,10 @@ QEDprocesses._post_processing(::TestSetupCustomPostProcessingFAIL,x,y) = _ground stp = TestSetupCustom() rnd_input = rand(RNG) rnd_output = rand(RNG) - + @test QEDprocesses._is_valid_input(stp, _groundtruth_input_validation(rnd_input)) @test !QEDprocesses._is_valid_input(stp, !_groundtruth_input_validation(rnd_input)) - @test_throws InvalidInputError compute(stp, _transform_to_invalid(rnd_input)) + @test_throws TestException() compute(stp, _transform_to_invalid(rnd_input)) @test isapprox(QEDprocesses._post_processing(stp,rnd_input,rnd_output), _groundtruth_post_processing(rnd_input,rnd_output)) @test isapprox(compute(stp,rnd_input), _groundtruth_post_processing(rnd_input,_groundtruth_compute(rnd_input))) end From 63c501951e1ff77a2eaddebd4cc741c7eb6aa27a Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Thu, 5 Oct 2023 00:07:51 +0200 Subject: [PATCH 17/19] formatting --- src/QEDprocesses.jl | 2 +- src/interfaces/process_interface.jl | 21 +++-- src/interfaces/setup_interface.jl | 22 +++--- test/interfaces/setup_interface.jl | 118 +++++++++++++++++++--------- test/runtests.jl | 4 +- 5 files changed, 110 insertions(+), 57 deletions(-) diff --git a/src/QEDprocesses.jl b/src/QEDprocesses.jl index 4f7ffe6..aa52614 100644 --- a/src/QEDprocesses.jl +++ b/src/QEDprocesses.jl @@ -15,7 +15,7 @@ export differential_cross_section, total_cross_section # Abstract setup interface export AbstractComputationSetup, InvalidInputError, compute -export AbstractProcessSetup, scattering_process, physical_model +export AbstractProcessSetup, scattering_process, physical_model # particle types export AbstractParticleType diff --git a/src/interfaces/process_interface.jl b/src/interfaces/process_interface.jl index 589171b..feff43e 100644 --- a/src/interfaces/process_interface.jl +++ b/src/interfaces/process_interface.jl @@ -115,14 +115,23 @@ function differential_cross_section( model_def::AbstractModelDefinition, init_phasespace::Union{AbstractVector{T},AbstractMatrix{T}}, final_phasespace::Union{AbstractVector{T},AbstractMatrix{T}}, - ) where {T<:QEDbase.AbstractFourMomentum} +) where {T<:QEDbase.AbstractFourMomentum} size(init_phasespace, 1) == number_incoming_particles(proc_def) || throw( - DimensionMismatch("The number of momenta in the initial phasespace <{length(init_phasespace)}> does not match the number of incoming particles of the process <{number_incoming_particles(proc_def)}>."), + DimensionMismatch( + "The number of momenta in the initial phasespace <{length(init_phasespace)}> does not match the number of incoming particles of the process <{number_incoming_particles(proc_def)}>.", + ), ) size(final_phasespace, 1) == number_outgoing_particles(proc_def) || throw( - DimensionMismatch("The number of momenta in the final phasespace <{length(final_phasespace)}> does not match the number of outgoing particles of the process <{number_outgoing_particles(proc_def)}>."), + DimensionMismatch( + "The number of momenta in the final phasespace <{length(final_phasespace)}> does not match the number of outgoing particles of the process <{number_outgoing_particles(proc_def)}>.", + ), + ) + return _differential_cross_section( + proc_def, + model_def, + init_phasespace, + final_phasespace, ) - return _differential_cross_section(proc_def, model_def, init_phasespace, final_phasespace) end # returns diffCS for single `initPS` and several `finalPS` points without input-check @@ -253,7 +262,9 @@ function total_cross_section( init_phasespace::Union{AbstractVector{T},AbstractMatrix{T}}, ) where {T<:QEDbase.AbstractFourMomentum} size(init_phasespace, 1) == number_incoming_particles(proc_def) || throw( - DimensionMismatch("The number of momenta in the initial phasespace <{length(init_phasespace)}> does not match the number of incoming particles of the process <{number_incoming_particles(proc_def)}>."), + DimensionMismatch( + "The number of momenta in the initial phasespace <{length(init_phasespace)}> does not match the number of incoming particles of the process <{number_incoming_particles(proc_def)}>.", + ), ) return _total_cross_section(proc_def, model_def, init_phasespace) end diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index da5e8e0..fac9986 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -78,10 +78,11 @@ abstract type AbstractInvalidInputException <: Exception end Exception which is thrown if a given input is invalid, e.g. passed to [`_assert_valid_input`](@ref). """ -struct InvalidInputError <: AbstractInvalidInputException +struct InvalidInputError <: AbstractInvalidInputException msg::String end -Base.showerror(io::IO, err::InvalidInputError) = println(io, "InvalidInputError: $(err.msg).") +Base.showerror(io::IO, err::InvalidInputError) = + println(io, "InvalidInputError: $(err.msg).") """ @@ -103,7 +104,7 @@ Interface function, which asserts that the given `input` is valid, and throws an Despite the presence of a custom `_assert_valid_input`, it is highly recommended to also implement `_is_valid_input` for `CustomSetup`, because it might be used outside of the assert function. """ -@inline function _assert_valid_input(stp::AbstractComputationSetup,input) +@inline function _assert_valid_input(stp::AbstractComputationSetup, input) return nothing end @@ -125,7 +126,7 @@ An assert version of this function is given by [`_assert_valid_input`](@ref), wh """ @inline function _is_valid_input(stp::AbstractComputationSetup, input) try - _assert_valid_input(stp,input) + _assert_valid_input(stp, input) catch e if isa(e, AbstractInvalidInputException) return false @@ -176,9 +177,9 @@ input validation ([`_assert_valid_input`]) and post processing (using [`_post_processing`](@ref)) are wrapped around the calculation (see [`AbstractComputationSetup`](@ref) for details). """ function compute(stp::AbstractComputationSetup, input) - _assert_valid_input(stp,input) - raw_result = _compute(stp,input) - return _post_processing(stp, input,raw_result) + _assert_valid_input(stp, input) + raw_result = _compute(stp, input) + return _post_processing(stp, input, raw_result) end """ @@ -219,6 +220,7 @@ an object which is a subtype of [`AbstractModelDefinition`](@ref). """ function physical_model end -@inline number_incoming_particles(stp::AbstractProcessSetup) = number_incoming_particles(scattering_process(stp)) -@inline number_outgoing_particles(stp::AbstractProcessSetup) = number_outgoing_particles(scattering_process(stp)) - +@inline number_incoming_particles(stp::AbstractProcessSetup) = + number_incoming_particles(scattering_process(stp)) +@inline number_outgoing_particles(stp::AbstractProcessSetup) = + number_outgoing_particles(scattering_process(stp)) diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl index c732b8f..6a71703 100644 --- a/test/interfaces/setup_interface.jl +++ b/test/interfaces/setup_interface.jl @@ -8,14 +8,14 @@ ATOL = 0.0 RTOL = sqrt(eps()) _groundtruth_compute(x) = x -_groundtruth_input_validation(x) = (x>0) +_groundtruth_input_validation(x) = (x > 0) struct TestException <: QEDprocesses.AbstractInvalidInputException end function _groundtruth_valid_input_assert(x) - _groundtruth_input_validation(x)||throw(TestException()) + _groundtruth_input_validation(x) || throw(TestException()) nothing end _transform_to_invalid(x) = -abs(x) -_groundtruth_post_processing(x,y) = x+y +_groundtruth_post_processing(x, y) = x + y # setups for which the interface is implemented abstract type AbstractTestSetup <: AbstractComputationSetup end @@ -25,17 +25,20 @@ QEDprocesses._compute(stp::AbstractTestSetup, x) = _groundtruth_compute(x) struct TestSetupDefault <: AbstractTestSetup end # setup with custom _assert_valid_input -struct TestSetupCustomAssertValidInput<: AbstractTestSetup end -QEDprocesses._assert_valid_input(stp::TestSetupCustomAssertValidInput, x) = _groundtruth_valid_input_assert(x) +struct TestSetupCustomAssertValidInput <: AbstractTestSetup end +QEDprocesses._assert_valid_input(stp::TestSetupCustomAssertValidInput, x) = + _groundtruth_valid_input_assert(x) # setup with custom post processing -struct TestSetupCustomPostProcessing<: AbstractTestSetup end -QEDprocesses._post_processing(::TestSetupCustomPostProcessing,x,y) = _groundtruth_post_processing(x,y) +struct TestSetupCustomPostProcessing <: AbstractTestSetup end +QEDprocesses._post_processing(::TestSetupCustomPostProcessing, x, y) = + _groundtruth_post_processing(x, y) # setup with custom input validation and post processing -struct TestSetupCustom <: AbstractTestSetup end -QEDprocesses._assert_valid_input(stp::TestSetupCustom, x) = _groundtruth_valid_input_assert(x) -QEDprocesses._post_processing(::TestSetupCustom,x,y) = _groundtruth_post_processing(x,y) +struct TestSetupCustom <: AbstractTestSetup end +QEDprocesses._assert_valid_input(stp::TestSetupCustom, x) = + _groundtruth_valid_input_assert(x) +QEDprocesses._post_processing(::TestSetupCustom, x, y) = _groundtruth_post_processing(x, y) # setup which fail on computation with default implementations struct TestSetupFAIL <: AbstractComputationSetup end @@ -43,26 +46,37 @@ struct TestSetupFAIL <: AbstractComputationSetup end # setup which fail on computation with custom input validation, where the # invalid input will be caught before the computation. struct TestSetupCustomValidationFAIL <: AbstractComputationSetup end -QEDprocesses._assert_valid_input(stp::TestSetupCustomValidationFAIL, x) = _groundtruth_valid_input_assert(x) +QEDprocesses._assert_valid_input(stp::TestSetupCustomValidationFAIL, x) = + _groundtruth_valid_input_assert(x) # setup which fail on computation with custom post processing struct TestSetupCustomPostProcessingFAIL <: AbstractComputationSetup end -QEDprocesses._post_processing(::TestSetupCustomPostProcessingFAIL,x,y) = _groundtruth_post_processing(x,y) +QEDprocesses._post_processing(::TestSetupCustomPostProcessingFAIL, x, y) = + _groundtruth_post_processing(x, y) @testset "general computation setup interface" begin @testset "interface fail" begin rnd_input = rand(RNG) - @test_throws MethodError QEDprocesses._compute(TestSetupFAIL(), rnd_input) - @test_throws MethodError compute(TestSetupFAIL(), rnd_input) + @test_throws MethodError QEDprocesses._compute(TestSetupFAIL(), rnd_input) + @test_throws MethodError compute(TestSetupFAIL(), rnd_input) - @test_throws MethodError QEDprocesses._compute(TestSetupCustomValidationFAIL(), rnd_input) - @test_throws MethodError compute(TestSetupCustomValidationFAIL(), rnd_input) + @test_throws MethodError QEDprocesses._compute( + TestSetupCustomValidationFAIL(), + rnd_input, + ) + @test_throws MethodError compute(TestSetupCustomValidationFAIL(), rnd_input) # invalid input should be caught without throwing a MethodError - @test_throws TestException compute(TestSetupCustomValidationFAIL(), _transform_to_invalid(rnd_input)) + @test_throws TestException compute( + TestSetupCustomValidationFAIL(), + _transform_to_invalid(rnd_input), + ) - @test_throws MethodError QEDprocesses._compute(TestSetupCustomPostProcessingFAIL(), rnd_input) - @test_throws MethodError compute(TestSetupCustomPostProcessingFAIL(), rnd_input) + @test_throws MethodError QEDprocesses._compute( + TestSetupCustomPostProcessingFAIL(), + rnd_input, + ) + @test_throws MethodError compute(TestSetupCustomPostProcessingFAIL(), rnd_input) end @testset "default interface" begin @@ -70,10 +84,20 @@ QEDprocesses._post_processing(::TestSetupCustomPostProcessingFAIL,x,y) = _ground rnd_input = rand(RNG) rnd_output = rand(RNG) - @test QEDprocesses._is_valid_input(stp,rnd_input) - @test QEDprocesses._post_processing(stp,rnd_input,rnd_output) == rnd_output - @test isapprox(QEDprocesses._compute(stp, rnd_input), _groundtruth_compute(rnd_input), atol=ATOL,rtol=RTOL) - @test isapprox(compute(stp, rnd_input), _groundtruth_compute(rnd_input), atol=ATOL,rtol=RTOL) + @test QEDprocesses._is_valid_input(stp, rnd_input) + @test QEDprocesses._post_processing(stp, rnd_input, rnd_output) == rnd_output + @test isapprox( + QEDprocesses._compute(stp, rnd_input), + _groundtruth_compute(rnd_input), + atol = ATOL, + rtol = RTOL, + ) + @test isapprox( + compute(stp, rnd_input), + _groundtruth_compute(rnd_input), + atol = ATOL, + rtol = RTOL, + ) end @testset "custom input validation" begin @@ -81,8 +105,11 @@ QEDprocesses._post_processing(::TestSetupCustomPostProcessingFAIL,x,y) = _ground rnd_input = rand(RNG) @test QEDprocesses._is_valid_input(stp, _groundtruth_input_validation(rnd_input)) @test !QEDprocesses._is_valid_input(stp, !_groundtruth_input_validation(rnd_input)) - @test QEDprocesses._assert_valid_input(stp,rnd_input)==nothing - @test_throws TestException QEDprocesses._assert_valid_input(stp,_transform_to_invalid(rnd_input)) + @test QEDprocesses._assert_valid_input(stp, rnd_input) == nothing + @test_throws TestException QEDprocesses._assert_valid_input( + stp, + _transform_to_invalid(rnd_input), + ) @test_throws TestException compute(stp, _transform_to_invalid(rnd_input)) end @@ -91,20 +118,32 @@ QEDprocesses._post_processing(::TestSetupCustomPostProcessingFAIL,x,y) = _ground stp = TestSetupCustomPostProcessing() rnd_input = rand(RNG) rnd_output = rand(RNG) - @test isapprox(QEDprocesses._post_processing(stp,rnd_input,rnd_output), _groundtruth_post_processing(rnd_input,rnd_output)) - @test isapprox(compute(stp,rnd_input), _groundtruth_post_processing(rnd_input,_groundtruth_compute(rnd_input))) + @test isapprox( + QEDprocesses._post_processing(stp, rnd_input, rnd_output), + _groundtruth_post_processing(rnd_input, rnd_output), + ) + @test isapprox( + compute(stp, rnd_input), + _groundtruth_post_processing(rnd_input, _groundtruth_compute(rnd_input)), + ) end @testset "custom input validation and post processing" begin stp = TestSetupCustom() rnd_input = rand(RNG) rnd_output = rand(RNG) - + @test QEDprocesses._is_valid_input(stp, _groundtruth_input_validation(rnd_input)) @test !QEDprocesses._is_valid_input(stp, !_groundtruth_input_validation(rnd_input)) @test_throws TestException() compute(stp, _transform_to_invalid(rnd_input)) - @test isapprox(QEDprocesses._post_processing(stp,rnd_input,rnd_output), _groundtruth_post_processing(rnd_input,rnd_output)) - @test isapprox(compute(stp,rnd_input), _groundtruth_post_processing(rnd_input,_groundtruth_compute(rnd_input))) + @test isapprox( + QEDprocesses._post_processing(stp, rnd_input, rnd_output), + _groundtruth_post_processing(rnd_input, rnd_output), + ) + @test isapprox( + compute(stp, rnd_input), + _groundtruth_post_processing(rnd_input, _groundtruth_compute(rnd_input)), + ) end end # process setup @@ -114,7 +153,7 @@ struct TestParticle2 <: AbstractParticle end struct TestParticle3 <: AbstractParticle end struct TestParticle4 <: AbstractParticle end -PARTICLE_SET = [TestParticle1(), TestParticle2(), TestParticle3(),TestParticle4()] +PARTICLE_SET = [TestParticle1(), TestParticle2(), TestParticle3(), TestParticle4()] struct TestProcess <: AbstractProcessDefinition end struct TestModel <: AbstractModelDefinition end @@ -135,20 +174,21 @@ struct TestProcessSetupFAIL <: AbstractProcessSetup end @testset "hard interface" begin stp = TestProcessSetup() - - @test QEDprocesses._is_computation_setup(stp) + + @test QEDprocesses._is_computation_setup(stp) @test scattering_process(stp) == TestProcess() @test physical_model(stp) == TestModel() end - @testset "($N_INCOMING,$N_OUTGOING)" for (N_INCOMING,N_OUTGOING) in Iterators.product( - (1, rand(RNG, 2:8)), (1, rand(RNG, 2:8)) - ) - INCOMING_PARTICLES = rand(RNG,PARTICLE_SET,N_INCOMING) - OUTGOING_PARTICLES = rand(RNG,PARTICLE_SET,N_OUTGOING) + @testset "($N_INCOMING,$N_OUTGOING)" for (N_INCOMING, N_OUTGOING) in Iterators.product( + (1, rand(RNG, 2:8)), + (1, rand(RNG, 2:8)), + ) + INCOMING_PARTICLES = rand(RNG, PARTICLE_SET, N_INCOMING) + OUTGOING_PARTICLES = rand(RNG, PARTICLE_SET, N_OUTGOING) QEDprocesses.incoming_particles(::TestProcess) = INCOMING_PARTICLES - QEDprocesses.outgoing_particles(::TestProcess) = OUTGOING_PARTICLES + QEDprocesses.outgoing_particles(::TestProcess) = OUTGOING_PARTICLES @testset "delegated functions" begin stp = TestProcessSetup() diff --git a/test/runtests.jl b/test/runtests.jl index b6bc916..4771120 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -13,8 +13,8 @@ begin @time @safetestset "process interface" begin include("interfaces/process_interface.jl") end - @time @safetestset "computation setup interface" begin - include("interfaces/setup_interface.jl") + @time @safetestset "computation setup interface" begin + include("interfaces/setup_interface.jl") end # modules From 2a37a0f6bc205cae216ce76e031356a81258fef8 Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Thu, 5 Oct 2023 15:43:01 +0200 Subject: [PATCH 18/19] removed _is_valid_input, since the usage could be misleading, and _assert_valid_input covers all necessary usecases --- src/interfaces/setup_interface.jl | 42 ++++-------------------------- test/interfaces/setup_interface.jl | 5 ---- 2 files changed, 5 insertions(+), 42 deletions(-) diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index fac9986..5f12833 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -30,7 +30,7 @@ quantity depends on is kept constant. _assert_valid_input(stp::AbstractComputationSetup, input) ``` - which should throw and an exception subtyped from [`AbstractInvalidInputException`](@ref) if the `input` is not valid for the computation of the associated quantity (see [`_is_valid_input`](@ref) and [`_assert_valid_input`](@ref) for more details). + which should throw and an exception subtyped from [`AbstractInvalidInputException`](@ref) if the `input` is not valid for the computation of the associated quantity ([`_assert_valid_input`](@ref) for more details). The default implementation does nothing, i.e. every input is valid by default. Provide a custom implementation if a different behavior is required. ## Actual computation @@ -92,51 +92,19 @@ Interface function, which asserts that the given `input` is valid, and throws an !!! note "default implementation" - The generic fallback uses the boolian value returned by `_is_valid_input(stp,input)` to check for validity, - i.e. if the returned value is `true` the assert does not trigger and nothing happens, but if the returned value is `false`, - an error with a generic error message will be thrown (see [`_is_valid_input`](@ref) for details). - To customize the error message, or use a custom assertion mechanism, just add your own implementation of + By default, every input is assumed to be valid. Therefore, this functions does nothing. + To customize this behavior add your own implementation of ```Julia _assert_valid_input(stp::YourCustomSetup,input) ``` - which should throw an [`InvalidInputError`](@ref) if the input is invalid. - Despite the presence of a custom `_assert_valid_input`, it is highly recommended to also implement `_is_valid_input` for `CustomSetup`, because it might be used outside of the assert function. + which should throw an exception, which is subtype of [`AbstractInvalidInputError`](@ref). One may also use the concrete implementation [`InvalidInputError`](@ref) if the input is invalid, instead of writing a custom exception type. """ @inline function _assert_valid_input(stp::AbstractComputationSetup, input) return nothing end -""" - - _is_valid_input(stp::AbstractComputationSetup, input::Any) - -Interface function, which returns true if the constraints of the `input` associated with the quantity of `stp` are met. -This function is called to validate the input of [`compute`](@ref) before calling [`_compute`](@ref). - -!!! note "Default implementation" - - Since no input validation is equivalent to every input being valid, this function returns `true` by default. - This behavior can be overwritten if actual validation is necessary. - - -An assert version of this function is given by [`_assert_valid_input`](@ref), which directly uses the output of this function. - -""" -@inline function _is_valid_input(stp::AbstractComputationSetup, input) - try - _assert_valid_input(stp, input) - catch e - if isa(e, AbstractInvalidInputException) - return false - end - @warn "The function _assert_valid_input throws an Exception, which is not an InvalidInputError! The Exception thrown is: " - throw(e) - end - return true -end - """ function _post_processing(stp::AbstractComputationSetup, input::Any, result::Any) @@ -161,7 +129,7 @@ Interface function that returns the value of the associated quantity evaluated o !!! note "unsafe implementation" - This function must be implemented for any subtype of [`AbstractComputationSetup`]. It should not do any input validation or post processing (see [`_is_valid_input`](@ref) and [`_post_processing`](@ref)), as those two are performed while calling + This function must be implemented for any subtype of [`AbstractComputationSetup`]. It should not do any input validation or post processing (see [`_assert_valid_input`](@ref) and [`_post_processing`](@ref)), as those two are performed while calling the safe version of this function [`compute`](@ref). """ diff --git a/test/interfaces/setup_interface.jl b/test/interfaces/setup_interface.jl index 6a71703..c7ed6a4 100644 --- a/test/interfaces/setup_interface.jl +++ b/test/interfaces/setup_interface.jl @@ -84,7 +84,6 @@ QEDprocesses._post_processing(::TestSetupCustomPostProcessingFAIL, x, y) = rnd_input = rand(RNG) rnd_output = rand(RNG) - @test QEDprocesses._is_valid_input(stp, rnd_input) @test QEDprocesses._post_processing(stp, rnd_input, rnd_output) == rnd_output @test isapprox( QEDprocesses._compute(stp, rnd_input), @@ -103,8 +102,6 @@ QEDprocesses._post_processing(::TestSetupCustomPostProcessingFAIL, x, y) = @testset "custom input validation" begin stp = TestSetupCustomAssertValidInput() rnd_input = rand(RNG) - @test QEDprocesses._is_valid_input(stp, _groundtruth_input_validation(rnd_input)) - @test !QEDprocesses._is_valid_input(stp, !_groundtruth_input_validation(rnd_input)) @test QEDprocesses._assert_valid_input(stp, rnd_input) == nothing @test_throws TestException QEDprocesses._assert_valid_input( stp, @@ -133,8 +130,6 @@ QEDprocesses._post_processing(::TestSetupCustomPostProcessingFAIL, x, y) = rnd_input = rand(RNG) rnd_output = rand(RNG) - @test QEDprocesses._is_valid_input(stp, _groundtruth_input_validation(rnd_input)) - @test !QEDprocesses._is_valid_input(stp, !_groundtruth_input_validation(rnd_input)) @test_throws TestException() compute(stp, _transform_to_invalid(rnd_input)) @test isapprox( QEDprocesses._post_processing(stp, rnd_input, rnd_output), From c5744ff047f78d8dbe0dc41115a7b76896f9df8b Mon Sep 17 00:00:00 2001 From: Uwe Hernandez Acosta Date: Thu, 5 Oct 2023 15:58:10 +0200 Subject: [PATCH 19/19] Apply suggestions from code review fixed comments on comments Co-authored-by: Anton Reinhard --- src/interfaces/setup_interface.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/interfaces/setup_interface.jl b/src/interfaces/setup_interface.jl index 5f12833..19e8122 100644 --- a/src/interfaces/setup_interface.jl +++ b/src/interfaces/setup_interface.jl @@ -30,7 +30,7 @@ quantity depends on is kept constant. _assert_valid_input(stp::AbstractComputationSetup, input) ``` - which should throw and an exception subtyped from [`AbstractInvalidInputException`](@ref) if the `input` is not valid for the computation of the associated quantity ([`_assert_valid_input`](@ref) for more details). + which should throw and an exception subtyped from [`AbstractInvalidInputException`](@ref) if the `input` is not valid for the computation of the associated quantity (see [`_assert_valid_input`](@ref) for more details). The default implementation does nothing, i.e. every input is valid by default. Provide a custom implementation if a different behavior is required. ## Actual computation @@ -92,13 +92,13 @@ Interface function, which asserts that the given `input` is valid, and throws an !!! note "default implementation" - By default, every input is assumed to be valid. Therefore, this functions does nothing. - To customize this behavior add your own implementation of + By default, every input is assumed to be valid. Therefore, this function does nothing. + To customize this behavior, add your own implementation of ```Julia _assert_valid_input(stp::YourCustomSetup,input) ``` - which should throw an exception, which is subtype of [`AbstractInvalidInputError`](@ref). One may also use the concrete implementation [`InvalidInputError`](@ref) if the input is invalid, instead of writing a custom exception type. + which should throw an exception, which is a subtype of [`AbstractInvalidInputError`](@ref). One may also use the concrete implementation [`InvalidInputError`](@ref) if the input is invalid instead of writing a custom exception type. """ @inline function _assert_valid_input(stp::AbstractComputationSetup, input) @@ -129,7 +129,7 @@ Interface function that returns the value of the associated quantity evaluated o !!! note "unsafe implementation" - This function must be implemented for any subtype of [`AbstractComputationSetup`]. It should not do any input validation or post processing (see [`_assert_valid_input`](@ref) and [`_post_processing`](@ref)), as those two are performed while calling + This function must be implemented for any subtype of [`AbstractComputationSetup`](@ref). It should not do any input validation or post processing (see [`_assert_valid_input`](@ref) and [`_post_processing`](@ref)), as those two are performed while calling the safe version of this function [`compute`](@ref). """