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

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

update ti head

File size: 17.7 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: G4CollisionOutput.cc,v 1.37 2010/10/19 19:48:34 mkelsey Exp $
26// Geant4 tag: $Name: hadr-casc-V09-03-85 $
27//
28// 20100114  M. Kelsey -- Remove G4CascadeMomentum, use G4LorentzVector directly
29// 20100309  M. Kelsey -- Introduced bug checking i3 for valid tuning pair
30// 20100409  M. Kelsey -- Move non-inlinable code here out of .hh file, replace
31//              loop over push_back() with block insert().
32// 20100418  M. Kelsey -- Add function to boost output lists to lab frame
33// 20100520  M. Kelsey -- Add function to rotate Z axis, from G4Casc.Interface
34// 20100620  M. Kelsey -- Add some diagnostics in setOnShell, simplify if's
35// 20100630  M. Kelsey -- Use "getExcitationEnergyInGeV()" instead of ".001*"
36// 20100701  M. Kelsey -- G4InuclNuclei now includes excitation energy as part
37//              of the reported mass and four-vector.
38// 20100714  M. Kelsey -- Modify setOnShell() to avoid creating particles
39//              with negative kinetic energy.
40// 20100715  M. Kelsey -- Add total charge and baryon number functions, and a
41//              combined "add()" function to put two of these together
42// 20100924  M. Kelsey -- Use "OutgoingNuclei" name consistently, replacing
43//              old "TargetFragment".  Add new (reusable) G4Fragment buffer
44//              and access functions for initial post-cascade processing.
45//              Move implementation of add() to .cc file.
46// 20101019  M. Kelsey -- CoVerity report: unitialized constructor
47
48#include "G4CollisionOutput.hh"
49#include "G4CascadParticle.hh"
50#include "G4ParticleLargerEkin.hh"
51#include "G4LorentzConvertor.hh"
52#include "G4LorentzRotation.hh"
53#include "G4ReactionProductVector.hh"
54#include "G4ReactionProduct.hh"
55#include <algorithm>
56
57typedef std::vector<G4InuclElementaryParticle>::iterator particleIterator;
58typedef std::vector<G4InuclNuclei>::iterator nucleiIterator;
59
60
61G4CollisionOutput::G4CollisionOutput()
62  : verboseLevel(0), eex_rest(0), on_shell(false) {
63  if (verboseLevel > 1)
64    G4cout << " >>> G4CollisionOutput::G4CollisionOutput" << G4endl;
65}
66
67
68G4CollisionOutput& G4CollisionOutput::operator=(const G4CollisionOutput& right)
69{
70  if (this != &right) {
71    verboseLevel = right.verboseLevel;
72    outgoingParticles = right.outgoingParticles;
73    outgoingNuclei = right.outgoingNuclei; 
74    theRecoilFragment = right.theRecoilFragment;
75    eex_rest = right.eex_rest;
76    on_shell = right.on_shell;
77  }
78  return *this;
79}
80
81void G4CollisionOutput::reset() {
82  outgoingNuclei.clear();
83  outgoingParticles.clear();
84
85  static const G4Fragment emptyFragment;        // Default ctor is all zeros
86  theRecoilFragment = emptyFragment;
87}
88
89
90// Merge two complete objects
91
92void G4CollisionOutput::add(const G4CollisionOutput& right) {
93  addOutgoingParticles(right.outgoingParticles);
94  addOutgoingNuclei(right.outgoingNuclei);
95  theRecoilFragment = right.theRecoilFragment;
96}
97
98
99// Append to lists
100
101void G4CollisionOutput::addOutgoingParticles(const std::vector<G4InuclElementaryParticle>& particles) {
102  outgoingParticles.insert(outgoingParticles.end(),
103                           particles.begin(), particles.end());
104}
105
106void G4CollisionOutput::addOutgoingNuclei(const std::vector<G4InuclNuclei>& nuclea) {
107  outgoingNuclei.insert(outgoingNuclei.end(), nuclea.begin(), nuclea.end());
108}
109
110// These are primarily for G4IntraNucleiCascader internal checks
111
112void G4CollisionOutput::addOutgoingParticle(const G4CascadParticle& cparticle) {
113  addOutgoingParticle(cparticle.getParticle());
114}
115
116void G4CollisionOutput::addOutgoingParticles(const std::vector<G4CascadParticle>& cparticles) {
117  for (unsigned i=0; i<cparticles.size(); i++)
118    addOutgoingParticle(cparticles[i].getParticle());
119}
120
121// This comes from PreCompound de-excitation, both particles and nuclei
122
123void G4CollisionOutput::addOutgoingParticles(const G4ReactionProductVector* rproducts) {
124  if (!rproducts) return;               // Sanity check, no error if null
125
126  G4ReactionProductVector::const_iterator j;
127  for (j=rproducts->begin(); j!=rproducts->end(); ++j) {
128    G4ParticleDefinition* pd = (*j)->GetDefinition();
129
130    // FIXME:  This is expensive and unnecessary copying!
131    G4DynamicParticle aFragment(pd, (*j)->GetMomentum());
132   
133    // Nucleons and nuclei are jumbled together in the list
134    if (G4InuclElementaryParticle::type(pd)) {
135      addOutgoingParticle(G4InuclElementaryParticle(aFragment, 9));
136    } else {
137      addOutgoingNucleus(G4InuclNuclei(aFragment, 9));
138    }
139  }
140}
141
142
143G4LorentzVector G4CollisionOutput::getTotalOutputMomentum() const {
144  if (verboseLevel > 1)
145    G4cout << " >>> G4CollisionOutput::getTotalOutputMomentum" << G4endl;
146
147  G4LorentzVector tot_mom;
148  G4int i(0);
149  for(i=0; i < G4int(outgoingParticles.size()); i++) {
150    tot_mom += outgoingParticles[i].getMomentum();
151  }
152  for(i=0; i < G4int(outgoingNuclei.size()); i++) {
153    tot_mom += outgoingNuclei[i].getMomentum();
154  }
155  return tot_mom;
156}
157
158G4int G4CollisionOutput::getTotalCharge() const {
159  if (verboseLevel > 1)
160    G4cout << " >>> G4CollisionOutput::getTotalCharge" << G4endl;
161
162  G4int charge = 0;
163  G4int i(0);
164  for(i=0; i < G4int(outgoingParticles.size()); i++) {
165    charge += G4int(outgoingParticles[i].getCharge());
166  }
167  for(i=0; i < G4int(outgoingNuclei.size()); i++) {
168    charge += G4int(outgoingNuclei[i].getCharge());
169  }
170  return charge;
171}
172
173G4int G4CollisionOutput::getTotalBaryonNumber() const {
174  if (verboseLevel > 1)
175    G4cout << " >>> G4CollisionOutput::getTotalBaryonNumber" << G4endl;
176
177  G4int baryon = 0;
178  G4int i(0);
179  for(i=0; i < G4int(outgoingParticles.size()); i++) {
180    baryon += outgoingParticles[i].baryon();
181  }
182  for(i=0; i < G4int(outgoingNuclei.size()); i++) {
183    baryon += G4int(outgoingNuclei[i].getA());
184  }
185  return baryon;
186}
187
188
189void G4CollisionOutput::printCollisionOutput() const {
190  G4cout << " Output: " << G4endl
191         << " Outgoing Particles: " << outgoingParticles.size() << G4endl;
192
193  G4int i(0);
194  for(i=0; i < G4int(outgoingParticles.size()); i++)
195    outgoingParticles[i].printParticle(); 
196
197  G4cout << " Outgoing Nuclei: " << outgoingNuclei.size() << G4endl;     
198  for(i=0; i < G4int(outgoingNuclei.size()); i++)
199    outgoingNuclei[i].printParticle();
200
201  if (theRecoilFragment.GetA() > 0) {
202    G4cout << theRecoilFragment << G4endl;
203  }
204}
205
206
207// Boost particles and fragment to LAB -- "convertor" must already be configured
208
209void G4CollisionOutput::boostToLabFrame(const G4LorentzConvertor& convertor) {
210  if (verboseLevel > 1)
211    G4cout << " >>> G4CollisionOutput::boostToLabFrame" << G4endl;
212
213  G4bool withReflection = convertor.reflectionNeeded();
214
215  if (!outgoingParticles.empty()) { 
216    particleIterator ipart = outgoingParticles.begin();
217    for(; ipart != outgoingParticles.end(); ipart++) {
218      G4LorentzVector mom = ipart->getMomentum();
219     
220      if (withReflection) mom.setZ(-mom.z());
221      mom = convertor.rotate(mom);
222      mom = convertor.backToTheLab(mom);
223      ipart->setMomentum(mom); 
224    }
225
226    std::sort(outgoingParticles.begin(), outgoingParticles.end(), G4ParticleLargerEkin());
227  }
228 
229  if (!outgoingNuclei.empty()) { 
230    nucleiIterator inuc = outgoingNuclei.begin();
231   
232    for (; inuc != outgoingNuclei.end(); inuc++) {
233      G4LorentzVector mom = inuc->getMomentum(); 
234     
235      if (withReflection) mom.setZ(-mom.z());
236      mom = convertor.rotate(mom);
237      mom = convertor.backToTheLab(mom);
238      inuc->setMomentum(mom);
239    }
240  }
241}
242
243
244// Apply LorentzRotation to all particles in event
245
246void G4CollisionOutput::rotateEvent(const G4LorentzRotation& rotate) {
247  if (verboseLevel > 1)
248    G4cout << " >>> G4CollisionOutput::rotateEvent" << G4endl;
249
250  particleIterator ipart = outgoingParticles.begin();
251  for(; ipart != outgoingParticles.end(); ipart++)
252    ipart->setMomentum(ipart->getMomentum()*=rotate);
253
254  nucleiIterator inuc = outgoingNuclei.begin();
255  for (; inuc != outgoingNuclei.end(); inuc++)
256    inuc->setMomentum(inuc->getMomentum()*=rotate);
257}
258
259
260void G4CollisionOutput::trivialise(G4InuclParticle* bullet, 
261                                   G4InuclParticle* target) {
262  if (verboseLevel > 1)
263    G4cout << " >>> G4CollisionOutput::trivialize" << G4endl;
264
265  if (G4InuclNuclei* nuclei_target = dynamic_cast<G4InuclNuclei*>(target)) {
266    outgoingNuclei.push_back(*nuclei_target);
267  } else {
268    G4InuclElementaryParticle* particle =
269      dynamic_cast<G4InuclElementaryParticle*>(target);
270    outgoingParticles.push_back(*particle);
271  }
272
273  if (G4InuclNuclei* nuclei_bullet = dynamic_cast<G4InuclNuclei*>(bullet)) {
274    outgoingNuclei.push_back(*nuclei_bullet);
275  } else {
276    G4InuclElementaryParticle* particle =
277      dynamic_cast<G4InuclElementaryParticle*>(bullet);
278    outgoingParticles.push_back(*particle);
279  }
280}
281
282
283void G4CollisionOutput::setOnShell(G4InuclParticle* bullet, 
284                                   G4InuclParticle* target) {
285  if (verboseLevel > 1)
286    G4cout << " >>> G4CollisionOutput::setOnShell" << G4endl;
287
288  const G4double accuracy = 0.00001; // momentum concerves at the level of 10 keV
289
290  on_shell = false;
291   
292  G4LorentzVector ini_mom = bullet->getMomentum();
293  G4LorentzVector momt = target->getMomentum();
294
295  ini_mom += momt;
296 
297  G4LorentzVector out_mom = getTotalOutputMomentum();
298  if(verboseLevel > 2){
299    G4cout << " bullet momentum = " << ini_mom.e() <<", "<< ini_mom.x() <<", "<< ini_mom.y()<<", "<< ini_mom.z()<<G4endl;
300    G4cout << " target momentum = " << momt.e()<<", "<< momt.x()<<", "<< momt.y()<<", "<< momt.z()<<G4endl;
301    G4cout << " Fstate momentum = " << out_mom.e()<<", "<< out_mom.x()<<", "<< out_mom.y()<<", "<< out_mom.z()<<G4endl;
302  }
303
304  G4LorentzVector mon_non_cons = ini_mom - out_mom;
305
306  G4double pnc = mon_non_cons.rho();
307  G4double enc = mon_non_cons.e();
308
309  setRemainingExitationEnergy();       
310
311  if(verboseLevel > 2){
312    printCollisionOutput();
313    G4cout << " momentum non conservation: " << G4endl
314           << " e " << enc << " p " << pnc << G4endl;
315    G4cout << " remaining exitation " << eex_rest << G4endl;
316  }
317
318  if(std::fabs(enc) <= accuracy && pnc <= accuracy) {
319    on_shell = true;
320    return;
321  }
322
323  // Adjust "last" particle's four-momentum to balance event
324  // ONLY adjust particles with sufficient e or p to remain physical!
325
326  if (verboseLevel > 2) G4cout << " re-balancing four-momenta" << G4endl;
327
328  G4int npart = outgoingParticles.size();
329  G4int nnuc = outgoingNuclei.size();
330  if (npart > 0) {
331    for (G4int ip=npart-1; ip>=0; ip--) {
332      if (outgoingParticles[ip].getKineticEnergy()+enc > 0.) {
333        G4LorentzVector last_mom = outgoingParticles[ip].getMomentum(); 
334        last_mom += mon_non_cons;
335        outgoingParticles[ip].setMomentum(last_mom);
336        break;
337      }
338    }
339  } else if (nnuc > 0) {
340    for (G4int in=nnuc-1; in>=0; in--) {
341      if (outgoingNuclei[in].getKineticEnergy()+enc > 0.) {
342        G4LorentzVector last_mom = outgoingNuclei[in].getMomentum();
343        last_mom += mon_non_cons;
344        outgoingNuclei[in].setMomentum(last_mom);
345        break;
346      }
347    }
348  }
349
350  out_mom = getTotalOutputMomentum();
351  mon_non_cons = ini_mom - out_mom;
352  pnc = mon_non_cons.rho();
353  enc = mon_non_cons.e();
354
355  if(verboseLevel > 2){
356    printCollisionOutput();
357    G4cout << " momentum non conservation after (1): " << G4endl
358           << " e " << enc << " p " << pnc << G4endl;
359  }
360
361  // Can energy be balanced just with nuclear excitation?
362  G4bool need_hard_tuning = true;
363 
364  G4double encMeV = mon_non_cons.e() / GeV;     // Excitation below is in MeV
365  if (outgoingNuclei.size() > 0) {
366    for (G4int i=0; i < G4int(outgoingNuclei.size()); i++) {
367      G4double eex = outgoingNuclei[i].getExitationEnergy();
368     
369      if(eex > 0.0 && eex + encMeV >= 0.0) {
370        outgoingNuclei[i].setExitationEnergy(eex+encMeV);
371        need_hard_tuning = false;
372        break;
373      }
374    }
375    if (need_hard_tuning && encMeV > 0.) {
376      outgoingNuclei[0].setExitationEnergy(encMeV);
377      need_hard_tuning = false;
378    }
379  }
380 
381  if (!need_hard_tuning) {
382    on_shell = true;
383    return;
384  }
385
386  // Momentum (hard) tuning required for energy conservation
387  if (verboseLevel > 2)
388    G4cout << " trying hard (particle-pair) tuning" << G4endl;
389
390  std::pair<std::pair<G4int, G4int>, G4int> tune_par = selectPairToTune(mon_non_cons.e());
391  std::pair<G4int, G4int> tune_particles = tune_par.first;
392  G4int mom_ind = tune_par.second;
393 
394  if(verboseLevel > 2) {
395    G4cout << " p1 " << tune_particles.first << " p2 " << tune_particles.second
396           << " ind " << mom_ind << G4endl;
397  }
398
399  G4bool tuning_possible = 
400    (tune_particles.first >= 0 && tune_particles.second >= 0 &&
401     mom_ind >= G4LorentzVector::X);
402
403  if (!tuning_possible) {
404    if (verboseLevel > 2) G4cout << " tuning impossible " << G4endl;
405    return;
406  }
407   
408  G4LorentzVector mom1 = outgoingParticles[tune_particles.first].getMomentum();
409  G4LorentzVector mom2 = outgoingParticles[tune_particles.second].getMomentum();
410  G4double newE12 = mom1.e() + mom2.e() + mon_non_cons.e();
411  G4double R = 0.5 * (newE12 * newE12 + mom2.e() * mom2.e() - mom1.e() * mom1.e()) / newE12;
412  G4double Q = -(mom1[mom_ind] + mom2[mom_ind]) / newE12;
413  G4double UDQ = 1.0 / (Q * Q - 1.0);
414  G4double W = (R * Q + mom2[mom_ind]) * UDQ;
415  G4double V = (mom2.e() * mom2.e() - R * R) * UDQ;
416  G4double DET = W * W + V;
417 
418  if (DET < 0.0) {
419    if (verboseLevel > 2) G4cout << " DET < 0 " << G4endl;
420    return;
421  }
422
423  // Tuning allowed only for non-negative determinant
424  G4double x1 = -(W + std::sqrt(DET));
425  G4double x2 = -(W - std::sqrt(DET));
426 
427  // choose the appropriate solution
428  G4bool xset = false;
429  G4double x = 0.0;
430 
431  if(mon_non_cons.e() > 0.0) { // x has to be > 0.0
432    if(x1 > 0.0) {
433      if(R + Q * x1 >= 0.0) {
434        x = x1;
435        xset = true;
436      };
437    }; 
438    if(!xset && x2 > 0.0) {
439      if(R + Q * x2 >= 0.0) {
440        x = x2;
441        xset = true;
442      };
443    };
444  } else { 
445    if(x1 < 0.0) {
446      if(R + Q * x1 >= 0.) {
447        x = x1;
448        xset = true;
449      };
450    }; 
451    if(!xset && x2 < 0.0) {
452      if(R + Q * x2 >= 0.0) {
453        x = x2;
454        xset = true;
455      };
456    };
457  }     // if(mon_non_cons.e() > 0.0)
458 
459  if(!xset) {
460    if(verboseLevel > 2)
461      G4cout << " no appropriate solution found " << G4endl;
462    return;
463  }     // if(xset)
464
465  // retune momentums
466  mom1[mom_ind] += x;
467  mom2[mom_ind] -= x;
468  outgoingParticles[tune_particles.first ].setMomentum(mom1);
469  outgoingParticles[tune_particles.second].setMomentum(mom2);
470  out_mom = getTotalOutputMomentum();
471  std::sort(outgoingParticles.begin(), outgoingParticles.end(), G4ParticleLargerEkin());
472  mon_non_cons = ini_mom - out_mom;
473  pnc = mon_non_cons.rho();
474  enc = mon_non_cons.e();
475
476  on_shell = (std::fabs(enc) < accuracy || pnc < accuracy);
477
478  if(verboseLevel > 2) {
479    G4cout << " momentum non conservation tuning: " << G4endl
480           << " e " << enc << " p " << pnc
481           << (on_shell?" success":" FAILURE") << G4endl;
482  }
483}
484
485
486
487void G4CollisionOutput::setRemainingExitationEnergy() { 
488  eex_rest = 0.0;
489  for(G4int i=0; i < G4int(outgoingNuclei.size()); i++) 
490    eex_rest += outgoingNuclei[i].getExitationEnergyInGeV();
491}
492
493
494std::pair<std::pair<G4int, G4int>, G4int> 
495G4CollisionOutput::selectPairToTune(G4double de) const {
496  if (verboseLevel > 2)
497    G4cout << " >>> G4CollisionOutput::selectPairToTune" << G4endl;
498
499  std::pair<G4int, G4int> tup(-1, -1);
500  G4int i3 = -1; 
501  std::pair<std::pair<G4int, G4int>, G4int> tuner(tup, i3);     // Set invalid
502
503  if (outgoingParticles.size() < 2) return tuner;       // Nothing to do
504
505  G4int ibest1 = -1;
506  G4int ibest2 = -1; 
507  G4double pbest = 0.0;
508  G4double pcut = 0.3 * std::sqrt(1.88 * std::fabs(de));
509  G4double p1 = 0.0;
510  G4double p2;
511 
512  for (G4int i = 0; i < G4int(outgoingParticles.size())-1; i++) {
513    G4LorentzVector mom1 = outgoingParticles[i].getMomentum();
514   
515    for (G4int j = i+1; j < G4int(outgoingParticles.size()); j++) {
516      G4LorentzVector mom2 = outgoingParticles[j].getMomentum();
517     
518      for (G4int l = G4LorentzVector::X; l<=G4LorentzVector::Z; l++) {
519        if (mom1[l]*mom2[l]<0.0) { 
520          if (std::fabs(mom1[l])>pcut && std::fabs(mom2[l])>pcut) {
521            G4double psum = std::fabs(mom1[l]) + std::fabs(mom2[l]); 
522           
523            if(psum > pbest) {
524              ibest1 = i;
525              ibest2 = j;
526              i3 = l;
527              p1 = mom1[l];
528              p2 = mom2[l];
529              pbest = psum;
530            }   // psum > pbest
531          }     // mom1 and mom2 > pcut
532        }       // mom1 ~ -mom2
533      } // for (G4int l ...
534    }   // for (G4int j ...
535  }     // for (G4int i ...
536
537  if (i3 < 0) return tuner;             
538 
539  tuner.second = i3;            // Momentum axis for tuning
540 
541  // NOTE: Sign of de determines order for special case of p1==0.
542  if (de > 0.0) {
543    tuner.first.first  = (p1>0.) ? ibest1 : ibest2;
544    tuner.first.second = (p1>0.) ? ibest2 : ibest1;
545  } else {
546    tuner.first.first  = (p1<0.) ? ibest2 : ibest1;
547    tuner.first.second = (p1<0.) ? ibest1 : ibest2;
548  }             
549 
550  return tuner;
551}
Note: See TracBrowser for help on using the repository browser.