Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
31a9591
Added extra DIS variables to electron scattering: xbj, nu, tau, tau p…
Garypenman Feb 21, 2026
8c7b13a
updated photo helicity decay header with inline functions and doxygen
Garypenman Feb 21, 2026
d9c5149
Added TCS HepMC example
Garypenman Feb 21, 2026
7aeef97
Merge branch 'master' of github.com:dglazier/rad into combi_dev
Garypenman Feb 24, 2026
f45d55c
indicing tests TCS
Garypenman Feb 24, 2026
b5985a7
added overlad to analysis manager constructor to read in vector of st…
Garypenman Mar 2, 2026
0e5eb64
added theta to DecayAngles_t struct, for brufit and other purposes
Garypenman Mar 2, 2026
1970b2c
default behaviour for useBeamsFromMC should be false
Garypenman Mar 2, 2026
7660b15
merge master branch combi fixes
Garypenman Mar 2, 2026
b7679ad
fixed erronous pickup of file from old branch in last commit
Garypenman Mar 3, 2026
edcd6a6
add some smearing modifers for particle momentum
dglazier Mar 10, 2026
71a5a16
add CheckedFullName as extra FullName. add FilterIndicesWithFlag meth…
dglazier Mar 24, 2026
48d3d3f
Merge branch 'combi_dev' into modifiers
dglazier Mar 24, 2026
a480482
Merge pull request #1 from dglazier/modifiers
Garypenman Mar 24, 2026
82a20d5
Local changes to pull upstream merge from derek
Garypenman Mar 24, 2026
a94cde2
Merged local dev changes with upstream and origin merge
Garypenman Mar 24, 2026
c0a5e54
added bool cut for truth match selection in streams
Garypenman Mar 24, 2026
e025a1e
Pushing lingering changes to dev branch
Garypenman Apr 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions examples/ProcessHepMCTCSCombi.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#include "CommonDefines.h"
#include "HepMCElectro.h"
#include "KinematicsProcElectro.h"
#include "KineCalculation.h"
#include "Indicing.h"
#include "ElectronScatterKinematics.h"
#include "gammaN_2_Spin0Spin0SpinHalf.h"
#include "TCSKinematics.h"
#include <TBenchmark.h>

/**
* @brief Example Script: TCS Analysis with Combinatorics and Missing Mass.
* Updated to use SetMesonParticles shortcut and CloneLinked.
*/
void ProcessHepMCTCSCombi(){

using namespace rad;
using namespace rad::consts::data_type;

gBenchmark->Start("df");

// =================================================================================
// 1. SETUP & INJECTION
// =================================================================================
HepMCElectro hepmc{
"hepmc3_tree",
"/w/work5/home/garyp/eic/Farm/data/EpIC_DDVCS_ee_18x275/rootfiles/18x275_ddvcs_edecay_hplus.root"
};
hepmc.SetupMC();

// =================================================================================
// 2. PARTICLE DEFINITIONS
// =================================================================================
hepmc.SetBeamIonIndex(3);
hepmc.SetBeamElectronIndex(0);
//hepmc.SetScatElectronCandidates({1, 6});
//hepmc.SetParticleCandidates("ele", {1, 6});
hepmc.SetScatElectronIndex(1);
hepmc.SetParticleIndex("ele",6);
hepmc.SetParticleIndex("pos", 7);
hepmc.SetParticleIndex("pprime", 5);

hepmc.MakeCombinations();

// =================================================================================
// 3. KINEMATICS PROCESSOR (Standard Topology)
// =================================================================================
KinematicsProcElectro kine{&hepmc, MC()};

// A. Define Particles FIRST (Topology Construction)
kine.Creator().Sum("gprime", {{"ele", "pos"}});

// Missing Mass: n_calc = (Beam + Target) - (ScatEle + Jpsi + pi+)
kine.Creator().Diff("pprime_calc",{
{consts::BeamIon(), consts::BeamEle()},
{"gprime", consts::ScatEle()}
});

// B. Define Groups NEXT (Lazy Definition)
// This uses the Processor's SetGroup wrapper, ensuring "Z" exists before the group is built.
kine.SetMesonParticles({"ele","pos"});
kine.SetBaryonParticles({"pprime"});

// =================================================================================
// 4. CALCULATIONS (Registered on Master)
// =================================================================================
// These will be calculated for Master AND automatically copied to the Linked clone

kine.Q2();
kine.xbj();
kine.y();
kine.nu();
kine.tau();
kine.tauprime();

kine.RegisterCalc("GammaPol",rad::physics::ElS_PolVirtPhot);
kine.RegisterCalc("GammaPolCirc",rad::physics::ElS_CircPolVirtPhot);

kine.RegisterCalc("CosThetaHel",rad::gn2s0s0s12::CosThetaHel);
kine.RegisterCalc("ThetaHel",rad::gn2s0s0s12::ThetaHel);
kine.RegisterCalc("PhiHel",rad::gn2s0s0s12::PhiHel);

kine.CosThetaCM();
kine.PhiCM();

kine.Mass("GMass", {"gprime"});
kine.Mass2("Qp2", {"gprime"});
kine.Mass2("MissMass2",
{consts::BeamIon(), consts::BeamEle()},
{"gprime", consts::ScatEle(), "pprime"});

kine.RegisterCalc("t_top", rad::physics::TTop);
kine.RegisterCalc("t_bot", rad::physics::TBot);
kine.RegisterCalc("tp_top", rad::physics::TPrimeTop);
kine.RegisterCalc("tp_bot", rad::physics::TPrimeBot);

kine.RegisterCalc("deltaT_top", rad::physics::DeltaTTop);
kine.RegisterCalc("deltaT_bot", rad::physics::DeltaTBot);

// =================================================================================
// 5. LINKED PROCESSOR (Cloned Hypothesis)
// =================================================================================

// 1. Clone: Copies all the calculations registered above (Q2, Phi, Mass, tp...)
// Creates a new processor for the "mc_" stream but with suffix "_ncalc"
// auto kine_miss = kine.CloneLinked("_ncalc");

// // 2. Customize: Override "Baryons" to be "n_calc" (missing neutron) for this hypothesis
// kine_miss->SetBaryonParticles({"n_calc"});

// =================================================================================
// 6. INITIALIZATION & EXECUTION
// =================================================================================

// Init Master: Executes definitions and calculations for Standard Topology
kine.Init();

// Init Linked: Binds to 'kine' topology and executes copied calculations for Missing Topology
//kine_miss->InitLinked(kine);

gBenchmark->Start("snapshot");
hepmc.Snapshot("/w/work5/home/garyp/combirad_trees/HepMC_ddvcs_ee_18x275_hplus.root");
gBenchmark->Stop("snapshot");
gBenchmark->Print("snapshot");
}
105 changes: 89 additions & 16 deletions include/AnalysisManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,32 @@ namespace rad {
* @param fileGlob Input file path/pattern.
*/
AnalysisManager(const std::string& name, const std::string& treeName, const std::string& fileGlob);



/**
* @brief Constructor (multiple input files).
* @param name Name of the analysis (used for output filenames).
* @param treeName Input TTree name.
* @param files Vector of input file paths.
*/
AnalysisManager(const std::string& name, const std::string& treeName, const ROOT::RVec<std::string>& files);


/**
* @brief Constructor (frome existing reaction).
* @param name Name of the analysis (used for output filenames).
* @param baseReaction Identifier of the base Reaction
*/
AnalysisManager(const std::string& name, const ReactionClass& baseReaction);


/**
* @brief Constructor clone method.
* @param newName Name of the new cloned analysis (used for output filenames).
* @param baseReaction Identifier of the base Reaction
*/
AnalysisManager Clone(const std::string& newName, bool copyStreams = false) const;

/** @brief Sets and creates the output directory. */
void SetOutputDir(const std::string& dir);

Expand Down Expand Up @@ -146,7 +171,7 @@ namespace rad {
* - Example: output/Y4260_rec_loose_Hist.root
* @param suffix Suffix for the histogram file (default "Hist.root").
*/
void Run(const std::string& suffix = "Hist.root");
void Run(const std::string& suffix = "_Hist.root");

/**
* @brief Print comprehensive diagnostics for the entire analysis setup.
Expand Down Expand Up @@ -182,13 +207,18 @@ namespace rad {
fullName += lbl;
outputSuffix = "_" + lbl;
}
else{
fullName.pop_back();
//if no labels we dont want "rec_" + "_Tree.root"
//i.e. rec__Tree.root, rec__Hist.root
}

// Ensure input prefix ends in "_" (e.g. "rec" -> "rec_")
std::string inputPrefix = src;
if(inputPrefix.back() != '_') inputPrefix += "_";

kine = std::make_unique<ProcessorClass>(reaction, inputPrefix, outputSuffix);
sel = std::make_unique<PhysicsSelection>(*kine);
sel = std::make_unique<PhysicsSelection>(*kine);
hist = std::make_unique<histo::Histogrammer>(*kine, sel.get());
}
};
Expand All @@ -212,17 +242,48 @@ namespace rad {
// ===========================================================================

template <typename R, typename P>
inline AnalysisManager<R,P>::AnalysisManager(const std::string& name, const std::string& treeName, const std::string& fileGlob)
: _reaction(treeName, fileGlob), _name(name) {}
inline AnalysisManager<R,P>::AnalysisManager(const std::string& name,
const std::string& treeName,
const std::string& fileGlob)
: _reaction(treeName, fileGlob), _name(name) {}


template <typename R, typename P>
inline AnalysisManager<R,P>::AnalysisManager(const std::string& name,
const std::string& treeName,
const ROOT::RVec<std::string>& files)
: _reaction(treeName, files), _name(name) {}

template <typename R, typename P>
inline void AnalysisManager<R,P>::SetOutputDir(const std::string& dir) {
_outputDir = dir;
if (!_outputDir.empty() && !std::filesystem::exists(_outputDir)) {
std::filesystem::create_directories(_outputDir);
}
inline void AnalysisManager<R,P>::SetOutputDir(const std::string& dir) {
_outputDir = dir;
if (!_outputDir.empty() && !std::filesystem::exists(_outputDir)) {
std::filesystem::create_directories(_outputDir);
}
}


template <typename R, typename P>
AnalysisManager<R,P>::AnalysisManager(const std::string& name,
const R& baseReaction)
: _reaction(baseReaction), _name(name)
{}//if this works we probably want to have safety on being base i.e. nothing setup yet, and clearing triggers etc

// --- Clone Management ---

template <typename R, typename P>
AnalysisManager<R,P> AnalysisManager<R,P>::Clone(const std::string& newName,
bool copyStreams) const
{
AnalysisManager<R,P> out(newName, _reaction);

if (copyStreams)
for (auto& [key, s] : _streams)
out.AddStream(s.source, s.label);
out.SetOutputDir(_outputDir);
return out;
}


// --- Stream Management ---

template <typename R, typename P>
Expand Down Expand Up @@ -320,12 +381,17 @@ namespace rad {
inline void AnalysisManager<R,P>::Init() {
if(_initialized) return;
if(_primaryStream.empty()) throw std::runtime_error("[AnalysisManager] No streams defined! Call SetTypes() or AddStream().");


/* // PASS 0: Ensure truth variable goes through prefix/suffix machinery */
/* for(auto& [key, stream] : _streams) { */
/* stream.kine->RegisterExternalVar(consts::TruthMatchedCombi()); */
/* } */

// PASS 1: Initialize Kinematics (Create Variables)
for(auto& [key, stream] : _streams) {
stream.kine->Init();
}

stream.kine->Init();
}
// PASS 2: Compile Selections (Create Masks)
for(auto& [key, stream] : _streams) {
if(stream.sel) stream.sel->Init();
Expand Down Expand Up @@ -382,7 +448,14 @@ namespace rad {

// Always add the Event Counter
cols.push_back("rdfentry_");


//Add the isTruth flag for rec streams
if(stream.source.find(Rec()) == 0){
cols.push_back(consts::TruthMatchedCombi());
cols.push_back(Rec()+consts::TruthMatchedCombi());
//cols.push_back(Rec()+consts::TruthMatchedCombi()+"_"+stream.label);
}

auto streamCols = CollectStreamColumns(*stream.kine);
cols.insert(cols.end(), streamCols.begin(), streamCols.end());

Expand Down
14 changes: 14 additions & 0 deletions include/BasicKinematics.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,20 @@ namespace rad {
return psum.Pt();
}

template<typename Tp, typename Tm>
inline ResultType_t FourVectorECalc(const RVecIndices &indices, const Tp &px, const Tp &py, const Tp &pz, const Tm &m) {
const auto& ipos = indices[0];
const auto& ineg = indices[1];

// Note: Assuming error checking for invalid indices is performed in the wrapper or upstream.

PxPyPzMVector psum(0,0,0,0);
SumFourVector(psum, ipos, px, py, pz, m);
SubtractFourVector(psum, ineg, px, py, pz, m);

return psum.E();
}

//---------------------- 3-Vector Components (RVec Ops) ----------------------

/**
Expand Down
11 changes: 7 additions & 4 deletions include/ConfigReaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ namespace rad {
// define a default "Always True" signal flag so snapshots don't break.
std::cout<<"[ConfigReaction] DefineTrueMatchCombi " <<col<<" does not exist all set TruthMatchedCombi()=1 for all."<< std::endl;
Define(consts::TruthMatchedCombi(), "1");
}

}
}

// --- Symmetry Interface ---
Expand Down Expand Up @@ -217,7 +218,7 @@ namespace rad {
const std::string& name = match.first;
int role = match.second;

std::string flagName = name + "_is_true";// + DoNotWriteTag();
std::string flagName = name + "_is_true";// + DoNotWriteTag();
std::string colName = type + name; // e.g. "rec_ele"

// Check: pIndices[i] is the candidate index for the i-th combination.
Expand All @@ -238,15 +239,17 @@ namespace rad {

},
{colName, matchIdCol});



if (!logic.empty()) logic += " && ";
logic += flagName;
}

if(logic.empty()) logic = "1";
Define(consts::TruthMatchedCombi(), logic);
Define(type + consts::TruthMatchedCombi(), consts::TruthMatchedCombi());
}

// ... [Rest of implementation remains unchanged] ...
inline void ConfigReaction::SetParticleCandidatesExpr(const std::string& name, const std::string& type, const std::string& expression) {
ValidateType(type);
Expand Down
32 changes: 8 additions & 24 deletions include/ElectroIonReaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,7 @@ namespace rad {

/** @brief Helper to set the internal index for the Beam Ion (Always 0). */
void SetBeamIonIndex(const int idx, const std::string& type = "");

/** @brief Helper to set the internal index for the Beam electron via JIT function expression */
void SetBeamElectronExpr(const std::string& type, const std::string& expression);

/** @brief Helper to set the internal index for the Beam Ion via JIT function expression */
void SetBeamIonExpr(const std::string& type, const std::string& expression);


protected:

PxPyPzMVector _p4el_beam; ///< Internal storage for Electron Beam P4
Expand Down Expand Up @@ -292,7 +286,7 @@ namespace rad {
_mcBeamEleIdx = eleIdx;
_mcBeamIonIdx = ionIdx;
_useBeamsFromMC = true;
}
}

inline void ElectroIonReaction::SetBeamElectronColumns(const std::string& px, const std::string& py,
const std::string& pz, const std::string& m,
Expand Down Expand Up @@ -389,24 +383,14 @@ namespace rad {
inline PxPyPzMVector ElectroIonReaction::P4BeamIon() const { return _p4ion_beam; }
inline PxPyPzMVector ElectroIonReaction::P4BeamEle() const { return _p4el_beam; }


// --- Beam Electron via function---
inline void ElectroIonReaction::SetBeamElectronExpr(const std::string& type, const std::string& expression){
SetParticleCandidatesExpr(consts::BeamEle(),type,expression);
}
// --- Beam Ion via function---
inline void ElectroIonReaction::SetBeamIonExpr(const std::string& type, const std::string& expression){
SetParticleCandidatesExpr(consts::BeamIon(),type,expression);
}
inline void ElectroIonReaction::SetBeamElectronIndex(const int idx, const std::string& type) {
SetParticleIndex(consts::BeamEle().data(), type.empty() ? GetDefaultType() : type, idx);
}

inline void ElectroIonReaction::SetBeamElectronIndex(const int idx, const std::string& type) {
SetParticleIndex(consts::BeamEle().data(), type.empty() ? GetDefaultType() : type, idx);
}
inline void ElectroIonReaction::SetBeamIonIndex(const int idx, const std::string& type) {
SetParticleIndex(consts::BeamIon().data(), type.empty() ? GetDefaultType() : type, idx);
}

inline void ElectroIonReaction::SetBeamIonIndex(const int idx, const std::string& type) {
SetParticleIndex(consts::BeamIon().data(), type.empty() ? GetDefaultType() : type, idx);
}

// --- Physics Helpers ---

namespace electroion {
Expand Down
Loading