19#include <TLorentzVector.h>
29 fInTrackData(nullptr),
32 RegisterInputCollection(
"InputCollection",
"Input collection of telescope data objects (derived from TTelescopeData)",
34 RegisterInputCollection(
"InputTrackCollection",
"Input collection of tracking data objects (derived from TTrack)",
36 RegisterOutputCollection(
"OutputCollection",
"Output collection containing reaction reconstruction information using the TGTIK method",
38 RegisterProcessorParameter(
"DetectorParameter",
"Name of the telescope parameter collection (detector parameters)",
40 RegisterProcessorParameter(
"TargetParameter",
"Name of the target parameter collection",
44 RegisterProcessorParameter(
"InitialBeamEnergy",
"Initial beam energy (in MeV) immediately after the exit window",
46 RegisterProcessorParameter(
"TargetName",
"Name of the target gas (used in TSrim calculation)",
48 RegisterProcessorParameter(
"TargetPressure",
"Target gas pressure in Torr",
50 RegisterProcessorParameter(
"TargetTemperature",
"Target gas temperature in Kelvin",
53 RegisterProcessorParameter(
"ParticleZArray",
"Array of atomic numbers (Z) for reaction particles",
55 RegisterProcessorParameter(
"ParticleAArray",
"Array of mass numbers (A) for reaction particles",
57 RegisterProcessorParameter(
"ExcitedEnergy",
"Excited state energy (MeV); use a negative value if not applicable",
61 RegisterProcessorParameter(
"UseCustomFunction",
"Flag to enable custom processing functions for additional corrections",
63 RegisterProcessorParameter(
"UseCenterPosition",
"Flag to use the detector's center position (useful when the DSSSD is not operational)",
86 col,
fInputColName,
"TClonesArray",
"art::crib::TTelescopeData");
87 if (std::holds_alternative<TString>(result)) {
88 SetStateError(std::get<TString>(result));
91 fInData = std::get<TClonesArray **>(result);
96 if (std::holds_alternative<TString>(result_track)) {
97 SetStateError(std::get<TString>(result_track));
105 if (std::holds_alternative<TString>(result_det_prm)) {
106 SetStateError(std::get<TString>(result_det_prm));
109 fDetectorPrm = std::get<TClonesArray *>(result_det_prm);
114 if (std::holds_alternative<TString>(result_tar_prm)) {
115 SetStateError(std::get<TString>(result_tar_prm));
118 fTargetPrm = std::get<TClonesArray *>(result_tar_prm);
121 SetStateError(
"Particle array size should be 4 in the steering file");
137 Info(
"Init",
"reconstract the reaction: %d%s + %d%s -> %d%s + %d%s (detected)",
142 Info(
"Init",
"\tQ-value: %lf MeV", (
M1 +
M2) - (
M3 +
M4));
145 const char *tsrim_path = std::getenv(
"TSRIM_DATA_HOME");
147 SetStateError(
"TSRIM_DATA_HOME environment variable is not defined");
154 fOutData =
new TClonesArray(
"art::crib::TReactionInfo");
159 gRandom->SetSeed(time(
nullptr));
169 Warning(
"Process",
"No input data object");
173 const int nData = (*fInData)->GetEntriesFast();
176 else if (nData != 1) {
177 Warning(
"Process",
"The input %s entry number is not 1, but %d.",
181 const int nTrackData = (*fInTrackData)->GetEntriesFast();
184 if (nTrackData != 1) {
185 Warning(
"Process",
"The input %s entry number is not 1 but %d.",
189 const auto *Data =
dynamic_cast<const TTelescopeData *
>((*fInData)->At(0));
190 const auto *TrackData =
dynamic_cast<const TTrack *
>((*fInTrackData)->At(0));
192 if (!IsValid(Data->GetTelID()))
196 if (Data->GetEtotal() < 0.01)
200 Double_t excited_energy = 0.0;
206 if (excited_energy < -1.0)
213 if (!IsValid(reac_z))
221 outData->
SetXYZ(TrackData->GetX(reac_z), TrackData->GetY(reac_z), reac_z);
224 outData->SetEnergy(Ecm);
227 outData->SetTheta(180.0 - (180.0 / TMath::Pi()) *
GetCMAngle(ELab, Ecm, ALab));
228 outData->SetExEnergy(excited_energy);
258 const Int_t numSteps = 10;
260 bool signChanged =
false;
261 bool firstValid =
true;
264 Double_t prev_z = 0.0, prev_f = 0.0;
267 for (Int_t i = 0; i <= numSteps; ++i) {
270 if (!IsValid(current_f))
281 if (prev_f * current_f < 0.0) {
294 Warning(
"bisection",
"No valid function value found in the initial range. (E = %lf)", data->
GetEtotal());
298 Warning(
"bisection",
"Could not find a valid zero crossing in the initial range. (E = %lf)", data->
GetEtotal());
305 if (!IsValid(f_low) || !IsValid(f_high)) {
306 Warning(
"bisection",
"f(z_low) or f(z_high) is invalid.");
309 if (f_low * f_high > 0.0) {
310 Warning(
"bisection",
"f(z_low) and f(z_high) do not bracket a zero: L = %lf / H = %lf, E = %lf",
315 Warning(
"bisection",
"Bracketing failed: interval touches boundaries.");
320 Double_t left = z_low;
321 Double_t right = z_high;
322 Double_t middle = 0.0;
324 Double_t f_left = f_low;
326 while (TMath::Abs(right - left) >
kEpsilon) {
327 middle = (left + right) / 2.0;
329 if (!IsValid(f_left) || !IsValid(f_middle))
332 if (f_left * f_middle < 0.0) {
341 Warning(
"bisection",
"Convergence not achieved within maximum iteration!");
364 if (!IsValid(Ecm_beam) || !IsValid(Ecm_detect)) {
367 return Ecm_beam - Ecm_detect;
391 Int_t sign = z > 0 ? 1 : -1;
394 TVector3 beam_flight(track->GetX(z) - track->GetX(0),
395 track->GetY(z) - track->GetY(0),
404 sign * beam_flight.Mag(),
412 Double_t beta = TMath::Sqrt(1.0 - TMath::Power(
M1 / (
M1 + energy), 2));
415 Double_t ang[2] = {track->GetA(), track->GetB()};
418 Double_t norm = TMath::Sqrt(TMath::Power(TMath::Tan(ang[0]), 2) +
419 TMath::Power(TMath::Tan(ang[1]), 2) + 1.0);
422 Double_t betaX = beta * TMath::Tan(ang[0]) / norm;
423 Double_t betaY = beta * TMath::Tan(ang[1]) / norm;
424 Double_t betaZ = beta / norm;
425 TVector3 betaVector(betaX, betaY, betaZ);
428 TLorentzVector beam(0., 0., 0.,
M1);
430 beam.Boost(betaVector);
433 TLorentzVector target(0., 0., 0.,
M2);
436 TLorentzVector cm_vec = beam + target;
437 TVector3 beta_cm = cm_vec.BoostVector();
439 beam.Boost(-beta_cm);
440 target.Boost(-beta_cm);
444 return (beam.E() - beam.M()) + (target.E() - target.M());
455 if (!IsValid(energy))
480 Warning(
"GetELabALabPair",
"Parameter is not found");
481 return {kInvalidD, kInvalidD};
487 Double_t stripSize[2] = {Prm->
GetSize(0) /
static_cast<Double_t
>(stripNum[0]),
488 Prm->
GetSize(1) /
static_cast<Double_t
>(stripNum[1])};
491 Double_t det_x = 0.0;
495 }
else if (stripID[0] >= 0 && stripID[0] < stripNum[0]) {
497 det_x = -Prm->
GetSize(0) / 2.0 + stripSize[0] *
static_cast<Double_t
>(stripID[0]);
504 Double_t det_y = 0.0;
507 else if (stripID[1] >= 0 && stripID[1] < stripNum[1])
508 det_y = -Prm->
GetSize(1) / 2.0 + stripSize[1] * (Double_t)stripID[1];
513 TVector3 detect_position(det_x, det_y, Prm->
GetDistance());
515 detect_position.RotateY(Prm->
GetAngle());
522 TVector3 reaction_position(track->GetX(z), track->GetY(z), z);
524 TVector3 track_direction(track->GetX(1.) - track->GetX(0.),
525 track->GetY(1.) - track->GetY(0.),
529 Double_t theta = track_direction.Angle(detect_position - reaction_position);
534 -(detect_position - reaction_position).Mag(),
536 return {energy, theta};
561 Double_t alpha = (
M2 * (
M1 +
M2)) / (2.0 *
M1);
562 Double_t beta = (
M4 * (
M3 +
M4)) / (2.0 *
M3);
564 Double_t qvalue = (
M1 +
M2) - (
M3 +
M4);
568 Double_t v4 = TMath::Sqrt(2.0 * energy /
M4);
571 if (TMath::Abs(alpha - beta) < 1.0e-5) {
572 Double_t cosTheta = TMath::Cos(theta);
573 if (TMath::Abs(cosTheta) < 1.0e-5) {
574 Warning(
"GetEcm_classic_kinematics",
"cos(theta) is too small in elastic scattering calculation");
578 Double_t vcm_elastic = -(qvalue - beta * v4 * v4) / (2.0 * beta * v4 * cosTheta);
579 if (vcm_elastic < 0) {
580 Warning(
"GetEcm_classic_kinematics",
"vcm < 0! : vcm = %lf, det_energy = %lf, theta = %lf",
581 vcm_elastic, energy, theta);
584 return alpha * vcm_elastic * vcm_elastic;
591 Double_t denominator = (alpha - beta);
592 Double_t b = (beta * v4 * TMath::Cos(theta)) / denominator;
593 Double_t c = (qvalue - beta * v4 * v4) / denominator;
594 Double_t D = b * b - c;
596 if (TMath::Abs(D) < 1.0e-5) {
599 Warning(
"GetEcm_classic_kinematics",
"b^2 - c = %lf < 0, det_energy = %lf, theta = %lf",
605 Double_t vcm = -b + TMath::Sqrt(D);
607 Warning(
"GetEcm_classic_kinematics",
"vcm < 0!, vcm = %lf + %lf, det_energy = %lf, theta = %lf",
608 -b, TMath::Sqrt(D), energy, theta);
612 return alpha * vcm * vcm;
631 Double_t alpha = (
M2 * (
M1 +
M2)) / (2.0 *
M1);
632 Double_t beta = (
M4 * (
M3 +
M4)) / (2.0 *
M3);
633 Double_t qvalue = (
M1 +
M2) - (
M3 +
M4);
636 Double_t v4 = TMath::Sqrt(2.0 * ELab /
M4);
638 Double_t vcm = TMath::Sqrt(Ecm / alpha);
640 Double_t v4cm = TMath::Sqrt((Ecm + qvalue) / beta);
643 Double_t theta_cm = TMath::ACos((v4 * TMath::Cos(ALab) - vcm) / v4cm);
662 const Double_t ex_energys[42] = {
706 Double_t max_energy = 30.0;
707 if (Etotal > max_energy)
711 TString filepath =
"/home/okawa/art_analysis/develop/develop/ana2/random_generator.root";
712 TFile *file = TFile::Open(filepath);
713 if (!file || file->IsZombie()) {
714 Warning(
"GetCustomExcitedEnergy",
"Error opening file: %s", filepath.Data());
721 TDirectory *dir =
dynamic_cast<TDirectory *
>(file->Get(Form(
"tel%d", telID)));
724 Warning(
"GetCustomExcitedEnergy",
"Error opening directory: tel%d", telID);
731 std::vector<TGraph *> graphs;
732 std::vector<TGraph *> grs_ratio;
733 TList *keys = dir->GetListOfKeys();
736 while ((key = (TKey *)next())) {
737 TObject *obj = key->ReadObj();
738 if (obj && obj->InheritsFrom(TGraph::Class())) {
739 graphs.emplace_back(
static_cast<TGraph *
>(obj));
740 TGraph *g =
new TGraph();
741 grs_ratio.emplace_back(g);
749 for (Double_t ene = 5.0; ene < max_energy; ene += 0.1) {
750 Double_t total = 0.0;
751 for (
const auto *gr : graphs) {
753 Double_t val = gr->Eval(ene);
759 for (Size_t j = 0; j < graphs.size(); j++) {
761 Double_t raw_val = graphs[j]->Eval(ene);
764 Double_t ratio = (total > 0.001) ? raw_val / total : (j == 0 ? 1.0 : 0.0);
765 grs_ratio[j]->SetPoint(i_point, ene, ratio);
771 Double_t uniform = gRandom->Uniform();
773 for (Size_t i = 0; i < grs_ratio.size(); i++) {
775 Double_t val = grs_ratio[i]->Eval(Etotal);
783 if (i == grs_ratio.size() - 1) {
784 Warning(
"GetCustomExcitedEnergy",
"Could not assign excited id!");
789 for (
auto g : grs_ratio) {
795 for (
auto g : graphs) {
806 return ex_energys[ex_id];
Utility functions for handling input and parameter objects in TEventCollection.
ClassImp(art::crib::TTGTIKProcessor)
ROOT macro for class implementation.
Processor for reconstructing reaction positions using the Thick Gas Target Inverse Kinematics (TGTIK)...
Double_t GetCenterRotPos(Int_t id) const
Double_t GetAngle() const
Int_t GetStripNum(Int_t id) const
Double_t GetSize(Int_t id) const
Double_t GetDistance() const
void SetXYZ(Double_t x, Double_t y, Double_t z)
Calculates the reaction position using telescope and tracking data.
IntVec_t fParticleAArray
Array of mass numbers for reaction particles.
const Double_t kEpsilon
Convergence threshold for the bisection method.
TClonesArray * fOutData
! Pointer to the output reaction information (TClonesArray of TReactionInfo)
Double_t newton(const TTrack *track, const TTelescopeData *data)
(Deprecated) Newton method for calculating reaction position.
TString fOutputColName
Name of the output reaction information collection (TReactionInfo)
TClonesArray ** fInData
! Pointer to the input telescope data (TClonesArray of TTelescopeData)
TClonesArray ** fInTrackData
! Pointer to the input tracking data (TClonesArray of TTrack)
const Int_t kMaxIteration
Maximum number of iterations for the bisection method.
const Double_t kInitialMax
Initial maximum value for bisection method (mm)
Double_t GetEcmFromBeam(Double_t z, const TTrack *track)
Calculate the center-of-mass energy from beam data.
Double_t GetEcmFromDetectParticle(Double_t z, const TTrack *track, const TTelescopeData *data)
Calculate the center-of-mass energy from detected particle data.
Double_t fPressure
Gas pressure in Torr.
Double_t GetCMAngle(Double_t ELab, Double_t Ecm, Double_t ALab)
Recalculate the LAB angle after reconstruction.
Double_t bisection(const TTrack *track, const TTelescopeData *data)
Bisection method for calculating reaction position.
Double_t fTemperature
Gas temperature in Kelvin.
TString fTargetParameterName
Name of the target parameter (TTargetParameter)
Double_t TargetFunction(Double_t z, const TTrack *track, const TTelescopeData *data)
Target function for the bisection (and Newton) method.
Double_t GetEcm_classic_kinematics(Double_t energy, Double_t theta)
Calculate the center-of-mass energy using classical kinematics.
IntVec_t fParticleZArray
Array of atomic numbers for reaction particles.
TString fInputTrackColName
Name of the input tracking data collection (TTrack)
Double_t fInitialBeamEnergy
Beam energy immediately after the window (MeV)
void Init(TEventCollection *col) override
Initialize the processor with an event collection.
Bool_t fDoCustom
Flag to enable custom processing.
Double_t GetReactionPosition(const TTrack *track, const TTelescopeData *data)
Calculate the reaction position along the Z-axis.
Double_t GetCustomExcitedEnergy(Int_t telID, Double_t Etotal)
Generate a custom excited state energy.
TClonesArray * fTargetPrm
! Pointer to target parameter objects (TClonesArray of TTargetParameter)
TString fInputColName
Name of the input telescope data collection (TTelescopeData)
TTGTIKProcessor()
Constructor.
TClonesArray * fDetectorPrm
! Pointer to detector parameter objects (TClonesArray of TDetectorParameter)
const Double_t kInitialMin
Initial minimum value for bisection method (mm)
TString fTargetName
Name of the gas target used in TSrim calculations.
Bool_t fDoCenterPos
Flag to use the detector center position.
void Process() override
Main processing function.
Double_t GetEcm_kinematics(Double_t energy, Double_t theta, Double_t low_e, Double_t high_e)
Calculate the center-of-mass energy using relativistic kinematics.
TString fDetectorParameterName
Name of the detector parameter (TDetectorParameter)
TSrim * srim
! TSrim object to calculate energy loss
std::pair< Double_t, Double_t > GetELabALabPair(Double_t z, const TTrack *track, const TTelescopeData *data)
Calculate the LAB energy and LAB angle from detected particle data.
Double_t fExcitedEnergy
Excited state energy (MeV)
~TTGTIKProcessor() override
Default destructor.
Double_t GetEtotal() const
std::enable_if_t< std::is_base_of_v< TObject, T >, std::variant< T **, TString > > GetInputObject(TEventCollection *col, const TString &name, const TString &expectedTypeName, const TString &elementTypeName="TObject")
Retrieve an object from TEventCollection with type validation.
std::enable_if_t< std::is_base_of_v< TObject, T >, std::variant< T *, TString > > GetParameterObject(TEventCollection *col, const TString &name, const TString &expectedTypeName, const TString &elementTypeName="art::TParameterObject")
Retrieves a parameter object from a TEventCollection.