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