Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4INCLInteractionAvatar.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 // INCL++ intra-nuclear cascade model
27 // Pekka Kaitaniemi, CEA and Helsinki Institute of Physics
28 // Davide Mancusi, CEA
29 // Alain Boudard, CEA
30 // Sylvie Leray, CEA
31 // Joseph Cugnon, University of Liege
32 //
33 #define INCLXX_IN_GEANT4_MODE 1
34 
35 #include "globals.hh"
36 
37 /* \file G4INCLInteractionAvatar.cc
38  * \brief Virtual class for interaction avatars.
39  *
40  * This class is inherited by decay and collision avatars. The goal is to
41  * provide a uniform treatment of common physics, such as Pauli blocking,
42  * enforcement of energy conservation, etc.
43  *
44  * \date Mar 1st, 2011
45  * \author Davide Mancusi
46  */
47 
49 #include "G4INCLKinematicsUtils.hh"
50 #include "G4INCLCrossSections.hh"
51 #include "G4INCLPauliBlocking.hh"
52 #include "G4INCLRootFinder.hh"
53 #include "G4INCLLogger.hh"
54 #include "G4INCLConfigEnums.hh"
55 // #include <cassert>
56 
57 namespace G4INCL {
58 
61 
63  : IAvatar(time), theNucleus(n),
64  particle1(p1), particle2(NULL), isPiN(false)
65  {
66  }
67 
69  G4INCL::Particle *p2)
70  : IAvatar(time), theNucleus(n),
71  particle1(p1), particle2(p2),
72  isPiN((p1->isPion() && p2->isNucleon()) || (p2->isPion() && p1->isNucleon()))
73  {
74  }
75 
77  }
78 
87 
88  if(particle2) {
99  } else {
101  }
102  }
103 
105  if(!theNucleus || p->isPion()) return; // Local energy does not make any sense without a nucleus
106 
109  }
110 
113 
115 
116  if(particle2) {
118  if(!isPiN) {
121  }
122  } else {
124  }
125  if(!isPiN)
127  }
128 
130  ThreeVector pos = p->getPosition();
131  G4double pos2 = pos.mag2();
133  short iterations=0;
134  const short maxIterations=50;
135 
136  if(pos2 < r*r) return true;
137 
138  while( pos2 >= r*r && iterations<maxIterations )
139  {
140  pos *= std::sqrt(r*r*0.99/pos2);
141  pos2 = pos.mag2();
142  iterations++;
143  }
144  if( iterations < maxIterations)
145  {
146  DEBUG("Particle position vector length was : " << p->getPosition().mag() << ", rescaled to: " << pos.mag() << std::endl);
147  p->setPosition(pos);
148  return true;
149  }
150  else
151  return false;
152  }
153 
155  ParticleList modified = fs->getModifiedParticles();
156  ParticleList modifiedAndCreated = modified;
157  ParticleList created = fs->getCreatedParticles();
158  modifiedAndCreated.insert(modifiedAndCreated.end(), created.begin(), created.end());
159 
160  if(!isPiN) {
161  // Boost back to lab
162  for( ParticleIter i = modifiedAndCreated.begin(); i != modifiedAndCreated.end(); ++i )
163  (*i)->boost(-boostVector);
164  }
165 
166  // If there is no Nucleus, just return
167  if(!theNucleus) return fs;
168 
169  // Mark pions that have been created outside their well (we will force them
170  // to be emitted later).
171  for( ParticleIter i = created.begin(); i != created.end(); ++i )
172  if((*i)->isPion() && (*i)->getPosition().mag() > theNucleus->getSurfaceRadius(*i)) {
173  (*i)->makeParticipant();
174  (*i)->setOutOfWell();
175  fs->addOutgoingParticle(*i);
176  DEBUG("Pion was created outside its potential well." << std::endl
177  << (*i)->print());
178  }
179 
180  // Try to enforce energy conservation
182  G4bool success = true;
183  if(!isPiN || shouldUseLocalEnergy())
184  success = enforceEnergyConservation(fs);
185  if(!success) {
186  DEBUG("Enforcing energy conservation: failed!" << std::endl);
187 
188  // Restore the state of the initial particles
190 
191  // Delete newly created particles
192  for( ParticleIter i = created.begin(); i != created.end(); ++i )
193  delete *i;
194 
195  FinalState *fsBlocked = new FinalState;
196  delete fs;
197  fsBlocked->makeNoEnergyConservation();
198  fsBlocked->setTotalEnergyBeforeInteraction(0.0);
199 
200  return fsBlocked; // Interaction is blocked. Return an empty final state.
201  }
202  DEBUG("Enforcing energy conservation: success!" << std::endl);
203 
204  // Check that outgoing delta resonances can decay to pi-N
205  for( ParticleIter i = modified.begin(); i != modified.end(); ++i )
206  if((*i)->isDelta() &&
208  DEBUG("Mass of the produced delta below decay threshold; forbidding collision. deltaMass=" <<
209  (*i)->getMass() << std::endl);
210 
211  // Restore the state of the initial particles
213 
214  // Delete newly created particles
215  for( ParticleIter j = created.begin(); j != created.end(); ++j )
216  delete *j;
217 
218  FinalState *fsBlocked = new FinalState;
219  delete fs;
220  fsBlocked->makeNoEnergyConservation();
221  fsBlocked->setTotalEnergyBeforeInteraction(0.0);
222 
223  return fsBlocked; // Interaction is blocked. Return an empty final state.
224  }
225 
226  // Test Pauli blocking
227  G4bool isBlocked = Pauli::isBlocked(modifiedAndCreated, theNucleus);
228 
229  if(isBlocked) {
230  DEBUG("Pauli: Blocked!" << std::endl);
231 
232  // Restore the state of the initial particles
234 
235  // Delete newly created particles
236  for( ParticleIter i = created.begin(); i != created.end(); ++i )
237  delete *i;
238 
239  FinalState *fsBlocked = new FinalState;
240  delete fs;
241  fsBlocked->makePauliBlocked();
242  fsBlocked->setTotalEnergyBeforeInteraction(0.0);
243 
244  return fsBlocked; // Interaction is blocked. Return an empty final state.
245  }
246  DEBUG("Pauli: Allowed!" << std::endl);
247 
248  // Test CDPP blocking
249  G4bool isCDPPBlocked = Pauli::isCDPPBlocked(created, theNucleus);
250 
251  if(isCDPPBlocked) {
252  DEBUG("CDPP: Blocked!" << std::endl);
253 
254  // Restore the state of the initial particles
256 
257  // Delete newly created particles
258  for( ParticleIter i = created.begin(); i != created.end(); ++i )
259  delete *i;
260 
261  FinalState *fsBlocked = new FinalState;
262  delete fs;
263  fsBlocked->makePauliBlocked();
264  fsBlocked->setTotalEnergyBeforeInteraction(0.0);
265 
266  return fsBlocked; // Interaction is blocked. Return an empty final state.
267  }
268  DEBUG("CDPP: Allowed!" << std::endl);
269 
270  // If all went well, try to bring particles inside the nucleus...
271  for( ParticleIter i = modifiedAndCreated.begin(); i != modifiedAndCreated.end(); ++i )
272  {
273  // ...except for pions beyond their surface radius.
274  if((*i)->isOutOfWell()) continue;
275 
276  const G4bool successBringParticlesInside = bringParticleInside(*i);
277  if( !successBringParticlesInside ) {
278  ERROR("Failed to bring particle inside the nucleus!" << std::endl);
279  }
280  }
281 
282  // Collision accepted!
283  for( ParticleIter i = modifiedAndCreated.begin(); i != modifiedAndCreated.end(); ++i ) {
284  if(!(*i)->isOutOfWell()) {
285  // Decide if the particle should be made into a spectator
286  // (Back to spectator)
287  G4bool goesBackToSpectator = false;
288  if((*i)->isNucleon() && theNucleus->getStore()->getConfig()->getBackToSpectator()) {
289  G4double threshold = (*i)->getPotentialEnergy();
290  if((*i)->getType()==Proton)
292  if((*i)->getKineticEnergy() < threshold)
293  goesBackToSpectator = true;
294  }
295 
296  // Thaw the particle propagation
297  (*i)->thawPropagation();
298 
299  // Increment or decrement the participant counters
300  if(goesBackToSpectator) {
301  DEBUG("The following particle goes back to spectator:" << std::endl
302  << (*i)->print() << std::endl);
303  if(!(*i)->isTargetSpectator()) {
305  }
306  (*i)->makeTargetSpectator();
307  } else {
308  if((*i)->isTargetSpectator()) {
310  }
311  (*i)->makeParticipant();
312  }
313  }
314  }
315  ParticleList destroyed = fs->getDestroyedParticles();
316  for( ParticleIter i = destroyed.begin(); i != destroyed.end(); ++i )
317  if(!(*i)->isTargetSpectator())
319 
320  return fs;
321  }
322 
331 
332  if(particle2) {
340  }
341  }
342 
344  // Set up the violationE calculation
345  ParticleList modified = fs->getModifiedParticles();
346  const G4bool manyBodyFinalState = (modified.size() + fs->getCreatedParticles().size() > 1);
347  if(manyBodyFinalState)
348  violationEFunctor = new ViolationEMomentumFunctor(theNucleus, fs, &boostVector, shouldUseLocalEnergy());
349  else {
350  Particle const * const p = modified.front();
351  // The following condition is necessary for the functor to work
352  // correctly. A similar condition exists in INCL4.6.
354  return false;
355  violationEFunctor = new ViolationEEnergyFunctor(theNucleus, fs);
356  }
357 
358  // Apply the root-finding algorithm
359  const G4bool success = RootFinder::solve(violationEFunctor, 1.0);
360  if(success) { // Apply the solution
361  std::pair<G4double,G4double> theSolution = RootFinder::getSolution();
362  (*violationEFunctor)(theSolution.first);
363  } else {
364  WARN("Couldn't enforce energy conservation after an interaction, root-finding algorithm failed." << std::endl);
365  }
366  delete violationEFunctor;
367  return success;
368  }
369 
370  /* *** ***
371  * *** InteractionAvatar::ViolationEMomentumFunctor methods ***
372  * *** ***/
373 
374  InteractionAvatar::ViolationEMomentumFunctor::ViolationEMomentumFunctor(Nucleus * const nucleus, FinalState const * const finalState, ThreeVector const * const boost, const G4bool localE) :
375  RootFunctor(0., 1E6),
376  initialEnergy(finalState->getTotalEnergyBeforeInteraction()),
377  theNucleus(nucleus),
378  boostVector(boost),
379  shouldUseLocalEnergy(localE)
380  {
381  // Set up the finalParticles list
382  finalParticles = finalState->getModifiedParticles();
383  ParticleList created = finalState->getCreatedParticles();
384  finalParticles.splice(finalParticles.end(), created);
385 
386  // Store the particle momenta (necessary for the calls to
387  // scaleParticleMomenta() to work)
388  particleMomenta.clear();
389  for(ParticleIter i=finalParticles.begin(); i!=finalParticles.end(); ++i) {
390  (*i)->boost(*boostVector);
391  particleMomenta.push_back((*i)->getMomentum());
392  }
393  }
394 
395  G4double InteractionAvatar::ViolationEMomentumFunctor::operator()(const G4double alpha) const {
396  scaleParticleMomenta(alpha);
397 
398  G4double deltaE = 0.0;
399  for(ParticleIter i=finalParticles.begin(); i!=finalParticles.end(); ++i)
400  deltaE += (*i)->getEnergy() - (*i)->getPotentialEnergy();
401  deltaE -= initialEnergy;
402  return deltaE;
403  }
404 
405  void InteractionAvatar::ViolationEMomentumFunctor::scaleParticleMomenta(const G4double alpha) const {
406 
407  std::list<ThreeVector>::const_iterator iP = particleMomenta.begin();
408  for(ParticleIter i=finalParticles.begin(); i!=finalParticles.end(); ++i, ++iP) {
409  (*i)->setMomentum((*iP)*alpha);
410  (*i)->adjustEnergyFromMomentum();
411  (*i)->boost(-(*boostVector));
412  if(theNucleus)
413  theNucleus->updatePotentialEnergy(*i);
414  else
415  (*i)->setPotentialEnergy(0.);
416 
417  if(shouldUseLocalEnergy && !(*i)->isPion()) { // This translates AECSVT's loops 1, 3 and 4
418 // assert(theNucleus); // Local energy without a nucleus doesn't make sense
419  const G4double energy = (*i)->getEnergy(); // Store the energy of the particle
420  G4double locE = KinematicsUtils::getLocalEnergy(theNucleus, *i); // Initial value of local energy
421  G4double locEOld;
422  G4double deltaLocE = InteractionAvatar::locEAccuracy + 1E3;
423  for(G4int iterLocE=0;
425  ++iterLocE) {
426  locEOld = locE;
427  (*i)->setEnergy(energy + locE); // Update the energy of the particle...
428  (*i)->adjustMomentumFromEnergy();
429  theNucleus->updatePotentialEnergy(*i); // ...update its potential energy...
430  locE = KinematicsUtils::getLocalEnergy(theNucleus, *i); // ...and recompute locE.
431  deltaLocE = std::abs(locE-locEOld);
432  }
433  }
434  }
435  }
436 
437  void InteractionAvatar::ViolationEMomentumFunctor::cleanUp(const G4bool success) const {
438  if(!success)
439  scaleParticleMomenta(1.);
440  }
441 
442  /* *** ***
443  * *** InteractionAvatar::ViolationEEnergyFunctor methods ***
444  * *** ***/
445 
446  InteractionAvatar::ViolationEEnergyFunctor::ViolationEEnergyFunctor(Nucleus * const nucleus, FinalState const * const finalState) :
447  RootFunctor(0., 1E6),
448  initialEnergy(finalState->getTotalEnergyBeforeInteraction()),
449  theNucleus(nucleus),
450  theParticle(finalState->getModifiedParticles().front()),
451  theEnergy(theParticle->getEnergy()),
452  theMomentum(theParticle->getMomentum()),
453  energyThreshold(KinematicsUtils::energy(theMomentum,ParticleTable::effectiveDeltaDecayThreshold))
454  {
455 // assert(theNucleus);
456 // assert(finalState->getModifiedParticles().size()==1);
457 // assert(theParticle->isDelta());
458  }
459 
460  G4double InteractionAvatar::ViolationEEnergyFunctor::operator()(const G4double alpha) const {
461  setParticleEnergy(alpha);
462  return theParticle->getEnergy() - theParticle->getPotentialEnergy() - initialEnergy;
463  }
464 
465  void InteractionAvatar::ViolationEEnergyFunctor::setParticleEnergy(const G4double alpha) const {
466 
467  G4double locE = KinematicsUtils::getLocalEnergy(theNucleus, theParticle); // Initial value of local energy
468  G4double locEOld;
469  G4double deltaLocE = InteractionAvatar::locEAccuracy + 1E3;
470  for(G4int iterLocE=0;
472  ++iterLocE) {
473  locEOld = locE;
474  const G4double particleEnergy = energyThreshold + alpha*(theEnergy-energyThreshold);
475  const G4double theMass = std::sqrt(std::pow(particleEnergy,2.)-theMomentum.mag2());
476  theParticle->setMass(theMass);
477  theParticle->setEnergy(particleEnergy + locE); // Update the energy of the particle...
478  theParticle->adjustMomentumFromEnergy();
479  theNucleus->updatePotentialEnergy(theParticle); // ...update its potential energy...
480  locE = KinematicsUtils::getLocalEnergy(theNucleus, theParticle); // ...and recompute locE.
481  deltaLocE = std::abs(locE-locEOld);
482  }
483 
484  }
485 
486  void InteractionAvatar::ViolationEEnergyFunctor::cleanUp(const G4bool success) const {
487  if(!success)
488  setParticleEnergy(1.);
489  }
490 
491 }