Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/hadronic/models/inclxx/incl_physics/src/G4INCLInteractionAvatar.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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 // Alain Boudard, CEA-Saclay, France
 28 // Joseph Cugnon, University of Liege, Belgium
 29 // Jean-Christophe David, CEA-Saclay, France
 30 // Pekka Kaitaniemi, CEA-Saclay, France, and Helsinki Institute of Physics, Finland
 31 // Sylvie Leray, CEA-Saclay, France
 32 // Davide Mancusi, CEA-Saclay, France
 33 //
 34 #define INCLXX_IN_GEANT4_MODE 1
 35 
 36 #include "globals.hh"
 37 
 38 /* \file G4INCLInteractionAvatar.cc
 39  * \brief Virtual class for interaction avatars.
 40  *
 41  * This class is inherited by decay and collision avatars. The goal is to
 42  * provide a uniform treatment of common physics, such as Pauli blocking,
 43  * enforcement of energy conservation, etc.
 44  *
 45  *  \date Mar 1st, 2011
 46  * \author Davide Mancusi
 47  */
 48 
 49 #include "G4INCLInteractionAvatar.hh"
 50 #include "G4INCLKinematicsUtils.hh"
 51 #include "G4INCLCrossSections.hh"
 52 #include "G4INCLPauliBlocking.hh"
 53 #include "G4INCLRootFinder.hh"
 54 #include "G4INCLLogger.hh"
 55 #include "G4INCLConfigEnums.hh"
 56 #include "G4INCLConfig.hh"
 57 // #include <cassert>
 58 
 59 namespace G4INCL {
 60 
 61   const G4double InteractionAvatar::locEAccuracy = 1.E-4;
 62   const G4int InteractionAvatar::maxIterLocE = 50;
 63   G4ThreadLocal Particle *InteractionAvatar::backupParticle1 = NULL;
 64   G4ThreadLocal Particle *InteractionAvatar::backupParticle2 = NULL;
 65 
 66   InteractionAvatar::InteractionAvatar(G4double time, G4INCL::Nucleus *n, G4INCL::Particle *p1)
 67     : IAvatar(time), theNucleus(n),
 68     particle1(p1), particle2(NULL),
 69     isPiN(false),
 70     weight(1.),
 71     violationEFunctor(NULL)
 72   {
 73   }
 74 
 75   InteractionAvatar::InteractionAvatar(G4double time, G4INCL::Nucleus *n, G4INCL::Particle *p1,
 76       G4INCL::Particle *p2)
 77     : IAvatar(time), theNucleus(n),
 78     particle1(p1), particle2(p2),
 79     isPiN((p1->isPion() && p2->isNucleon()) || (p2->isPion() && p1->isNucleon())),
 80     weight(1.),
 81     violationEFunctor(NULL)
 82   {
 83   }
 84 
 85   InteractionAvatar::~InteractionAvatar() {
 86   }
 87 
 88   void InteractionAvatar::deleteBackupParticles() {
 89     delete backupParticle1;
 90     if(backupParticle2)
 91       delete backupParticle2;
 92     backupParticle1 = NULL;
 93     backupParticle2 = NULL;
 94   }
 95 
 96   void InteractionAvatar::preInteractionBlocking() {
 97     if(backupParticle1)
 98       (*backupParticle1) = (*particle1);
 99     else
100       backupParticle1 = new Particle(*particle1);
101 
102     if(particle2) {
103       if(backupParticle2)
104         (*backupParticle2) = (*particle2);
105       else
106         backupParticle2 = new Particle(*particle2);
107 
108       oldTotalEnergy = particle1->getEnergy() + particle2->getEnergy()
109         - particle1->getPotentialEnergy() - particle2->getPotentialEnergy();
110       oldXSec = CrossSections::total(particle1, particle2);
111     } else {
112       oldTotalEnergy = particle1->getEnergy() - particle1->getPotentialEnergy();
113     }
114   }
115 
116   void InteractionAvatar::preInteractionLocalEnergy(Particle * const p) {
117     if(!theNucleus || p->isMeson() || p->isPhoton() || p->isAntiNucleon()) return; // Local energy does not make any sense without a nucleus
118 
119     if(shouldUseLocalEnergy())
120       KinematicsUtils::transformToLocalEnergyFrame(theNucleus, p);
121   }
122 
123   void InteractionAvatar::preInteraction() {
124     preInteractionBlocking();
125 
126     preInteractionLocalEnergy(particle1);
127 
128     if(particle2) {
129       preInteractionLocalEnergy(particle2);
130       boostVector = KinematicsUtils::makeBoostVector(particle1, particle2);
131       particle2->boost(boostVector);
132     } else {
133       boostVector = particle1->getMomentum()/particle1->getEnergy();
134     }
135     particle1->boost(boostVector);
136   }
137 
138   G4bool InteractionAvatar::bringParticleInside(Particle * const p) {
139     if(!theNucleus)
140       return false;
141 
142     ThreeVector pos = p->getPosition();
143     p->rpCorrelate();
144     G4double pos2 = pos.mag2();
145     const G4double r = theNucleus->getSurfaceRadius(p);
146     short iterations=0;
147     const short maxIterations=50;
148 
149     if(pos2 < r*r) return true;
150 
151     while( pos2 >= r*r && iterations<maxIterations ) /* Loop checking, 10.07.2015, D.Mancusi */
152     {
153       pos *= std::sqrt(r*r*0.9801/pos2); // 0.9801 == 0.99*0.99
154       pos2 = pos.mag2();
155       iterations++;
156     }
157     if( iterations < maxIterations)
158     {
159       INCL_DEBUG("Particle position vector length was : " << p->getPosition().mag() << ", rescaled to: " << pos.mag() << '\n');
160       p->setPosition(pos);
161       return true;
162     }
163     else
164       return false;
165   }
166 
167   void InteractionAvatar::postInteraction(FinalState *fs) {
168     INCL_DEBUG("postInteraction: final state: " << '\n' << fs->print() << '\n');
169     modified = fs->getModifiedParticles();
170     created = fs->getCreatedParticles();
171     Destroyed = fs->getDestroyedParticles();
172     modifiedAndCreated = modified;
173     modifiedAndCreated.insert(modifiedAndCreated.end(), created.begin(), created.end());
174     ModifiedAndDestroyed = modified;
175     ModifiedAndDestroyed.insert(ModifiedAndDestroyed.end(), Destroyed.begin(), Destroyed.end());
176 
177     // Boost back to lab
178     modifiedAndCreated.boost(-boostVector);
179 
180     // If there is no Nucleus, just return
181     if(!theNucleus) return;
182 
183     // Mark pions and kaons that have been created outside their well (we will force them
184     // to be emitted later).
185     for(ParticleIter i=created.begin(), e=created.end(); i!=e; ++i )
186       if(((*i)->isPion() || (*i)->isKaon() || (*i)->isAntiKaon()) && (*i)->getPosition().mag() > theNucleus->getSurfaceRadius(*i)) {
187         (*i)->makeParticipant();
188         (*i)->setOutOfWell();
189         fs->addOutgoingParticle(*i);
190         INCL_DEBUG("Pion was created outside its potential well." << '\n'
191             << (*i)->print());
192       }
193 
194     // Try to enforce energy conservation
195     fs->setTotalEnergyBeforeInteraction(oldTotalEnergy);
196     G4bool success = enforceEnergyConservation(fs);
197     if(!success) {
198       INCL_DEBUG("Enforcing energy conservation: failed!" << '\n');
199 
200       // Restore the state of the initial particles
201       restoreParticles();
202 
203       // Delete newly created particles
204       for(ParticleIter i=created.begin(), e=created.end(); i!=e; ++i )
205         delete *i;
206 
207       fs->reset();
208       fs->makeNoEnergyConservation();
209       fs->setTotalEnergyBeforeInteraction(0.0);
210 
211       return; // Interaction is blocked. Return an empty final state.
212     }
213     INCL_DEBUG("Enforcing energy conservation: success!" << '\n');
214 
215     INCL_DEBUG("postInteraction after energy conservation: final state: " << '\n' << fs->print() << '\n');
216 
217     // Check that outgoing delta resonances can decay to pi-N
218     for(ParticleIter i=modified.begin(), e=modified.end(); i!=e; ++i )
219       if((*i)->isDelta() &&
220           (*i)->getMass() < ParticleTable::minDeltaMass) {
221         INCL_DEBUG("Mass of the produced delta below decay threshold; forbidding collision. deltaMass=" <<
222             (*i)->getMass() << '\n');
223 
224         // Restore the state of the initial particles
225         restoreParticles();
226 
227         // Delete newly created particles
228         for(ParticleIter j=created.begin(), end=created.end(); j!=end; ++j )
229           delete *j;
230 
231         fs->reset();
232         fs->makeNoEnergyConservation();
233         fs->setTotalEnergyBeforeInteraction(0.0);
234 
235         return; // Interaction is blocked. Return an empty final state.
236       }
237 
238     INCL_DEBUG("Random seeds before Pauli blocking: " << Random::getSeeds() << '\n');
239     // Test Pauli blocking
240     G4bool isBlocked = Pauli::isBlocked(modifiedAndCreated, theNucleus);
241 
242     if(isBlocked) {
243       INCL_DEBUG("Pauli: Blocked!" << '\n');
244 
245       // Restore the state of the initial particles
246       restoreParticles();
247 
248       // Delete newly created particles
249       for(ParticleIter i=created.begin(), e=created.end(); i!=e; ++i )
250         delete *i;
251 
252       fs->reset();
253       fs->makePauliBlocked();
254       fs->setTotalEnergyBeforeInteraction(0.0);
255 
256       return; // Interaction is blocked. Return an empty final state.
257     }
258     INCL_DEBUG("Pauli: Allowed!" << '\n');
259 
260     // Test CDPP blocking
261     G4bool isCDPPBlocked = Pauli::isCDPPBlocked(created, theNucleus);
262 
263     if(isCDPPBlocked) {
264       INCL_DEBUG("CDPP: Blocked!" << '\n');
265 
266       // Restore the state of the initial particles
267       restoreParticles();
268 
269       // Delete newly created particles
270       for(ParticleIter i=created.begin(), e=created.end(); i!=e; ++i )
271         delete *i;
272 
273       fs->reset();
274       fs->makePauliBlocked();
275       fs->setTotalEnergyBeforeInteraction(0.0);
276 
277       return; // Interaction is blocked. Return an empty final state.
278     }
279     INCL_DEBUG("CDPP: Allowed!" << '\n');
280 
281     // If all went well, try to bring particles inside the nucleus...
282     for(ParticleIter i=modifiedAndCreated.begin(), e=modifiedAndCreated.end(); i!=e; ++i )
283     {
284       // ...except for pions beyond their surface radius.
285       if((*i)->isOutOfWell()) continue;
286 
287       const G4bool successBringParticlesInside = bringParticleInside(*i);
288       if( !successBringParticlesInside ) {
289         INCL_ERROR("Failed to bring particle inside the nucleus!" << '\n');
290       }
291     }
292 
293     // Collision accepted!
294     // Biasing of the final state
295     std::vector<G4int> newBiasCollisionVector;
296     newBiasCollisionVector = ModifiedAndDestroyed.getParticleListBiasVector();
297     if(std::fabs(weight-1.) > 1E-6){
298       newBiasCollisionVector.push_back(Particle::nextBiasedCollisionID);
299       Particle::FillINCLBiasVector(1./weight);
300       weight = 1.; // useless?
301     }
302     for(ParticleIter i=modifiedAndCreated.begin(), e=modifiedAndCreated.end(); i!=e; ++i ) {
303       (*i)->setBiasCollisionVector(newBiasCollisionVector);
304       if(!(*i)->isOutOfWell()) {
305         // Decide if the particle should be made into a spectator
306         // (Back to spectator)
307         G4bool goesBackToSpectator = false;
308         if((*i)->isNucleon() && theNucleus->getStore()->getConfig()->getBackToSpectator()) {
309           G4double threshold = (*i)->getPotentialEnergy();
310           if((*i)->getType()==Proton)
311             threshold += Math::twoThirds*theNucleus->getTransmissionBarrier(*i);
312           if((*i)->getKineticEnergy() < threshold)
313             goesBackToSpectator = true;
314         }
315         // Thaw the particle propagation
316         (*i)->thawPropagation();
317 
318         // Increment or decrement the participant counters
319         if(goesBackToSpectator) {
320           INCL_DEBUG("The following particle goes back to spectator:" << '\n'
321               << (*i)->print() << '\n');
322           if(!(*i)->isTargetSpectator()) {
323             theNucleus->getStore()->getBook().decrementCascading();
324           }
325           (*i)->makeTargetSpectator();
326         } else {
327           if((*i)->isTargetSpectator()) {
328             theNucleus->getStore()->getBook().incrementCascading();
329           }
330           (*i)->makeParticipant();
331         }
332       }
333     }
334     ParticleList destroyed = fs->getDestroyedParticles();
335     for(ParticleIter i=destroyed.begin(), e=destroyed.end(); i!=e; ++i )
336       if(!(*i)->isTargetSpectator())
337         theNucleus->getStore()->getBook().decrementCascading();
338     return;
339   }
340 
341   void InteractionAvatar::restoreParticles() const {
342     (*particle1) = (*backupParticle1);
343     if(particle2)
344       (*particle2) = (*backupParticle2);
345   }
346 
347   G4bool InteractionAvatar::shouldUseLocalEnergy() const {
348     if(!theNucleus) return false;
349     LocalEnergyType theLocalEnergyType;
350     if(theNucleus->getStore()->getConfig()->getProjectileType()==antiProton ||
351      theNucleus->getStore()->getConfig()->getProjectileType()==antiNeutron){
352       return false;
353     }
354     if(getType()==DecayAvatarType || isPiN)
355       theLocalEnergyType = theNucleus->getStore()->getConfig()->getLocalEnergyPiType();
356     else
357       theLocalEnergyType = theNucleus->getStore()->getConfig()->getLocalEnergyBBType();
358 
359     const G4bool firstAvatar = (theNucleus->getStore()->getBook().getAcceptedCollisions() == 0);
360     return ((theLocalEnergyType == FirstCollisionLocalEnergy && firstAvatar) ||
361             theLocalEnergyType == AlwaysLocalEnergy);
362   }
363 
364   G4bool InteractionAvatar::enforceEnergyConservation(FinalState * const fs) {
365     // Set up the violationE calculation
366     const G4bool manyBodyFinalState = (modifiedAndCreated.size() > 1);
367     
368     if(manyBodyFinalState)
369       violationEFunctor = new ViolationEMomentumFunctor(theNucleus, modifiedAndCreated, fs->getTotalEnergyBeforeInteraction(), boostVector, shouldUseLocalEnergy());
370     else {
371       if (modified.empty()) {
372         Particle * const p1 = created.front(); //we destroy all nucleons during annihilation in NNbar case
373          // The following condition is necessary for the functor to work
374          // correctly. A similar condition exists in INCL4.6.
375         if(p1->getMass() < ParticleTable::minDeltaMass)
376           return false;
377         violationEFunctor = new ViolationEEnergyFunctor(theNucleus, p1, fs->getTotalEnergyBeforeInteraction(), shouldUseLocalEnergy());
378       }
379       else{
380         Particle * const p2 = modified.front(); // normal situation
381          // The following condition is necessary for the functor to work
382          // correctly. A similar condition exists in INCL4.6.
383          if(p2->getMass() < ParticleTable::minDeltaMass)
384            return false;
385          violationEFunctor = new ViolationEEnergyFunctor(theNucleus, p2, fs->getTotalEnergyBeforeInteraction(), shouldUseLocalEnergy());
386       }
387     }
388 
389     // Apply the root-finding algorithm
390     const RootFinder::Solution theSolution = RootFinder::solve(violationEFunctor, 1.0);
391     if(theSolution.success) { // Apply the solution
392       (*violationEFunctor)(theSolution.x);
393     } else if(theNucleus){
394       INCL_DEBUG("Couldn't enforce energy conservation after an interaction, root-finding algorithm failed." << '\n');
395       theNucleus->getStore()->getBook().incrementEnergyViolationInteraction();
396     }
397     delete violationEFunctor;
398     violationEFunctor = NULL;
399     return theSolution.success;
400   }
401 
402   /* ***                                                      ***
403    * *** InteractionAvatar::ViolationEMomentumFunctor methods ***
404    * ***                                                      ***/
405 
406   InteractionAvatar::ViolationEMomentumFunctor::ViolationEMomentumFunctor(Nucleus * const nucleus, ParticleList const &modAndCre, const G4double totalEnergyBeforeInteraction, ThreeVector const &boost, const G4bool localE) :
407     RootFunctor(0., 1E6),
408     finalParticles(modAndCre),
409     initialEnergy(totalEnergyBeforeInteraction),
410     theNucleus(nucleus),
411     boostVector(boost),
412     shouldUseLocalEnergy(localE)
413   {
414     // Store the particle momenta (necessary for the calls to
415     // scaleParticleMomenta() to work)
416     for(ParticleIter i=finalParticles.begin(), e=finalParticles.end(); i!=e; ++i) {
417       (*i)->boost(boostVector);
418       particleMomenta.push_back((*i)->getMomentum());
419     }
420   }
421 
422   InteractionAvatar::ViolationEMomentumFunctor::~ViolationEMomentumFunctor() {
423     particleMomenta.clear();
424   }
425 
426   G4double InteractionAvatar::ViolationEMomentumFunctor::operator()(const G4double alpha) const {
427     scaleParticleMomenta(alpha);
428 
429     G4double deltaE = 0.0;
430     for(ParticleIter i=finalParticles.begin(), e=finalParticles.end(); i!=e; ++i)
431       deltaE += (*i)->getEnergy() - (*i)->getPotentialEnergy();
432     deltaE -= initialEnergy;
433     return deltaE;
434   }
435 
436   void InteractionAvatar::ViolationEMomentumFunctor::scaleParticleMomenta(const G4double alpha) const {
437 
438     std::vector<ThreeVector>::const_iterator iP = particleMomenta.begin();
439     for(ParticleIter i=finalParticles.begin(), e=finalParticles.end(); i!=e; ++i, ++iP) {
440       (*i)->setMomentum((*iP)*alpha);
441       (*i)->adjustEnergyFromMomentum();
442       (*i)->rpCorrelate();
443       (*i)->boost(-boostVector);
444       if(theNucleus){
445         theNucleus->updatePotentialEnergy(*i);
446       } else {
447         (*i)->setPotentialEnergy(0.);
448       }
449 
450       if(shouldUseLocalEnergy && !(*i)->isPion() && !(*i)->isEta() && !(*i)->isOmega() &&
451          !(*i)->isKaon() && !(*i)->isAntiKaon()  && !(*i)->isSigma() && !(*i)->isPhoton() && !(*i)->isLambda() && !(*i)->isAntiBaryon()) { // This translates AECSVT's loops 1, 3 and 4
452 // assert(theNucleus); // Local energy without a nucleus doesn't make sense
453          const G4double energy = (*i)->getEnergy(); // Store the energy of the particle
454          G4double locE = KinematicsUtils::getLocalEnergy(theNucleus, *i); // Initial value of local energy
455          G4double locEOld;
456          G4double deltaLocE = InteractionAvatar::locEAccuracy + 1E3;
457          for(G4int iterLocE=0;
458             deltaLocE>InteractionAvatar::locEAccuracy && iterLocE<InteractionAvatar::maxIterLocE;
459             ++iterLocE) {
460           locEOld = locE;
461           (*i)->setEnergy(energy + locE); // Update the energy of the particle...
462           (*i)->adjustMomentumFromEnergy();
463           theNucleus->updatePotentialEnergy(*i); // ...update its potential energy...
464           locE = KinematicsUtils::getLocalEnergy(theNucleus, *i); // ...and recompute locE.
465           deltaLocE = std::abs(locE-locEOld);
466         }
467       }
468 
469 //jlrs  For lambdas and nuclei with masses higher than 19 also local energy
470         if(shouldUseLocalEnergy && (*i)->isLambda() && theNucleus->getA()>19) {
471 // assert(theNucleus); // Local energy without a nucleus doesn't make sense
472          const G4double energy = (*i)->getEnergy(); // Store the energy of the particle
473          G4double locE = KinematicsUtils::getLocalEnergy(theNucleus, *i); // Initial value of local energy
474          G4double locEOld;
475          G4double deltaLocE = InteractionAvatar::locEAccuracy + 1E3;
476          for(G4int iterLocE=0;
477             deltaLocE>InteractionAvatar::locEAccuracy && iterLocE<InteractionAvatar::maxIterLocE;
478             ++iterLocE) {
479           locEOld = locE;
480           (*i)->setEnergy(energy + locE); // Update the energy of the particle...
481           (*i)->adjustMomentumFromEnergy();
482           theNucleus->updatePotentialEnergy(*i); // ...update its potential energy...
483           locE = KinematicsUtils::getLocalEnergy(theNucleus, *i); // ...and recompute locE.
484           deltaLocE = std::abs(locE-locEOld);
485          }
486         }
487     }
488   }
489 
490   void InteractionAvatar::ViolationEMomentumFunctor::cleanUp(const G4bool success) const {
491     if(!success)
492       scaleParticleMomenta(1.);
493   }
494 
495   /* ***                                                    ***
496    * *** InteractionAvatar::ViolationEEnergyFunctor methods ***
497    * ***                                                    ***/
498 
499   InteractionAvatar::ViolationEEnergyFunctor::ViolationEEnergyFunctor(Nucleus * const nucleus, Particle * const aParticle, const G4double totalEnergyBeforeInteraction, const G4bool localE) :
500     RootFunctor(0., 1E6),
501     initialEnergy(totalEnergyBeforeInteraction),
502     theNucleus(nucleus),
503     theParticle(aParticle),
504     theEnergy(theParticle->getEnergy()),
505     theMomentum(theParticle->getMomentum()),
506     energyThreshold(KinematicsUtils::energy(theMomentum,ParticleTable::minDeltaMass)),
507     shouldUseLocalEnergy(localE)
508   {
509 // assert(theParticle->isDelta());
510   }
511 
512   G4double InteractionAvatar::ViolationEEnergyFunctor::operator()(const G4double alpha) const {
513     setParticleEnergy(alpha);
514     return theParticle->getEnergy() - theParticle->getPotentialEnergy() - initialEnergy;
515   }
516 
517   void InteractionAvatar::ViolationEEnergyFunctor::setParticleEnergy(const G4double alpha) const {
518 
519     G4double locE;
520     if(shouldUseLocalEnergy) {
521 // assert(theNucleus); // Local energy without a nucleus doesn't make sense
522       locE = KinematicsUtils::getLocalEnergy(theNucleus, theParticle); // Initial value of local energy
523     } else
524       locE = 0.;
525     G4double locEOld;
526     G4double deltaLocE = InteractionAvatar::locEAccuracy + 1E3;
527     for(G4int iterLocE=0;
528         deltaLocE>InteractionAvatar::locEAccuracy && iterLocE<InteractionAvatar::maxIterLocE;
529         ++iterLocE) {
530       locEOld = locE;
531       G4double particleEnergy = energyThreshold + locE + alpha*(theEnergy-energyThreshold);
532       const G4double theMass2 = std::pow(particleEnergy,2.)-theMomentum.mag2();
533       G4double theMass;
534       if(theMass2>ParticleTable::minDeltaMass2)
535         theMass = std::sqrt(theMass2);
536       else {
537         theMass = ParticleTable::minDeltaMass;
538         particleEnergy = energyThreshold;
539       }
540       theParticle->setMass(theMass);
541       theParticle->setEnergy(particleEnergy); // Update the energy of the particle...
542       if(theNucleus) {
543         theNucleus->updatePotentialEnergy(theParticle); // ...update its potential energy...
544         if(shouldUseLocalEnergy)
545           locE = KinematicsUtils::getLocalEnergy(theNucleus, theParticle); // ...and recompute locE.
546         else
547           locE = 0.;
548       } else
549         locE = 0.;
550       deltaLocE = std::abs(locE-locEOld);
551     }
552 
553   }
554 
555   void InteractionAvatar::ViolationEEnergyFunctor::cleanUp(const G4bool success) const {
556     if(!success)
557       setParticleEnergy(1.);
558   }
559 
560 }
561