diff --git a/README.md b/README.md index 8b79af5..38c54e9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## General information -The Paticle Finder Simple package is simplified version of the KF Partice package based on its mathematical apparatus. It is developed for the complete reconstruction of short-lived particles with their momentum, energy, mass, lifetime, decaylength, rapidity, etc. +The Paticle Finder Simple package is simplified version of the KF Partice package based on its mathematical apparatus. It is developed for the complete reconstruction of short-lived particles with their momentum, energy, mass, lifetime, decaylength, rapidity, etc. 2- and 3-body decays can get reconstructed. It is also possible to reconstruct multiple decays in one run as well as cascade decays. ## Requirements @@ -27,163 +27,163 @@ AnalysisTree with c++17 standard is strongly recommended. Clone PFSimple Source ROOT - - source /path-to-root/install/bin/thisroot.sh - +``` +source /path-to-root/install/bin/thisroot.sh +``` To use pre-installed AnalysisTree set the environment variable: - export AnalysisTree_DIR=/path-to-analysistree/install/lib/cmake/AnalysisTree +``` +export AnalysisTree_DIR=/path-to-analysistree/install/lib/cmake/AnalysisTree +``` To build AnalysisTree automatically together with PFSimple use following cmake keys: - -DPFSimple_BUNDLED_AT=ON - -DPFSimple_BUNDLED_AT_VERSION=v2.3.4 +``` +-DPFSimple_BUNDLED_AT=ON +-DPFSimple_BUNDLED_AT_VERSION=v2.3.4 +``` You need to source root and export AnalysisTree each time when you are compiling project from 0 (perform cmake command) but have no need to do it when just recompiling project (perform just make). Install PFSimple - - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=/path-to-install-pfsimple /path-to-source-pfsimple - make -j install - +``` +mkdir build +cd build +cmake -DCMAKE_INSTALL_PREFIX=/path-to-install-pfsimple /path-to-source-pfsimple +make -j install +``` ## Configuration of decay settings - -The reconstruction will be executed with at_interface/main.cpp. - -The reconstruction can be configured with the parameter-files -at_interface/parfile2.txt for 2-body decays and at_interface/parfile3.txt for 3-body decays. - -The user can select: -1) Decay: mother and daughters - - Pdg mass and pdg mass sigma for mother: if set to "-1" values from - KFParticleDatabase are taken - - Option for daughters: alternative pdgs can be used in addition - for the reconstruction - - for background: set to "1" / "-1" for pos / neg daughters - - for tracks without TOF id: set to "2" / "-2" for pos / neg - daughters (in pid-mode 2, 3, 4) - - In pid-mode 0 optional daughers "1" / "-1" for pos / neg pdgs must be added. - - If no alternative pdgs should be used, set to "0". - - If more optional pdgs than 2 should be added, change in main2.cpp / - main3.cpp and recompile. - -2) Geometrical cuts to be applied and cut-values - - If a cut should not be used, set to "-1". - - For more information on specific cuts see " Constants.hpp". - -3) Options for the saving of the reconstructed mother - - - A nonlinear mass constraint can be applied on the mother particle which modifies the mother's state vector and covariance matrix to - assure the 4-momentum is consitent with the pdg mass. - - - The mother can be transported to the PV. - - - The writing out of the mother into the output-file (e.g. the lower-level mother in cascade decays) can get surpressed. But - if this option is selected, it is not possible to peform the MC-matching for the upper-level mother. - -4) Pid-method: - - - 0: no pid (only charge information is used ! optional daughers must - be set to "1" / "-1" for pos / neg pdgs !) - - - 1: mc-pid - - - 2: reconstructed TOF pid - default from Pid-framework - - - 3: reconstructed TOF pid - pdg with max. pdg-purity is selected, if pdg-purity >min. purity - - - 4: reconstructed TOF pid - pdg is selected, if pdg-purity > min. purity (pdg-specfic purities are possible) - - for 2-4: Pid-framework needs to be applied first to include TOF-pid & probabilities into the analysistree input-file - -5) Minium purities for pid-mode 3 & 4: - - for pid-mode 3: minimum purity is set for all pdgs (pdg-spefic purities - need to be set to "-1") - - for pid-mode 4: minimum purity can be set for all pdgs or specifically - for every pdg (general purity will be overwritten, if pdg-specific - purity is not set to "-1") - -6) Input/Output information: - - treename in input aTree, default names: "rTree" for standard aTree, - "aTree" after running Pid-framework - - branchname of reconstructed tracks in input analysistree, default names: "VtxTracks" - for standard analyistree, "RecParticles" after running Pid-framework - - optional detailed background information in output variable "generation": - format for bg for 2-body-decay: -m12 0 d2 d1 - format for bg for 3-body-decay: -m13 m23 m12 d3 d2 d1 - with m12: mother of daughter 1 & 2 etc. - code for daughters (d): - 1 - reco daughter is unmatched to mc - 2 - reco daughter is matched, but primary - 3 - reco daughter is secondary, produced not in decay from mother with not expected pdg - 4 - reco daughter is secondary, produced not in decay from mother with expected pdg - 5 - reco daughter is secondary, produced in decay from mother with not expected pdg - 6 - reco daughter is secondary, produced in decay from mother with expected pdg - code for mothers (m): - 1 - daughters have the same mother - 2 - daughters have different mothers - 0 - at least one daughter does not have mother (e.g. primary) - - If detailed background is not selected or if mc match for mother is found, value of variable "generation" is: - 0 - no mc match for mother - 1 - mother is primary particle - 2 - mother is second generation etc. - - - number of events to be processed (-1 = all events) - - Output format: default output is analysistree format - optional: plain tree: output is a simple root tree containing the candidates - -### 3-body-decays -For 3-body decays, the list of available cuts is extended, amoung others, to cuts -on the secondary mothers (SM) of combinations of 2 daughters. E.g. for -H3L->p + pi + d, cuts on the SM of p-pi can be applied. The cuts -that test the mother against the PV, e.g. chi2topo, are inverted for -the SM to exclude SMs that come from the PV. - -### Multiple decays -If more than one decay should be reconstructed in the same run, additional -parfiles at_interface/parfile2_add.txt or at_interface/parfile3_add.txt can be added -where 1.) - 3.) can be selected. 4.) - 6.) can not be changed in the same run. The -decays can be independent or build a cascade decay. Multiple additional -parfiles can be added. +The program is configured with a JSON config file which contains various settings related to input and output as well as the decays to reconstruct. In the following, the different blocks and fields are explained. In `at_interface/config/config_template.json` all available JSON fields are listed. + +### io +| Key | Description | +| --------------------------| --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `input_treename` | name of the input AnalysisTree (for standard analysistree `rTree`, after running PID framework `pTree`) | +| `rectracks_branchname` | branchname of reconstructed tracks in input analysistree, default names: `VtxTracks` for standard analyistree, `RecParticles` after running Pid-framework | +| `n_events` | number of events to be processed, set to `-1` to process all events | +| `save_options` (optional) | defines save options for the candidates of all decays in this config (see next table) | + +| `save_options` Flag | Description | +| --------------------------| --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `make_plain_tree` | normal root tree containing the candidates is written besides the default output tree in AnalysisTree format | +| `signal_only` | save only mc-true signal candidates | +| `write_detailed_bg` | detailed background information in output variable `generation`* | + +*Format of detailed background information in the `generation` variable: + +format for bg for 2-body-decay: -m12 0 d2 d1 +format for bg for 3-body-decay: -m13 m23 m12 d3 d2 d1 +with m12: mother of daughter 1 & 2 etc. +code for daughters (d): +1 - reco daughter is unmatched to mc +2 - reco daughter is matched, but primary +3 - reco daughter is secondary, produced not in decay from mother with not expected pdg +4 - reco daughter is secondary, produced not in decay from mother with expected pdg +5 - reco daughter is secondary, produced in decay from mother with not expected pdg +6 - reco daughter is secondary, produced in decay from mother with expected pdg +code for mothers (m): +1 - daughters have the same mother +2 - daughters have different mothers +0 - at least one daughter does not have mother (e.g. primary) + +If detailed background is not selected or if mc match for mother is found, value of variable "generation" is: +0 - no mc match for mother +1 - mother is primary particle +2 - mother is second generation etc. + +### pid_mode +Methods for particle identification: +| `pid_mode` | Description | +| ---------- | --------------------------------------------------------------------------------------------------------- | +| `0` | no pid (only charge information is used! optional daughers must be set to 1 / -1 for pos / neg pdgs!) | +| `1` | mc-pid | +| `2` | reconstructed TOF pid - default from Pid-framework* | +| `3` | reconstructed TOF pid - pdg with max. pdg-purity is selected, if pdg-purity >min. purity* | +| `4` | reconstructed TOF pid - pdg is selected, if pdg-purity > min. purity (pdg-specfic purities are possible)* | + +** *for 2-4: Pid-framework needs to be applied first to include TOF-pid & probabilities into the analysistree input-file** + +### pid_purity +Mimimum purities for pid-mode 3 & 4: +- `all_pdgs`: minimum purity is set for all pdgs (pdg-spefic purities need to be omitted) (in pid-mode 3 & 4) +- `protons`, `pions`, etc: minimum purity is set specifically for every pdg (general purity will be overwritten, if pdg-specific purity is given) (in pid-mode 4) + +### decays +One or multiple decays get can reconstructed in one run. Each decay is defined by several sub-blocks: + +#### mother +- `pdg_code` +- `name` (chosen by user) +- `mass` (Unit: GeV/c^2) and `mass_sigma` (optional): if set to "-1" values from KFParticleDatabase are taken (if available) +- `cuts`: subblock for the definition of cuts to be applied to the mother (See `at_interface/config/config_template.json` for the available JSON keys and `Constants.hpp` for more details.) +- `save_options`: options for the saving of the reconstructed mother: + +| Flag | Description | +| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `mass_constraint` | nonlinear mass constraint is applied on the mother particle which modifies the mother's state vector and covariance matrix to assure the 4-momentum is consitent with the pdg mass | +| `transport_to_pv` | mother is transported to the PV before saving | +| `do_not_save_mother` | writing of the mother into the output-file (e.g. the lower-level mother in cascade decays) is surpressed. If this option is selected, it is not possible to peform the MC-matching for the upper-level mother. | + +#### daughters +The 2 (3) daughters of the mother are be defined in 2 (3) subblocks (for 2-/3-body decays). +- `pdg_code` (in JSON list format): + first entry: daugher PDG; + second and following entries (optional): additional pdgs or background can be considered as possible daughter candidates, for background set: + - for background: set to "1" / "-1" for pos / neg daughters + - for tracks without TOF id: set to "2" / "-2" for pos / neg daughters (in pid-mode 2, 3, 4) + In pid-mode 0 optional daughers "1" / "-1" for pos / neg pdgs must be added +- `cuts`: subblock for the definition of cuts to be applied to the daughter (See `at_interface/config/config_template.json` for the available JSON keys and `Constants.hpp` for more details.) + +#### secondary_mother_cuts (3-body-decays) +Cuts on the secondary mothers (SM) of combinations of 2 daughters can have up to 3 entries (JSON list format): cuts for daughter combinations [1 & 2, 1 & 3, 2 & 3]. +E.g. for H3L->p + pi + d, a cut on the SM of p-pi can be applied. +The cuts that test the mother against the PV, e.g. chi2topo, are inverted for the SM to exclude SMs that come from the PV. +(See `at_interface/config/config_template.json` for the available JSON keys and `Constants.hpp` for more details.) + +### output_cuts +The optional `output_cuts` block contains AnalysisTree field cuts to be applied to the output candidates before storing them to disk. One can either select a certain range for a cut variable with `from` and `to` or select a specific value with `equal`. It is possible to chain several cuts. ### Cascade decays -The reconstruction of a cascade decay works the same way as adding an additional decay -to the run as described above. The order of the parfiles need to be from last generation to -first generation. Cascade decays with multiple stages as well as combinations of -2- and 3-body-decays can get reconstructed. +For the reconstruction of a cascade decay all consecutive decays are added into one config-file. The order of the decays need to be from last generation to +first generation. +Cascade decays with multiple stages as well as combinations of 2- and 3-body-decays can get reconstructed. + +## Example Configs +Several example parameter files can be found in the folder `at_interface/configs`. + +| File | Particle(s) | `pid_mode` | Comment | +|-------------------------------------- |--------------------|------------|--------------------------------------- | +| `config_template.json` | - | - | all available JSON fields listed | +| `config_lambda_pidmode1_v1.json` | Lambda | `1` | KFParticle cuts | +| `config_lambda_pidmode1_v2.json` | Lambda | `1` | optimized cuts | +| `config_lambda_pidmode0.json` | Lambda | `0` | | +| `config_lambda_pidmode2.json` | Lambda | `2` | | +| `config_lambda_pidmode1_v3.json` | Lambda | `1` | for machine learning applications | +| `config_H3L_pidmode1.json` | H3L | `1` | 3-body decay | +| `config_H3L_pidmode4.json` | H3L | `4` | 3-body decay, minimum purities applied | +| `config_He5L_pidmode1.json` | He5L | `1` | 3-body decay | +| `config_xi_pidmode1.json` | Xi, Lambda | `1` | cascade decay | +| `config_omega_pidmode1.json` | Omega, Lambda | `1` | cascade decay | +| `config_omegastar_pidmode1.json` | Omega*, Xi, Lambda | `1` | cascade decay, 3-body decay | +| `config_lambda_k0short_pidmode1.json` | Lambda, K0Short | `1` | | -Several example parameter files can be found in the folder at_interface/example_parfiles. -## First run +## First run Each time before running the prepared executable you should set the environment variables to let your system know where to find libraries: - - source /path-to-root/install/bin/thisroot.sh - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path-to-pfsimple-installation/lib/ - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path-to-pfsimple-installation/external/lib/ - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path-to-analysistree-installation/lib/ - -Then run the executable: - - ./main filelist.txt dataset parfile2.txt (parfile2_add.txt parfile3_add.txt) - -or - - ./main filelist.txt dataset parfile3.txt (parfile2_add.txt parfile3_add.txt) - -where filelist.txt must be a text file with names (including paths) to +``` +source /path-to-root/install/bin/thisroot.sh +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path-to-pfsimple-installation/lib/ +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path-to-pfsimple-installation/external/lib/ +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path-to-analysistree-installation/lib/ #can be ommitted if PFSimple_BUNDLED_AT was set to ON +``` + +The reconstruction will be executed with the following command: +``` +at_interface/main_json filelist.txt config.json [--output ] [--plain-output ] [--set =] +``` +The binary accepts 2 positional arguments: The path of the input filelist.txt file and the config file in JSON format. It is also possible to modify the output file paths with the `--output` and `--plain-output` optional arguments as well as to override keys in the JSON config file by adding keys like `--set decays[0].mother.cuts.LdL=4.0`. + +### filelist.txt +filelist.txt must be a text file with names (including paths) to AnalysisTree files which you want to analyze with PFSimple. Each file name should be on the next line, and the last symbol should also be a switch to next line. The example of filelist is in the source directory of PFSimple (filelist_example.txt) - -and where [dataset] specifies the names of the outputfiles: -- analyistree: [dataset].PFSimpleOutput.root -- plain tree: [dataset].PFSimplePlainTree.root - diff --git a/at_interface/CMakeLists.txt b/at_interface/CMakeLists.txt index a700b86..fb94d78 100644 --- a/at_interface/CMakeLists.txt +++ b/at_interface/CMakeLists.txt @@ -26,6 +26,12 @@ add_dependencies(main KFMan) add_target_property(main COMPILE_FLAGS "-DDO_TPCCATRACKER_EFF_PERFORMANCE -DNonhomogeneousField -DCBM -DUSE_TIMERS") target_link_libraries(main KFMan KFParticleSimple KFParticleInterface KFParticle Vc) +add_executable(main_json main_json.cpp) +add_dependencies(main_json KFMan) +add_target_property(main_json COMPILE_FLAGS "-DDO_TPCCATRACKER_EFF_PERFORMANCE -DNonhomogeneousField -DCBM -DUSE_TIMERS") +target_include_directories(main_json PRIVATE ${ROOT_INCLUDE_DIRS}) +target_link_libraries(main_json KFMan KFParticleSimple KFParticleInterface KFParticle Vc) + install(TARGETS KFMan EXPORT KFManTargets LIBRARY DESTINATION lib ARCHIVE DESTINATION lib @@ -49,4 +55,4 @@ install( lib OPTIONAL ) -install (TARGETS main RUNTIME DESTINATION bin) +install (TARGETS main main_json RUNTIME DESTINATION bin) diff --git a/at_interface/configs/config_H3L_pidmode1.json b/at_interface/configs/config_H3L_pidmode1.json new file mode 100644 index 0000000..ca19a44 --- /dev/null +++ b/at_interface/configs/config_H3L_pidmode1.json @@ -0,0 +1,42 @@ +{ + "io" : { + "input_treename" : "pTree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "RecTracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1, + "save_options": ["make_plain_tree"] + }, + "pid_mode" : 1, // pid mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for 2-4: Pid-framework needs to be applied first + "decays" : [ + { + "mother" : { + "name" : "H3L", + "pdg_code" : 3004, + "cuts" : { + "LdL" : 10.0, + "dist" : 0.2, + "distSV" : 0.2 //for 3-body decay + } + }, + "daughters" : [ + { + "pdg_code" : [2212], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [-211], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [1000010020], + "cuts" : {"chi2prim" : 10.0} + } + ], + "secondary_mother_cuts" : { // for 3-body decay + // daugher 1 & 2, daughter 1 & 3, daughter 2 & 3 + "chi2geo" : [3.0], + "chi2topo" : [2.0] + } + } + ] +} \ No newline at end of file diff --git a/at_interface/configs/config_H3L_pidmode4.json b/at_interface/configs/config_H3L_pidmode4.json new file mode 100644 index 0000000..fb7e410 --- /dev/null +++ b/at_interface/configs/config_H3L_pidmode4.json @@ -0,0 +1,50 @@ +{ + "io" : { + "input_treename" : "pTree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "RecTracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1, + "save_options": ["make_plain_tree"] + }, + "pid_mode" : 4, // pid mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for 2-4: Pid-framework needs to be applied first + "pid_purity" : { // this block is only needed in pid_mode > 2 + "all_pdgs" : 0.5, + "protons" : 0.7, + "pions" : 0.7, + "kaons" : 0.7, + "deuterons" : 0.2, + "background" : 0.7 + }, + "decays" : [ + { + "mother" : { + "name" : "H3L", + "pdg_code" : 3004, + "cuts" : { + "LdL" : 10.0, + "dist" : 0.2, + "distSV" : 0.2 //for 3-body decay + } + }, + "daughters" : [ + { + "pdg_code" : [2212], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [-211], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [1000010020], + "cuts" : {"chi2prim" : 10.0} + } + ], + "secondary_mother_cuts" : { // for 3-body decay + // daugher 1 & 2, daughter 1 & 3, daughter 2 & 3 + "chi2geo" : [3.0], + "chi2topo" : [2.0] + } + } + ] +} \ No newline at end of file diff --git a/at_interface/configs/config_He5L_pidmode1.json b/at_interface/configs/config_He5L_pidmode1.json new file mode 100644 index 0000000..c11436b --- /dev/null +++ b/at_interface/configs/config_He5L_pidmode1.json @@ -0,0 +1,42 @@ +{ + "io" : { + "input_treename" : "pTree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "RecTracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1, + "save_options": ["make_plain_tree"] + }, + "pid_mode" : 1, // pid mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for 2-4: Pid-framework needs to be applied first + "decays" : [ + { + "mother" : { + "name" : "He5L", + "pdg_code" : 3007, + "cuts" : { + "LdL" : 5.0, + "dist" : 1.0, + "chi2geo" : 6.0, + "chi2topo" : 5.0 + } + }, + "daughters" : [ + { + "pdg_code" : [1000020040], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [-211], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [2212], + "cuts" : {"chi2prim" : 18.42} + } + ], + "secondary_mother_cuts" : { // for 3-body decay + // daugher 1 & 2, daughter 1 & 3, daughter 2 & 3 + "chi2geo" : [3.0] + } + } + ] +} \ No newline at end of file diff --git a/at_interface/configs/config_lambda_k0short_pidmode1.json b/at_interface/configs/config_lambda_k0short_pidmode1.json new file mode 100644 index 0000000..6a29296 --- /dev/null +++ b/at_interface/configs/config_lambda_k0short_pidmode1.json @@ -0,0 +1,53 @@ +{ + "io" : { + "input_treename" : "rTree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "VtxTracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1 + }, + "pid_mode" : 1, // pid mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for 2-4: Pid-framework needs to be applied first + "decays" : [ + { + "mother" : { + "name" : "Lambda", + "pdg_code" : 3122, + "cuts" : { + "dist" : 1, + "chi2geo" : 3, + "LdL" : 5 + } + }, + "daughters" : [ + { + "pdg_code" : [-211], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [2212], + "cuts" : {"chi2prim" : 18.42} + } + ] + }, + { + "mother" : { + "name" : "K0Short", + "pdg_code" : 310, + "cuts" : { + "dist" : 1, + "chi2geo" : 3, + "LdL" : 5 + } + }, + "daughters" : [ + { + "pdg_code" : [-211], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [211], + "cuts" : {"chi2prim" : 18.42} + } + ] + } + ] +} \ No newline at end of file diff --git a/at_interface/configs/config_lambda_pidmode0.json b/at_interface/configs/config_lambda_pidmode0.json new file mode 100644 index 0000000..a38f553 --- /dev/null +++ b/at_interface/configs/config_lambda_pidmode0.json @@ -0,0 +1,33 @@ +{ + "io" : { + "input_treename" : "rTree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "VtxTracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1, + "save_options": ["make_plain_tree"] + }, + "pid_mode" : 0, // pid mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for 2-4: Pid-framework needs to be applied first + "decays" : [ + { + "mother" : { + "name" : "Lambda", + "pdg_code" : 3122, + "cuts" : { + "LdL" : 5.0, + "dist" : 1.0, + "chi2geo" : 3.0 + } + }, + "daughters" : [ + { + "pdg_code" : [-211, -1], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [2212, 1], + "cuts" : {"chi2prim" : 18.42} + } + ] + } + ] +} \ No newline at end of file diff --git a/at_interface/configs/config_lambda_pidmode1_v1.json b/at_interface/configs/config_lambda_pidmode1_v1.json new file mode 100644 index 0000000..e8174e2 --- /dev/null +++ b/at_interface/configs/config_lambda_pidmode1_v1.json @@ -0,0 +1,34 @@ +//(Lambda pid 1, cuts from KFParticle) +{ + "io" : { + "input_treename" : "rTree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "VtxTracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1, + "save_options": ["make_plain_tree"] + }, + "pid_mode" : 1, // pid mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for 2-4: Pid-framework needs to be applied first + "decays" : [ + { + "mother" : { + "name" : "Lambda", + "pdg_code" : 3122, + "cuts" : { + "LdL" : 5.0, + "dist" : 1.0, + "chi2geo" : 3.0 + } + }, + "daughters" : [ + { + "pdg_code" : [-211], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [2212], + "cuts" : {"chi2prim" : 18.42} + } + ] + } + ] +} \ No newline at end of file diff --git a/at_interface/configs/config_lambda_pidmode1_v2.json b/at_interface/configs/config_lambda_pidmode1_v2.json new file mode 100644 index 0000000..1332a26 --- /dev/null +++ b/at_interface/configs/config_lambda_pidmode1_v2.json @@ -0,0 +1,35 @@ +//(Lambda pid 1, cuts optimized) +{ + "io" : { + "input_treename" : "rTree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "VtxTracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1, + "save_options": ["make_plain_tree"] + }, + "pid_mode" : 1, // pid mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for 2-4: Pid-framework needs to be applied first + "decays" : [ + { + "mother" : { + "name" : "Lambda", + "pdg_code" : 3122, + "cuts" : { + "LdL" : 4.0, + "dist" : 0.15, + "chi2geo" : 11.0, + "chi2topo" : 29.0 + } + }, + "daughters" : [ + { + "pdg_code" : [-211], + "cuts" : {"chi2prim" : 110.00} + }, + { + "pdg_code" : [2212], + "cuts" : {"chi2prim" : 26.00, "cos" : 0.99825} + } + ] + } + ] +} \ No newline at end of file diff --git a/at_interface/configs/config_lambda_pidmode1_v3.json b/at_interface/configs/config_lambda_pidmode1_v3.json new file mode 100644 index 0000000..5d982fb --- /dev/null +++ b/at_interface/configs/config_lambda_pidmode1_v3.json @@ -0,0 +1,39 @@ +{ + "io" : { + "input_treename" : "rTree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "VtxTracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1, + "save_options": ["signal_only"] + }, + "pid_mode" : 1, // pid mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for 2-4: Pid-framework needs to be applied first + "decays" : [ + { + "mother" : { + "name" : "Lambda", + "pdg_code" : 3122, + "cuts" : { + "dist" : 100.0, + "chi2geo" : 1000.0 + } + }, + "daughters" : [ + { + "pdg_code" : [-211] + }, + { + "pdg_code" : [2212] + } + ] + } + ], + "output_cuts" : [ + {"var" : "mass", "from" : 1.07, "to" : 1.2}, + {"var" : "x", "from" : -50, "to" : 50}, + {"var" : "y", "from" : -50, "to" : 50}, + {"var" : "distance", "from" : 0, "to" : 100}, + {"var" : "eta", "from" : 1, "to" : 6.5}, + {"var" : "chi2_topo", "from" : 0, "to" : 100000}, + {"var" : "chi2_geo", "from" : 0, "to" : 1000} + ] +} \ No newline at end of file diff --git a/at_interface/configs/config_lambda_pidmode2.json b/at_interface/configs/config_lambda_pidmode2.json new file mode 100644 index 0000000..f73fc69 --- /dev/null +++ b/at_interface/configs/config_lambda_pidmode2.json @@ -0,0 +1,33 @@ +{ + "io" : { + "input_treename" : "pTree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "RecTracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1, + "save_options": ["make_plain_tree"] + }, + "pid_mode" : 2, // pid mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for 2-4: Pid-framework needs to be applied first + "decays" : [ + { + "mother" : { + "name" : "Lambda", + "pdg_code" : 3122, + "cuts" : { + "LdL" : 5.0, + "dist" : 1.0, + "chi2geo" : 3.0 + } + }, + "daughters" : [ + { + "pdg_code" : [-211, -2], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [2212, 2], + "cuts" : {"chi2prim" : 18.42} + } + ] + } + ] +} \ No newline at end of file diff --git a/at_interface/configs/config_omega_pidmode1.json b/at_interface/configs/config_omega_pidmode1.json new file mode 100644 index 0000000..26c1efe --- /dev/null +++ b/at_interface/configs/config_omega_pidmode1.json @@ -0,0 +1,58 @@ +{ + "io" : { + "input_treename" : "rTree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "VtxTracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1, + "save_options": ["make_plain_tree", "write_detailed_bg"] + }, + "pid_mode" : 1, // pid mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for 2-4: Pid-framework needs to be applied first + "decays" : [ + { + "mother" : { + "name" : "Lambda", + "pdg_code" : 3122, + "cuts" : { + "LdL" : 10.0, + "dist" : 1.0, + "chi2geo" : 3.0, + "chi2topo" : 5.0, + "invmass" : 3.0 + }, + "save_options" : ["mass_constraint"] + }, + "daughters" : [ + { + "pdg_code" : [-211, -1], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [2212, 1], + "cuts" : {"chi2prim" : 18.42} + } + ] + }, + { + "mother" : { + "name" : "Omega", + "pdg_code" : 3334, + "cuts" : { + "chi2topo" : 5.0, + "LdL" : 5.0, + "chi2geo" : 6.0, + "dist" : 1.0 + }, + "save_options" : ["transport_to_pv"] + }, + "daughters" : [ + { + "pdg_code" : [-321], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [3122] + } + ] + } + ] +} \ No newline at end of file diff --git a/at_interface/configs/config_omegastar_pidmode1.json b/at_interface/configs/config_omegastar_pidmode1.json new file mode 100644 index 0000000..787444c --- /dev/null +++ b/at_interface/configs/config_omegastar_pidmode1.json @@ -0,0 +1,91 @@ +{ + "io" : { + "input_treename" : "rTree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "VtxTracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1, + "save_options": ["make_plain_tree", "write_detailed_bg"] + }, + "pid_mode" : 1, // pid mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for 2-4: Pid-framework needs to be applied first + "decays" : [ + { + "mother" : { + "name" : "Lambda", + "pdg_code" : 3122, + "cuts" : { + "LdL" : 10.0, + "dist" : 1.0, + "chi2geo" : 3.0, + "chi2topo" : 5.0, + "invmass" : 3.0 + }, + "save_options" : ["mass_constraint"] + }, + "daughters" : [ + { + "pdg_code" : [-211, -1], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [2212, 1], + "cuts" : {"chi2prim" : 18.42} + } + ] + }, + { + "mother" : { + "name" : "Xi-", + "pdg_code" : 3312, + "cuts" : { + "chi2topo" : 5.0, + "dist" : 1.0, + "LdL" : 5.0, + "chi2geo" : 6.0, + "invmass" : 3.0 + }, + "save_options" : ["mass_constraint"] + }, + "daughters" : [ + { + "pdg_code" : [-211, -1], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [3122] + } + ] + }, + { + "mother" : { + "name" : "Omega*-", + "pdg_code" : 1003334, + "mass" : 2.252, + "mass_sigma" : 0.055, + "cuts" : { + "dist" : 1.0, + "chi2topo" : 1000.0, + "LdL" : 5.0, + "chi2geo" : 3.0 + } + }, + "daughters" : [ + { + "pdg_code" : [3312], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [211], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [-321], + "cuts" : {"chi2prim" : 18.42} + } + ], + "secondary_mother_cuts" : { // for 3-body decay + //daugher 1 & 2, daughter 1 & 3, daughter 2 & 3 + "chi2geo" : [3.0] + } + } + ] +} \ No newline at end of file diff --git a/at_interface/configs/config_template.json b/at_interface/configs/config_template.json new file mode 100644 index 0000000..b2dc4f5 --- /dev/null +++ b/at_interface/configs/config_template.json @@ -0,0 +1,62 @@ +{ + "io" : { + "input_treename" : "name_tree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "name_tracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1, + "save_options": ["make_plain_tree", "write_detailed_bg" , "signal_only"] + }, + "pid_mode" : number, // pid_mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for pid_mode 2-4: Pid-framework needs to be applied first! + "pid_purity" : { // this block is only needed in pid_mode > 2 + "all_pdgs" : purity_value, + "protons" : purity_value, + "pions" : purity_value, + "kaons" : purity_value, + "deuterons" : purity_value, + "background" : purity_value + }, + "decays" : [ + { + "mother" : { + "name" : "mother_name", + "pdg_code" : mother_pdg, + "cuts" : { + "dist" : cut_value, + "distSV" : cut_value, //for 3-body decay only + "chi2geo" : cut_value, + "cosopen" : cut_value, + "chi2topo" : cut_value, + "costopo" : cut_value, + "LdL" : cut_value, + "L" : cut_value, + "distPVline" : cut_value, + "invmass" : cut_value + }, + "save_options" : ["mass_constraint", "transport_to_pv", "do_not_save_mother"] + }, + "daughters" : [ + { + "pdg_code" : [daughter_1_pdg], + "cuts" : {"chi2prim" : cut_value, "cos" : cut_value} + }, + { + "pdg_code" : [daughter_2_pdg], + "cuts" : {"chi2prim" : cut_value, "cos" : cut_value} + } + ], + "secondary_mother_cuts" : { // for 3-body decay only + // up to 3 entries for: daugher 1 & 2, daughter 1 & 3, daughter 2 & 3 + "chi2geo" : [cut_value, cut_value, cut_value], + "cosopen" : [cut_value, cut_value, cut_value], + "chi2topo" : [cut_value, cut_value, cut_value], + "costopo" : [cut_value, cut_value, cut_value] + } + + } + //add more decays to this list if needed... + ], + "output_cuts" : [ + {"var" : "x", "from" : cut_value1, "to" : cut_value2}, + {"var" : "y", "from" : cut_value1, "to" : cut_value2} + ] +} \ No newline at end of file diff --git a/at_interface/configs/config_xi_pidmode1.json b/at_interface/configs/config_xi_pidmode1.json new file mode 100644 index 0000000..6f5238a --- /dev/null +++ b/at_interface/configs/config_xi_pidmode1.json @@ -0,0 +1,58 @@ +{ + "io" : { + "input_treename" : "rTree", // "rTree" for standard analysistree, "pTree" after running PID-framework (for pid_mode > 2) + "rectracks_branchname" : "VtxTracks", // "VtxTracks" for standard analyistree, "RecParticles" after running Pid-framework (for pid_mode > 2) + "n_events" : -1, + "save_options": ["make_plain_tree", "write_detailed_bg"] + }, + "pid_mode" : 1, // pid mode: =0: no pid; =1: mc pid; =2: rec pid (default); =3: rec pid (max. purity & purity > min. purity); =4 (purity > min. purity) + // for 2-4: Pid-framework needs to be applied first + "decays" : [ + { + "mother" : { + "name" : "Lambda", + "pdg_code" : 3122, + "cuts" : { + "LdL" : 10.0, + "dist" : 1.0, + "chi2geo" : 3.0, + "chi2topo" : 5.0, + "invmass" : 3.0 + }, + "save_options" : ["mass_constraint"] + }, + "daughters" : [ + { + "pdg_code" : [-211, -1], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [2212, 1], + "cuts" : {"chi2prim" : 18.42} + } + ] + }, + { + "mother" : { + "name" : "Xi-", + "pdg_code" : 3312, + "cuts" : { + "chi2topo" : 5.0, + "dist" : 1.0, + "LdL" : 5.0, + "chi2geo" : 6.0 + }, + "save_options" : ["transport_to_pv"] + }, + "daughters" : [ + { + "pdg_code" : [-211, -1], + "cuts" : {"chi2prim" : 18.42} + }, + { + "pdg_code" : [3122] + } + ] + } + ] +} \ No newline at end of file diff --git a/at_interface/main_json.cpp b/at_interface/main_json.cpp new file mode 100644 index 0000000..4c27f5b --- /dev/null +++ b/at_interface/main_json.cpp @@ -0,0 +1,325 @@ +#include "PFSimpleTask.hpp" + +#include "ConverterIn.hpp" +#include "ConverterOut.hpp" + +#include "AnalysisTree/PlainTreeFiller.hpp" +#include "AnalysisTree/TaskManager.hpp" + +#include +#include +#include +#include +#include +#include + +using namespace AnalysisTree; +using json = nlohmann::json; + +#define LIST_CONTAINS(list, value) std::find(list.begin(), list.end(), value) != list.end() +void set_json_value(json& j, const std::string& path, const std::string& value); + +nlohmann::json load_config(const std::string& filepath) { + std::ifstream file_stream(filepath); + if (!file_stream.is_open()) { + throw std::runtime_error("Failed to open file: " + filepath); + } + + try { + return nlohmann::json::parse(file_stream, nullptr, true, true); // last 'true' enables comment support + } catch (const nlohmann::json::parse_error& e) { + throw std::runtime_error("JSON parse error in file " + filepath + ": " + e.what()); + } +} + +int main(int argc, char** argv) { + std::string input_file; + std::string config_file; + std::string output_file = "PFSimpleOutput.root"; + std::string plain_output_file = "PFSimplePlainTree.root"; + std::vector> overrides; + + //Parse command line args + static struct option long_options[] = { + {"output", required_argument, nullptr, 'o'}, + {"plain-output", required_argument, nullptr, 'p'}, + {"set", required_argument, nullptr, 's'}, + {0, 0, 0, 0} + }; + + int opt; + while ((opt = getopt_long(argc, argv, "o:p:s:", long_options, nullptr)) != -1) { + switch (opt) { + case 'o': output_file = optarg; break; + case 'p': plain_output_file = optarg; break; + case 's': { + std::string arg = optarg; + size_t eqPos = arg.find('='); + if (eqPos != std::string::npos) { + std::string key = arg.substr(0, eqPos); + std::string value = arg.substr(eqPos + 1); + overrides.emplace_back(key, value); // Save for later + } else { + std::cerr << "Invalid --set format: use key=value\n"; + return 1; + } + break; + } + default: + return 1; + } + } + + if (optind + 2 > argc) { + std::cerr << "Usage: " << argv[0] << " filelist.txt config.json [--output file] [--plain-output file] [--set key=value]\n"; + return 1; + } + + input_file = argv[optind]; + config_file = argv[optind + 1]; + + // Load config JSON file + json config = load_config(config_file); + + // Apply deferred overrides + for (const auto& [key, value] : overrides) { + set_json_value(config, key, value); + } + + // For demonstration + //std::cout << "Modified config:\n" << config.dump(2) << std::endl; + + // Setup PFSimple from JSON config + auto* man = TaskManager::GetInstance(); + + auto* in_converter = new ConverterIn(); + in_converter->SetRecEventHeaderName("RecEventHeader"); + in_converter->SetRecTracksName(config["io"]["rectracks_branchname"]); + in_converter->SetSimTracksName("SimParticles"); + in_converter->SetTrackCuts(new Cuts("Cut to reproduce KFPF", {EqualsCut((config["io"]["rectracks_branchname"].get() + ".pass_cuts").c_str(), 1)})); + + + std::vector decays; + + for (const auto& decay_cfg : config["decays"]) { + printf("Configuring decay %s\n", decay_cfg["mother"]["name"].get().c_str()); + + // Load daughters & cuts + auto daughters_cfg = decay_cfg["daughters"]; + std::vector daughters; + for (const auto& daughter_cfg : daughters_cfg) { + std::vector pdg_codes = daughter_cfg["pdg_code"].get>(); + + if (pdg_codes.size() > 1) + daughters.emplace_back(Daughter(pdg_codes[0], pdg_codes)); + else + daughters.emplace_back(Daughter(pdg_codes[0])); + + auto& d = daughters.back(); + d.CancelCuts(); + if (daughter_cfg.contains("cuts")) { + auto cuts = daughter_cfg["cuts"]; + if (cuts.contains("chi2prim")) d.SetCutChi2Prim(cuts["chi2prim"]); + if (cuts.contains("cos")) d.SetCutCos(cuts["cos"]); + } + } + + // Load mother + auto mother_cfg = decay_cfg["mother"]; + Mother mother(mother_cfg["pdg_code"]); + mother.CancelCuts(); + if (mother_cfg.contains("mass")) mother.SetMassPdg(mother_cfg["mass"]); + if (mother_cfg.contains("mass_sigma")) mother.SetMassPdgSigma(mother_cfg["mass_sigma"]); + + if (mother_cfg.contains("cuts")) { + auto cuts = mother_cfg["cuts"]; + if (cuts.contains("dist")) mother.SetCutDistance(cuts["dist"]); + if (cuts.contains("distSV")) mother.SetCutDistanceToSV(cuts["distSV"]); + if (cuts.contains("chi2geo")) mother.SetCutChi2Geo(cuts["chi2geo"]); + if (cuts.contains("cosopen")) mother.SetCutCosOpen(cuts["cosopen"]); + if (cuts.contains("chi2topo")) mother.SetCutChi2Topo(cuts["chi2topo"]); + if (cuts.contains("costopo")) mother.SetCutCosTopo(cuts["costopo"]); + if (cuts.contains("LdL")) mother.SetCutLdL(cuts["LdL"]); + if (cuts.contains("L")) mother.SetCutDecayLength(cuts["L"]); + if (cuts.contains("distPVline")) mother.SetCutDistancePVLine(cuts["distPVline"]); + if (cuts.contains("invmass")) mother.SetCutInvMass(cuts["invmass"]); + } + + // Secondary mother cuts (SM) + if (decay_cfg.contains("secondary_mother_cuts")) { + auto combo_cuts = decay_cfg["secondary_mother_cuts"]; + + if (combo_cuts.contains("chi2geo")) mother.SetCutChi2GeoSM(combo_cuts["chi2geo"].get>()); + if (combo_cuts.contains("cosopen")) mother.SetCutCosOpenSM(combo_cuts["cosopen"].get>()); + if (combo_cuts.contains("chi2topo")) mother.SetCutChi2TopoSM(combo_cuts["chi2topo"].get>()); + if (combo_cuts.contains("costopo")) mother.SetCutCosTopoSM(combo_cuts["costopo"].get>()); + } + + // Construct decay and set save options + Decay decay(mother_cfg["name"], mother, {daughters}); + + if (mother_cfg.contains("save_options")) { + const auto& options = mother_cfg["save_options"]; + if (LIST_CONTAINS(options, "mass_constraint")) decay.SetIsApplyMassConstraint(); + if (LIST_CONTAINS(options, "transport_to_pv")) decay.SetIsTransportToPV(); + if (LIST_CONTAINS(options, "do_not_save_mother")) decay.SetIsDoNotWriteMother(); + } + + decays.push_back(decay); + } + + // PID and IO settings + auto pid_mode = config["pid_mode"]; + auto pid_purity_cfg = config["pid_purity"]; + + in_converter->SetPidMode(pid_mode); + if (pid_purity_cfg.contains("default")) in_converter->SetPidPurity(pid_purity_cfg["default"]); + if (pid_purity_cfg.contains("protons")) in_converter->SetPidPurityProton(pid_purity_cfg["protons"]); + if (pid_purity_cfg.contains("pions")) in_converter->SetPidPurityPion(pid_purity_cfg["pions"]); + if (pid_purity_cfg.contains("kaons")) in_converter->SetPidPurityKaon(pid_purity_cfg["kaons"]); + if (pid_purity_cfg.contains("deuterons")) in_converter->SetPidPurityDeuteron(pid_purity_cfg["deuterons"]); + if (pid_purity_cfg.contains("background")) in_converter->SetPidPurityBG(pid_purity_cfg["background"]); + + auto* pf_task = new PFSimpleTask(); + pf_task->SetInTask(in_converter); + pf_task->SetDecays({decays}); + + auto* out_converter = new ConverterOut(); + man->SetOutputName(output_file, "pTree"); + out_converter->SetSimEventHeaderName("SimEventHeader"); + out_converter->SetRecTracksName(config["io"]["rectracks_branchname"]); + out_converter->SetSimTracksName("SimParticles"); + out_converter->SetPFSimpleTask(pf_task); + out_converter->SetDecays(decays); + if(LIST_CONTAINS(config["io"]["save_options"], "write_detailed_bg")) out_converter->SetIsWriteDetailedBG(true); + + std::vector vec_output_cuts = {}; + if (config.contains("output_cuts")) + { + for (const auto& cut_cfg : config["output_cuts"]) { + if (cut_cfg.contains("equal")) + vec_output_cuts.push_back(AnalysisTree::EqualsCut("Candidates." + cut_cfg["var"].get(), cut_cfg["equal"])); + else if (cut_cfg.contains("from")) + vec_output_cuts.push_back(AnalysisTree::RangeCut("Candidates." + cut_cfg["var"].get(), cut_cfg["from"], cut_cfg["to"])); + } + } + + if(LIST_CONTAINS(config["io"]["save_options"], "signal_only")) + vec_output_cuts.push_back(AnalysisTree::SimpleCut({"Candidates.generation"}, []( std::vector& var ) { return var.at(0) != 0; })); + + if (vec_output_cuts.size() > 0) + { + AnalysisTree::Cuts* output_cuts = new AnalysisTree::Cuts("output_cuts", vec_output_cuts); + out_converter->SetOutputCuts(output_cuts); + } + + man->AddTask(in_converter); + man->AddTask(pf_task); + man->AddTask(out_converter); + man->SetVerbosityPeriod(100); + + man->Init({input_file}, {config["io"]["input_treename"]}); + man->Run(config["io"]["n_events"]); + man->Finish(); + man->ClearTasks(); + + if(LIST_CONTAINS(config["io"]["save_options"], "make_plain_tree")) { + std::ofstream filelist; + filelist.open("filelist.txt"); + filelist << output_file; + filelist << "\n"; + filelist.close(); + + auto* tree_task = new PlainTreeFiller(); + tree_task->SetOutputName(plain_output_file, "plain_tree"); + std::string branchname_rec = "Candidates"; + tree_task->SetInputBranchNames({branchname_rec}); + tree_task->AddBranch(branchname_rec); + //tree_task->SetIsPrependLeavesWithBranchName(false); //Uncomment when most recent AnalysisTree is installed in cbmroot + + man->AddTask(tree_task); + + man->Init({"filelist.txt"}, {"pTree"}); + man->Run(config["io"]["n_events"]); + man->Finish(); + } + + return 0; +} + + +/* +Function to overide a value inside the json config, e.g. decays[0].mother.cuts.LdL=4.0 +Command line argument usage example for lists: --set 'io.save_options=["signal_only"]' +*/ +void set_json_value(json& config, const std::string& path, const std::string& value) { + std::cout << "[DEBUG] Setting " << path << " to " << value << std::endl; + + std::regex token_regex(R"(([^.\[\]]+)(?:\[(\d+)\])?)"); + auto tokens_begin = std::sregex_iterator(path.begin(), path.end(), token_regex); + auto tokens_end = std::sregex_iterator(); + + json* current = &config; + + for (auto it = tokens_begin; it != tokens_end; ++it) { + std::string key = (*it)[1]; + std::string index_str = (*it)[2]; + bool is_last = (std::next(it) == tokens_end); + + if (!index_str.empty()) { + // Handle arrays + int index = std::stoi(index_str); + if (!(*current)[key].is_array()) { + (*current)[key] = json::array(); + } + + while ((*current)[key].size() <= index) { + (*current)[key].push_back(nullptr); + } + + if (is_last) { + json& target = (*current)[key][index]; + try { + if (value == "true" || value == "false") { + target = (value == "true"); + } else if (value == "null") { + target = json(); + } else if (!value.empty() && value.front() == '[' && value.back() == ']') { + target = json::parse(value); // Parse list + } else if (value.find('.') != std::string::npos) { + target = std::stod(value); + } else { + target = std::stoi(value); + } + } catch (...) { + target = value; + } + return; + } else { + current = &((*current)[key][index]); + } + } else { + if (is_last) { + json& target = (*current)[key]; + try { + if (value == "true" || value == "false") { + target = (value == "true"); + } else if (value == "null") { + target = json(); + } else if (!value.empty() && value.front() == '[' && value.back() == ']') { + target = json::parse(value); // Parse list + } else if (value.find('.') != std::string::npos) { + target = std::stod(value); + } else { + target = std::stoi(value); + } + } catch (...) { + target = value; + } + return; + } else { + current = &((*current)[key]); + } + } + } +} \ No newline at end of file diff --git a/src/Daughter.hpp b/src/Daughter.hpp index ea703e0..802a06a 100644 --- a/src/Daughter.hpp +++ b/src/Daughter.hpp @@ -27,7 +27,7 @@ class Daughter { float GetCutChi2Prim() const { return chi2_prim_; } float GetCutCos() const { return cos_; } int GetId() const { return id_; } - + void SetGeneration(int generation) { generation_ = generation; } void SetCutChi2Prim(float value) { chi2_prim_ = value; } void SetCutCos(float value) { cos_ = value; } diff --git a/src/Decay.hpp b/src/Decay.hpp index d43d180..95336c8 100644 --- a/src/Decay.hpp +++ b/src/Decay.hpp @@ -1,11 +1,11 @@ #ifndef KFPARTICLESIMPLE_KFSIMPLE_DECAY_HPP_ #define KFPARTICLESIMPLE_KFSIMPLE_DECAY_HPP_ +#include #include #include #include #include -#include #include "Daughter.hpp" #include "Mother.hpp" @@ -46,14 +46,14 @@ class Decay { void SetMother(const Mother& mother) { mother_ = mother; } int GetNDaughters() const { return daughters_.size(); } - + void SetIsApplyMassConstraint(bool is = true) { is_apply_mass_constraint_ = is; } void SetIsTransportToPV(bool is = true) { is_transport_to_pv_ = is; } void SetIsDoNotWriteMother(bool is = true) { - std::cout << "WARNING!! If the mother particle is not written in the output-tree, MC-matching is not possible for upper-level mothers from cascade decays. "<< std::endl; - is_do_not_write_mother_ = is; + std::cout << "WARNING!! If the mother particle is not written in the output-tree, MC-matching is not possible for upper-level mothers from cascade decays. " << std::endl; + is_do_not_write_mother_ = is; } - + bool GetIsApplyMassConstraint() const { return is_apply_mass_constraint_; } bool GetIsTransportToPV() const { return is_transport_to_pv_; } bool GetIsDoNotWriteMother() const { return is_do_not_write_mother_; } @@ -63,7 +63,7 @@ class Decay { Mother mother_; ///< cuts for mother particle std::vector daughters_{};///< cuts for daughter particles - + bool is_apply_mass_constraint_{false}; bool is_transport_to_pv_{false}; bool is_do_not_write_mother_{false}; diff --git a/src/Mother.cpp b/src/Mother.cpp index 46c0cb2..104ab17 100644 --- a/src/Mother.cpp +++ b/src/Mother.cpp @@ -25,22 +25,22 @@ float Mother::GetMassKFDatabase() const { float massPDG, massPDGsigma; KFParticleDatabase::Instance()->GetMotherMass(pdg_, massPDG, massPDGsigma); - + if (massPDG == mass_kaon_ && pdg_ != 310) throw std::runtime_error("Mass for mother pdg " + to_string(pdg_) + " is not availabe in KFParticleDatabase. Set mass manually with Mother::SetMassPdg(mass)."); - + return massPDG; }; float Mother::GetMassSigmaKFDatabase() const { if (mass_pdg_sigma_ > 0) return mass_pdg_sigma_; - + float massPDG, massPDGsigma; KFParticleDatabase::Instance()->GetMotherMass(pdg_, massPDG, massPDGsigma); if (massPDG == mass_kaon_ && pdg_ != 310) throw std::runtime_error("Mass sigma for mother pdg " + to_string(pdg_) + " is not availabe in KFParticleDatabase. Set mass sigma manually with Mother::SetMassPdgSigma(mass_sigma)."); - + return massPDGsigma; }; diff --git a/src/Mother.hpp b/src/Mother.hpp index 46f5a50..4918e36 100644 --- a/src/Mother.hpp +++ b/src/Mother.hpp @@ -2,8 +2,8 @@ #define KFPARTICLESIMPLE_KFSIMPLE_MOTHERCUTS_HPP_ #include -#include #include +#include #include "Constants.hpp" @@ -17,7 +17,10 @@ class Mother { Mother& operator=(const Mother&) = default; ~Mother() = default; - explicit Mother(Pdg_t pdg) : pdg_(pdg) { mass_pdg_ = -1.0; mass_pdg_sigma_ = -1.0; } + explicit Mother(Pdg_t pdg) : pdg_(pdg) { + mass_pdg_ = -1.0; + mass_pdg_sigma_ = -1.0; + } void SetMassPdg(float mass_pdg) { mass_pdg_ = mass_pdg; } void SetMassPdgSigma(float mass_pdg_sigma) { mass_pdg_sigma_ = mass_pdg_sigma; } @@ -44,7 +47,7 @@ class Mother { for (std::size_t i = 1; i < cos_open_sm.size() + 1; ++i) cos_open_.at(i) = cos_open_sm.at(i - 1); } void SetCutInvMass(float value) { invmass_discrepancy_ = value; } - + void CancelCutDistance() { this->SetCutDistance(huge_value); } void CancelCutDistanceToSV() { this->SetCutDistanceToSV(huge_value); } void CancelCutChi2Geo() { this->SetCutChi2Geo(huge_value); } @@ -58,16 +61,18 @@ class Mother { void CancelCutCosTopoSM() { this->SetCutCosTopoSM({huge_value, huge_value, huge_value}); } void CancelCutCosOpen() { this->SetCutCosOpen(-huge_value); } void CancelCutCosOpenSM() { this->SetCutCosOpenSM({-huge_value, -huge_value, -huge_value}); } - void CancelCutInvMass() { this->SetCutInvMass(huge_value); } + void CancelCutInvMass() { this->SetCutInvMass(huge_value); } void CancelCuts(); Pdg_t GetPdg() const { return pdg_; } float GetMassPdg() { if (mass_pdg_ < 0) mass_pdg_ = GetMassKFDatabase(); - return mass_pdg_; }; + return mass_pdg_; + }; float GetMassPdgSigma() { if (mass_pdg_sigma_ < 0) mass_pdg_sigma_ = GetMassSigmaKFDatabase(); - return mass_pdg_sigma_; } + return mass_pdg_sigma_; + } float GetMassKFDatabase() const; float GetMassSigmaKFDatabase() const; float GetCutDistance() const { return distance_; } @@ -85,7 +90,7 @@ class Mother { Pdg_t pdg_{-1}; float mass_pdg_{-1.0}; float mass_pdg_sigma_{-1.0}; - float mass_kaon_{0.497614}; // default mass value in KFParticleDatabase + float mass_kaon_{0.497614};// default mass value in KFParticleDatabase float distance_{1.f};///< lower value float distance_sv_{1.f}; diff --git a/src/SimpleFinder.cpp b/src/SimpleFinder.cpp index 81c53d2..4e2583d 100644 --- a/src/SimpleFinder.cpp +++ b/src/SimpleFinder.cpp @@ -7,12 +7,12 @@ using std::to_string; void SimpleFinder::Init(std::vector&& tracks, const KFVertex& pv) { output_.clear(); current_candidate_id_ = 0; - + if (!tracks.empty()) last_track_id_ = tracks.at(tracks.size() - 1).Id(); - else + else last_track_id_ = 0; - + tracks_ = tracks; prim_vx_ = pv; } @@ -71,10 +71,10 @@ void SimpleFinder::CalculateParamsInSV(const std::array& tracks, } for (int i = 0; i < 3; i++) - sec_vx_.at(i) = (sec_vx.at(0).at(i) + sec_vx.at(1).at(i) + sec_vx.at(2).at(i)) / 3 ; - + sec_vx_.at(i) = (sec_vx.at(0).at(i) + sec_vx.at(1).at(i) + sec_vx.at(2).at(i)) / 3; + params_.resize(3); - + for (int itrack = 0; itrack < 3; itrack++) { KFParticle particle(tracks.at(itrack)); particle.SetPDG(pids.at(itrack)); @@ -112,7 +112,7 @@ KFParticleSIMD SimpleFinder::ConstructMother(const std::vector& trac std::vector particles_simd{}; for (size_t i = 0; i < n; ++i) { - if(tracks.at(i).Id() <= last_track_id_) + if (tracks.at(i).Id() <= last_track_id_) SetKFParticleEnergy(particles.at(i), pdgs.at(i)); particles.at(i).SetPDG(pdgs.at(i)); particles.at(i).SetId(tracks.at(i).Id());// TODO rm obsolet ID copying? @@ -138,17 +138,15 @@ KFParticleSIMD SimpleFinder::ConstructMother(const std::vector& trac const KFParticleSIMD* vDaughtersPointer[2] = {&particles_simd.at(0), &particles_simd.at(1)}; mother.Construct(vDaughtersPointer, 2, nullptr); - if((tracks.at(0).Id() <= last_track_id_ || tracks.at(1).Id() <= last_track_id_) && print) - { - std::cout << particles_simd.at(0).GetPx()[0] << "\t" << particles_simd.at(0).GetPy()[0] << "\t" << particles_simd.at(0).GetPz()[0] << "\t" << particles_simd.at(0).GetE()[0] << "\n"; - std::cout << particles_simd.at(1).GetPx()[0] << "\t" << particles_simd.at(1).GetPy()[0] << "\t" << particles_simd.at(1).GetPz()[0] << "\t" << particles_simd.at(1).GetE()[0] << "\n"; - std::cout << mother.GetPx()[0] << "\t" << mother.GetPy()[0] << "\t" << mother.GetPz()[0] << "\t" << mother.GetE()[0] << "\n"; - } - + if ((tracks.at(0).Id() <= last_track_id_ || tracks.at(1).Id() <= last_track_id_) && print) { + std::cout << particles_simd.at(0).GetPx()[0] << "\t" << particles_simd.at(0).GetPy()[0] << "\t" << particles_simd.at(0).GetPz()[0] << "\t" << particles_simd.at(0).GetE()[0] << "\n"; + std::cout << particles_simd.at(1).GetPx()[0] << "\t" << particles_simd.at(1).GetPy()[0] << "\t" << particles_simd.at(1).GetPz()[0] << "\t" << particles_simd.at(1).GetE()[0] << "\n"; + std::cout << mother.GetPx()[0] << "\t" << mother.GetPy()[0] << "\t" << mother.GetPz()[0] << "\t" << mother.GetE()[0] << "\n"; + } + } else if (n == 3) { const KFParticleSIMD* vDaughtersPointer[3] = {&particles_simd.at(0), &particles_simd.at(1), &particles_simd.at(2)}; mother.Construct(vDaughtersPointer, 3, nullptr); - } return mother; @@ -239,18 +237,13 @@ bool SimpleFinder::IsGoodDaughter(const KFParticle& track, const Daughter& daugh values_.chi2_prim.at(id) = CalculateChiToPrimaryVertex(track, daughter.GetPdgHypo()); if (values_.chi2_prim.at(id) < daughter.GetCutChi2Prim() || std::isnan(values_.chi2_prim.at(id))) { return false; } - - if (! (track.Id() > last_track_id_)) { - if (TMath::Abs(daughter.GetPdgHypo()) == 3112 || - TMath::Abs(daughter.GetPdgHypo()) == 3312 || - TMath::Abs(daughter.GetPdgHypo()) == 3334 || - TMath::Abs(daughter.GetPdgHypo()) == 11 || - TMath::Abs(daughter.GetPdgHypo()) == 13) { + + if (!(track.Id() > last_track_id_)) { + if (TMath::Abs(daughter.GetPdgHypo()) == 3112 || TMath::Abs(daughter.GetPdgHypo()) == 3312 || TMath::Abs(daughter.GetPdgHypo()) == 3334 || TMath::Abs(daughter.GetPdgHypo()) == 11 || TMath::Abs(daughter.GetPdgHypo()) == 13) { if ((TMath::Sign(1, daughter.GetPdgHypo()) > 0 && track.Q() != -1) || (TMath::Sign(1, daughter.GetPdgHypo()) < 0 && track.Q() != +1)) { return false; } - } - else { + } else { if ((TMath::Sign(1, daughter.GetPdgHypo()) > 0 && track.Q() != +1) || (TMath::Sign(1, daughter.GetPdgHypo()) < 0 && track.Q() != -1)) { return false; } - } + } } return true; @@ -262,7 +255,7 @@ bool SimpleFinder::IsGoodPair(const KFParticle& track1, if (track1.Id() == track2.Id()) { return false; } - std::vector tracks = { track1, track2}; + std::vector tracks = {track1, track2}; if (IsGoodTrackIdsGenerations(tracks) == false) { return false; } int generation1 = track1.Id() > last_track_id_ ? 1 : 0; @@ -272,8 +265,7 @@ bool SimpleFinder::IsGoodPair(const KFParticle& track1, for (int i = 0; i < tracks.size(); i++) generation.push_back(tracks[i].Id() > last_track_id_ ? 1 : 0); - if (std::accumulate(generation.begin(), generation.end(), 0) > 0) - { + if (std::accumulate(generation.begin(), generation.end(), 0) > 0) { KFParticle track1_nonconst = track1; KFParticle track2_nonconst = track2; KFParticleSIMD track1_simd = KFParticleSIMD(track1_nonconst); @@ -281,8 +273,7 @@ bool SimpleFinder::IsGoodPair(const KFParticle& track1, track1_simd.SetPDG(decay.GetDaughters().at(0).GetPdgHypo()); track2_simd.SetPDG(decay.GetDaughters().at(1).GetPdgHypo()); values_.distance = CalculateDistanceBetweenParticles(track1_simd, track2_simd); - } - else + } else values_.distance = CalculateDistanceBetweenParticles(); if (values_.distance > decay.GetMother().GetCutDistance() || std::isnan(values_.distance)) { return false; } @@ -302,8 +293,8 @@ bool SimpleFinder::IsGoodThree(const KFParticle& track1, if (track1.Id() == track2.Id()) { return false; } if (track1.Id() == track3.Id()) { return false; } if (track2.Id() == track3.Id()) { return false; } - - std::vector tracks = { track1, track2, track3 }; + + std::vector tracks = {track1, track2, track3}; if (IsGoodTrackIdsGenerations(tracks) == false) { return false; } values_.distance_sv = CalculateDistanceToSV(); @@ -316,9 +307,9 @@ bool SimpleFinder::IsGoodThree(const KFParticle& track1, } std::vector cos_tmp; - for (int i = 1; i < 4; i++) + for (int i = 1; i < 4; i++) cos_tmp.push_back(values_.cos_open[i]); - + values_.cos_open[0] = *std::min_element(cos_tmp.begin(), cos_tmp.end()); if (values_.cos_open[0] < decay.GetMother().GetCutCosOpen()[0] || std::isnan(values_.cos_open[0])) { return false; } @@ -328,13 +319,13 @@ bool SimpleFinder::IsGoodThree(const KFParticle& track1, bool SimpleFinder::IsGoodMother(const KFParticleSIMD& kf_mother, const Mother& mother, const int id_mother) { values_.chi2_geo[id_mother] = kf_mother.Chi2()[0] / simd_cast(kf_mother.NDF())[0]; if (values_.chi2_geo[id_mother] > mother.GetCutChi2Geo()[id_mother] || std::isnan(values_.chi2_geo[id_mother])) { return false; } - if (values_.chi2_geo[id_mother] < 0. || ! std::isfinite(values_.chi2_geo[id_mother])) { return false; } + if (values_.chi2_geo[id_mother] < 0. || !std::isfinite(values_.chi2_geo[id_mother])) { return false; } return true; } bool SimpleFinder::IsGoodMotherMass(const KFParticleSIMD& kf_mother, const Mother& mother) { KFParticle particle; - KFParticleSIMD(kf_mother).GetKFParticle(particle, 0); + KFParticleSIMD(kf_mother).GetKFParticle(particle, 0); values_.invmassdisc = CalculateInvMassDiscrepancy(particle, mother); if (std::fabs(values_.invmassdisc) > mother.GetCutInvMass()) { return false; } return true; @@ -361,9 +352,9 @@ bool SimpleFinder::IsMotherFromPV(const KFParticleSIMD& kf_mother, const Mother& } KFParticle particle; - KFParticleSIMD(kf_mother).GetKFParticle(particle, 0); + KFParticleSIMD(kf_mother).GetKFParticle(particle, 0); values_.chi2_prim_mother = CalculateChiToPrimaryVertex(particle, mother.GetPdg()); - + return true; } @@ -396,19 +387,18 @@ bool SimpleFinder::IsGoodDecayLength(const KFParticleSIMD& kf_mother, const Moth void SimpleFinder::SaveParticle(KFParticleSIMD& particle_simd, const Decay& decay) { KFParticle particle; - + auto mothertmp = decay.GetMother(); - if(decay.GetIsApplyMassConstraint()) + if (decay.GetIsApplyMassConstraint()) particle_simd.SetNonlinearMassConstraint(float_v(mothertmp.GetMassPdg())); - - if(decay.GetIsTransportToPV()) - { - KFVertex prim_vx_tmp = prim_vx_; - const KFParticleSIMD prim_vx_Simd(prim_vx_tmp); - const float_v point[3] = {prim_vx_Simd.X(), prim_vx_Simd.Y(), prim_vx_Simd.Z()}; - particle_simd.TransportToPoint(point); - } - + + if (decay.GetIsTransportToPV()) { + KFVertex prim_vx_tmp = prim_vx_; + const KFParticleSIMD prim_vx_Simd(prim_vx_tmp); + const float_v point[3] = {prim_vx_Simd.X(), prim_vx_Simd.Y(), prim_vx_Simd.Z()}; + particle_simd.TransportToPoint(point); + } + particle_simd.GetKFParticle(particle, 0); particle.SetPDG(decay.GetMother().GetPdg()); @@ -417,7 +407,7 @@ void SimpleFinder::SaveParticle(KFParticleSIMD& particle_simd, const Decay& deca particle.SetId(track_id); tracks_.emplace_back(particle); current_candidate_id_++; - + if (decay.GetIsDoNotWriteMother() == true) return; OutputContainer mother(particle); @@ -426,7 +416,7 @@ void SimpleFinder::SaveParticle(KFParticleSIMD& particle_simd, const Decay& deca std::vector daughters_generation; for (int i = 0; i < particle.NDaughters(); i++) - if (particle.DaughterIds().at(i) > last_track_id_ ) + if (particle.DaughterIds().at(i) > last_track_id_) daughters_generation.push_back(1); else daughters_generation.push_back(0); @@ -465,7 +455,7 @@ bool SimpleFinder::IsGoodCos(const KFParticleSIMD& mother, const Decay& decay) { float SimpleFinder::CalculateCosOpen(const int id_daughter_1, const int id_daughter_2) const { const auto& par1 = params_.at(id_daughter_1); const auto& par2 = params_.at(id_daughter_2); - const float sp = par1[kPx] * par2[kPx] + par1[kPy] * par2[kPy] + par1[kPz] * par2[kPz]; + const float sp = par1[kPx] * par2[kPx] + par1[kPy] * par2[kPy] + par1[kPz] * par2[kPz]; const float norm = std::sqrt(par1[kPx] * par1[kPx] + par1[kPy] * par1[kPy] + par1[kPz] * par1[kPz]) * std::sqrt(par2[kPx] * par2[kPx] + par2[kPy] * par2[kPy] + par2[kPz] * par2[kPz]); return sp / norm; @@ -485,47 +475,47 @@ bool SimpleFinder::IsGoodTrackIdsGenerations(const std::vector track std::vector> trackIdsGen0; std::vector> tracksLevel; - + tracksLevel.resize(1); for (int i = 0; i < n; i++) tracksLevel.at(0).push_back(tracks[i]); - + int ilevel = 0; - while (tracksLevel.at(ilevel).size() > 0) { + while (tracksLevel.at(ilevel).size() > 0) { int ntracksL = tracksLevel.at(ilevel).size(); - trackIdsGen0.resize(ilevel+1); - tracksLevel.resize(ilevel+2); - + trackIdsGen0.resize(ilevel + 1); + tracksLevel.resize(ilevel + 2); + for (int i = 0; i < ntracksL; i++) { - if( !(tracksLevel.at(ilevel)[i].Id() > last_track_id_)) - trackIdsGen0.at(ilevel).push_back(tracksLevel.at(ilevel)[i].Id()); + if (!(tracksLevel.at(ilevel)[i].Id() > last_track_id_)) + trackIdsGen0.at(ilevel).push_back(tracksLevel.at(ilevel)[i].Id()); else { - for (int idaughter = 0; idaughter < tracksLevel.at(ilevel)[i].DaughterIds().size(); idaughter++) { - int daughterId = tracksLevel.at(ilevel)[i].DaughterIds().at(idaughter); - int index = id2index_.find(daughterId)->second; - tracksLevel.at(ilevel + 1).push_back(tracks_[index]); - } + for (int idaughter = 0; idaughter < tracksLevel.at(ilevel)[i].DaughterIds().size(); idaughter++) { + int daughterId = tracksLevel.at(ilevel)[i].DaughterIds().at(idaughter); + int index = id2index_.find(daughterId)->second; + tracksLevel.at(ilevel + 1).push_back(tracks_[index]); + } } } - ilevel ++; + ilevel++; } - + ilevel = 0; while (trackIdsGen0.size() > ilevel + 1) { - if (trackIdsGen0.at(ilevel+1).size() == 0) - return false; - for (int itrack = 0; itrack < trackIdsGen0.at(ilevel).size(); itrack++) { + if (trackIdsGen0.at(ilevel + 1).size() == 0) + return false; + for (int itrack = 0; itrack < trackIdsGen0.at(ilevel).size(); itrack++) { int jlevel = ilevel + 1; while (trackIdsGen0.size() > jlevel) { - for (int jtrack = 0; jtrack < trackIdsGen0.at(jlevel).size(); jtrack++) { - if (trackIdsGen0.at(ilevel)[itrack] == trackIdsGen0.at(jlevel)[jtrack]) - return false; - } - jlevel ++; + for (int jtrack = 0; jtrack < trackIdsGen0.at(jlevel).size(); jtrack++) { + if (trackIdsGen0.at(ilevel)[itrack] == trackIdsGen0.at(jlevel)[jtrack]) + return false; + } + jlevel++; } } - ilevel ++; + ilevel++; } return true; } @@ -564,7 +554,7 @@ void SimpleFinder::ReconstructDecay(const Decay& decay) { track.at(1).Pz() *= std::abs(charge); } - CalculateParamsInPCA(track.at(0), pdgs.at(0), track.at(1), pdgs.at(1)); + CalculateParamsInPCA(track.at(0), pdgs.at(0), track.at(1), pdgs.at(1)); if (!IsGoodPair(track.at(0), track.at(1), decay)) continue; KFParticleSIMD kf_mother = ConstructMother({track.at(0), track.at(1)}, pdgs, decay, false); @@ -575,8 +565,8 @@ void SimpleFinder::ReconstructDecay(const Decay& decay) { if (!IsMotherFromPV(kf_mother, decay.GetMother(), id_mother)) continue; if (!IsGoodDecayLength(kf_mother, decay.GetMother())) continue; if (!IsGoodCos(kf_mother, decay)) continue; - if (!IsGoodMotherMass(kf_mother, decay.GetMother())) continue; - + if (!IsGoodMotherMass(kf_mother, decay.GetMother())) continue; + FillDaughtersInfo({track.at(0), track.at(1)}, pdgs); SaveParticle(kf_mother, decay); @@ -599,27 +589,27 @@ void SimpleFinder::ReconstructDecay(const Decay& decay) { track.at(2).Pz() *= std::abs(charge); } - CalculateParamsInSV(track, pdgs); - + CalculateParamsInSV(track, pdgs); + if (!IsGoodThree(track.at(0), track.at(1), track.at(2), decay)) continue; - id_mother = 2; - kf_mother = ConstructMother({track.at(0), track.at(2)}, {pdgs.at(0), pdgs.at(2)}, decay); + id_mother = 2; + kf_mother = ConstructMother({track.at(0), track.at(2)}, {pdgs.at(0), pdgs.at(2)}, decay); if (!IsGoodMother(kf_mother, decay.GetMother(), id_mother)) continue; if (IsMotherFromPV(kf_mother, decay.GetMother(), id_mother)) continue; - id_mother = 3; - kf_mother = ConstructMother({track.at(1), track.at(2)}, {pdgs.at(1), pdgs.at(2)}, decay); + id_mother = 3; + kf_mother = ConstructMother({track.at(1), track.at(2)}, {pdgs.at(1), pdgs.at(2)}, decay); if (!IsGoodMother(kf_mother, decay.GetMother(), id_mother)) continue; if (IsMotherFromPV(kf_mother, decay.GetMother(), id_mother)) continue; - id_mother = 0; - kf_mother = ConstructMother({track.at(0), track.at(1), track.at(2)}, pdgs, decay); + id_mother = 0; + kf_mother = ConstructMother({track.at(0), track.at(1), track.at(2)}, pdgs, decay); if (!IsGoodMother(kf_mother, decay.GetMother(), id_mother)) continue; if (!IsMotherFromPV(kf_mother, decay.GetMother(), id_mother)) continue; if (!IsGoodDecayLength(kf_mother, decay.GetMother())) continue; if (!IsGoodCos(kf_mother, decay)) continue; - if (!IsGoodMotherMass(kf_mother, decay.GetMother())) continue; + if (!IsGoodMotherMass(kf_mother, decay.GetMother())) continue; FillDaughtersInfo({track.at(0), track.at(1), track.at(2)}, pdgs); @@ -637,6 +627,3 @@ void SimpleFinder::FillDaughtersInfo(const std::vector& tracks, cons values_.chi2_prim[i] = CalculateChiToPrimaryVertex(tracks.at(i), pdgs.at(i)); } } - - - diff --git a/src/SimpleFinder.hpp b/src/SimpleFinder.hpp index 3ed8657..5d3ea1a 100644 --- a/src/SimpleFinder.hpp +++ b/src/SimpleFinder.hpp @@ -13,11 +13,11 @@ #ifndef KFPARTICLESIMPLE_KFSIMPLE_SIMPLEFINDER_HPP_ #define KFPARTICLESIMPLE_KFSIMPLE_SIMPLEFINDER_HPP_ -#include #include +#include -#include #include +#include #include #include #include @@ -67,14 +67,14 @@ class SimpleFinder { NonLinearCutBase* ml_cuts_{nullptr};///< input information: non-linear cuts class (optional) std::map> indexes_{};///< map of indexes for a given particle specie - std::map id2index_{}; ///< map of track Ids to indexes - Parameters_t params_{}; ///< vector of daughter parameters at current SV estimation - SelectionValues values_{};///< struct with mother and daughters properties used to apply cuts + std::map id2index_{}; ///< map of track Ids to indexes + Parameters_t params_{}; ///< vector of daughter parameters at current SV estimation + SelectionValues values_{}; ///< struct with mother and daughters properties used to apply cuts std::vector output_{};///< output information: vector of candidates int current_candidate_id_{0}; int last_track_id_{0}; - + /** * Find indexes of good daughters * @param cuts daughter particle cuts container @@ -92,7 +92,7 @@ class SimpleFinder { bool IsGoodCos(const KFParticleSIMD& mother, const Decay& decay); bool IsGoodTrackIdsGenerations(const std::vector tracks); - KFParticleSIMD ConstructMother(const std::vector& tracks, const std::vector& pdgs, const Decay& decay, bool print=false); + KFParticleSIMD ConstructMother(const std::vector& tracks, const std::vector& pdgs, const Decay& decay, bool print = false); void CalculateSecondaryVertex(); void CalculateParamsInPCA(const KFParticle& track1, int pid1, const KFParticle& track2, int pid2); @@ -121,4 +121,3 @@ class SimpleFinder { }; #endif//KFPARTICLESIMPLE_KFSIMPLE_SIMPLEFINDER_HPP_ -