Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4FTFModel.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26//
27//
28
29// ------------------------------------------------------------
30// GEANT 4 class implementation file
31//
32// ---------------- G4FTFModel ----------------
33// by Gunter Folger, May 1998.
34// class implementing the excitation in the FTF Parton String Model
35//
36// Vladimir Uzhinsky, November - December 2012
37// simulation of nucleus-nucleus interactions was implemented.
38// ------------------------------------------------------------
39
40#include <utility>
41
42#include "G4FTFModel.hh"
43#include "G4ios.hh"
45#include "G4SystemOfUnits.hh"
46#include "G4FTFParameters.hh"
47#include "G4FTFParticipants.hh"
50#include "G4LorentzRotation.hh"
52#include "G4ParticleTable.hh"
53#include "G4IonTable.hh"
54#include "G4KineticTrack.hh"
56#include "G4Exp.hh"
57#include "G4Log.hh"
58
59//============================================================================
60
61//#define debugFTFmodel
62//#define debugReggeonCascade
63//#define debugPutOnMassShell
64//#define debugAdjust
65//#define debugBuildString
66
67
68//============================================================================
69
70G4FTFModel::G4FTFModel( const G4String& modelName ) :
71 G4VPartonStringModel( modelName ),
72 theExcitation( new G4DiffractiveExcitation() ),
73 theElastic( new G4ElasticHNScattering() ),
74 theAnnihilation( new G4FTFAnnihilation() )
75{
76 // ---> JVY theParameters = 0;
77 theParameters = new G4FTFParameters();
78 //
79 NumberOfInvolvedNucleonsOfTarget = 0;
80 NumberOfInvolvedNucleonsOfProjectile= 0;
81 for ( G4int i = 0; i < 250; ++i ) {
82 TheInvolvedNucleonsOfTarget[i] = 0;
83 TheInvolvedNucleonsOfProjectile[i] = 0;
84 }
85
86 //LowEnergyLimit = 2000.0*MeV;
87 LowEnergyLimit = 1000.0*MeV;
88
89 HighEnergyInter = true;
90
91 G4LorentzVector tmp( 0.0, 0.0, 0.0, 0.0 );
92 ProjectileResidual4Momentum = tmp;
93 ProjectileResidualMassNumber = 0;
94 ProjectileResidualCharge = 0;
95 ProjectileResidualLambdaNumber = 0;
96 ProjectileResidualExcitationEnergy = 0.0;
97
98 TargetResidual4Momentum = tmp;
99 TargetResidualMassNumber = 0;
100 TargetResidualCharge = 0;
101 TargetResidualExcitationEnergy = 0.0;
102
103 Bimpact = -1.0;
104 BinInterval = false;
105 Bmin = 0.0;
106 Bmax = 0.0;
107 NumberOfProjectileSpectatorNucleons = 0;
108 NumberOfTargetSpectatorNucleons = 0;
109 NumberOfNNcollisions = 0;
110
111 SetEnergyMomentumCheckLevels( 2.0*perCent, 150.0*MeV );
112}
113
114
115//============================================================================
116
117struct DeleteVSplitableHadron { void operator()( G4VSplitableHadron* aH ) { delete aH; } };
118
119
120//============================================================================
121
123 // Because FTF model can be called for various particles
124 //
125 // ---> NOTE (JVY): This statement below is no longer true !!!
126 // theParameters must be erased at the end of each call.
127 // Thus the delete is also in G4FTFModel::GetStrings() method.
128 // ---> JVY
129 //
130 if ( theParameters != 0 ) delete theParameters;
131 if ( theExcitation != 0 ) delete theExcitation;
132 if ( theElastic != 0 ) delete theElastic;
133 if ( theAnnihilation != 0 ) delete theAnnihilation;
134
135 // Erasing of strings created at annihilation.
136 if ( theAdditionalString.size() != 0 ) {
137 std::for_each( theAdditionalString.begin(), theAdditionalString.end(),
139 }
140 theAdditionalString.clear();
141
142 // Erasing of target involved nucleons.
143 if ( NumberOfInvolvedNucleonsOfTarget != 0 ) {
144 for ( G4int i = 0; i < NumberOfInvolvedNucleonsOfTarget; ++i ) {
145 G4VSplitableHadron* aNucleon = TheInvolvedNucleonsOfTarget[i]->GetSplitableHadron();
146 if ( aNucleon ) delete aNucleon;
147 }
148 }
149
150 // Erasing of projectile involved nucleons.
151 if ( NumberOfInvolvedNucleonsOfProjectile != 0 ) {
152 for ( G4int i = 0; i < NumberOfInvolvedNucleonsOfProjectile; ++i ) {
153 G4VSplitableHadron* aNucleon = TheInvolvedNucleonsOfProjectile[i]->GetSplitableHadron();
154 if ( aNucleon ) delete aNucleon;
155 }
156 }
157}
158
159
160//============================================================================
161
162void G4FTFModel::Init( const G4Nucleus& aNucleus, const G4DynamicParticle& aProjectile ) {
163
164 theProjectile = aProjectile;
165
166 G4double PlabPerParticle( 0.0 ); // Laboratory momentum Pz per particle/nucleon
167
168 #ifdef debugFTFmodel
169 G4cout << "FTF init Proj Name " << theProjectile.GetDefinition()->GetParticleName() << G4endl
170 << "FTF init Proj Mass " << theProjectile.GetMass()
171 << " " << theProjectile.GetMomentum() << G4endl
172 << "FTF init Proj B Q " << theProjectile.GetDefinition()->GetBaryonNumber()
173 << " " << (G4int) theProjectile.GetDefinition()->GetPDGCharge() << G4endl
174 << "FTF init Target A Z " << aNucleus.GetA_asInt()
175 << " " << aNucleus.GetZ_asInt() << G4endl;
176 #endif
177
178 theParticipants.Clean();
179
180 theParticipants.SetProjectileNucleus( 0 );
181
182 G4LorentzVector tmp( 0.0, 0.0, 0.0, 0.0 );
183 ProjectileResidualMassNumber = 0;
184 ProjectileResidualCharge = 0;
185 ProjectileResidualLambdaNumber = 0;
186 ProjectileResidualExcitationEnergy = 0.0;
187 ProjectileResidual4Momentum = tmp;
188
189 TargetResidualMassNumber = aNucleus.GetA_asInt();
190 TargetResidualCharge = aNucleus.GetZ_asInt();
191 TargetResidualExcitationEnergy = 0.0;
192 TargetResidual4Momentum = tmp;
194 ->GetIonMass( TargetResidualCharge, TargetResidualMassNumber );
195
196 TargetResidual4Momentum.setE( TargetResidualMass );
197
198 if ( std::abs( theProjectile.GetDefinition()->GetBaryonNumber() ) <= 1 ) {
199 // Projectile is a hadron : meson or baryon
200 ProjectileResidualMassNumber = std::abs( theProjectile.GetDefinition()->GetBaryonNumber() );
201 ProjectileResidualCharge = G4int( theProjectile.GetDefinition()->GetPDGCharge() );
202 PlabPerParticle = theProjectile.GetMomentum().z();
203 ProjectileResidualExcitationEnergy = 0.0;
204 //G4double ProjectileResidualMass = theProjectile.GetMass();
205 ProjectileResidual4Momentum.setVect( theProjectile.GetMomentum() );
206 ProjectileResidual4Momentum.setE( theProjectile.GetTotalEnergy() );
207 if ( PlabPerParticle < LowEnergyLimit ) {
208 HighEnergyInter = false;
209 } else {
210 HighEnergyInter = true;
211 }
212 } else {
213 if ( theProjectile.GetDefinition()->GetBaryonNumber() > 1 ) {
214 // Projectile is a nucleus
215 ProjectileResidualMassNumber = theProjectile.GetDefinition()->GetBaryonNumber();
216 ProjectileResidualCharge = G4int( theProjectile.GetDefinition()->GetPDGCharge() );
217 ProjectileResidualLambdaNumber = theProjectile.GetDefinition()->GetNumberOfLambdasInHypernucleus();
218 PlabPerParticle = theProjectile.GetMomentum().z() / ProjectileResidualMassNumber;
219 if ( PlabPerParticle < LowEnergyLimit ) {
220 HighEnergyInter = false;
221 } else {
222 HighEnergyInter = true;
223 }
224 theParticipants.InitProjectileNucleus( ProjectileResidualMassNumber, ProjectileResidualCharge,
225 ProjectileResidualLambdaNumber );
226 } else if ( theProjectile.GetDefinition()->GetBaryonNumber() < -1 ) {
227 // Projectile is an anti-nucleus
228 ProjectileResidualMassNumber = std::abs( theProjectile.GetDefinition()->GetBaryonNumber() );
229 ProjectileResidualCharge = std::abs( G4int( theProjectile.GetDefinition()->GetPDGCharge() ) );
230 ProjectileResidualLambdaNumber = theProjectile.GetDefinition()->GetNumberOfAntiLambdasInAntiHypernucleus();
231 PlabPerParticle = theProjectile.GetMomentum().z() / ProjectileResidualMassNumber;
232 if ( PlabPerParticle < LowEnergyLimit ) {
233 HighEnergyInter = false;
234 } else {
235 HighEnergyInter = true;
236 }
237 theParticipants.InitProjectileNucleus( ProjectileResidualMassNumber, ProjectileResidualCharge,
238 ProjectileResidualLambdaNumber );
239 theParticipants.GetProjectileNucleus()->StartLoop();
240 G4Nucleon* aNucleon;
241 while ( ( aNucleon = theParticipants.GetProjectileNucleus()->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
242 if ( aNucleon->GetDefinition() == G4Proton::Definition() ) {
244 } else if ( aNucleon->GetDefinition() == G4Neutron::Definition() ) {
246 } else if ( aNucleon->GetDefinition() == G4Lambda::Definition() ) {
248 }
249 }
250 }
251
252 G4ThreeVector BoostVector = theProjectile.GetMomentum() / theProjectile.GetTotalEnergy();
253 theParticipants.GetProjectileNucleus()->DoLorentzBoost( BoostVector );
254 theParticipants.GetProjectileNucleus()->DoLorentzContraction( BoostVector );
255 ProjectileResidualExcitationEnergy = 0.0;
256 //G4double ProjectileResidualMass = theProjectile.GetMass();
257 ProjectileResidual4Momentum.setVect( theProjectile.GetMomentum() );
258 ProjectileResidual4Momentum.setE( theProjectile.GetTotalEnergy() );
259 }
260
261 // Init target nucleus (assumed to be never a hypernucleus)
262 theParticipants.Init( aNucleus.GetA_asInt(), aNucleus.GetZ_asInt() );
263
264 NumberOfProjectileSpectatorNucleons = std::abs( theProjectile.GetDefinition()->GetBaryonNumber() );
265 NumberOfTargetSpectatorNucleons = aNucleus.GetA_asInt();
266 NumberOfNNcollisions = 0;
267
268 // reset/recalculate everything for the new interaction
269 theParameters->InitForInteraction( theProjectile.GetDefinition(), aNucleus.GetA_asInt(),
270 aNucleus.GetZ_asInt(), PlabPerParticle );
271
272 if ( theAdditionalString.size() != 0 ) {
273 std::for_each( theAdditionalString.begin(), theAdditionalString.end(),
275 }
276 theAdditionalString.clear();
277
278 #ifdef debugFTFmodel
279 G4cout << "FTF end of Init" << G4endl << G4endl;
280 #endif
281
282 // In the case of Hydrogen target, for non-ion hadron projectiles,
283 // do NOT simulate quasi-elastic (by forcing to 0 the probability of
284 // elastic scatering in theParameters - which is used only by FTF).
285 // This is necessary because in this case quasi-elastic on a target nucleus
286 // with only one nucleon would be identical to the hadron elastic scattering,
287 // and the latter is already included in the elastic process
288 // (i.e. G4HadronElasticProcess).
289 if ( std::abs( theProjectile.GetDefinition()->GetBaryonNumber() ) <= 1 &&
290 aNucleus.GetA_asInt() < 2 ) theParameters->SetProbabilityOfElasticScatt( 0.0 );
291
292 if ( SampleBinInterval() ) theParticipants.SetBminBmax( GetBmin(), GetBmax() );
293}
294
295
296//============================================================================
297
299
300 #ifdef debugFTFmodel
301 G4cout << "G4FTFModel::GetStrings() " << G4endl;
302 #endif
303
305 theParticipants.GetList( theProjectile, theParameters );
306
307 SetImpactParameter( theParticipants.GetImpactParameter() );
308
309 StoreInvolvedNucleon();
310
311 G4bool Success( true );
312
313 if ( HighEnergyInter ) {
314 ReggeonCascade();
315
316 #ifdef debugFTFmodel
317 G4cout << "FTF PutOnMassShell " << G4endl;
318 #endif
319
320 Success = PutOnMassShell();
321
322 #ifdef debugFTFmodel
323 G4cout << "FTF PutOnMassShell Success? " << Success << G4endl;
324 #endif
325
326 }
327
328 #ifdef debugFTFmodel
329 G4cout << "FTF ExciteParticipants " << G4endl;
330 #endif
331
332 if ( Success ) Success = ExciteParticipants();
333
334 #ifdef debugFTFmodel
335 G4cout << "FTF ExciteParticipants Success? " << Success << G4endl;
336 #endif
337
338 if ( Success ) {
339
340 #ifdef debugFTFmodel
341 G4cout << "FTF BuildStrings ";
342 #endif
343
344 BuildStrings( theStrings );
345
346 #ifdef debugFTFmodel
347 G4cout << "FTF BuildStrings " << theStrings << " OK" << G4endl
348 << "FTF GetResiduals of Nuclei " << G4endl;
349 #endif
350
351 GetResiduals();
352
353 /*
354 if ( theParameters != 0 ) {
355 delete theParameters;
356 theParameters = 0;
357 }
358 */
359 } else if ( ! GetProjectileNucleus() ) {
360 // Erase the hadron projectile
361 std::vector< G4VSplitableHadron* > primaries;
362 theParticipants.StartLoop();
363 while ( theParticipants.Next() ) { /* Loop checking, 10.08.2015, A.Ribon */
364 const G4InteractionContent& interaction = theParticipants.GetInteraction();
365 // Do not allow for duplicates
366 if ( primaries.end() ==
367 std::find( primaries.begin(), primaries.end(), interaction.GetProjectile() ) ) {
368 primaries.push_back( interaction.GetProjectile() );
369 }
370 }
371 std::for_each( primaries.begin(), primaries.end(), DeleteVSplitableHadron() );
372 primaries.clear();
373 }
374
375 // Cleaning of the memory
376 G4VSplitableHadron* aNucleon = 0;
377
378 // Erase the projectile nucleons
379 for ( G4int i = 0; i < NumberOfInvolvedNucleonsOfProjectile; ++i ) {
380 aNucleon = TheInvolvedNucleonsOfProjectile[i]->GetSplitableHadron();
381 if ( aNucleon ) delete aNucleon;
382 }
383 NumberOfInvolvedNucleonsOfProjectile = 0;
384
385 // Erase the target nucleons
386 for ( G4int i = 0; i < NumberOfInvolvedNucleonsOfTarget; ++i ) {
387 aNucleon = TheInvolvedNucleonsOfTarget[i]->GetSplitableHadron();
388 if ( aNucleon ) delete aNucleon;
389 }
390 NumberOfInvolvedNucleonsOfTarget = 0;
391
392 #ifdef debugFTFmodel
393 G4cout << "End of FTF. Go to fragmentation" << G4endl
394 << "To continue - enter 1, to stop - ^C" << G4endl;
395 #endif
396
397 theParticipants.Clean();
398
399 return theStrings;
400}
401
402
403//============================================================================
404
405void G4FTFModel::StoreInvolvedNucleon() {
406 //To store nucleons involved in the interaction
407
408 NumberOfInvolvedNucleonsOfTarget = 0;
409
410 G4V3DNucleus* theTargetNucleus = GetTargetNucleus();
411 theTargetNucleus->StartLoop();
412
413 G4Nucleon* aNucleon;
414 while ( ( aNucleon = theTargetNucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
415 if ( aNucleon->AreYouHit() ) {
416 TheInvolvedNucleonsOfTarget[NumberOfInvolvedNucleonsOfTarget] = aNucleon;
417 NumberOfInvolvedNucleonsOfTarget++;
418 }
419 }
420
421 #ifdef debugFTFmodel
422 G4cout << "G4FTFModel::StoreInvolvedNucleon -------------" << G4endl;
423 G4cout << "NumberOfInvolvedNucleonsOfTarget " << NumberOfInvolvedNucleonsOfTarget
424 << G4endl << G4endl;
425 #endif
426
427
428 if ( ! GetProjectileNucleus() ) return; // The projectile is a hadron
429
430 // The projectile is a nucleus or an anti-nucleus.
431
432 NumberOfInvolvedNucleonsOfProjectile = 0;
433
434 G4V3DNucleus* theProjectileNucleus = GetProjectileNucleus();
435 theProjectileNucleus->StartLoop();
436
437 G4Nucleon* aProjectileNucleon;
438 while ( ( aProjectileNucleon = theProjectileNucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
439 if ( aProjectileNucleon->AreYouHit() ) {
440 // Projectile nucleon was involved in the interaction.
441 TheInvolvedNucleonsOfProjectile[NumberOfInvolvedNucleonsOfProjectile] = aProjectileNucleon;
442 NumberOfInvolvedNucleonsOfProjectile++;
443 }
444 }
445
446 #ifdef debugFTFmodel
447 G4cout << "NumberOfInvolvedNucleonsOfProjectile " << NumberOfInvolvedNucleonsOfProjectile
448 << G4endl << G4endl;
449 #endif
450 return;
451}
452
453
454//============================================================================
455
456void G4FTFModel::ReggeonCascade() {
457 // Implementation of the reggeon theory inspired model
458
459 #ifdef debugReggeonCascade
460 G4cout << "G4FTFModel::ReggeonCascade -----------" << G4endl
461 << "theProjectile.GetTotalMomentum() " << theProjectile.GetTotalMomentum() << G4endl
462 << "theProjectile.GetTotalEnergy() " << theProjectile.GetTotalEnergy() << G4endl
463 << "ExcitationE/WN " << theParameters->GetExcitationEnergyPerWoundedNucleon() << G4endl;
464 #endif
465
466 G4int InitNINt = NumberOfInvolvedNucleonsOfTarget;
467
468 // Reggeon cascading in target nucleus
469 for ( G4int InvTN = 0; InvTN < InitNINt; InvTN++ ) {
470 G4Nucleon* aTargetNucleon = TheInvolvedNucleonsOfTarget[ InvTN ];
471
472 G4double CreationTime = aTargetNucleon->GetSplitableHadron()->GetTimeOfCreation();
473
474 G4double XofWoundedNucleon = aTargetNucleon->GetPosition().x();
475 G4double YofWoundedNucleon = aTargetNucleon->GetPosition().y();
476
477 G4V3DNucleus* theTargetNucleus = GetTargetNucleus();
478 theTargetNucleus->StartLoop();
479
480 G4Nucleon* Neighbour(0);
481 while ( ( Neighbour = theTargetNucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
482 if ( ! Neighbour->AreYouHit() ) {
483 G4double impact2 = sqr( XofWoundedNucleon - Neighbour->GetPosition().x() ) +
484 sqr( YofWoundedNucleon - Neighbour->GetPosition().y() );
485
486 if ( G4UniformRand() < theParameters->GetCofNuclearDestruction() *
487 G4Exp( -impact2 / theParameters->GetR2ofNuclearDestruction() )
488 ) {
489 // The neighbour nucleon is involved in the reggeon cascade
490 TheInvolvedNucleonsOfTarget[ NumberOfInvolvedNucleonsOfTarget ] = Neighbour;
491 NumberOfInvolvedNucleonsOfTarget++;
492
493 G4VSplitableHadron* targetSplitable;
494 targetSplitable = new G4DiffractiveSplitableHadron( *Neighbour );
495
496 Neighbour->Hit( targetSplitable );
497 targetSplitable->SetTimeOfCreation( CreationTime );
498 targetSplitable->SetStatus( 3 ); // 2->3
499 }
500 }
501 }
502 }
503
504 #ifdef debugReggeonCascade
505 G4cout << "Final NumberOfInvolvedNucleonsOfTarget "
506 << NumberOfInvolvedNucleonsOfTarget << G4endl << G4endl;
507 #endif
508
509 if ( ! GetProjectileNucleus() ) return;
510
511 // Nucleus-Nucleus Interaction : Destruction of Projectile
512 G4int InitNINp = NumberOfInvolvedNucleonsOfProjectile;
513
514 //for ( G4int InvPN = 0; InvPN < NumberOfInvolvedNucleonsOfProjectile; InvPN++ ) {
515 for ( G4int InvPN = 0; InvPN < InitNINp; InvPN++ ) {
516 G4Nucleon* aProjectileNucleon = TheInvolvedNucleonsOfProjectile[ InvPN ];
517
518 G4double CreationTime = aProjectileNucleon->GetSplitableHadron()->GetTimeOfCreation();
519
520 G4double XofWoundedNucleon = aProjectileNucleon->GetPosition().x();
521 G4double YofWoundedNucleon = aProjectileNucleon->GetPosition().y();
522
523 G4V3DNucleus* theProjectileNucleus = GetProjectileNucleus();
524 theProjectileNucleus->StartLoop();
525
526 G4Nucleon* Neighbour( 0 );
527 while ( ( Neighbour = theProjectileNucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
528 if ( ! Neighbour->AreYouHit() ) {
529 G4double impact2= sqr( XofWoundedNucleon - Neighbour->GetPosition().x() ) +
530 sqr( YofWoundedNucleon - Neighbour->GetPosition().y() );
531
532 if ( G4UniformRand() < theParameters->GetCofNuclearDestructionPr() *
533 G4Exp( -impact2 / theParameters->GetR2ofNuclearDestruction() )
534 ) {
535 // The neighbour nucleon is involved in the reggeon cascade
536 TheInvolvedNucleonsOfProjectile[ NumberOfInvolvedNucleonsOfProjectile ] = Neighbour;
537 NumberOfInvolvedNucleonsOfProjectile++;
538
539 G4VSplitableHadron* projectileSplitable;
540 projectileSplitable = new G4DiffractiveSplitableHadron( *Neighbour );
541
542 Neighbour->Hit( projectileSplitable );
543 projectileSplitable->SetTimeOfCreation( CreationTime );
544 projectileSplitable->SetStatus( 3 );
545 }
546 }
547 }
548 }
549
550 #ifdef debugReggeonCascade
551 G4cout << "NumberOfInvolvedNucleonsOfProjectile "
552 << NumberOfInvolvedNucleonsOfProjectile << G4endl << G4endl;
553 #endif
554}
555
556
557//============================================================================
558
559G4bool G4FTFModel::PutOnMassShell() {
560
561 G4bool isProjectileNucleus = false;
562 if ( GetProjectileNucleus() ) isProjectileNucleus = true;
563
564 #ifdef debugPutOnMassShell
565 G4cout << "PutOnMassShell start " << G4endl;
566 if ( isProjectileNucleus ) {
567 G4cout << "PutOnMassShell for Nucleus_Nucleus " << G4endl;
568 }
569 #endif
570
571 G4LorentzVector Pprojectile( theProjectile.GetMomentum(), theProjectile.GetTotalEnergy() );
572 if ( Pprojectile.z() < 0.0 ) return false;
573
574 G4bool isOk = true;
575
576 G4LorentzVector Ptarget( 0.0, 0.0, 0.0, 0.0 );
577 G4LorentzVector PtargetResidual( 0.0, 0.0, 0.0, 0.0 );
578 G4double SumMasses = 0.0;
579 G4V3DNucleus* theTargetNucleus = GetTargetNucleus();
580 G4double TargetResidualMass = 0.0;
581
582 #ifdef debugPutOnMassShell
583 G4cout << "Target : ";
584 #endif
585 isOk = ComputeNucleusProperties( theTargetNucleus, Ptarget, PtargetResidual, SumMasses,
586 TargetResidualExcitationEnergy, TargetResidualMass,
587 TargetResidualMassNumber, TargetResidualCharge );
588 if ( ! isOk ) return false;
589
590 G4double Mprojectile = 0.0;
591 G4double M2projectile = 0.0;
592 G4LorentzVector Pproj( 0.0, 0.0, 0.0, 0.0 );
593 G4LorentzVector PprojResidual( 0.0, 0.0, 0.0, 0.0 );
594 G4V3DNucleus* thePrNucleus = GetProjectileNucleus();
595 G4double PrResidualMass = 0.0;
596
597 if ( ! isProjectileNucleus ) { // hadron-nucleus collision
598 Mprojectile = Pprojectile.mag();
599 M2projectile = Pprojectile.mag2();
600 SumMasses += Mprojectile + 20.0*MeV;
601 } else { // nucleus-nucleus or antinucleus-nucleus collision
602 #ifdef debugPutOnMassShell
603 G4cout << "Projectile : ";
604 #endif
605 isOk = ComputeNucleusProperties( thePrNucleus, Pproj, PprojResidual, SumMasses,
606 ProjectileResidualExcitationEnergy, PrResidualMass,
607 ProjectileResidualMassNumber, ProjectileResidualCharge );
608 if ( ! isOk ) return false;
609 }
610
611 G4LorentzVector Psum = Pprojectile + Ptarget;
612 G4double SqrtS = Psum.mag();
613 G4double S = Psum.mag2();
614
615 #ifdef debugPutOnMassShell
616 G4cout << "Psum " << Psum/GeV << " GeV" << G4endl << "SqrtS " << SqrtS/GeV << " GeV" << G4endl
617 << "SumMasses, PrResidualMass and TargetResidualMass " << SumMasses/GeV << " "
618 << PrResidualMass/GeV << " " << TargetResidualMass/GeV << " GeV" << G4endl;
619 #endif
620
621 if ( SqrtS < SumMasses ) return false; // It is impossible to simulate after putting nuclear nucleons on mass-shell
622
623 // Try to consider also the excitation energy of the residual nucleus, if this is
624 // possible, with the available energy; otherwise, set the excitation energy to zero.
625 G4double savedSumMasses = SumMasses;
626 if ( isProjectileNucleus ) {
627 SumMasses -= std::sqrt( sqr( PrResidualMass ) + PprojResidual.perp2() );
628 SumMasses += std::sqrt( sqr( PrResidualMass + ProjectileResidualExcitationEnergy )
629 + PprojResidual.perp2() );
630 }
631 SumMasses -= std::sqrt( sqr( TargetResidualMass ) + PtargetResidual.perp2() );
632 SumMasses += std::sqrt( sqr( TargetResidualMass + TargetResidualExcitationEnergy )
633 + PtargetResidual.perp2() );
634
635 if ( SqrtS < SumMasses ) {
636 SumMasses = savedSumMasses;
637 if ( isProjectileNucleus ) ProjectileResidualExcitationEnergy = 0.0;
638 TargetResidualExcitationEnergy = 0.0;
639 }
640
641 TargetResidualMass += TargetResidualExcitationEnergy;
642 if ( isProjectileNucleus ) PrResidualMass += ProjectileResidualExcitationEnergy;
643
644 #ifdef debugPutOnMassShell
645 if ( isProjectileNucleus ) {
646 G4cout << "PrResidualMass ProjResidualExcitationEnergy " << PrResidualMass/GeV << " "
647 << ProjectileResidualExcitationEnergy << " MeV" << G4endl;
648 }
649 G4cout << "TargetResidualMass TargetResidualExcitationEnergy " << TargetResidualMass/GeV << " "
650 << TargetResidualExcitationEnergy << " MeV" << G4endl
651 << "Sum masses " << SumMasses/GeV << G4endl;
652 #endif
653
654 // Sampling of nucleons what can transfer to delta-isobars
655 if ( isProjectileNucleus && thePrNucleus->GetMassNumber() != 1 ) {
656 isOk = GenerateDeltaIsobar( SqrtS, NumberOfInvolvedNucleonsOfProjectile,
657 TheInvolvedNucleonsOfProjectile, SumMasses );
658 }
659 if ( theTargetNucleus->GetMassNumber() != 1 ) {
660 isOk = isOk && GenerateDeltaIsobar( SqrtS, NumberOfInvolvedNucleonsOfTarget,
661 TheInvolvedNucleonsOfTarget, SumMasses );
662 }
663 if ( ! isOk ) return false;
664
665 // Now we know that it is kinematically possible to produce a final state made
666 // of the involved nucleons (or corresponding delta-isobars) and a residual nucleus.
667 // We have to sample the kinematical variables which will allow to define the 4-momenta
668 // of the final state. The sampled kinematical variables refer to the center-of-mass frame.
669 // Notice that the sampling of the transverse momentum corresponds to take into account
670 // Fermi motion.
671
672 G4LorentzRotation toCms( -1*Psum.boostVector() );
673 G4LorentzVector Ptmp = toCms*Pprojectile;
674 if ( Ptmp.pz() <= 0.0 ) return false; // "String" moving backwards in c.m.s., abort collision!
675
676 G4LorentzRotation toLab( toCms.inverse() );
677
678 G4double YprojectileNucleus = 0.0;
679 if ( isProjectileNucleus ) {
680 Ptmp = toCms*Pproj;
681 YprojectileNucleus = Ptmp.rapidity();
682 }
683 Ptmp = toCms*Ptarget;
684 G4double YtargetNucleus = Ptmp.rapidity();
685
686 // Ascribing of the involved nucleons Pt and Xminus
687 G4double DcorP = 0.0;
688 if ( isProjectileNucleus ) DcorP = theParameters->GetDofNuclearDestruction() / thePrNucleus->GetMassNumber();
689 G4double DcorT = theParameters->GetDofNuclearDestruction() / theTargetNucleus->GetMassNumber();
690 G4double AveragePt2 = theParameters->GetPt2ofNuclearDestruction();
691 G4double maxPtSquare = theParameters->GetMaxPt2ofNuclearDestruction();
692
693 #ifdef debugPutOnMassShell
694 if ( isProjectileNucleus ) {
695 G4cout << "Y projectileNucleus " << YprojectileNucleus << G4endl;
696 }
697 G4cout << "Y targetNucleus " << YtargetNucleus << G4endl
698 << "Dcor " << theParameters->GetDofNuclearDestruction()
699 << " DcorP DcorT " << DcorP << " " << DcorT << " AveragePt2 " << AveragePt2 << G4endl;
700 #endif
701
702 G4double M2proj = M2projectile; // Initialization needed only for hadron-nucleus collisions
703 G4double WplusProjectile = 0.0;
704 G4double M2target = 0.0;
705 G4double WminusTarget = 0.0;
706 G4int NumberOfTries = 0;
707 G4double ScaleFactor = 2.0;
708 G4bool OuterSuccess = true;
709
710 const G4int maxNumberOfLoops = 1000;
711 G4int loopCounter = 0;
712 do { // while ( ! OuterSuccess )
713 OuterSuccess = true;
714 const G4int maxNumberOfInnerLoops = 10000;
715 do { // while ( SqrtS < Mprojectile + std::sqrt( M2target ) )
716 NumberOfTries++;
717 if ( NumberOfTries == 100*(NumberOfTries/100) ) {
718 // After many tries, it is convenient to reduce the values of DcorP, DcorT and
719 // AveragePt2, so that the sampled momenta (respectively, pz, and pt) of the
720 // involved nucleons (or corresponding delta-isomers) are smaller, and therefore
721 // it is more likely to satisfy the momentum conservation.
722 ScaleFactor /= 2.0;
723 DcorP *= ScaleFactor;
724 DcorT *= ScaleFactor;
725 AveragePt2 *= ScaleFactor;
726 }
727 if ( isProjectileNucleus ) {
728 // Sampling of kinematical properties of projectile nucleons
729 isOk = SamplingNucleonKinematics( AveragePt2, maxPtSquare, DcorP,
730 thePrNucleus, PprojResidual,
731 PrResidualMass, ProjectileResidualMassNumber,
732 NumberOfInvolvedNucleonsOfProjectile,
733 TheInvolvedNucleonsOfProjectile, M2proj );
734 }
735 // Sampling of kinematical properties of target nucleons
736 isOk = isOk && SamplingNucleonKinematics( AveragePt2, maxPtSquare, DcorT,
737 theTargetNucleus, PtargetResidual,
738 TargetResidualMass, TargetResidualMassNumber,
739 NumberOfInvolvedNucleonsOfTarget,
740 TheInvolvedNucleonsOfTarget, M2target );
741 #ifdef debugPutOnMassShell
742 G4cout << "SqrtS, Mp+Mt, Mp, Mt " << SqrtS/GeV << " "
743 << ( std::sqrt( M2proj ) + std::sqrt( M2target) )/GeV << " "
744 << std::sqrt( M2proj )/GeV << " " << std::sqrt( M2target )/GeV << G4endl;
745 #endif
746 if ( ! isOk ) return false;
747 } while ( ( SqrtS < std::sqrt( M2proj ) + std::sqrt( M2target ) ) &&
748 NumberOfTries < maxNumberOfInnerLoops ); /* Loop checking, 10.08.2015, A.Ribon */
749 if ( NumberOfTries >= maxNumberOfInnerLoops ) {
750 #ifdef debugPutOnMassShell
751 G4cout << "BAD situation: forced exit of the inner while loop!" << G4endl;
752 #endif
753 return false;
754 }
755 if ( isProjectileNucleus ) {
756 isOk = CheckKinematics( S, SqrtS, M2proj, M2target, YprojectileNucleus, true,
757 NumberOfInvolvedNucleonsOfProjectile,
758 TheInvolvedNucleonsOfProjectile,
759 WminusTarget, WplusProjectile, OuterSuccess );
760 }
761 isOk = isOk && CheckKinematics( S, SqrtS, M2proj, M2target, YtargetNucleus, false,
762 NumberOfInvolvedNucleonsOfTarget, TheInvolvedNucleonsOfTarget,
763 WminusTarget, WplusProjectile, OuterSuccess );
764 if ( ! isOk ) return false;
765 } while ( ( ! OuterSuccess ) &&
766 ++loopCounter < maxNumberOfLoops ); /* Loop checking, 10.08.2015, A.Ribon */
767 if ( loopCounter >= maxNumberOfLoops ) {
768 #ifdef debugPutOnMassShell
769 G4cout << "BAD situation: forced exit of the while loop!" << G4endl;
770 #endif
771 return false;
772 }
773
774 // Now the sampling is completed, and we can determine the kinematics of the
775 // whole system. This is done first in the center-of-mass frame, and then it is boosted
776 // to the lab frame. The transverse momentum of the residual nucleus is determined as
777 // the recoil of each hadron (nucleon or delta) which is emitted, i.e. in such a way
778 // to conserve (by construction) the transverse momentum.
779
780 if ( ! isProjectileNucleus ) { // hadron-nucleus collision
781
782 G4double Pzprojectile = WplusProjectile/2.0 - M2projectile/2.0/WplusProjectile;
783 G4double Eprojectile = WplusProjectile/2.0 + M2projectile/2.0/WplusProjectile;
784 Pprojectile.setPz( Pzprojectile );
785 Pprojectile.setE( Eprojectile );
786
787 #ifdef debugPutOnMassShell
788 G4cout << "Proj after in CMS " << Pprojectile << G4endl;
789 #endif
790
791 Pprojectile.transform( toLab );
792 theProjectile.SetMomentum( Pprojectile.vect() );
793 theProjectile.SetTotalEnergy( Pprojectile.e() );
794
795 theParticipants.StartLoop();
796 theParticipants.Next();
797 G4VSplitableHadron* primary = theParticipants.GetInteraction().GetProjectile();
798 primary->Set4Momentum( Pprojectile );
799
800 #ifdef debugPutOnMassShell
801 G4cout << "Final proj. mom in Lab. " << primary->Get4Momentum() << G4endl;
802 #endif
803
804 } else { // nucleus-nucleus or antinucleus-nucleus collision
805
806 isOk = FinalizeKinematics( WplusProjectile, true, toLab, PrResidualMass,
807 ProjectileResidualMassNumber, NumberOfInvolvedNucleonsOfProjectile,
808 TheInvolvedNucleonsOfProjectile, ProjectileResidual4Momentum );
809
810 #ifdef debugPutOnMassShell
811 G4cout << "Projectile Residual4Momentum in CMS " << ProjectileResidual4Momentum << G4endl;
812 #endif
813
814 if ( ! isOk ) return false;
815
816 ProjectileResidual4Momentum.transform( toLab );
817
818 #ifdef debugPutOnMassShell
819 G4cout << "Projectile Residual4Momentum in Lab " << ProjectileResidual4Momentum << G4endl;
820 #endif
821
822 }
823
824 isOk = FinalizeKinematics( WminusTarget, false, toLab, TargetResidualMass,
825 TargetResidualMassNumber, NumberOfInvolvedNucleonsOfTarget,
826 TheInvolvedNucleonsOfTarget, TargetResidual4Momentum );
827
828 #ifdef debugPutOnMassShell
829 G4cout << "Target Residual4Momentum in CMS " << TargetResidual4Momentum << G4endl;
830 #endif
831
832 if ( ! isOk ) return false;
833
834 TargetResidual4Momentum.transform( toLab );
835
836 #ifdef debugPutOnMassShell
837 G4cout << "Target Residual4Momentum in Lab " << TargetResidual4Momentum << G4endl;
838 #endif
839
840 return true;
841
842}
843
844
845//============================================================================
846
847G4bool G4FTFModel::ExciteParticipants() {
848
849 #ifdef debugBuildString
850 G4cout << "G4FTFModel::ExciteParticipants() " << G4endl;
851 #endif
852
853 G4bool Success( false );
854 G4int MaxNumOfInelCollisions = G4int( theParameters->GetMaxNumberOfCollisions() );
855 if ( MaxNumOfInelCollisions > 0 ) { // Plab > Pbound, normal application of FTF is possible
856 G4double ProbMaxNumber = theParameters->GetMaxNumberOfCollisions() - MaxNumOfInelCollisions;
857 if ( G4UniformRand() < ProbMaxNumber ) MaxNumOfInelCollisions++;
858 } else {
859 // Plab < Pbound, normal application of FTF is impossible,low energy corrections applied
860 MaxNumOfInelCollisions = 1;
861 }
862
863 #ifdef debugBuildString
864 G4cout << "MaxNumOfInelCollisions per hadron/nucleon " << MaxNumOfInelCollisions << G4endl;
865 #endif
866
867 G4int CurrentInteraction( 0 );
868 theParticipants.StartLoop();
869
870 G4bool InnerSuccess( true );
871 while ( theParticipants.Next() ) { /* Loop checking, 10.08.2015, A.Ribon */
872 CurrentInteraction++;
873 const G4InteractionContent& collision = theParticipants.GetInteraction();
874 G4VSplitableHadron* projectile = collision.GetProjectile();
875 G4Nucleon* ProjectileNucleon = collision.GetProjectileNucleon();
876 G4VSplitableHadron* target = collision.GetTarget();
877 G4Nucleon* TargetNucleon = collision.GetTargetNucleon();
878
879 #ifdef debugBuildString
880 G4cout << G4endl << "Interaction # Status " << CurrentInteraction << " "
881 << collision.GetStatus() << G4endl << "Pr* Tr* " << projectile << " "
882 << target << G4endl << "projectile->GetStatus target->GetStatus "
883 << projectile->GetStatus() << " " << target->GetStatus() << G4endl
884 << "projectile->GetSoftC target->GetSoftC " << projectile->GetSoftCollisionCount()
885 << " " << target->GetSoftCollisionCount() << G4endl;
886 #endif
887
888 if ( collision.GetStatus() ) {
889 if ( G4UniformRand() < theParameters->GetProbabilityOfElasticScatt() ) {
890 // Elastic scattering
891
892 #ifdef debugBuildString
893 G4cout << "Elastic scattering" << G4endl;
894 #endif
895
896 if ( ! HighEnergyInter ) {
897 G4bool Annihilation = false;
898 G4bool Result = AdjustNucleons( projectile, ProjectileNucleon, target,
899 TargetNucleon, Annihilation );
900 if ( ! Result ) continue;
901 }
902 InnerSuccess = theElastic->ElasticScattering( projectile, target, theParameters );
903 } else if ( G4UniformRand() > theParameters->GetProbabilityOfAnnihilation() ) {
904 // Inelastic scattering
905
906 #ifdef debugBuildString
907 G4cout << "Inelastic interaction" << G4endl
908 << "MaxNumOfInelCollisions per hadron/nucleon " << MaxNumOfInelCollisions << G4endl;
909 #endif
910
911 if ( ! HighEnergyInter ) {
912 G4bool Annihilation = false;
913 G4bool Result = AdjustNucleons( projectile, ProjectileNucleon, target,
914 TargetNucleon, Annihilation );
915 if ( ! Result ) continue;
916 }
917 if ( G4UniformRand() <
918 ( 1.0 - target->GetSoftCollisionCount() / MaxNumOfInelCollisions ) *
919 ( 1.0 - projectile->GetSoftCollisionCount() / MaxNumOfInelCollisions ) ) {
920 //if ( ! HighEnergyInter ) {
921 // G4bool Annihilation = false;
922 // G4bool Result = AdjustNucleons( projectile, ProjectileNucleon, target,
923 // TargetNucleon, Annihilation );
924 // if ( ! Result ) continue;
925 //}
926 if ( theExcitation->ExciteParticipants( projectile, target, theParameters, theElastic ) ) {
927 InnerSuccess = true;
928 NumberOfNNcollisions++;
929 #ifdef debugBuildString
930 G4cout << "FTF excitation Successfull " << G4endl;
931 // G4cout << "After pro " << projectile->Get4Momentum() << " "
932 // << projectile->Get4Momentum().mag() << G4endl
933 // << "After tar " << target->Get4Momentum() << " "
934 // << target->Get4Momentum().mag() << G4endl;
935 #endif
936 } else {
937 InnerSuccess = theElastic->ElasticScattering( projectile, target, theParameters );
938 #ifdef debugBuildString
939 G4cout << "FTF excitation Non InnerSuccess of Elastic scattering "
940 << InnerSuccess << G4endl;
941 #endif
942 }
943 } else { // The inelastic interactition was rejected -> elastic scattering
944 #ifdef debugBuildString
945 G4cout << "Elastic scat. at rejection inelastic scattering" << G4endl;
946 #endif
947 //if ( ! HighEnergyInter ) {
948 // G4bool Annihilation = false;
949 // G4bool Result = AdjustNucleons( projectile, ProjectileNucleon, target,
950 // TargetNucleon, Annihilation );
951 // if ( ! Result) continue;
952 //}
953 InnerSuccess = theElastic->ElasticScattering( projectile, target, theParameters );
954 }
955 } else { // Annihilation
956
957 #ifdef debugBuildString
958 G4cout << "Annihilation" << G4endl;
959 #endif
960
961 // At last, annihilation
962 if ( ! HighEnergyInter ) {
963 G4bool Annihilation = true;
964 G4bool Result = AdjustNucleons( projectile, ProjectileNucleon, target,
965 TargetNucleon, Annihilation );
966 if ( ! Result ) continue;
967 }
968
969 G4VSplitableHadron* AdditionalString = 0;
970 if ( theAnnihilation->Annihilate( projectile, target, AdditionalString, theParameters ) ) {
971 InnerSuccess = true;
972 #ifdef debugBuildString
973 G4cout << "Annihilation successfull. " << "*AdditionalString "
974 << AdditionalString << G4endl;
975 //G4cout << "After pro " << projectile->Get4Momentum() << G4endl;
976 //G4cout << "After tar " << target->Get4Momentum() << G4endl;
977 #endif
978
979 if ( AdditionalString != 0 ) theAdditionalString.push_back( AdditionalString );
980
981 NumberOfNNcollisions++;
982
983 // Skipping possible interactions of the annihilated nucleons
984 while ( theParticipants.Next() ) { /* Loop checking, 10.08.2015, A.Ribon */
985 G4InteractionContent& acollision = theParticipants.GetInteraction();
986 G4VSplitableHadron* NextProjectileNucleon = acollision.GetProjectile();
987 G4VSplitableHadron* NextTargetNucleon = acollision.GetTarget();
988 if ( projectile == NextProjectileNucleon || target == NextTargetNucleon ) {
989 acollision.SetStatus( 0 );
990 }
991 }
992
993 // Continue the interactions
994 theParticipants.StartLoop();
995 for ( G4int i = 0; i < CurrentInteraction; ++i ) theParticipants.Next();
996
997 /*
998 if ( target->GetStatus() == 4 ) {
999 // Skipping possible interactions of the annihilated nucleons
1000 while ( theParticipants.Next() ) {
1001 G4InteractionContent& acollision = theParticipants.GetInteraction();
1002 G4VSplitableHadron* NextProjectileNucleon = acollision.GetProjectile();
1003 G4VSplitableHadron* NextTargetNucleon = acollision.GetTarget();
1004 if ( target == NextTargetNucleon ) { acollision.SetStatus( 0 ); }
1005 }
1006 }
1007 theParticipants.StartLoop();
1008 for ( G4int I = 0; I < CurrentInteraction; ++I ) theParticipants.Next();
1009 */
1010
1011 }
1012 }
1013 }
1014
1015 if( InnerSuccess ) Success = true;
1016
1017 #ifdef debugBuildString
1018 G4cout << "----------------------------- Final properties " << G4endl
1019 << "projectile->GetStatus target->GetStatus " << projectile->GetStatus()
1020 << " " << target->GetStatus() << G4endl << "projectile->GetSoftC target->GetSoftC "
1021 << projectile->GetSoftCollisionCount() << " " << target->GetSoftCollisionCount()
1022 << G4endl << "ExciteParticipants() Success? " << Success << G4endl;
1023 #endif
1024
1025 } // end of while ( theParticipants.Next() )
1026
1027 return Success;
1028}
1029
1030
1031//============================================================================
1032
1033G4bool G4FTFModel::AdjustNucleons( G4VSplitableHadron* SelectedAntiBaryon,
1034 G4Nucleon* ProjectileNucleon,
1035 G4VSplitableHadron* SelectedTargetNucleon,
1036 G4Nucleon* TargetNucleon,
1037 G4bool Annihilation ) {
1038
1039 #ifdef debugAdjust
1040 G4cout << "AdjustNucleons ---------------------------------------" << G4endl
1041 << "Proj is nucleus? " << GetProjectileNucleus() << G4endl
1042 << "Proj 4mom " << SelectedAntiBaryon->Get4Momentum() << G4endl
1043 << "Targ 4mom " << SelectedTargetNucleon->Get4Momentum() << G4endl
1044 << "Pr ResidualMassNumber Pr ResidualCharge Pr ResidualExcitationEnergy "
1045 << ProjectileResidualMassNumber << " " << ProjectileResidualCharge << " "
1046 << ProjectileResidualExcitationEnergy << G4endl
1047 << "Tr ResidualMassNumber Tr ResidualCharge Tr ResidualExcitationEnergy "
1048 << TargetResidualMassNumber << " " << TargetResidualCharge << " "
1049 << TargetResidualExcitationEnergy << G4endl
1050 << "Collis. pr tr " << SelectedAntiBaryon->GetSoftCollisionCount() << " "
1051 << SelectedTargetNucleon->GetSoftCollisionCount() << G4endl;
1052 #endif
1053
1054 if ( SelectedAntiBaryon->GetSoftCollisionCount() != 0 &&
1055 SelectedTargetNucleon->GetSoftCollisionCount() != 0 ) {
1056 return true; // Selected hadrons were adjusted before.
1057 }
1058
1059 G4int interactionCase = 0;
1060 if ( ( ! GetProjectileNucleus() &&
1061 SelectedAntiBaryon->GetSoftCollisionCount() == 0 &&
1062 SelectedTargetNucleon->GetSoftCollisionCount() == 0 )
1063 ||
1064 ( SelectedAntiBaryon->GetSoftCollisionCount() != 0 &&
1065 SelectedTargetNucleon->GetSoftCollisionCount() == 0 ) ) {
1066 // The case of hadron-nucleus interactions, or
1067 // the case when projectile nuclear nucleon participated in
1068 // a collision, but target nucleon did not participate.
1069 interactionCase = 1;
1070 #ifdef debugAdjust
1071 G4cout << "case 1, hA prcol=0 trcol=0, AA prcol#0 trcol=0" << G4endl;
1072 #endif
1073 if ( TargetResidualMassNumber < 1 ) {
1074 return false;
1075 }
1076 if ( SelectedAntiBaryon->Get4Momentum().rapidity() < TargetResidual4Momentum.rapidity() ) {
1077 return false;
1078 }
1079 if ( TargetResidualMassNumber == 1 ) {
1080 TargetResidualMassNumber = 0;
1081 TargetResidualCharge = 0;
1082 TargetResidualExcitationEnergy = 0.0;
1083 SelectedTargetNucleon->Set4Momentum( TargetResidual4Momentum );
1084 TargetResidual4Momentum = G4LorentzVector( 0.0, 0.0, 0.0, 0.0 );
1085 return true;
1086 }
1087 } else if ( SelectedAntiBaryon->GetSoftCollisionCount() == 0 &&
1088 SelectedTargetNucleon->GetSoftCollisionCount() != 0 ) {
1089 // It is assumed that in the case there is ProjectileResidualNucleus
1090 interactionCase = 2;
1091 #ifdef debugAdjust
1092 G4cout << "case 2, prcol=0 trcol#0" << G4endl;
1093 #endif
1094 if ( ProjectileResidualMassNumber < 1 ) {
1095 return false;
1096 }
1097 if ( ProjectileResidual4Momentum.rapidity() <=
1098 SelectedTargetNucleon->Get4Momentum().rapidity() ) {
1099 return false;
1100 }
1101 if ( ProjectileResidualMassNumber == 1 ) {
1102 ProjectileResidualMassNumber = 0;
1103 ProjectileResidualCharge = 0;
1104 ProjectileResidualExcitationEnergy = 0.0;
1105 SelectedAntiBaryon->Set4Momentum( ProjectileResidual4Momentum );
1106 ProjectileResidual4Momentum = G4LorentzVector( 0.0, 0.0, 0.0, 0.0 );
1107 return true;
1108 }
1109 } else { // It has to be a nucleus-nucleus interaction
1110 interactionCase = 3;
1111 #ifdef debugAdjust
1112 G4cout << "case 3, prcol=0 trcol=0" << G4endl;
1113 #endif
1114 if ( ! GetProjectileNucleus() ) {
1115 return false;
1116 }
1117 #ifdef debugAdjust
1118 G4cout << "Proj res Init " << ProjectileResidual4Momentum << G4endl
1119 << "Targ res Init " << TargetResidual4Momentum << G4endl
1120 << "ProjectileResidualMassNumber ProjectileResidualCharge (ProjectileResidualLambdaNumber)"
1121 << ProjectileResidualMassNumber << " " << ProjectileResidualCharge
1122 << " (" << ProjectileResidualLambdaNumber << ") " << G4endl
1123 << "TargetResidualMassNumber TargetResidualCharge " << TargetResidualMassNumber
1124 << " " << TargetResidualCharge << G4endl;
1125 #endif
1126 }
1127
1128 CommonVariables common;
1129 G4int returnCode = AdjustNucleonsAlgorithm_beforeSampling( interactionCase, SelectedAntiBaryon,
1130 ProjectileNucleon, SelectedTargetNucleon,
1131 TargetNucleon, Annihilation, common );
1132 G4bool returnResult = false;
1133 if ( returnCode == 0 ) {
1134 returnResult = true; // Successfully ended: no need of extra work
1135 } else if ( returnCode == 1 ) {
1136 // The part before sampling has been successfully completed: now try the sampling
1137 returnResult = AdjustNucleonsAlgorithm_Sampling( interactionCase, common );
1138 if ( returnResult ) { // The sampling has completed successfully: do the last part
1139 AdjustNucleonsAlgorithm_afterSampling( interactionCase, SelectedAntiBaryon,
1140 SelectedTargetNucleon, common );
1141 }
1142 }
1143
1144 return returnResult;
1145}
1146
1147//-------------------------------------------------------------------
1148
1149G4int G4FTFModel::AdjustNucleonsAlgorithm_beforeSampling( G4int interactionCase,
1150 G4VSplitableHadron* SelectedAntiBaryon,
1151 G4Nucleon* ProjectileNucleon,
1152 G4VSplitableHadron* SelectedTargetNucleon,
1153 G4Nucleon* TargetNucleon,
1154 G4bool Annihilation,
1155 G4FTFModel::CommonVariables& common ) {
1156 // First of the three utility methods used only by AdjustNucleons: prepare for sampling.
1157 // This method returns an integer code - instead of a boolean, with the following meaning:
1158 // "0" : successfully ended and nothing else needs to be done (i.e. no sampling);
1159 // "1" : successfully completed, but the work needs to be continued, i.e. try to sample;
1160 // "99" : unsuccessfully ended, nothing else can be done.
1161 G4int returnCode = 99;
1162
1163 G4double ExcitationEnergyPerWoundedNucleon = theParameters->GetExcitationEnergyPerWoundedNucleon();
1164
1165 // some checks and initializations
1166 if ( interactionCase == 1 ) {
1167 common.Psum = SelectedAntiBaryon->Get4Momentum() + TargetResidual4Momentum;
1168 #ifdef debugAdjust
1169 G4cout << "Targ res Init " << TargetResidual4Momentum << G4endl;
1170 #endif
1171 common.Pprojectile = SelectedAntiBaryon->Get4Momentum();
1172 } else if ( interactionCase == 2 ) {
1173 common.Psum = ProjectileResidual4Momentum + SelectedTargetNucleon->Get4Momentum();
1174 common.Pprojectile = ProjectileResidual4Momentum;
1175 } else if ( interactionCase == 3 ) {
1176 common.Psum = ProjectileResidual4Momentum + TargetResidual4Momentum;
1177 common.Pprojectile = ProjectileResidual4Momentum;
1178 }
1179
1180 // transform momenta to cms and then rotate parallel to z axis
1181 common.toCms = G4LorentzRotation( -1*common.Psum.boostVector() );
1182 common.Ptmp = common.toCms * common.Pprojectile;
1183 common.toCms.rotateZ( -1*common.Ptmp.phi() );
1184 common.toCms.rotateY( -1*common.Ptmp.theta() );
1185 common.Pprojectile.transform( common.toCms );
1186 common.toLab = common.toCms.inverse();
1187 common.SqrtS = common.Psum.mag();
1188 common.S = sqr( common.SqrtS );
1189
1190 // get properties of the target residual and/or projectile residual
1191 G4bool Stopping = false;
1192 if ( interactionCase == 1 ) {
1193 common.TResidualMassNumber = TargetResidualMassNumber - 1;
1194 common.TResidualCharge = TargetResidualCharge
1195 - G4int( TargetNucleon->GetDefinition()->GetPDGCharge() );
1196 common.TResidualExcitationEnergy = TargetResidualExcitationEnergy
1197 - ExcitationEnergyPerWoundedNucleon*G4Log( G4UniformRand() );
1198 if ( common.TResidualMassNumber <= 1 ) {
1199 common.TResidualExcitationEnergy = 0.0;
1200 }
1201 if ( common.TResidualMassNumber != 0 ) {
1202 common.TResidualMass = G4ParticleTable::GetParticleTable()->GetIonTable()
1203 ->GetIonMass( common.TResidualCharge, common.TResidualMassNumber );
1204 }
1205 common.TNucleonMass = TargetNucleon->GetDefinition()->GetPDGMass();
1206 common.SumMasses = SelectedAntiBaryon->Get4Momentum().mag() + common.TNucleonMass
1207 + common.TResidualMass;
1208 #ifdef debugAdjust
1209 G4cout << "Annihilation " << Annihilation << G4endl;
1210 #endif
1211 } else if ( interactionCase == 2 ) {
1212 common.Ptarget = common.toCms * SelectedTargetNucleon->Get4Momentum();
1213 common.TResidualMassNumber = ProjectileResidualMassNumber - 1;
1214 common.TResidualCharge = ProjectileResidualCharge
1215 - std::abs( G4int(ProjectileNucleon->GetDefinition()->GetPDGCharge()) );
1216 common.TResidualExcitationEnergy = ProjectileResidualExcitationEnergy
1217 - ExcitationEnergyPerWoundedNucleon*G4Log( G4UniformRand() );
1218 if ( common.TResidualMassNumber <= 1 ) {
1219 common.TResidualExcitationEnergy = 0.0;
1220 }
1221 if ( common.TResidualMassNumber != 0 ) {
1222 common.TResidualMass = G4ParticleTable::GetParticleTable()->GetIonTable()
1223 ->GetIonMass( common.TResidualCharge, common.TResidualMassNumber );
1224 }
1225 common.TNucleonMass = ProjectileNucleon->GetDefinition()->GetPDGMass();
1226 common.SumMasses = SelectedTargetNucleon->Get4Momentum().mag() + common.TNucleonMass
1227 + common.TResidualMass;
1228 #ifdef debugAdjust
1229 G4cout << "SelectedTN.mag() PNMass + PResidualMass "
1230 << SelectedTargetNucleon->Get4Momentum().mag() << " "
1231 << common.TNucleonMass << " " << common.TResidualMass << G4endl;
1232 #endif
1233 } else if ( interactionCase == 3 ) {
1234 common.Ptarget = common.toCms * TargetResidual4Momentum;
1235 common.PResidualMassNumber = ProjectileResidualMassNumber - 1;
1236 common.PResidualCharge = ProjectileResidualCharge
1237 - std::abs( G4int(ProjectileNucleon->GetDefinition()->GetPDGCharge()) );
1238 common.PResidualLambdaNumber = ProjectileResidualLambdaNumber;
1239 if ( ProjectileNucleon->GetDefinition() == G4Lambda::Definition() ||
1240 ProjectileNucleon->GetDefinition() == G4AntiLambda::Definition() ) {
1241 --common.PResidualLambdaNumber;
1242 }
1243 common.PResidualExcitationEnergy = ProjectileResidualExcitationEnergy
1244 - ExcitationEnergyPerWoundedNucleon*G4Log( G4UniformRand() );
1245 if ( common.PResidualMassNumber <= 1 ) {
1246 common.PResidualExcitationEnergy = 0.0;
1247 }
1248 if ( common.PResidualMassNumber != 0 ) {
1249 if ( common.PResidualMassNumber == 1 ) {
1250 if ( std::abs( common.PResidualCharge ) == 1 ) {
1251 common.PResidualMass = G4Proton::Definition()->GetPDGMass();
1252 } else if ( common.PResidualLambdaNumber == 1 ) {
1253 common.PResidualMass = G4Lambda::Definition()->GetPDGMass();
1254 } else {
1255 common.PResidualMass = G4Neutron::Definition()->GetPDGMass();
1256 }
1257 } else {
1258 if ( common.PResidualLambdaNumber > 0 ) {
1259 if ( common.PResidualMassNumber == 2 ) {
1260 common.PResidualMass = G4Lambda::Definition()->GetPDGMass();
1261 if ( std::abs( common.PResidualCharge ) == 1 ) { // lambda + proton
1262 common.PResidualMass += G4Proton::Definition()->GetPDGMass();
1263 } else if ( common.PResidualLambdaNumber == 1 ) { // lambda + neutron
1264 common.PResidualMass += G4Neutron::Definition()->GetPDGMass();
1265 } else { // lambda + lambda
1266 common.PResidualMass += G4Lambda::Definition()->GetPDGMass();
1267 }
1268 } else {
1269 common.PResidualMass = G4HyperNucleiProperties::GetNuclearMass( common.PResidualMassNumber,
1270 std::abs( common.PResidualCharge ),
1271 common.PResidualLambdaNumber );
1272 }
1273 } else {
1274 common.PResidualMass = G4ParticleTable::GetParticleTable()->GetIonTable()->
1275 GetIonMass( std::abs( common.PResidualCharge ), common.PResidualMassNumber );
1276 }
1277 }
1278 }
1279 common.PNucleonMass = ProjectileNucleon->GetDefinition()->GetPDGMass(); // On-shell (anti-)nucleon mass
1280 common.TResidualMassNumber = TargetResidualMassNumber - 1;
1281 common.TResidualCharge = TargetResidualCharge
1282 - G4int( TargetNucleon->GetDefinition()->GetPDGCharge() );
1283 common.TResidualExcitationEnergy = TargetResidualExcitationEnergy
1284 - ExcitationEnergyPerWoundedNucleon*G4Log( G4UniformRand() );
1285 if ( common.TResidualMassNumber <= 1 ) {
1286 common.TResidualExcitationEnergy = 0.0;
1287 }
1288 if ( common.TResidualMassNumber != 0 ) {
1289 common.TResidualMass = G4ParticleTable::GetParticleTable()->GetIonTable()->
1290 GetIonMass( common.TResidualCharge, common.TResidualMassNumber );
1291 }
1292 common.TNucleonMass = TargetNucleon->GetDefinition()->GetPDGMass(); // On-shell nucleon mass
1293 common.SumMasses = common.PNucleonMass + common.PResidualMass + common.TNucleonMass
1294 + common.TResidualMass;
1295 #ifdef debugAdjust
1296 G4cout << "PNucleonMass PResidualMass TNucleonMass TResidualMass " << common.PNucleonMass
1297 << " " << common.PResidualMass << " " << common.TNucleonMass << " "
1298 << common.TResidualMass << G4endl
1299 << "PResidualExcitationEnergy " << common.PResidualExcitationEnergy << G4endl
1300 << "TResidualExcitationEnergy " << common.TResidualExcitationEnergy << G4endl;
1301 #endif
1302 } // End-if on interactionCase
1303
1304 if ( ! Annihilation ) {
1305 if ( common.SqrtS < common.SumMasses ) {
1306 #ifdef debugAdjust
1307 G4cout << "SqrtS < SumMasses " << common.SqrtS << " " << common.SumMasses << G4endl;
1308 #endif
1309 return returnCode; // Unsuccessfully ended, nothing else can be done
1310 }
1311 if ( interactionCase == 1 || interactionCase == 2 ) {
1312 if ( common.SqrtS < common.SumMasses + common.TResidualExcitationEnergy ) {
1313 #ifdef debugAdjust
1314 G4cout << "TResidualExcitationEnergy : before " << common.TResidualExcitationEnergy << G4endl;
1315 #endif
1316 common.TResidualExcitationEnergy = common.SqrtS - common.SumMasses;
1317 #ifdef debugAdjust
1318 G4cout << "TResidualExcitationEnergy : after " << common.TResidualExcitationEnergy << G4endl;
1319 #endif
1320 Stopping = true;
1321 return returnCode; // unsuccessfully ended, nothing else can be done
1322 }
1323 } else if ( interactionCase == 3 ) {
1324 #ifdef debugAdjust
1325 G4cout << "SqrtS < SumMasses + PResidualExcitationEnergy + TResidualExcitationEnergy "
1326 << common.SqrtS << " " << common.SumMasses + common.PResidualExcitationEnergy + common.TResidualExcitationEnergy
1327 << G4endl;
1328 #endif
1329 if ( common.SqrtS < common.SumMasses + common.PResidualExcitationEnergy
1330 + common.TResidualExcitationEnergy ) {
1331 Stopping = true;
1332 if ( common.PResidualExcitationEnergy <= 0.0 ) {
1333 common.TResidualExcitationEnergy = common.SqrtS - common.SumMasses;
1334 } else if ( common.TResidualExcitationEnergy <= 0.0 ) {
1335 common.PResidualExcitationEnergy = common.SqrtS - common.SumMasses;
1336 } else {
1337 G4double Fraction = ( common.SqrtS - common.SumMasses )
1338 / ( common.PResidualExcitationEnergy + common.TResidualExcitationEnergy );
1339 common.PResidualExcitationEnergy *= Fraction;
1340 common.TResidualExcitationEnergy *= Fraction;
1341 }
1342 }
1343 }
1344 } // End-if on ! Annihilation
1345
1346 if ( Annihilation ) {
1347 #ifdef debugAdjust
1348 G4cout << "SqrtS < SumMasses - TNucleonMass " << common.SqrtS << " "
1349 << common.SumMasses - common.TNucleonMass << G4endl;
1350 #endif
1351 if ( common.SqrtS < common.SumMasses - common.TNucleonMass ) {
1352 return returnCode; // unsuccessfully ended, nothing else can be done
1353 }
1354 #ifdef debugAdjust
1355 G4cout << "SqrtS < SumMasses " << common.SqrtS << " " << common.SumMasses << G4endl;
1356 #endif
1357 if ( common.SqrtS < common.SumMasses ) {
1358 if ( interactionCase == 2 || interactionCase == 3 ) {
1359 common.TResidualExcitationEnergy = 0.0;
1360 }
1361 common.TNucleonMass = common.SqrtS - ( common.SumMasses - common.TNucleonMass )
1362 - common.TResidualExcitationEnergy; // Off-shell nucleon mass
1363 #ifdef debugAdjust
1364 G4cout << "TNucleonMass " << common.TNucleonMass << G4endl;
1365 #endif
1366 common.SumMasses = common.SqrtS - common.TResidualExcitationEnergy;
1367 Stopping = true;
1368 #ifdef debugAdjust
1369 G4cout << "SqrtS < SumMasses " << common.SqrtS << " " << common.SumMasses << G4endl;
1370 #endif
1371 }
1372 if ( interactionCase == 1 || interactionCase == 2 ) {
1373 if ( common.SqrtS < common.SumMasses + common.TResidualExcitationEnergy ) {
1374 common.TResidualExcitationEnergy = common.SqrtS - common.SumMasses;
1375 Stopping = true;
1376 }
1377 } else if ( interactionCase == 3 ) {
1378 if ( common.SqrtS < common.SumMasses + common.PResidualExcitationEnergy
1379 + common.TResidualExcitationEnergy ) {
1380 Stopping = true;
1381 if ( common.PResidualExcitationEnergy <= 0.0 ) {
1382 common.TResidualExcitationEnergy = common.SqrtS - common.SumMasses;
1383 } else if ( common.TResidualExcitationEnergy <= 0.0 ) {
1384 common.PResidualExcitationEnergy = common.SqrtS - common.SumMasses;
1385 } else {
1386 G4double Fraction = ( common.SqrtS - common.SumMasses ) /
1387 ( common.PResidualExcitationEnergy + common.TResidualExcitationEnergy );
1388 common.PResidualExcitationEnergy *= Fraction;
1389 common.TResidualExcitationEnergy *= Fraction;
1390 }
1391 }
1392 }
1393 } // End-if on Annihilation
1394
1395 #ifdef debugAdjust
1396 G4cout << "Stopping " << Stopping << G4endl;
1397 #endif
1398
1399 if ( Stopping ) {
1400 // All 3-momenta of particles = 0
1401 common.Ptmp.setPx( 0.0 ); common.Ptmp.setPy( 0.0 ); common.Ptmp.setPz( 0.0 );
1402 // New projectile
1403 if ( interactionCase == 1 ) {
1404 common.Ptmp.setE( SelectedAntiBaryon->Get4Momentum().mag() );
1405 } else if ( interactionCase == 2 ) {
1406 common.Ptmp.setE( common.TNucleonMass );
1407 } else if ( interactionCase == 3 ) {
1408 common.Ptmp.setE( common.PNucleonMass );
1409 }
1410 #ifdef debugAdjust
1411 G4cout << "Proj stop " << common.Ptmp << G4endl;
1412 #endif
1413 common.Pprojectile = common.Ptmp;
1414 common.Pprojectile.transform( common.toLab ); // From center-of-mass to Lab frame
1415 //---AR-Jul2019 : To avoid unphysical projectile (anti-)fragments at rest, save the
1416 // original momentum of the anti-baryon in the center-of-mass frame.
1417 G4LorentzVector saveSelectedAntiBaryon4Momentum = SelectedAntiBaryon->Get4Momentum();
1418 saveSelectedAntiBaryon4Momentum.transform( common.toCms ); // From Lab to center-of-mass frame
1419 //---
1420 SelectedAntiBaryon->Set4Momentum( common.Pprojectile );
1421 // New target nucleon
1422 if ( interactionCase == 1 || interactionCase == 3 ) {
1423 common.Ptmp.setE( common.TNucleonMass );
1424 } else if ( interactionCase == 2 ) {
1425 common.Ptmp.setE( SelectedTargetNucleon->Get4Momentum().mag() );
1426 }
1427 #ifdef debugAdjust
1428 G4cout << "Targ stop " << common.Ptmp << G4endl;
1429 #endif
1430 common.Ptarget = common.Ptmp;
1431 common.Ptarget.transform( common.toLab ); // From center-of-mass to Lab frame
1432 //---AR-Jul2019 : To avoid unphysical target fragments at rest, save the original
1433 // momentum of the target nucleon in the center-of-mass frame.
1434 G4LorentzVector saveSelectedTargetNucleon4Momentum = SelectedTargetNucleon->Get4Momentum();
1435 saveSelectedTargetNucleon4Momentum.transform( common.toCms ); // From Lab to center-of-mass frame
1436 //---
1437 SelectedTargetNucleon->Set4Momentum( common.Ptarget );
1438 // New target residual
1439 if ( interactionCase == 1 || interactionCase == 3 ) {
1440 common.Ptmp.setPx( 0.0 ); common.Ptmp.setPy( 0.0 ); common.Ptmp.setPz( 0.0 );
1441 TargetResidualMassNumber = common.TResidualMassNumber;
1442 TargetResidualCharge = common.TResidualCharge;
1443 TargetResidualExcitationEnergy = common.TResidualExcitationEnergy;
1444 //---AR-Jul2019 : To avoid unphysical target fragments at rest, use the saved
1445 // original momentum of the target nucleon (instead of setting 0).
1446 // This is a rough and simple approach!
1447 //common.Ptmp.setE( common.TResidualMass + TargetResidualExcitationEnergy );
1448 common.Ptmp.setPx( -saveSelectedTargetNucleon4Momentum.x() );
1449 common.Ptmp.setPy( -saveSelectedTargetNucleon4Momentum.y() );
1450 common.Ptmp.setPz( -saveSelectedTargetNucleon4Momentum.z() );
1451 common.Ptmp.setE( std::sqrt( sqr( common.TResidualMass + TargetResidualExcitationEnergy ) + common.Ptmp.vect().mag2() ) );
1452 //---
1453 #ifdef debugAdjust
1454 G4cout << "Targ Resi stop " << common.Ptmp << G4endl;
1455 #endif
1456 common.Ptmp.transform( common.toLab ); // From center-of-mass to Lab frame
1457 TargetResidual4Momentum = common.Ptmp;
1458 }
1459 // New projectile residual
1460 if ( interactionCase == 2 || interactionCase == 3 ) {
1461 common.Ptmp.setPx( 0.0 ); common.Ptmp.setPy( 0.0 ); common.Ptmp.setPz( 0.0 );
1462 if ( interactionCase == 2 ) {
1463 ProjectileResidualMassNumber = common.TResidualMassNumber;
1464 ProjectileResidualCharge = common.TResidualCharge;
1465 ProjectileResidualLambdaNumber = 0; // The target nucleus and its residual are never hypernuclei
1466 ProjectileResidualExcitationEnergy = common.TResidualExcitationEnergy;
1467 common.Ptmp.setE( common.TResidualMass + ProjectileResidualExcitationEnergy );
1468 } else {
1469 ProjectileResidualMassNumber = common.PResidualMassNumber;
1470 ProjectileResidualCharge = common.PResidualCharge;
1471 ProjectileResidualLambdaNumber = common.PResidualLambdaNumber;
1472 ProjectileResidualExcitationEnergy = common.PResidualExcitationEnergy;
1473 //---AR-Jul2019 : To avoid unphysical projectile (anti-)fragments at rest, use the
1474 // saved original momentum of the anti-baryon (instead of setting 0).
1475 // This is a rough and simple approach!
1476 //common.Ptmp.setE( common.PResidualMass + ProjectileResidualExcitationEnergy );
1477 common.Ptmp.setPx( -saveSelectedAntiBaryon4Momentum.x() );
1478 common.Ptmp.setPy( -saveSelectedAntiBaryon4Momentum.y() );
1479 common.Ptmp.setPz( -saveSelectedAntiBaryon4Momentum.z() );
1480 common.Ptmp.setE( std::sqrt( sqr( common.PResidualMass + ProjectileResidualExcitationEnergy ) + common.Ptmp.vect().mag2() ) );
1481 //---
1482 }
1483 #ifdef debugAdjust
1484 G4cout << "Proj Resi stop " << common.Ptmp << G4endl;
1485 #endif
1486 common.Ptmp.transform( common.toLab ); // From center-of-mass to Lab frame
1487 ProjectileResidual4Momentum = common.Ptmp;
1488 }
1489 return returnCode = 0; // successfully ended and nothing else needs to be done (i.e. no sampling)
1490 } // End-if on Stopping
1491
1492 // Initializations before sampling
1493 if ( interactionCase == 1 ) {
1494 common.Mprojectile = common.Pprojectile.mag();
1495 common.M2projectile = common.Pprojectile.mag2();
1496 common.TResidual4Momentum = common.toCms * TargetResidual4Momentum;
1497 common.YtargetNucleus = common.TResidual4Momentum.rapidity();
1498 common.TResidualMass += common.TResidualExcitationEnergy;
1499 } else if ( interactionCase == 2 ) {
1500 common.Mtarget = common.Ptarget.mag();
1501 common.M2target = common.Ptarget.mag2();
1502 common.TResidual4Momentum = common.toCms * ProjectileResidual4Momentum;
1503 common.YprojectileNucleus = common.TResidual4Momentum.rapidity();
1504 common.TResidualMass += common.TResidualExcitationEnergy;
1505 } else if ( interactionCase == 3 ) {
1506 common.PResidual4Momentum = common.toCms * ProjectileResidual4Momentum;
1507 common.YprojectileNucleus = common.PResidual4Momentum.rapidity();
1508 common.TResidual4Momentum = common.toCms*TargetResidual4Momentum;
1509 common.YtargetNucleus = common.TResidual4Momentum.rapidity();
1510 common.PResidualMass += common.PResidualExcitationEnergy;
1511 common.TResidualMass += common.TResidualExcitationEnergy;
1512 }
1513 #ifdef debugAdjust
1514 G4cout << "YprojectileNucleus " << common.YprojectileNucleus << G4endl;
1515 #endif
1516
1517 return returnCode = 1; // successfully completed, but the work needs to be continued, i.e. try to sample
1518}
1519
1520
1521//-------------------------------------------------------------------
1522
1523G4bool G4FTFModel::AdjustNucleonsAlgorithm_Sampling( G4int interactionCase,
1524 G4FTFModel::CommonVariables& common ) {
1525 // Second of the three utility methods used only by AdjustNucleons: do the sampling.
1526 // This method returns "false" if it fails to sample properly, else it returns "true".
1527
1528 // Ascribing of the involved nucleons Pt and X
1529 G4double Dcor = theParameters->GetDofNuclearDestruction();
1530 G4double DcorP = 0.0, DcorT = 0.0;
1531 if ( ProjectileResidualMassNumber != 0 ) DcorP = Dcor / G4double(ProjectileResidualMassNumber);
1532 if ( TargetResidualMassNumber != 0 ) DcorT = Dcor / G4double(TargetResidualMassNumber);
1533 G4double AveragePt2 = theParameters->GetPt2ofNuclearDestruction();
1534 G4double maxPtSquare = theParameters->GetMaxPt2ofNuclearDestruction();
1535
1536 G4double ScaleFactor = 1.0;
1537 G4bool OuterSuccess = true;
1538 const G4int maxNumberOfLoops = 1000;
1539 const G4int maxNumberOfTries = 10000;
1540 G4int loopCounter = 0;
1541 G4int NumberOfTries = 0;
1542 do { // Outmost do while loop
1543 OuterSuccess = true;
1544 G4bool loopCondition = false;
1545 do { // Intermediate do while loop
1546 if ( NumberOfTries == 100*(NumberOfTries/100) ) {
1547 // At large number of tries it would be better to reduce the values
1548 ScaleFactor /= 2.0;
1549 DcorP *= ScaleFactor;
1550 DcorT *= ScaleFactor;
1551 AveragePt2 *= ScaleFactor;
1552 #ifdef debugAdjust
1553 //G4cout << "NumberOfTries ScaleFactor " << NumberOfTries << " " << ScaleFactor << G4endl;
1554 #endif
1555 }
1556
1557 // Some kinematics
1558 if ( interactionCase == 1 ) {
1559 } else if ( interactionCase == 2 ) {
1560 #ifdef debugAdjust
1561 G4cout << "ProjectileResidualMassNumber " << ProjectileResidualMassNumber << G4endl;
1562 #endif
1563 if ( ProjectileResidualMassNumber > 1 ) {
1564 common.PtNucleon = GaussianPt( AveragePt2, maxPtSquare );
1565 } else {
1566 common.PtNucleon = G4ThreeVector( 0.0, 0.0, 0.0 );
1567 }
1568 common.PtResidual = - common.PtNucleon;
1569 common.Mprojectile = std::sqrt( sqr( common.TNucleonMass ) + common.PtNucleon.mag2() )
1570 + std::sqrt( sqr( common.TResidualMass ) + common.PtResidual.mag2() );
1571 #ifdef debugAdjust
1572 G4cout << "SqrtS < Mtarget + Mprojectile " << common.SqrtS << " " << common.Mtarget
1573 << " " << common.Mprojectile << " " << common.Mtarget + common.Mprojectile << G4endl;
1574 #endif
1575 common.M2projectile = sqr( common.Mprojectile );
1576 if ( common.SqrtS < common.Mtarget + common.Mprojectile ) {
1577 OuterSuccess = false;
1578 loopCondition = true;
1579 continue;
1580 }
1581 } else if ( interactionCase == 3 ) {
1582 if ( ProjectileResidualMassNumber > 1 ) {
1583 common.PtNucleonP = GaussianPt( AveragePt2, maxPtSquare );
1584 } else {
1585 common.PtNucleonP = G4ThreeVector( 0.0, 0.0, 0.0 );
1586 }
1587 common.PtResidualP = - common.PtNucleonP;
1588 if ( TargetResidualMassNumber > 1 ) {
1589 common.PtNucleonT = GaussianPt( AveragePt2, maxPtSquare );
1590 } else {
1591 common.PtNucleonT = G4ThreeVector( 0.0, 0.0, 0.0 );
1592 }
1593 common.PtResidualT = - common.PtNucleonT;
1594 common.Mprojectile = std::sqrt( sqr( common.PNucleonMass ) + common.PtNucleonP.mag2() )
1595 + std::sqrt( sqr( common.PResidualMass ) + common.PtResidualP.mag2() );
1596 common.M2projectile = sqr( common.Mprojectile );
1597 common.Mtarget = std::sqrt( sqr( common.TNucleonMass ) + common.PtNucleonT.mag2() )
1598 + std::sqrt( sqr( common.TResidualMass ) + common.PtResidualT.mag2() );
1599 common.M2target = sqr( common.Mtarget );
1600 if ( common.SqrtS < common.Mprojectile + common.Mtarget ) {
1601 OuterSuccess = false;
1602 loopCondition = true;
1603 continue;
1604 }
1605 } // End-if on interactionCase
1606
1607 G4int numberOfTimesExecuteInnerLoop = 1;
1608 if ( interactionCase == 3 ) numberOfTimesExecuteInnerLoop = 2;
1609 for ( G4int iExecute = 0; iExecute < numberOfTimesExecuteInnerLoop; iExecute++ ) {
1610
1611 G4bool InnerSuccess = true;
1612 G4bool isTargetToBeHandled = ( interactionCase == 1 ||
1613 ( interactionCase == 3 && iExecute == 1 ) );
1614 G4bool condition = false;
1615 if ( isTargetToBeHandled ) {
1616 condition = ( TargetResidualMassNumber > 1 );
1617 } else { // Projectile to be handled
1618 condition = ( ProjectileResidualMassNumber > 1 );
1619 }
1620 if ( condition ) {
1621 const G4int maxNumberOfInnerLoops = 1000;
1622 G4int innerLoopCounter = 0;
1623 do { // Inner do while loop
1624 InnerSuccess = true;
1625 if ( isTargetToBeHandled ) {
1626 G4double Xcenter = 0.0;
1627 if ( interactionCase == 1 ) {
1628 common.PtNucleon = GaussianPt( AveragePt2, maxPtSquare );
1629 common.PtResidual = - common.PtNucleon;
1630 common.Mtarget = std::sqrt( sqr( common.TNucleonMass ) + common.PtNucleon.mag2() )
1631 + std::sqrt( sqr( common.TResidualMass ) + common.PtResidual.mag2() );
1632 if ( common.SqrtS < common.Mprojectile + common.Mtarget ) {
1633 InnerSuccess = false;
1634 continue;
1635 }
1636 Xcenter = std::sqrt( sqr( common.TNucleonMass ) + common.PtNucleon.mag2() )
1637 / common.Mtarget;
1638 } else {
1639 Xcenter = std::sqrt( sqr( common.TNucleonMass ) + common.PtNucleonT.mag2() )
1640 / common.Mtarget;
1641 }
1642 G4ThreeVector tmpX = GaussianPt( DcorT*DcorT, 1.0 );
1643 common.XminusNucleon = Xcenter + tmpX.x();
1644 if ( common.XminusNucleon <= 0.0 || common.XminusNucleon >= 1.0 ) {
1645 InnerSuccess = false;
1646 continue;
1647 }
1648 common.XminusResidual = 1.0 - common.XminusNucleon;
1649 } else { // Projectile to be handled
1650 G4ThreeVector tmpX = GaussianPt( DcorP*DcorP, 1.0 );
1651 G4double Xcenter = 0.0;
1652 if ( interactionCase == 2 ) {
1653 Xcenter = std::sqrt( sqr( common.TNucleonMass ) + common.PtNucleon.mag2() )
1654 / common.Mprojectile;
1655 } else {
1656 Xcenter = std::sqrt( sqr( common.PNucleonMass ) + common.PtNucleonP.mag2() )
1657 / common.Mprojectile;
1658 }
1659 common.XplusNucleon = Xcenter + tmpX.x();
1660 if ( common.XplusNucleon <= 0.0 || common.XplusNucleon >= 1.0 ) {
1661 InnerSuccess = false;
1662 continue;
1663 }
1664 common.XplusResidual = 1.0 - common.XplusNucleon;
1665 } // End-if on isTargetToBeHandled
1666 } while ( ( ! InnerSuccess ) && // Inner do while loop
1667 ++innerLoopCounter < maxNumberOfInnerLoops ); /* Loop checking, 10.08.2015, A.Ribon */
1668 if ( innerLoopCounter >= maxNumberOfInnerLoops ) {
1669 #ifdef debugAdjust
1670 G4cout << "BAD situation: forced exit of the inner while loop!" << G4endl;
1671 #endif
1672 return false;
1673 }
1674 } else { // condition is false
1675 if ( isTargetToBeHandled ) {
1676 common.XminusNucleon = 1.0;
1677 common.XminusResidual = 1.0; // It must be 0, but in the calculation of Pz, E is problematic
1678 } else { // Projectile to be handled
1679 common.XplusNucleon = 1.0;
1680 common.XplusResidual = 1.0; // It must be 0, but in the calculation of Pz, E is problematic
1681 }
1682 } // End-if on condition
1683
1684 } // End of for loop on iExecute
1685
1686 if ( interactionCase == 1 ) {
1687 common.M2target = ( sqr( common.TNucleonMass ) + common.PtNucleon.mag2() )
1688 / common.XminusNucleon
1689 + ( sqr( common.TResidualMass ) + common.PtResidual.mag2() )
1690 / common.XminusResidual;
1691 loopCondition = ( common.SqrtS < common.Mprojectile + std::sqrt( common.M2target ) );
1692 } else if ( interactionCase == 2 ) {
1693 #ifdef debugAdjust
1694 G4cout << "TNucleonMass PtNucleon XplusNucleon " << common.TNucleonMass << " "
1695 << common.PtNucleon << " " << common.XplusNucleon << G4endl
1696 << "TResidualMass PtResidual XplusResidual " << common.TResidualMass << " "
1697 << common.PtResidual << " " << common.XplusResidual << G4endl;
1698 #endif
1699 common.M2projectile = ( sqr( common.TNucleonMass ) + common.PtNucleon.mag2() )
1700 / common.XplusNucleon
1701 + ( sqr( common.TResidualMass ) + common.PtResidual.mag2() )
1702 / common.XplusResidual;
1703 #ifdef debugAdjust
1704 G4cout << "SqrtS < Mtarget + std::sqrt(M2projectile) " << common.SqrtS << " "
1705 << common.Mtarget << " " << std::sqrt( common.M2projectile ) << " "
1706 << common.Mtarget + std::sqrt( common.M2projectile ) << G4endl;
1707 #endif
1708 loopCondition = ( common.SqrtS < common.Mtarget + std::sqrt( common.M2projectile ) );
1709 } else if ( interactionCase == 3 ) {
1710 #ifdef debugAdjust
1711 G4cout << "PtNucleonP " << common.PtNucleonP << " " << common.PtResidualP << G4endl
1712 << "XplusNucleon XplusResidual " << common.XplusNucleon
1713 << " " << common.XplusResidual << G4endl
1714 << "PtNucleonT " << common.PtNucleonT << " " << common.PtResidualT << G4endl
1715 << "XminusNucleon XminusResidual " << common.XminusNucleon
1716 << " " << common.XminusResidual << G4endl;
1717 #endif
1718 common.M2projectile = ( sqr( common.PNucleonMass ) + common.PtNucleonP.mag2() )
1719 / common.XplusNucleon
1720 + ( sqr( common.PResidualMass) + common.PtResidualP.mag2() )
1721 / common.XplusResidual;
1722 common.M2target = ( sqr( common.TNucleonMass ) + common.PtNucleonT.mag2() )
1723 / common.XminusNucleon
1724 + ( sqr( common.TResidualMass ) + common.PtResidualT.mag2() )
1725 / common.XminusResidual;
1726 loopCondition = ( common.SqrtS < ( std::sqrt( common.M2projectile )
1727 + std::sqrt( common.M2target ) ) );
1728 } // End-if on interactionCase
1729
1730 } while ( loopCondition && // Intermediate do while loop
1731 ++NumberOfTries < maxNumberOfTries ); /* Loop checking, 10.08.2015, A.Ribon */
1732 if ( NumberOfTries >= maxNumberOfTries ) {
1733 #ifdef debugAdjust
1734 G4cout << "BAD situation: forced exit of the intermediate while loop!" << G4endl;
1735 #endif
1736 return false;
1737 }
1738
1739 // kinematics
1740 G4double Yprojectile = 0.0, YprojectileNucleon = 0.0, Ytarget = 0.0, YtargetNucleon = 0.0;
1741 G4double DecayMomentum2 = sqr( common.S ) + sqr( common.M2projectile ) + sqr( common.M2target )
1742 - 2.0 * ( common.S * ( common.M2projectile + common.M2target )
1743 + common.M2projectile * common.M2target );
1744 if ( interactionCase == 1 ) {
1745 common.WminusTarget = ( common.S - common.M2projectile + common.M2target
1746 + std::sqrt( DecayMomentum2 ) ) / 2.0 / common.SqrtS;
1747 common.WplusProjectile = common.SqrtS - common.M2target / common.WminusTarget;
1748 common.Pzprojectile = common.WplusProjectile / 2.0
1749 - common.M2projectile / 2.0 / common.WplusProjectile;
1750 common.Eprojectile = common.WplusProjectile / 2.0
1751 + common.M2projectile / 2.0 / common.WplusProjectile;
1752 Yprojectile = 0.5 * G4Log( ( common.Eprojectile + common.Pzprojectile )
1753 / ( common.Eprojectile - common.Pzprojectile ) );
1754 #ifdef debugAdjust
1755 G4cout << "DecayMomentum2 " << DecayMomentum2 << G4endl
1756 << "WminusTarget WplusProjectile " << common.WminusTarget
1757 << " " << common.WplusProjectile << G4endl
1758 << "Yprojectile " << Yprojectile << G4endl;
1759 #endif
1760 common.Mt2targetNucleon = sqr( common.TNucleonMass ) + common.PtNucleon.mag2();
1761 common.PztargetNucleon = - common.WminusTarget * common.XminusNucleon / 2.0
1762 + common.Mt2targetNucleon
1763 / ( 2.0 * common.WminusTarget * common.XminusNucleon );
1764 common.EtargetNucleon = common.WminusTarget * common.XminusNucleon / 2.0
1765 + common.Mt2targetNucleon
1766 / ( 2.0 * common.WminusTarget * common.XminusNucleon );
1767 YtargetNucleon = 0.5 * G4Log( ( common.EtargetNucleon + common.PztargetNucleon )
1768 / ( common.EtargetNucleon - common.PztargetNucleon ) );
1769 #ifdef debugAdjust
1770 G4cout << "YtN Ytr YtN-Ytr " << " " << YtargetNucleon << " " << common.YtargetNucleus
1771 << " " << YtargetNucleon - common.YtargetNucleus << G4endl
1772 << "YtN Ypr YtN-Ypr " << " " << YtargetNucleon << " " << Yprojectile
1773 << " " << YtargetNucleon - Yprojectile << G4endl;
1774 #endif
1775 if ( std::abs( YtargetNucleon - common.YtargetNucleus ) > 2 ||
1776 Yprojectile < YtargetNucleon ) {
1777 OuterSuccess = false;
1778 continue;
1779 }
1780 } else if ( interactionCase == 2 ) {
1781 common.WplusProjectile = ( common.S + common.M2projectile - common.M2target
1782 + std::sqrt( DecayMomentum2 ) ) / 2.0 / common.SqrtS;
1783 common.WminusTarget = common.SqrtS - common.M2projectile / common.WplusProjectile;
1784 common.Pztarget = - common.WminusTarget / 2.0 + common.M2target / 2.0 / common.WminusTarget;
1785 common.Etarget = common.WminusTarget / 2.0 + common.M2target / 2.0 / common.WminusTarget;
1786 Ytarget = 0.5 * G4Log( ( common.Etarget + common.Pztarget )
1787 / ( common.Etarget - common.Pztarget ) );
1788 #ifdef debugAdjust
1789 G4cout << "DecayMomentum2 " << DecayMomentum2 << G4endl
1790 << "WminusTarget WplusProjectile " << common.WminusTarget
1791 << " " << common.WplusProjectile << G4endl
1792 << "Ytarget " << Ytarget << G4endl;
1793 #endif
1794 common.Mt2projectileNucleon = sqr( common.TNucleonMass ) + common.PtNucleon.mag2();
1795 common.PzprojectileNucleon = common.WplusProjectile * common.XplusNucleon / 2.0
1796 - common.Mt2projectileNucleon
1797 / ( 2.0 * common.WplusProjectile * common.XplusNucleon );
1798 common.EprojectileNucleon = common.WplusProjectile * common.XplusNucleon / 2.0
1799 + common.Mt2projectileNucleon
1800 / ( 2.0 * common.WplusProjectile * common.XplusNucleon );
1801 YprojectileNucleon = 0.5 * G4Log( ( common.EprojectileNucleon + common.PzprojectileNucleon )
1802 / ( common.EprojectileNucleon - common.PzprojectileNucleon) );
1803 #ifdef debugAdjust
1804 G4cout << "YpN Ypr YpN-Ypr " << " " << YprojectileNucleon << " " << common.YprojectileNucleus
1805 << " " << YprojectileNucleon - common.YprojectileNucleus << G4endl
1806 << "YpN Ytr YpN-Ytr " << " " << YprojectileNucleon << " " << Ytarget
1807 << " " << YprojectileNucleon - Ytarget << G4endl;
1808 #endif
1809 if ( std::abs( YprojectileNucleon - common.YprojectileNucleus ) > 2 ||
1810 Ytarget > YprojectileNucleon ) {
1811 OuterSuccess = false;
1812 continue;
1813 }
1814 } else if ( interactionCase == 3 ) {
1815 common.WplusProjectile = ( common.S + common.M2projectile - common.M2target
1816 + std::sqrt( DecayMomentum2 ) ) / 2.0 / common.SqrtS;
1817 common.WminusTarget = common.SqrtS - common.M2projectile / common.WplusProjectile;
1818 common.Mt2projectileNucleon = sqr( common.PNucleonMass ) + common.PtNucleonP.mag2();
1819 common.PzprojectileNucleon = common.WplusProjectile * common.XplusNucleon / 2.0
1820 - common.Mt2projectileNucleon
1821 / ( 2.0 * common.WplusProjectile * common.XplusNucleon );
1822 common.EprojectileNucleon = common.WplusProjectile * common.XplusNucleon / 2.0
1823 + common.Mt2projectileNucleon
1824 / ( 2.0 * common.WplusProjectile * common.XplusNucleon );
1825 YprojectileNucleon = 0.5 * G4Log( ( common.EprojectileNucleon + common.PzprojectileNucleon )
1826 / ( common.EprojectileNucleon - common.PzprojectileNucleon ) );
1827 common.Mt2targetNucleon = sqr( common.TNucleonMass ) + common.PtNucleonT.mag2();
1828 common.PztargetNucleon = - common.WminusTarget * common.XminusNucleon / 2.0
1829 + common.Mt2targetNucleon
1830 / ( 2.0 * common.WminusTarget * common.XminusNucleon );
1831 common.EtargetNucleon = common.WminusTarget * common.XminusNucleon / 2.0
1832 + common.Mt2targetNucleon
1833 / ( 2.0 * common.WminusTarget * common.XminusNucleon );
1834 YtargetNucleon = 0.5 * G4Log( ( common.EtargetNucleon + common.PztargetNucleon )
1835 / ( common.EtargetNucleon - common.PztargetNucleon ) );
1836 if ( std::abs( YtargetNucleon - common.YtargetNucleus ) > 2 ||
1837 std::abs( YprojectileNucleon - common.YprojectileNucleus ) > 2 ||
1838 YprojectileNucleon < YtargetNucleon ) {
1839 OuterSuccess = false;
1840 continue;
1841 }
1842 } // End-if on interactionCase
1843
1844 } while ( ( ! OuterSuccess ) && // Outmost do while loop
1845 ++loopCounter < maxNumberOfLoops ); /* Loop checking, 10.08.2015, A.Ribon */
1846 if ( loopCounter >= maxNumberOfLoops ) {
1847 #ifdef debugAdjust
1848 G4cout << "BAD situation: forced exit of the while loop!" << G4endl;
1849 #endif
1850 return false;
1851 }
1852
1853 return true;
1854}
1855
1856//-------------------------------------------------------------------
1857
1858void G4FTFModel::AdjustNucleonsAlgorithm_afterSampling( G4int interactionCase,
1859 G4VSplitableHadron* SelectedAntiBaryon,
1860 G4VSplitableHadron* SelectedTargetNucleon,
1861 G4FTFModel::CommonVariables& common ) {
1862 // Third of the three utility methods used only by AdjustNucleons: do the final kinematics
1863 // and transform back.
1864
1865 // New projectile
1866 if ( interactionCase == 1 ) {
1867 common.Pprojectile.setPz( common.Pzprojectile );
1868 common.Pprojectile.setE( common.Eprojectile );
1869 } else if ( interactionCase == 2 ) {
1870 common.Pprojectile.setPx( common.PtNucleon.x() );
1871 common.Pprojectile.setPy( common.PtNucleon.y() );
1872 common.Pprojectile.setPz( common.PzprojectileNucleon );
1873 common.Pprojectile.setE( common.EprojectileNucleon );
1874 } else if ( interactionCase == 3 ) {
1875 common.Pprojectile.setPx( common.PtNucleonP.x() );
1876 common.Pprojectile.setPy( common.PtNucleonP.y() );
1877 common.Pprojectile.setPz( common.PzprojectileNucleon );
1878 common.Pprojectile.setE( common.EprojectileNucleon );
1879 }
1880 #ifdef debugAdjust
1881 G4cout << "Proj after in CMS " << common.Pprojectile << G4endl;
1882 #endif
1883 common.Pprojectile.transform( common.toLab );
1884 SelectedAntiBaryon->Set4Momentum( common.Pprojectile );
1885 #ifdef debugAdjust
1886 G4cout << "Proj after in Lab " << common.Pprojectile << G4endl;
1887 #endif
1888
1889 // New target nucleon
1890 if ( interactionCase == 1 ) {
1891 common.Ptarget.setPx( common.PtNucleon.x() );
1892 common.Ptarget.setPy( common.PtNucleon.y() );
1893 common.Ptarget.setPz( common.PztargetNucleon );
1894 common.Ptarget.setE( common.EtargetNucleon );
1895 } else if ( interactionCase == 2 ) {
1896 common.Ptarget.setPz( common.Pztarget );
1897 common.Ptarget.setE( common.Etarget );
1898 } else if ( interactionCase == 3 ) {
1899 common.Ptarget.setPx( common.PtNucleonT.x() );
1900 common.Ptarget.setPy( common.PtNucleonT.y() );
1901 common.Ptarget.setPz( common.PztargetNucleon );
1902 common.Ptarget.setE( common.EtargetNucleon );
1903 }
1904 #ifdef debugAdjust
1905 G4cout << "Targ after in CMS " << common.Ptarget << G4endl;
1906 #endif
1907 common.Ptarget.transform( common.toLab );
1908 SelectedTargetNucleon->Set4Momentum( common.Ptarget );
1909 #ifdef debugAdjust
1910 G4cout << "Targ after in Lab " << common.Ptarget << G4endl;
1911 #endif
1912
1913 // New target residual
1914 if ( interactionCase == 1 || interactionCase == 3 ) {
1915 TargetResidualMassNumber = common.TResidualMassNumber;
1916 TargetResidualCharge = common.TResidualCharge;
1917 TargetResidualExcitationEnergy = common.TResidualExcitationEnergy;
1918 #ifdef debugAdjust
1919 G4cout << "TargetResidualMassNumber TargetResidualCharge TargetResidualExcitationEnergy "
1920 << TargetResidualMassNumber << " " << TargetResidualCharge << " "
1921 << TargetResidualExcitationEnergy << G4endl;
1922 #endif
1923 if ( TargetResidualMassNumber != 0 ) {
1924 G4double Mt2 = 0.0;
1925 if ( interactionCase == 1 ) {
1926 Mt2 = sqr( common.TResidualMass ) + common.PtResidual.mag2();
1927 TargetResidual4Momentum.setPx( common.PtResidual.x() );
1928 TargetResidual4Momentum.setPy( common.PtResidual.y() );
1929 } else { // interactionCase == 3
1930 Mt2 = sqr( common.TResidualMass ) + common.PtResidualT.mag2();
1931 TargetResidual4Momentum.setPx( common.PtResidualT.x() );
1932 TargetResidual4Momentum.setPy( common.PtResidualT.y() );
1933 }
1934 G4double Pz = - common.WminusTarget * common.XminusResidual / 2.0
1935 + Mt2 / ( 2.0 * common.WminusTarget * common.XminusResidual );
1936 G4double E = common.WminusTarget * common.XminusResidual / 2.0
1937 + Mt2 / ( 2.0 * common.WminusTarget * common.XminusResidual );
1938 TargetResidual4Momentum.setPz( Pz );
1939 TargetResidual4Momentum.setE( E ) ;
1940 TargetResidual4Momentum.transform( common.toLab );
1941 } else {
1942 TargetResidual4Momentum = G4LorentzVector( 0.0, 0.0, 0.0, 0.0 );
1943 }
1944 #ifdef debugAdjust
1945 G4cout << "Tr N R " << common.Ptarget << G4endl << " " << TargetResidual4Momentum << G4endl;
1946 #endif
1947 }
1948
1949 // New projectile residual
1950 if ( interactionCase == 2 || interactionCase == 3 ) {
1951 if ( interactionCase == 2 ) {
1952 ProjectileResidualMassNumber = common.TResidualMassNumber;
1953 ProjectileResidualCharge = common.TResidualCharge;
1954 ProjectileResidualExcitationEnergy = common.TResidualExcitationEnergy;
1955 ProjectileResidualLambdaNumber = common.PResidualLambdaNumber;
1956 } else { // interactionCase == 3
1957 ProjectileResidualMassNumber = common.PResidualMassNumber;
1958 ProjectileResidualCharge = common.PResidualCharge;
1959 ProjectileResidualExcitationEnergy = common.PResidualExcitationEnergy;
1960 ProjectileResidualLambdaNumber = common.PResidualLambdaNumber;
1961 }
1962 #ifdef debugAdjust
1963 G4cout << "ProjectileResidualMassNumber ProjectileResidualCharge Lambdas ProjectileResidualExcitationEnergy "
1964 << ProjectileResidualMassNumber << " " << ProjectileResidualCharge << " "
1965 << ProjectileResidualLambdaNumber << " "
1966 << ProjectileResidualExcitationEnergy << G4endl;
1967 #endif
1968 if ( ProjectileResidualMassNumber != 0 ) {
1969 G4double Mt2 = 0.0;
1970 if ( interactionCase == 2 ) {
1971 Mt2 = sqr( common.TResidualMass ) + common.PtResidual.mag2();
1972 ProjectileResidual4Momentum.setPx( common.PtResidual.x() );
1973 ProjectileResidual4Momentum.setPy( common.PtResidual.y() );
1974 } else { // interactionCase == 3
1975 Mt2 = sqr( common.PResidualMass ) + common.PtResidualP.mag2();
1976 ProjectileResidual4Momentum.setPx( common.PtResidualP.x() );
1977 ProjectileResidual4Momentum.setPy( common.PtResidualP.y() );
1978 }
1979 G4double Pz = common.WplusProjectile * common.XplusResidual / 2.0
1980 - Mt2 / ( 2.0 * common.WplusProjectile * common.XplusResidual );
1981 G4double E = common.WplusProjectile * common.XplusResidual / 2.0
1982 + Mt2 / ( 2.0 * common.WplusProjectile * common.XplusResidual );
1983 ProjectileResidual4Momentum.setPz( Pz );
1984 ProjectileResidual4Momentum.setE( E );
1985 ProjectileResidual4Momentum.transform( common.toLab );
1986 } else {
1987 ProjectileResidual4Momentum = G4LorentzVector( 0.0, 0.0, 0.0, 0.0 );
1988 }
1989 #ifdef debugAdjust
1990 G4cout << "Pr N R " << common.Pprojectile << G4endl
1991 << " " << ProjectileResidual4Momentum << G4endl;
1992 #endif
1993 }
1994
1995}
1996
1997
1998//============================================================================
1999
2000void G4FTFModel::BuildStrings( G4ExcitedStringVector* strings ) {
2001 // Loop over all collisions; find all primaries, and all targets
2002 // (targets may be duplicate in the List (to unique G4VSplitableHadrons) ).
2003
2004 G4ExcitedString* FirstString( 0 ); // If there will be a kink,
2005 G4ExcitedString* SecondString( 0 ); // two strings will be produced.
2006
2007 if ( ! GetProjectileNucleus() ) {
2008
2009 std::vector< G4VSplitableHadron* > primaries;
2010 theParticipants.StartLoop();
2011 while ( theParticipants.Next() ) { /* Loop checking, 10.08.2015, A.Ribon */
2012 const G4InteractionContent& interaction = theParticipants.GetInteraction();
2013 // do not allow for duplicates ...
2014 if ( interaction.GetStatus() ) {
2015 if ( primaries.end() == std::find( primaries.begin(), primaries.end(),
2016 interaction.GetProjectile() ) ) {
2017 primaries.push_back( interaction.GetProjectile() );
2018 }
2019 }
2020 }
2021
2022 #ifdef debugBuildString
2023 G4cout << "G4FTFModel::BuildStrings()" << G4endl
2024 << "Number of projectile strings " << primaries.size() << G4endl;
2025 #endif
2026
2027 for ( unsigned int ahadron = 0; ahadron < primaries.size(); ahadron++ ) {
2028 G4bool isProjectile( true );
2029 //G4cout << "primaries[ ahadron ] " << primaries[ ahadron ] << G4endl;
2030 //if ( primaries[ ahadron ]->GetStatus() <= 1 ) isProjectile = true;
2031 FirstString = 0; SecondString = 0;
2032 if ( primaries[ahadron]->GetStatus() == 0 ) {
2033 theExcitation->CreateStrings( primaries[ ahadron ], isProjectile,
2034 FirstString, SecondString, theParameters );
2035 NumberOfProjectileSpectatorNucleons--;
2036 } else if ( primaries[ahadron]->GetStatus() == 1
2037 && primaries[ahadron]->GetSoftCollisionCount() != 0 ) {
2038 theExcitation->CreateStrings( primaries[ ahadron ], isProjectile,
2039 FirstString, SecondString, theParameters );
2040 NumberOfProjectileSpectatorNucleons--;
2041 } else if ( primaries[ahadron]->GetStatus() == 1
2042 && primaries[ahadron]->GetSoftCollisionCount() == 0 ) {
2043 G4LorentzVector ParticleMomentum=primaries[ahadron]->Get4Momentum();
2044 G4KineticTrack* aTrack = new G4KineticTrack( primaries[ahadron]->GetDefinition(),
2045 primaries[ahadron]->GetTimeOfCreation(),
2046 primaries[ahadron]->GetPosition(),
2047 ParticleMomentum );
2048 FirstString = new G4ExcitedString( aTrack );
2049 } else if (primaries[ahadron]->GetStatus() == 2) {
2050 G4LorentzVector ParticleMomentum=primaries[ahadron]->Get4Momentum();
2051 G4KineticTrack* aTrack = new G4KineticTrack( primaries[ahadron]->GetDefinition(),
2052 primaries[ahadron]->GetTimeOfCreation(),
2053 primaries[ahadron]->GetPosition(),
2054 ParticleMomentum );
2055 FirstString = new G4ExcitedString( aTrack );
2056 NumberOfProjectileSpectatorNucleons--;
2057 } else {
2058 G4cout << "Something wrong in FTF Model Build String" << G4endl;
2059 }
2060
2061 if ( FirstString != 0 ) strings->push_back( FirstString );
2062 if ( SecondString != 0 ) strings->push_back( SecondString );
2063
2064 #ifdef debugBuildString
2065 G4cout << "FirstString & SecondString? " << FirstString << " " << SecondString << G4endl;
2066 if ( FirstString->IsExcited() ) {
2067 G4cout << "Quarks on the FirstString ends " << FirstString->GetRightParton()->GetPDGcode()
2068 << " " << FirstString->GetLeftParton()->GetPDGcode() << G4endl;
2069 } else {
2070 G4cout << "Kinetic track is stored" << G4endl;
2071 }
2072 #endif
2073
2074 }
2075
2076 #ifdef debugBuildString
2077 if ( FirstString->IsExcited() ) {
2078 G4cout << "Check 1 string " << strings->operator[](0)->GetRightParton()->GetPDGcode()
2079 << " " << strings->operator[](0)->GetLeftParton()->GetPDGcode() << G4endl << G4endl;
2080 }
2081 #endif
2082
2083 std::for_each( primaries.begin(), primaries.end(), DeleteVSplitableHadron() );
2084 primaries.clear();
2085
2086 } else { // Projectile is a nucleus
2087
2088 #ifdef debugBuildString
2089 G4cout << "Building of projectile-like strings" << G4endl;
2090 #endif
2091
2092 G4bool isProjectile = true;
2093 for ( G4int ahadron = 0; ahadron < NumberOfInvolvedNucleonsOfProjectile; ahadron++ ) {
2094
2095 #ifdef debugBuildString
2096 G4cout << "Nucleon #, status, intCount " << ahadron << " "
2097 << TheInvolvedNucleonsOfProjectile[ ahadron ]->GetSplitableHadron()->GetStatus()
2098 << " " << TheInvolvedNucleonsOfProjectile[ ahadron ]->GetSplitableHadron()
2100 #endif
2101
2102 G4VSplitableHadron* aProjectile =
2103 TheInvolvedNucleonsOfProjectile[ ahadron ]->GetSplitableHadron();
2104
2105 #ifdef debugBuildString
2106 G4cout << G4endl << "ahadron aProjectile Status " << ahadron << " " << aProjectile
2107 << " " << aProjectile->GetStatus() << G4endl;
2108 #endif
2109
2110 FirstString = 0; SecondString = 0;
2111 if ( aProjectile->GetStatus() == 0 ) { // A nucleon took part in non-diffractive interaction
2112
2113 #ifdef debugBuildString
2114 G4cout << "Case1 aProjectile->GetStatus() == 0 " << G4endl;
2115 #endif
2116
2117 theExcitation->CreateStrings(
2118 TheInvolvedNucleonsOfProjectile[ ahadron ]->GetSplitableHadron(),
2119 isProjectile, FirstString, SecondString, theParameters );
2120 NumberOfProjectileSpectatorNucleons--;
2121 } else if ( aProjectile->GetStatus() == 1 && aProjectile->GetSoftCollisionCount() != 0 ) {
2122 // Nucleon took part in diffractive interaction
2123
2124 #ifdef debugBuildString
2125 G4cout << "Case2 aProjectile->GetStatus() !=0 St==1 SoftCol!=0" << G4endl;
2126 #endif
2127
2128 theExcitation->CreateStrings(
2129 TheInvolvedNucleonsOfProjectile[ ahadron ]->GetSplitableHadron(),
2130 isProjectile, FirstString, SecondString, theParameters );
2131 NumberOfProjectileSpectatorNucleons--;
2132 } else if ( aProjectile->GetStatus() == 1 && aProjectile->GetSoftCollisionCount() == 0 &&
2133 HighEnergyInter ) {
2134 // Nucleon was considered as a paricipant of an interaction,
2135 // but the interaction was skipped due to annihilation.
2136 // It is now considered as an involved nucleon at high energies.
2137
2138 #ifdef debugBuildString
2139 G4cout << "Case3 aProjectile->GetStatus() !=0 St==1 SoftCol==0" << G4endl;
2140 #endif
2141
2142 G4LorentzVector ParticleMomentum = aProjectile->Get4Momentum();
2143 G4KineticTrack* aTrack = new G4KineticTrack( aProjectile->GetDefinition(),
2144 aProjectile->GetTimeOfCreation(),
2145 aProjectile->GetPosition(),
2146 ParticleMomentum );
2147 FirstString = new G4ExcitedString( aTrack );
2148
2149 #ifdef debugBuildString
2150 G4cout << " Strings are built for nucleon marked for an interaction, but"
2151 << " the interaction was skipped." << G4endl;
2152 #endif
2153
2154 } else if ( aProjectile->GetStatus() == 2 || aProjectile->GetStatus() == 3 ) {
2155 // Nucleon which was involved in the Reggeon cascading
2156
2157 #ifdef debugBuildString
2158 G4cout << "Case4 aProjectile->GetStatus() !=0 St==2 " << G4endl;
2159 #endif
2160
2161 G4LorentzVector ParticleMomentum = aProjectile->Get4Momentum();
2162 G4KineticTrack* aTrack = new G4KineticTrack( aProjectile->GetDefinition(),
2163 aProjectile->GetTimeOfCreation(),
2164 aProjectile->GetPosition(),
2165 ParticleMomentum );
2166 FirstString = new G4ExcitedString( aTrack );
2167
2168 #ifdef debugBuildString
2169 G4cout << " Strings are build for involved nucleon." << G4endl;
2170 #endif
2171
2172 if ( aProjectile->GetStatus() == 2 ) NumberOfProjectileSpectatorNucleons--;
2173 } else {
2174
2175 #ifdef debugBuildString
2176 G4cout << "Case5 " << G4endl;
2177 #endif
2178
2179 //TheInvolvedNucleonsOfProjectile[ ahadron ]->Hit( 0 );
2180 //G4cout << TheInvolvedNucleonsOfProjectile[ ahadron ]->GetSplitableHadron() << G4endl;
2181
2182 #ifdef debugBuildString
2183 G4cout << " No string" << G4endl;
2184 #endif
2185
2186 }
2187
2188 if ( FirstString != 0 ) strings->push_back( FirstString );
2189 if ( SecondString != 0 ) strings->push_back( SecondString );
2190 }
2191 }
2192
2193 #ifdef debugBuildString
2194 G4cout << "Building of target-like strings" << G4endl;
2195 #endif
2196
2197 G4bool isProjectile = false;
2198 for ( G4int ahadron = 0; ahadron < NumberOfInvolvedNucleonsOfTarget; ahadron++ ) {
2199 G4VSplitableHadron* aNucleon = TheInvolvedNucleonsOfTarget[ ahadron ]->GetSplitableHadron();
2200
2201 #ifdef debugBuildString
2202 G4cout << "Nucleon #, status, intCount " << aNucleon << " " << ahadron << " "
2203 << aNucleon->GetStatus() << " " << aNucleon->GetSoftCollisionCount()<<G4endl;;
2204 #endif
2205
2206 FirstString = 0 ; SecondString = 0;
2207
2208 if ( aNucleon->GetStatus() == 0 ) { // A nucleon took part in non-diffractive interaction
2209 theExcitation->CreateStrings( aNucleon, isProjectile,
2210 FirstString, SecondString, theParameters );
2211 NumberOfTargetSpectatorNucleons--;
2212
2213 #ifdef debugBuildString
2214 G4cout << " 1 case A string is build" << G4endl;
2215 #endif
2216
2217 } else if ( aNucleon->GetStatus() == 1 && aNucleon->GetSoftCollisionCount() != 0 ) {
2218 // A nucleon took part in diffractive interaction
2219 theExcitation->CreateStrings( aNucleon, isProjectile,
2220 FirstString, SecondString, theParameters );
2221
2222 #ifdef debugBuildString
2223 G4cout << " 2 case A string is build, nucleon was excited." << G4endl;
2224 #endif
2225
2226 NumberOfTargetSpectatorNucleons--;
2227
2228 } else if ( aNucleon->GetStatus() == 1 && aNucleon->GetSoftCollisionCount() == 0 &&
2229 HighEnergyInter ) {
2230 // A nucleon was considered as a participant but due to annihilation
2231 // its interactions were skipped. It will be considered as involved one
2232 // at high energies.
2233
2234 G4LorentzVector ParticleMomentum = aNucleon->Get4Momentum();
2235 G4KineticTrack* aTrack = new G4KineticTrack( aNucleon->GetDefinition(),
2236 aNucleon->GetTimeOfCreation(),
2237 aNucleon->GetPosition(),
2238 ParticleMomentum );
2239
2240 FirstString = new G4ExcitedString( aTrack );
2241
2242 #ifdef debugBuildString
2243 G4cout << "3 case A string is build" << G4endl;
2244 #endif
2245
2246 } else if ( aNucleon->GetStatus() == 1 && aNucleon->GetSoftCollisionCount() == 0 &&
2247 ! HighEnergyInter ) {
2248 // A nucleon was considered as a participant but due to annihilation
2249 // its interactions were skipped. It will be returned to nucleus
2250 // at low energies energies.
2251 aNucleon->SetStatus( 5 ); // 4->5
2252 // ??? delete aNucleon;
2253
2254 #ifdef debugBuildString
2255 G4cout << "4 case A string is not build" << G4endl;
2256 #endif
2257
2258 } else if ( aNucleon->GetStatus() == 2 || // A nucleon took part in quark exchange
2259 aNucleon->GetStatus() == 3 ) { // A nucleon was involved in Reggeon cascading
2260 G4LorentzVector ParticleMomentum = aNucleon->Get4Momentum();
2261 G4KineticTrack* aTrack = new G4KineticTrack( aNucleon->GetDefinition(),
2262 aNucleon->GetTimeOfCreation(),
2263 aNucleon->GetPosition(),
2264 ParticleMomentum );
2265 FirstString = new G4ExcitedString( aTrack );
2266
2267 #ifdef debugBuildString
2268 G4cout << "5 case A string is build" << G4endl;
2269 #endif
2270
2271 if ( aNucleon->GetStatus() == 2 ) NumberOfTargetSpectatorNucleons--;
2272
2273 } else {
2274
2275 #ifdef debugBuildString
2276 G4cout << "6 case No string" << G4endl;
2277 #endif
2278
2279 }
2280
2281 if ( FirstString != 0 ) strings->push_back( FirstString );
2282 if ( SecondString != 0 ) strings->push_back( SecondString );
2283
2284 }
2285
2286 #ifdef debugBuildString
2287 G4cout << G4endl << "theAdditionalString.size() " << theAdditionalString.size()
2288 << G4endl << G4endl;
2289 #endif
2290
2291 isProjectile = true;
2292 if ( theAdditionalString.size() != 0 ) {
2293 for ( unsigned int ahadron = 0; ahadron < theAdditionalString.size(); ahadron++ ) {
2294 //if ( theAdditionalString[ ahadron ]->GetStatus() <= 1 ) isProjectile = true;
2295 FirstString = 0; SecondString = 0;
2296 theExcitation->CreateStrings( theAdditionalString[ ahadron ], isProjectile,
2297 FirstString, SecondString, theParameters );
2298 if ( FirstString != 0 ) strings->push_back( FirstString );
2299 if ( SecondString != 0 ) strings->push_back( SecondString );
2300 }
2301 }
2302
2303 //for ( unsigned int ahadron = 0; ahadron < strings->size(); ahadron++ ) {
2304 // G4cout << ahadron << " " << strings->operator[]( ahadron )->GetRightParton()->GetPDGcode()
2305 // << " " << strings->operator[]( ahadron )->GetLeftParton()->GetPDGcode() << G4endl;
2306 //}
2307 //G4cout << "------------------------" << G4endl;
2308
2309 return;
2310}
2311
2312
2313//============================================================================
2314
2315void G4FTFModel::GetResiduals() {
2316 // This method is needed for the correct application of G4PrecompoundModelInterface
2317
2318 #ifdef debugFTFmodel
2319 G4cout << "GetResiduals(): HighEnergyInter? GetProjectileNucleus()?"
2320 << HighEnergyInter << " " << GetProjectileNucleus() << G4endl;
2321 #endif
2322
2323 if ( HighEnergyInter ) {
2324
2325 #ifdef debugFTFmodel
2326 G4cout << "NumberOfInvolvedNucleonsOfTarget "<< NumberOfInvolvedNucleonsOfTarget << G4endl;
2327 #endif
2328
2329 G4double DeltaExcitationE = TargetResidualExcitationEnergy /
2330 G4double( NumberOfInvolvedNucleonsOfTarget );
2331 G4LorentzVector DeltaPResidualNucleus = TargetResidual4Momentum /
2332 G4double( NumberOfInvolvedNucleonsOfTarget );
2333
2334 for ( G4int i = 0; i < NumberOfInvolvedNucleonsOfTarget; ++i ) {
2335 G4Nucleon* aNucleon = TheInvolvedNucleonsOfTarget[i];
2336
2337 #ifdef debugFTFmodel
2338 G4VSplitableHadron* targetSplitable = aNucleon->GetSplitableHadron();
2339 G4cout << i << " Hit? " << aNucleon->AreYouHit() << " pointer " << targetSplitable << G4endl;
2340 if ( targetSplitable ) G4cout << i << "Status " << targetSplitable->GetStatus() << G4endl;
2341 #endif
2342
2343 G4LorentzVector tmp = -DeltaPResidualNucleus;
2344 aNucleon->SetMomentum( tmp );
2345 aNucleon->SetBindingEnergy( DeltaExcitationE );
2346 }
2347
2348 if ( TargetResidualMassNumber != 0 ) {
2349 G4ThreeVector bstToCM = TargetResidual4Momentum.findBoostToCM();
2350
2351 G4V3DNucleus* theTargetNucleus = GetTargetNucleus();
2352 G4LorentzVector residualMomentum( 0.0, 0.0, 0.0, 0.0 );
2353 G4Nucleon* aNucleon = 0;
2354 theTargetNucleus->StartLoop();
2355 while ( ( aNucleon = theTargetNucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
2356 if ( ! aNucleon->AreYouHit() ) {
2357 G4LorentzVector tmp = aNucleon->Get4Momentum(); tmp.boost( bstToCM );
2358 aNucleon->SetMomentum( tmp );
2359 residualMomentum += tmp;
2360 }
2361 }
2362
2363 residualMomentum /= TargetResidualMassNumber;
2364
2365 G4double Mass = TargetResidual4Momentum.mag();
2366 G4double SumMasses = 0.0;
2367
2368 aNucleon = 0;
2369 theTargetNucleus->StartLoop();
2370 while ( ( aNucleon = theTargetNucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
2371 if ( ! aNucleon->AreYouHit() ) {
2372 G4LorentzVector tmp = aNucleon->Get4Momentum() - residualMomentum;
2373 G4double E = std::sqrt( tmp.vect().mag2() +
2374 sqr( aNucleon->GetDefinition()->GetPDGMass() - aNucleon->GetBindingEnergy() ) );
2375 tmp.setE( E ); aNucleon->SetMomentum( tmp );
2376 SumMasses += E;
2377 }
2378 }
2379
2380 G4double Chigh = Mass / SumMasses; G4double Clow = 0.0; G4double C;
2381 const G4int maxNumberOfLoops = 1000;
2382 G4int loopCounter = 0;
2383 do {
2384 C = ( Chigh + Clow ) / 2.0;
2385 SumMasses = 0.0;
2386 aNucleon = 0;
2387 theTargetNucleus->StartLoop();
2388 while ( ( aNucleon = theTargetNucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
2389 if ( ! aNucleon->AreYouHit() ) {
2390 G4LorentzVector tmp = aNucleon->Get4Momentum();
2391 G4double E = std::sqrt( tmp.vect().mag2()*sqr(C) +
2392 sqr( aNucleon->GetDefinition()->GetPDGMass() - aNucleon->GetBindingEnergy() ) );
2393 SumMasses += E;
2394 }
2395 }
2396
2397 if ( SumMasses > Mass ) Chigh = C;
2398 else Clow = C;
2399
2400 } while ( Chigh - Clow > 0.01 &&
2401 ++loopCounter < maxNumberOfLoops ); /* Loop checking, 10.08.2015, A.Ribon */
2402 if ( loopCounter >= maxNumberOfLoops ) {
2403 #ifdef debugFTFmodel
2404 G4cout << "BAD situation: forced exit of the first while loop in G4FTFModel::GetResidual" << G4endl
2405 << "\t return immediately from the method!" << G4endl;
2406 #endif
2407 return;
2408 }
2409
2410 aNucleon = 0;
2411 theTargetNucleus->StartLoop();
2412 while ( ( aNucleon = theTargetNucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
2413 if ( !aNucleon->AreYouHit() ) {
2414 G4LorentzVector tmp = aNucleon->Get4Momentum()*C;
2415 G4double E = std::sqrt( tmp.vect().mag2()+
2416 sqr( aNucleon->GetDefinition()->GetPDGMass()-aNucleon->GetBindingEnergy() ) );
2417 tmp.setE( E ); tmp.boost( -bstToCM );
2418 aNucleon->SetMomentum( tmp );
2419 }
2420 }
2421 }
2422
2423 if ( ! GetProjectileNucleus() ) return; // The projectile is a hadron
2424
2425 #ifdef debugFTFmodel
2426 G4cout << "NumberOfInvolvedNucleonsOfProjectile " << NumberOfInvolvedNucleonsOfProjectile
2427 << G4endl << "ProjectileResidualExcitationEnergy ProjectileResidual4Momentum "
2428 << ProjectileResidualExcitationEnergy << " " << ProjectileResidual4Momentum << G4endl;
2429 #endif
2430
2431 DeltaExcitationE = ProjectileResidualExcitationEnergy /
2432 G4double( NumberOfInvolvedNucleonsOfProjectile );
2433 DeltaPResidualNucleus = ProjectileResidual4Momentum /
2434 G4double( NumberOfInvolvedNucleonsOfProjectile );
2435
2436 for ( G4int i = 0; i < NumberOfInvolvedNucleonsOfProjectile; ++i ) {
2437 G4Nucleon* aNucleon = TheInvolvedNucleonsOfProjectile[i];
2438
2439 #ifdef debugFTFmodel
2440 G4VSplitableHadron* projSplitable = aNucleon->GetSplitableHadron();
2441 G4cout << i << " Hit? " << aNucleon->AreYouHit() << " pointer " << projSplitable << G4endl;
2442 if ( projSplitable ) G4cout << i << "Status " << projSplitable->GetStatus() << G4endl;
2443 #endif
2444
2445 G4LorentzVector tmp = -DeltaPResidualNucleus;
2446 aNucleon->SetMomentum( tmp );
2447 aNucleon->SetBindingEnergy( DeltaExcitationE );
2448 }
2449
2450 if ( ProjectileResidualMassNumber != 0 ) {
2451 G4ThreeVector bstToCM = ProjectileResidual4Momentum.findBoostToCM();
2452
2453 G4V3DNucleus* theProjectileNucleus = GetProjectileNucleus();
2454 G4LorentzVector residualMomentum( 0.0, 0.0, 0.0, 0.0);
2455 G4Nucleon* aNucleon = 0;
2456 theProjectileNucleus->StartLoop();
2457 while ( ( aNucleon = theProjectileNucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
2458 if ( ! aNucleon->AreYouHit() ) {
2459 G4LorentzVector tmp = aNucleon->Get4Momentum(); tmp.boost( bstToCM );
2460 aNucleon->SetMomentum( tmp );
2461 residualMomentum += tmp;
2462 }
2463 }
2464
2465 residualMomentum /= ProjectileResidualMassNumber;
2466
2467 G4double Mass = ProjectileResidual4Momentum.mag();
2468 G4double SumMasses= 0.0;
2469
2470 aNucleon = 0;
2471 theProjectileNucleus->StartLoop();
2472 while ( ( aNucleon = theProjectileNucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
2473 if ( ! aNucleon->AreYouHit() ) {
2474 G4LorentzVector tmp = aNucleon->Get4Momentum() - residualMomentum;
2475 G4double E=std::sqrt( tmp.vect().mag2() +
2476 sqr(aNucleon->GetDefinition()->GetPDGMass()-aNucleon->GetBindingEnergy() ) );
2477 tmp.setE( E ); aNucleon->SetMomentum( tmp );
2478 SumMasses += E;
2479 }
2480 }
2481
2482 G4double Chigh = Mass / SumMasses; G4double Clow = 0.0; G4double C;
2483 const G4int maxNumberOfLoops = 1000;
2484 G4int loopCounter = 0;
2485 do {
2486 C = ( Chigh + Clow ) / 2.0;
2487
2488 SumMasses = 0.0;
2489 aNucleon = 0;
2490 theProjectileNucleus->StartLoop();
2491 while ( ( aNucleon = theProjectileNucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
2492 if ( ! aNucleon->AreYouHit() ) {
2493 G4LorentzVector tmp = aNucleon->Get4Momentum();
2494 G4double E = std::sqrt( tmp.vect().mag2()*sqr(C) +
2495 sqr( aNucleon->GetDefinition()->GetPDGMass() - aNucleon->GetBindingEnergy() ) );
2496 SumMasses += E;
2497 }
2498 }
2499
2500 if ( SumMasses > Mass) Chigh = C;
2501 else Clow = C;
2502
2503 } while ( Chigh - Clow > 0.01 &&
2504 ++loopCounter < maxNumberOfLoops ); /* Loop checking, 10.08.2015, A.Ribon */
2505 if ( loopCounter >= maxNumberOfLoops ) {
2506 #ifdef debugFTFmodel
2507 G4cout << "BAD situation: forced exit of the second while loop in G4FTFModel::GetResidual" << G4endl
2508 << "\t return immediately from the method!" << G4endl;
2509 #endif
2510 return;
2511 }
2512
2513 aNucleon = 0;
2514 theProjectileNucleus->StartLoop();
2515 while ( ( aNucleon = theProjectileNucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
2516 if ( ! aNucleon->AreYouHit() ) {
2517 G4LorentzVector tmp = aNucleon->Get4Momentum()*C;
2518 G4double E = std::sqrt( tmp.vect().mag2() +
2519 sqr( aNucleon->GetDefinition()->GetPDGMass() - aNucleon->GetBindingEnergy() ) );
2520 tmp.setE( E ); tmp.boost( -bstToCM );
2521 aNucleon->SetMomentum( tmp );
2522 }
2523 }
2524 } // End of if ( ProjectileResidualMassNumber != 0 )
2525
2526 #ifdef debugFTFmodel
2527 G4cout << "End projectile" << G4endl;
2528 #endif
2529
2530 } else { // Related to the condition: if ( HighEnergyInter )
2531
2532 #ifdef debugFTFmodel
2533 G4cout << "Low energy interaction: Target nucleus --------------" << G4endl
2534 << "Tr ResidualMassNumber Tr ResidualCharge Tr ResidualExcitationEnergy "
2535 << TargetResidualMassNumber << " " << TargetResidualCharge << " "
2536 << TargetResidualExcitationEnergy << G4endl;
2537 #endif
2538
2539 G4int NumberOfTargetParticipant( 0 );
2540 for ( G4int i = 0; i < NumberOfInvolvedNucleonsOfTarget; ++i ) {
2541 G4Nucleon* aNucleon = TheInvolvedNucleonsOfTarget[i];
2542 G4VSplitableHadron* targetSplitable = aNucleon->GetSplitableHadron();
2543 if ( targetSplitable->GetSoftCollisionCount() != 0 ) NumberOfTargetParticipant++;
2544 }
2545
2546 G4double DeltaExcitationE( 0.0 );
2547 G4LorentzVector DeltaPResidualNucleus = G4LorentzVector( 0.0, 0.0, 0.0, 0.0 );
2548
2549 if ( NumberOfTargetParticipant != 0 ) {
2550 DeltaExcitationE = TargetResidualExcitationEnergy / G4double( NumberOfTargetParticipant );
2551 DeltaPResidualNucleus = TargetResidual4Momentum / G4double( NumberOfTargetParticipant );
2552 }
2553
2554 for ( G4int i = 0; i < NumberOfInvolvedNucleonsOfTarget; ++i ) {
2555 G4Nucleon* aNucleon = TheInvolvedNucleonsOfTarget[i];
2556 G4VSplitableHadron* targetSplitable = aNucleon->GetSplitableHadron();
2557 if ( targetSplitable->GetSoftCollisionCount() != 0 ) {
2558 G4LorentzVector tmp = -DeltaPResidualNucleus;
2559 aNucleon->SetMomentum( tmp );
2560 aNucleon->SetBindingEnergy( DeltaExcitationE );
2561 } else {
2562 delete targetSplitable;
2563 targetSplitable = 0;
2564 aNucleon->Hit( targetSplitable );
2565 aNucleon->SetBindingEnergy( 0.0 );
2566 }
2567 }
2568
2569 #ifdef debugFTFmodel
2570 G4cout << "NumberOfTargetParticipant " << NumberOfTargetParticipant << G4endl
2571 << "TargetResidual4Momentum " << TargetResidual4Momentum << G4endl;
2572 #endif
2573
2574 if ( ! GetProjectileNucleus() ) return; // The projectile is a hadron
2575
2576 #ifdef debugFTFmodel
2577 G4cout << "Low energy interaction: Projectile nucleus --------------" << G4endl
2578 << "Pr ResidualMassNumber Pr ResidualCharge Pr ResidualExcitationEnergy "
2579 << ProjectileResidualMassNumber << " " << ProjectileResidualCharge << " "
2580 << ProjectileResidualExcitationEnergy << G4endl;
2581 #endif
2582
2583 G4int NumberOfProjectileParticipant( 0 );
2584 for ( G4int i = 0; i < NumberOfInvolvedNucleonsOfProjectile; ++i ) {
2585 G4Nucleon* aNucleon = TheInvolvedNucleonsOfProjectile[i];
2586 G4VSplitableHadron* projectileSplitable = aNucleon->GetSplitableHadron();
2587 if ( projectileSplitable->GetSoftCollisionCount() != 0 ) NumberOfProjectileParticipant++;
2588 }
2589
2590 #ifdef debugFTFmodel
2591 G4cout << "NumberOfProjectileParticipant" << G4endl;
2592 #endif
2593
2594 DeltaExcitationE = 0.0;
2595 DeltaPResidualNucleus = G4LorentzVector( 0.0, 0.0, 0.0, 0.0 );
2596
2597 if ( NumberOfProjectileParticipant != 0 ) {
2598 DeltaExcitationE = ProjectileResidualExcitationEnergy / G4double( NumberOfProjectileParticipant );
2599 DeltaPResidualNucleus = ProjectileResidual4Momentum / G4double( NumberOfProjectileParticipant );
2600 }
2601 //G4cout << "DeltaExcitationE DeltaPResidualNucleus " << DeltaExcitationE
2602 // << " " << DeltaPResidualNucleus << G4endl;
2603 for ( G4int i = 0; i < NumberOfInvolvedNucleonsOfProjectile; ++i ) {
2604 G4Nucleon* aNucleon = TheInvolvedNucleonsOfProjectile[i];
2605 G4VSplitableHadron* projectileSplitable = aNucleon->GetSplitableHadron();
2606 if ( projectileSplitable->GetSoftCollisionCount() != 0 ) {
2607 G4LorentzVector tmp = -DeltaPResidualNucleus;
2608 aNucleon->SetMomentum( tmp );
2609 aNucleon->SetBindingEnergy( DeltaExcitationE );
2610 } else {
2611 delete projectileSplitable;
2612 projectileSplitable = 0;
2613 aNucleon->Hit( projectileSplitable );
2614 aNucleon->SetBindingEnergy( 0.0 );
2615 }
2616 }
2617
2618 #ifdef debugFTFmodel
2619 G4cout << "NumberOfProjectileParticipant " << NumberOfProjectileParticipant << G4endl
2620 << "ProjectileResidual4Momentum " << ProjectileResidual4Momentum << G4endl;
2621 #endif
2622
2623 } // End of the condition: if ( HighEnergyInter )
2624
2625 #ifdef debugFTFmodel
2626 G4cout << "End GetResiduals -----------------" << G4endl;
2627 #endif
2628
2629}
2630
2631
2632//============================================================================
2633
2634G4ThreeVector G4FTFModel::GaussianPt( G4double AveragePt2, G4double maxPtSquare ) const {
2635
2636 G4double Pt2( 0.0 ), Pt( 0.0 );
2637
2638 if (AveragePt2 > 0.0) {
2639 const G4double ymax = maxPtSquare/AveragePt2;
2640 if ( ymax < 200. ) {
2641 Pt2 = -AveragePt2 * G4Log( 1.0 + G4UniformRand() * ( G4Exp( -ymax ) -1.0 ) );
2642 } else {
2643 Pt2 = -AveragePt2 * G4Log( 1.0 - G4UniformRand() );
2644 }
2645 Pt = std::sqrt( Pt2 );
2646 }
2647
2648 G4double phi = G4UniformRand() * twopi;
2649
2650 return G4ThreeVector( Pt*std::cos(phi), Pt*std::sin(phi), 0.0 );
2651}
2652
2653//============================================================================
2654
2655G4bool G4FTFModel::
2656ComputeNucleusProperties( G4V3DNucleus* nucleus, // input parameter
2657 G4LorentzVector& nucleusMomentum, // input & output parameter
2658 G4LorentzVector& residualMomentum, // input & output parameter
2659 G4double& sumMasses, // input & output parameter
2660 G4double& residualExcitationEnergy, // input & output parameter
2661 G4double& residualMass, // input & output parameter
2662 G4int& residualMassNumber, // input & output parameter
2663 G4int& residualCharge ) { // input & output parameter
2664
2665 // This method, which is called only by PutOnMassShell, computes some nucleus properties for:
2666 // - either the target nucleus (which is never an antinucleus): this for any kind
2667 // of hadronic interaction (hadron-nucleus, nucleus-nucleus, antinucleus-nucleus);
2668 // - or the projectile nucleus or antinucleus: this only in the case of nucleus-nucleus
2669 // or antinucleus-nucleus interaction.
2670 // This method assumes that the all the parameters have been initialized by the caller;
2671 // the action of this method consists in modifying all these parameters, except the
2672 // first one. The return value is "false" only in the case the pointer to the nucleus
2673 // is null.
2674
2675 if ( ! nucleus ) return false;
2676
2677 G4double ExcitationEnergyPerWoundedNucleon =
2678 theParameters->GetExcitationEnergyPerWoundedNucleon();
2679
2680 // Loop over the nucleons of the nucleus.
2681 // The nucleons that have been involved in the interaction (either from Glauber or
2682 // Reggeon Cascading) will be candidate to be emitted.
2683 // All the remaining nucleons will be the nucleons of the candidate residual nucleus.
2684 // The variable sumMasses is the amount of energy corresponding to:
2685 // 1. transverse mass of each involved nucleon
2686 // 2. 20.0*MeV separation energy for each involved nucleon
2687 // 3. transverse mass of the residual nucleus
2688 // In this first evaluation of sumMasses, the excitation energy of the residual nucleus
2689 // (residualExcitationEnergy, estimated by adding a constant value to each involved
2690 // nucleon) is not taken into account.
2691 G4int residualNumberOfLambdas = 0; // Projectile nucleus and its residual can be a hypernucleus
2692 G4Nucleon* aNucleon = 0;
2693 nucleus->StartLoop();
2694 while ( ( aNucleon = nucleus->GetNextNucleon() ) ) { /* Loop checking, 10.08.2015, A.Ribon */
2695 nucleusMomentum += aNucleon->Get4Momentum();
2696 if ( aNucleon->AreYouHit() ) { // Involved nucleons
2697 // Consider in sumMasses the nominal, i.e. on-shell, masses of the nucleons
2698 // (not the current masses, which could be different because the nucleons are off-shell).
2699 sumMasses += std::sqrt( sqr( aNucleon->GetDefinition()->GetPDGMass() )
2700 + aNucleon->Get4Momentum().perp2() );
2701 sumMasses += 20.0*MeV; // Separation energy for a nucleon
2702
2703 //residualExcitationEnergy += ExcitationEnergyPerWoundedNucleon; // In G4 10.1
2704 residualExcitationEnergy += -ExcitationEnergyPerWoundedNucleon*G4Log( G4UniformRand() );
2705
2706 residualMassNumber--;
2707 // The absolute value below is needed only in the case of anti-nucleus.
2708 residualCharge -= std::abs( G4int( aNucleon->GetDefinition()->GetPDGCharge() ) );
2709 } else { // Spectator nucleons
2710 residualMomentum += aNucleon->Get4Momentum();
2711 if ( aNucleon->GetDefinition() == G4Lambda::Definition() ||
2712 aNucleon->GetDefinition() == G4AntiLambda::Definition() ) {
2713 ++residualNumberOfLambdas;
2714 }
2715 }
2716 }
2717 #ifdef debugPutOnMassShell
2718 G4cout << "ExcitationEnergyPerWoundedNucleon " << ExcitationEnergyPerWoundedNucleon << G4endl
2719 << "\t Residual Charge, MassNumber (Number of Lambdas)" << residualCharge << " "
2720 << residualMassNumber << " (" << residualNumberOfLambdas << ") "
2721 << G4endl << "\t Initial Momentum " << nucleusMomentum
2722 << G4endl << "\t Residual Momentum " << residualMomentum << G4endl;
2723 #endif
2724 residualMomentum.setPz( 0.0 );
2725 residualMomentum.setE( 0.0 );
2726 if ( residualMassNumber == 0 ) {
2727 residualMass = 0.0;
2728 residualExcitationEnergy = 0.0;
2729 } else {
2730 if ( residualMassNumber == 1 ) {
2731 if ( std::abs( residualCharge ) == 1 ) {
2732 residualMass = G4Proton::Definition()->GetPDGMass();
2733 } else if ( residualNumberOfLambdas == 1 ) {
2734 residualMass = G4Lambda::Definition()->GetPDGMass();
2735 } else {
2736 residualMass = G4Neutron::Definition()->GetPDGMass();
2737 }
2738 residualExcitationEnergy = 0.0;
2739 } else {
2740 if ( residualNumberOfLambdas > 0 ) {
2741 if ( residualMassNumber == 2 ) {
2742 residualMass = G4Lambda::Definition()->GetPDGMass();
2743 if ( std::abs( residualCharge ) == 1 ) { // lambda + proton
2744 residualMass += G4Proton::Definition()->GetPDGMass();
2745 } else if ( residualNumberOfLambdas == 1 ) { // lambda + neutron
2746 residualMass += G4Neutron::Definition()->GetPDGMass();
2747 } else { // lambda + lambda
2748 residualMass += G4Lambda::Definition()->GetPDGMass();
2749 }
2750 } else {
2751 residualMass = G4HyperNucleiProperties::GetNuclearMass( residualMassNumber, std::abs( residualCharge ),
2752 residualNumberOfLambdas );
2753 }
2754 } else {
2756 GetIonMass( std::abs( residualCharge ), residualMassNumber );
2757 }
2758 }
2759 residualMass += residualExcitationEnergy;
2760 }
2761 sumMasses += std::sqrt( sqr( residualMass ) + residualMomentum.perp2() );
2762 return true;
2763}
2764
2765
2766//============================================================================
2767
2768G4bool G4FTFModel::
2769GenerateDeltaIsobar( const G4double sqrtS, // input parameter
2770 const G4int numberOfInvolvedNucleons, // input parameter
2771 G4Nucleon* involvedNucleons[], // input & output parameter
2772 G4double& sumMasses ) { // input & output parameter
2773
2774 // This method, which is called only by PutOnMassShell, check whether is possible to
2775 // re-interpret some of the involved nucleons as delta-isobars:
2776 // - either by replacing a proton (2212) with a Delta+ (2214),
2777 // - or by replacing a neutron (2112) with a Delta0 (2114).
2778 // The on-shell mass of these delta-isobars is ~1232 MeV, so ~292-294 MeV heavier than
2779 // the corresponding nucleon on-shell mass. However 400.0*MeV is considered to estimate
2780 // the max number of deltas compatible with the available energy.
2781 // The delta-isobars are considered with the same transverse momentum as their
2782 // corresponding nucleons.
2783 // This method assumes that all the parameters have been initialized by the caller;
2784 // the action of this method consists in modifying (eventually) involveNucleons and
2785 // sumMasses. The return value is "false" only in the case that the input parameters
2786 // have unphysical values.
2787
2788 if ( sqrtS < 0.0 || numberOfInvolvedNucleons <= 0 || sumMasses < 0.0 ) return false;
2789
2790 const G4double probDeltaIsobar = 0.05;
2791
2792 G4int maxNumberOfDeltas = G4int( (sqrtS - sumMasses)/(400.0*MeV) );
2793 G4int numberOfDeltas = 0;
2794
2795 for ( G4int i = 0; i < numberOfInvolvedNucleons; ++i ) {
2796
2797 if ( G4UniformRand() < probDeltaIsobar && numberOfDeltas < maxNumberOfDeltas ) {
2798 numberOfDeltas++;
2799 if ( ! involvedNucleons[i] ) continue;
2800 // Skip any eventual lambda (that can be present in a projectile hypernucleus)
2801 if ( involvedNucleons[i]->GetDefinition() == G4Lambda::Definition() ||
2802 involvedNucleons[i]->GetDefinition() == G4AntiLambda::Definition() ) continue;
2803 G4VSplitableHadron* splitableHadron = involvedNucleons[i]->GetSplitableHadron();
2804 G4double massNuc = std::sqrt( sqr( splitableHadron->GetDefinition()->GetPDGMass() )
2805 + splitableHadron->Get4Momentum().perp2() );
2806 // The absolute value below is needed in the case of an antinucleus.
2807 G4int pdgCode = std::abs( splitableHadron->GetDefinition()->GetPDGEncoding() );
2808 const G4ParticleDefinition* old_def = splitableHadron->GetDefinition();
2809 G4int newPdgCode = pdgCode/10; newPdgCode = newPdgCode*10 + 4; // Delta
2810 if ( splitableHadron->GetDefinition()->GetPDGEncoding() < 0 ) newPdgCode *= -1;
2811 const G4ParticleDefinition* ptr =
2813 splitableHadron->SetDefinition( ptr );
2814 G4double massDelta = std::sqrt( sqr( splitableHadron->GetDefinition()->GetPDGMass() )
2815 + splitableHadron->Get4Momentum().perp2() );
2816 //G4cout << i << " " << sqrtS/GeV << " " << sumMasses/GeV << " " << massDelta/GeV
2817 // << " " << massNuc << G4endl;
2818 if ( sqrtS < sumMasses + massDelta - massNuc ) { // Change cannot be accepted!
2819 splitableHadron->SetDefinition( old_def );
2820 break;
2821 } else { // Change is accepted
2822 sumMasses += ( massDelta - massNuc );
2823 }
2824 }
2825 }
2826
2827 return true;
2828}
2829
2830
2831//============================================================================
2832
2833G4bool G4FTFModel::
2834SamplingNucleonKinematics( G4double averagePt2, // input parameter
2835 const G4double maxPt2, // input parameter
2836 G4double dCor, // input parameter
2837 G4V3DNucleus* nucleus, // input parameter
2838 const G4LorentzVector& pResidual, // input parameter
2839 const G4double residualMass, // input parameter
2840 const G4int residualMassNumber, // input parameter
2841 const G4int numberOfInvolvedNucleons, // input parameter
2842 G4Nucleon* involvedNucleons[], // input & output parameter
2843 G4double& mass2 ) { // output parameter
2844
2845 // This method, which is called only by PutOnMassShell, does the sampling of:
2846 // - either the target nucleons: this for any kind of hadronic interactions
2847 // (hadron-nucleus, nucleus-nucleus, antinucleus-nucleus);
2848 // - or the projectile nucleons or antinucleons: this only in the case of
2849 // nucleus-nucleus or antinucleus-nucleus interactions, respectively.
2850 // This method assumes that all the parameters have been initialized by the caller;
2851 // the action of this method consists in changing the properties of the nucleons
2852 // whose pointers are in the vector involvedNucleons, as well as changing the
2853 // variable mass2.
2854#ifdef debugPutOnMassShell
2855 G4cout << "G4FTFModel::SamplingNucleonKinematics:" << G4endl;
2856 G4cout << " averagePt2= " << averagePt2 << " maxPt2= " << maxPt2
2857 << " dCor= " << dCor << " resMass(GeV)= " << residualMass/GeV
2858 << " resMassN= " << residualMassNumber
2859 << " nNuc= " << numberOfInvolvedNucleons
2860 << " lv= " << pResidual << G4endl;
2861#endif
2862
2863 if ( ! nucleus || numberOfInvolvedNucleons < 1 ) return false;
2864
2865 if ( residualMassNumber == 0 && numberOfInvolvedNucleons == 1 ) {
2866 dCor = 0.0;
2867 averagePt2 = 0.0;
2868 }
2869
2870 G4bool success = true;
2871
2872 G4double SumMasses = residualMass;
2873 G4double invN = 1.0 / (G4double)numberOfInvolvedNucleons;
2874
2875 // to avoid problems due to precision lost a tolerance is added
2876 const G4double eps = 1.e-10;
2877 const G4int maxNumberOfLoops = 1000;
2878 G4int loopCounter = 0;
2879 do {
2880
2881 success = true;
2882
2883 // Sampling of nucleon Pt
2884 G4ThreeVector ptSum( 0.0, 0.0, 0.0 );
2885 if( averagePt2 > 0.0 ) {
2886 for ( G4int i = 0; i < numberOfInvolvedNucleons; ++i ) {
2887 G4Nucleon* aNucleon = involvedNucleons[i];
2888 if ( ! aNucleon ) continue;
2889 G4ThreeVector tmpPt = GaussianPt( averagePt2, maxPt2 );
2890 ptSum += tmpPt;
2891 G4LorentzVector tmp( tmpPt.x(), tmpPt.y(), 0.0, 0.0 );
2892 aNucleon->SetMomentum( tmp );
2893 }
2894 }
2895
2896 G4double deltaPx = ( ptSum.x() - pResidual.x() )*invN;
2897 G4double deltaPy = ( ptSum.y() - pResidual.y() )*invN;
2898
2899 SumMasses = residualMass;
2900 for ( G4int i = 0; i < numberOfInvolvedNucleons; ++i ) {
2901 G4Nucleon* aNucleon = involvedNucleons[i];
2902 if ( ! aNucleon ) continue;
2903 G4double px = aNucleon->Get4Momentum().px() - deltaPx;
2904 G4double py = aNucleon->Get4Momentum().py() - deltaPy;
2905 G4double MtN = std::sqrt( sqr( aNucleon->GetSplitableHadron()->GetDefinition()->GetPDGMass() )
2906 + sqr( px ) + sqr( py ) );
2907 SumMasses += MtN;
2908 G4LorentzVector tmp( px, py, 0.0, MtN);
2909 aNucleon->SetMomentum( tmp );
2910 }
2911
2912 // Sampling X of nucleon
2913 G4double xSum = 0.0;
2914
2915 for ( G4int i = 0; i < numberOfInvolvedNucleons; ++i ) {
2916 G4Nucleon* aNucleon = involvedNucleons[i];
2917 if ( ! aNucleon ) continue;
2918
2919 G4double x = 0.0;
2920 if( 0.0 != dCor ) {
2921 G4ThreeVector tmpX = GaussianPt( dCor*dCor, 1.0 );
2922 x = tmpX.x();
2923 }
2924 x += aNucleon->Get4Momentum().e()/SumMasses;
2925 if ( x < -eps || x > 1.0 + eps ) {
2926 success = false;
2927 break;
2928 }
2929 x = std::min(1.0, std::max(x, 0.0));
2930 xSum += x;
2931 // The energy is in the lab (instead of cms) frame but it will not be used
2932
2933 G4LorentzVector tmp( aNucleon->Get4Momentum().x(),
2934 aNucleon->Get4Momentum().y(),
2935 x, aNucleon->Get4Momentum().e() );
2936 aNucleon->SetMomentum( tmp );
2937 }
2938
2939 if ( xSum < -eps || xSum > 1.0 + eps ) success = false;
2940 if ( ! success ) continue;
2941
2942 G4double delta = ( residualMassNumber == 0 ) ? std::min( xSum - 1.0, 0.0 )*invN : 0.0;
2943
2944 xSum = 1.0;
2945 mass2 = 0.0;
2946 for ( G4int i = 0; i < numberOfInvolvedNucleons; ++i ) {
2947 G4Nucleon* aNucleon = involvedNucleons[i];
2948 if ( ! aNucleon ) continue;
2949 G4double x = aNucleon->Get4Momentum().pz() - delta;
2950 xSum -= x;
2951
2952 if ( residualMassNumber == 0 ) {
2953 if ( x <= -eps || x > 1.0 + eps ) {
2954 success = false;
2955 break;
2956 }
2957 } else {
2958 if ( x <= -eps || x > 1.0 + eps || xSum <= -eps || xSum > 1.0 + eps ) {
2959 success = false;
2960 break;
2961 }
2962 }
2963 x = std::min( 1.0, std::max(x, eps) );
2964
2965 mass2 += sqr( aNucleon->Get4Momentum().e() ) / x;
2966
2967 G4LorentzVector tmp( aNucleon->Get4Momentum().px(), aNucleon->Get4Momentum().py(),
2968 x, aNucleon->Get4Momentum().e() );
2969 aNucleon->SetMomentum( tmp );
2970 }
2971 if ( ! success ) continue;
2972 xSum = std::min( 1.0, std::max(xSum, eps) );
2973
2974 if ( residualMassNumber > 0 ) mass2 += ( sqr( residualMass ) + pResidual.perp2() ) / xSum;
2975
2976 #ifdef debugPutOnMassShell
2977 G4cout << "success: " << success << " Mt(GeV)= "
2978 << std::sqrt( mass2 )/GeV << G4endl;
2979 #endif
2980
2981 } while ( ( ! success ) &&
2982 ++loopCounter < maxNumberOfLoops ); /* Loop checking, 10.08.2015, A.Ribon */
2983 return ( loopCounter < maxNumberOfLoops );
2984}
2985
2986
2987//============================================================================
2988
2989G4bool G4FTFModel::
2990CheckKinematics( const G4double sValue, // input parameter
2991 const G4double sqrtS, // input parameter
2992 const G4double projectileMass2, // input parameter
2993 const G4double targetMass2, // input parameter
2994 const G4double nucleusY, // input parameter
2995 const G4bool isProjectileNucleus, // input parameter
2996 const G4int numberOfInvolvedNucleons, // input parameter
2997 G4Nucleon* involvedNucleons[], // input parameter
2998 G4double& targetWminus, // output parameter
2999 G4double& projectileWplus, // output parameter
3000 G4bool& success ) { // input & output parameter
3001
3002 // This method, which is called only by PutOnMassShell, checks whether the
3003 // kinematics is acceptable or not.
3004 // This method assumes that all the parameters have been initialized by the caller;
3005 // notice that the input boolean parameter isProjectileNucleus is meant to be true
3006 // only in the case of nucleus or antinucleus projectile.
3007 // The action of this method consists in computing targetWminus and projectileWplus
3008 // and setting the parameter success to false in the case that the kinematics should
3009 // be rejeted.
3010
3011 G4double decayMomentum2 = sqr( sValue ) + sqr( projectileMass2 ) + sqr( targetMass2 )
3012 - 2.0*( sValue*( projectileMass2 + targetMass2 )
3013 + projectileMass2*targetMass2 );
3014 targetWminus = ( sValue - projectileMass2 + targetMass2 + std::sqrt( decayMomentum2 ) )
3015 / 2.0 / sqrtS;
3016 projectileWplus = sqrtS - targetMass2/targetWminus;
3017 G4double projectilePz = projectileWplus/2.0 - projectileMass2/2.0/projectileWplus;
3018 G4double projectileE = projectileWplus/2.0 + projectileMass2/2.0/projectileWplus;
3019 G4double projectileY = 0.5 * G4Log( (projectileE + projectilePz)/
3020 (projectileE - projectilePz) );
3021 G4double targetPz = -targetWminus/2.0 + targetMass2/2.0/targetWminus;
3022 G4double targetE = targetWminus/2.0 + targetMass2/2.0/targetWminus;
3023 G4double targetY = 0.5 * G4Log( (targetE + targetPz)/(targetE - targetPz) );
3024
3025 #ifdef debugPutOnMassShell
3026 G4cout << "decayMomentum2 " << decayMomentum2 << G4endl
3027 << "\t targetWminus projectileWplus " << targetWminus << " " << projectileWplus << G4endl
3028 << "\t projectileY targetY " << projectileY << " " << targetY << G4endl;
3029 if ( isProjectileNucleus ) {
3030 G4cout << "Order# of Wounded nucleon i, nucleon Y proj Y nuclY - proj Y " << G4endl;
3031 } else {
3032 G4cout << "Order# of Wounded nucleon i, nucleon Y targ Y nuclY - targ Y " << G4endl;
3033 }
3034 G4cout << G4endl;
3035 #endif
3036
3037 for ( G4int i = 0; i < numberOfInvolvedNucleons; ++i ) {
3038 G4Nucleon* aNucleon = involvedNucleons[i];
3039 if ( ! aNucleon ) continue;
3040 G4LorentzVector tmp = aNucleon->Get4Momentum();
3041 G4double mt2 = sqr( tmp.x() ) + sqr( tmp.y() ) +
3042 sqr( aNucleon->GetSplitableHadron()->GetDefinition()->GetPDGMass() );
3043 G4double x = tmp.z();
3044 G4double pz = -targetWminus*x/2.0 + mt2/(2.0*targetWminus*x);
3045 G4double e = targetWminus*x/2.0 + mt2/(2.0*targetWminus*x);
3046 if ( isProjectileNucleus ) {
3047 pz = projectileWplus*x/2.0 - mt2/(2.0*projectileWplus*x);
3048 e = projectileWplus*x/2.0 + mt2/(2.0*projectileWplus*x);
3049 }
3050 G4double nucleonY = 0.5 * G4Log( (e + pz)/(e - pz) );
3051
3052 #ifdef debugPutOnMassShell
3053 if( isProjectileNucleus ) {
3054 G4cout << " " << i << " " << nucleonY << " " << projectileY << " " <<nucleonY - projectileY << G4endl;
3055 } else {
3056 G4cout << " " << i << " " << nucleonY << " " << targetY << " " <<nucleonY - targetY << G4endl;
3057 }
3058 G4cout << G4endl;
3059 #endif
3060
3061 if ( std::abs( nucleonY - nucleusY ) > 2 ||
3062 ( isProjectileNucleus && targetY > nucleonY ) ||
3063 ( ! isProjectileNucleus && projectileY < nucleonY ) ) {
3064 success = false;
3065 break;
3066 }
3067 }
3068 return true;
3069}
3070
3071
3072//============================================================================
3073
3074G4bool G4FTFModel::
3075FinalizeKinematics( const G4double w, // input parameter
3076 const G4bool isProjectileNucleus, // input parameter
3077 const G4LorentzRotation& boostFromCmsToLab, // input parameter
3078 const G4double residualMass, // input parameter
3079 const G4int residualMassNumber, // input parameter
3080 const G4int numberOfInvolvedNucleons, // input parameter
3081 G4Nucleon* involvedNucleons[], // input & output parameter
3082 G4LorentzVector& residual4Momentum ) { // output parameter
3083
3084 // This method, which is called only by PutOnMassShell, finalizes the kinematics:
3085 // this method is called when we are sure that the sampling of the kinematics is
3086 // acceptable.
3087 // This method assumes that all the parameters have been initialized by the caller;
3088 // notice that the input boolean parameter isProjectileNucleus is meant to be true
3089 // only in the case of nucleus or antinucleus projectile: this information is needed
3090 // because the sign of pz (in the center-of-mass frame) in this case is opposite
3091 // with respect to the case of a normal hadron projectile.
3092 // The action of this method consists in modifying the momenta of the nucleons
3093 // (in the lab frame) and computing the residual 4-momentum (in the center-of-mass
3094 // frame).
3095
3096 G4ThreeVector residual3Momentum( 0.0, 0.0, 1.0 );
3097
3098 for ( G4int i = 0; i < numberOfInvolvedNucleons; ++i ) {
3099 G4Nucleon* aNucleon = involvedNucleons[i];
3100 if ( ! aNucleon ) continue;
3101 G4LorentzVector tmp = aNucleon->Get4Momentum();
3102 residual3Momentum -= tmp.vect();
3103 G4double mt2 = sqr( tmp.x() ) + sqr( tmp.y() ) +
3104 sqr( aNucleon->GetSplitableHadron()->GetDefinition()->GetPDGMass() );
3105 G4double x = tmp.z();
3106 G4double pz = -w * x / 2.0 + mt2 / ( 2.0 * w * x );
3107 G4double e = w * x / 2.0 + mt2 / ( 2.0 * w * x );
3108 // Reverse the sign of pz in the case of nucleus or antinucleus projectile
3109 if ( isProjectileNucleus ) pz *= -1.0;
3110 tmp.setPz( pz );
3111 tmp.setE( e );
3112 tmp.transform( boostFromCmsToLab );
3113 aNucleon->SetMomentum( tmp );
3114 G4VSplitableHadron* splitableHadron = aNucleon->GetSplitableHadron();
3115 splitableHadron->Set4Momentum( tmp );
3116 }
3117
3118 G4double residualMt2 = sqr( residualMass ) + sqr( residual3Momentum.x() )
3119 + sqr( residual3Momentum.y() );
3120
3121 #ifdef debugPutOnMassShell
3122 if ( isProjectileNucleus ) {
3123 G4cout << "Wminus Proj and residual3Momentum.z() " << w << " " << residual3Momentum.z() << G4endl;
3124 } else {
3125 G4cout << "Wplus Targ and residual3Momentum.z() " << w << " " << residual3Momentum.z() << G4endl;
3126 }
3127 #endif
3128
3129 G4double residualPz = 0.0;
3130 G4double residualE = 0.0;
3131 if ( residualMassNumber != 0 ) {
3132 residualPz = -w * residual3Momentum.z() / 2.0 +
3133 residualMt2 / ( 2.0 * w * residual3Momentum.z() );
3134 residualE = w * residual3Momentum.z() / 2.0 +
3135 residualMt2 / ( 2.0 * w * residual3Momentum.z() );
3136 // Reverse the sign of residualPz in the case of nucleus or antinucleus projectile
3137 if ( isProjectileNucleus ) residualPz *= -1.0;
3138 }
3139
3140 residual4Momentum.setPx( residual3Momentum.x() );
3141 residual4Momentum.setPy( residual3Momentum.y() );
3142 residual4Momentum.setPz( residualPz );
3143 residual4Momentum.setE( residualE );
3144
3145 return true;
3146}
3147
3148
3149//============================================================================
3150
3151void G4FTFModel::ModelDescription( std::ostream& desc ) const {
3152 desc << " FTF (Fritiof) Model \n"
3153 << "The FTF model is based on the well-known FRITIOF \n"
3154 << "model (B. Andersson et al., Nucl. Phys. B281, 289 \n"
3155 << "(1987)). Its first program implementation was given\n"
3156 << "by B. Nilsson-Almquist and E. Stenlund (Comp. Phys.\n"
3157 << "Comm. 43, 387 (1987)). The Fritiof model assumes \n"
3158 << "that all hadron-hadron interactions are binary \n"
3159 << "reactions, h_1+h_2->h_1'+h_2' where h_1' and h_2' \n"
3160 << "are excited states of the hadrons with continuous \n"
3161 << "mass spectra. The excited hadrons are considered as\n"
3162 << "QCD-strings, and the corresponding LUND-string \n"
3163 << "fragmentation model is applied for a simulation of \n"
3164 << "their decays. \n"
3165 << " The Fritiof model assumes that in the course of \n"
3166 << "a hadron-nucleus interaction a string originated \n"
3167 << "from the projectile can interact with various intra\n"
3168 << "nuclear nucleons and becomes into highly excited \n"
3169 << "states. The probability of multiple interactions is\n"
3170 << "calculated in the Glauber approximation. A cascading\n"
3171 << "of secondary particles was neglected as a rule. Due\n"
3172 << "to these, the original Fritiof model fails to des- \n"
3173 << "cribe a nuclear destruction and slow particle spectra.\n"
3174 << " In order to overcome the difficulties we enlarge\n"
3175 << "the model by the reggeon theory inspired model of \n"
3176 << "nuclear desctruction (Kh. Abdel-Waged and V.V. Uzhi-\n"
3177 << "nsky, Phys. Atom. Nucl. 60, 828 (1997); Yad. Fiz. 60, 925\n"
3178 << "(1997)). Momenta of the nucleons ejected from a nuc-\n"
3179 << "leus in the reggeon cascading are sampled according\n"
3180 << "to a Fermi motion algorithm presented in (EMU-01 \n"
3181 << "Collaboration (M.I. Adamovich et al.) Zeit. fur Phys.\n"
3182 << "A358, 337 (1997)). \n"
3183 << " New features were also added to the Fritiof model\n"
3184 << "implemented in Geant4: a simulation of elastic had-\n"
3185 << "ron-nucleon scatterings, a simulation of binary \n"
3186 << "reactions like NN>NN* in hadron-nucleon interactions,\n"
3187 << "a separate simulation of single diffractive and non-\n"
3188 << " diffractive events. These allowed to describe after\n"
3189 << "model parameter tuning a wide set of experimental \n"
3190 << "data. \n";
3191}
3192
G4double C(G4double temp)
G4double S(G4double temp)
G4double condition(const G4ErrorSymMatrix &m)
std::vector< G4ExcitedString * > G4ExcitedStringVector
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition G4Exp.hh:180
G4double G4Log(G4double x)
Definition G4Log.hh:227
CLHEP::HepLorentzRotation G4LorentzRotation
CLHEP::HepLorentzVector G4LorentzVector
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition Randomize.hh:52
double z() const
double x() const
double mag2() const
double y() const
HepLorentzRotation & rotateY(double delta)
HepLorentzRotation & rotateZ(double delta)
HepLorentzRotation inverse() const
double theta() const
Hep3Vector boostVector() const
HepLorentzVector & boost(double, double, double)
Hep3Vector vect() const
double perp2() const
void setVect(const Hep3Vector &)
Hep3Vector findBoostToCM() const
HepLorentzVector & transform(const HepRotation &)
static G4AntiLambda * Definition()
static G4AntiNeutron * Definition()
static G4AntiProton * Definition()
virtual G4bool ExciteParticipants(G4VSplitableHadron *aPartner, G4VSplitableHadron *bPartner, G4FTFParameters *theParameters, G4ElasticHNScattering *theElastic) const
virtual void CreateStrings(G4VSplitableHadron *aHadron, G4bool isProjectile, G4ExcitedString *&FirstString, G4ExcitedString *&SecondString, G4FTFParameters *theParameters) const
virtual G4bool ElasticScattering(G4VSplitableHadron *aPartner, G4VSplitableHadron *bPartner, G4FTFParameters *theParameters) const
virtual G4bool Annihilate(G4VSplitableHadron *aPartner, G4VSplitableHadron *bPartner, G4VSplitableHadron *&AdditionalString, G4FTFParameters *theParameters) const
G4bool SampleBinInterval() const
void SetImpactParameter(const G4double b_value)
G4V3DNucleus * GetTargetNucleus() const
G4FTFModel(const G4String &modelName="FTF")
Definition G4FTFModel.cc:70
G4ExcitedStringVector * GetStrings() override
~G4FTFModel() override
G4V3DNucleus * GetProjectileNucleus() const override
void Init(const G4Nucleus &aNucleus, const G4DynamicParticle &aProjectile) override
G4double GetBmin() const
void ModelDescription(std::ostream &) const override
G4double GetBmax() const
G4double GetCofNuclearDestructionPr()
G4double GetProbabilityOfAnnihilation()
G4double GetMaxNumberOfCollisions()
void SetProbabilityOfElasticScatt(const G4double Xtotal, const G4double Xelastic)
G4double GetPt2ofNuclearDestruction()
G4double GetMaxPt2ofNuclearDestruction()
G4double GetProbabilityOfElasticScatt()
G4double GetExcitationEnergyPerWoundedNucleon()
void InitForInteraction(const G4ParticleDefinition *, G4int theA, G4int theZ, G4double s)
G4double GetDofNuclearDestruction()
G4double GetR2ofNuclearDestruction()
G4double GetCofNuclearDestruction()
void GetList(const G4ReactionProduct &thePrimary, G4FTFParameters *theParameters)
void SetBminBmax(const G4double bmin_value, const G4double bmax_value)
G4double GetImpactParameter() const
G4InteractionContent & GetInteraction()
void SetEnergyMomentumCheckLevels(G4double relativeLevel, G4double absoluteLevel)
static G4double GetNuclearMass(G4int A, G4int Z, G4int L)
G4Nucleon * GetTargetNucleon() const
G4VSplitableHadron * GetProjectile() const
G4Nucleon * GetProjectileNucleon() const
void SetStatus(G4int aValue)
G4VSplitableHadron * GetTarget() const
G4double GetIonMass(G4int Z, G4int A, G4int nL=0, G4int lvl=0) const
static G4Lambda * Definition()
Definition G4Lambda.cc:48
static G4Neutron * Definition()
Definition G4Neutron.cc:50
const G4ThreeVector & GetPosition() const
Definition G4Nucleon.hh:140
G4bool AreYouHit() const
Definition G4Nucleon.hh:98
void SetMomentum(G4LorentzVector &aMomentum)
Definition G4Nucleon.hh:70
G4VSplitableHadron * GetSplitableHadron() const
Definition G4Nucleon.hh:97
virtual const G4LorentzVector & Get4Momentum() const
Definition G4Nucleon.hh:72
void Hit(G4VSplitableHadron *aHit)
Definition G4Nucleon.hh:91
G4double GetBindingEnergy() const
Definition G4Nucleon.hh:75
void SetParticleType(G4Proton *aProton)
Definition G4Nucleon.hh:77
void SetBindingEnergy(G4double anEnergy)
Definition G4Nucleon.hh:74
virtual const G4ParticleDefinition * GetDefinition() const
Definition G4Nucleon.hh:86
G4int GetA_asInt() const
Definition G4Nucleus.hh:99
G4int GetZ_asInt() const
Definition G4Nucleus.hh:105
G4int GetNumberOfLambdasInHypernucleus() const
G4int GetNumberOfAntiLambdasInAntiHypernucleus() const
const G4String & GetParticleName() const
G4IonTable * GetIonTable() const
G4ParticleDefinition * FindParticle(G4int PDGEncoding)
static G4ParticleTable * GetParticleTable()
static G4Proton * Definition()
Definition G4Proton.cc:45
void SetMomentum(const G4double x, const G4double y, const G4double z)
void SetTotalEnergy(const G4double en)
G4double GetTotalMomentum() const
const G4ParticleDefinition * GetDefinition() const
G4double GetTotalEnergy() const
G4ThreeVector GetMomentum() const
G4double GetMass() const
virtual G4Nucleon * GetNextNucleon()=0
virtual G4bool StartLoop()=0
virtual void DoLorentzBoost(const G4LorentzVector &theBoost)=0
virtual void DoLorentzContraction(const G4LorentzVector &theBoost)=0
virtual G4int GetMassNumber()=0
virtual void InitProjectileNucleus(G4int theZ, G4int theA, G4int numberOfLambdasOrAntiLambdas=0)
virtual void Init(G4int theZ, G4int theA)
virtual void SetProjectileNucleus(G4V3DNucleus *aNucleus)
virtual G4V3DNucleus * GetProjectileNucleus() const
void SetTimeOfCreation(G4double aTime)
void SetStatus(const G4int aStatus)
const G4ParticleDefinition * GetDefinition() const
void Set4Momentum(const G4LorentzVector &a4Momentum)
void SetDefinition(const G4ParticleDefinition *aDefinition)
const G4LorentzVector & Get4Momentum() const
const G4ThreeVector & GetPosition() const
void operator()(G4VSplitableHadron *aH)
T sqr(const T &x)
Definition templates.hh:128