From 6361e1b0d25544add310e1ca99a384a49c1d70b6 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Mon, 11 Nov 2024 13:12:47 +0100 Subject: [PATCH 01/34] add submodule for c api, library compilation with PackageCompiler --- .gitignore | 3 + compile/Project.toml | 11 + compile/README.md | 65 ++++++ compile/build.jl | 16 ++ compile/include/JetReconstruction.h | 145 +++++++++++++ compile/precompile_execution.jl | 1 + compile/precompile_statements.jl | 1 + compile/test/jetreconstruction_test.c | 67 ++++++ .../C_JetReconstruction.jl | 191 ++++++++++++++++++ src/JetReconstruction.jl | 3 + 10 files changed, 503 insertions(+) create mode 100644 compile/Project.toml create mode 100644 compile/README.md create mode 100644 compile/build.jl create mode 100644 compile/include/JetReconstruction.h create mode 100644 compile/precompile_execution.jl create mode 100644 compile/precompile_statements.jl create mode 100644 compile/test/jetreconstruction_test.c create mode 100644 src/C_JetReconstruction/C_JetReconstruction.jl diff --git a/.gitignore b/.gitignore index cb8bb026..39b113a6 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ benchmark/* **/profile/* /statprof/* /debug/* + +# Compiled packages +JetReconstructionCompiled diff --git a/compile/Project.toml b/compile/Project.toml new file mode 100644 index 00000000..e93077e4 --- /dev/null +++ b/compile/Project.toml @@ -0,0 +1,11 @@ +[deps] +JetReconstruction = "44e8cb2c-dfab-4825-9c70-d4808a591196" +PackageCompiler = "9b87118b-4619-50d2-8e1e-99f35a4d4d9d" + +[sources] +JetReconstruction = {path = ".."} + +[compat] +JetReconstruction = "0.4" +PackageCompiler = "2" +julia = "1.11" diff --git a/compile/README.md b/compile/README.md new file mode 100644 index 00000000..838e3f15 --- /dev/null +++ b/compile/README.md @@ -0,0 +1,65 @@ +# Compiling JetReconstruction.jl to a C-library + +Minimal C bindings for JetReconstruction.jl + +- [C-header](JetReconstruction.h) +- shared library compiled with [PackageCompiler.jl](https://github.com/JuliaLang/PackageCompiler.jl) + +## Building library + +To build the library, run the following command from the package root directory: + +```sh +julia --project=compile compile/build.jl +``` + +## Usage example + +### Example source file + +Example usage of C bindings in an application: + +```C +#include "JetReconstruction.h" +#include "julia_init.h" /*Should be automatically generated by PackageCompiler.jl and distributed together with the "JetReconstruction.h" header file*/ + +int main(int argc, char *argv[]) { + init_julia(argc, argv); /*initialization of julia runtime*/ + + /*Prepare array of pseudo jets*/ + size_t particles_len; + jetreconstruction_PseudoJet* particles; + /*Initialize with desired values*/ + + /*Call jet reconstruction*/ + jetreconstruction_JetAlgorithm algorithm = JETRECONSTRUCTION_JETALGORITHM_CA; + double R = 3.0; + jetreconstruction_RecoStrategy strategy = JETRECONSTRUCTION_RECOSTRATEGY_BEST; + + jetreconstruction_ClusterSequence cluster_seq; + jetreconstruction_jet_reconstruct(particles, len, algorithm, R, strategy, + &cluster_seq); + + /*Use the cluster sequence in your application + then free memory allocations done by library*/ + jetreconstruction_ClusterSequence_free_members(&cluster_seq); + shutdown_julia(0); /*teardown of julia runtime*/ + return 0; +} + +``` + +### Example compilation + +To build an example application run the following command: + +```shell +cc -o jetreconstruction_test compile/test/jetreconstruction_test.c -IJetReconstructionCompiled/include -LJetReconstructionCompiled/lib -ljetreconstruction -ljulia +``` + +In case the compiled library resides in non-standard location, add its location to `LD_LIBRARY_PATH` when running example application: + +```shell +LD_LIBRARY_PATH=JetReconstructionCompiled/lib/:${LD_LIBRARY_PATH} ./jetreconstruction_test +``` + diff --git a/compile/build.jl b/compile/build.jl new file mode 100644 index 00000000..4508cf78 --- /dev/null +++ b/compile/build.jl @@ -0,0 +1,16 @@ +using PackageCompiler + +output_directory = joinpath(splitdir(@__DIR__) |> first, "JetReconstructionCompiled") + +@info "Creating library in $output_directory" +PackageCompiler.create_library(".", output_directory; + lib_name = "jetreconstruction", + header_files = [joinpath(@__DIR__, "include", + "JetReconstruction.h")], + # precompile_execution_file = [joinpath(@__DIR__, + # "precompile_execution.jl")], + # precompile_statements_file = [jointpath(@__DIR__, + # "precompile_statements.jl")], + incremental = false, + filter_stdlibs = true, + force = true) diff --git a/compile/include/JetReconstruction.h b/compile/include/JetReconstruction.h new file mode 100644 index 00000000..c9c79c7d --- /dev/null +++ b/compile/include/JetReconstruction.h @@ -0,0 +1,145 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 JetReconstruction.jl authors, CERN + * SPDX-License-Identifier: MIT + */ + +#include + +/* +Enumeration representing different jet algorithms used in +the JetReconstruction module. +*/ +typedef enum { + JETRECONSTRUCTION_JETALGORITHM_ANTIKT = 0, /* The Anti-Kt algorithm. */ + JETRECONSTRUCTION_JETALGORITHM_CA = 1, /* The Cambridge/Aachen algorithm. */ + JETRECONSTRUCTION_JETALGORITHM_KT = 2, /* The Inclusive-Kt algorithm. */ + JETRECONSTRUCTION_JETALGORITHM_GENKT = + 3, /* The Generalised Kt algorithm (with arbitrary power). */ + JETRECONSTRUCTION_JETALGORITHM_EEKT = + 4, /* The Generalised e+e- kt algorithm. */ + JETRECONSTRUCTION_JETALGORITHM_DURHAM = + 5 /* The e+e- kt algorithm, aka Durham. */ +} jetreconstruction_JetAlgorithm; + +/* +Scoped enumeration (using EnumX) representing the different strategies for jet +reconstruction. +*/ +typedef enum { + JETRECONSTRUCTION_RECOSTRATEGY_BEST = 0, /* The best strategy. */ + JETRECONSTRUCTION_RECOSTRATEGY_N2PLAIN = 1, /* The plain N2 strategy. */ + JETRECONSTRUCTION_RECOSTRATEGY_N2TILTED = 2 /* The tiled N2 strategy. */ +} jetreconstruction_RecoStrategy; + +/* The `PseudoJet` struct represents a pseudojet, a four-momentum object used in +jet reconstruction algorithms. Additional information for the link back into the +history of the clustering is stored in the `_cluster_hist_index` field. There is +caching of the more expensive calculations for rapidity and azimuthal angle.*/ +typedef struct { + double px; /* The x-component of the momentum. */ + double py; /* The y-component of the momentum. */ + double pz; /* The z-component of the momentum. */ + double E; /* The energy component of the momentum. */ + long _cluster_hist_index; /* The index of the cluster history. */ + double _pt2; /* The squared transverse momentum. */ + double _inv_pt2; /* The inverse squared transverse momentum. */ + double _rap; /* The rapidity. */ + double _phi; /* The azimuthal angle. */ +} jetreconstruction_PseudoJet; + +int jetreconstruction_PseudoJet_init(jetreconstruction_PseudoJet *ptr, + double px, double py, double pz, double E); +/* +A struct holding a record of jet mergers and finalisations +*/ +typedef struct { + long parent1; /* Index in history where first parent of this jet was + created (NonexistentParent if this jet is an original + particle) */ + long parent2; /* Index in history where second parent of this jet was + created (NonexistentParent if this jet is an original + particle); BeamJet if this history entry just labels the + fact that the jet has recombined with the beam */ + long child; /* Index in history where the current jet is recombined with + another jet to form its child. It is Invalid + if this jet does not further recombine. */ + long jetp_index; /* Index in the jets vector where we will find the + PseudoJet object corresponding to this jet (i.e. the + jet created at this entry of the history). NB: if this + element of the history corresponds to a beam + recombination, then `jetp_index=Invalid`. */ + double dij; /* The distance corresponding to the recombination at this + stage of the clustering. */ + double max_dij_so_far; /* The largest recombination distance seen so far + in the clustering history */ +} jetreconstruction_HistoryElement; + +/* +A struct holding the full history of a jet clustering sequence, including the +final jets. +*/ +typedef struct { + jetreconstruction_JetAlgorithm + algorithm; /* The algorithm used for clustering. */ + double power; /* The power value used for the clustering algorithm (note that + this value is always stored as a Float64 to be + type stable) */ + double R; /* The R parameter used for the clustering algorithm. */ + jetreconstruction_RecoStrategy + strategy; /* The strategy used for clustering. */ + jetreconstruction_PseudoJet + *jets; /* The actual jets in the cluster sequence, which are of type `T + <: FourMomentum`. */ + size_t jets_length; /* Length of jets. */ + long n_initial_jets; /* The initial number of particles used for exclusive + jets. */ + jetreconstruction_HistoryElement + *history; /* The branching history of the cluster sequence. Each + stage in the history indicates where to look in the + jets vector to get the physical PseudoJet. */ + size_t history_length; /* Length of history. */ + double Qtot; /* The total energy of the event. */ +} jetreconstruction_ClusterSequence; + +void jetreconstruction_ClusterSequence_free_members_( + jetreconstruction_ClusterSequence *ptr); +static inline void jetreconstruction_ClusterSequence_free_members( + jetreconstruction_ClusterSequence *ptr) { + jetreconstruction_ClusterSequence_free_members_(ptr); + ptr->jets = NULL; + ptr->jets_length = 0; + ptr->history = NULL; + ptr->history_length = 0; +} + +int jetreconstruction_jet_reconstruct( + const jetreconstruction_PseudoJet *particles, size_t particles_length, + jetreconstruction_JetAlgorithm algorithm, double R, + jetreconstruction_RecoStrategy strategy, + jetreconstruction_ClusterSequence *result); + +typedef struct { + jetreconstruction_PseudoJet *data; + size_t length; +} jetreconstruction_JetsResult; + +void jetreconstruction_JetsResult_free_members_( + jetreconstruction_JetsResult *ptr); +static inline void +jetreconstruction_JetsResult_free_members(jetreconstruction_JetsResult *ptr) { + jetreconstruction_JetsResult_free_members_(ptr); + ptr->data = NULL; + ptr->length = 0; +} + +int jetreconstruction_exclusive_jets_dcut( + const jetreconstruction_ClusterSequence *clustersequence, double dcut, + jetreconstruction_JetsResult *result); + +int jetreconstruction_exclusive_jets_njets( + const jetreconstruction_ClusterSequence *clustersequence, size_t njets, + jetreconstruction_JetsResult *result); + +int jetreconstruction_inclusive_jets( + const jetreconstruction_ClusterSequence *clustersequence, double ptmin, + jetreconstruction_JetsResult *result); diff --git a/compile/precompile_execution.jl b/compile/precompile_execution.jl new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/compile/precompile_execution.jl @@ -0,0 +1 @@ + diff --git a/compile/precompile_statements.jl b/compile/precompile_statements.jl new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/compile/precompile_statements.jl @@ -0,0 +1 @@ + diff --git a/compile/test/jetreconstruction_test.c b/compile/test/jetreconstruction_test.c new file mode 100644 index 00000000..0a04917a --- /dev/null +++ b/compile/test/jetreconstruction_test.c @@ -0,0 +1,67 @@ +#include "JetReconstruction.h" +#include "julia_init.h" +#include +#include +#include + +void printPseudoJet(const jetreconstruction_PseudoJet *jet) { + assert(jet != NULL); + printf("PseudoJet(%f %f %f %f %ld %f %f %f %f)\n", + jet->px, jet->py, jet->pz, jet->E, jet->_cluster_hist_index, jet->_pt2, + jet->_inv_pt2, jet->_rap, jet->_phi); +} + +void printHistoryElement(const jetreconstruction_HistoryElement *history) { + assert(history != NULL); + printf("HistoryElement(%ld %ld %ld %ld %lf %lf)\n", + history->parent1, history->parent2, history->child, + history->jetp_index, history->dij, history->max_dij_so_far); +} + +void printClusterSequence(const jetreconstruction_ClusterSequence *sequence) { + printf("Cluster Sequence Information:\n" + "Algorithm: %d\n" + "Power: %f\n" + "R parameter: %f\n" + "Strategy: %d\n" + "Initial number of jets: %ld\n" + "Total event energy (Qtot): %f\n", + sequence->algorithm, sequence->power, sequence->R, sequence->strategy, + sequence->n_initial_jets, sequence->Qtot); + printf("Number of jets: %zu\n", sequence->jets_length); + if (sequence->jets != NULL) { + for (size_t i = 0; i < sequence->jets_length; i++) { + printPseudoJet(sequence->jets + i); + } + } + printf("History length: %zu\n", sequence->history_length); + if (sequence->history != NULL) { + for (size_t i = 0; i < sequence->history_length; i++) { + printHistoryElement(sequence->history + i); + } + } +} + +int main(int argc, char *argv[]) { + init_julia(argc, argv); + size_t len = 2; + jetreconstruction_PseudoJet particles[2]; + jetreconstruction_PseudoJet_init(&particles[0], 0.0, 1.0, 2.0, 3.0); + jetreconstruction_PseudoJet_init(&particles[1], 1.0, 2.0, 3.0, 4.0); + + jetreconstruction_JetAlgorithm algorithm = JETRECONSTRUCTION_JETALGORITHM_CA; + double R = 3.0; + jetreconstruction_RecoStrategy strategy = JETRECONSTRUCTION_RECOSTRATEGY_BEST; + + jetreconstruction_ClusterSequence cluster_seq; + jetreconstruction_jet_reconstruct(particles, len, algorithm, R, strategy, + &cluster_seq); + + printClusterSequence(&cluster_seq); + jetreconstruction_JetsResult result; + jetreconstruction_exclusive_jets_njets(&cluster_seq, 2, &result); + jetreconstruction_JetsResult_free_members(&result); + jetreconstruction_ClusterSequence_free_members(&cluster_seq); + shutdown_julia(0); + return 0; +} diff --git a/src/C_JetReconstruction/C_JetReconstruction.jl b/src/C_JetReconstruction/C_JetReconstruction.jl new file mode 100644 index 00000000..4c123349 --- /dev/null +++ b/src/C_JetReconstruction/C_JetReconstruction.jl @@ -0,0 +1,191 @@ +""" +Minimal C bindings for JetReconstruction.jl +""" +module C_JetReconstruction + +using ..JetReconstruction: JetAlgorithm, RecoStrategy, PseudoJet, ClusterSequence, + HistoryElement, jet_reconstruct, + exclusive_jets, inclusive_jets + +""" + unsafe_wrap_c_array(ptr::Ptr{T}, array_length::Csize_t) where {T} + +Wraps a C array into a Julia `Vector` for both bits and non-bits types. + +# Arguments +- `ptr::Ptr{T}`: A pointer to the C array. +- `array_length::Csize_t`: The length of the C array. + +# Returns +- A Julia `Vector{T}` containing the elements of the C array. + +# Safety +This function use 'unsafe' methods and has undefined behaviour +if pointer isn't valid or length isn't correct. +""" +function unsafe_wrap_c_array(ptr::Ptr{T}, array_length::Csize_t) where {T} + if isbitstype(T) + return unsafe_wrap(Vector{T}, ptr, array_length) + end + + vec = Vector{T}(undef, array_length) + for i in eachindex(vec) + @inbounds vec[i] = unsafe_load(ptr, i) + end + return vec +end + +""" + make_c_array(v::Vector{T}) where {T} + +Helper function for converting a Julia vector to a C-style array. +A C-style array is dynamically allocated and contents of input vector copied to it. + +# Arguments +- `v::Vector{T}`: A Julia vector of type `T`. + +# Returns +- `ptr::Ptr{T}`: A pointer to the allocated C-style array. +- `len::Int`: The length of the vector. + +# Throws +- `OutOfMemoryError`: If memory allocation fails. + +# Notes +- The caller is responsible for freeing the allocated memory using `Libc.free(ptr)`. +""" +function make_c_array(v::Vector{T}) where {T} + len = length(v) + ptr = Ptr{T}(Libc.malloc(len * sizeof(T))) + if ptr == C_NULL + throw(OutOfMemoryError("Libc.malloc failed to allocate memory")) + end + for i in 1:len + @inbounds unsafe_store!(ptr, v[i], i) + end + return ptr, len +end + +Base.@ccallable function jetreconstruction_PseudoJet_init(ptr::Ptr{PseudoJet}, px::Cdouble, + py::Cdouble, pz::Cdouble, + E::Cdouble)::Cint + pseudojet = PseudoJet(px, py, pz, E) + unsafe_store!(ptr, pseudojet) + return 0 +end + +struct C_ClusterSequence{T} + algorithm::JetAlgorithm.Algorithm + power::Cdouble + R::Cdouble + strategy::RecoStrategy.Strategy + jets::Ptr{T} + jets_length::Csize_t + n_initial_jets::Clong + history::Ptr{HistoryElement} + history_length::Csize_t + Qtot::Cdouble +end + +function free_members(ptr::Ptr{C_ClusterSequence{T}}) where {T} + if ptr != C_NULL + clusterseq = unsafe_load(ptr) + Libc.free(clusterseq.jets) + Libc.free(clusterseq.history) + # Struct is immutable so pointers can't be assigned NULL and lengths updated to zero (without making a copy) + end +end +Base.@ccallable function jetreconstruction_ClusterSequence_free_members_(ptr::Ptr{C_ClusterSequence{PseudoJet}})::Cvoid + free_members(ptr) + return nothing +end + +function ClusterSequence{T}(c::C_ClusterSequence{T}) where {T} + jets_v = unsafe_wrap_c_array(c.jets, c.jets_length) + history_v = unsafe_wrap_c_array(c.history, c.history_length) + return ClusterSequence{T}(c.algorithm, c.power, c.R, c.strategy, jets_v, + c.n_initial_jets, + history_v, c.Qtot) +end + +function C_ClusterSequence{T}(clustersequence::ClusterSequence{T}) where {T} + jets_ptr, jets_length = make_c_array(clustersequence.jets) + history_ptr, history_length = make_c_array(clustersequence.history) + return C_ClusterSequence{T}(clustersequence.algorithm, clustersequence.power, + clustersequence.R, clustersequence.strategy, jets_ptr, + jets_length, clustersequence.n_initial_jets, history_ptr, + history_length, clustersequence.Qtot) +end + +function c_jet_reconstruct(particles::Ptr{T}, + particles_length::Csize_t, + algorithm::JetAlgorithm.Algorithm, + R::Cdouble, + strategy::RecoStrategy.Strategy, + result::Ptr{C_ClusterSequence{U}}) where {T, U} + particles_v = unsafe_wrap_c_array(particles, particles_length) + clusterseq = jet_reconstruct(particles_v; p = nothing, algorithm = algorithm, R = R, + strategy = strategy) + c_clusterseq = C_ClusterSequence{U}(clusterseq) + unsafe_store!(result, c_clusterseq) + return 0 +end + +Base.@ccallable function jetreconstruction_jet_reconstruct(particles::Ptr{PseudoJet}, + particles_length::Csize_t, + algorithm::JetAlgorithm.Algorithm, + R::Cdouble, + strategy::RecoStrategy.Strategy, + result::Ptr{C_ClusterSequence{PseudoJet}})::Cint + c_jet_reconstruct(particles, particles_length, algorithm, R, strategy, result) + return 0 +end + +struct C_JetsResult{T} + data::Ptr{T} + length::Csize_t +end + +function free_members(ptr::Ptr{C_JetsResult{T}}) where {T} + if ptr != C_NULL + result = unsafe_load(ptr) + Libc.free(result.data) + # Struct is immutable so pointer can't be assigned NULL and length updated to zero (without making a copy) + end +end + +Base.@ccallable function jetreconstruction_JetsResult_free_members_(ptr::Ptr{C_JetsResult{PseudoJet}})::Cvoid + free_members(ptr) + return nothing +end + +function jets_selection(selector, clustersequence::Ptr{C_ClusterSequence{T}}, + result::Ptr{C_JetsResult{U}}; kwargs...)::Cint where {T, U} + c_clusterseq = unsafe_load(clustersequence) + clusterseq = ClusterSequence{T}(c_clusterseq) + jets_result = selector(clusterseq; kwargs...) + println(jets_result) + c_results = C_JetsResult{U}(C_NULL, 0) # TODO convert and write to result + unsafe_store!(result, c_results) + return 0 +end + +Base.@ccallable function jetreconstruction_exclusive_jets_dcut(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, + dcut::Cdouble, + result::Ptr{C_JetsResult{PseudoJet}})::Cint + return jets_selection(exclusive_jets, clustersequence, result; dcut = dcut) +end + +Base.@ccallable function jetreconstruction_exclusive_jets_njets(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, + njets::Csize_t, + result::Ptr{C_JetsResult{PseudoJet}})::Cint + return jets_selection(exclusive_jets, clustersequence, result; njets = njets) +end + +Base.@ccallable function jetreconstruction_inclusive_jets(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, + ptmin::Cdouble, + result::Ptr{C_JetsResult{PseudoJet}})::Cint + return jets_selection(inclusive_jets, clustersequence, result; ptmin = ptmin) +end + +end # module C_JetReconstruction diff --git a/src/JetReconstruction.jl b/src/JetReconstruction.jl index dd171900..c5c8b383 100644 --- a/src/JetReconstruction.jl +++ b/src/JetReconstruction.jl @@ -111,4 +111,7 @@ export jetsplot, animatereco include("JSONresults.jl") export FinalJet, FinalJets +# C bindings sub-module +include("C_JetReconstruction/C_JetReconstruction.jl") + end From f86740993f09a12b39643ff60bc0dad1a2482c9b Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Mon, 11 Nov 2024 17:57:10 +0100 Subject: [PATCH 02/34] add ClusterSequence constants --- compile/include/JetReconstruction.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compile/include/JetReconstruction.h b/compile/include/JetReconstruction.h index c9c79c7d..f21703e9 100644 --- a/compile/include/JetReconstruction.h +++ b/compile/include/JetReconstruction.h @@ -5,6 +5,11 @@ #include +/*Special states in a history.*/ +#define JETRECONSTRUCTION_INVALID -3 +#define JETRECONSTRUCTION_NONEXISTENTPARENT -2 +#define JETRECONSTRUCTION_BEAMJET -1 + /* Enumeration representing different jet algorithms used in the JetReconstruction module. From 7f41cdd995d3257c6ba793de691597e4237bae80 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Tue, 12 Nov 2024 18:06:59 +0100 Subject: [PATCH 03/34] add writing jets selections results to ptr --- compile/test/jetreconstruction_test.c | 9 +++++++++ src/C_JetReconstruction/C_JetReconstruction.jl | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/compile/test/jetreconstruction_test.c b/compile/test/jetreconstruction_test.c index 0a04917a..0f4b32e1 100644 --- a/compile/test/jetreconstruction_test.c +++ b/compile/test/jetreconstruction_test.c @@ -42,6 +42,13 @@ void printClusterSequence(const jetreconstruction_ClusterSequence *sequence) { } } +void printJetsResult(const jetreconstruction_JetsResult *results) { + assert(results != NULL); + for (size_t i = 0; i < results->length; ++i) { + printPseudoJet(results->data + i); + } +} + int main(int argc, char *argv[]) { init_julia(argc, argv); size_t len = 2; @@ -60,6 +67,8 @@ int main(int argc, char *argv[]) { printClusterSequence(&cluster_seq); jetreconstruction_JetsResult result; jetreconstruction_exclusive_jets_njets(&cluster_seq, 2, &result); + printJetsResult(&result); + jetreconstruction_JetsResult_free_members(&result); jetreconstruction_ClusterSequence_free_members(&cluster_seq); shutdown_julia(0); diff --git a/src/C_JetReconstruction/C_JetReconstruction.jl b/src/C_JetReconstruction/C_JetReconstruction.jl index 4c123349..08962c23 100644 --- a/src/C_JetReconstruction/C_JetReconstruction.jl +++ b/src/C_JetReconstruction/C_JetReconstruction.jl @@ -23,6 +23,7 @@ Wraps a C array into a Julia `Vector` for both bits and non-bits types. This function use 'unsafe' methods and has undefined behaviour if pointer isn't valid or length isn't correct. """ + function unsafe_wrap_c_array(ptr::Ptr{T}, array_length::Csize_t) where {T} if isbitstype(T) return unsafe_wrap(Vector{T}, ptr, array_length) @@ -163,9 +164,8 @@ function jets_selection(selector, clustersequence::Ptr{C_ClusterSequence{T}}, result::Ptr{C_JetsResult{U}}; kwargs...)::Cint where {T, U} c_clusterseq = unsafe_load(clustersequence) clusterseq = ClusterSequence{T}(c_clusterseq) - jets_result = selector(clusterseq; kwargs...) - println(jets_result) - c_results = C_JetsResult{U}(C_NULL, 0) # TODO convert and write to result + jets_result = selector(clusterseq; T = U, kwargs...) + c_results = C_JetsResult{U}(make_c_array(jets_result)...) unsafe_store!(result, c_results) return 0 end From 237f7f0289bce39ec39d06f881292812f4448db6 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Thu, 14 Nov 2024 17:28:40 +0100 Subject: [PATCH 04/34] add measuring execution time for c-app --- compile/test/jetreconstruction_test.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compile/test/jetreconstruction_test.c b/compile/test/jetreconstruction_test.c index 0f4b32e1..7ba9c237 100644 --- a/compile/test/jetreconstruction_test.c +++ b/compile/test/jetreconstruction_test.c @@ -3,6 +3,7 @@ #include #include #include +#include void printPseudoJet(const jetreconstruction_PseudoJet *jet) { assert(jet != NULL); @@ -50,6 +51,7 @@ void printJetsResult(const jetreconstruction_JetsResult *results) { } int main(int argc, char *argv[]) { + clock_t start_time = clock(); init_julia(argc, argv); size_t len = 2; jetreconstruction_PseudoJet particles[2]; @@ -72,5 +74,9 @@ int main(int argc, char *argv[]) { jetreconstruction_JetsResult_free_members(&result); jetreconstruction_ClusterSequence_free_members(&cluster_seq); shutdown_julia(0); + + clock_t end_time = clock(); + double time_spent = (double)(end_time - start_time) / CLOCKS_PER_SEC; + printf("Execution time: %f seconds\n", time_spent); return 0; } From dd5df397c9182a2947dda70d7178baf7ca55d403 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Thu, 14 Nov 2024 17:27:39 +0100 Subject: [PATCH 05/34] add precompile execution, remove precompile statements, use args for build script --- compile/Project.toml | 1 + compile/build.jl | 29 +++++++++++++++++------ compile/precompile_execution.jl | 40 ++++++++++++++++++++++++++++++++ compile/precompile_statements.jl | 1 - 4 files changed, 63 insertions(+), 8 deletions(-) delete mode 100644 compile/precompile_statements.jl diff --git a/compile/Project.toml b/compile/Project.toml index e93077e4..1cd28755 100644 --- a/compile/Project.toml +++ b/compile/Project.toml @@ -1,4 +1,5 @@ [deps] +ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63" JetReconstruction = "44e8cb2c-dfab-4825-9c70-d4808a591196" PackageCompiler = "9b87118b-4619-50d2-8e1e-99f35a4d4d9d" diff --git a/compile/build.jl b/compile/build.jl index 4508cf78..697723d5 100644 --- a/compile/build.jl +++ b/compile/build.jl @@ -1,16 +1,31 @@ using PackageCompiler +using ArgParse -output_directory = joinpath(splitdir(@__DIR__) |> first, "JetReconstructionCompiled") +s = ArgParseSettings() +@add_arg_table s begin + "--source-dir" + help = "Directory containing the source files" + arg_type = String + default = splitdir(@__DIR__) |> first -@info "Creating library in $output_directory" -PackageCompiler.create_library(".", output_directory; + "--output-dir" + help = "Directory to save the compiled library" + arg_type = String + default = joinpath(splitdir(@__DIR__) |> first, "JetReconstructionCompiled") +end + +parsed_args = parse_args(s) +source_dir = parsed_args["source-dir"] +output_dir = parsed_args["output-dir"] + +@info "Compiling package from $source_dir" +@info "Creating library in $output_dir" +PackageCompiler.create_library(source_dir, output_dir; lib_name = "jetreconstruction", header_files = [joinpath(@__DIR__, "include", "JetReconstruction.h")], - # precompile_execution_file = [joinpath(@__DIR__, - # "precompile_execution.jl")], - # precompile_statements_file = [jointpath(@__DIR__, - # "precompile_statements.jl")], + precompile_execution_file = [joinpath(@__DIR__, + "precompile_execution.jl")], incremental = false, filter_stdlibs = true, force = true) diff --git a/compile/precompile_execution.jl b/compile/precompile_execution.jl index 8b137891..e6ff2719 100644 --- a/compile/precompile_execution.jl +++ b/compile/precompile_execution.jl @@ -1 +1,41 @@ +using JetReconstruction +using JetReconstruction.C_JetReconstruction: jetreconstruction_PseudoJet_init, + C_ClusterSequence, + jetreconstruction_ClusterSequence_free_members_, + C_JetsResult, + jetreconstruction_JetsResult_free_members_, + jetreconstruction_jet_reconstruct, + jetreconstruction_inclusive_jets, + jetreconstruction_exclusive_jets_njets, + jetreconstruction_exclusive_jets_dcut + +pseudoJets_len = Csize_t(2) +pseudoJets_ptr = Ptr{PseudoJet}(Libc.malloc(pseudoJets_len * sizeof(PseudoJet))) + +jetreconstruction_PseudoJet_init(pseudoJets_ptr, 0.0, 1.0, 2.0, 3.0) +jetreconstruction_PseudoJet_init(pseudoJets_ptr + sizeof(PseudoJet), 1.0, 2.0, 3.0, 4.0) + +strategy = RecoStrategy.Best +algorithm = JetAlgorithm.CA +R = 2.0 + +clustersequence_ptr = Ptr{C_ClusterSequence{PseudoJet}}(Libc.malloc(sizeof(C_ClusterSequence{PseudoJet}))) +jetreconstruction_jet_reconstruct(pseudoJets_ptr, pseudoJets_len, algorithm, R, + RecoStrategy.Best, + clustersequence_ptr) + +results = C_JetsResult{PseudoJet}(C_NULL, 0) +results_ptr = Base.unsafe_convert(Ptr{C_JetsResult{PseudoJet}}, Ref(results)) +jetreconstruction_exclusive_jets_njets(clustersequence_ptr, Csize_t(2), results_ptr) +jetreconstruction_JetsResult_free_members_(results_ptr) + +jetreconstruction_exclusive_jets_dcut(clustersequence_ptr, 1.0, results_ptr) +jetreconstruction_JetsResult_free_members_(results_ptr) + +jetreconstruction_inclusive_jets(clustersequence_ptr, 0.0, results_ptr) +jetreconstruction_JetsResult_free_members_(results_ptr) + +jetreconstruction_ClusterSequence_free_members_(clustersequence_ptr) +Libc.free(pseudoJets_ptr) +Libc.free(clustersequence_ptr) diff --git a/compile/precompile_statements.jl b/compile/precompile_statements.jl deleted file mode 100644 index 8b137891..00000000 --- a/compile/precompile_statements.jl +++ /dev/null @@ -1 +0,0 @@ - From 0b902414ebffeca5adf48799be08827486bdbe72 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Fri, 15 Nov 2024 23:41:47 +0100 Subject: [PATCH 06/34] add cmake configuration --- compile/build.jl | 90 +++++++++++------ .../JetReconstructionConfig.cmake | 39 ++++++++ .../JetReconstructionConfigVersion.cmake.in | 65 +++++++++++++ .../JetReconstructionTargets.cmake | 96 +++++++++++++++++++ 4 files changed, 262 insertions(+), 28 deletions(-) create mode 100644 compile/cmake/JetReconstruction/JetReconstructionConfig.cmake create mode 100644 compile/cmake/JetReconstruction/JetReconstructionConfigVersion.cmake.in create mode 100644 compile/cmake/JetReconstruction/JetReconstructionTargets.cmake diff --git a/compile/build.jl b/compile/build.jl index 697723d5..aef2e425 100644 --- a/compile/build.jl +++ b/compile/build.jl @@ -1,31 +1,65 @@ using PackageCompiler -using ArgParse - -s = ArgParseSettings() -@add_arg_table s begin - "--source-dir" - help = "Directory containing the source files" - arg_type = String - default = splitdir(@__DIR__) |> first - - "--output-dir" - help = "Directory to save the compiled library" - arg_type = String - default = joinpath(splitdir(@__DIR__) |> first, "JetReconstructionCompiled") +import ArgParse +import JetReconstruction + +function parse_args(args) + s = ArgParse.ArgParseSettings() + ArgParse.@add_arg_table s begin + "--source-dir" + help = "Directory containing the source files" + arg_type = String + default = splitdir(@__DIR__) |> first + + "--output-dir", "-o" + help = "Directory to save the compiled library" + arg_type = String + default = joinpath(splitdir(@__DIR__) |> first, "JetReconstructionCompiled") + end + + return ArgParse.parse_args(args, s) +end + +function configure_file(template_path::String, output_path::String, + replacements::Dict{String, String}) + template = read(template_path, String) + for (key, value) in replacements + template = replace(template, "@$(key)@" => value) + end + open(output_path, "w") do io + write(io, template) + end end -parsed_args = parse_args(s) -source_dir = parsed_args["source-dir"] -output_dir = parsed_args["output-dir"] - -@info "Compiling package from $source_dir" -@info "Creating library in $output_dir" -PackageCompiler.create_library(source_dir, output_dir; - lib_name = "jetreconstruction", - header_files = [joinpath(@__DIR__, "include", - "JetReconstruction.h")], - precompile_execution_file = [joinpath(@__DIR__, - "precompile_execution.jl")], - incremental = false, - filter_stdlibs = true, - force = true) +function (@main)(args) + parsed_args = parse_args(args) + source_dir = parsed_args["source-dir"] + output_dir = parsed_args["output-dir"] + + @info "Compiling package from $source_dir" + @info "Creating library in $output_dir" + PackageCompiler.create_library(source_dir, output_dir; + lib_name = "jetreconstruction", + header_files = [joinpath(@__DIR__, "include", + "JetReconstruction.h")], + precompile_execution_file = [joinpath(@__DIR__, + "precompile_execution.jl")], + incremental = false, + filter_stdlibs = true, + force = true) + + cmake_input = joinpath(@__DIR__, "cmake", "JetReconstruction") + cmake_output = joinpath(output_dir, "lib", "cmake", "JetReconstruction") + + version = pkgversion(JetReconstruction) + cmake_project_version = "$(version.major).$(version.minor).$(version.patch)" + + @info "Copying CMake file to $cmake_output" + mkpath(cmake_output) + cp_file(input_dir, basename, output_dir) = cp(joinpath(input_dir, basename), + joinpath(output_dir, basename)) + cp_file(cmake_input, "JetReconstructionConfig.cmake", cmake_output) + cp_file(cmake_input, "JetReconstructionTargets.cmake", cmake_output) + configure_file(joinpath(cmake_input, "JetReconstructionConfigVersion.cmake.in"), + joinpath(cmake_output, "JetReconstructionConfigVersion.cmake"), + Dict("PROJECT_VERSION" => cmake_project_version)) +end \ No newline at end of file diff --git a/compile/cmake/JetReconstruction/JetReconstructionConfig.cmake b/compile/cmake/JetReconstruction/JetReconstructionConfig.cmake new file mode 100644 index 00000000..db499e6c --- /dev/null +++ b/compile/cmake/JetReconstruction/JetReconstructionConfig.cmake @@ -0,0 +1,39 @@ +# Config file for the JetReconstruction.jl package +# Manualy adjusted from standard cmake generated config file +get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) + +macro(set_and_check _var _file) + set(${_var} "${_file}") + if(NOT EXISTS "${_file}") + message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !") + endif() +endmacro() + +macro(check_required_components _NAME) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(NOT ${_NAME}_${comp}_FOUND) + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_NAME}_FOUND FALSE) + endif() + endif() + endforeach() +endmacro() + +#################################################################################### + +# - Create relocatable paths to headers. +# NOTE: Do not strictly need paths as all usage requirements are encoded in +# the imported targets created later. +set_and_check(JetReconstruction_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include") + +# - Create path to installed read-only data files (e.g. yaml files) +set_and_check(JetReconstruction_DATA_DIR "${PACKAGE_PREFIX_DIR}/share/julia") + +# - Include the targets file to create the imported targets that a client can +# link to (libraries) or execute (programs) +include("${CMAKE_CURRENT_LIST_DIR}/JetReconstructionTargets.cmake") + +# print the default "Found:" message and check library location +include(FindPackageHandleStandardArgs) +get_property(TEST_JETRECONSTRUCTION_LIBRARY TARGET JetReconstruction::JetReconstruction PROPERTY LOCATION) +find_package_handle_standard_args(JetReconstruction DEFAULT_MSG CMAKE_CURRENT_LIST_FILE TEST_JETRECONSTRUCTION_LIBRARY) diff --git a/compile/cmake/JetReconstruction/JetReconstructionConfigVersion.cmake.in b/compile/cmake/JetReconstruction/JetReconstructionConfigVersion.cmake.in new file mode 100644 index 00000000..c6966692 --- /dev/null +++ b/compile/cmake/JetReconstruction/JetReconstructionConfigVersion.cmake.in @@ -0,0 +1,65 @@ +# This is a basic version file for the Config-mode of find_package(). +# It is used by write_basic_package_version_file() as input file for configure_file() +# to create a version-file which can be installed along a config.cmake file. +# +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version, +# but only if the requested major version is the same as the current one. +# The variable CVF_VERSION must be set before calling configure_file(). + + +set(PACKAGE_VERSION "@PROJECT_VERSION@") + +if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + + if(PACKAGE_VERSION MATCHES "^([0-9]+)\\.") + set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}") + if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0) + string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}") + endif() + else() + set(CVF_VERSION_MAJOR ${PACKAGE_VERSION}) + endif() + + if(PACKAGE_FIND_VERSION_RANGE) + # both endpoints of the range must have the expected major version + math (EXPR CVF_VERSION_MAJOR_NEXT "${CVF_VERSION_MAJOR} + 1") + if (NOT PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR + OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL CVF_VERSION_MAJOR_NEXT))) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR + AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX))) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + else() + if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() + endif() +endif() + + +# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8") + math(EXPR installedBits "8 * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/compile/cmake/JetReconstruction/JetReconstructionTargets.cmake b/compile/cmake/JetReconstruction/JetReconstructionTargets.cmake new file mode 100644 index 00000000..7d548f25 --- /dev/null +++ b/compile/cmake/JetReconstruction/JetReconstructionTargets.cmake @@ -0,0 +1,96 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "3.0.0") + message(FATAL_ERROR "CMake >= 3.0.0 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 3.0.0...3.28) + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS JetReconstruction::JetReconstruction) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target JetReconstruction::JetReconstruction +add_library(JetReconstruction::JetReconstruction SHARED IMPORTED) +set_target_properties(JetReconstruction::JetReconstruction PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" + IMPORTED_LOCATION "${_IMPORT_PREFIX}/lib/libjetreconstruction.so" + IMPORTED_SONAME "libjetreconstruction.so" +) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + if(CMAKE_VERSION VERSION_LESS "3.28" + OR NOT DEFINED _cmake_import_check_xcframework_for_${_cmake_target} + OR NOT IS_DIRECTORY "${_cmake_import_check_xcframework_for_${_cmake_target}}") + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + endif() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) From 484ac868a037da4751d7486950d1880ad4a12868 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Mon, 18 Nov 2024 09:03:31 +0100 Subject: [PATCH 07/34] fix format --- compile/build.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compile/build.jl b/compile/build.jl index aef2e425..717d7530 100644 --- a/compile/build.jl +++ b/compile/build.jl @@ -62,4 +62,4 @@ function (@main)(args) configure_file(joinpath(cmake_input, "JetReconstructionConfigVersion.cmake.in"), joinpath(cmake_output, "JetReconstructionConfigVersion.cmake"), Dict("PROJECT_VERSION" => cmake_project_version)) -end \ No newline at end of file +end From 34c2ba1d5cd6884a8f3e30f0d6a804fc8577e54a Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Mon, 18 Nov 2024 16:16:18 +0100 Subject: [PATCH 08/34] add example cmake downstream, add comments --- compile/README.md | 18 +++++ compile/downstream/CMakeLists.txt | 15 ++++ compile/downstream/README.md | 3 + compile/downstream/jetreconstruction_test.c | 82 +++++++++++++++++++++ compile/precompile_execution.jl | 2 + 5 files changed, 120 insertions(+) create mode 100644 compile/downstream/CMakeLists.txt create mode 100644 compile/downstream/README.md create mode 100644 compile/downstream/jetreconstruction_test.c diff --git a/compile/README.md b/compile/README.md index 838e3f15..c49f4c1b 100644 --- a/compile/README.md +++ b/compile/README.md @@ -63,3 +63,21 @@ In case the compiled library resides in non-standard location, add its location LD_LIBRARY_PATH=JetReconstructionCompiled/lib/:${LD_LIBRARY_PATH} ./jetreconstruction_test ``` +### Compilation with CMake + +The JetReconstruction library comes with a CMake target `JetReconstruction::JetReconstruction`. Example usage in CMake file: + +```cmake +find_package(JetReconstruction REQUIRED) + +target_link_libraries(myTarget PUBLIC JetReconstruction::JetReconstruction) +``` + +## Limitations + +Currently it's not possible to create libraries for different platforms - no cross-compilation! + +The library is relocatable given the whole installation tree is moved, including libraries in the `lib/julia/` directory. + +It's advised to install the library in a separate directory to avoid possible conflicts. +The library must not be installed in the same directory as another Julia package compiled with `PackageCompiler.jl` as they would overwrite the package specific files in `share/julia`. diff --git a/compile/downstream/CMakeLists.txt b/compile/downstream/CMakeLists.txt new file mode 100644 index 00000000..32ea65ed --- /dev/null +++ b/compile/downstream/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.12) + +project( + JetReconstruction_downstream + LANGUAGES C + VERSION 0.1.0) + +find_package(JetReconstruction 0.4.3 REQUIRED) + +add_executable(jetreconstruction_test jetreconstruction_test.c) +target_link_libraries(jetreconstruction_test + PUBLIC JetReconstruction::JetReconstruction) + +enable_testing() +add_test(NAME JetReconstructionTest COMMAND jetreconstruction_test) diff --git a/compile/downstream/README.md b/compile/downstream/README.md new file mode 100644 index 00000000..9e29950c --- /dev/null +++ b/compile/downstream/README.md @@ -0,0 +1,3 @@ +# Downstream project example + +Example downstream project using C-bindings of JetReconstruction.jl diff --git a/compile/downstream/jetreconstruction_test.c b/compile/downstream/jetreconstruction_test.c new file mode 100644 index 00000000..829e7f4d --- /dev/null +++ b/compile/downstream/jetreconstruction_test.c @@ -0,0 +1,82 @@ +#include "JetReconstruction.h" +#include "julia_init.h" +#include +#include +#include +#include + +void printPseudoJet(const jetreconstruction_PseudoJet *jet) { + assert(jet != NULL); + printf("PseudoJet(%f %f %f %f %ld %f %f %f %f)\n", jet->px, jet->py, jet->pz, + jet->E, jet->_cluster_hist_index, jet->_pt2, jet->_inv_pt2, jet->_rap, + jet->_phi); +} + +void printHistoryElement(const jetreconstruction_HistoryElement *history) { + assert(history != NULL); + printf("HistoryElement(%ld %ld %ld %ld %lf %lf)\n", history->parent1, + history->parent2, history->child, history->jetp_index, history->dij, + history->max_dij_so_far); +} + +void printClusterSequence(const jetreconstruction_ClusterSequence *sequence) { + printf("Cluster Sequence Information:\n" + "Algorithm: %d\n" + "Power: %f\n" + "R parameter: %f\n" + "Strategy: %d\n" + "Initial number of jets: %ld\n" + "Total event energy (Qtot): %f\n", + sequence->algorithm, sequence->power, sequence->R, sequence->strategy, + sequence->n_initial_jets, sequence->Qtot); + printf("Number of jets: %zu\n", sequence->jets_length); + if (sequence->jets != NULL) { + for (size_t i = 0; i < sequence->jets_length; i++) { + printPseudoJet(sequence->jets + i); + } + } + printf("History length: %zu\n", sequence->history_length); + if (sequence->history != NULL) { + for (size_t i = 0; i < sequence->history_length; i++) { + printHistoryElement(sequence->history + i); + } + } +} + +void printJetsResult(const jetreconstruction_JetsResult *results) { + assert(results != NULL); + for (size_t i = 0; i < results->length; ++i) { + printPseudoJet(results->data + i); + } +} + +int main(int argc, char *argv[]) { + clock_t start_time = clock(); + init_julia(argc, argv); + size_t len = 2; + jetreconstruction_PseudoJet particles[2]; + jetreconstruction_PseudoJet_init(&particles[0], 0.0, 1.0, 2.0, 3.0); + jetreconstruction_PseudoJet_init(&particles[1], 1.0, 2.0, 3.0, 4.0); + + jetreconstruction_JetAlgorithm algorithm = JETRECONSTRUCTION_JETALGORITHM_CA; + double R = 3.0; + jetreconstruction_RecoStrategy strategy = JETRECONSTRUCTION_RECOSTRATEGY_BEST; + + jetreconstruction_ClusterSequence cluster_seq; + jetreconstruction_jet_reconstruct(particles, len, algorithm, R, strategy, + &cluster_seq); + + printClusterSequence(&cluster_seq); + jetreconstruction_JetsResult result; + jetreconstruction_exclusive_jets_njets(&cluster_seq, 2, &result); + printJetsResult(&result); + + jetreconstruction_JetsResult_free_members(&result); + jetreconstruction_ClusterSequence_free_members(&cluster_seq); + shutdown_julia(0); + + clock_t end_time = clock(); + double time_spent = (double)(end_time - start_time) / CLOCKS_PER_SEC; + printf("Execution time: %f seconds\n", time_spent); + return 0; +} diff --git a/compile/precompile_execution.jl b/compile/precompile_execution.jl index e6ff2719..8204cdb0 100644 --- a/compile/precompile_execution.jl +++ b/compile/precompile_execution.jl @@ -1,3 +1,5 @@ +# Dummy code to call and cache compilation of all C-bindings +# The numeric values doesn't make sense and are used only to select correct dispatch using JetReconstruction using JetReconstruction.C_JetReconstruction: jetreconstruction_PseudoJet_init, From f7b4029a78341c0da2a0f540a1900296cba937f3 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Tue, 19 Nov 2024 17:40:47 +0100 Subject: [PATCH 09/34] update docstrings --- compile/include/JetReconstruction.h | 278 +++++++++++++----- .../C_JetReconstruction.jl | 218 +++++++++++++- 2 files changed, 426 insertions(+), 70 deletions(-) diff --git a/compile/include/JetReconstruction.h b/compile/include/JetReconstruction.h index f21703e9..2331d6ed 100644 --- a/compile/include/JetReconstruction.h +++ b/compile/include/JetReconstruction.h @@ -3,111 +3,157 @@ * SPDX-License-Identifier: MIT */ +/** + * @file JetReconstruction.h + * @brief Header file for the C-bindings of JetReconstruction.jl. + * + * This file contains the definitions of data structures and functions used in + * JetReconstruction.jl. The library provides functionality for efficient jet + * reconstruction. + */ + #include /*Special states in a history.*/ + +/**Special history state: Invalid child for this jet, meaning it did not + * recombine further */ #define JETRECONSTRUCTION_INVALID -3 +/**Special history state: Original cluster so it has no parent */ #define JETRECONSTRUCTION_NONEXISTENTPARENT -2 +/**Special history state: Cluster recombined with beam" */ #define JETRECONSTRUCTION_BEAMJET -1 -/* -Enumeration representing different jet algorithms used in -the JetReconstruction module. -*/ +/** + * @enum jetreconstruction_JetAlgorithm + * @brief Enumeration representing different jet algorithms used in + * the JetReconstruction. + */ typedef enum { - JETRECONSTRUCTION_JETALGORITHM_ANTIKT = 0, /* The Anti-Kt algorithm. */ - JETRECONSTRUCTION_JETALGORITHM_CA = 1, /* The Cambridge/Aachen algorithm. */ - JETRECONSTRUCTION_JETALGORITHM_KT = 2, /* The Inclusive-Kt algorithm. */ + JETRECONSTRUCTION_JETALGORITHM_ANTIKT = 0, /**< The Anti-Kt algorithm. */ + JETRECONSTRUCTION_JETALGORITHM_CA = 1, /**< The Cambridge/Aachen algorithm. */ + JETRECONSTRUCTION_JETALGORITHM_KT = 2, /**< The Inclusive-Kt algorithm. */ JETRECONSTRUCTION_JETALGORITHM_GENKT = - 3, /* The Generalised Kt algorithm (with arbitrary power). */ + 3, /**< The Generalised Kt algorithm (with arbitrary power). */ JETRECONSTRUCTION_JETALGORITHM_EEKT = - 4, /* The Generalised e+e- kt algorithm. */ + 4, /**< The Generalised e+e- kt algorithm. */ JETRECONSTRUCTION_JETALGORITHM_DURHAM = - 5 /* The e+e- kt algorithm, aka Durham. */ + 5 /**< The e+e- kt algorithm, aka Durham. */ } jetreconstruction_JetAlgorithm; -/* -Scoped enumeration (using EnumX) representing the different strategies for jet -reconstruction. -*/ +/** + * @enum jetreconstruction_RecoStrategy + * @brief Enumeration representing the different strategies for jet + * reconstruction. + */ typedef enum { - JETRECONSTRUCTION_RECOSTRATEGY_BEST = 0, /* The best strategy. */ - JETRECONSTRUCTION_RECOSTRATEGY_N2PLAIN = 1, /* The plain N2 strategy. */ - JETRECONSTRUCTION_RECOSTRATEGY_N2TILTED = 2 /* The tiled N2 strategy. */ + JETRECONSTRUCTION_RECOSTRATEGY_BEST = 0, /**< The best strategy. */ + JETRECONSTRUCTION_RECOSTRATEGY_N2PLAIN = 1, /**< The plain N2 strategy. */ + JETRECONSTRUCTION_RECOSTRATEGY_N2TILTED = 2 /**< The tiled N2 strategy. */ } jetreconstruction_RecoStrategy; -/* The `PseudoJet` struct represents a pseudojet, a four-momentum object used in -jet reconstruction algorithms. Additional information for the link back into the -history of the clustering is stored in the `_cluster_hist_index` field. There is -caching of the more expensive calculations for rapidity and azimuthal angle.*/ +/** + * @struct jetreconstruction_PseudoJet + * @brief A struct representing a pseudojet, a four-momentum object used in + * jet reconstruction algorithms. Additional information for the link back into + * the history of the clustering is stored in the _cluster_hist_index field. + * There is caching of the more expensive calculations for rapidity and + * azimuthal angle. + */ typedef struct { - double px; /* The x-component of the momentum. */ - double py; /* The y-component of the momentum. */ - double pz; /* The z-component of the momentum. */ - double E; /* The energy component of the momentum. */ - long _cluster_hist_index; /* The index of the cluster history. */ - double _pt2; /* The squared transverse momentum. */ - double _inv_pt2; /* The inverse squared transverse momentum. */ - double _rap; /* The rapidity. */ - double _phi; /* The azimuthal angle. */ + double px; /**< The x-component of the momentum. */ + double py; /**< The y-component of the momentum. */ + double pz; /**< The z-component of the momentum. */ + double E; /**< The energy component of the momentum. */ + long _cluster_hist_index; /**< The index of the cluster history. */ + double _pt2; /**< The squared transverse momentum. */ + double _inv_pt2; /**< The inverse squared transverse momentum. */ + double _rap; /**< The rapidity. */ + double _phi; /**< The azimuthal angle. */ } jetreconstruction_PseudoJet; +/** + * @brief Initializes a jetreconstruction_PseudoJet object with given momentum. + * + * @param[in] ptr Pointer to the jetreconstruction_PseudoJet object to be + * initialized. + * @param[in] px The x-component of the momentum. + * @param[in] py The y-component of the momentum. + * @param[in] pz The z-component of the momentum. + * @param[in] E The energy component of the momentum. + * @return An integer status code indicating the success or failure. + */ int jetreconstruction_PseudoJet_init(jetreconstruction_PseudoJet *ptr, double px, double py, double pz, double E); -/* -A struct holding a record of jet mergers and finalisations -*/ + +/** + * @struct jetreconstruction_HistoryElement + * @brief A struct holding a record of jet mergers and finalisations. + */ typedef struct { - long parent1; /* Index in history where first parent of this jet was - created (NonexistentParent if this jet is an original - particle) */ - long parent2; /* Index in history where second parent of this jet was - created (NonexistentParent if this jet is an original - particle); BeamJet if this history entry just labels the - fact that the jet has recombined with the beam */ - long child; /* Index in history where the current jet is recombined with - another jet to form its child. It is Invalid - if this jet does not further recombine. */ - long jetp_index; /* Index in the jets vector where we will find the + long parent1; /**< Index in history where first parent of this jet was + created (@ref JETRECONSTRUCTION_NONEXISTENTPARENT if this jet is + an original particle) */ + long parent2; /**< Index in history where second parent of this jet was + created (@ref JETRECONSTRUCTION_NONEXISTENTPARENT if this jet is + an original particle); @ref JETRECONSTRUCTION_BEAMJET if this + history entry just labels the fact that the jet has + recombined with the beam */ + long child; /**< Index in history where the current jet is recombined with + another jet to form its child. It is Invalid + if this jet does not further recombine. */ + long jetp_index; /**< Index in the jets vector where we will find the PseudoJet object corresponding to this jet (i.e. the jet created at this entry of the history). NB: if this element of the history corresponds to a beam - recombination, then `jetp_index=Invalid`. */ - double dij; /* The distance corresponding to the recombination at this - stage of the clustering. */ - double max_dij_so_far; /* The largest recombination distance seen so far + recombination, then @p jetp_index = @ref JETRECONSTRUCTION_INVALID. + */ + double dij; /**< The distance corresponding to the recombination at this + stage of the clustering. */ + double max_dij_so_far; /**< The largest recombination distance seen so far in the clustering history */ } jetreconstruction_HistoryElement; -/* -A struct holding the full history of a jet clustering sequence, including the -final jets. -*/ +/** + * @struct jetreconstruction_ClusterSequence + * @brief A struct holding the full history of a jet clustering sequence, + * including the final jets. + */ typedef struct { jetreconstruction_JetAlgorithm - algorithm; /* The algorithm used for clustering. */ - double power; /* The power value used for the clustering algorithm (note that - this value is always stored as a Float64 to be - type stable) */ - double R; /* The R parameter used for the clustering algorithm. */ + algorithm; /**< The algorithm used for clustering. */ + double power; /**< The power value used for the clustering algorithm */ + double R; /**< The R parameter used for the clustering algorithm. */ jetreconstruction_RecoStrategy - strategy; /* The strategy used for clustering. */ + strategy; /**< The strategy used for clustering. */ jetreconstruction_PseudoJet - *jets; /* The actual jets in the cluster sequence, which are of type `T - <: FourMomentum`. */ - size_t jets_length; /* Length of jets. */ - long n_initial_jets; /* The initial number of particles used for exclusive + *jets; /**< A pointer to an array of jetreconstruction_PseudoJet + containing the actual jets in the cluster sequence. */ + size_t jets_length; /**< The length of @ref jets array. */ + long n_initial_jets; /**< The initial number of particles used for exclusive jets. */ jetreconstruction_HistoryElement - *history; /* The branching history of the cluster sequence. Each - stage in the history indicates where to look in the - jets vector to get the physical PseudoJet. */ - size_t history_length; /* Length of history. */ - double Qtot; /* The total energy of the event. */ + *history; /**< A pointer to an array of jetreconstruction_HistoryElement + containing the branching history of the cluster sequence. + Each stage in the history indicates where to look in the jets + vector to get the physical PseudoJet. */ + size_t history_length; /**< The length of @ref history array. */ + double Qtot; /**< The total energy of the event. */ } jetreconstruction_ClusterSequence; +/** @private */ void jetreconstruction_ClusterSequence_free_members_( jetreconstruction_ClusterSequence *ptr); + +/** + * @brief Frees the members of a jetreconstruction_ClusterSequence structure. + * + * This function releases any resources held by the members of the given + * jetreconstruction_ClusterSequence structure. + * + * @param[in,out] ptr Pointer to the jetreconstruction_ClusterSequence + * structure. + */ static inline void jetreconstruction_ClusterSequence_free_members( jetreconstruction_ClusterSequence *ptr) { jetreconstruction_ClusterSequence_free_members_(ptr); @@ -117,19 +163,54 @@ static inline void jetreconstruction_ClusterSequence_free_members( ptr->history_length = 0; } +/** + * @brief Reconstructs jets from a collection of particles using a specified + * algorithm and strategy. + * + * This function reconstructs jets from a collection of particles using a + * specified algorithm and strategy. + * + * @note The memory allocated for members of @p result must be freed using + * the @ref jetreconstruction_ClusterSequence_free_members function after the + * @p result is no longer needed to prevent memory leaks. + * + * @param[in] particles Pointer to an array of pseudojet objects used for jet + * reconstruction. + * @param[in] particles_length The length of @p particles array. + * @param[in] algorithm The algorithm to use for jet reconstruction. + * @param[in] R The jet radius parameter. + * @param[in] strategy The jet reconstruction strategy to use. + * @param[out] result A pointer to which a cluster sequence containing the + * reconstructed jets and the merging history will be stored. + * @return An integer status code indicating the success or failure. + */ int jetreconstruction_jet_reconstruct( const jetreconstruction_PseudoJet *particles, size_t particles_length, jetreconstruction_JetAlgorithm algorithm, double R, jetreconstruction_RecoStrategy strategy, jetreconstruction_ClusterSequence *result); +/** + * @struct jetreconstruction_JetsResult + * @brief A structure to hold the inclusive or exclusive jets. + */ typedef struct { - jetreconstruction_PseudoJet *data; - size_t length; + jetreconstruction_PseudoJet *data; /**< Pointer to an array of jetreconstruction_PseudoJet. */ + size_t length; /**< The length of the @ref data array. */ } jetreconstruction_JetsResult; +/** @private */ void jetreconstruction_JetsResult_free_members_( jetreconstruction_JetsResult *ptr); + +/** + * @brief Frees the members of a jetreconstruction_JetsResult structure. + * + * This function releases any resources held by the members of the given + * jetreconstruction_JetsResult structure. + * + * @param[in,out] ptr A pointer to the jetreconstruction_JetsResult structure. + */ static inline void jetreconstruction_JetsResult_free_members(jetreconstruction_JetsResult *ptr) { jetreconstruction_JetsResult_free_members_(ptr); @@ -137,14 +218,73 @@ jetreconstruction_JetsResult_free_members(jetreconstruction_JetsResult *ptr) { ptr->length = 0; } +/** + * @brief Return all exclusive jets of a jetreconstruction_ClusterSequence with + * a cut on the maximum distance parameter. + * + * This function computes the exclusive jets from a given + * jetreconstruction_ClusterSequence with a cut on the maximum distance + * parameter. + * + * @note The memory allocated for members of @p result must be freed using + * the @ref jetreconstruction_JetsResult_free_members function after the + * @p result is no longer needed to prevent memory leaks. + * + * @param[in] clustersequence A pointer to the jetreconstruction_ClusterSequence + * object containing the clustering history and jets. + * @param[in] dcut The distance parameter used to define the exclusive jets. + * @param[out] result A pointer to the jetreconstruction_JetsResult object where + * the resulting jets will be stored. + * @return An integer status code indicating the success or failure. + */ int jetreconstruction_exclusive_jets_dcut( const jetreconstruction_ClusterSequence *clustersequence, double dcut, jetreconstruction_JetsResult *result); +/** + * @brief Return all exclusive jets of a jetreconstruction_ClusterSequence with + * a specific number of jets. + * + * This function computes a specific number of exclusive jets from a given + * jetreconstruction_ClusterSequence. + * + * @note The memory allocated for members of @p result must be freed using + * the @ref jetreconstruction_JetsResult_free_members function after the + * @p result is no longer needed to prevent memory leaks. + * + * @param[in] clustersequence A pointer to the jetreconstruction_ClusterSequence + * object containing the clustering history and jets. + * @param[in] njets The number of exclusive jets to be calculated. + * @param[out] result A pointer to the jetreconstruction_JetsResult object where + * the resulting jets will be stored. + * @return An integer status code indicating the success or failure. + */ int jetreconstruction_exclusive_jets_njets( const jetreconstruction_ClusterSequence *clustersequence, size_t njets, jetreconstruction_JetsResult *result); +/** + * @brief Return all inclusive jets of a jetreconstruction_ClusterSequence with + * pt > @p ptmin. + * + * This function computes the inclusive jets from a given + * jetreconstruction_ClusterSequence. It iterates over the clustering history + * and checks the transverse momentum of each parent jet. If the transverse + * momentum is greater than or equal to @p ptmin, the jet is added to results + * structure. + * + * @note The memory allocated for members of @p result must be freed using + * the @ref jetreconstruction_JetsResult_free_members function after the + * @p result is no longer needed to prevent memory leaks. + * + * @param[in] clustersequence A pointer to the jetreconstruction_ClusterSequence + * object containing the clustering history and jets. + * @param[in] ptmin The minimum transverse momentum (pt) threshold for the + * inclusive jets. + * @param[out] result A pointer to the jetreconstruction_JetsResult object where + * the resulting jets will be stored. + * @return An integer status code indicating the success or failure. + */ int jetreconstruction_inclusive_jets( const jetreconstruction_ClusterSequence *clustersequence, double ptmin, jetreconstruction_JetsResult *result); diff --git a/src/C_JetReconstruction/C_JetReconstruction.jl b/src/C_JetReconstruction/C_JetReconstruction.jl index 08962c23..e42962a3 100644 --- a/src/C_JetReconstruction/C_JetReconstruction.jl +++ b/src/C_JetReconstruction/C_JetReconstruction.jl @@ -23,7 +23,6 @@ Wraps a C array into a Julia `Vector` for both bits and non-bits types. This function use 'unsafe' methods and has undefined behaviour if pointer isn't valid or length isn't correct. """ - function unsafe_wrap_c_array(ptr::Ptr{T}, array_length::Csize_t) where {T} if isbitstype(T) return unsafe_wrap(Vector{T}, ptr, array_length) @@ -67,6 +66,22 @@ function make_c_array(v::Vector{T}) where {T} return ptr, len end +""" + jetreconstruction_PseudoJet_init(ptr::Ptr{PseudoJet}, px::Cdouble, py::Cdouble, pz::Cdouble, E::Cdouble) -> Cint + +C-binding for `PseudoJet` initialization. + +# Arguments +- `ptr::Ptr{PseudoJet}`: A pointer to the memory location where the `PseudoJet` object will be stored. +- `px::Cdouble`: The x-component of the momentum. +- `py::Cdouble`: The y-component of the momentum. +- `pz::Cdouble`: The z-component of the momentum. +- `E::Cdouble`: The energy of the jet. + +# Returns +- `Cint`: An integer status code indicating the success or failure. + +""" Base.@ccallable function jetreconstruction_PseudoJet_init(ptr::Ptr{PseudoJet}, px::Cdouble, py::Cdouble, pz::Cdouble, E::Cdouble)::Cint @@ -75,6 +90,11 @@ Base.@ccallable function jetreconstruction_PseudoJet_init(ptr::Ptr{PseudoJet}, p return 0 end +""" + struct C_ClusterSequence{T} + +A C-compatible struct corresponding to `ClusterSequence` +""" struct C_ClusterSequence{T} algorithm::JetAlgorithm.Algorithm power::Cdouble @@ -88,6 +108,14 @@ struct C_ClusterSequence{T} Qtot::Cdouble end +""" + free_members(ptr::Ptr{C_ClusterSequence{T}}) where {T} + +Internal function for freeing dynamically allocated `C_ClusterSequence` members memory. + +# Arguments +- `ptr::Ptr{C_ClusterSequence{T}}`: A pointer to a `C_ClusterSequence` structure. +""" function free_members(ptr::Ptr{C_ClusterSequence{T}}) where {T} if ptr != C_NULL clusterseq = unsafe_load(ptr) @@ -96,11 +124,39 @@ function free_members(ptr::Ptr{C_ClusterSequence{T}}) where {T} # Struct is immutable so pointers can't be assigned NULL and lengths updated to zero (without making a copy) end end + +""" + jetreconstruction_ClusterSequence_free_members_(ptr::Ptr{C_ClusterSequence{PseudoJet}}) -> Cvoid + +C-binding for freeing the members of a `C_ClusterSequence` object pointed to by `ptr`. + +# Arguments +- `ptr::Ptr{C_ClusterSequence{PseudoJet}}`: A pointer to the `C_ClusterSequence` object whose members are to be freed. + +# Returns +- `Cvoid`: This function does not return a value. +""" Base.@ccallable function jetreconstruction_ClusterSequence_free_members_(ptr::Ptr{C_ClusterSequence{PseudoJet}})::Cvoid free_members(ptr) return nothing end +""" + ClusterSequence(c::C_ClusterSequence{T}) where {T} + +Convert a `C_ClusterSequence` object to a `ClusterSequence` object. + + +# Arguments +- `c::C_ClusterSequence{T}`: The `C_ClusterSequence` object to be converted. + +# Returns +- `ClusterSequence{T}`: The converted `ClusterSequence` object. + +# Notes +- The array members of output are wrapping the array members of input. +- The input object must remain valid while the output object is used. +""" function ClusterSequence{T}(c::C_ClusterSequence{T}) where {T} jets_v = unsafe_wrap_c_array(c.jets, c.jets_length) history_v = unsafe_wrap_c_array(c.history, c.history_length) @@ -109,6 +165,21 @@ function ClusterSequence{T}(c::C_ClusterSequence{T}) where {T} history_v, c.Qtot) end +""" + C_ClusterSequence(clustersequence::ClusterSequence{T}) where {T} + +Convert a `ClusterSequence` object to a `C_ClusterSequence` object. + +# Arguments +- `clustersequence::ClusterSequence{T}`: The `ClusterSequence` object to be converted. + +# Returns +- `C_ClusterSequence{T}`: The converted `C_ClusterSequence` object. + +# Notes +- The array members of input are deep-copied to output object, it's safe to use output even if input doesn't exist anymore. +- The memory allocated for output data-object members should be freed with the `free_members` function or equivalent. +""" function C_ClusterSequence{T}(clustersequence::ClusterSequence{T}) where {T} jets_ptr, jets_length = make_c_array(clustersequence.jets) history_ptr, history_length = make_c_array(clustersequence.history) @@ -118,6 +189,30 @@ function C_ClusterSequence{T}(clustersequence::ClusterSequence{T}) where {T} history_length, clustersequence.Qtot) end +""" + c_jet_reconstruct(particles::Ptr{T}, + particles_length::Csize_t, + algorithm::JetAlgorithm.Algorithm, + R::Cdouble, + strategy::RecoStrategy.Strategy, + result::Ptr{C_ClusterSequence{U}})::Cint where {T, U} + +Internal helper functions for calling `jet_reconstruct` with C-compatible data-structers. + +# Arguments +- `particles::Ptr{T}`: Pointer to an array of pseudojet objects used for jet reconstruction. +- `particles_length::Csize_t`: The length of `particles`` array. +- `algorithm::JetAlgorithm.Algorithm`: The algorithm to use for jet reconstruction. +- `R::Cdouble`: The jet radius parameter.. +- `strategy::RecoStrategy.Strategy`: The jet reconstruction strategy to use. +- `result::Ptr{C_ClusterSequence{U}}`: A pointer to which a cluster sequence containing the reconstructed jets and the merging history will be stored. + +# Returns +- `Cint`: An integer status code indicating the success or failure. + +# Notes +- To avoid memory leaks the memory allocated for members of `result` should be freed with `free_members` function or equivalent. +""" function c_jet_reconstruct(particles::Ptr{T}, particles_length::Csize_t, algorithm::JetAlgorithm.Algorithm, @@ -132,6 +227,30 @@ function c_jet_reconstruct(particles::Ptr{T}, return 0 end +""" + jetreconstruction_jet_reconstruct(particles::Ptr{PseudoJet}, + particles_length::Csize_t, + algorithm::JetAlgorithm.Algorithm, + R::Cdouble, + strategy::RecoStrategy.Strategy, + result::Ptr{C_ClusterSequence{PseudoJet}})::Cint + +C-binding for `jet_reconstruct`. + +# Arguments +- `particles::Ptr{PseudoJet}`: Pointer to an array of pseudojet objects used for jet reconstruction. +- `particles_length::Csize_t`: The length of `particles`` array. +- `algorithm::JetAlgorithm.Algorithm`: The algorithm to use for jet reconstruction. +- `R::Cdouble`: The jet radius parameter.. +- `strategy::RecoStrategy.Strategy`: The jet reconstruction strategy to use. +- `result::Ptr{C_ClusterSequence{PseudoJet}}`: A pointer to which a cluster sequence containing the reconstructed jets and the merging history will be stored. + +# Returns +- `Cint`: An integer status code indicating the success or failure. + +# Notes +- To avoid memory leaks the memory allocated for members of `result` should be freed with `jetreconstruction_ClusterSequence_free_members_`. +""" Base.@ccallable function jetreconstruction_jet_reconstruct(particles::Ptr{PseudoJet}, particles_length::Csize_t, algorithm::JetAlgorithm.Algorithm, @@ -142,11 +261,28 @@ Base.@ccallable function jetreconstruction_jet_reconstruct(particles::Ptr{Pseudo return 0 end +""" + struct C_JetsResult{T} + +A C-compatible wrapper for array-like data + +# Fields +- `data::Ptr{T}`: A pointer to the data of type `T`. +- `length::Csize_t`: The length of the data. +""" struct C_JetsResult{T} data::Ptr{T} length::Csize_t end +""" + free_members(ptr::Ptr{C_JetsResult{T}}) where {T} + +Internal function for freeing dynamically allocated `C_JetsResult` members memory. + +# Arguments +- `ptr::Ptr{C_JetsResult{T}}`: A pointer to a `C_JetsResult` structure. +""" function free_members(ptr::Ptr{C_JetsResult{T}}) where {T} if ptr != C_NULL result = unsafe_load(ptr) @@ -155,11 +291,37 @@ function free_members(ptr::Ptr{C_JetsResult{T}}) where {T} end end +""" + jetreconstruction_JetsResult_free_members_(ptr::Ptr{C_JetsResult{PseudoJet}})::Cvoid + +C-binding for freeing the members of a `C_JetsResult{PseudoJet}` object pointed to by `ptr`. + +# Arguments +- `ptr::Ptr{C_JetsResult{PseudoJet}}`: A pointer to the `C_JetsResult{PseudoJet}` structure whose members are to be freed. + +# Returns +- `Cvoid`: This function does not return any value. +""" Base.@ccallable function jetreconstruction_JetsResult_free_members_(ptr::Ptr{C_JetsResult{PseudoJet}})::Cvoid free_members(ptr) return nothing end +""" + jets_selection(selector, clustersequence::Ptr{C_ClusterSequence{T}}, + result::Ptr{C_JetsResult{U}}; kwargs...)::Cint where {T, U} + +An internal helper function for calling calling functions selecting jets from a given cluster sequence. + +# Arguments +- `selector`: A function that takes a `ClusterSequence{T}` and returns a list of jets. +- `clustersequence::Ptr{C_ClusterSequence{T}}`: A pointer to a C-compatible cluster sequence. +- `result::Ptr{C_JetsResult{U}}`: A pointer to a C-compatible structure where the result will be stored. +- `kwargs...`: Additional keyword arguments to be passed to the selector function. + +# Returns +- `Cint`: An integer status code indicating the success or failure. +""" function jets_selection(selector, clustersequence::Ptr{C_ClusterSequence{T}}, result::Ptr{C_JetsResult{U}}; kwargs...)::Cint where {T, U} c_clusterseq = unsafe_load(clustersequence) @@ -170,18 +332,72 @@ function jets_selection(selector, clustersequence::Ptr{C_ClusterSequence{T}}, return 0 end +""" + jetreconstruction_exclusive_jets_dcut(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, + dcut::Cdouble, + result::Ptr{C_JetsResult{PseudoJet}}) -> Cint + +C-binding for `exclusive_jets` with a cut on the maximum distance parameter. + +# Arguments +- `clustersequence::Ptr{C_ClusterSequence{PseudoJet}}`: A pointer to the cluster sequence object containing the clustering history and jets. +- `dcut::Cdouble`: The distance parameter used to define the exclusive jets. +- `result::Ptr{C_JetsResult{PseudoJet}}`: A pointer to the results. + +# Returns +- `Cint`: An integer status code indicating the success or failure. + +# Notes +- To avoid memory leaks the memory allocated for members of `result` should be freed with `jetreconstruction_JetsResult_free_members_`. +""" Base.@ccallable function jetreconstruction_exclusive_jets_dcut(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, dcut::Cdouble, result::Ptr{C_JetsResult{PseudoJet}})::Cint return jets_selection(exclusive_jets, clustersequence, result; dcut = dcut) end +""" + jetreconstruction_exclusive_jets_njets(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, + njets::Csize_t, + result::Ptr{C_JetsResult{PseudoJet}}) -> Cint + +C-binding for `exclusive_jets` with a specific number of jets. + +# Arguments +- `clustersequence::Ptr{C_ClusterSequence{PseudoJet}}`: A pointer to the cluster sequence object containing the clustering history and jets. +- `njets::Csize_t`: The number of exclusive jets to be calculated. +- `result::Ptr{C_JetsResult{PseudoJet}}`: A pointer to the results. + +# Returns +- `Cint`: An integer status code indicating the success or failure. + +# Notes +- To avoid memory leaks the memory allocated for members of `result` should be freed with `jetreconstruction_JetsResult_free_members_`. +""" Base.@ccallable function jetreconstruction_exclusive_jets_njets(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, njets::Csize_t, result::Ptr{C_JetsResult{PseudoJet}})::Cint return jets_selection(exclusive_jets, clustersequence, result; njets = njets) end +""" + jetreconstruction_inclusive_jets(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, + ptmin::Cdouble, + result::Ptr{C_JetsResult{PseudoJet}}) -> Cint + +C-binding for `inclusive_jets`. + +# Arguments +- `clustersequence::Ptr{C_ClusterSequence{PseudoJet}}`: A pointer to the cluster sequence object containing the clustering history and jets. +- `ptmin::Cdouble`: The minimum transverse momentum (pt) threshold for the inclusive jets. +- `result::Ptr{C_JetsResult{PseudoJet}}`: A pointer to the results. + +# Returns +- `Cint`: An integer status code indicating the success or failure. + +# Notes +- To avoid memory leaks the memory allocated for members of `result` should be freed with `jetreconstruction_JetsResult_free_members_`. +""" Base.@ccallable function jetreconstruction_inclusive_jets(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, ptmin::Cdouble, result::Ptr{C_JetsResult{PseudoJet}})::Cint From 0194ddf6104f992523a5c95c4fd6e72c5e4a2426 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Tue, 19 Nov 2024 17:40:56 +0100 Subject: [PATCH 10/34] remove obsolete files --- compile/test/jetreconstruction_test.c | 82 --------------------------- 1 file changed, 82 deletions(-) delete mode 100644 compile/test/jetreconstruction_test.c diff --git a/compile/test/jetreconstruction_test.c b/compile/test/jetreconstruction_test.c deleted file mode 100644 index 7ba9c237..00000000 --- a/compile/test/jetreconstruction_test.c +++ /dev/null @@ -1,82 +0,0 @@ -#include "JetReconstruction.h" -#include "julia_init.h" -#include -#include -#include -#include - -void printPseudoJet(const jetreconstruction_PseudoJet *jet) { - assert(jet != NULL); - printf("PseudoJet(%f %f %f %f %ld %f %f %f %f)\n", - jet->px, jet->py, jet->pz, jet->E, jet->_cluster_hist_index, jet->_pt2, - jet->_inv_pt2, jet->_rap, jet->_phi); -} - -void printHistoryElement(const jetreconstruction_HistoryElement *history) { - assert(history != NULL); - printf("HistoryElement(%ld %ld %ld %ld %lf %lf)\n", - history->parent1, history->parent2, history->child, - history->jetp_index, history->dij, history->max_dij_so_far); -} - -void printClusterSequence(const jetreconstruction_ClusterSequence *sequence) { - printf("Cluster Sequence Information:\n" - "Algorithm: %d\n" - "Power: %f\n" - "R parameter: %f\n" - "Strategy: %d\n" - "Initial number of jets: %ld\n" - "Total event energy (Qtot): %f\n", - sequence->algorithm, sequence->power, sequence->R, sequence->strategy, - sequence->n_initial_jets, sequence->Qtot); - printf("Number of jets: %zu\n", sequence->jets_length); - if (sequence->jets != NULL) { - for (size_t i = 0; i < sequence->jets_length; i++) { - printPseudoJet(sequence->jets + i); - } - } - printf("History length: %zu\n", sequence->history_length); - if (sequence->history != NULL) { - for (size_t i = 0; i < sequence->history_length; i++) { - printHistoryElement(sequence->history + i); - } - } -} - -void printJetsResult(const jetreconstruction_JetsResult *results) { - assert(results != NULL); - for (size_t i = 0; i < results->length; ++i) { - printPseudoJet(results->data + i); - } -} - -int main(int argc, char *argv[]) { - clock_t start_time = clock(); - init_julia(argc, argv); - size_t len = 2; - jetreconstruction_PseudoJet particles[2]; - jetreconstruction_PseudoJet_init(&particles[0], 0.0, 1.0, 2.0, 3.0); - jetreconstruction_PseudoJet_init(&particles[1], 1.0, 2.0, 3.0, 4.0); - - jetreconstruction_JetAlgorithm algorithm = JETRECONSTRUCTION_JETALGORITHM_CA; - double R = 3.0; - jetreconstruction_RecoStrategy strategy = JETRECONSTRUCTION_RECOSTRATEGY_BEST; - - jetreconstruction_ClusterSequence cluster_seq; - jetreconstruction_jet_reconstruct(particles, len, algorithm, R, strategy, - &cluster_seq); - - printClusterSequence(&cluster_seq); - jetreconstruction_JetsResult result; - jetreconstruction_exclusive_jets_njets(&cluster_seq, 2, &result); - printJetsResult(&result); - - jetreconstruction_JetsResult_free_members(&result); - jetreconstruction_ClusterSequence_free_members(&cluster_seq); - shutdown_julia(0); - - clock_t end_time = clock(); - double time_spent = (double)(end_time - start_time) / CLOCKS_PER_SEC; - printf("Execution time: %f seconds\n", time_spent); - return 0; -} From e5b50479143fd345060e755b58d2225d99d7af6b Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Wed, 20 Nov 2024 16:56:06 +0100 Subject: [PATCH 11/34] add status codes --- compile/README.md | 14 ++- compile/downstream/jetreconstruction_test.c | 15 ++- compile/include/JetReconstruction.h | 87 +++++++++++++---- .../C_JetReconstruction.jl | 97 +++++++++++++++---- 4 files changed, 167 insertions(+), 46 deletions(-) diff --git a/compile/README.md b/compile/README.md index c49f4c1b..6ee62ea2 100644 --- a/compile/README.md +++ b/compile/README.md @@ -2,7 +2,7 @@ Minimal C bindings for JetReconstruction.jl -- [C-header](JetReconstruction.h) +- [C-header](include/JetReconstruction.h) - shared library compiled with [PackageCompiler.jl](https://github.com/JuliaLang/PackageCompiler.jl) ## Building library @@ -37,10 +37,14 @@ int main(int argc, char *argv[]) { jetreconstruction_RecoStrategy strategy = JETRECONSTRUCTION_RECOSTRATEGY_BEST; jetreconstruction_ClusterSequence cluster_seq; - jetreconstruction_jet_reconstruct(particles, len, algorithm, R, strategy, - &cluster_seq); - - /*Use the cluster sequence in your application + int ret = jetreconstruction_jet_reconstruct(particles, len, algorithm, R, strategy, + &cluster_seq); + if (ret != JETRECONSTRUCTION_STATUSCODE_OK){ + /*An error occurred check the value or stderr for more information*/ + return 1; + } + + /*Use the cluster sequence in your application then free memory allocations done by library*/ jetreconstruction_ClusterSequence_free_members(&cluster_seq); shutdown_julia(0); /*teardown of julia runtime*/ diff --git a/compile/downstream/jetreconstruction_test.c b/compile/downstream/jetreconstruction_test.c index 829e7f4d..60417a19 100644 --- a/compile/downstream/jetreconstruction_test.c +++ b/compile/downstream/jetreconstruction_test.c @@ -52,23 +52,28 @@ void printJetsResult(const jetreconstruction_JetsResult *results) { int main(int argc, char *argv[]) { clock_t start_time = clock(); + int sc = 0; init_julia(argc, argv); size_t len = 2; jetreconstruction_PseudoJet particles[2]; - jetreconstruction_PseudoJet_init(&particles[0], 0.0, 1.0, 2.0, 3.0); - jetreconstruction_PseudoJet_init(&particles[1], 1.0, 2.0, 3.0, 4.0); + sc = jetreconstruction_PseudoJet_init(&particles[0], 0.0, 1.0, 2.0, 3.0); + assert(sc == JETRECONSTRUCTION_STATUSCODE_OK); + sc = jetreconstruction_PseudoJet_init(&particles[1], 1.0, 2.0, 3.0, 4.0); + assert(sc == JETRECONSTRUCTION_STATUSCODE_OK); jetreconstruction_JetAlgorithm algorithm = JETRECONSTRUCTION_JETALGORITHM_CA; double R = 3.0; jetreconstruction_RecoStrategy strategy = JETRECONSTRUCTION_RECOSTRATEGY_BEST; jetreconstruction_ClusterSequence cluster_seq; - jetreconstruction_jet_reconstruct(particles, len, algorithm, R, strategy, - &cluster_seq); + sc = jetreconstruction_jet_reconstruct(particles, len, algorithm, R, strategy, + &cluster_seq); + assert(sc == JETRECONSTRUCTION_STATUSCODE_OK); printClusterSequence(&cluster_seq); jetreconstruction_JetsResult result; - jetreconstruction_exclusive_jets_njets(&cluster_seq, 2, &result); + sc = jetreconstruction_exclusive_jets_njets(&cluster_seq, 2, &result); + assert(sc == JETRECONSTRUCTION_STATUSCODE_OK); printJetsResult(&result); jetreconstruction_JetsResult_free_members(&result); diff --git a/compile/include/JetReconstruction.h b/compile/include/JetReconstruction.h index 2331d6ed..aecfd13d 100644 --- a/compile/include/JetReconstruction.h +++ b/compile/include/JetReconstruction.h @@ -24,6 +24,47 @@ /**Special history state: Cluster recombined with beam" */ #define JETRECONSTRUCTION_BEAMJET -1 +/** + * @enum jetreconstruction_StatusCode + * @brief Status codes for Jet Reconstruction operations. + * + * Common status codes for Jet Reconstruction operations. Most of the standard + * Julia + * https://docs.julialang.org/en/v1/manual/control-flow/#Exception-Handling + * exceptions are mapped to corresponding codes. + */ +typedef enum { + JETRECONSTRUCTION_STATUSCODE_OK = 0, /**< The operation succeeded. */ + JETRECONSTRUCTION_STATUSCODE_GENERICEXCEPTION = + 1, /**< An unspecified error, not covered by other status codes occurred. + */ + JETRECONSTRUCTION_STATUSCODE_ARGUMENTERROR = 2, + JETRECONSTRUCTION_STATUSCODE_BOUNDSERROR = 3, + JETRECONSTRUCTION_STATUSCODE_COMPOSITEEXCEPTION = 4, + JETRECONSTRUCTION_STATUSCODE_DIMENSIONMISMATCH = 5, + JETRECONSTRUCTION_STATUSCODE_DIVIDEERROR = 6, + JETRECONSTRUCTION_STATUSCODE_DOMAINERROR = 7, + JETRECONSTRUCTION_STATUSCODE_EOFERROR = 8, + JETRECONSTRUCTION_STATUSCODE_ERROREXCEPTION = 9, + JETRECONSTRUCTION_STATUSCODE_INEXACTERROR = 10, + JETRECONSTRUCTION_STATUSCODE_INITERROR = 11, + JETRECONSTRUCTION_STATUSCODE_INTERRUPTEXCEPTION = 12, + JETRECONSTRUCTION_STATUSCODE_INVALIDSTATEEXCEPTION = 13, + JETRECONSTRUCTION_STATUSCODE_KEYERROR = 14, + JETRECONSTRUCTION_STATUSCODE_LOADERROR = 15, + JETRECONSTRUCTION_STATUSCODE_OUTOFMEMORYERROR = 16, + JETRECONSTRUCTION_STATUSCODE_READONLYMEMORYERROR = 17, + /*JETRECONSTRUCTION_STATUSCODE_REMOTEEXCEPTION = 18, distributed only */ + JETRECONSTRUCTION_STATUSCODE_METHODERROR = 19, + JETRECONSTRUCTION_STATUSCODE_OVERFLOWERROR = 20, + /*JETRECONSTRUCTION_STATUSCODE_PARSEERROR = 21, meta only*/ + JETRECONSTRUCTION_STATUSCODE_SYSTEMERROR = 22, + JETRECONSTRUCTION_STATUSCODE_TYPEERROR = 23, + JETRECONSTRUCTION_STATUSCODE_UNDEFREFERROR = 24, + JETRECONSTRUCTION_STATUSCODE_UNDEFVARERROR = 25, + JETRECONSTRUCTION_STATUSCODE_STRINGINDEXERROR = 26 +} jetreconstruction_StatusCode; + /** * @enum jetreconstruction_JetAlgorithm * @brief Enumeration representing different jet algorithms used in @@ -81,10 +122,12 @@ typedef struct { * @param[in] py The y-component of the momentum. * @param[in] pz The z-component of the momentum. * @param[in] E The energy component of the momentum. - * @return An integer status code indicating the success or failure. + * @return An integer status code indicating the success or failure. See common + * status codes jetreconstruction_StatusCode. */ -int jetreconstruction_PseudoJet_init(jetreconstruction_PseudoJet *ptr, - double px, double py, double pz, double E); +jetreconstruction_StatusCode +jetreconstruction_PseudoJet_init(jetreconstruction_PseudoJet *ptr, double px, + double py, double pz, double E); /** * @struct jetreconstruction_HistoryElement @@ -92,12 +135,12 @@ int jetreconstruction_PseudoJet_init(jetreconstruction_PseudoJet *ptr, */ typedef struct { long parent1; /**< Index in history where first parent of this jet was - created (@ref JETRECONSTRUCTION_NONEXISTENTPARENT if this jet is - an original particle) */ + created (@ref JETRECONSTRUCTION_NONEXISTENTPARENT if this jet + is an original particle) */ long parent2; /**< Index in history where second parent of this jet was - created (@ref JETRECONSTRUCTION_NONEXISTENTPARENT if this jet is - an original particle); @ref JETRECONSTRUCTION_BEAMJET if this - history entry just labels the fact that the jet has + created (@ref JETRECONSTRUCTION_NONEXISTENTPARENT if this jet + is an original particle); @ref JETRECONSTRUCTION_BEAMJET if + this history entry just labels the fact that the jet has recombined with the beam */ long child; /**< Index in history where the current jet is recombined with another jet to form its child. It is Invalid @@ -106,7 +149,8 @@ typedef struct { PseudoJet object corresponding to this jet (i.e. the jet created at this entry of the history). NB: if this element of the history corresponds to a beam - recombination, then @p jetp_index = @ref JETRECONSTRUCTION_INVALID. + recombination, then @p jetp_index = @ref + JETRECONSTRUCTION_INVALID. */ double dij; /**< The distance corresponding to the recombination at this stage of the clustering. */ @@ -182,9 +226,10 @@ static inline void jetreconstruction_ClusterSequence_free_members( * @param[in] strategy The jet reconstruction strategy to use. * @param[out] result A pointer to which a cluster sequence containing the * reconstructed jets and the merging history will be stored. - * @return An integer status code indicating the success or failure. + * @return An integer status code indicating the success or failure. See common + * status codes jetreconstruction_StatusCode. */ -int jetreconstruction_jet_reconstruct( +jetreconstruction_StatusCode jetreconstruction_jet_reconstruct( const jetreconstruction_PseudoJet *particles, size_t particles_length, jetreconstruction_JetAlgorithm algorithm, double R, jetreconstruction_RecoStrategy strategy, @@ -195,8 +240,9 @@ int jetreconstruction_jet_reconstruct( * @brief A structure to hold the inclusive or exclusive jets. */ typedef struct { - jetreconstruction_PseudoJet *data; /**< Pointer to an array of jetreconstruction_PseudoJet. */ - size_t length; /**< The length of the @ref data array. */ + jetreconstruction_PseudoJet + *data; /**< Pointer to an array of jetreconstruction_PseudoJet. */ + size_t length; /**< The length of the @ref data array. */ } jetreconstruction_JetsResult; /** @private */ @@ -235,9 +281,10 @@ jetreconstruction_JetsResult_free_members(jetreconstruction_JetsResult *ptr) { * @param[in] dcut The distance parameter used to define the exclusive jets. * @param[out] result A pointer to the jetreconstruction_JetsResult object where * the resulting jets will be stored. - * @return An integer status code indicating the success or failure. + * @return An integer status code indicating the success or failure. See common + * status codes jetreconstruction_StatusCode. */ -int jetreconstruction_exclusive_jets_dcut( +jetreconstruction_StatusCode jetreconstruction_exclusive_jets_dcut( const jetreconstruction_ClusterSequence *clustersequence, double dcut, jetreconstruction_JetsResult *result); @@ -257,9 +304,10 @@ int jetreconstruction_exclusive_jets_dcut( * @param[in] njets The number of exclusive jets to be calculated. * @param[out] result A pointer to the jetreconstruction_JetsResult object where * the resulting jets will be stored. - * @return An integer status code indicating the success or failure. + * @return An integer status code indicating the success or failure. See common + * status codes jetreconstruction_StatusCode. */ -int jetreconstruction_exclusive_jets_njets( +jetreconstruction_StatusCode jetreconstruction_exclusive_jets_njets( const jetreconstruction_ClusterSequence *clustersequence, size_t njets, jetreconstruction_JetsResult *result); @@ -283,8 +331,9 @@ int jetreconstruction_exclusive_jets_njets( * inclusive jets. * @param[out] result A pointer to the jetreconstruction_JetsResult object where * the resulting jets will be stored. - * @return An integer status code indicating the success or failure. + * @return An integer status code indicating the success or failure. See common + * status codes jetreconstruction_StatusCode. */ -int jetreconstruction_inclusive_jets( +jetreconstruction_StatusCode jetreconstruction_inclusive_jets( const jetreconstruction_ClusterSequence *clustersequence, double ptmin, jetreconstruction_JetsResult *result); diff --git a/src/C_JetReconstruction/C_JetReconstruction.jl b/src/C_JetReconstruction/C_JetReconstruction.jl index e42962a3..9aa06a13 100644 --- a/src/C_JetReconstruction/C_JetReconstruction.jl +++ b/src/C_JetReconstruction/C_JetReconstruction.jl @@ -6,6 +6,58 @@ module C_JetReconstruction using ..JetReconstruction: JetAlgorithm, RecoStrategy, PseudoJet, ClusterSequence, HistoryElement, jet_reconstruct, exclusive_jets, inclusive_jets +using EnumX + +""" + @enumx StatusCode + +An enumeration of common status codes used in the JetReconstruction C-bindings. + +## Fields +- `OK` - The operation succeeded. +- `GenericException`- An unspecified error, not covered by other status codes occurred. +- The rest of the status codes have corresponding standard Julia exception. +""" +@enumx StatusCode OK=0 GenericException=1 ArgumentError=2 BoundsError=3 CompositeException=4 DimensionMismatch=5 DivideError=6 DomainError=7 EOFError=8 ErrorException=9 InexactError=10 InitError=11 InterruptException=12 InvalidStateException=13 KeyError=14 LoadError=15 OutOfMemoryError=16 ReadOnlyMemoryError=17 RemoteException=18 MethodError=19 OverflowError=20 ParseError=21 SystemError=22 TypeError=23 UndefRefError=24 UndefVarError=25 StringIndexError=26 + +function handle_exception(exception)::Cint + @error exception + return Cint(exception_to_enum(exception)) +end + +""" + exception_to_enum(::Any)::Cint + +Helper function matching Julia exception with C-style status code. +# Returns +- A numerical representation of the corresponding status code from the `StatusCode.T`. +""" +exception_to_enum(::Any) = Cint(StatusCode.GenericException) +exception_to_enum(::ArgumentError) = Cint(StatusCode.ArgumentError) +exception_to_enum(::BoundsError) = Cint(StatusCode.BoundsError) +exception_to_enum(::CompositeException) = Cint(StatusCode.CompositeException) +exception_to_enum(::DimensionMismatch) = Cint(StatusCode.DimensionMismatch) +exception_to_enum(::DivideError) = Cint(StatusCode.DivideError) +exception_to_enum(::DomainError) = Cint(StatusCode.DomainError) +exception_to_enum(::EOFError) = Cint(StatusCode.EOFError) +exception_to_enum(::ErrorException) = Cint(StatusCode.ErrorException) +exception_to_enum(::InexactError) = Cint(StatusCode.InexactError) +exception_to_enum(::InitError) = Cint(StatusCode.InitError) +exception_to_enum(::InterruptException) = Cint(StatusCode.InterruptException) +exception_to_enum(::InvalidStateException) = Cint(StatusCode.InvalidStateException) +exception_to_enum(::KeyError) = Cint(StatusCode.KeyError) +exception_to_enum(::LoadError) = Cint(StatusCode.LoadError) +exception_to_enum(::OutOfMemoryError) = Cint(StatusCode.OutOfMemoryError) +exception_to_enum(::ReadOnlyMemoryError) = Cint(StatusCode.ReadOnlyMemoryError) +# exception_to_enum(::Distributed.RemoteException) = Cint(StatusCode.RemoteException) +exception_to_enum(::MethodError) = Cint(StatusCode.MethodError) +exception_to_enum(::OverflowError) = Cint(StatusCode.OverflowError) +# exception_to_enum(::Meta.ParseError) = Cint(StatusCode.ParseError) +exception_to_enum(::SystemError) = Cint(StatusCode.SystemError) +exception_to_enum(::TypeError) = Cint(StatusCode.TypeError) +exception_to_enum(::UndefRefError) = Cint(StatusCode.UndefRefError) +exception_to_enum(::UndefVarError) = Cint(StatusCode.UndefVarError) +exception_to_enum(::StringIndexError) = Cint(StatusCode.StringIndexError) """ unsafe_wrap_c_array(ptr::Ptr{T}, array_length::Csize_t) where {T} @@ -85,9 +137,13 @@ C-binding for `PseudoJet` initialization. Base.@ccallable function jetreconstruction_PseudoJet_init(ptr::Ptr{PseudoJet}, px::Cdouble, py::Cdouble, pz::Cdouble, E::Cdouble)::Cint - pseudojet = PseudoJet(px, py, pz, E) - unsafe_store!(ptr, pseudojet) - return 0 + try + pseudojet = PseudoJet(px, py, pz, E) + unsafe_store!(ptr, pseudojet) + catch e + return handle_exception(e) + end + return Cint(StatusCode.OK) end """ @@ -219,12 +275,16 @@ function c_jet_reconstruct(particles::Ptr{T}, R::Cdouble, strategy::RecoStrategy.Strategy, result::Ptr{C_ClusterSequence{U}}) where {T, U} - particles_v = unsafe_wrap_c_array(particles, particles_length) - clusterseq = jet_reconstruct(particles_v; p = nothing, algorithm = algorithm, R = R, - strategy = strategy) - c_clusterseq = C_ClusterSequence{U}(clusterseq) - unsafe_store!(result, c_clusterseq) - return 0 + try + particles_v = unsafe_wrap_c_array(particles, particles_length) + clusterseq = jet_reconstruct(particles_v; p = nothing, algorithm = algorithm, R = R, + strategy = strategy) + c_clusterseq = C_ClusterSequence{U}(clusterseq) + unsafe_store!(result, c_clusterseq) + catch e + return handle_exception(e) + end + return Cint(StatusCode.OK) end """ @@ -257,8 +317,7 @@ Base.@ccallable function jetreconstruction_jet_reconstruct(particles::Ptr{Pseudo R::Cdouble, strategy::RecoStrategy.Strategy, result::Ptr{C_ClusterSequence{PseudoJet}})::Cint - c_jet_reconstruct(particles, particles_length, algorithm, R, strategy, result) - return 0 + return c_jet_reconstruct(particles, particles_length, algorithm, R, strategy, result) end """ @@ -324,12 +383,16 @@ An internal helper function for calling calling functions selecting jets from a """ function jets_selection(selector, clustersequence::Ptr{C_ClusterSequence{T}}, result::Ptr{C_JetsResult{U}}; kwargs...)::Cint where {T, U} - c_clusterseq = unsafe_load(clustersequence) - clusterseq = ClusterSequence{T}(c_clusterseq) - jets_result = selector(clusterseq; T = U, kwargs...) - c_results = C_JetsResult{U}(make_c_array(jets_result)...) - unsafe_store!(result, c_results) - return 0 + try + c_clusterseq = unsafe_load(clustersequence) + clusterseq = ClusterSequence{T}(c_clusterseq) + jets_result = selector(clusterseq; T = U, kwargs...) + c_results = C_JetsResult{U}(make_c_array(jets_result)...) + unsafe_store!(result, c_results) + catch e + return handle_exception(e) + end + return Cint(StatusCode.OK) end """ From 3e0e36853164af89c4718c6404c12b522ea30bce Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Wed, 20 Nov 2024 17:01:42 +0100 Subject: [PATCH 12/34] add missing header guard --- compile/include/JetReconstruction.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compile/include/JetReconstruction.h b/compile/include/JetReconstruction.h index aecfd13d..5c0c963a 100644 --- a/compile/include/JetReconstruction.h +++ b/compile/include/JetReconstruction.h @@ -12,6 +12,9 @@ * reconstruction. */ +#ifndef JET_RECONSTRUCTION_JL_H_ +#define JET_RECONSTRUCTION_JL_H_ + #include /*Special states in a history.*/ @@ -337,3 +340,5 @@ jetreconstruction_StatusCode jetreconstruction_exclusive_jets_njets( jetreconstruction_StatusCode jetreconstruction_inclusive_jets( const jetreconstruction_ClusterSequence *clustersequence, double ptmin, jetreconstruction_JetsResult *result); + +#endif /* JET_RECONSTRUCTION_JL_H_ */ From 797efa676a572a668e043dfffa42548067c313db Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Thu, 21 Nov 2024 14:37:05 +0100 Subject: [PATCH 13/34] fix pointee lifetime in precompilation file --- compile/precompile_execution.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compile/precompile_execution.jl b/compile/precompile_execution.jl index 8204cdb0..1a388acd 100644 --- a/compile/precompile_execution.jl +++ b/compile/precompile_execution.jl @@ -27,8 +27,7 @@ jetreconstruction_jet_reconstruct(pseudoJets_ptr, pseudoJets_len, algorithm, R, RecoStrategy.Best, clustersequence_ptr) -results = C_JetsResult{PseudoJet}(C_NULL, 0) -results_ptr = Base.unsafe_convert(Ptr{C_JetsResult{PseudoJet}}, Ref(results)) +results_ptr = Ptr{C_JetsResult{PseudoJet}}(Libc.malloc(sizeof(C_JetsResult{PseudoJet}))) jetreconstruction_exclusive_jets_njets(clustersequence_ptr, Csize_t(2), results_ptr) jetreconstruction_JetsResult_free_members_(results_ptr) @@ -41,3 +40,4 @@ jetreconstruction_JetsResult_free_members_(results_ptr) jetreconstruction_ClusterSequence_free_members_(clustersequence_ptr) Libc.free(pseudoJets_ptr) Libc.free(clustersequence_ptr) +Libc.free(results_ptr) From 3d269838609cab93773a7fde860ac60f2d524720 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Mon, 10 Feb 2025 14:51:11 +0100 Subject: [PATCH 14/34] add extern C when C++ --- compile/include/JetReconstruction.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compile/include/JetReconstruction.h b/compile/include/JetReconstruction.h index 5c0c963a..5dee8826 100644 --- a/compile/include/JetReconstruction.h +++ b/compile/include/JetReconstruction.h @@ -15,6 +15,10 @@ #ifndef JET_RECONSTRUCTION_JL_H_ #define JET_RECONSTRUCTION_JL_H_ +#ifdef __cplusplus +extern "C" { +#endif + #include /*Special states in a history.*/ @@ -341,4 +345,8 @@ jetreconstruction_StatusCode jetreconstruction_inclusive_jets( const jetreconstruction_ClusterSequence *clustersequence, double ptmin, jetreconstruction_JetsResult *result); +#ifdef __cplusplus +} +#endif + #endif /* JET_RECONSTRUCTION_JL_H_ */ From 6d21d72fcacca0d5f4946eb2334411fbccfb128a Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Mon, 10 Feb 2025 14:53:48 +0100 Subject: [PATCH 15/34] cover more scenarios in precompile --- compile/precompile_execution.jl | 68 +++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/compile/precompile_execution.jl b/compile/precompile_execution.jl index 1a388acd..655cfa47 100644 --- a/compile/precompile_execution.jl +++ b/compile/precompile_execution.jl @@ -1,7 +1,7 @@ # Dummy code to call and cache compilation of all C-bindings -# The numeric values doesn't make sense and are used only to select correct dispatch +# The numeric values don't make sense and are used only to select correct dispatch -using JetReconstruction +using JetReconstruction: PseudoJet, RecoStrategy, JetAlgorithm using JetReconstruction.C_JetReconstruction: jetreconstruction_PseudoJet_init, C_ClusterSequence, jetreconstruction_ClusterSequence_free_members_, @@ -10,34 +10,52 @@ using JetReconstruction.C_JetReconstruction: jetreconstruction_PseudoJet_init, jetreconstruction_jet_reconstruct, jetreconstruction_inclusive_jets, jetreconstruction_exclusive_jets_njets, - jetreconstruction_exclusive_jets_dcut + jetreconstruction_exclusive_jets_dcut, + StatusCode -pseudoJets_len = Csize_t(2) -pseudoJets_ptr = Ptr{PseudoJet}(Libc.malloc(pseudoJets_len * sizeof(PseudoJet))) +function assert_ok(ret_val) + @assert StatusCode.T(ret_val) == StatusCode.OK +end -jetreconstruction_PseudoJet_init(pseudoJets_ptr, 0.0, 1.0, 2.0, 3.0) -jetreconstruction_PseudoJet_init(pseudoJets_ptr + sizeof(PseudoJet), 1.0, 2.0, 3.0, 4.0) - -strategy = RecoStrategy.Best -algorithm = JetAlgorithm.CA R = 2.0 +jets_len = Csize_t(2) -clustersequence_ptr = Ptr{C_ClusterSequence{PseudoJet}}(Libc.malloc(sizeof(C_ClusterSequence{PseudoJet}))) -jetreconstruction_jet_reconstruct(pseudoJets_ptr, pseudoJets_len, algorithm, R, - RecoStrategy.Best, - clustersequence_ptr) +### pp jets ### +jets_ptr = Ptr{PseudoJet}(Libc.malloc(jets_len * sizeof(PseudoJet))) +@assert jets_ptr != C_NULL +clustersequence_ptr = Ptr{C_ClusterSequence{PseudoJet}}(Libc.malloc(sizeof(C_ClusterSequence{PseudoJet}))) +@assert clustersequence_ptr != C_NULL results_ptr = Ptr{C_JetsResult{PseudoJet}}(Libc.malloc(sizeof(C_JetsResult{PseudoJet}))) -jetreconstruction_exclusive_jets_njets(clustersequence_ptr, Csize_t(2), results_ptr) -jetreconstruction_JetsResult_free_members_(results_ptr) - -jetreconstruction_exclusive_jets_dcut(clustersequence_ptr, 1.0, results_ptr) -jetreconstruction_JetsResult_free_members_(results_ptr) - -jetreconstruction_inclusive_jets(clustersequence_ptr, 0.0, results_ptr) -jetreconstruction_JetsResult_free_members_(results_ptr) - -jetreconstruction_ClusterSequence_free_members_(clustersequence_ptr) -Libc.free(pseudoJets_ptr) +@assert results_ptr != C_NULL + +assert_ok(jetreconstruction_PseudoJet_init(jets_ptr, 0.0, 1.0, 2.0, 3.0)) +assert_ok(jetreconstruction_PseudoJet_init(jets_ptr + sizeof(PseudoJet), 1.0, 2.0, 3.0, + 4.0)) + +for algorithm in [JetAlgorithm.AntiKt, JetAlgorithm.CA, JetAlgorithm.Kt] + for strategy in [RecoStrategy.N2Plain, RecoStrategy.N2Tiled, RecoStrategy.Best] + assert_ok(jetreconstruction_jet_reconstruct(jets_ptr, jets_len, algorithm, R, + strategy, + clustersequence_ptr)) + + assert_ok(jetreconstruction_inclusive_jets(clustersequence_ptr, 0.0, results_ptr)) + jetreconstruction_JetsResult_free_members_(results_ptr) + + if algorithm != JetAlgorithm.AntiKt + assert_ok(jetreconstruction_exclusive_jets_njets(clustersequence_ptr, + Csize_t(2), + results_ptr)) + jetreconstruction_JetsResult_free_members_(results_ptr) + + assert_ok(jetreconstruction_exclusive_jets_dcut(clustersequence_ptr, 1.0, + results_ptr)) + jetreconstruction_JetsResult_free_members_(results_ptr) + + jetreconstruction_ClusterSequence_free_members_(clustersequence_ptr) + end + end +end +Libc.free(jets_ptr) Libc.free(clustersequence_ptr) Libc.free(results_ptr) From 2551e6d96648fb8a73b04be666c79c364ca4b201 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Mon, 10 Feb 2025 14:54:49 +0100 Subject: [PATCH 16/34] fix C array length type --- src/C_JetReconstruction/C_JetReconstruction.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/C_JetReconstruction/C_JetReconstruction.jl b/src/C_JetReconstruction/C_JetReconstruction.jl index 9aa06a13..496d77c8 100644 --- a/src/C_JetReconstruction/C_JetReconstruction.jl +++ b/src/C_JetReconstruction/C_JetReconstruction.jl @@ -115,7 +115,7 @@ function make_c_array(v::Vector{T}) where {T} for i in 1:len @inbounds unsafe_store!(ptr, v[i], i) end - return ptr, len + return ptr, Csize_t(len) end """ From 524551c04da7c5a1c6b8b656d17b3b70b5b26c16 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Mon, 10 Feb 2025 14:56:01 +0100 Subject: [PATCH 17/34] add tests for c-interface --- test/runtests.jl | 3 + test/test-c-interface.jl | 152 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 test/test-c-interface.jl diff --git a/test/runtests.jl b/test/runtests.jl index 4256853f..ae3ee62c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -48,6 +48,9 @@ function main() # Test with Aqua (https://juliatesting.github.io/Aqua.jl/stable/) include("test-aqua.jl") + + # C-interface tests + include("test-c-interface.jl") end logger = ConsoleLogger(stdout, Logging.Warn) diff --git a/test/test-c-interface.jl b/test/test-c-interface.jl new file mode 100644 index 00000000..00049482 --- /dev/null +++ b/test/test-c-interface.jl @@ -0,0 +1,152 @@ +# Tests functions exposed as C-interface + +include("common.jl") +using JetReconstruction.C_JetReconstruction + +# helper function make generic field-wise comparison +function struct_approx_equal(x::T, y::T) where {T} + return all(getfield(x, f) ≈ getfield(y, f) for f in fieldnames(typeof(x))) +end + +function compare_results(ptr::Ptr{C_JetReconstruction.C_ClusterSequence{T}}, + cluster_seq::ClusterSequence{T}) where {T} + @test ptr != C_NULL + c_cluster_seq = unsafe_load(ptr) + @test c_cluster_seq.algorithm == cluster_seq.algorithm + @test c_cluster_seq.power ≈ cluster_seq.power + @test c_cluster_seq.R ≈ cluster_seq.R + @test c_cluster_seq.strategy == cluster_seq.strategy + @test c_cluster_seq.jets_length == length(cluster_seq.jets) + c_jets = C_JetReconstruction.unsafe_wrap_c_array(c_cluster_seq.jets, + c_cluster_seq.jets_length) + @test all(struct_approx_equal.(c_jets, cluster_seq.jets)) + @test c_cluster_seq.n_initial_jets == cluster_seq.n_initial_jets + @test c_cluster_seq.history_length == length(cluster_seq.history) + c_history = C_JetReconstruction.unsafe_wrap_c_array(c_cluster_seq.history, + c_cluster_seq.history_length) + @test all(struct_approx_equal.(c_history, cluster_seq.history)) + @test c_cluster_seq.Qtot ≈ cluster_seq.Qtot +end + +function compare_results(ptr::Ptr{C_JetReconstruction.C_JetsResult{T}}, + jets::Vector{T}) where {T} + @test ptr != C_NULL + c_results = unsafe_load(ptr) + @test c_results.length == length(jets) + c_data = C_JetReconstruction.unsafe_wrap_c_array(c_results.data, + c_results.length) + @test all(struct_approx_equal.(c_data, jets)) +end + +function test_jet_reconstruct(filename; algorithm, R, strategy, power = nothing, + T = PseudoJet) + @testset "C-interface jet reconstruct" begin + events = JetReconstruction.read_final_state_particles(filename) + results = Vector{ClusterSequence{T}}(undef, length(events)) + c_results = Vector{Ptr{C_JetReconstruction.C_ClusterSequence{T}}}(undef, + length(events)) + for (ievent, event) in enumerate(events) + c_event, c_event_length = C_JetReconstruction.make_c_array(event) + cluster_seq_ptr = Ptr{C_JetReconstruction.C_ClusterSequence{T}}(Libc.malloc(sizeof(C_JetReconstruction.C_ClusterSequence{T}))) + @test cluster_seq_ptr != C_NULL + + ret = C_JetReconstruction.jetreconstruction_jet_reconstruct(c_event, + c_event_length, + algorithm, + R, + strategy, + cluster_seq_ptr) + @test C_JetReconstruction.StatusCode.T(ret) == C_JetReconstruction.StatusCode.OK + + cluster_seq = JetReconstruction.jet_reconstruct(event; R = R, + p = power, + algorithm = algorithm, + strategy = strategy) + compare_results(cluster_seq_ptr, cluster_seq) + @inbounds results[ievent] = cluster_seq + @inbounds c_results[ievent] = cluster_seq_ptr + Libc.free(c_event) + end + return c_results, results + end +end + +function test_inclusive_jets(cluster_seq_ptrs::Vector{Ptr{C_JetReconstruction.C_ClusterSequence{T}}}, + cluster_seqs::Vector{JetReconstruction.ClusterSequence{T}}; + ptmin) where {T} + @testset "C-interface inclusive jets" begin + results_ptr = Ptr{C_JetReconstruction.C_JetsResult{T}}(Libc.malloc(sizeof(C_JetReconstruction.C_JetsResult{T}))) + for (cluster_seq_ptr, cluster_seq) in zip(cluster_seq_ptrs, cluster_seqs) + ret = C_JetReconstruction.jetreconstruction_inclusive_jets(cluster_seq_ptr, + ptmin, + results_ptr) + @test C_JetReconstruction.StatusCode.T(ret) == C_JetReconstruction.StatusCode.OK + results = inclusive_jets(cluster_seq; ptmin = ptmin, T = T) + compare_results(results_ptr, results) + C_JetReconstruction.jetreconstruction_JetsResult_free_members_(results_ptr) + end + Libc.free(results_ptr) + end +end + +function test_exclusive_jets_njets(cluster_seq_ptrs::Vector{Ptr{C_JetReconstruction.C_ClusterSequence{T}}}, + cluster_seqs::Vector{JetReconstruction.ClusterSequence{T}}; + njets) where {T} + @testset "C-interface exclusive jets njets" begin + results_ptr = Ptr{C_JetReconstruction.C_JetsResult{T}}(Libc.malloc(sizeof(C_JetReconstruction.C_JetsResult{T}))) + for (cluster_seq_ptr, cluster_seq) in zip(cluster_seq_ptrs, cluster_seqs) + ret = C_JetReconstruction.jetreconstruction_exclusive_jets_njets(cluster_seq_ptr, + Csize_t(njets), + results_ptr) + @test C_JetReconstruction.StatusCode.T(ret) == C_JetReconstruction.StatusCode.OK + results = exclusive_jets(cluster_seq; njets = njets, T = T) + compare_results(results_ptr, results) + C_JetReconstruction.jetreconstruction_JetsResult_free_members_(results_ptr) + end + Libc.free(results_ptr) + end +end + +function test_exclusive_jets_dcut(cluster_seq_ptrs::Vector{Ptr{C_JetReconstruction.C_ClusterSequence{T}}}, + cluster_seqs::Vector{JetReconstruction.ClusterSequence{T}}; + dcut) where {T} + @testset "C-interface exclusive jets dcut" begin + results_ptr = Ptr{C_JetReconstruction.C_JetsResult{T}}(Libc.malloc(sizeof(C_JetReconstruction.C_JetsResult{T}))) + for (cluster_seq_ptr, cluster_seq) in zip(cluster_seq_ptrs, cluster_seqs) + ret = C_JetReconstruction.jetreconstruction_exclusive_jets_dcut(cluster_seq_ptr, + dcut, + results_ptr) + @test C_JetReconstruction.StatusCode.T(ret) == C_JetReconstruction.StatusCode.OK + results = exclusive_jets(cluster_seq; dcut = dcut, T = T) + compare_results(results_ptr, results) + C_JetReconstruction.jetreconstruction_JetsResult_free_members_(results_ptr) + end + Libc.free(results_ptr) + end +end + +@testset "C-interface JetReconstruction pp" begin + test_cone_size = 0.4 + for alg in [JetAlgorithm.AntiKt, JetAlgorithm.CA, JetAlgorithm.Kt], + stg in [RecoStrategy.Best, RecoStrategy.N2Plain, RecoStrategy.N2Tiled] + + power = JetReconstruction.algorithm2power[alg] + @testset "C-interface JetReconstruction comparison: alg=$alg, p=$power, R=$test_cone_size, strategy=$stg" begin + cluster_seq_ptrs, cluster_seqs = test_jet_reconstruct(events_file_pp; + algorithm = alg, + strategy = stg, + R = test_cone_size, + power = power) + test_inclusive_jets(cluster_seq_ptrs, cluster_seqs; ptmin = 5.0) + if alg != JetAlgorithm.AntiKt + test_exclusive_jets_njets(cluster_seq_ptrs, cluster_seqs; njets = 4) + test_exclusive_jets_dcut(cluster_seq_ptrs, cluster_seqs; dcut = 0.99) + end + + for ptr in cluster_seq_ptrs + C_JetReconstruction.jetreconstruction_ClusterSequence_free_members_(ptr) + Libc.free(ptr) + end + end + end +end From 8e48e7ef69d49acb3d89b479bfba28d5da2830ed Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Mon, 10 Feb 2025 15:30:00 +0100 Subject: [PATCH 18/34] add test PseudoJet__init --- test/test-c-interface.jl | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/test-c-interface.jl b/test/test-c-interface.jl index 00049482..24e7e145 100644 --- a/test/test-c-interface.jl +++ b/test/test-c-interface.jl @@ -38,6 +38,16 @@ function compare_results(ptr::Ptr{C_JetReconstruction.C_JetsResult{T}}, @test all(struct_approx_equal.(c_data, jets)) end +function test_pseudojet() + ptr = Ptr{PseudoJet}(Libc.malloc(sizeof(PseudoJet))) + @test ptr != C_NULL + ret = C_JetReconstruction.jetreconstruction_PseudoJet_init(ptr, 0.1, 0.2, 0.3, 1.0) + @test C_JetReconstruction.StatusCode.T(ret) == C_JetReconstruction.StatusCode.OK + c_jet = unsafe_load(ptr) + jet = PseudoJet(0.1, 0.2, 0.3, 1.0) + struct_approx_equal(jet, c_jet) +end + function test_jet_reconstruct(filename; algorithm, R, strategy, power = nothing, T = PseudoJet) @testset "C-interface jet reconstruct" begin @@ -127,6 +137,9 @@ end @testset "C-interface JetReconstruction pp" begin test_cone_size = 0.4 + + test_pseudojet() + for alg in [JetAlgorithm.AntiKt, JetAlgorithm.CA, JetAlgorithm.Kt], stg in [RecoStrategy.Best, RecoStrategy.N2Plain, RecoStrategy.N2Tiled] From c8961b6ba68797ec6538652a5ec8dff7125340a0 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Tue, 11 Mar 2025 17:45:11 +0100 Subject: [PATCH 19/34] add compiling with juliac --- compile/README.md | 26 +++++-- compile/build.jl | 72 +++++++++++++++---- ...cmake => JetReconstructionConfig.cmake.in} | 9 ++- ...econstruction.h => JetReconstruction.h.in} | 3 + 4 files changed, 89 insertions(+), 21 deletions(-) rename compile/cmake/JetReconstruction/{JetReconstructionConfig.cmake => JetReconstructionConfig.cmake.in} (82%) rename compile/include/{JetReconstruction.h => JetReconstruction.h.in} (99%) diff --git a/compile/README.md b/compile/README.md index 6ee62ea2..3290bcdf 100644 --- a/compile/README.md +++ b/compile/README.md @@ -2,8 +2,8 @@ Minimal C bindings for JetReconstruction.jl -- [C-header](include/JetReconstruction.h) -- shared library compiled with [PackageCompiler.jl](https://github.com/JuliaLang/PackageCompiler.jl) +- [C-header](include/JetReconstruction.h.in) +- shared library compiled with [PackageCompiler.jl](https://github.com/JuliaLang/PackageCompiler.jl) or juliac ## Building library @@ -13,6 +13,16 @@ To build the library, run the following command from the package root directory: julia --project=compile compile/build.jl ``` +> [!NOTE] +> Since Julia 1.12 `--juliac` can be specified to use the juliac compiler instead of PackageCompiler. +> Before Julia 1.12, nightlies can be used instead: +> +> ```sh +> julia +nightly --project=compile compile/build.jl --juliac +> ``` +> +> Packes compiled with `PackageCompiler.jl` will have `JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER` defined. Packages compiled with `juliac` will have `JETRECONSTRUCTION_COMPILER_JULIAC` defined. + ## Usage example ### Example source file @@ -21,10 +31,16 @@ Example usage of C bindings in an application: ```C #include "JetReconstruction.h" -#include "julia_init.h" /*Should be automatically generated by PackageCompiler.jl and distributed together with the "JetReconstruction.h" header file*/ + +/*Should be automatically generated by PackageCompiler.jl and distributed together with the "JetReconstruction.h" header file*/ +#ifdef JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER +#include "julia_init.h" +#endif int main(int argc, char *argv[]) { - init_julia(argc, argv); /*initialization of julia runtime*/ +#ifdef JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER + init_julia(0, NULL); /*initialization of julia runtime*/ +#endif /*Prepare array of pseudo jets*/ size_t particles_len; @@ -47,7 +63,9 @@ int main(int argc, char *argv[]) { /*Use the cluster sequence in your application then free memory allocations done by library*/ jetreconstruction_ClusterSequence_free_members(&cluster_seq); +#ifdef JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER shutdown_julia(0); /*teardown of julia runtime*/ +#endif return 0; } diff --git a/compile/build.jl b/compile/build.jl index 717d7530..70e9a00e 100644 --- a/compile/build.jl +++ b/compile/build.jl @@ -14,11 +14,20 @@ function parse_args(args) help = "Directory to save the compiled library" arg_type = String default = joinpath(splitdir(@__DIR__) |> first, "JetReconstructionCompiled") + + "--juliac" + help = "Use juliac compiler" + action = :store_true end return ArgParse.parse_args(args, s) end +function cp_file(input_dir, basename, output_dir) + cp(joinpath(input_dir, basename), + joinpath(output_dir, basename); force = true) +end + function configure_file(template_path::String, output_path::String, replacements::Dict{String, String}) template = read(template_path, String) @@ -30,6 +39,28 @@ function configure_file(template_path::String, output_path::String, end end +function compile_w_packagecompiler(source_dir, output_dir) + return @elapsed PackageCompiler.create_library(source_dir, output_dir; + lib_name = "jetreconstruction", + precompile_execution_file = [joinpath(@__DIR__, + "precompile_execution.jl")], + incremental = false, + filter_stdlibs = true, + force = true) +end + +function compile_w_juliac(source_dir, output_dir) + julia_path = joinpath(Sys.BINDIR, Base.julia_exename()) + juliac_path = joinpath(Sys.BINDIR, "..", "share", "julia", "juliac.jl") + jetreconstruction_path = joinpath(source_dir, "src", "JetReconstruction.jl") + lib_dir = joinpath(output_dir, "lib") + mkpath(lib_dir) + output_lib = joinpath(lib_dir, "libjetreconstruction.so") + command = "$(julia_path) --project=$(source_dir) $(juliac_path) --experimental --trim=no --compile-ccallable --output-lib $(output_lib) $(jetreconstruction_path)" + @info command + return @elapsed run(`$(split(command))`) +end + function (@main)(args) parsed_args = parse_args(args) source_dir = parsed_args["source-dir"] @@ -37,29 +68,40 @@ function (@main)(args) @info "Compiling package from $source_dir" @info "Creating library in $output_dir" - PackageCompiler.create_library(source_dir, output_dir; - lib_name = "jetreconstruction", - header_files = [joinpath(@__DIR__, "include", - "JetReconstruction.h")], - precompile_execution_file = [joinpath(@__DIR__, - "precompile_execution.jl")], - incremental = false, - filter_stdlibs = true, - force = true) + + compilation_time = if parsed_args["juliac"] + @info "Using juliac compiler" + compile_w_juliac(source_dir, output_dir) + else + @info "Using PackageCompiler compiler" + compile_w_packagecompiler(source_dir, output_dir) + end + @info "Compiled in $(compilation_time) seconds" + compiler = parsed_args["juliac"] ? "JETRECONSTRUCTION_COMPILER_JULIAC" : + "JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER" + + includes_input = joinpath(@__DIR__, "include") + includes_output = joinpath(output_dir, "include") + mkpath(includes_output) + @info "Copying header files to $includes_output" + configure_file(joinpath(includes_input, "JetReconstruction.h.in"), + joinpath(includes_output, "JetReconstruction.h"), + Dict("JETRECONSTRUCTION_COMPILER" => compiler)) cmake_input = joinpath(@__DIR__, "cmake", "JetReconstruction") cmake_output = joinpath(output_dir, "lib", "cmake", "JetReconstruction") + @info "Copying CMake files to $cmake_output" + mkpath(cmake_output) version = pkgversion(JetReconstruction) cmake_project_version = "$(version.major).$(version.minor).$(version.patch)" - @info "Copying CMake file to $cmake_output" - mkpath(cmake_output) - cp_file(input_dir, basename, output_dir) = cp(joinpath(input_dir, basename), - joinpath(output_dir, basename)) - cp_file(cmake_input, "JetReconstructionConfig.cmake", cmake_output) - cp_file(cmake_input, "JetReconstructionTargets.cmake", cmake_output) + configure_file(joinpath(cmake_input, "JetReconstructionConfig.cmake.in"), + joinpath(cmake_output, "JetReconstructionConfig.cmake"), + Dict("JETRECONSTRUCTION_COMPILER" => compiler)) configure_file(joinpath(cmake_input, "JetReconstructionConfigVersion.cmake.in"), joinpath(cmake_output, "JetReconstructionConfigVersion.cmake"), Dict("PROJECT_VERSION" => cmake_project_version)) + cp_file(cmake_input, "JetReconstructionTargets.cmake", cmake_output) + return 0 end diff --git a/compile/cmake/JetReconstruction/JetReconstructionConfig.cmake b/compile/cmake/JetReconstruction/JetReconstructionConfig.cmake.in similarity index 82% rename from compile/cmake/JetReconstruction/JetReconstructionConfig.cmake rename to compile/cmake/JetReconstruction/JetReconstructionConfig.cmake.in index db499e6c..310c1a62 100644 --- a/compile/cmake/JetReconstruction/JetReconstructionConfig.cmake +++ b/compile/cmake/JetReconstruction/JetReconstructionConfig.cmake.in @@ -1,5 +1,8 @@ # Config file for the JetReconstruction.jl package # Manualy adjusted from standard cmake generated config file + +set(JETRECONSTRUCTION_COMPILER "@JETRECONSTRUCTION_COMPILER@") + get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) macro(set_and_check _var _file) @@ -26,8 +29,10 @@ endmacro() # the imported targets created later. set_and_check(JetReconstruction_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include") -# - Create path to installed read-only data files (e.g. yaml files) -set_and_check(JetReconstruction_DATA_DIR "${PACKAGE_PREFIX_DIR}/share/julia") +if (${JETRECONSTRUCTION_COMPILER} STREQUAL "JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER") + # - Create path to installed read-only data files (e.g. yaml files) + set_and_check(JetReconstruction_DATA_DIR "${PACKAGE_PREFIX_DIR}/share/julia") +endif() # - Include the targets file to create the imported targets that a client can # link to (libraries) or execute (programs) diff --git a/compile/include/JetReconstruction.h b/compile/include/JetReconstruction.h.in similarity index 99% rename from compile/include/JetReconstruction.h rename to compile/include/JetReconstruction.h.in index 5dee8826..01241827 100644 --- a/compile/include/JetReconstruction.h +++ b/compile/include/JetReconstruction.h.in @@ -21,6 +21,9 @@ extern "C" { #include +/** Compiler used to compiler JetReconstruction.jl package */ +#define @JETRECONSTRUCTION_COMPILER@ 1 + /*Special states in a history.*/ /**Special history state: Invalid child for this jet, meaning it did not From 6f4725773c25c5cd700afddfc9676efd6f02560d Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Wed, 12 Mar 2025 09:19:36 +0100 Subject: [PATCH 20/34] update downstream example to work with juliac compiled lib --- compile/downstream/jetreconstruction_test.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compile/downstream/jetreconstruction_test.c b/compile/downstream/jetreconstruction_test.c index 60417a19..1296b935 100644 --- a/compile/downstream/jetreconstruction_test.c +++ b/compile/downstream/jetreconstruction_test.c @@ -1,5 +1,7 @@ #include "JetReconstruction.h" +#ifdef JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER #include "julia_init.h" +#endif #include #include #include @@ -53,7 +55,9 @@ void printJetsResult(const jetreconstruction_JetsResult *results) { int main(int argc, char *argv[]) { clock_t start_time = clock(); int sc = 0; - init_julia(argc, argv); +#ifdef JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER + init_julia(0, NULL); +#endif size_t len = 2; jetreconstruction_PseudoJet particles[2]; sc = jetreconstruction_PseudoJet_init(&particles[0], 0.0, 1.0, 2.0, 3.0); @@ -78,7 +82,9 @@ int main(int argc, char *argv[]) { jetreconstruction_JetsResult_free_members(&result); jetreconstruction_ClusterSequence_free_members(&cluster_seq); +#ifdef JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER shutdown_julia(0); +#endif clock_t end_time = clock(); double time_spent = (double)(end_time - start_time) / CLOCKS_PER_SEC; From 08a2c5bcd70cb12a17a610924b40f08364383fa3 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Thu, 13 Mar 2025 08:20:59 +0100 Subject: [PATCH 21/34] update compile README --- compile/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compile/README.md b/compile/README.md index 3290bcdf..9677a839 100644 --- a/compile/README.md +++ b/compile/README.md @@ -10,18 +10,18 @@ Minimal C bindings for JetReconstruction.jl To build the library, run the following command from the package root directory: ```sh -julia --project=compile compile/build.jl +julia --project=compile compile/build.jl --output-dir JetReconstructionCompiled ``` > [!NOTE] -> Since Julia 1.12 `--juliac` can be specified to use the juliac compiler instead of PackageCompiler. -> Before Julia 1.12, nightlies can be used instead: +> Since Julia 1.12 `--juliac` can be specified to use the juliac compiler instead of PackageCompiler. +> Before Julia 1.12, nightlies can be used instead (make sure to instantiate the main JetReconstruction and `compile` projects with the same version of Julia): > > ```sh > julia +nightly --project=compile compile/build.jl --juliac > ``` > -> Packes compiled with `PackageCompiler.jl` will have `JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER` defined. Packages compiled with `juliac` will have `JETRECONSTRUCTION_COMPILER_JULIAC` defined. +> Packages compiled with `PackageCompiler.jl` will have `JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER` defined. Packages compiled with `juliac` will have `JETRECONSTRUCTION_COMPILER_JULIAC` defined. ## Usage example @@ -76,7 +76,7 @@ int main(int argc, char *argv[]) { To build an example application run the following command: ```shell -cc -o jetreconstruction_test compile/test/jetreconstruction_test.c -IJetReconstructionCompiled/include -LJetReconstructionCompiled/lib -ljetreconstruction -ljulia +cc -o jetreconstruction_test compile/downstream/jetreconstruction_test.c -IJetReconstructionCompiled/include -LJetReconstructionCompiled/lib -ljetreconstruction ``` In case the compiled library resides in non-standard location, add its location to `LD_LIBRARY_PATH` when running example application: From 9fdf0dcb11cf543822f2f87938e24987b54ed557 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Tue, 18 Mar 2025 17:50:44 +0100 Subject: [PATCH 22/34] point to 1.12 nighthlies in the readme, remove compat on julia version --- compile/Project.toml | 1 - compile/README.md | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compile/Project.toml b/compile/Project.toml index 1cd28755..44bce240 100644 --- a/compile/Project.toml +++ b/compile/Project.toml @@ -9,4 +9,3 @@ JetReconstruction = {path = ".."} [compat] JetReconstruction = "0.4" PackageCompiler = "2" -julia = "1.11" diff --git a/compile/README.md b/compile/README.md index 9677a839..4f611454 100644 --- a/compile/README.md +++ b/compile/README.md @@ -18,7 +18,7 @@ julia --project=compile compile/build.jl --output-dir JetReconstructionCompiled > Before Julia 1.12, nightlies can be used instead (make sure to instantiate the main JetReconstruction and `compile` projects with the same version of Julia): > > ```sh -> julia +nightly --project=compile compile/build.jl --juliac +> julia +1.12-nightly --project=compile compile/build.jl --juliac > ``` > > Packages compiled with `PackageCompiler.jl` will have `JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER` defined. Packages compiled with `juliac` will have `JETRECONSTRUCTION_COMPILER_JULIAC` defined. @@ -99,7 +99,8 @@ target_link_libraries(myTarget PUBLIC JetReconstruction::JetReconstruction) Currently it's not possible to create libraries for different platforms - no cross-compilation! -The library is relocatable given the whole installation tree is moved, including libraries in the `lib/julia/` directory. +PackageCompiler specific: -It's advised to install the library in a separate directory to avoid possible conflicts. -The library must not be installed in the same directory as another Julia package compiled with `PackageCompiler.jl` as they would overwrite the package specific files in `share/julia`. +- The library is relocatable given the whole installation tree is moved, including libraries in the `lib/julia/` directory. +- It's advised to install the library in a separate directory to avoid possible conflicts. + The library must not be installed in the same directory as another Julia package compiled with `PackageCompiler.jl` as they would overwrite the package specific files in `share/julia`. From 2c409bf42064e9eff68162b59305b6bb05e4e4f0 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Thu, 20 Mar 2025 17:45:14 +0100 Subject: [PATCH 23/34] comment on minimal libstdc++ for julia 1.12 --- compile/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compile/README.md b/compile/README.md index 4f611454..b84c9b37 100644 --- a/compile/README.md +++ b/compile/README.md @@ -23,6 +23,10 @@ julia --project=compile compile/build.jl --output-dir JetReconstructionCompiled > > Packages compiled with `PackageCompiler.jl` will have `JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER` defined. Packages compiled with `juliac` will have `JETRECONSTRUCTION_COMPILER_JULIAC` defined. + +> [!CAUTION] +> Packages compiled with Julia 1.12 require GLIBCXX_3.4.30 (gcc 12.1.0) or later. + ## Usage example ### Example source file From b85b99042d3169c7382e42aed65b99b19a833ec1 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Mon, 24 Mar 2025 14:31:10 +0100 Subject: [PATCH 24/34] update readme --- compile/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compile/README.md b/compile/README.md index b84c9b37..70b77be8 100644 --- a/compile/README.md +++ b/compile/README.md @@ -21,6 +21,12 @@ julia --project=compile compile/build.jl --output-dir JetReconstructionCompiled > julia +1.12-nightly --project=compile compile/build.jl --juliac > ``` > +> or +> +> ```sh +> julia +nightly --project=compile compile/build.jl --juliac +> ``` +> > Packages compiled with `PackageCompiler.jl` will have `JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER` defined. Packages compiled with `juliac` will have `JETRECONSTRUCTION_COMPILER_JULIAC` defined. From 6cff5c4b11e9f26ef7955cdb5a7f5b3051469188 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Fri, 27 Jun 2025 15:35:39 +0200 Subject: [PATCH 25/34] remove constrain on JetReconstruction version in compile project --- compile/Project.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/compile/Project.toml b/compile/Project.toml index 44bce240..765f706e 100644 --- a/compile/Project.toml +++ b/compile/Project.toml @@ -7,5 +7,4 @@ PackageCompiler = "9b87118b-4619-50d2-8e1e-99f35a4d4d9d" JetReconstruction = {path = ".."} [compat] -JetReconstruction = "0.4" PackageCompiler = "2" From 8a108f203c995a360ea20622aa53fa586e7b5e94 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Wed, 2 Jul 2025 15:29:22 +0200 Subject: [PATCH 26/34] add cluster history index argument to pseudojet init --- compile/downstream/jetreconstruction_test.c | 4 ++-- compile/include/JetReconstruction.h.in | 3 ++- compile/precompile_execution.jl | 4 ++-- src/C_JetReconstruction/C_JetReconstruction.jl | 11 +++++++---- test/test-c-interface.jl | 4 ++-- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/compile/downstream/jetreconstruction_test.c b/compile/downstream/jetreconstruction_test.c index 1296b935..64f62189 100644 --- a/compile/downstream/jetreconstruction_test.c +++ b/compile/downstream/jetreconstruction_test.c @@ -60,9 +60,9 @@ int main(int argc, char *argv[]) { #endif size_t len = 2; jetreconstruction_PseudoJet particles[2]; - sc = jetreconstruction_PseudoJet_init(&particles[0], 0.0, 1.0, 2.0, 3.0); + sc = jetreconstruction_PseudoJet_init(&particles[0], 0.0, 1.0, 2.0, 3.0, 1); assert(sc == JETRECONSTRUCTION_STATUSCODE_OK); - sc = jetreconstruction_PseudoJet_init(&particles[1], 1.0, 2.0, 3.0, 4.0); + sc = jetreconstruction_PseudoJet_init(&particles[1], 1.0, 2.0, 3.0, 4.0, 2); assert(sc == JETRECONSTRUCTION_STATUSCODE_OK); jetreconstruction_JetAlgorithm algorithm = JETRECONSTRUCTION_JETALGORITHM_CA; diff --git a/compile/include/JetReconstruction.h.in b/compile/include/JetReconstruction.h.in index 01241827..34d83bc0 100644 --- a/compile/include/JetReconstruction.h.in +++ b/compile/include/JetReconstruction.h.in @@ -132,12 +132,13 @@ typedef struct { * @param[in] py The y-component of the momentum. * @param[in] pz The z-component of the momentum. * @param[in] E The energy component of the momentum. + * @param[in] cluter_hist_index The index of the cluster history. * @return An integer status code indicating the success or failure. See common * status codes jetreconstruction_StatusCode. */ jetreconstruction_StatusCode jetreconstruction_PseudoJet_init(jetreconstruction_PseudoJet *ptr, double px, - double py, double pz, double E); + double py, double pz, double E, long cluter_hist_index); /** * @struct jetreconstruction_HistoryElement diff --git a/compile/precompile_execution.jl b/compile/precompile_execution.jl index 655cfa47..ad2429f2 100644 --- a/compile/precompile_execution.jl +++ b/compile/precompile_execution.jl @@ -29,9 +29,9 @@ clustersequence_ptr = Ptr{C_ClusterSequence{PseudoJet}}(Libc.malloc(sizeof(C_Clu results_ptr = Ptr{C_JetsResult{PseudoJet}}(Libc.malloc(sizeof(C_JetsResult{PseudoJet}))) @assert results_ptr != C_NULL -assert_ok(jetreconstruction_PseudoJet_init(jets_ptr, 0.0, 1.0, 2.0, 3.0)) +assert_ok(jetreconstruction_PseudoJet_init(jets_ptr, 0.0, 1.0, 2.0, 3.0, 1)) assert_ok(jetreconstruction_PseudoJet_init(jets_ptr + sizeof(PseudoJet), 1.0, 2.0, 3.0, - 4.0)) + 4.0, 2)) for algorithm in [JetAlgorithm.AntiKt, JetAlgorithm.CA, JetAlgorithm.Kt] for strategy in [RecoStrategy.N2Plain, RecoStrategy.N2Tiled, RecoStrategy.Best] diff --git a/src/C_JetReconstruction/C_JetReconstruction.jl b/src/C_JetReconstruction/C_JetReconstruction.jl index 496d77c8..e5635154 100644 --- a/src/C_JetReconstruction/C_JetReconstruction.jl +++ b/src/C_JetReconstruction/C_JetReconstruction.jl @@ -119,8 +119,9 @@ function make_c_array(v::Vector{T}) where {T} end """ - jetreconstruction_PseudoJet_init(ptr::Ptr{PseudoJet}, px::Cdouble, py::Cdouble, pz::Cdouble, E::Cdouble) -> Cint - + jetreconstruction_PseudoJet_init(ptr::Ptr{PseudoJet}, px::Cdouble, + py::Cdouble, pz::Cdouble, + E::Cdouble, cluster_hist_index::Clong) -> Cint C-binding for `PseudoJet` initialization. # Arguments @@ -129,6 +130,7 @@ C-binding for `PseudoJet` initialization. - `py::Cdouble`: The y-component of the momentum. - `pz::Cdouble`: The z-component of the momentum. - `E::Cdouble`: The energy of the jet. +- `cluster_hist_index::Clong`: The index of the cluster history. # Returns - `Cint`: An integer status code indicating the success or failure. @@ -136,9 +138,10 @@ C-binding for `PseudoJet` initialization. """ Base.@ccallable function jetreconstruction_PseudoJet_init(ptr::Ptr{PseudoJet}, px::Cdouble, py::Cdouble, pz::Cdouble, - E::Cdouble)::Cint + E::Cdouble, + cluster_hist_index::Clong)::Cint try - pseudojet = PseudoJet(px, py, pz, E) + pseudojet = PseudoJet(px, py, pz, E; cluster_hist_index = cluster_hist_index) unsafe_store!(ptr, pseudojet) catch e return handle_exception(e) diff --git a/test/test-c-interface.jl b/test/test-c-interface.jl index 24e7e145..88aab827 100644 --- a/test/test-c-interface.jl +++ b/test/test-c-interface.jl @@ -41,10 +41,10 @@ end function test_pseudojet() ptr = Ptr{PseudoJet}(Libc.malloc(sizeof(PseudoJet))) @test ptr != C_NULL - ret = C_JetReconstruction.jetreconstruction_PseudoJet_init(ptr, 0.1, 0.2, 0.3, 1.0) + ret = C_JetReconstruction.jetreconstruction_PseudoJet_init(ptr, 0.1, 0.2, 0.3, 1.0, 1) @test C_JetReconstruction.StatusCode.T(ret) == C_JetReconstruction.StatusCode.OK c_jet = unsafe_load(ptr) - jet = PseudoJet(0.1, 0.2, 0.3, 1.0) + jet = PseudoJet(0.1, 0.2, 0.3, 1.0; cluster_hist_index = 1) struct_approx_equal(jet, c_jet) end From 4aad538df59fc42139e92bbddf8141d0838836b5 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Wed, 2 Jul 2025 15:45:31 +0200 Subject: [PATCH 27/34] use batch memory operations --- .../C_JetReconstruction.jl | 41 +++---------------- test/test-c-interface.jl | 11 +++-- 2 files changed, 11 insertions(+), 41 deletions(-) diff --git a/src/C_JetReconstruction/C_JetReconstruction.jl b/src/C_JetReconstruction/C_JetReconstruction.jl index e5635154..4e435f87 100644 --- a/src/C_JetReconstruction/C_JetReconstruction.jl +++ b/src/C_JetReconstruction/C_JetReconstruction.jl @@ -59,38 +59,10 @@ exception_to_enum(::UndefRefError) = Cint(StatusCode.UndefRefError) exception_to_enum(::UndefVarError) = Cint(StatusCode.UndefVarError) exception_to_enum(::StringIndexError) = Cint(StatusCode.StringIndexError) -""" - unsafe_wrap_c_array(ptr::Ptr{T}, array_length::Csize_t) where {T} - -Wraps a C array into a Julia `Vector` for both bits and non-bits types. - -# Arguments -- `ptr::Ptr{T}`: A pointer to the C array. -- `array_length::Csize_t`: The length of the C array. - -# Returns -- A Julia `Vector{T}` containing the elements of the C array. - -# Safety -This function use 'unsafe' methods and has undefined behaviour -if pointer isn't valid or length isn't correct. -""" -function unsafe_wrap_c_array(ptr::Ptr{T}, array_length::Csize_t) where {T} - if isbitstype(T) - return unsafe_wrap(Vector{T}, ptr, array_length) - end - - vec = Vector{T}(undef, array_length) - for i in eachindex(vec) - @inbounds vec[i] = unsafe_load(ptr, i) - end - return vec -end - """ make_c_array(v::Vector{T}) where {T} -Helper function for converting a Julia vector to a C-style array. +Helper function for converting a Julia vector of isbits objects to a C-style array. A C-style array is dynamically allocated and contents of input vector copied to it. # Arguments @@ -105,6 +77,7 @@ A C-style array is dynamically allocated and contents of input vector copied to # Notes - The caller is responsible for freeing the allocated memory using `Libc.free(ptr)`. +- The `T` type must be an isbits type. """ function make_c_array(v::Vector{T}) where {T} len = length(v) @@ -112,9 +85,7 @@ function make_c_array(v::Vector{T}) where {T} if ptr == C_NULL throw(OutOfMemoryError("Libc.malloc failed to allocate memory")) end - for i in 1:len - @inbounds unsafe_store!(ptr, v[i], i) - end + unsafe_copyto!(ptr, pointer(v), len) return ptr, Csize_t(len) end @@ -217,8 +188,8 @@ Convert a `C_ClusterSequence` object to a `ClusterSequence` object. - The input object must remain valid while the output object is used. """ function ClusterSequence{T}(c::C_ClusterSequence{T}) where {T} - jets_v = unsafe_wrap_c_array(c.jets, c.jets_length) - history_v = unsafe_wrap_c_array(c.history, c.history_length) + jets_v = unsafe_wrap(Vector{T}, c.jets, c.jets_length) + history_v = unsafe_wrap(Vector{HistoryElement}, c.history, c.history_length) return ClusterSequence{T}(c.algorithm, c.power, c.R, c.strategy, jets_v, c.n_initial_jets, history_v, c.Qtot) @@ -279,7 +250,7 @@ function c_jet_reconstruct(particles::Ptr{T}, strategy::RecoStrategy.Strategy, result::Ptr{C_ClusterSequence{U}}) where {T, U} try - particles_v = unsafe_wrap_c_array(particles, particles_length) + particles_v = unsafe_wrap(Vector{T}, particles, particles_length) clusterseq = jet_reconstruct(particles_v; p = nothing, algorithm = algorithm, R = R, strategy = strategy) c_clusterseq = C_ClusterSequence{U}(clusterseq) diff --git a/test/test-c-interface.jl b/test/test-c-interface.jl index 88aab827..fd8df4e2 100644 --- a/test/test-c-interface.jl +++ b/test/test-c-interface.jl @@ -17,13 +17,13 @@ function compare_results(ptr::Ptr{C_JetReconstruction.C_ClusterSequence{T}}, @test c_cluster_seq.R ≈ cluster_seq.R @test c_cluster_seq.strategy == cluster_seq.strategy @test c_cluster_seq.jets_length == length(cluster_seq.jets) - c_jets = C_JetReconstruction.unsafe_wrap_c_array(c_cluster_seq.jets, - c_cluster_seq.jets_length) + c_jets = unsafe_wrap(Vector{T}, c_cluster_seq.jets, + c_cluster_seq.jets_length) @test all(struct_approx_equal.(c_jets, cluster_seq.jets)) @test c_cluster_seq.n_initial_jets == cluster_seq.n_initial_jets @test c_cluster_seq.history_length == length(cluster_seq.history) - c_history = C_JetReconstruction.unsafe_wrap_c_array(c_cluster_seq.history, - c_cluster_seq.history_length) + c_history = unsafe_wrap(Vector{JetReconstruction.HistoryElement}, c_cluster_seq.history, + c_cluster_seq.history_length) @test all(struct_approx_equal.(c_history, cluster_seq.history)) @test c_cluster_seq.Qtot ≈ cluster_seq.Qtot end @@ -33,8 +33,7 @@ function compare_results(ptr::Ptr{C_JetReconstruction.C_JetsResult{T}}, @test ptr != C_NULL c_results = unsafe_load(ptr) @test c_results.length == length(jets) - c_data = C_JetReconstruction.unsafe_wrap_c_array(c_results.data, - c_results.length) + c_data = unsafe_wrap(Vector{T}, c_results.data, c_results.length) @test all(struct_approx_equal.(c_data, jets)) end From c33ff08cbd63defbd80c22a0b928641d301671c3 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Wed, 2 Jul 2025 16:37:06 +0200 Subject: [PATCH 28/34] add recombination schemes to C-bindings --- compile/README.md | 7 ++-- compile/downstream/jetreconstruction_test.c | 6 ++- compile/include/JetReconstruction.h.in | 17 +++++++- compile/precompile_execution.jl | 42 +++++++++++-------- .../C_JetReconstruction.jl | 21 +++++++--- test/test-c-interface.jl | 8 +++- 6 files changed, 69 insertions(+), 32 deletions(-) diff --git a/compile/README.md b/compile/README.md index 70b77be8..9249c752 100644 --- a/compile/README.md +++ b/compile/README.md @@ -61,11 +61,12 @@ int main(int argc, char *argv[]) { jetreconstruction_JetAlgorithm algorithm = JETRECONSTRUCTION_JETALGORITHM_CA; double R = 3.0; jetreconstruction_RecoStrategy strategy = JETRECONSTRUCTION_RECOSTRATEGY_BEST; + jetreconstruction_RecombinationScheme recombination = JETRECONCSTRUCTION_RECOMBINATIONSCHEME_ESCHEME; jetreconstruction_ClusterSequence cluster_seq; - int ret = jetreconstruction_jet_reconstruct(particles, len, algorithm, R, strategy, - &cluster_seq); - if (ret != JETRECONSTRUCTION_STATUSCODE_OK){ + jetreconstruction_StatusCode sc = jetreconstruction_jet_reconstruct(particles, len, algorithm, R, + strategy, recombination, &cluster_seq); + if (sc != JETRECONSTRUCTION_STATUSCODE_OK){ /*An error occurred check the value or stderr for more information*/ return 1; } diff --git a/compile/downstream/jetreconstruction_test.c b/compile/downstream/jetreconstruction_test.c index 64f62189..a4f33873 100644 --- a/compile/downstream/jetreconstruction_test.c +++ b/compile/downstream/jetreconstruction_test.c @@ -54,7 +54,7 @@ void printJetsResult(const jetreconstruction_JetsResult *results) { int main(int argc, char *argv[]) { clock_t start_time = clock(); - int sc = 0; + jetreconstruction_StatusCode sc = 0; #ifdef JETRECONSTRUCTION_COMPILER_PACKAGECOMPILER init_julia(0, NULL); #endif @@ -68,10 +68,12 @@ int main(int argc, char *argv[]) { jetreconstruction_JetAlgorithm algorithm = JETRECONSTRUCTION_JETALGORITHM_CA; double R = 3.0; jetreconstruction_RecoStrategy strategy = JETRECONSTRUCTION_RECOSTRATEGY_BEST; + jetreconstruction_RecombinationScheme recombination = + JETRECONCSTRUCTION_RECOMBINATIONSCHEME_ESCHEME; jetreconstruction_ClusterSequence cluster_seq; sc = jetreconstruction_jet_reconstruct(particles, len, algorithm, R, strategy, - &cluster_seq); + recombination, &cluster_seq); assert(sc == JETRECONSTRUCTION_STATUSCODE_OK); printClusterSequence(&cluster_seq); diff --git a/compile/include/JetReconstruction.h.in b/compile/include/JetReconstruction.h.in index 34d83bc0..def2b3e2 100644 --- a/compile/include/JetReconstruction.h.in +++ b/compile/include/JetReconstruction.h.in @@ -103,6 +103,17 @@ typedef enum { JETRECONSTRUCTION_RECOSTRATEGY_N2TILTED = 2 /**< The tiled N2 strategy. */ } jetreconstruction_RecoStrategy; +/** + * @enum jetreconstruction_RecombinationScheme + * @brief Enumeration representing the different recombination schemes used in + * jet reconstruction. + */ +typedef enum { + JETRECONCSTRUCTION_RECOMBINATIONSCHEME_ESCHEME = 0, + JETRECONCSTRUCTION_RECOMBINATIONSCHEME_PTSCHEME = 1, + JETRECONCSTRUCTION_RECOMBINATIONSCHEME_PT2SCHEME = 2, +} jetreconstruction_RecombinationScheme; + /** * @struct jetreconstruction_PseudoJet * @brief A struct representing a pseudojet, a four-momentum object used in @@ -138,7 +149,8 @@ typedef struct { */ jetreconstruction_StatusCode jetreconstruction_PseudoJet_init(jetreconstruction_PseudoJet *ptr, double px, - double py, double pz, double E, long cluter_hist_index); + double py, double pz, double E, + long cluter_hist_index); /** * @struct jetreconstruction_HistoryElement @@ -235,6 +247,8 @@ static inline void jetreconstruction_ClusterSequence_free_members( * @param[in] algorithm The algorithm to use for jet reconstruction. * @param[in] R The jet radius parameter. * @param[in] strategy The jet reconstruction strategy to use. + * @param[in] recombination_scheme The recombination scheme used for combining + * particles. * @param[out] result A pointer to which a cluster sequence containing the * reconstructed jets and the merging history will be stored. * @return An integer status code indicating the success or failure. See common @@ -244,6 +258,7 @@ jetreconstruction_StatusCode jetreconstruction_jet_reconstruct( const jetreconstruction_PseudoJet *particles, size_t particles_length, jetreconstruction_JetAlgorithm algorithm, double R, jetreconstruction_RecoStrategy strategy, + jetreconstruction_RecombinationScheme recombination_scheme, jetreconstruction_ClusterSequence *result); /** diff --git a/compile/precompile_execution.jl b/compile/precompile_execution.jl index ad2429f2..b61d477f 100644 --- a/compile/precompile_execution.jl +++ b/compile/precompile_execution.jl @@ -1,7 +1,7 @@ # Dummy code to call and cache compilation of all C-bindings # The numeric values don't make sense and are used only to select correct dispatch -using JetReconstruction: PseudoJet, RecoStrategy, JetAlgorithm +using JetReconstruction: PseudoJet, RecoStrategy, JetAlgorithm, RecombinationScheme using JetReconstruction.C_JetReconstruction: jetreconstruction_PseudoJet_init, C_ClusterSequence, jetreconstruction_ClusterSequence_free_members_, @@ -33,27 +33,33 @@ assert_ok(jetreconstruction_PseudoJet_init(jets_ptr, 0.0, 1.0, 2.0, 3.0, 1)) assert_ok(jetreconstruction_PseudoJet_init(jets_ptr + sizeof(PseudoJet), 1.0, 2.0, 3.0, 4.0, 2)) -for algorithm in [JetAlgorithm.AntiKt, JetAlgorithm.CA, JetAlgorithm.Kt] - for strategy in [RecoStrategy.N2Plain, RecoStrategy.N2Tiled, RecoStrategy.Best] - assert_ok(jetreconstruction_jet_reconstruct(jets_ptr, jets_len, algorithm, R, - strategy, - clustersequence_ptr)) +for algorithm in [JetAlgorithm.AntiKt, JetAlgorithm.CA, JetAlgorithm.Kt], + strategy in [RecoStrategy.N2Plain, RecoStrategy.N2Tiled, RecoStrategy.Best], + recombination in [ + RecombinationScheme.EScheme, + RecombinationScheme.PtScheme, + RecombinationScheme.Pt2Scheme + ] - assert_ok(jetreconstruction_inclusive_jets(clustersequence_ptr, 0.0, results_ptr)) - jetreconstruction_JetsResult_free_members_(results_ptr) + assert_ok(jetreconstruction_jet_reconstruct(jets_ptr, jets_len, algorithm, R, + strategy, recombination, + clustersequence_ptr)) + + assert_ok(jetreconstruction_inclusive_jets(clustersequence_ptr, 0.0, + results_ptr)) + jetreconstruction_JetsResult_free_members_(results_ptr) - if algorithm != JetAlgorithm.AntiKt - assert_ok(jetreconstruction_exclusive_jets_njets(clustersequence_ptr, - Csize_t(2), - results_ptr)) - jetreconstruction_JetsResult_free_members_(results_ptr) + if algorithm != JetAlgorithm.AntiKt + assert_ok(jetreconstruction_exclusive_jets_njets(clustersequence_ptr, + Csize_t(2), + results_ptr)) + jetreconstruction_JetsResult_free_members_(results_ptr) - assert_ok(jetreconstruction_exclusive_jets_dcut(clustersequence_ptr, 1.0, - results_ptr)) - jetreconstruction_JetsResult_free_members_(results_ptr) + assert_ok(jetreconstruction_exclusive_jets_dcut(clustersequence_ptr, 1.0, + results_ptr)) + jetreconstruction_JetsResult_free_members_(results_ptr) - jetreconstruction_ClusterSequence_free_members_(clustersequence_ptr) - end + jetreconstruction_ClusterSequence_free_members_(clustersequence_ptr) end end Libc.free(jets_ptr) diff --git a/src/C_JetReconstruction/C_JetReconstruction.jl b/src/C_JetReconstruction/C_JetReconstruction.jl index 4e435f87..64c7d744 100644 --- a/src/C_JetReconstruction/C_JetReconstruction.jl +++ b/src/C_JetReconstruction/C_JetReconstruction.jl @@ -3,9 +3,10 @@ Minimal C bindings for JetReconstruction.jl """ module C_JetReconstruction -using ..JetReconstruction: JetAlgorithm, RecoStrategy, PseudoJet, ClusterSequence, - HistoryElement, jet_reconstruct, - exclusive_jets, inclusive_jets +using ..JetReconstruction: JetAlgorithm, RecoStrategy, + RecombinationScheme, RecombinationMethods, + PseudoJet, ClusterSequence, HistoryElement, + jet_reconstruct, exclusive_jets, inclusive_jets using EnumX """ @@ -225,6 +226,7 @@ end algorithm::JetAlgorithm.Algorithm, R::Cdouble, strategy::RecoStrategy.Strategy, + recombination_scheme::RecombinationScheme.Recombine, result::Ptr{C_ClusterSequence{U}})::Cint where {T, U} Internal helper functions for calling `jet_reconstruct` with C-compatible data-structers. @@ -233,8 +235,9 @@ Internal helper functions for calling `jet_reconstruct` with C-compatible data-s - `particles::Ptr{T}`: Pointer to an array of pseudojet objects used for jet reconstruction. - `particles_length::Csize_t`: The length of `particles`` array. - `algorithm::JetAlgorithm.Algorithm`: The algorithm to use for jet reconstruction. -- `R::Cdouble`: The jet radius parameter.. +- `R::Cdouble`: The jet radius parameter. - `strategy::RecoStrategy.Strategy`: The jet reconstruction strategy to use. +- `recombination_scheme::RecombinationScheme.Recombine`: The recombination scheme used for combining particles. - `result::Ptr{C_ClusterSequence{U}}`: A pointer to which a cluster sequence containing the reconstructed jets and the merging history will be stored. # Returns @@ -248,11 +251,13 @@ function c_jet_reconstruct(particles::Ptr{T}, algorithm::JetAlgorithm.Algorithm, R::Cdouble, strategy::RecoStrategy.Strategy, + recombination_scheme::RecombinationScheme.Recombine, result::Ptr{C_ClusterSequence{U}}) where {T, U} try particles_v = unsafe_wrap(Vector{T}, particles, particles_length) clusterseq = jet_reconstruct(particles_v; p = nothing, algorithm = algorithm, R = R, - strategy = strategy) + strategy = strategy, + RecombinationMethods[recombination_scheme]...) c_clusterseq = C_ClusterSequence{U}(clusterseq) unsafe_store!(result, c_clusterseq) catch e @@ -267,6 +272,7 @@ end algorithm::JetAlgorithm.Algorithm, R::Cdouble, strategy::RecoStrategy.Strategy, + recombination_scheme::RecombinationScheme.Recombine, result::Ptr{C_ClusterSequence{PseudoJet}})::Cint C-binding for `jet_reconstruct`. @@ -277,6 +283,7 @@ C-binding for `jet_reconstruct`. - `algorithm::JetAlgorithm.Algorithm`: The algorithm to use for jet reconstruction. - `R::Cdouble`: The jet radius parameter.. - `strategy::RecoStrategy.Strategy`: The jet reconstruction strategy to use. +- `recombination_scheme::RecombinationScheme.Recombine`: The recombination scheme used for combining particles. - `result::Ptr{C_ClusterSequence{PseudoJet}}`: A pointer to which a cluster sequence containing the reconstructed jets and the merging history will be stored. # Returns @@ -290,8 +297,10 @@ Base.@ccallable function jetreconstruction_jet_reconstruct(particles::Ptr{Pseudo algorithm::JetAlgorithm.Algorithm, R::Cdouble, strategy::RecoStrategy.Strategy, + recombination_scheme::RecombinationScheme.Recombine, result::Ptr{C_ClusterSequence{PseudoJet}})::Cint - return c_jet_reconstruct(particles, particles_length, algorithm, R, strategy, result) + return c_jet_reconstruct(particles, particles_length, algorithm, R, strategy, + recombination_scheme, result) end """ diff --git a/test/test-c-interface.jl b/test/test-c-interface.jl index fd8df4e2..db818196 100644 --- a/test/test-c-interface.jl +++ b/test/test-c-interface.jl @@ -47,7 +47,7 @@ function test_pseudojet() struct_approx_equal(jet, c_jet) end -function test_jet_reconstruct(filename; algorithm, R, strategy, power = nothing, +function test_jet_reconstruct(filename; algorithm, R, strategy, recombine, power = nothing, T = PseudoJet) @testset "C-interface jet reconstruct" begin events = JetReconstruction.read_final_state_particles(filename) @@ -64,13 +64,15 @@ function test_jet_reconstruct(filename; algorithm, R, strategy, power = nothing, algorithm, R, strategy, + recombine, cluster_seq_ptr) @test C_JetReconstruction.StatusCode.T(ret) == C_JetReconstruction.StatusCode.OK cluster_seq = JetReconstruction.jet_reconstruct(event; R = R, p = power, algorithm = algorithm, - strategy = strategy) + strategy = strategy, + RecombinationMethods[recombine]...) compare_results(cluster_seq_ptr, cluster_seq) @inbounds results[ievent] = cluster_seq @inbounds c_results[ievent] = cluster_seq_ptr @@ -136,6 +138,7 @@ end @testset "C-interface JetReconstruction pp" begin test_cone_size = 0.4 + test_recombine_scheme = RecombinationScheme.EScheme test_pseudojet() @@ -147,6 +150,7 @@ end cluster_seq_ptrs, cluster_seqs = test_jet_reconstruct(events_file_pp; algorithm = alg, strategy = stg, + recombine = test_recombine_scheme, R = test_cone_size, power = power) test_inclusive_jets(cluster_seq_ptrs, cluster_seqs; ptmin = 5.0) From 48d975d4a598c9ad077a1ae2dfb5c99514fc6a8c Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Thu, 3 Jul 2025 12:45:30 +0200 Subject: [PATCH 29/34] update docs, fix typos, use workaround for Julia 1.10 docstrings for ccallable functions --- .../JetReconstructionConfig.cmake.in | 2 +- .../C_JetReconstruction.jl | 47 +++++++++++++------ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/compile/cmake/JetReconstruction/JetReconstructionConfig.cmake.in b/compile/cmake/JetReconstruction/JetReconstructionConfig.cmake.in index 310c1a62..4a875a88 100644 --- a/compile/cmake/JetReconstruction/JetReconstructionConfig.cmake.in +++ b/compile/cmake/JetReconstruction/JetReconstructionConfig.cmake.in @@ -1,5 +1,5 @@ # Config file for the JetReconstruction.jl package -# Manualy adjusted from standard cmake generated config file +# Manually adjusted from standard cmake generated config file set(JETRECONSTRUCTION_COMPILER "@JETRECONSTRUCTION_COMPILER@") diff --git a/src/C_JetReconstruction/C_JetReconstruction.jl b/src/C_JetReconstruction/C_JetReconstruction.jl index 64c7d744..5eacb683 100644 --- a/src/C_JetReconstruction/C_JetReconstruction.jl +++ b/src/C_JetReconstruction/C_JetReconstruction.jl @@ -90,7 +90,8 @@ function make_c_array(v::Vector{T}) where {T} return ptr, Csize_t(len) end -""" +# Workaround for Julia 1.10 not accepting docstrings together with `@ccallable` +@doc """ jetreconstruction_PseudoJet_init(ptr::Ptr{PseudoJet}, px::Cdouble, py::Cdouble, pz::Cdouble, E::Cdouble, cluster_hist_index::Clong) -> Cint @@ -104,10 +105,14 @@ C-binding for `PseudoJet` initialization. - `E::Cdouble`: The energy of the jet. - `cluster_hist_index::Clong`: The index of the cluster history. +# Note + For an array of initial jets the `cluster_hist_index` should be 1+index of the jet in an array. + # Returns - `Cint`: An integer status code indicating the success or failure. -""" +""" jetreconstruction_PseudoJet_init + Base.@ccallable function jetreconstruction_PseudoJet_init(ptr::Ptr{PseudoJet}, px::Cdouble, py::Cdouble, pz::Cdouble, E::Cdouble, @@ -156,7 +161,8 @@ function free_members(ptr::Ptr{C_ClusterSequence{T}}) where {T} end end -""" +# Workaround for Julia 1.10 not accepting docstrings together with `@ccallable` +@doc """ jetreconstruction_ClusterSequence_free_members_(ptr::Ptr{C_ClusterSequence{PseudoJet}}) -> Cvoid C-binding for freeing the members of a `C_ClusterSequence` object pointed to by `ptr`. @@ -166,7 +172,8 @@ C-binding for freeing the members of a `C_ClusterSequence` object pointed to by # Returns - `Cvoid`: This function does not return a value. -""" +""" jetreconstruction_ClusterSequence_free_members_ + Base.@ccallable function jetreconstruction_ClusterSequence_free_members_(ptr::Ptr{C_ClusterSequence{PseudoJet}})::Cvoid free_members(ptr) return nothing @@ -229,7 +236,7 @@ end recombination_scheme::RecombinationScheme.Recombine, result::Ptr{C_ClusterSequence{U}})::Cint where {T, U} -Internal helper functions for calling `jet_reconstruct` with C-compatible data-structers. +Internal helper functions for calling `jet_reconstruct` with C-compatible data-structures. # Arguments - `particles::Ptr{T}`: Pointer to an array of pseudojet objects used for jet reconstruction. @@ -266,7 +273,8 @@ function c_jet_reconstruct(particles::Ptr{T}, return Cint(StatusCode.OK) end -""" +# Workaround for Julia 1.10 not accepting docstrings together with `@ccallable` +@doc """ jetreconstruction_jet_reconstruct(particles::Ptr{PseudoJet}, particles_length::Csize_t, algorithm::JetAlgorithm.Algorithm, @@ -291,7 +299,8 @@ C-binding for `jet_reconstruct`. # Notes - To avoid memory leaks the memory allocated for members of `result` should be freed with `jetreconstruction_ClusterSequence_free_members_`. -""" +""" jetreconstruction_jet_reconstruct + Base.@ccallable function jetreconstruction_jet_reconstruct(particles::Ptr{PseudoJet}, particles_length::Csize_t, algorithm::JetAlgorithm.Algorithm, @@ -333,7 +342,8 @@ function free_members(ptr::Ptr{C_JetsResult{T}}) where {T} end end -""" +# Workaround for Julia 1.10 not accepting docstrings together with `@ccallable` +@doc """ jetreconstruction_JetsResult_free_members_(ptr::Ptr{C_JetsResult{PseudoJet}})::Cvoid C-binding for freeing the members of a `C_JetsResult{PseudoJet}` object pointed to by `ptr`. @@ -343,7 +353,8 @@ C-binding for freeing the members of a `C_JetsResult{PseudoJet}` object pointed # Returns - `Cvoid`: This function does not return any value. -""" +""" jetreconstruction_JetsResult_free_members_ + Base.@ccallable function jetreconstruction_JetsResult_free_members_(ptr::Ptr{C_JetsResult{PseudoJet}})::Cvoid free_members(ptr) return nothing @@ -378,7 +389,8 @@ function jets_selection(selector, clustersequence::Ptr{C_ClusterSequence{T}}, return Cint(StatusCode.OK) end -""" +# Workaround for Julia 1.10 not accepting docstrings together with `@ccallable` +@doc """ jetreconstruction_exclusive_jets_dcut(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, dcut::Cdouble, result::Ptr{C_JetsResult{PseudoJet}}) -> Cint @@ -395,14 +407,16 @@ C-binding for `exclusive_jets` with a cut on the maximum distance parameter. # Notes - To avoid memory leaks the memory allocated for members of `result` should be freed with `jetreconstruction_JetsResult_free_members_`. -""" +""" jetreconstruction_exclusive_jets_dcut + Base.@ccallable function jetreconstruction_exclusive_jets_dcut(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, dcut::Cdouble, result::Ptr{C_JetsResult{PseudoJet}})::Cint return jets_selection(exclusive_jets, clustersequence, result; dcut = dcut) end -""" +# Workaround for Julia 1.10 not accepting docstrings together with `@ccallable` +@doc """ jetreconstruction_exclusive_jets_njets(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, njets::Csize_t, result::Ptr{C_JetsResult{PseudoJet}}) -> Cint @@ -419,14 +433,16 @@ C-binding for `exclusive_jets` with a specific number of jets. # Notes - To avoid memory leaks the memory allocated for members of `result` should be freed with `jetreconstruction_JetsResult_free_members_`. -""" +""" jetreconstruction_exclusive_jets_njets + Base.@ccallable function jetreconstruction_exclusive_jets_njets(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, njets::Csize_t, result::Ptr{C_JetsResult{PseudoJet}})::Cint return jets_selection(exclusive_jets, clustersequence, result; njets = njets) end -""" +# Workaround for Julia 1.10 not accepting docstrings together with `@ccallable` +@doc """ jetreconstruction_inclusive_jets(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, ptmin::Cdouble, result::Ptr{C_JetsResult{PseudoJet}}) -> Cint @@ -443,7 +459,8 @@ C-binding for `inclusive_jets`. # Notes - To avoid memory leaks the memory allocated for members of `result` should be freed with `jetreconstruction_JetsResult_free_members_`. -""" +""" jetreconstruction_inclusive_jets + Base.@ccallable function jetreconstruction_inclusive_jets(clustersequence::Ptr{C_ClusterSequence{PseudoJet}}, ptmin::Cdouble, result::Ptr{C_JetsResult{PseudoJet}})::Cint From 1292f1f24316989f44123c7fdeedbfbdc36da668 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Thu, 3 Jul 2025 22:39:25 +0200 Subject: [PATCH 30/34] add downstream project gitignore --- compile/downstream/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 compile/downstream/.gitignore diff --git a/compile/downstream/.gitignore b/compile/downstream/.gitignore new file mode 100644 index 00000000..d1638636 --- /dev/null +++ b/compile/downstream/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file From 3c2481ff3e210e87258e1810534148cca245dfda Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Thu, 3 Jul 2025 22:52:04 +0200 Subject: [PATCH 31/34] prevent breaking cmake substitution with clang-format --- compile/include/JetReconstruction.h.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compile/include/JetReconstruction.h.in b/compile/include/JetReconstruction.h.in index def2b3e2..e0089a4e 100644 --- a/compile/include/JetReconstruction.h.in +++ b/compile/include/JetReconstruction.h.in @@ -21,8 +21,10 @@ extern "C" { #include +/* clang-format off */ /** Compiler used to compiler JetReconstruction.jl package */ #define @JETRECONSTRUCTION_COMPILER@ 1 +/* clang-format on */ /*Special states in a history.*/ From c16cdef937dcd825ebf662629eb836dbecdd4f48 Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Fri, 4 Jul 2025 15:20:15 +0200 Subject: [PATCH 32/34] add support for GenKt --- compile/README.md | 3 ++- compile/downstream/jetreconstruction_test.c | 5 +++-- compile/include/JetReconstruction.h.in | 5 ++++- compile/precompile_execution.jl | 5 +++-- src/C_JetReconstruction/C_JetReconstruction.jl | 12 +++++++++--- test/test-c-interface.jl | 11 ++++++----- 6 files changed, 27 insertions(+), 14 deletions(-) diff --git a/compile/README.md b/compile/README.md index 9249c752..3ae025b4 100644 --- a/compile/README.md +++ b/compile/README.md @@ -60,11 +60,12 @@ int main(int argc, char *argv[]) { /*Call jet reconstruction*/ jetreconstruction_JetAlgorithm algorithm = JETRECONSTRUCTION_JETALGORITHM_CA; double R = 3.0; + double power = 0.0; jetreconstruction_RecoStrategy strategy = JETRECONSTRUCTION_RECOSTRATEGY_BEST; jetreconstruction_RecombinationScheme recombination = JETRECONCSTRUCTION_RECOMBINATIONSCHEME_ESCHEME; jetreconstruction_ClusterSequence cluster_seq; - jetreconstruction_StatusCode sc = jetreconstruction_jet_reconstruct(particles, len, algorithm, R, + jetreconstruction_StatusCode sc = jetreconstruction_jet_reconstruct(particles, len, algorithm, power, R, strategy, recombination, &cluster_seq); if (sc != JETRECONSTRUCTION_STATUSCODE_OK){ /*An error occurred check the value or stderr for more information*/ diff --git a/compile/downstream/jetreconstruction_test.c b/compile/downstream/jetreconstruction_test.c index a4f33873..e3b82368 100644 --- a/compile/downstream/jetreconstruction_test.c +++ b/compile/downstream/jetreconstruction_test.c @@ -65,14 +65,15 @@ int main(int argc, char *argv[]) { sc = jetreconstruction_PseudoJet_init(&particles[1], 1.0, 2.0, 3.0, 4.0, 2); assert(sc == JETRECONSTRUCTION_STATUSCODE_OK); - jetreconstruction_JetAlgorithm algorithm = JETRECONSTRUCTION_JETALGORITHM_CA; + jetreconstruction_JetAlgorithm algorithm = JETRECONSTRUCTION_JETALGORITHM_GENKT; double R = 3.0; + double power = 0.5; jetreconstruction_RecoStrategy strategy = JETRECONSTRUCTION_RECOSTRATEGY_BEST; jetreconstruction_RecombinationScheme recombination = JETRECONCSTRUCTION_RECOMBINATIONSCHEME_ESCHEME; jetreconstruction_ClusterSequence cluster_seq; - sc = jetreconstruction_jet_reconstruct(particles, len, algorithm, R, strategy, + sc = jetreconstruction_jet_reconstruct(particles, len, algorithm, power, R, strategy, recombination, &cluster_seq); assert(sc == JETRECONSTRUCTION_STATUSCODE_OK); diff --git a/compile/include/JetReconstruction.h.in b/compile/include/JetReconstruction.h.in index e0089a4e..dd86e814 100644 --- a/compile/include/JetReconstruction.h.in +++ b/compile/include/JetReconstruction.h.in @@ -247,6 +247,9 @@ static inline void jetreconstruction_ClusterSequence_free_members( * reconstruction. * @param[in] particles_length The length of @p particles array. * @param[in] algorithm The algorithm to use for jet reconstruction. + * @param[in] power The power value used for the distance measure for + * generalised k_T algorithms (GenKt, EEKt). Other algorithms will ignore this + * value. * @param[in] R The jet radius parameter. * @param[in] strategy The jet reconstruction strategy to use. * @param[in] recombination_scheme The recombination scheme used for combining @@ -258,7 +261,7 @@ static inline void jetreconstruction_ClusterSequence_free_members( */ jetreconstruction_StatusCode jetreconstruction_jet_reconstruct( const jetreconstruction_PseudoJet *particles, size_t particles_length, - jetreconstruction_JetAlgorithm algorithm, double R, + jetreconstruction_JetAlgorithm algorithm, double power, double R, jetreconstruction_RecoStrategy strategy, jetreconstruction_RecombinationScheme recombination_scheme, jetreconstruction_ClusterSequence *result); diff --git a/compile/precompile_execution.jl b/compile/precompile_execution.jl index b61d477f..673cdfbd 100644 --- a/compile/precompile_execution.jl +++ b/compile/precompile_execution.jl @@ -19,6 +19,7 @@ end R = 2.0 jets_len = Csize_t(2) +power = 0.5 ### pp jets ### @@ -33,7 +34,7 @@ assert_ok(jetreconstruction_PseudoJet_init(jets_ptr, 0.0, 1.0, 2.0, 3.0, 1)) assert_ok(jetreconstruction_PseudoJet_init(jets_ptr + sizeof(PseudoJet), 1.0, 2.0, 3.0, 4.0, 2)) -for algorithm in [JetAlgorithm.AntiKt, JetAlgorithm.CA, JetAlgorithm.Kt], +for algorithm in [JetAlgorithm.AntiKt, JetAlgorithm.CA, JetAlgorithm.Kt, JetAlgorithm.GenKt], strategy in [RecoStrategy.N2Plain, RecoStrategy.N2Tiled, RecoStrategy.Best], recombination in [ RecombinationScheme.EScheme, @@ -41,7 +42,7 @@ for algorithm in [JetAlgorithm.AntiKt, JetAlgorithm.CA, JetAlgorithm.Kt], RecombinationScheme.Pt2Scheme ] - assert_ok(jetreconstruction_jet_reconstruct(jets_ptr, jets_len, algorithm, R, + assert_ok(jetreconstruction_jet_reconstruct(jets_ptr, jets_len, algorithm, power, R, strategy, recombination, clustersequence_ptr)) diff --git a/src/C_JetReconstruction/C_JetReconstruction.jl b/src/C_JetReconstruction/C_JetReconstruction.jl index 5eacb683..1f36ca47 100644 --- a/src/C_JetReconstruction/C_JetReconstruction.jl +++ b/src/C_JetReconstruction/C_JetReconstruction.jl @@ -231,6 +231,7 @@ end c_jet_reconstruct(particles::Ptr{T}, particles_length::Csize_t, algorithm::JetAlgorithm.Algorithm, + power::Cdouble, R::Cdouble, strategy::RecoStrategy.Strategy, recombination_scheme::RecombinationScheme.Recombine, @@ -242,6 +243,7 @@ Internal helper functions for calling `jet_reconstruct` with C-compatible data-s - `particles::Ptr{T}`: Pointer to an array of pseudojet objects used for jet reconstruction. - `particles_length::Csize_t`: The length of `particles`` array. - `algorithm::JetAlgorithm.Algorithm`: The algorithm to use for jet reconstruction. +- `power::Cdouble`: The power value used for the distance measure for generalised k_T algorithms (GenKt, EEKt). Other algorithms will ignore this value. - `R::Cdouble`: The jet radius parameter. - `strategy::RecoStrategy.Strategy`: The jet reconstruction strategy to use. - `recombination_scheme::RecombinationScheme.Recombine`: The recombination scheme used for combining particles. @@ -256,13 +258,14 @@ Internal helper functions for calling `jet_reconstruct` with C-compatible data-s function c_jet_reconstruct(particles::Ptr{T}, particles_length::Csize_t, algorithm::JetAlgorithm.Algorithm, + power::Cdouble, R::Cdouble, strategy::RecoStrategy.Strategy, recombination_scheme::RecombinationScheme.Recombine, result::Ptr{C_ClusterSequence{U}}) where {T, U} try particles_v = unsafe_wrap(Vector{T}, particles, particles_length) - clusterseq = jet_reconstruct(particles_v; p = nothing, algorithm = algorithm, R = R, + clusterseq = jet_reconstruct(particles_v; p = power, algorithm = algorithm, R = R, strategy = strategy, RecombinationMethods[recombination_scheme]...) c_clusterseq = C_ClusterSequence{U}(clusterseq) @@ -278,6 +281,7 @@ end jetreconstruction_jet_reconstruct(particles::Ptr{PseudoJet}, particles_length::Csize_t, algorithm::JetAlgorithm.Algorithm, + power::Cdouble, R::Cdouble, strategy::RecoStrategy.Strategy, recombination_scheme::RecombinationScheme.Recombine, @@ -289,7 +293,8 @@ C-binding for `jet_reconstruct`. - `particles::Ptr{PseudoJet}`: Pointer to an array of pseudojet objects used for jet reconstruction. - `particles_length::Csize_t`: The length of `particles`` array. - `algorithm::JetAlgorithm.Algorithm`: The algorithm to use for jet reconstruction. -- `R::Cdouble`: The jet radius parameter.. +- `power::Cdouble`: The power value used for the distance measure for generalised k_T algorithms (GenKt, EEKt). Other algorithms will ignore this value. +- `R::Cdouble`: The jet radius parameter. - `strategy::RecoStrategy.Strategy`: The jet reconstruction strategy to use. - `recombination_scheme::RecombinationScheme.Recombine`: The recombination scheme used for combining particles. - `result::Ptr{C_ClusterSequence{PseudoJet}}`: A pointer to which a cluster sequence containing the reconstructed jets and the merging history will be stored. @@ -304,11 +309,12 @@ C-binding for `jet_reconstruct`. Base.@ccallable function jetreconstruction_jet_reconstruct(particles::Ptr{PseudoJet}, particles_length::Csize_t, algorithm::JetAlgorithm.Algorithm, + power::Cdouble, R::Cdouble, strategy::RecoStrategy.Strategy, recombination_scheme::RecombinationScheme.Recombine, result::Ptr{C_ClusterSequence{PseudoJet}})::Cint - return c_jet_reconstruct(particles, particles_length, algorithm, R, strategy, + return c_jet_reconstruct(particles, particles_length, algorithm, power, R, strategy, recombination_scheme, result) end diff --git a/test/test-c-interface.jl b/test/test-c-interface.jl index db818196..e84b4927 100644 --- a/test/test-c-interface.jl +++ b/test/test-c-interface.jl @@ -47,7 +47,7 @@ function test_pseudojet() struct_approx_equal(jet, c_jet) end -function test_jet_reconstruct(filename; algorithm, R, strategy, recombine, power = nothing, +function test_jet_reconstruct(filename; algorithm, R, strategy, recombine, power = 0.0, T = PseudoJet) @testset "C-interface jet reconstruct" begin events = JetReconstruction.read_final_state_particles(filename) @@ -62,6 +62,7 @@ function test_jet_reconstruct(filename; algorithm, R, strategy, recombine, power ret = C_JetReconstruction.jetreconstruction_jet_reconstruct(c_event, c_event_length, algorithm, + power, R, strategy, recombine, @@ -139,20 +140,20 @@ end @testset "C-interface JetReconstruction pp" begin test_cone_size = 0.4 test_recombine_scheme = RecombinationScheme.EScheme + test_power = 0.5 test_pseudojet() - for alg in [JetAlgorithm.AntiKt, JetAlgorithm.CA, JetAlgorithm.Kt], + for alg in [JetAlgorithm.AntiKt, JetAlgorithm.CA, JetAlgorithm.Kt, JetAlgorithm.GenKt], stg in [RecoStrategy.Best, RecoStrategy.N2Plain, RecoStrategy.N2Tiled] - power = JetReconstruction.algorithm2power[alg] - @testset "C-interface JetReconstruction comparison: alg=$alg, p=$power, R=$test_cone_size, strategy=$stg" begin + @testset "C-interface JetReconstruction comparison: alg=$alg, R=$test_cone_size, strategy=$stg" begin cluster_seq_ptrs, cluster_seqs = test_jet_reconstruct(events_file_pp; algorithm = alg, strategy = stg, recombine = test_recombine_scheme, R = test_cone_size, - power = power) + power = test_power) test_inclusive_jets(cluster_seq_ptrs, cluster_seqs; ptmin = 5.0) if alg != JetAlgorithm.AntiKt test_exclusive_jets_njets(cluster_seq_ptrs, cluster_seqs; njets = 4) From d15a8f25b692111a38cad9767626a4c65b83eb5b Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Mon, 14 Jul 2025 17:28:39 +0200 Subject: [PATCH 33/34] update juliac location --- compile/build.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compile/build.jl b/compile/build.jl index 70e9a00e..6cccf72e 100644 --- a/compile/build.jl +++ b/compile/build.jl @@ -51,7 +51,7 @@ end function compile_w_juliac(source_dir, output_dir) julia_path = joinpath(Sys.BINDIR, Base.julia_exename()) - juliac_path = joinpath(Sys.BINDIR, "..", "share", "julia", "juliac.jl") + juliac_path = joinpath(Sys.BINDIR, "..", "share", "julia", "juliac", "juliac.jl") jetreconstruction_path = joinpath(source_dir, "src", "JetReconstruction.jl") lib_dir = joinpath(output_dir, "lib") mkpath(lib_dir) From 7db31ad701d76ae7d4b6289c524ed36f5983a08c Mon Sep 17 00:00:00 2001 From: Mateusz Jakub Fila Date: Sun, 20 Jul 2025 15:14:26 +0200 Subject: [PATCH 34/34] adapt to changed jet selection signature --- src/C_JetReconstruction/C_JetReconstruction.jl | 2 +- test/test-c-interface.jl | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/C_JetReconstruction/C_JetReconstruction.jl b/src/C_JetReconstruction/C_JetReconstruction.jl index 1f36ca47..5c0c5714 100644 --- a/src/C_JetReconstruction/C_JetReconstruction.jl +++ b/src/C_JetReconstruction/C_JetReconstruction.jl @@ -386,7 +386,7 @@ function jets_selection(selector, clustersequence::Ptr{C_ClusterSequence{T}}, try c_clusterseq = unsafe_load(clustersequence) clusterseq = ClusterSequence{T}(c_clusterseq) - jets_result = selector(clusterseq; T = U, kwargs...) + jets_result = selector(clusterseq, U; kwargs...) c_results = C_JetsResult{U}(make_c_array(jets_result)...) unsafe_store!(result, c_results) catch e diff --git a/test/test-c-interface.jl b/test/test-c-interface.jl index e84b4927..83c7b10d 100644 --- a/test/test-c-interface.jl +++ b/test/test-c-interface.jl @@ -47,8 +47,8 @@ function test_pseudojet() struct_approx_equal(jet, c_jet) end -function test_jet_reconstruct(filename; algorithm, R, strategy, recombine, power = 0.0, - T = PseudoJet) +function test_jet_reconstruct(filename, ::Type{T} = PseudoJet; algorithm, R, strategy, + recombine, power = 0.0) where {T} @testset "C-interface jet reconstruct" begin events = JetReconstruction.read_final_state_particles(filename) results = Vector{ClusterSequence{T}}(undef, length(events)) @@ -93,7 +93,7 @@ function test_inclusive_jets(cluster_seq_ptrs::Vector{Ptr{C_JetReconstruction.C_ ptmin, results_ptr) @test C_JetReconstruction.StatusCode.T(ret) == C_JetReconstruction.StatusCode.OK - results = inclusive_jets(cluster_seq; ptmin = ptmin, T = T) + results = inclusive_jets(cluster_seq, T; ptmin = ptmin) compare_results(results_ptr, results) C_JetReconstruction.jetreconstruction_JetsResult_free_members_(results_ptr) end @@ -111,7 +111,7 @@ function test_exclusive_jets_njets(cluster_seq_ptrs::Vector{Ptr{C_JetReconstruct Csize_t(njets), results_ptr) @test C_JetReconstruction.StatusCode.T(ret) == C_JetReconstruction.StatusCode.OK - results = exclusive_jets(cluster_seq; njets = njets, T = T) + results = exclusive_jets(cluster_seq, T; njets = njets) compare_results(results_ptr, results) C_JetReconstruction.jetreconstruction_JetsResult_free_members_(results_ptr) end @@ -129,7 +129,7 @@ function test_exclusive_jets_dcut(cluster_seq_ptrs::Vector{Ptr{C_JetReconstructi dcut, results_ptr) @test C_JetReconstruction.StatusCode.T(ret) == C_JetReconstruction.StatusCode.OK - results = exclusive_jets(cluster_seq; dcut = dcut, T = T) + results = exclusive_jets(cluster_seq, T; dcut = dcut) compare_results(results_ptr, results) C_JetReconstruction.jetreconstruction_JetsResult_free_members_(results_ptr) end