From 0f79d0bd01a72a17040b400ed20751558b828a85 Mon Sep 17 00:00:00 2001 From: Christopher Dilks Date: Fri, 10 Jan 2025 19:35:57 -0500 Subject: [PATCH 1/3] build: add `rapidjson` dependency --- meson.build | 23 +++++++++++++++-------- subprojects/rapidjson.wrap | 13 +++++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 subprojects/rapidjson.wrap diff --git a/meson.build b/meson.build index 50a6bb97..05282e0b 100644 --- a/meson.build +++ b/meson.build @@ -44,6 +44,12 @@ yamlcpp_dep = dependency( method: 'pkg-config', version: '>=' + run_command(prog_minver, 'yaml-cpp', check: true).stdout().strip(), ) +rapidjson_dep = dependency( + 'RapidJSON', + method: 'pkg-config', + version: '>=1.1.0', + fallback: ['rapidjson', 'rapidjson_dep'] ###### TODO: need to test the wrapDB fallback actually works, but last time I tried, I got 'error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Missing Authority Key Identifier' +) hipo_dep = dependency( 'hipo4', method: 'pkg-config', @@ -76,7 +82,7 @@ thread_dep = dependency( # themselves are listed last (see FIXME in meson/this_iguana.sh.in) # NOTE: omit ROOT (handled differently, and most ROOT users already have it in their environment) dep_list = [] -foreach dep : [ hipo_dep, fmt_dep, yamlcpp_dep, rcdb_dep ] +foreach dep : [ hipo_dep, fmt_dep, yamlcpp_dep, rapidjson_dep, rcdb_dep ] if dep.found() dep_list += dep endif @@ -89,11 +95,12 @@ dep_pkgconfig_dirs = [] foreach dep : dep_list # get library and include dirs + libdirs = [] + incdirs = [] if dep.type_name() == 'pkgconfig' - libdirs = [ dep.get_variable(pkgconfig: 'libdir') ] - incdirs = [ dep.get_variable(pkgconfig: 'includedir') ] + libdirs += dep.get_variable(pkgconfig: 'libdir', default_value: 'not_defined') + incdirs += dep.get_variable(pkgconfig: 'includedir', default_value: 'not_defined') elif dep.type_name() == 'cmake' - libdirs = [] foreach lib : dep.get_variable(cmake: 'PACKAGE_LIBRARIES').split(';') libdirs += run_command('dirname', lib, check: true).stdout().strip() endforeach @@ -101,7 +108,7 @@ foreach dep : dep_list else name = dep.get_variable(internal: 'name', default_value: dep.name()) if name == 'rcdb' - incdirs = [ dep.get_variable(internal: 'includedir') ] + incdirs += dep.get_variable(internal: 'includedir') else warning(f'Unknown dependency "@name@"') continue @@ -110,7 +117,7 @@ foreach dep : dep_list # append to `dep_*_dirs` arrays, uniquely foreach libdir : libdirs - if not dep_lib_dirs.contains(libdir) + if not dep_lib_dirs.contains(libdir) and libdir != 'not_defined' dep_lib_dirs += libdir endif if dep.type_name() == 'pkgconfig' @@ -121,7 +128,7 @@ foreach dep : dep_list endif endforeach foreach incdir : incdirs - if not dep_include_dirs.contains(incdir) + if not dep_include_dirs.contains(incdir) and incdir != 'not_defined' dep_include_dirs += incdir endif endforeach @@ -241,7 +248,7 @@ pkg.generate( name: meson.project_name(), description: project_description, libraries: project_libs, - requires: [ fmt_dep, yamlcpp_dep, hipo_dep ], # pkg-config dependencies only + requires: [ fmt_dep, yamlcpp_dep, rapidjson_dep, hipo_dep ], # pkg-config dependencies only #### FIXME: using wrapDB with rapidjson will probably break this (cf. hipo repo) variables: project_pkg_vars_nonempty, ) diff --git a/subprojects/rapidjson.wrap b/subprojects/rapidjson.wrap new file mode 100644 index 00000000..50b83466 --- /dev/null +++ b/subprojects/rapidjson.wrap @@ -0,0 +1,13 @@ +[wrap-file] +directory = rapidjson-1.1.0 +source_url = https://github.com/Tencent/rapidjson/archive/v1.1.0.tar.gz +source_filename = rapidjson-1.1.0.tar.gz +source_hash = bf7ced29704a1e696fbccf2a2b4ea068e7774fa37f6d7dd4039d0787f8bed98e +patch_filename = rapidjson_1.1.0-2_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/rapidjson_1.1.0-2/get_patch +patch_hash = c1480d0ecef09dbaa4b4d85d86090205386fb2c7e87f4f158b20dbbda14c9afc +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/rapidjson_1.1.0-2/rapidjson-1.1.0.tar.gz +wrapdb_version = 1.1.0-2 + +[provide] +rapidjson = rapidjson_dep From 73ef0e3ae9dba212c94ab38d77d6a5dca95dc59c Mon Sep 17 00:00:00 2001 From: Christopher Dilks Date: Sun, 12 Jan 2025 15:43:57 -0500 Subject: [PATCH 2/3] fix: `.gitignore` --- subprojects/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 subprojects/.gitignore diff --git a/subprojects/.gitignore b/subprojects/.gitignore new file mode 100644 index 00000000..6f049f80 --- /dev/null +++ b/subprojects/.gitignore @@ -0,0 +1,2 @@ +*/ +!/rcdb From 5caf200ad5ac3563638d25f99c83021cd1ac2a49 Mon Sep 17 00:00:00 2001 From: Christopher Dilks Date: Sun, 12 Jan 2025 21:20:39 -0500 Subject: [PATCH 3/3] feat: begin the algo --- meson.build | 31 +++++-- src/iguana/algorithms/clas12/QADB/Action.yaml | 20 +++++ .../algorithms/clas12/QADB/Algorithm.cc | 75 ++++++++++++++++ src/iguana/algorithms/clas12/QADB/Algorithm.h | 86 +++++++++++++++++++ src/iguana/algorithms/clas12/QADB/Config.yaml | 14 +++ src/iguana/algorithms/meson.build | 5 ++ 6 files changed, 225 insertions(+), 6 deletions(-) create mode 100644 src/iguana/algorithms/clas12/QADB/Action.yaml create mode 100644 src/iguana/algorithms/clas12/QADB/Algorithm.cc create mode 100644 src/iguana/algorithms/clas12/QADB/Algorithm.h create mode 100644 src/iguana/algorithms/clas12/QADB/Config.yaml diff --git a/meson.build b/meson.build index 05282e0b..14a177f9 100644 --- a/meson.build +++ b/meson.build @@ -33,6 +33,7 @@ rcdb_subproj = subproject('rcdb', required: get_option('z_require_rcdb')) # resolve dependencies prog_minver = find_program('meson' / 'minimum-version.sh') +rapidjson_ver = '1.1.0' # NOTE: those that are typically installed by package managers should use `meson/minimum-version.sh` fmt_dep = dependency( 'fmt', @@ -47,8 +48,7 @@ yamlcpp_dep = dependency( rapidjson_dep = dependency( 'RapidJSON', method: 'pkg-config', - version: '>=1.1.0', - fallback: ['rapidjson', 'rapidjson_dep'] ###### TODO: need to test the wrapDB fallback actually works, but last time I tried, I got 'error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Missing Authority Key Identifier' + version: f'>=@rapidjson_ver@', ) hipo_dep = dependency( 'hipo4', @@ -88,6 +88,23 @@ foreach dep : [ hipo_dep, fmt_dep, yamlcpp_dep, rapidjson_dep, rcdb_dep ] endif endforeach +# list of 'requires' for generated pkg-config file +# FIXME: depenencies built from wrapdb subprojects (type_name()=='internal') need to +# be handled differently: +# - add to `pkgconfig_reqs` by text +# - dep.name() does not give the actual name +pkgconfig_reqs = [] +foreach dep : dep_list + if dep.type_name() != 'internal' + pkgconfig_reqs += dep + endif +endforeach +foreach dep_name, dep : { 'RapidJSON': rapidjson_dep, } + if dep.type_name() == 'internal' + pkgconfig_reqs += f'@dep_name@ >= @rapidjson_ver@' + endif +endforeach + # pkgconfig configuration: make a list of dependency library and include directories dep_lib_dirs = [] dep_include_dirs = [] @@ -105,17 +122,19 @@ foreach dep : dep_list libdirs += run_command('dirname', lib, check: true).stdout().strip() endforeach incdirs = ROOT_dep.get_variable(cmake: 'PACKAGE_INCLUDE_DIRS').split(';') - else + elif dep.type_name() == 'internal' name = dep.get_variable(internal: 'name', default_value: dep.name()) if name == 'rcdb' incdirs += dep.get_variable(internal: 'includedir') else - warning(f'Unknown dependency "@name@"') + # warning(f'Unknown dependency "@name@"') continue endif + else + error('Dependency type "' + dep.type_name() + '" is unknown') endif - # append to `dep_*_dirs` arrays, uniquely + # append to `dep_*` arrays, uniquely foreach libdir : libdirs if not dep_lib_dirs.contains(libdir) and libdir != 'not_defined' dep_lib_dirs += libdir @@ -248,7 +267,7 @@ pkg.generate( name: meson.project_name(), description: project_description, libraries: project_libs, - requires: [ fmt_dep, yamlcpp_dep, rapidjson_dep, hipo_dep ], # pkg-config dependencies only #### FIXME: using wrapDB with rapidjson will probably break this (cf. hipo repo) + requires: pkgconfig_reqs, variables: project_pkg_vars_nonempty, ) diff --git a/src/iguana/algorithms/clas12/QADB/Action.yaml b/src/iguana/algorithms/clas12/QADB/Action.yaml new file mode 100644 index 00000000..ed5c5ca9 --- /dev/null +++ b/src/iguana/algorithms/clas12/QADB/Action.yaml @@ -0,0 +1,20 @@ +algorithm: + name: 'clas12::QADB' + +actions: + - name: PrepareEvent + type: creator + inputs: + - name: runnum + type: int + - name: evnum + type: int + outputs: + - type: concurrent_key_t + cast: int + - name: Filter + type: filter + inputs: + - name: key + type: concurrent_key_t + cast: int diff --git a/src/iguana/algorithms/clas12/QADB/Algorithm.cc b/src/iguana/algorithms/clas12/QADB/Algorithm.cc new file mode 100644 index 00000000..d5e776b7 --- /dev/null +++ b/src/iguana/algorithms/clas12/QADB/Algorithm.cc @@ -0,0 +1,75 @@ +#include "Algorithm.h" + +namespace iguana::clas12 { + + REGISTER_IGUANA_ALGORITHM(QADB); + + void QADB::Start(hipo::banklist& banks) + { + + // get configuration + ParseYAMLConfig(); + o_datasets = GetOptionVector("datasets"); + o_qadb_dir = GetOptionScalar("qadb_dir"); + o_create_bank = GetOptionScalar("create_bank"); + o_runnum = ConcurrentParamFactory::Create(); + o_binnum = ConcurrentParamFactory::Create(); + + // get expected bank indices + b_config = GetBankIndex(banks, "RUN::config"); + } + + void QADB::Run(hipo::banklist& banks) const + { + + // get the banks + auto& configBank = GetBank(banks, b_config, "RUN::config"); + + // prepare the event, reloading configuration parameters, if necessary + auto key = PrepareEvent(configBank.getInt("run", 0), configBank.getInt("event", 0)); + + Filter(key); // FIXME: do something with this + } + + concurrent_key_t QADB::PrepareEvent(int const runnum, int const evnum) const { + m_log->Trace("calling PrepareEvent({}, {})", runnum, evnum); + if(o_runnum->NeedsHashing()) { + std::hash hash_ftn; + auto hash_key = hash_ftn(runnum); // FIXME: need to hash both runnum and evnum + if(!o_runnum->HasKey(hash_key)) + Reload(runnum, evnum, hash_key); + return hash_key; + } else { + if(o_runnum->IsEmpty() || o_runnum->Load(0) != runnum) // FIXME: bound check evnum here + Reload(runnum, evnum, 0); + return 0; + } + } + + void QADB::Reload(int const runnum, int const evnum, concurrent_key_t key) const { + std::lock_guard const lock(m_mutex); // NOTE: be sure to lock successive `ConcurrentParam::Save` calls !!! + m_log->Trace("-> calling Reload({}, {})", runnum, key); + o_runnum->Save(runnum, key); + // FIXME: query QADB here + } + + bool QADB::Filter(concurrent_key_t key) const + { + return true; // FIXME + } + + int QADB::GetRunNum(concurrent_key_t const key) const + { + return o_runnum->Load(key); + } + + int QADB::GetBinNum(concurrent_key_t const key) const + { + return o_binnum->Load(key); + } + + void QADB::Stop() + { + } + +} diff --git a/src/iguana/algorithms/clas12/QADB/Algorithm.h b/src/iguana/algorithms/clas12/QADB/Algorithm.h new file mode 100644 index 00000000..cee5253f --- /dev/null +++ b/src/iguana/algorithms/clas12/QADB/Algorithm.h @@ -0,0 +1,86 @@ +#pragma once + +#include "iguana/algorithms/Algorithm.h" +#include "iguana/services/ConcurrentParam.h" + +namespace iguana::clas12 { + + /// @brief_algo Filter using Quality Assurance Database (QADB) + /// + /// @begin_doc_algo{clas12::QADB | EventFilter} + /// @input_banks{RUN::config} + /// @output_banks{REC::Particle} + /// @end_doc + /// + /// @begin_doc_config + /// @config_param{datasets | list[string] | the list of QADB datasets to include (see below)} + /// @config_param{qadb_dir | string | custom QADB directory; if not set, defaults to environment variable `$QADB`} + /// @config_param{create_bank | bool | if `true`, create the output bank with QADB information for this event} + /// @end_doc + /// + /// This algorithm is an "EventFilter" type, which uses the return value of `iguana::Algorithm::Run` to + /// indicate whether the whole event is filtered or not. + /// + /// This algorithm requires the QADB to be installed. The environment variable `$QADB` is assumed to point + /// to the QADB installation. Alternatively, use the configuration variable `qadb_dir` if you do not + /// want to use `$QADB`. + /// + /// The QADB is defined for various datasets, and you must choose which dataset(s) to load by setting the + /// `datasets` configuration parameter; it is a list of `string`s, where each can be either: + /// - a dataset name, where the list of datasets is found in the QADB documentation + /// - in this case, the QADB files should be within `$QADB` (or `qadb_dir`) within `qadb//` + /// - the full path to a QADB `json` file + /// + /// This algorithm has the option `create_bank` to control whether or not an output bank is created, + /// which contains information from the QADB about the QA bin that contains the current event. + class QADB : public Algorithm + { + + DEFINE_IGUANA_ALGORITHM(QADB, clas12::QADB) + + public: + + void Start(hipo::banklist& banks) override; + void Run(hipo::banklist& banks) const override; + void Stop() override; + + /// @action_function{reload} prepare the event + /// @when_to_call{for each event} + /// @param runnum the run number + /// @param evnum the event number + /// @returns the key to be used in `::Filter` + concurrent_key_t PrepareEvent(int const runnum, int const evnum) const; + + /// @action_function{scalar filter} checks if the Z Vertex is within specified bounds if pid is one for which the filter should be applied to.; + /// Cuts applied to particles in FD or CD (ie not in FT). + /// @when_to_call{for each particle} + /// @param key the return value of `::PrepareEvent` + /// @returns `true` if `zvertex` is within specified bounds + bool Filter(concurrent_key_t const key) const; + + /// @param key the return value of `::PrepareEvent` + /// @returns the current run number + int GetRunNum(concurrent_key_t const key) const; + + /// @param key the return value of `::PrepareEvent` + /// @returns the current QA bin number + int GetBinNum(concurrent_key_t const key) const; + + private: + hipo::banklist::size_type b_particle, b_config; + + // Reload function + void Reload(int const runnum, int const evnum, concurrent_key_t key) const; + + // configuration options + std::vector o_datasets; + std::string o_qadb_dir; + bool o_create_bank{false}; + + // concurrent params + mutable std::unique_ptr> o_runnum; + mutable std::unique_ptr> o_binnum; + + }; + +} diff --git a/src/iguana/algorithms/clas12/QADB/Config.yaml b/src/iguana/algorithms/clas12/QADB/Config.yaml new file mode 100644 index 00000000..21db56e8 --- /dev/null +++ b/src/iguana/algorithms/clas12/QADB/Config.yaml @@ -0,0 +1,14 @@ +clas12::QADB + + # choose which datasets to include; see QADB documentation + # for the full list + datasets: + - latest/rga_fa18_inbending + - latest/rga_fa18_outbending + - latest/rga_sp19 + + # location of QADB; if set to 'env', uses `$QADB` + qadb_dir: env + + # whether or not to create a bank with QADB results + create_bank: false diff --git a/src/iguana/algorithms/meson.build b/src/iguana/algorithms/meson.build index 7ac67bcb..c5e5bcc9 100644 --- a/src/iguana/algorithms/meson.build +++ b/src/iguana/algorithms/meson.build @@ -98,6 +98,11 @@ algo_dict = [ 'has_action_yaml': false, 'test_args': {'banks': [ 'REC::Particle', 'REC::Calorimeter', 'RUN::config' ]}, }, + { + 'name': 'clas12::QADB', + 'has_validator': false, + 'test_args': {'banks': [ 'RUN::config' ]}, + }, ] # make lists of objects to build; inclusion depends on whether ROOT is needed or not, and if we have ROOT