@@ -243,6 +243,54 @@ class GenTPCLoopers : public Generator
243243 return true;
244244 }
245245
246+ Bool_t generateEvent (TH1D * t_hist )
247+ {
248+ // Clear the vector of pairs
249+ mGenPairs .clear ();
250+ // Clear the vector of compton electrons
251+ mGenElectrons .clear ();
252+ // Set number of loopers if poissonian params are available
253+ if (mPoissonSet )
254+ {
255+ mNLoopersPairs = static_cast < short int > (std ::round (mMultiplier [0 ] * PoissonPairs ()));
256+ }
257+ if (mGaussSet )
258+ {
259+ mNLoopersCompton = static_cast < short int > (std ::round (mMultiplier [1 ] * GaussianElectrons ()));
260+ }
261+ // Find the time histogram edge
262+ double time_constraint = t_hist -> GetXaxis ()-> GetXmax ();
263+ LOG (info ) << "Time constraint for loopers: " << time_constraint << " ns" ;
264+ // Generate pairs
265+ for (int i = 0 ; i < mNLoopersPairs ; ++ i )
266+ {
267+ std ::vector < double > pair = mONNX_pair -> generate_sample ();
268+ // Apply the inverse transformation using the scaler
269+ std ::vector < double > transformed_pair = mScaler_pair -> inverse_transform (pair );
270+ // Check if the time constraint is satisfied
271+ while ((transformed_pair [9 ] / 1e9 ) > time_constraint )
272+ {
273+ transformed_pair [9 ] = t_hist -> GetRandom () * 1e9 ; // Regenerate time if it exceeds the constraint, multiplied by 1e9 to account for ratio in importParticles
274+ }
275+ LOG (info ) << "Transformed pair time: " << transformed_pair [9 ] / 1e9 << " ns" ;
276+ mGenPairs .push_back (transformed_pair );
277+ }
278+ // Generate compton electrons
279+ for (int i = 0 ; i < mNLoopersCompton ; ++ i )
280+ {
281+ std ::vector < double > electron = mONNX_compton -> generate_sample ();
282+ // Apply the inverse transformation using the scaler
283+ std ::vector < double > transformed_electron = mScaler_compton -> inverse_transform (electron );
284+ while ((transformed_electron [6 ] / 1e9 ) > time_constraint )
285+ {
286+ transformed_electron [6 ] = t_hist -> GetRandom () * 1e9 ; // Regenerate time if it exceeds the constraint, multiplied by 1e9 to account for ratio in importParticles
287+ }
288+ LOG (info ) << "Transformed electron time: " << transformed_electron [6 ] / 1e9 << " ns" ;
289+ mGenElectrons .push_back (transformed_electron );
290+ }
291+ return true;
292+ }
293+
246294 Bool_t importParticles () override
247295 {
248296 // Get looper pairs from the event
@@ -390,12 +438,18 @@ class GenLoopersInjector : public Generator
390438 Generator ::setEnergyUnit (1.0 );
391439 }
392440
393- void setAdaptiveLoopers (Bool_t adaptive )
441+ void setAdaptiveLoopers (Bool_t & adaptive )
394442 {
395443 mAdaptiveLoopers = adaptive ;
396444 LOG (info ) << "Adaptive loopers: " << (mAdaptiveLoopers ? "ON" : "OFF" );
397445 }
398446
447+ void setTimeConstraint (Bool_t & constraint )
448+ {
449+ mTimeConstraint = constraint ;
450+ LOG (info ) << "Time constraint: " << (mTimeConstraint ? "ON" : "OFF" );
451+ }
452+
399453 void setLoopsFractions (float & fraction , float & fractionPairs )
400454 {
401455 if (fraction < 0 || fraction >= 1 )
@@ -458,6 +512,19 @@ class GenLoopersInjector : public Generator
458512 // apply unit transformation of sub-generator
459513 unit_transformer (p , pos_unit , time_unit , energy_unit , mom_unit );
460514 }
515+ // Print Maximum values of time
516+ double maxTime = 0.0 ;
517+ double minTime = 0.0 ;
518+ for (const auto & p : parts ) {
519+ if (p .T () > maxTime ) {
520+ maxTime = p .T ();
521+ }
522+ if (p .T () < minTime ) {
523+ minTime = p .T ();
524+ }
525+ }
526+ LOG (info ) << "Maximum time in the event: " << maxTime ;
527+ LOG (info ) << "Minimum time in the event: " << minTime ;
461528 return parts ;
462529 }
463530
@@ -475,9 +542,20 @@ class GenLoopersInjector : public Generator
475542 LOG (info ) << "Size of kineparts: " << kineparts .size ();
476543 mParticles .insert (mParticles .end (), kineparts .begin (), kineparts .end ());
477544 LOG (info ) << "Size mParticles at kine stage " << mParticles .size ();
545+ double maxTime = 0.0 ;
546+ // Find the maximum time in the imported particles
547+ for (const auto & p : mParticles ) {
548+ if (p .T () > maxTime ) {
549+ maxTime = p .T ();
550+ }
551+ }
552+ // Create a histogram containing original generator time values
553+ auto time_hist = std ::make_unique < TH1D > ("time_hist" , "Time Histogram" , 1000 , 0. , maxTime );
554+ for (const auto & p : mParticles ) {
555+ time_hist -> Fill (p .T ());
556+ }
478557 // Check size of mParticles stack and set loopers accordingly if mAdaptiveLoopers is true
479- if (mAdaptiveLoopers )
480- {
558+ if (mAdaptiveLoopers ) {
481559 int nParticles = mParticles .size ();
482560 if (nParticles > 0 )
483561 {
@@ -494,7 +572,11 @@ class GenLoopersInjector : public Generator
494572 }
495573 // Generate loopers using GenTPCLoopers
496574 // this is valid also when number of loopers is fixed
497- mGenTPCLoopers -> generateEvent ();
575+ if (mTimeConstraint ) {
576+ mGenTPCLoopers -> generateEvent (time_hist .get ());
577+ } else {
578+ mGenTPCLoopers -> generateEvent ();
579+ }
498580 auto stat2 = mGenTPCLoopers -> importParticles ();
499581 if (!stat2 ) {
500582 LOG (error ) << "Failed to import particles from GenTPCLoopers" ;
@@ -506,7 +588,7 @@ class GenLoopersInjector : public Generator
506588 mParticles .insert (mParticles .end (), loopers .begin (), loopers .end ());
507589 LOG (info ) << "Size mParticles at loopers stage " << mParticles .size ();
508590 } else {
509- LOG (error ) << "Failed to import particles from O2 Kinematics or TPCLoopers " ;
591+ LOG (error ) << "Failed to import particles from O2 Kinematics" ;
510592 return false;
511593 }
512594 return true;
@@ -518,6 +600,8 @@ class GenLoopersInjector : public Generator
518600 Bool_t mAdaptiveLoopers = true; // Flag to indicate if adaptive loopers are used
519601 float mLoopsFraction = 0.05 ; // Fraction of loopers to be injected adaptively
520602 float mLoopsFractionPairs = 0.08 ; // Fraction of loopers from Pairs
603+ Bool_t mTimeConstraint = true; // Flag to indicate if time constraint is applied
604+ double mTimeConstraintValue = 0.0 ; // Time constraint value, adaptively set based on the maximum time of the main generator events
521605};
522606
523607} // namespace eventgen
@@ -600,7 +684,7 @@ FairGenerator *
600684// Loopers are considered adaptive by default, meaning that the number of loopers is determined by the number of particles in the kinematics file per event
601685FairGenerator *
602686GeneratorLoopersInjector (std ::string kineFileName = "genevents_Kine.root" , std ::string model_pairs = "tpcloopmodel.onnx" , std ::string model_compton = "tpcloopmodelcompton.onnx" ,
603- std ::string scaler_pair = "scaler_pair.json" , std ::string scaler_compton = "scaler_compton.json" , float loopers_fraction = 0.05 , float fraction_pairs = 0.08 )
687+ std ::string scaler_pair = "scaler_pair.json" , std ::string scaler_compton = "scaler_compton.json" , bool time_constraint = true, float loopers_fraction = 0.05 , float fraction_pairs = 0.08 )
604688{
605689 // Expand all environment paths
606690 model_pairs = gSystem -> ExpandPathName (model_pairs .c_str ()) ;
@@ -694,5 +778,7 @@ GeneratorLoopersInjector(std::string kineFileName = "genevents_Kine.root", std::
694778 } else {
695779 generator -> setLoopsFractions (loopers_fraction , fraction_pairs );
696780 }
781+ // Set adaptive time constraint flag
782+ generator -> setTimeConstraint (time_constraint );
697783 return generator ;
698784}
0 commit comments