source: trunk/source/processes/hadronic/models/cascade/cascade/src/G4IntraNucleiCascader.cc @ 1340

Last change on this file since 1340 was 1340, checked in by garnier, 14 years ago

update ti head

File size: 20.6 KB
Line 
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// $Id: G4IntraNucleiCascader.cc,v 1.68 2010/09/25 06:44:30 mkelsey Exp $
26// Geant4 tag: $Name: hadr-casc-V09-03-85 $
27//
28// 20100114  M. Kelsey -- Remove G4CascadeMomentum, use G4LorentzVector directly
29// 20100307  M. Kelsey -- Bug fix: momentum_out[0] should be momentum_out.e()
30// 20100309  M. Kelsey -- Eliminate some unnecessary std::pow()
31// 20100407  M. Kelsey -- Pass "all_particles" as argument to initializeCascad,
32//              following recent change to G4NucleiModel.
33// 20100413  M. Kelsey -- Pass G4CollisionOutput by ref to ::collide()
34// 20100517  M. Kelsey -- Inherit from common base class, make other colliders
35//              simple data members
36// 20100616  M. Kelsey -- Add reporting of final residual particle
37// 20100617  M. Kelsey -- Remove "RUN" preprocessor flag and all "#else" code,
38//              pass verbosity to collider.  Make G4NucleiModel a data member,
39//              instead of creating and deleting on every cycle.
40// 20100620  M. Kelsey -- Improved diagnostic messages.  Simplify kinematics
41//              of recoil nucleus.
42// 20100622  M. Kelsey -- Use local "bindingEnergy()" to call through.
43// 20100623  M. Kelsey -- Undo G4NucleiModel change from 0617.  Does not work
44//              properly across multiple interactions.
45// 20100627  M. Kelsey -- Protect recoil nucleus energy from floating roundoff
46//              by setting small +ve or -ve values to zero.
47// 20100701  M. Kelsey -- Let excitation energy be handled by G4InuclNuclei,
48//              allow for ground-state recoil (goodCase == true for Eex==0.)
49// 20100702  M. Kelsey -- Negative energy recoil should be rejected
50// 20100706  D. Wright -- Copy "abandoned" cparticles to output list, copy
51//              mesonic "excitons" to output list; should be absorbed, fix up
52//              diagnostic messages.
53// 20100713  M. Kelsey -- Add more diagnostics for Dennis' changes.
54// 20100714  M. Kelsey -- Switch to new G4CascadeColliderBase class, remove
55//              sanity check on afin/zfin (not valid).
56// 20100715  M. Kelsey -- Add diagnostic for ekin_in vs. actual ekin; reduce
57//              KE across Coulomb barrier.  Rearrange end-of-loop if blocks,
58//              add conservation check at end.
59// 20100716  M. Kelsey -- Eliminate inter_case; use base-class functionality.
60//              Add minimum-fragment requirement for recoil, in order to
61//              allow for momentum balancing
62// 20100720  M. Kelsey -- Make EPCollider pointer member
63// 20100721  M. Kelsey -- Turn on conservation checks unconditionally (override
64//              new G4CASCADE_CHECK_ECONS setting
65// 20100722  M. Kelsey -- Move cascade output buffers to .hh file
66// 20100728  M. Kelsey -- Make G4NucleiModel data member for persistence,
67//              delete colliders in destructor
68// 20100906  M. Kelsey -- Hide "non-physical fragment" behind verbose flag
69// 20100907  M. Kelsey -- Add makeResidualFragment function to create object
70// 20100909  M. Kelsey -- Remove all local "fragment" stuff, use RecoilMaker.
71//              move goodCase() to RecoilMaker.
72// 20100910  M. Kelsey -- Use RecoilMaker::makeRecoilFragment().
73// 20100915  M. Kelsey -- Define functions to deal with trapped particles,
74//              move the exciton container to a data member
75// 20100916  M. Kelsey -- Put decay photons directly onto output list
76// 20100921  M. Kelsey -- Migrate to RecoilMaker::makeRecoilNuclei().
77// 20100924  M. Kelsey -- Minor shuffling of post-cascade recoil building.
78//              Create G4Fragment for recoil and store in output.
79
80#include "G4IntraNucleiCascader.hh"
81#include "G4CascadParticle.hh"
82#include "G4CascadeRecoilMaker.hh"
83#include "G4ElementaryParticleCollider.hh"
84#include "G4CollisionOutput.hh"
85#include "G4DecayTable.hh"
86#include "G4DecayProducts.hh"
87#include "G4HadTmpUtil.hh"
88#include "G4InuclElementaryParticle.hh"
89#include "G4InuclNuclei.hh"
90#include "G4InuclSpecialFunctions.hh"
91#include "G4LorentzConvertor.hh"
92#include "G4NucleiModel.hh"
93#include "G4ParticleLargerEkin.hh"
94#include "Randomize.hh"
95#include <algorithm>
96
97using namespace G4InuclSpecialFunctions;
98
99
100typedef std::vector<G4InuclElementaryParticle>::iterator particleIterator;
101
102G4IntraNucleiCascader::G4IntraNucleiCascader()
103  : G4CascadeColliderBase("G4IntraNucleiCascader"),
104    model(new G4NucleiModel),
105    theElementaryParticleCollider(new G4ElementaryParticleCollider),
106    theRecoilMaker(new G4CascadeRecoilMaker) {}
107
108G4IntraNucleiCascader::~G4IntraNucleiCascader() {
109  delete model;
110  delete theElementaryParticleCollider;
111  delete theRecoilMaker;
112}
113
114
115void G4IntraNucleiCascader::collide(G4InuclParticle* bullet,
116                                    G4InuclParticle* target,
117                                    G4CollisionOutput& globalOutput) {
118  if (verboseLevel) G4cout << " >>> G4IntraNucleiCascader::collide " << G4endl;
119
120  const G4int itry_max = 1000;
121  const G4int reflection_cut = 500;
122
123  const G4double small_ekin = 0.001*MeV;        // Tolerance for round-off zero
124  const G4double quasielast_cut = 1*MeV;        // To recover elastic scatters
125
126  // Configure processing modules
127  model->setVerboseLevel(verboseLevel);
128  theElementaryParticleCollider->setVerboseLevel(verboseLevel);
129  theRecoilMaker->setVerboseLevel(verboseLevel);
130  theRecoilMaker->setTolerance(small_ekin);
131
132  // Energy/momentum conservation usually requires a recoiling nuclear fragment
133  // This cut will be increased on each "itry" if momentum could not balance.
134  G4double minimum_recoil_A = 0.;               // Nuclear fragment required
135
136  if (verboseLevel > 3) {
137    bullet->printParticle();
138    target->printParticle();
139  }
140
141  G4InuclNuclei* tnuclei = dynamic_cast<G4InuclNuclei*>(target);
142  if (!tnuclei) {
143    if (verboseLevel)
144      G4cerr << " Target is not a nucleus.  Abandoning." << G4endl;
145    return;
146  }
147
148  interCase.set(bullet,target);         // Classify collision type
149
150  model->generateModel(tnuclei);
151
152  G4double coulombBarrier = 0.00126*tnuclei->getZ()/
153                                      (1.+G4cbrt(tnuclei->getA()));
154
155  G4LorentzVector momentum_in = bullet->getMomentum() + target->getMomentum();
156
157  if (verboseLevel > 3) {
158    model->printModel();
159    G4cout << " intitial momentum  E " << momentum_in.e() << " Px "
160           << momentum_in.x() << " Py " << momentum_in.y() << " Pz "
161           << momentum_in.z() << G4endl;
162  }
163
164  // Bullet may be nucleus or simple particle
165  G4InuclNuclei* bnuclei = dynamic_cast<G4InuclNuclei*>(bullet);
166  G4InuclElementaryParticle* bparticle = 
167                          dynamic_cast<G4InuclElementaryParticle*>(bullet);
168
169  G4int itry = 0;
170  while (itry < itry_max) {
171    itry++;
172    if (verboseLevel > 2) {
173      G4cout << " itry " << itry << " inter_case " << interCase.code()
174             << G4endl;
175    }
176
177    model->reset();                     // Start new cascade process
178    output.reset();
179    cascad_particles.clear();
180    output_particles.clear();
181    theExitonConfiguration.clear();
182
183    if (interCase.hadNucleus()) {               // particle with nuclei
184      if (verboseLevel > 3)
185        G4cout << " bparticle charge " << bparticle->getCharge()
186               << " baryon number " << bparticle->baryon() << G4endl;
187
188      cascad_particles.push_back(model->initializeCascad(bparticle));
189    } else {                            // nuclei with nuclei
190      G4int ab = bnuclei->getA();
191      G4int zb = bnuclei->getZ();
192
193      G4NucleiModel::modelLists all_particles;    // Buffer to receive lists
194      model->initializeCascad(bnuclei, tnuclei, all_particles);
195
196      cascad_particles = all_particles.first;
197
198      output_particles.insert(output_particles.end(),
199                              all_particles.second.begin(),
200                              all_particles.second.end());
201
202      if (cascad_particles.size() == 0) { // compound nuclei
203        G4int i;
204
205        for (i = 0; i < ab; i++) {
206          G4int knd = i < zb ? 1 : 2;
207          theExitonConfiguration.incrementQP(knd);
208        };
209
210        G4int ihn = G4int(2 * (ab-zb) * inuclRndm() + 0.5);
211        G4int ihz = G4int(2 * zb * inuclRndm() + 0.5);
212
213        for (i = 0; i < ihn; i++) theExitonConfiguration.incrementHoles(2);
214        for (i = 0; i < ihz; i++) theExitonConfiguration.incrementHoles(1);
215      }
216    }   // if (interCase ...
217
218    new_cascad_particles.clear();
219    G4int iloop = 0;
220
221    while (!cascad_particles.empty() && !model->empty()) {
222      iloop++;
223
224      if (verboseLevel > 2) {
225        G4cout << " Iteration " << iloop << ": Number of cparticles "
226               << cascad_particles.size() << " last one: " << G4endl;
227        cascad_particles.back().print();
228      }
229
230      new_cascad_particles = model->generateParticleFate(cascad_particles.back(),
231                                                        theElementaryParticleCollider);
232      if (verboseLevel > 2) {
233        G4cout << " After generate fate: New particles "
234               << new_cascad_particles.size() << G4endl
235               << " Discarding last cparticle from list " << G4endl;
236      }
237
238      cascad_particles.pop_back();
239
240      // handle the result of a new step
241
242      if (new_cascad_particles.size() == 1) { // last particle goes without interaction
243        const G4CascadParticle& currentCParticle = new_cascad_particles[0];
244
245        if (model->stillInside(currentCParticle)) {
246          if (verboseLevel > 3)
247            G4cout << " particle still inside nucleus " << G4endl;
248
249          if (currentCParticle.getNumberOfReflections() < reflection_cut &&
250              model->worthToPropagate(currentCParticle)) {
251            if (verboseLevel > 3) G4cout << " continue reflections " << G4endl;
252            cascad_particles.push_back(currentCParticle);
253          } else {
254            processTrappedParticle(currentCParticle);
255          }     // reflection or exciton
256
257        } else { // particle about to leave nucleus - check for Coulomb barrier
258          if (verboseLevel > 3) G4cout << " possible escape " << G4endl;
259
260          const G4InuclElementaryParticle& currentParticle =
261            currentCParticle.getParticle();
262
263          G4double KE = currentParticle.getKineticEnergy();
264          G4double mass = currentParticle.getMass();
265          G4double Q = currentParticle.getCharge();
266
267          if (verboseLevel > 3)
268            G4cout << " KE " << KE << " barrier " << Q*coulombBarrier << G4endl;
269
270          if (KE < Q*coulombBarrier) {
271            // Calculate barrier penetration
272            G4double CBP = 0.0; 
273
274            // if (KE > 0.0001) CBP = std::exp(-0.00126*tnuclei->getZ()*0.25*
275            //   (1./KE - 1./coulombBarrier));
276            if (KE > 0.0001) CBP = std::exp(-0.0181*0.5*tnuclei->getZ()*
277                                            (1./KE - 1./coulombBarrier)*
278                                         std::sqrt(mass*(coulombBarrier-KE)) );
279
280            if (G4UniformRand() < CBP) {
281              if (verboseLevel > 3) {
282                G4cout << " tunneled " << G4endl;
283                currentParticle.printParticle();
284              }
285              // Tunnelling through barrier leaves KE unchanged
286              output_particles.push_back(currentParticle);
287            } else {
288              processTrappedParticle(currentCParticle);
289            }
290          } else {
291            if (verboseLevel > 3) G4cout << " Goes out " << G4endl;
292
293            output_particles.push_back(currentParticle);
294
295            /*****
296            // Adjust kinetic energy by height of potential (+ve or -ve)
297            G4double newKE = KE - Q*coulombBarrier;
298            output_particles.back().setKineticEnergy(newKE);
299            *****/
300
301            if (verboseLevel > 3) output_particles.back().printParticle();
302          }
303        } 
304      } else { // interaction
305        if (verboseLevel > 3)
306          G4cout << " interacted, adding new to list " << G4endl;
307
308        cascad_particles.insert(cascad_particles.end(),
309                                new_cascad_particles.begin(),
310                                new_cascad_particles.end());
311
312        std::pair<G4int, G4int> holes = model->getTypesOfNucleonsInvolved();
313        if (verboseLevel > 3)
314          G4cout << " adding new exciton holes " << holes.first << ","
315                 << holes.second << G4endl;
316
317        theExitonConfiguration.incrementHoles(holes.first);
318
319        if (holes.second > 0)
320          theExitonConfiguration.incrementHoles(holes.second);
321      }         // if (new_cascad_particles ...
322
323      // Evaluate nuclear residue
324      theRecoilMaker->collide(bullet,target,output_particles,cascad_particles);
325
326      G4double aresid = theRecoilMaker->getRecoilA();
327      if (verboseLevel > 2) {
328        G4cout << " cparticles remaining " << cascad_particles.size()
329               << " nucleus (model) has "
330               << model->getNumberOfNeutrons() << " n, "
331               << model->getNumberOfProtons() << " p "
332               << " residual fragment A " << aresid << G4endl;
333      }
334
335      if (aresid <= minimum_recoil_A) break;    // Must have minimum fragment
336    }           // while cascade-list and model
337
338    // Add left-over cascade particles to output
339    for (G4int i = 0; i < G4int(cascad_particles.size()); i++)
340      output_particles.push_back(cascad_particles[i].getParticle());
341 
342    // Cascade is finished. Check if it's OK.
343    if (verboseLevel > 3) {
344      G4cout << " Cascade finished  " << G4endl
345             << " output_particles  " << output_particles.size() <<  G4endl;
346
347      particleIterator ipart = output_particles.begin();
348      for (; ipart != output_particles.end(); ipart++) {
349        ipart->printParticle();
350        G4cout << "  charge " << ipart->getCharge() << " baryon number "
351               << ipart->baryon() << G4endl;
352      }
353    }
354
355    // Use last created recoil fragment instead of re-constructing
356    G4int afin = theRecoilMaker->getRecoilA();
357    G4int zfin = theRecoilMaker->getRecoilZ();
358
359    // Sanity check before proceeding
360    if (!theRecoilMaker->goodFragment() && !theRecoilMaker->wholeEvent()) {
361      if (verboseLevel > 1)
362        G4cerr << " Recoil nucleus is not physical: A=" << afin << " Z="
363               << zfin << G4endl;
364      continue;                         // Discard event and try again
365    }
366
367    const G4LorentzVector& presid = theRecoilMaker->getRecoilMomentum();
368
369    if (verboseLevel > 1) {
370      G4cout << "  afin " << afin << " zfin " << zfin <<  G4endl;
371    }
372
373    if (afin == 0) break;               // Whole event fragmented, exit
374
375    if (afin == 1) {                    // Add bare nucleon to particle list
376      G4int last_type = (zfin==1) ? 1 : 2;      // proton=1, neutron=2
377
378      G4double mass = G4InuclElementaryParticle::getParticleMass(last_type);
379      G4double mres = presid.m();
380
381      // Check for sensible kinematics
382      if (mres-mass < -small_ekin) {            // Insufficient recoil energy
383        if (verboseLevel > 2) G4cerr << " unphysical recoil nucleon" << G4endl;
384        continue;
385      }
386
387      if (mres-mass > small_ekin) {             // Too much extra energy
388        if (verboseLevel > 2)
389          G4cerr << " extra energy with recoil nucleon" << G4endl;
390
391        // FIXME:  For now, we add the nucleon as unbalanced, and let
392        //         "SetOnShell" fudge things.  This should be abandoned.
393      }
394
395      G4InuclElementaryParticle last_particle(presid, last_type, 4);
396
397      if (verboseLevel > 3) {
398        G4cout << " adding recoiling nucleon to output list" << G4endl;
399        last_particle.printParticle();
400      }
401
402      output_particles.push_back(last_particle);
403    }
404
405    // Process recoil fragment for consistency, exit or reject
406    if (output_particles.size() == 1) {
407      G4double Eex = theRecoilMaker->getRecoilExcitation();
408      if (std::abs(Eex) < quasielast_cut) {
409        if (verboseLevel > 3) {
410          G4cout << " quasi-elastic scatter with " << Eex << " MeV recoil"
411                 << G4endl;
412        }
413       
414        theRecoilMaker->setRecoilExcitation(Eex=0.);
415        if (verboseLevel > 3) {
416          G4cout << " Eex reset to " << theRecoilMaker->getRecoilExcitation()
417                 << G4endl;
418        }
419      }
420    }
421   
422    if (theRecoilMaker->goodNucleus()) {
423      theRecoilMaker->addExcitonConfiguration(theExitonConfiguration);
424   
425      G4Fragment* recoilFrag = theRecoilMaker->makeRecoilFragment();
426      if (!recoilFrag) {
427        G4cerr << "Got null pointer for recoil fragment!" << G4endl;
428        continue;
429      }
430      output.addRecoilFragment(*recoilFrag);
431
432      // TEMPORARY:  Add both frag and nuclei, for code validation
433      G4InuclNuclei* recoilNucl = theRecoilMaker->makeRecoilNuclei(4);
434      if (!recoilFrag) {
435        G4cerr << "Got null pointer for recoil nucleus!" << G4endl;
436        continue;
437      }
438      output.addOutgoingNucleus(*recoilNucl);
439     
440      if (verboseLevel > 2)
441        G4cout << " adding recoil nucleus/fragment to output list" << G4endl;
442    }
443
444    // Put final-state particle in "leading order" for return
445    std::sort(output_particles.begin(), output_particles.end(), G4ParticleLargerEkin());
446    output.addOutgoingParticles(output_particles);
447
448    // Adjust final state without fragment to balance momentum and energy
449    if (afin <= 1) {
450      output.setVerboseLevel(verboseLevel);
451      output.setOnShell(bullet, target);
452      output.setVerboseLevel(0);
453
454      if (output.acceptable()) break;
455    } else if (theRecoilMaker->goodNucleus()) break;
456
457    // Cascade not physically reasonable
458    if (afin <= minimum_recoil_A && minimum_recoil_A < tnuclei->getA()) {
459      ++minimum_recoil_A;
460      if (verboseLevel > 3) {
461        G4cout << " minimum recoil fragment increased to A " << minimum_recoil_A
462               << G4endl;
463      }
464    }
465  }     // while (itry < itry_max)
466
467  // Cascade completed, for good or ill
468  if (itry == itry_max) {
469    if (verboseLevel > 3) {
470      G4cout << " IntraNucleiCascader-> no inelastic interaction after "
471             << itry_max << " attempts " << G4endl;
472    }
473
474    output.trivialise(bullet, target);
475  } else if (verboseLevel) {
476    G4cout << " IntraNucleiCascader output after trials " << itry << G4endl;
477  }
478
479  // Copy final generated cascade to output buffer for return
480  globalOutput.add(output);
481  return;
482}
483
484
485// Convert particles which cannot escape into excitons (or eject/decay them)
486
487void G4IntraNucleiCascader::
488processTrappedParticle(const G4CascadParticle& trapped) {
489  const G4InuclElementaryParticle& trappedP = trapped.getParticle();
490
491  G4int xtype = trappedP.type();
492  if (verboseLevel > 3) G4cout << " exciton of type " << xtype << G4endl;
493 
494  if (trappedP.nucleon()) {     // normal exciton (proton or neutron)
495    theExitonConfiguration.incrementQP(xtype);
496    return;
497  }
498
499  if (trappedP.hyperon()) {     // Not nucleon, so must be hyperon
500    decayTrappedParticle(trapped);
501    return;
502  }
503
504  // non-standard exciton; release it
505  // FIXME: this is a meson, so need to absorb it
506  if (verboseLevel > 3) {
507    G4cout << " non-standard should be absorbed, now released" << G4endl;
508    trapped.print();
509  }
510 
511  output_particles.push_back(trappedP);
512}
513
514
515// Decay unstable trapped particles, and add secondaries to processing list
516
517void G4IntraNucleiCascader::
518decayTrappedParticle(const G4CascadParticle& trapped) {
519  if (verboseLevel > 3) 
520    G4cout << " unstable must be decayed in flight" << G4endl;
521
522  const G4InuclElementaryParticle& trappedP = trapped.getParticle();
523
524  G4DecayTable* unstable = trappedP.getDefinition()->GetDecayTable();
525  if (!unstable) {                      // No decay table; cannot decay!
526    if (verboseLevel > 3)
527      G4cerr << " no decay table!  Releasing trapped particle" << G4endl;
528
529    output_particles.push_back(trappedP);
530    return;
531  }
532
533  // Get secondaries from decay in particle's rest frame
534  G4DecayProducts* daughters = unstable->SelectADecayChannel()->DecayIt();
535  if (!daughters) {                     // No final state; cannot decay!
536    if (verboseLevel > 3)
537      G4cerr << " no daughters from trapped particle decay" << G4endl;
538
539    output_particles.push_back(trappedP);
540    return;
541  }
542
543  if (verboseLevel > 3) daughters->DumpInfo();
544
545  // Convert secondaries to lab frame
546  G4double decayEnergy = trappedP.getEnergy();
547  G4ThreeVector decayDir = trappedP.getMomentum().vect().unit();
548  daughters->Boost(decayEnergy, decayDir);
549
550  // Put all the secondaries onto the list for propagation
551  const G4ThreeVector& decayPos = trapped.getPosition();
552  G4int zone = trapped.getCurrentZone();
553  G4int gen = trapped.getGeneration()+1;
554
555  for (G4int i=0; i<daughters->entries(); i++) {
556    G4DynamicParticle* idaug = (*daughters)[i];
557
558    G4InuclElementaryParticle idaugEP(*idaug, 4);
559
560    // Only hadronic secondaries can be propagated; photons escape
561    if (idaugEP.isPhoton()) output_particles.push_back(idaugEP);
562    else {
563      G4CascadParticle idaugCP(idaugEP, decayPos, zone, 0., gen);
564      cascad_particles.push_back(idaugCP);
565    }
566  }
567}
Note: See TracBrowser for help on using the repository browser.