]> git.uio.no Git - u/mrichter/AliRoot.git/blob - THijing/AliGenHijing.cxx
Correct time at vertex for beam-gas simulations.
[u/mrichter/AliRoot.git] / THijing / AliGenHijing.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 // Generator using HIJING as an external generator
19 // The main HIJING options are accessable for the user through this interface.
20 // Uses the THijing implementation of TGenerator.
21 // Author:
22 // Andreas Morsch    (andreas.morsch@cern.ch)
23 //
24
25 #include <TClonesArray.h>
26 #include <TGraph.h>
27 #include <THijing.h>
28 #include <TLorentzVector.h>
29 #include <TPDGCode.h>
30 #include <TParticle.h>
31
32 #include "AliGenHijing.h"
33 #include "AliGenHijingEventHeader.h"
34 #include "AliHijingRndm.h"
35 #include "AliLog.h"
36 #include "AliRun.h"
37
38 ClassImp(AliGenHijing)
39
40 AliGenHijing::AliGenHijing()
41     :AliGenMC(),
42      fFrame("CMS"),
43      fMinImpactParam(0.),
44      fMaxImpactParam(5.),
45      fKeep(0),
46      fQuench(1),
47      fShadowing(1),
48      fDecaysOff(1),
49      fTrigger(0),     
50      fEvaluate(0),
51      fSelectAll(0),
52      fFlavor(0),
53      fKineBias(0.),
54      fTrials(0),
55      fXsection(0.),
56      fHijing(0),
57      fPtHardMin(0.),
58      fPtHardMax(1.e4),
59      fSpectators(1),
60      fDsigmaDb(0),
61      fDnDb(0),
62      fPtMinJet(-2.5),
63      fEtaMinJet(-20.),
64      fEtaMaxJet(+20.),
65      fPhiMinJet(0.),
66      fPhiMaxJet(2. * TMath::Pi()),
67      fRadiation(3),
68      fSimpleJet(kFALSE),
69      fNoGammas(kFALSE),
70      fProjectileSpecn(0),
71      fProjectileSpecp(0),
72      fTargetSpecn(0),
73      fTargetSpecp(0),
74      fLHC(kFALSE),
75      fRandomPz(kFALSE),
76      fNoHeavyQuarks(kFALSE)
77 {
78   // Constructor
79   fEnergyCMS = 5500.;
80   AliHijingRndm::SetHijingRandom(GetRandom());
81 }
82
83 AliGenHijing::AliGenHijing(Int_t npart)
84     :AliGenMC(npart),
85      fFrame("CMS"),
86      fMinImpactParam(0.),
87      fMaxImpactParam(5.),
88      fKeep(0),
89      fQuench(1),
90      fShadowing(1),
91      fDecaysOff(1),
92      fTrigger(0),     
93      fEvaluate(0),
94      fSelectAll(0),
95      fFlavor(0),
96      fKineBias(0.),
97      fTrials(0),
98      fXsection(0.),
99      fHijing(0),
100      fPtHardMin(0.),
101      fPtHardMax(1.e4),
102      fSpectators(1),
103      fDsigmaDb(0),
104      fDnDb(0),
105      fPtMinJet(-2.5),
106      fEtaMinJet(-20.),
107      fEtaMaxJet(+20.),
108      fPhiMinJet(0.),
109      fPhiMaxJet(2. * TMath::Pi()),
110      fRadiation(3),
111      fSimpleJet(kFALSE),
112      fNoGammas(kFALSE),
113      fProjectileSpecn(0),
114      fProjectileSpecp(0),
115      fTargetSpecn(0),
116      fTargetSpecp(0),
117      fLHC(kFALSE),
118      fRandomPz(kFALSE),
119      fNoHeavyQuarks(kFALSE)
120 {
121 // Default PbPb collisions at 5. 5 TeV
122 //
123     fEnergyCMS = 5500.;
124     fName = "Hijing";
125     fTitle= "Particle Generator using HIJING";
126 //
127 //
128 // Set random number generator   
129     AliHijingRndm::SetHijingRandom(GetRandom());
130 }
131
132 AliGenHijing::~AliGenHijing()
133 {
134 // Destructor
135     if ( fDsigmaDb) delete  fDsigmaDb;  
136     if ( fDnDb)     delete  fDnDb;  
137 }
138
139 void AliGenHijing::Init()
140 {
141 // Initialisation
142     fFrame.Resize(8);
143     fTarget.Resize(8);
144     fProjectile.Resize(8);
145     
146     SetMC(new THijing(fEnergyCMS, fFrame, fProjectile, fTarget, 
147                       fAProjectile, fZProjectile, fATarget, fZTarget, 
148                       fMinImpactParam, fMaxImpactParam));
149
150     fHijing=(THijing*) fMCEvGen;
151     fHijing->SetIHPR2(2,  fRadiation);
152     fHijing->SetIHPR2(3,  fTrigger);
153     fHijing->SetIHPR2(6,  fShadowing);
154     fHijing->SetIHPR2(12, fDecaysOff);    
155     fHijing->SetIHPR2(21, fKeep);
156     fHijing->SetHIPR1(10, fPtMinJet);   
157     fHijing->SetHIPR1(50, fSimpleJet);
158 //
159 //  Quenching
160 //
161 //
162 //  fQuench = 0:  no quenching
163 //  fQuench = 1:  hijing default
164 //  fQuench = 2:  new LHC  parameters for HIPR1(11) and HIPR1(14)
165 //  fQuench = 3:  new RHIC parameters for HIPR1(11) and HIPR1(14)
166 //  fQuench = 4:  new LHC  parameters with log(e) dependence
167 //  fQuench = 5:  new RHIC parameters with log(e) dependence
168     fHijing->SetIHPR2(50, 0);
169     if (fQuench > 0) 
170         fHijing->SetIHPR2(4,  1);
171     else
172         fHijing->SetIHPR2(4,  0);
173 // New LHC parameters from Xin-Nian Wang
174     if (fQuench == 2) {
175         fHijing->SetHIPR1(14, 1.1);
176         fHijing->SetHIPR1(11, 3.7);
177     } else if (fQuench == 3) {
178         fHijing->SetHIPR1(14, 0.20);
179         fHijing->SetHIPR1(11, 2.5);
180     } else if (fQuench == 4) {
181         fHijing->SetIHPR2(50, 1);
182         fHijing->SetHIPR1(14, 4.*0.34);
183         fHijing->SetHIPR1(11, 3.7);
184     } else if (fQuench == 5) {
185         fHijing->SetIHPR2(50, 1);
186         fHijing->SetHIPR1(14, 0.34);
187         fHijing->SetHIPR1(11, 2.5);
188     }
189     
190 //
191 // Heavy quarks
192 //    
193     if (fNoHeavyQuarks) {
194         fHijing->SetIHPR2(49, 1);
195     } else {
196         fHijing->SetIHPR2(49, 0);
197     }
198     
199     
200     AliGenMC::Init();
201     
202 //
203 //  Initialize Hijing  
204 //    
205     fHijing->Initialize();
206 //
207     if (fEvaluate) EvaluateCrossSections();
208 //
209 }
210
211 void AliGenHijing::Generate()
212 {
213 // Generate one event
214
215   Float_t polar[3]    =   {0,0,0};
216   Float_t origin[3]   =   {0,0,0};
217   Float_t origin0[3]  =   {0,0,0};
218   Float_t p[3];
219   Float_t tof;
220
221 //  converts from mm/c to s
222   const Float_t kconv = 0.001/2.99792458e8;
223 //
224   Int_t nt  = 0;
225   Int_t jev = 0;
226   Int_t j, kf, ks, ksp, imo;
227   kf = 0;
228     
229
230     
231   fTrials = 0;
232   
233   for (j = 0;j < 3; j++) origin0[j] = fOrigin[j];
234
235   if(fVertexSmear == kPerEvent) {
236       Vertex();
237       for (j=0; j < 3; j++) origin0[j] = fVertex[j];
238   } 
239
240
241   Float_t sign = (fRandomPz && (Rndm() < 0.5))? -1. : 1.;
242
243   while(1)
244   {
245 //    Generate one event
246 // --------------------------------------------------------------------------
247       fProjectileSpecn    = 0;  
248       fProjectileSpecp    = 0;
249       fTargetSpecn        = 0;  
250       fTargetSpecp        = 0;
251 // --------------------------------------------------------------------------
252       fHijing->GenerateEvent();
253       fTrials++;
254       fNprimaries = 0;
255       fHijing->ImportParticles(&fParticles,"All");
256       if (fTrigger != kNoTrigger) {
257           if (!CheckTrigger()) continue;
258       }
259       if (fLHC) Boost();
260       
261       
262       Int_t np = fParticles.GetEntriesFast();
263       Int_t nc = 0;
264       if (np == 0 ) continue;
265       Int_t i;
266       Int_t* newPos     = new Int_t[np];
267       Int_t* pSelected  = new Int_t[np];
268
269       for (i = 0; i < np; i++) {
270           newPos[i]    = i;
271           pSelected[i] = 0;
272       }
273       
274 //      Get event vertex
275 //
276       TParticle *  iparticle = (TParticle *) fParticles.At(0);
277       fVertex[0] = origin0[0];
278       fVertex[1] = origin0[1];  
279       fVertex[2] = origin0[2];
280       
281 //
282 //      First select parent particles
283 //
284
285       for (i = 0; i < np; i++) {
286           iparticle = (TParticle *) fParticles.At(i);
287
288 // Is this a parent particle ?
289           if (Stable(iparticle)) continue;
290 //
291           Bool_t  selected             =  kTRUE;
292           Bool_t  hasSelectedDaughters =  kFALSE;
293           
294           
295           kf        = iparticle->GetPdgCode();
296           ks        = iparticle->GetStatusCode();
297           if (kf == 92) continue;
298             
299           if (!fSelectAll) selected = KinematicSelection(iparticle, 0) && 
300                                SelectFlavor(kf);
301           hasSelectedDaughters = DaughtersSelection(iparticle);
302 //
303 // Put particle on the stack if it is either selected or 
304 // it is the mother of at least one seleted particle
305 //
306           if (selected || hasSelectedDaughters) {
307               nc++;
308               pSelected[i] = 1;
309           } // selected
310       } // particle loop parents
311 //
312 // Now select the final state particles
313 //
314
315       for (i = 0; i<np; i++) {
316           iparticle = (TParticle *) fParticles.At(i);
317 // Is this a final state particle ?
318           if (!Stable(iparticle)) continue;
319       
320           Bool_t  selected             =  kTRUE;
321           kf        = iparticle->GetPdgCode();
322           ks        = iparticle->GetStatusCode();
323           ksp       = iparticle->GetUniqueID();
324           
325 // --------------------------------------------------------------------------
326 // Count spectator neutrons and protons
327           if(ksp == 0 || ksp == 1){
328               if(kf == kNeutron) fProjectileSpecn += 1;
329               if(kf == kProton)  fProjectileSpecp += 1;
330           }
331           else if(ksp == 10 || ksp == 11){
332               if(kf == kNeutron) fTargetSpecn += 1;
333               if(kf == kProton)  fTargetSpecp += 1;
334           }
335 // --------------------------------------------------------------------------
336 //          
337           if (!fSelectAll) {
338               selected = KinematicSelection(iparticle,0)&&SelectFlavor(kf);
339               if (!fSpectators && selected) selected = (ksp != 0 && ksp != 1 && ksp != 10
340                                                         && ksp != 11);
341           }
342 //
343 // Put particle on the stack if selected
344 //
345           if (selected) {
346               nc++;
347               pSelected[i] = 1;
348           } // selected
349       } // particle loop final state
350
351 //
352 //    Time of the interactions
353       Float_t tInt = 0.;
354       if (fPileUpTimeWindow > 0.) tInt = fPileUpTimeWindow * (2. * gRandom->Rndm() - 1.);
355
356 //
357 // Write particles to stack
358
359       for (i = 0; i<np; i++) {
360           iparticle = (TParticle *) fParticles.At(i);
361           Bool_t  hasMother   = (iparticle->GetFirstMother()     >=0);
362           Bool_t  hasDaughter = (iparticle->GetFirstDaughter()   >=0);
363           if (pSelected[i]) {
364               kf   = iparticle->GetPdgCode();
365               ks   = iparticle->GetStatusCode();
366               p[0] = iparticle->Px();
367               p[1] = iparticle->Py();
368               p[2] = iparticle->Pz() * sign;
369               origin[0] = origin0[0]+iparticle->Vx()/10;
370               origin[1] = origin0[1]+iparticle->Vy()/10;
371               origin[2] = origin0[2]+iparticle->Vz()/10;
372               if (TestBit(kVertexRange)) {
373                   tof = kconv * iparticle->T() + sign * origin0[2] / 2.99792458e10;
374               } else {
375                   tof = kconv * iparticle->T();
376                   if (fPileUpTimeWindow > 0.) tof += tInt;
377               }
378               imo = -1;
379               TParticle* mother = 0;
380               if (hasMother) {
381                   imo = iparticle->GetFirstMother();
382                   mother = (TParticle *) fParticles.At(imo);
383                   imo = (mother->GetPdgCode() != 92) ? newPos[imo] : -1;
384               } // if has mother   
385               Bool_t tFlag = (fTrackIt && !hasDaughter);
386               PushTrack(tFlag,imo,kf,p,origin,polar,tof,kPNoProcess,nt, 1., ks);
387               fNprimaries++;
388               KeepTrack(nt);
389               newPos[i] = nt;
390           } // if selected
391       } // particle loop
392       delete[] newPos;
393       delete[] pSelected;
394       
395       AliInfo(Form("\n I've put %i particles on the stack \n",nc));
396       if (nc > 0) {
397           jev += nc;
398           if (jev >= fNpart || fNpart == -1) {
399               fKineBias = Float_t(fNpart)/Float_t(fTrials);
400               AliInfo(Form("\n Trials: %i %i %i\n",fTrials, fNpart, jev));
401               break;
402           }
403       }
404   } // event loop
405   MakeHeader();
406   SetHighWaterMark(nt);
407 }
408
409 void AliGenHijing::KeepFullEvent()
410 {
411     fKeep=1;
412 }
413
414 void AliGenHijing::EvaluateCrossSections()
415 {
416 //     Glauber Calculation of geometrical x-section
417 //
418     Float_t xTot       = 0.;          // barn
419     Float_t xTotHard   = 0.;          // barn 
420     Float_t xPart      = 0.;          // barn
421     Float_t xPartHard  = 0.;          // barn 
422     Float_t sigmaHard  = 0.1;         // mbarn
423     Float_t bMin       = 0.;
424     Float_t bMax       = fHijing->GetHIPR1(34)+fHijing->GetHIPR1(35);
425     const Float_t kdib = 0.2;
426     Int_t   kMax       = Int_t((bMax-bMin)/kdib)+1;
427
428
429     printf("\n Projectile Radius (fm): %f \n",fHijing->GetHIPR1(34));
430     printf("\n Target     Radius (fm): %f \n",fHijing->GetHIPR1(35));    
431     Int_t i;
432     Float_t oldvalue= 0.;
433
434     Float_t* b   = new Float_t[kMax];
435     Float_t* si1 = new Float_t[kMax];    
436     Float_t* si2 = new Float_t[kMax];    
437     
438     for (i = 0; i < kMax; i++)
439     {
440         Float_t xb  = bMin+i*kdib;
441         Float_t ov;
442         ov=fHijing->Profile(xb);
443         Float_t gb  =  2.*0.01*fHijing->GetHIPR1(40)*kdib*xb*(1.-TMath::Exp(-fHijing->GetHINT1(12)*ov));
444         Float_t gbh =  2.*0.01*fHijing->GetHIPR1(40)*kdib*xb*sigmaHard*ov;
445         xTot+=gb;
446         xTotHard += gbh;
447         printf("profile %f %f %f\n", xb, ov, fHijing->GetHINT1(12));
448         
449         if (xb > fMinImpactParam && xb < fMaxImpactParam)
450         {
451             xPart += gb;
452             xPartHard += gbh;
453         }
454         
455         if(oldvalue) if ((xTot-oldvalue)/oldvalue<0.0001) break;
456         oldvalue = xTot;
457         printf("\n Total cross section (barn): %d %f %f \n",i, xb, xTot);
458         printf("\n Hard  cross section (barn): %d %f %f \n\n",i, xb, xTotHard);
459         if (i>0) {
460             si1[i] = gb/kdib;
461             si2[i] = gbh/gb;
462             b[i]  = xb;
463         }
464     }
465
466     printf("\n Total cross section (barn): %f \n",xTot);
467     printf("\n Hard  cross section (barn): %f \n \n",xTotHard);
468     printf("\n Partial       cross section (barn): %f %f \n",xPart, xPart/xTot*100.);
469     printf("\n Partial  hard cross section (barn): %f %f \n",xPartHard, xPartHard/xTotHard*100.);
470
471 //  Store result as a graph
472     b[0] = 0;
473     si1[0] = 0;
474     si2[0]=si2[1];
475     
476     fDsigmaDb  = new TGraph(i, b, si1);
477     fDnDb      = new TGraph(i, b, si2);
478 }
479
480 Bool_t AliGenHijing::DaughtersSelection(TParticle* iparticle)
481 {
482 //
483 // Looks recursively if one of the daughters has been selected
484 //
485 //    printf("\n Consider daughters %d:",iparticle->GetPdgCode());
486     Int_t imin = -1;
487     Int_t imax = -1;
488     Int_t i;
489     Bool_t hasDaughters = (iparticle->GetFirstDaughter() >=0);
490     Bool_t selected = kFALSE;
491     if (hasDaughters) {
492         imin = iparticle->GetFirstDaughter();
493         imax = iparticle->GetLastDaughter();       
494         for (i = imin; i <= imax; i++){
495             TParticle *  jparticle = (TParticle *) fParticles.At(i);    
496             Int_t ip = jparticle->GetPdgCode();
497             if (KinematicSelection(jparticle,0)&&SelectFlavor(ip)) {
498                 selected=kTRUE; break;
499             }
500             if (DaughtersSelection(jparticle)) {selected=kTRUE; break; }
501         }
502     } else {
503         return kFALSE;
504     }
505     return selected;
506 }
507
508
509 Bool_t AliGenHijing::SelectFlavor(Int_t pid)
510 {
511 // Select flavor of particle
512 // 0: all
513 // 4: charm and beauty
514 // 5: beauty
515     Bool_t res = 0;
516     
517     if (fFlavor == 0) {
518         res = kTRUE;
519     } else {
520         Int_t ifl = TMath::Abs(pid/100);
521         if (ifl > 10) ifl/=10;
522         res = (fFlavor == ifl);
523     }
524 //
525 //  This part if gamma writing is inhibited
526     if (fNoGammas) 
527         res = res && (pid != kGamma && pid != kPi0);
528 //
529     return res;
530 }
531
532 Bool_t AliGenHijing::Stable(TParticle*  particle) const
533 {
534 // Return true for a stable particle
535 //
536     
537     if (particle->GetFirstDaughter() < 0 )
538     {
539         return kTRUE;
540     } else {
541         return kFALSE;
542     }
543 }
544
545
546
547 void AliGenHijing::MakeHeader()
548 {
549 // Builds the event header, to be called after each event
550     AliGenEventHeader* header = new AliGenHijingEventHeader("Hijing");
551     ((AliGenHijingEventHeader*) header)->SetNProduced(fNprimaries);
552     ((AliGenHijingEventHeader*) header)->SetImpactParameter(fHijing->GetHINT1(19));
553     ((AliGenHijingEventHeader*) header)->SetTotalEnergy(fHijing->GetEATT());
554     ((AliGenHijingEventHeader*) header)->SetHardScatters(fHijing->GetJATT());
555     ((AliGenHijingEventHeader*) header)->SetParticipants(fHijing->GetNP(), fHijing->GetNT());
556     ((AliGenHijingEventHeader*) header)->SetCollisions(fHijing->GetN0(),
557                                                        fHijing->GetN01(),
558                                                        fHijing->GetN10(),
559                                                        fHijing->GetN11());
560     ((AliGenHijingEventHeader*) header)->SetSpectators(fProjectileSpecn, fProjectileSpecp,
561                                                        fTargetSpecn,fTargetSpecp);
562     ((AliGenHijingEventHeader*) header)->SetReactionPlaneAngle(fHijing->GetHINT1(20));
563 //    printf("Impact Parameter %13.3f \n", fHijing->GetHINT1(19));
564     
565
566
567 // 4-momentum vectors of the triggered jets.
568 //
569 // Before final state gluon radiation.
570     TLorentzVector* jet1 = new TLorentzVector(fHijing->GetHINT1(21), 
571                                               fHijing->GetHINT1(22),
572                                               fHijing->GetHINT1(23),
573                                               fHijing->GetHINT1(24));
574
575     TLorentzVector* jet2 = new TLorentzVector(fHijing->GetHINT1(31), 
576                                               fHijing->GetHINT1(32),
577                                               fHijing->GetHINT1(33),
578                                               fHijing->GetHINT1(34));
579 // After final state gluon radiation.
580     TLorentzVector* jet3 = new TLorentzVector(fHijing->GetHINT1(26), 
581                                               fHijing->GetHINT1(27),
582                                               fHijing->GetHINT1(28),
583                                               fHijing->GetHINT1(29));
584
585     TLorentzVector* jet4 = new TLorentzVector(fHijing->GetHINT1(36), 
586                                               fHijing->GetHINT1(37),
587                                               fHijing->GetHINT1(38),
588                                               fHijing->GetHINT1(39));
589     ((AliGenHijingEventHeader*) header)->SetJets(jet1, jet2, jet3, jet4);
590 // Bookkeeping for kinematic bias
591     ((AliGenHijingEventHeader*) header)->SetTrials(fTrials);
592 // Event Vertex
593     header->SetPrimaryVertex(fVertex);
594     AddHeader(header);
595     fCollisionGeometry = (AliGenHijingEventHeader*)  header;
596 }
597
598
599 Bool_t AliGenHijing::CheckTrigger()
600 {
601 // Check the kinematic trigger condition
602 //
603     Bool_t   triggered = kFALSE;
604  
605     if (fTrigger == 1) {
606 //
607 //  jet-jet Trigger     
608         
609         TLorentzVector* jet1 = new TLorentzVector(fHijing->GetHINT1(26), 
610                                                   fHijing->GetHINT1(27),
611                                                   fHijing->GetHINT1(28),
612                                                   fHijing->GetHINT1(29));
613         
614         TLorentzVector* jet2 = new TLorentzVector(fHijing->GetHINT1(36), 
615                                                   fHijing->GetHINT1(37),
616                                                   fHijing->GetHINT1(38),
617                                                   fHijing->GetHINT1(39));
618         Double_t eta1      = jet1->Eta();
619         Double_t eta2      = jet2->Eta();
620         Double_t phi1      = jet1->Phi();
621         Double_t phi2      = jet2->Phi();
622 //    printf("\n Trigger: %f %f %f %f",
623 //         fEtaMinJet, fEtaMaxJet, fPhiMinJet, fPhiMaxJet);
624         if (
625             (eta1 < fEtaMaxJet && eta1 > fEtaMinJet &&  
626              phi1 < fPhiMaxJet && phi1 > fPhiMinJet) 
627             ||
628             (eta2 < fEtaMaxJet && eta2 > fEtaMinJet &&  
629              phi2 < fPhiMaxJet && phi2 > fPhiMinJet)
630             ) 
631             triggered = kTRUE;
632     } else if (fTrigger == 2) {
633 //  Gamma Jet
634 //
635         Int_t np = fParticles.GetEntriesFast();
636         for (Int_t i = 0; i < np; i++) {
637             TParticle* part = (TParticle*) fParticles.At(i);
638             Int_t kf = part->GetPdgCode();
639             Int_t ksp = part->GetUniqueID();
640             if (kf == 22 && ksp == 40) {
641                 Float_t phi = part->Phi();
642                 Float_t eta = part->Eta();
643                 if  (eta < fEtaMaxJet && 
644                      eta > fEtaMinJet &&
645                      phi < fPhiMaxJet && 
646                      phi > fPhiMinJet) {
647                     triggered = 1;
648                     break;
649                 } // check phi,eta within limits
650             } // direct gamma ? 
651         } // particle loop
652     } // fTrigger == 2
653     return triggered;
654 }