Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 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:57
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:52
double z() const
double x() const
double mag2() const
double y() 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()
Definition: G4AntiLambda.cc:52
static G4AntiNeutron * Definition()
static G4AntiProton * Definition()
Definition: G4AntiProton.cc:50
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
Definition: G4FTFModel.hh:240
void SetImpactParameter(const G4double b_value)
Definition: G4FTFModel.hh:224
G4V3DNucleus * GetTargetNucleus() const
Definition: G4FTFModel.hh:216
G4FTFModel(const G4String &modelName="FTF")
Definition: G4FTFModel.cc:70
G4ExcitedStringVector * GetStrings() override
Definition: G4FTFModel.cc:298
~G4FTFModel() override
Definition: G4FTFModel.cc:122
G4V3DNucleus * GetProjectileNucleus() const override
Definition: G4FTFModel.hh:220
void Init(const G4Nucleus &aNucleus, const G4DynamicParticle &aProjectile) override
Definition: G4FTFModel.cc:162
G4double GetBmin() const
Definition: G4FTFModel.hh:244
void ModelDescription(std::ostream &) const override
Definition: G4FTFModel.cc:3151
G4double GetBmax() const
Definition: G4FTFModel.hh:248
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
Definition: G4IonTable.cc:1517
static G4Lambda * Definition()
Definition: G4Lambda.cc:52
static G4Neutron * Definition()
Definition: G4Neutron.cc:53
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
G4double GetPDGCharge() const
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:48
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)
Definition: G4FTFModel.cc:117
T sqr(const T &x)
Definition: templates.hh:128