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

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

update ti head

File size: 16.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: G4CascadeInterface.cc,v 1.104 2010/09/24 21:09:01 mkelsey Exp $
26// Geant4 tag: $Name: hadr-casc-V09-03-85 $
27//
28// 20100114  M. Kelsey -- Remove G4CascadeMomentum, use G4LorentzVector directly
29// 20100413  M. Kelsey -- Pass G4CollisionOutput by ref to ::collide()
30// 20100414  M. Kelsey -- Check for K0L/K0S before using G4InuclElemPart::type
31// 20100418  M. Kelsey -- Reference output particle lists via const-ref, use
32//              const_iterator for both.
33// 20100428  M. Kelsey -- Use G4InuclParticleNames enum
34// 20100429  M. Kelsey -- Change "case gamma:" to "case photon:"
35// 20100517  M. Kelsey -- Follow new ctors for G4*Collider family.
36// 20100520  M. Kelsey -- Simplify collision loop, move momentum rotations to
37//              G4CollisionOutput, copy G4DynamicParticle directly from
38//              G4InuclParticle, no switch-block required.
39// 20100615  M. Kelsey -- Bug fix: For K0's need ekin in GEANT4 units
40// 20100617  M. Kelsey -- Rename "debug_" preprocessor flag to G4CASCADE_DEBUG,
41//              and "BERTDEV" to "G4CASCADE_COULOMB_DEV"
42// 20100617  M. Kelsey -- Make G4InuclCollider a local data member
43// 20100618  M. Kelsey -- Deploy energy-conservation test on final state, with
44//              preprocessor flag G4CASCADE_SKIP_ECONS to skip test.
45// 20100620  M. Kelsey -- Use new energy-conservation pseudo-collider
46// 20100621  M. Kelsey -- Fix compiler warning from GCC 4.5
47// 20100624  M. Kelsey -- Fix cascade loop to check nTries every time (had
48//              allowed for infinite loop on E-violation); dump event data
49//              to output if E-violation exceeds maxTries; use CheckBalance
50//              for baryon and charge conservation.
51// 20100701  M. Kelsey -- Pass verbosity through to G4CollisionOutput
52// 20100714  M. Kelsey -- Report number of iterations before success
53// 20100720  M. Kelsey -- Use G4CASCADE_SKIP_ECONS flag for reporting
54// 20100723  M. Kelsey -- Move G4CollisionOutput to .hh file for reuse
55// 20100914  M. Kelsey -- Migrate to integer A and Z
56// 20100916  M. Kelsey -- Simplify ApplyYourself() by encapsulating code blocks
57//              into numerous functions; make data-member colliders pointers;
58//              provide support for projectile nucleus
59// 20100919  M. Kelsey -- Fix incorrect logic in retryInelasticNucleus()
60// 20100922  M. Kelsey -- Add functions to select de-excitation method
61// 20100924  M. Kelsey -- Migrate to "OutgoingNuclei" names in CollisionOutput
62
63#include "G4CascadeInterface.hh"
64#include "globals.hh"
65#include "G4CascadeCheckBalance.hh"
66#include "G4CollisionOutput.hh"
67#include "G4DynamicParticle.hh"
68#include "G4HadronicException.hh"
69#include "G4InuclCollider.hh"
70#include "G4InuclElementaryParticle.hh"
71#include "G4InuclNuclei.hh"
72#include "G4InuclParticle.hh"
73#include "G4InuclParticleNames.hh"
74#include "G4KaonZeroLong.hh"
75#include "G4KaonZeroShort.hh"
76#include "G4Nucleus.hh"
77#include "G4ParticleDefinition.hh"
78#include "G4Track.hh"
79#include "G4V3DNucleus.hh"
80#include <cmath>
81
82using namespace G4InuclParticleNames;
83
84typedef std::vector<G4InuclElementaryParticle>::const_iterator particleIterator;
85typedef std::vector<G4InuclNuclei>::const_iterator nucleiIterator;
86
87
88// Maximum number of iterations allowed for inelastic collision attempts
89
90const G4int G4CascadeInterface::maximumTries = 100;
91
92
93// Constructor and destrutor
94
95G4CascadeInterface::G4CascadeInterface(const G4String& name)
96  : G4VIntraNuclearTransportModel(name),
97    verboseLevel(0), numberOfTries(0),
98    collider(new G4InuclCollider), 
99    balance(new G4CascadeCheckBalance(0.05, 0.1, name)),
100    bullet(0), target(0), output(new G4CollisionOutput) {
101  initializeElasticCuts();
102}
103
104G4CascadeInterface::~G4CascadeInterface() {
105  delete collider; collider=0;
106  delete balance; balance=0;
107  delete bullet; bullet=0;
108  delete target; target=0;
109  delete output; output=0;
110}
111
112// Fill sparse array with minimum momenta for inelastic on hydrogen
113
114void G4CascadeInterface::initializeElasticCuts() {
115  cutElastic[proton   ]   = 1.0;        // Bertini uses GeV for everything
116  cutElastic[neutron  ]   = 1.0;
117  cutElastic[pionPlus ]   = 0.6;
118  cutElastic[pionMinus]   = 0.2;
119  cutElastic[pionZero ]   = 0.2;
120  cutElastic[kaonPlus ]   = 0.5;
121  cutElastic[kaonMinus]   = 0.5;
122  cutElastic[kaonZero]    = 0.5;
123  cutElastic[kaonZeroBar] = 0.5;
124  cutElastic[lambda]      = 1.0;
125  cutElastic[sigmaPlus]   = 1.0;
126  cutElastic[sigmaZero]   = 1.0;
127  cutElastic[sigmaMinus]  = 1.0;
128  cutElastic[xiZero]      = 1.0;
129  cutElastic[xiMinus]     = 1.0;
130}
131
132
133// Select post-cascade processing (default will be CascadeDeexcitation)
134// NOTE:  Currently just calls through to Collider, in future will do something
135
136void G4CascadeInterface::useCascadeDeexcitation() {
137  collider->useCascadeDeexcitation();
138}
139
140void G4CascadeInterface::usePreCompoundDeexcitation() {
141  collider->usePreCompoundDeexcitation();
142}
143
144// Main Actions
145
146G4ReactionProductVector* 
147G4CascadeInterface::Propagate(G4KineticTrackVector*, G4V3DNucleus* ) {
148  return 0;
149}
150
151G4HadFinalState* 
152G4CascadeInterface::ApplyYourself(const G4HadProjectile& aTrack, 
153                                  G4Nucleus& theNucleus) {
154  if (verboseLevel)
155    G4cout << " >>> G4CascadeInterface::ApplyYourself" << G4endl;
156
157#ifdef G4CASCADE_DEBUG_INTERFACE
158  static G4int counter(0);
159  counter++;
160  G4cerr << "Reaction number "<< counter << " "
161         << aTrack.GetDefinition()->GetParticleName() << " "
162         << aTrack.GetKineticEnergy() << G4endl;
163#endif
164
165  theResult.Clear();
166
167  // Make conversion between native Geant4 and Bertini cascade classes.
168  // NOTE: Geant4 units are MeV = 1 and GeV = 1000. Cascade code by default use GeV = 1.
169
170  createBullet(aTrack);
171  createTarget(theNucleus);
172
173  if (verboseLevel > 2) {
174    G4cout << "Bullet:  " << G4endl; 
175    bullet->printParticle();
176    G4cout << "Target:  " << G4endl; 
177    target->printParticle();
178  }
179
180  // Colliders initialisation
181  collider->setVerboseLevel(verboseLevel);
182  balance->setVerboseLevel(verboseLevel);
183  output->setVerboseLevel(verboseLevel);
184
185  numberOfTries = 0;
186
187  // special treatment for target H(1,1) (proton)
188  if (theNucleus.GetA_asInt() == 1) {
189    G4int btype = dynamic_cast<G4InuclElementaryParticle*>(bullet)->type();
190
191    if (bullet->getMomModule() <= cutElastic[btype]) {
192      collider->collide(bullet, target, *output);       // Only elastic
193    } else {
194      do {                      // we try to create inelastic interaction
195        if (verboseLevel > 1)
196          G4cout << " Generating cascade attempt " << numberOfTries << G4endl;
197
198        output->reset();
199        collider->collide(bullet, target, *output);
200        balance->collide(bullet, target, *output);
201
202        numberOfTries++;
203      } while(retryInelasticProton());
204    }
205  } else {                      // treat all other targets excepet H(1,1)
206    do {                        // we try to create inelastic interaction
207      if (verboseLevel > 1)
208        G4cout << " Generating cascade attempt " << numberOfTries << G4endl;
209
210      output->reset();
211      collider->collide(bullet, target, *output);
212      balance->collide(bullet, target, *output);
213
214      numberOfTries++;
215    } while (retryInelasticNucleus());
216  }
217
218  // Check whether repeated attempts have all failed; report and exit
219  if (numberOfTries >= maximumTries && !balance->okay()) {
220    throwNonConservationFailure();      // This terminates the job
221  }
222
223  // Successful cascade -- clean up and return
224  if (verboseLevel) {
225    G4cout << " Cascade output after trials " << numberOfTries << G4endl;
226    if (verboseLevel > 1) output->printCollisionOutput();
227  }
228
229  // Rotate event to put Z axis along original projectile direction
230  output->rotateEvent(bulletInLabFrame);
231
232  copyOutputToHadronicResult();
233
234  // Report violations of conservation laws in original frame
235  balance->collide(bullet, target, *output);
236
237  if (verboseLevel > 2) {
238    if (!balance->baryonOkay()) {
239      G4cerr << "ERROR: no baryon number conservation, sum of baryons = "
240             << balance->deltaB() << G4endl;
241    }
242
243    if (!balance->chargeOkay()) {
244      G4cerr << "ERROR: no charge conservation, sum of charges = "
245             << balance->deltaQ() << G4endl;
246    }
247
248    if (std::abs(balance->deltaKE()) > 0.01 ) { // GeV
249      G4cerr << "Kinetic energy conservation violated by "
250             << balance->deltaKE() << " GeV" << G4endl;
251    }
252
253    G4double eInit = bullet->getEnergy() + target->getEnergy();
254    G4double eFinal = eInit + balance->deltaE();
255
256    G4cout << "Initial energy " << eInit << " final energy " << eFinal
257           << "\nTotal energy conservation at level "
258           << balance->deltaE() * GeV << " MeV" << G4endl;
259   
260    if (balance->deltaKE() > 5.0e-5 ) {         // 0.05 MeV
261      G4cerr << "FATAL ERROR: kinetic energy created  "
262             << balance->deltaKE() * GeV << " MeV" << G4endl;
263    }
264  }
265
266  delete bullet; bullet=0;
267  delete target; target=0;
268
269  return &theResult;
270}
271
272
273// Convert input projectile to Bertini internal object
274
275void G4CascadeInterface::createBullet(const G4HadProjectile& aTrack) {
276  const G4ParticleDefinition* trkDef = aTrack.GetDefinition();
277
278  G4int bulletType = 0;                 // For elementary particles
279  G4int bulletA = 0, bulletZ = 0;       // For nucleus projectile
280
281  if (trkDef->GetAtomicMass() <= 1) {
282    if (trkDef == G4KaonZeroLong::KaonZeroLong() ||
283        trkDef == G4KaonZeroShort::KaonZeroShort() )
284      bulletType = (G4UniformRand() > 0.5) ? kaonZero : kaonZeroBar;
285    else 
286      bulletType = G4InuclElementaryParticle::type(trkDef);
287  } else {
288    bulletA = trkDef->GetAtomicMass();
289    bulletZ = trkDef->GetAtomicNumber();
290  }
291
292  // Code momentum and energy -- Bertini wants z-axis and GeV units
293  G4LorentzVector projectileMomentum = aTrack.Get4Momentum()/GeV;
294 
295  // Rrotation/boost to get from z-axis back to original frame
296  bulletInLabFrame = G4LorentzRotation::IDENTITY;       // Initialize
297  bulletInLabFrame.rotateZ(-projectileMomentum.phi());
298  bulletInLabFrame.rotateY(-projectileMomentum.theta());
299  bulletInLabFrame.invert();
300 
301  G4LorentzVector momentumBullet(0., 0., projectileMomentum.rho(),
302                                 projectileMomentum.e());
303
304  if (bulletType > 0)
305    bullet = new G4InuclElementaryParticle(momentumBullet, bulletType);
306  else
307    bullet = new G4InuclNuclei(momentumBullet, bulletA, bulletZ);
308
309  return;
310}
311
312
313// Convert input nuclear target to Bertini internal object
314
315void G4CascadeInterface::createTarget(G4Nucleus& theNucleus) {
316  G4int theNucleusA = theNucleus.GetA_asInt();
317  G4int theNucleusZ = theNucleus.GetZ_asInt();
318
319  if (theNucleusA == 1)
320    target = new G4InuclElementaryParticle((theNucleusZ==1)?proton:neutron);
321  else
322    target = new G4InuclNuclei(theNucleusA, theNucleusZ);
323
324  return;
325}
326
327
328// Transfer Bertini internal final state to hadronics interface
329
330void G4CascadeInterface::copyOutputToHadronicResult() {
331  const std::vector<G4InuclNuclei>& outgoingNuclei = output->getOutgoingNuclei();
332  const std::vector<G4InuclElementaryParticle>& particles = output->getOutgoingParticles();
333
334  theResult.SetStatusChange(stopAndKill);
335
336  // Get outcoming particles
337  G4DynamicParticle* cascadeParticle = 0;
338
339  if (!particles.empty()) { 
340    particleIterator ipart = particles.begin();
341    for (; ipart != particles.end(); ipart++) {
342      G4int outgoingType = ipart->type();
343
344      if (!ipart->valid() || ipart->quasi_deutron()) {
345        G4cerr << " ERROR: G4CascadeInterface::ApplyYourself incompatible"
346               << " particle type " << outgoingType << G4endl;
347        continue;
348      }
349
350      // Copy local G4DynPart to public output (handle kaon mixing specially)
351      if (outgoingType == kaonZero || outgoingType == kaonZeroBar) {
352        G4ThreeVector momDir = ipart->getMomentum().vect().unit();
353        G4double ekin = ipart->getKineticEnergy()*GeV;  // Bertini -> G4 units
354
355        G4ParticleDefinition* pd = G4KaonZeroShort::Definition();
356        if (G4UniformRand() > 0.5) pd = G4KaonZeroLong::Definition();
357
358        cascadeParticle = new G4DynamicParticle(pd, momDir, ekin);
359      } else {
360        cascadeParticle = new G4DynamicParticle(ipart->getDynamicParticle());
361      }
362
363      theResult.AddSecondary(cascadeParticle); 
364    }
365  }
366
367  // get nuclei fragments
368  G4DynamicParticle * aFragment = 0;
369  if (!outgoingNuclei.empty()) { 
370    nucleiIterator ifrag = outgoingNuclei.begin();
371    for (; ifrag != outgoingNuclei.end(); ifrag++) {
372      if (verboseLevel > 2) {
373        G4cout << " Nuclei fragment: " << G4endl;
374        ifrag->printParticle();
375      }
376     
377      // Copy local G4DynPart to public output
378      aFragment =  new G4DynamicParticle(ifrag->getDynamicParticle());
379      theResult.AddSecondary(aFragment); 
380    }
381  }
382}
383
384
385// Evaluate whether any outgoing particles penetrated Coulomb barrier
386
387G4bool G4CascadeInterface::coulombBarrierViolation() const {
388  G4bool violated = false;              // by default coulomb analysis is OK
389
390  const G4double coulumbBarrier = 8.7 * MeV/GeV;        // Bertini uses GeV
391
392  const std::vector<G4InuclElementaryParticle>& p =
393    output->getOutgoingParticles();
394
395  for (particleIterator ipart=p.begin(); ipart != p.end(); ipart++) {
396    if (ipart->type() == proton) {
397      violated |= (ipart->getKineticEnergy() < coulumbBarrier);
398    }
399  }
400
401  return violated;
402}
403
404// Check whether inelastic collision on proton failed
405
406G4bool G4CascadeInterface::retryInelasticProton() const {
407  const std::vector<G4InuclElementaryParticle>& out =
408    output->getOutgoingParticles();
409
410  return ( (numberOfTries < maximumTries) &&
411           (out.size() == 2) &&
412           (out[0].getDefinition() == bullet->getDefinition() ||
413            out[1].getDefinition() == bullet->getDefinition())
414           );
415}
416
417// Check whether generic inelastic collision failed
418// NOTE:  some conditions are set by compiler flags
419
420G4bool G4CascadeInterface::retryInelasticNucleus() const {
421  // Quantities necessary for conditional block below
422  G4int npart = output->numberOfOutgoingParticles();
423  G4int nfrag = output->numberOfOutgoingNuclei();
424
425  const G4ParticleDefinition* firstOut = (npart == 0) ? 0 :
426    output->getOutgoingParticles().begin()->getDefinition();
427
428  return ( ((numberOfTries < maximumTries) &&
429            (npart != 0) &&
430#ifdef G4CASCADE_COULOMB_DEV
431            (coulombBarrierViolation() && npart+nfrag > 2)
432#else
433            (npart+nfrag < 3 && firstOut == bullet->getDefinition())
434#endif
435            )
436#ifndef G4CASCADE_SKIP_ECONS
437           || (!balance->okay())
438#endif
439           );
440}
441
442
443// Terminate job in case of persistent non-conservation
444
445void G4CascadeInterface::throwNonConservationFailure() {
446  G4cerr << " >>> G4CascadeInterface::ApplyYourself()\n has non-conserving"
447         << " cascade after " << numberOfTries << " attempts." << G4endl;
448
449  G4String throwMsg = "G4CascadeInterface::ApplyYourself() - ";
450  if (!balance->energyOkay()) {
451    throwMsg += "Energy";
452    G4cerr << " Energy conservation violated by " << balance->deltaE()
453           << " GeV (" << balance->relativeE() << ")" << G4endl;
454  }
455 
456  if (!balance->momentumOkay()) {
457    throwMsg += "Momentum";
458    G4cerr << " Momentum conservation violated by " << balance->deltaP()
459           << " GeV/c (" << balance->relativeP() << ")" << G4endl;
460  }
461 
462  if (!balance->baryonOkay()) {
463    throwMsg += "Baryon number";
464    G4cerr << " Baryon number violated by " << balance->deltaB() << G4endl;
465  }
466 
467  if (!balance->chargeOkay()) {
468    throwMsg += "Charge";
469    G4cerr << " Charge conservation violated by " << balance->deltaB()
470           << G4endl;
471  }
472 
473  G4cout << "\n Final event output, for debugging:"
474         << "\n Bullet:  " << G4endl; 
475  bullet->printParticle();
476  G4cout << "\n Target:  " << G4endl; 
477  target->printParticle();
478 
479  output->printCollisionOutput();
480 
481  throwMsg += " non-conservation. More info in output.";
482  throw G4HadronicException(__FILE__, __LINE__, throwMsg);   // Job ends here!
483}
Note: See TracBrowser for help on using the repository browser.