33 #define INCLXX_IN_GEANT4_MODE 1
44 #ifndef G4INCLNucleus_hh
45 #define G4INCLNucleus_hh 1
70 theInitialZ(charge), theInitialA(mass),
71 theNpInitial(0), theNnInitial(0),
72 initialInternalEnergy(0.),
73 incomingAngularMomentum(0.,0.,0.), incomingMomentum(0.,0.,0.),
74 initialCenterOfMass(0.,0.,0.),
79 forceTransparent(false),
82 theUniverseRadius(universeRadius),
83 isNucleusNucleus(false),
84 theProjectileRemnant(NULL),
98 switch(potentialType) {
112 FATAL(
"Unrecognized potential type at Nucleus creation." << std::endl);
124 if(theUniverseRadius<0)
125 theUniverseRadius = theDensity->getMaximumRadius();
126 theStore =
new Store(conf);
139 delete theProjectileRemnant;
140 theProjectileRemnant = NULL;
153 std::stringstream ss;
154 ss <<
"(list ;; List of participants " << std::endl;
156 for(
ParticleIter i = participants.begin(); i != participants.end(); ++i) {
157 ss <<
"(make-particle-avatar-map " << std::endl
159 <<
"(list ;; List of avatars in this particle" << std::endl
160 <<
")) ;; Close the list of avatars and the particle-avatar-map" << std::endl;
162 ss <<
")" << std::endl;
176 for(
ParticleIter iter = created.begin(); iter != created.end(); ++iter) {
177 theStore->
add((*iter));
178 if(!(*iter)->isOutOfWell()) {
179 totalEnergy += (*iter)->getEnergy() - (*iter)->getPotentialEnergy();
180 justCreated.push_back((*iter));
185 for(
ParticleIter iter = deleted.begin(); iter != deleted.end(); ++iter) {
190 for(
ParticleIter iter = modified.begin(); iter != modified.end(); ++iter) {
192 totalEnergy += (*iter)->getEnergy() - (*iter)->getPotentialEnergy();
193 toBeUpdated.push_back((*iter));
197 for(
ParticleIter iter = out.begin(); iter != out.end(); ++iter) {
198 if((*iter)->isCluster()) {
206 totalEnergy += (*iter)->getEnergy();
207 theA -= (*iter)->getA();
208 theZ -= (*iter)->getZ();
214 for(
ParticleIter iter = entering.begin(); iter != entering.end(); ++iter) {
216 totalEnergy += (*iter)->getEnergy() - (*iter)->getPotentialEnergy();
217 toBeUpdated.push_back((*iter));
222 DEBUG(
"A Particle is entering below the Fermi sea:" << std::endl << finalstate->
print() << std::endl);
225 for(
ParticleIter iter = entering.begin(); iter != entering.end(); ++iter) {
229 DEBUG(
"A Particle is entering below zero energy:" << std::endl << finalstate->
print() << std::endl);
230 forceTransparent =
true;
232 for(
ParticleIter iter = entering.begin(); iter != entering.end(); ++iter) {
239 ERROR(
"Energy nonconservation! Energy at the beginning of the event = "
241 <<
" and after interaction = "
242 << totalEnergy << std::endl
243 << finalstate->
print());
248 WARN(
"Useless Nucleus::propagateParticles -method called." << std::endl);
255 if((*p)->isNucleon())
256 totalEnergy += (*p)->getKineticEnergy() - (*p)->getPotentialEnergy();
257 else if((*p)->isResonance())
260 totalEnergy += (*p)->getEnergy() - (*p)->getPotentialEnergy();
270 computeOneNucleonRecoilKinematics();
277 theSpin = incomingAngularMomentum;
283 theSpin -= (*p)->getAngularMomentum();
300 const G4double mass = (*p)->getMass();
301 cm += (*p)->getPosition() * mass;
312 return totalEnergy - initialInternalEnergy - separationEnergies;
317 std::stringstream ss;
318 ss <<
"Particles in the nucleus:" << std::endl
319 <<
"Participants:" << std::endl;
322 for(
ParticleIter p = participants.begin();
p != participants.end(); ++
p) {
323 ss <<
"index = " << counter << std::endl
327 ss <<
"Spectators:" << std::endl;
331 ss <<
"Outgoing:" << std::endl;
342 for(
ParticleIter i = out.begin(); i != out.end(); ++i) {
343 if((*i)->isDelta()) deltas.push_back((*i));
345 if(deltas.empty())
return false;
347 for(
ParticleIter i = deltas.begin(); i != deltas.end(); ++i) {
348 DEBUG(
"Decay outgoing delta particle:" << std::endl
349 << (*i)->print() << std::endl);
351 const G4double deltaMass = (*i)->getMass();
356 (*i)->setEnergy((*i)->getMass());
369 newMomentum *= decayMomentum / newMomentum.
mag();
381 nucleon->
boost(beta);
400 const G4bool unphysicalRemnant = (theZ<0 || theZ>
theA);
407 for(
ParticleIter i = inside.begin(); i != inside.end(); ++i)
408 if((*i)->isDelta()) deltas.push_back((*i));
411 for(
ParticleIter i = deltas.begin(); i != deltas.end(); ++i) {
412 DEBUG(
"Decay inside delta particle:" << std::endl
413 << (*i)->print() << std::endl);
419 if(unphysicalRemnant)
437 if(unphysicalRemnant) {
438 DEBUG(
"Remnant is unphysical: Z=" <<
theZ <<
", A=" <<
theA << std::endl);
448 for(
ParticleIter i = out.begin(); i != out.end(); ++i) {
449 if((*i)->isCluster()) clusters.push_back((*i));
451 if(clusters.empty())
return false;
453 for(
ParticleIter i = clusters.begin(); i != clusters.end(); ++i) {
457 for(
ParticleIter j = decayProducts.begin(); j!=decayProducts.end(); ++j)
469 for(
ParticleIter j = decayProducts.begin(); j!=decayProducts.end(); ++j)
480 WARN(
"Forcing emissions of all pions in the nucleus." << std::endl);
483 const G4double tinyPionEnergy = 0.1;
487 for(
ParticleIter i = inside.begin(); i != inside.end(); ++i) {
491 const G4double theQValueCorrection = (*i)->getEmissionQValueCorrection(
theA,
theZ);
492 const G4double kineticEnergyOutside = (*i)->getKineticEnergy() - (*i)->getPotentialEnergy() + theQValueCorrection;
493 (*i)->setTableMass();
494 if(kineticEnergyOutside > 0.0)
495 (*i)->setEnergy((*i)->getMass()+kineticEnergyOutside);
497 (*i)->setEnergy((*i)->getMass()+tinyPionEnergy);
498 (*i)->adjustMomentumFromEnergy();
499 (*i)->setPotentialEnergy(0.);
500 theZ -= (*i)->getZ();
514 G4int outZ = 0, outA = 0;
519 if( (*p)->getNumberOfCollisions() != 0 )
return false;
520 if( (*p)->getNumberOfDecays() != 0 )
return false;
521 outZ += (*p)->getZ();
522 outA += (*p)->getA();
526 if(theProjectileRemnant) {
527 outZ += theProjectileRemnant->
getZ();
528 outA += theProjectileRemnant->
getA();
531 if(outZ!=projectileZ || outA!=projectileA)
return false;
537 void Nucleus::computeOneNucleonRecoilKinematics() {
541 ERROR(
"Computing one-nucleon recoil kinematics. We should never be here nowadays, cascade should stop earlier than this." << std::endl);
560 for(
ParticleIter j = created.begin(); j != created.end(); ++j)
568 if(outgoing.size() == 2) {
570 DEBUG(
"Two particles in the outgoing channel, applying exact two-body kinematics" << std::endl);
574 Particle *p1 = outgoing.front(), *p2 = outgoing.back();
575 const ThreeVector aBoostVector = incomingMomentum / initialEnergy;
577 p1->boost(aBoostVector);
578 const G4double sqrts = std::sqrt(initialEnergy*initialEnergy - incomingMomentum.
mag2());
582 p1->setMomentum(p1->getMomentum()*
scale);
583 p2->setMomentum(-p1->getMomentum());
584 p1->adjustEnergyFromMomentum();
585 p2->adjustEnergyFromMomentum();
587 p1->boost(-aBoostVector);
588 p2->boost(-aBoostVector);
592 DEBUG(
"Trying to adjust final-state momenta to achieve energy and momentum conservation" << std::endl);
594 const G4int maxIterations=8;
596 G4double val=1.E+100, oldVal=1.E+100, oldOldVal=1.E+100, oldOldOldVal;
597 ThreeVector totalMomentum, deltaP;
598 std::vector<ThreeVector> minMomenta;
601 minMomenta.reserve(outgoing.size());
604 totalMomentum.setX(0.0);
605 totalMomentum.setY(0.0);
606 totalMomentum.setZ(0.0);
607 for(
ParticleIter i=outgoing.begin(); i!=outgoing.end(); ++i)
608 totalMomentum += (*i)->getMomentum();
612 for(
ParticleIter i=outgoing.begin(); i!=outgoing.end(); ++i)
613 totalEnergy += (*i)->getEnergy();
616 for(
G4int iterations=0; iterations < maxIterations; ++iterations) {
619 oldOldOldVal = oldOldVal;
623 if(iterations%2 == 0) {
624 DEBUG(
"Momentum step" << std::endl);
626 deltaP = incomingMomentum - totalMomentum;
628 for(
ParticleIter i=outgoing.begin(); i!=outgoing.end(); ++i)
629 pOldTot += (*i)->getMomentum().
mag();
630 for(
ParticleIter i=outgoing.begin(); i!=outgoing.end(); ++i) {
631 const ThreeVector mom = (*i)->getMomentum();
632 (*i)->setMomentum(mom + deltaP*mom.mag()/pOldTot);
633 (*i)->adjustEnergyFromMomentum();
636 DEBUG(
"Energy step" << std::endl);
638 energyScale = initialEnergy/totalEnergy;
639 for(
ParticleIter i=outgoing.begin(); i!=outgoing.end(); ++i) {
640 const ThreeVector mom = (*i)->getMomentum();
641 G4double pScale = ((*i)->getEnergy()*energyScale - std::pow((*i)->getMass(),2))/mom.mag2();
643 (*i)->setEnergy((*i)->getEnergy()*energyScale);
644 (*i)->adjustMomentumFromEnergy();
650 totalMomentum.setX(0.0);
651 totalMomentum.setY(0.0);
652 totalMomentum.setZ(0.0);
654 for(
ParticleIter i=outgoing.begin(); i!=outgoing.end(); ++i) {
655 totalMomentum += (*i)->getMomentum();
656 totalEnergy += (*i)->getEnergy();
660 val = std::pow(totalEnergy - initialEnergy,2) +
661 0.25*(totalMomentum - incomingMomentum).mag2();
662 DEBUG(
"Merit function: val=" << val <<
", oldVal=" << oldVal <<
", oldOldVal=" << oldOldVal <<
", oldOldOldVal=" << oldOldOldVal << std::endl);
666 DEBUG(
"New minimum found, storing the particle momenta" << std::endl);
668 for(
ParticleIter i=outgoing.begin(); i!=outgoing.end(); ++i)
669 minMomenta.push_back((*i)->getMomentum());
673 if(val > oldOldVal && oldVal > oldOldOldVal) {
674 DEBUG(
"Search is diverging, breaking out of the iteration loop: val=" << val <<
", oldVal=" << oldVal <<
", oldOldVal=" << oldOldVal <<
", oldOldOldVal=" << oldOldOldVal << std::endl);
683 DEBUG(
"Applying the solution" << std::endl);
684 std::vector<ThreeVector>::const_iterator
v = minMomenta.begin();
685 for(
ParticleIter i=outgoing.begin(); i!=outgoing.end(); ++i, ++
v) {
686 (*i)->setMomentum(*v);
687 (*i)->adjustEnergyFromMomentum();
697 G4bool isNucleonAbsorption =
false;
699 G4bool isPionAbsorption =
false;
705 isPionAbsorption =
true;
716 if(outgoingParticles.size() == 0 &&
719 isNucleonAbsorption =
true;
726 for(
ParticleIter i = outgoingParticles.begin(); i != outgoingParticles.end(); ++i ) {
728 if((*i)->isCluster()) {
731 #ifdef INCLXX_IN_GEANT4_MODE
736 if(std::abs(eStar)>1E-10) {
738 WARN(
"Negative excitation energy in outgoing cluster! EStar = " << eStar << std::endl);
750 remnantSpin *= remnantSpinMag/remnantSpin.
mag();
769 if(isPionAbsorption) {
771 isPionAbsorption =
false;
774 eventInfo->
A[eventInfo->
nParticles] = (*i)->getA();
775 eventInfo->
Z[eventInfo->
nParticles] = (*i)->getZ();
777 eventInfo->
EKin[eventInfo->
nParticles] = (*i)->getKineticEnergy();
785 eventInfo->
history.push_back(
"");
798 WARN(
"Negative excitation energy! EStarRem = " << eventInfo->
EStarRem[eventInfo->
nRemnants] << std::endl);
830 theBalance.
Z = theEventInfo.
Zp + theEventInfo.
Zt;
831 theBalance.
A = theEventInfo.
Ap + theEventInfo.
At;
838 for(
ParticleIter i = outgoingParticles.begin(); i != outgoingParticles.end(); ++i ) {
839 theBalance.
Z -= (*i)->getZ();
840 theBalance.
A -= (*i)->getA();
843 theBalance.
energy -= (*i)->getEnergy();
844 theBalance.
momentum -= (*i)->getMomentum();
849 theBalance.
Z -=
getZ();
850 theBalance.
A -=
getA();
864 setSpin(incomingAngularMomentum);
871 if(theProjectileRemnant->
getA()>1) {
874 theProjectileRemnant->
setMass(aMass);
877 const G4double anExcitationEnergy = aMass
893 theProjectileRemnant = NULL;
894 }
else if(theProjectileRemnant->
getA()==1) {