Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4CollisionOutput.cc
Go to the documentation of this file.
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//
27// 20100114 M. Kelsey -- Remove G4CascadeMomentum, use G4LorentzVector directly
28// 20100309 M. Kelsey -- Introduced bug checking i3 for valid tuning pair
29// 20100409 M. Kelsey -- Move non-inlinable code here out of .hh file, replace
30// loop over push_back() with block insert().
31// 20100418 M. Kelsey -- Add function to boost output lists to lab frame
32// 20100520 M. Kelsey -- Add function to rotate Z axis, from G4Casc.Interface
33// 20100620 M. Kelsey -- Add some diagnostics in setOnShell, simplify if's
34// 20100630 M. Kelsey -- Use "getExcitationEnergyInGeV()" instead of ".001*"
35// 20100701 M. Kelsey -- G4InuclNuclei now includes excitation energy as part
36// of the reported mass and four-vector.
37// 20100714 M. Kelsey -- Modify setOnShell() to avoid creating particles
38// with negative kinetic energy.
39// 20100715 M. Kelsey -- Add total charge and baryon number functions, and a
40// combined "add()" function to put two of these together
41// 20100924 M. Kelsey -- Use "OutgoingNuclei" name consistently, replacing
42// old "TargetFragment". Add new (reusable) G4Fragment buffer
43// and access functions for initial post-cascade processing.
44// Move implementation of add() to .cc file.
45// 20101019 M. Kelsey -- CoVerity report: unitialized constructor
46// 20110214 M. Kelsey -- Follow G4InuclParticle::Model enumerator migration
47// 20110225 M. Kelsey -- Add non-const functions to remove list elements
48// 20110302 M. Kelsey -- Fix message in setOnShell() by moving ini_mom calc
49// 20110307 M. Kelsey -- Need to discard existing ouput lists in trivialize()
50// 20110311 M. Kelsey -- Include nuclear fragment in setOnShell balancing,
51// including calculation of final-state momentum
52// 20110519 M. Kelsey -- Drop unused "p2" variable from selectPairToTune()
53// 20110801 M. Kelsey -- Use resize to avoid temporaries when copying from
54// G4ReactionProductVector
55// 20110922 M. Kelsey -- Follow G4InuclParticle::print(ostream&) migration,
56// Add optional stream argument to printCollisionOutput
57// 20121002 M. Kelsey -- Add strangeness calculation
58// 20130628 M. Kelsey -- Support multiple recoil fragments (for G4Fissioner)
59// 20141208 M. Kelsey -- Split function to do pair-wise "hard" tuning
60
61#include <algorithm>
62
63#include "G4CollisionOutput.hh"
64#include "G4SystemOfUnits.hh"
66#include "G4CascadParticle.hh"
68#include "G4Electron.hh"
70#include "G4LorentzConvertor.hh"
71#include "G4LorentzRotation.hh"
72#include "G4LorentzVector.hh"
74#include "G4ReactionProduct.hh"
75#include "G4ThreeVector.hh"
76
77typedef std::vector<G4InuclElementaryParticle>::iterator particleIterator;
78typedef std::vector<G4InuclNuclei>::iterator nucleiIterator;
79typedef std::vector<G4Fragment>::iterator fragmentIterator;
80
81const G4Fragment G4CollisionOutput::emptyFragment; // All zeros
82
83
85 : verboseLevel(0), eex_rest(0), on_shell(false) {
86 if (verboseLevel > 1)
87 G4cout << " >>> G4CollisionOutput::G4CollisionOutput" << G4endl;
88}
89
90
92{
93 if (this != &right) {
94 verboseLevel = right.verboseLevel;
95 outgoingParticles = right.outgoingParticles;
96 outgoingNuclei = right.outgoingNuclei;
97 recoilFragments = right.recoilFragments;
98 eex_rest = right.eex_rest;
99 on_shell = right.on_shell;
100 }
101 return *this;
102}
103
105 outgoingNuclei.clear();
106 outgoingParticles.clear();
107 recoilFragments.clear();
108 eex_rest = 0.;
109 on_shell = false;
110}
111
112
113// Get requested recoil fragment from list, or return dummy version
114
116 return ( (index >= 0 && index < numberOfFragments())
117 ? recoilFragments[index] : emptyFragment);
118}
119
120
121// Merge two complete objects
122
124 addOutgoingParticles(right.outgoingParticles);
125 addOutgoingNuclei(right.outgoingNuclei);
126 recoilFragments = right.recoilFragments; // Replace, don't combine
127 eex_rest = 0.;
128 on_shell = false;
129}
130
131
132// Append to lists
133
134void G4CollisionOutput::addOutgoingParticles(const std::vector<G4InuclElementaryParticle>& particles) {
135 outgoingParticles.insert(outgoingParticles.end(),
136 particles.begin(), particles.end());
137}
138
139void G4CollisionOutput::addOutgoingNuclei(const std::vector<G4InuclNuclei>& nuclea) {
140 outgoingNuclei.insert(outgoingNuclei.end(), nuclea.begin(), nuclea.end());
141}
142
143// These are primarily for G4IntraNucleiCascader internal checks
144
146 addOutgoingParticle(cparticle.getParticle());
147}
148
149void G4CollisionOutput::addOutgoingParticles(const std::vector<G4CascadParticle>& cparticles) {
150 for (unsigned i=0; i<cparticles.size(); i++)
151 addOutgoingParticle(cparticles[i]);
152}
153
154// This comes from PreCompound de-excitation, both particles and nuclei
155
157 if (!rproducts) return; // Sanity check, no error if null
158
159 if (verboseLevel) {
160 G4cout << " >>> G4CollisionOutput::addOutgoingParticles(G4RPVector)"
161 << G4endl;
162 }
163
164 G4ReactionProductVector::const_iterator j;
165 for (j=rproducts->begin(); j!=rproducts->end(); ++j) {
166 const G4ParticleDefinition* pd = (*j)->GetDefinition();
168
169 // FIXME: Momentum returned by value; extra copying here!
170 G4LorentzVector mom((*j)->GetMomentum(), (*j)->GetTotalEnergy());
171 mom /= GeV; // Convert from GEANT4 to Bertini units
172
173 if (verboseLevel>1)
174 G4cout << " Processing " << pd->GetParticleName() << " (" << type
175 << "), momentum " << mom << " GeV" << G4endl;
176
177 // Nucleons and nuclei are jumbled together in the list
178 // NOTE: Resize and set/fill avoid unnecessary temporary copies
179 if (type) {
180 outgoingParticles.resize(numberOfOutgoingParticles()+1);
181 outgoingParticles.back().fill(mom, pd, G4InuclParticle::PreCompound);
182
183 if (verboseLevel>1) G4cout << outgoingParticles.back() << G4endl;
184 } else {
185 outgoingNuclei.resize(numberOfOutgoingNuclei()+1);
186 outgoingNuclei.back().fill(mom,pd->GetAtomicMass(),pd->GetAtomicNumber(),
188
189 if (verboseLevel>1) G4cout << outgoingNuclei.back() << G4endl;
190 }
191 }
192}
193
194
195// Removing elements from lists by index
196
198 if (index >= 0 && index < numberOfOutgoingParticles())
199 outgoingParticles.erase(outgoingParticles.begin()+(size_t)index);
200}
201
203 if (index >= 0 && index < numberOfOutgoingNuclei())
204 outgoingNuclei.erase(outgoingNuclei.begin()+(size_t)index);
205}
206
207// Remove elements from list by reference, or by value comparison
208
210 particleIterator pos =
211 std::find(outgoingParticles.begin(), outgoingParticles.end(), particle);
212 if (pos != outgoingParticles.end()) outgoingParticles.erase(pos);
213}
214
216 nucleiIterator pos =
217 std::find(outgoingNuclei.begin(), outgoingNuclei.end(), nuclei);
218 if (pos != outgoingNuclei.end()) outgoingNuclei.erase(pos);
219}
220
221// Remove specified recoil fragment(s) from buffer
222
224 if (index < 0) recoilFragments.clear();
225 else if (index < numberOfFragments())
226 recoilFragments.erase(recoilFragments.begin()+(size_t)index);
227}
228
229
230// Kinematics of final state, for recoil and conservation checks
231
233 if (verboseLevel > 1)
234 G4cout << " >>> G4CollisionOutput::getTotalOutputMomentum" << G4endl;
235
236 G4LorentzVector tot_mom;
237 G4int i(0);
238 for(i=0; i < numberOfOutgoingParticles(); i++) {
239 tot_mom += outgoingParticles[i].getMomentum();
240 }
241 for(i=0; i < numberOfOutgoingNuclei(); i++) {
242 tot_mom += outgoingNuclei[i].getMomentum();
243 }
244 for(i=0; i < numberOfFragments(); i++) {
245 tot_mom += recoilFragments[i].GetMomentum()/GeV; // Need Bertini units!
246 }
247
248 return tot_mom;
249}
250
252 if (verboseLevel > 1)
253 G4cout << " >>> G4CollisionOutput::getTotalCharge" << G4endl;
254
255 G4int charge = 0;
256 G4int i(0);
257
258 for (i = 0; i < numberOfOutgoingParticles(); i++)
259 charge += G4int(outgoingParticles[i].getCharge());
260
261 for (i = 0; i < numberOfOutgoingNuclei(); i++)
262 charge += G4int(outgoingNuclei[i].getCharge());
263
264 for (i = 0; i < numberOfFragments(); i++)
265 charge += recoilFragments[i].GetZ_asInt();
266
267 return charge;
268}
269
270
272 if (verboseLevel > 1)
273 G4cout << " >>> G4CollisionOutput::getTotalBaryonNumber" << G4endl;
274
275 G4int baryon = 0;
276 G4int i(0);
277 for(i=0; i < numberOfOutgoingParticles(); i++) {
278 baryon += outgoingParticles[i].baryon();
279 }
280 for(i=0; i < numberOfOutgoingNuclei(); i++) {
281 baryon += G4int(outgoingNuclei[i].getA());
282 }
283 for(i=0; i < numberOfFragments(); i++) {
284 baryon += recoilFragments[i].GetA_asInt();
285 }
286
287 return baryon;
288}
289
291 if (verboseLevel > 1)
292 G4cout << " >>> G4CollisionOutput::getTotalStrangeness" << G4endl;
293
294 G4int strange = 0;
295 G4int i(0);
296 for(i=0; i < numberOfOutgoingParticles(); i++) {
297 strange += outgoingParticles[i].getStrangeness();
298 }
299
300 return strange;
301}
302
303
304void G4CollisionOutput::printCollisionOutput(std::ostream& os) const {
305 os << " Output: " << G4endl
306 << " Outgoing Particles: " << numberOfOutgoingParticles() << G4endl;
307
308 G4int i(0);
309 for(i=0; i < numberOfOutgoingParticles(); i++)
310 os << outgoingParticles[i] << G4endl;
311
312 os << " Outgoing Nuclei: " << numberOfOutgoingNuclei() << G4endl;
313 for(i=0; i < numberOfOutgoingNuclei(); i++)
314 os << outgoingNuclei[i] << G4endl;
315 for(i=0; i < numberOfFragments(); i++)
316 os << recoilFragments[i] << G4endl;
317}
318
319
320// Boost particles and fragment to LAB -- "convertor" must already be configured
321
323 if (verboseLevel > 1)
324 G4cout << " >>> G4CollisionOutput::boostToLabFrame" << G4endl;
325
326 particleIterator ipart = outgoingParticles.begin();
327 for(; ipart != outgoingParticles.end(); ipart++) {
328 ipart->setMomentum(boostToLabFrame(ipart->getMomentum(), convertor));
329 }
330
331 std::sort(outgoingParticles.begin(), outgoingParticles.end(),
333
334 nucleiIterator inuc = outgoingNuclei.begin();
335 for (; inuc != outgoingNuclei.end(); inuc++) {
336 inuc->setMomentum(boostToLabFrame(inuc->getMomentum(), convertor));
337 }
338
339 // NOTE: Fragment momentum must be converted to and from Bertini units
340 G4LorentzVector fmom;
341 fragmentIterator ifrag = recoilFragments.begin();
342 for (; ifrag != recoilFragments.end(); ifrag++) {
343 fmom = ifrag->GetMomentum() / GeV;
344 ifrag->SetMomentum(boostToLabFrame(fmom, convertor)*GeV);
345 }
346}
347
348// Pass by value to allow direct (internal) manipulation
351 const G4LorentzConvertor& convertor) const {
352 if (convertor.reflectionNeeded()) mom.setZ(-mom.z());
353 mom = convertor.rotate(mom);
354 mom = convertor.backToTheLab(mom);
355
356 return mom;
357}
358
359// Apply LorentzRotation to all particles in event
360
362 if (verboseLevel > 1)
363 G4cout << " >>> G4CollisionOutput::rotateEvent" << G4endl;
364
365 particleIterator ipart = outgoingParticles.begin();
366 for(; ipart != outgoingParticles.end(); ipart++)
367 ipart->setMomentum(ipart->getMomentum()*=rotate);
368
369 nucleiIterator inuc = outgoingNuclei.begin();
370 for (; inuc != outgoingNuclei.end(); inuc++)
371 inuc->setMomentum(inuc->getMomentum()*=rotate);
372
373 fragmentIterator ifrag = recoilFragments.begin();
374 for (; ifrag != recoilFragments.end(); ifrag++) {
375 G4LorentzVector mom = ifrag->GetMomentum(); // Need copy
376 ifrag->SetMomentum(mom*=rotate);
377 }
378}
379
380
382 G4InuclParticle* target) {
383 if (verboseLevel > 1)
384 G4cout << " >>> G4CollisionOutput::trivialize" << G4endl;
385
386 reset(); // Discard existing output, replace with bullet/target
387
388 if (G4InuclNuclei* nuclei_target = dynamic_cast<G4InuclNuclei*>(target)) {
389 outgoingNuclei.push_back(*nuclei_target);
390 } else {
391 G4InuclElementaryParticle* particle =
392 dynamic_cast<G4InuclElementaryParticle*>(target);
393 outgoingParticles.push_back(*particle);
394 }
395
396 if (G4InuclNuclei* nuclei_bullet = dynamic_cast<G4InuclNuclei*>(bullet)) {
397 outgoingNuclei.push_back(*nuclei_bullet);
398 } else {
399 G4InuclElementaryParticle* particle =
400 dynamic_cast<G4InuclElementaryParticle*>(bullet);
401 outgoingParticles.push_back(*particle);
402 }
403}
404
405
407 G4InuclParticle* target) {
408 if (verboseLevel > 1)
409 G4cout << " >>> G4CollisionOutput::setOnShell" << G4endl;
410
411 const G4double accuracy = 0.00001; // momentum concerves at the level of 10 keV
412
413 on_shell = false;
414
415 G4LorentzVector ini_mom = bullet->getMomentum();
416 G4LorentzVector momt = target->getMomentum();
418 if(verboseLevel > 2){
419 G4cout << " bullet momentum = " << ini_mom.e() <<", "<< ini_mom.x() <<", "<< ini_mom.y()<<", "<< ini_mom.z()<<G4endl;
420 G4cout << " target momentum = " << momt.e()<<", "<< momt.x()<<", "<< momt.y()<<", "<< momt.z()<<G4endl;
421 G4cout << " Fstate momentum = " << out_mom.e()<<", "<< out_mom.x()<<", "<< out_mom.y()<<", "<< out_mom.z()<<G4endl;
422 }
423 // correction for internal conversion
424 G4LorentzVector el4mom(0.,0.,0.,electron_mass_c2/GeV);
425 for(G4int i=0; i < numberOfOutgoingParticles(); ++i) {
426 if (outgoingParticles[i].getDefinition() == G4Electron::Electron())
427 momt += el4mom;
428 }
429
430 ini_mom += momt;
431
432 mom_non_cons = ini_mom - out_mom;
433 G4double pnc = mom_non_cons.rho();
434 G4double enc = mom_non_cons.e();
435
437
438 if(verboseLevel > 2) {
440 G4cout << " momentum non conservation: " << G4endl
441 << " e " << enc << " p " << pnc << G4endl
442 << " remaining exitation " << eex_rest << G4endl;
443 }
444
445 if (std::fabs(enc) <= accuracy && pnc <= accuracy) {
446 on_shell = true;
447 return;
448 }
449
450 // Adjust "last" particle's four-momentum to balance event
451 // ONLY adjust particles with sufficient e or p to remain physical!
452
453 if (verboseLevel > 2) G4cout << " re-balancing four-momenta" << G4endl;
454
457 G4int nfrag = numberOfFragments();
458
459 G4LorentzVector last_mom; // Buffer to reduce memory churn
460
461 if (npart > 0) {
462 for (G4int ip=npart-1; ip>=0; ip--) {
463 if (outgoingParticles[ip].getKineticEnergy()+enc > 0.) {
464 last_mom = outgoingParticles[ip].getMomentum();
465 last_mom += mom_non_cons;
466 outgoingParticles[ip].setMomentum(last_mom);
467 break;
468 }
469 }
470 } else if (nnuc > 0) {
471 for (G4int in=nnuc-1; in>=0; in--) {
472 if (outgoingNuclei[in].getKineticEnergy()+enc > 0.) {
473 last_mom = outgoingNuclei[in].getMomentum();
474 last_mom += mom_non_cons;
475 outgoingNuclei[in].setMomentum(last_mom);
476 break;
477 }
478 }
479 } else if (nfrag > 0) {
480 for (G4int ifr=nfrag-1; ifr>=0; ifr--) {
481 // NOTE: G4Fragment does not use Bertini units!
482 last_mom = recoilFragments[ifr].GetMomentum()/GeV;
483 if ((last_mom.e()-last_mom.m())+enc > 0.) {
484 last_mom += mom_non_cons;
485 recoilFragments[ifr].SetMomentum(last_mom*GeV);
486 break;
487 }
488 }
489 }
490
491 // Recompute momentum non-conservation parameters
492 out_mom = getTotalOutputMomentum();
493 mom_non_cons = ini_mom - out_mom;
494 pnc = mom_non_cons.rho();
495 enc = mom_non_cons.e();
496
497 if(verboseLevel > 2){
499 G4cout << " momentum non conservation after (1): " << G4endl
500 << " e " << enc << " p " << pnc << G4endl;
501 }
502
503 // Can energy be balanced just with nuclear excitation?
504 G4bool need_hard_tuning = true;
505
506 G4double encMeV = mom_non_cons.e() / GeV; // Excitation below is in MeV
507 if (nfrag > 0) {
508 for (G4int i=0; i < nfrag; i++) {
509 G4double eex = recoilFragments[0].GetExcitationEnergy();
510 if (eex > 0.0 && eex + encMeV >= 0.0) {
511 // NOTE: G4Fragment doesn't have function to change excitation energy
512 // ==> theRecoilFragment.SetExcitationEnergy(eex+encMeV);
513
514 G4LorentzVector fragMom = recoilFragments[i].GetMomentum();
515 G4double newMass = fragMom.m() + encMeV; // .m() includes eex
516 fragMom.setVectM(fragMom.vect(), newMass);
517 need_hard_tuning = false;
518 break;
519 }
520 }
521 } else if (nnuc > 0) {
522 for (G4int i=0; i < nnuc; i++) {
523 G4double eex = outgoingNuclei[i].getExitationEnergy();
524 if (eex > 0.0 && eex + encMeV >= 0.0) {
525 outgoingNuclei[i].setExitationEnergy(eex+encMeV);
526 need_hard_tuning = false;
527 break;
528 }
529 }
530 if (need_hard_tuning && encMeV > 0.) {
531 outgoingNuclei[0].setExitationEnergy(encMeV);
532 need_hard_tuning = false;
533 }
534 }
535
536 if (!need_hard_tuning) {
537 on_shell = true;
538 return;
539 }
540
541 // Momentum (hard) tuning required for energy conservation
542 if (verboseLevel > 2) {
543 G4cout << " trying hard (particle-pair) tuning" << G4endl;
544 }
545 /*****
546 // Hard tuning of quasielastic particle against nucleus
547 if (npart == 1) {
548 if (verboseLevel > 2)
549 G4cout << " tuning particle 0 against recoil nucleus" << G4endl;
550
551 G4LorentzVector mom1 = outgoingParticles[0].getMomentum();
552 G4LorentzVector mom2 = recoilFragments[0].GetMomentum()/GeV;
553
554 // Preserve momentum direction of outgoing particle
555 G4ThreeVector pdir = mom1.vect().unit();
556
557 // Two-body kinematics (nucleon against nucleus) in overall CM system
558 G4double ecmsq = ini_mom.m2();
559 G4double a = 0.5 * (ecmsq - mom1.m2() - mom2.m2());
560 G4double pmod = std::sqrt((a*a - mom1.m2()*mom2.m2()) / ecmsq);
561
562 mom1.setVectM(pdir*pmod, mom1.m());
563 mom2.setVectM(-pdir*pmod, mom2.m());
564
565 // Boost CM momenta back into lab frame, assign back to particles
566 mom1.boost(-ini_mom.boostVector());
567 mom2.boost(-ini_mom.boostVector());
568
569 outgoingParticles[0].setMomentum(mom1);
570 recoilFragments[0].SetMomentum(mom2*GeV);
571 } else { // Hard tuning using pair of outgoing particles
572 *****/
573 std::pair<std::pair<G4int, G4int>, G4int> tune_par = selectPairToTune(enc);
574 std::pair<G4int, G4int> tune_particles = tune_par.first;
575 G4int mom_ind = tune_par.second;
576
577 G4bool tuning_possible =
578 (tune_particles.first >= 0 && tune_particles.second >= 0 &&
579 mom_ind >= G4LorentzVector::X);
580
581 if (!tuning_possible) {
582 if (verboseLevel > 2) G4cout << " tuning impossible " << G4endl;
583 return;
584 }
585
586 if(verboseLevel > 2) {
587 G4cout << " p1 " << tune_particles.first << " p2 " << tune_particles.second
588 << " ind " << mom_ind << G4endl;
589 }
590
591 G4LorentzVector mom1 = outgoingParticles[tune_particles.first].getMomentum();
592 G4LorentzVector mom2 = outgoingParticles[tune_particles.second].getMomentum();
593
594 if (tuneSelectedPair(mom1, mom2, mom_ind)) {
595 outgoingParticles[tune_particles.first ].setMomentum(mom1);
596 outgoingParticles[tune_particles.second].setMomentum(mom2);
597 }
598 else return;
599 //***** }
600
601 out_mom = getTotalOutputMomentum();
602 std::sort(outgoingParticles.begin(), outgoingParticles.end(), G4ParticleLargerEkin());
603 mom_non_cons = ini_mom - out_mom;
604 pnc = mom_non_cons.rho();
605 enc = mom_non_cons.e();
606
607 on_shell = (std::fabs(enc) < accuracy || pnc < accuracy);
608
609 if(verboseLevel > 2) {
610 G4cout << " momentum non conservation tuning: " << G4endl
611 << " e " << enc << " p " << pnc
612 << (on_shell?" success":" FAILURE") << G4endl;
613 }
614}
615
616
617// Returns excitation energy in GeV
618
620 eex_rest = 0.;
621 G4int i(0);
622 for (i=0; i < numberOfOutgoingNuclei(); i++)
623 eex_rest += outgoingNuclei[i].getExitationEnergyInGeV();
624 for (i=0; i < numberOfFragments(); i++)
625 eex_rest += recoilFragments[i].GetExcitationEnergy() / GeV;
626}
627
628
629std::pair<std::pair<G4int, G4int>, G4int>
630G4CollisionOutput::selectPairToTune(G4double de) const {
631 if (verboseLevel > 2)
632 G4cout << " >>> G4CollisionOutput::selectPairToTune" << G4endl;
633
634 std::pair<G4int, G4int> tup(-1, -1);
635 G4int i3 = -1;
636 std::pair<std::pair<G4int, G4int>, G4int> tuner(tup, i3); // Set invalid
637
638 if (outgoingParticles.size() < 2) return tuner; // Nothing to do
639
640 G4int ibest1 = -1;
641 G4int ibest2 = -1;
642 G4double pbest = 0.0;
643 G4double pcut = 0.3 * std::sqrt(1.88 * std::fabs(de));
644 G4double p1 = 0.0;
645
646 for (G4int i = 0; i < G4int(outgoingParticles.size())-1; i++) {
647 G4LorentzVector mom1 = outgoingParticles[i].getMomentum();
648
649 for (G4int j = i+1; j < G4int(outgoingParticles.size()); j++) {
650 G4LorentzVector mom2 = outgoingParticles[j].getMomentum();
651
652 for (G4int l = G4LorentzVector::X; l<=G4LorentzVector::Z; l++) {
653 if (mom1[l]*mom2[l]<0.0) {
654 if (std::fabs(mom1[l])>pcut && std::fabs(mom2[l])>pcut) {
655 G4double psum = std::fabs(mom1[l]) + std::fabs(mom2[l]);
656
657 if (psum > pbest) {
658 ibest1 = i;
659 ibest2 = j;
660 i3 = l;
661 p1 = mom1[l];
662 pbest = psum;
663 } // psum > pbest
664 } // mom1 and mom2 > pcut
665 } // mom1 ~ -mom2
666 } // for (G4int l ...
667 } // for (G4int j ...
668 } // for (G4int i ...
669
670 if (i3 < 0) return tuner;
671
672 tuner.second = i3; // Momentum axis for tuning
673
674 // NOTE: Sign of de determines order for special case of p1==0.
675 if (de > 0.0) {
676 tuner.first.first = (p1>0.) ? ibest1 : ibest2;
677 tuner.first.second = (p1>0.) ? ibest2 : ibest1;
678 } else {
679 tuner.first.first = (p1<0.) ? ibest2 : ibest1;
680 tuner.first.second = (p1<0.) ? ibest1 : ibest2;
681 }
682
683 return tuner;
684}
685
686
687G4bool G4CollisionOutput::tuneSelectedPair(G4LorentzVector& mom1,
688 G4LorentzVector& mom2,
689 G4int mom_ind) const {
690 if (verboseLevel > 2)
691 G4cout << " >>> G4CollisionOutput::tuneSelectedPair" << G4endl;
692
693 G4double newE12 = mom1.e() + mom2.e() + mom_non_cons.e();
694 G4double R = 0.5 * (newE12*newE12 + mom2.e()*mom2.e() - mom1.e()*mom1.e()) / newE12;
695 G4double Q = -(mom1[mom_ind] + mom2[mom_ind]) / newE12;
696 G4double UDQ = 1.0 / (Q*Q - 1.0);
697 G4double W = (R * Q + mom2[mom_ind]) * UDQ;
698 G4double V = (mom2.e()*mom2.e() - R*R) * UDQ;
699 G4double DET = W*W + V;
700
701 if (DET < 0.0) {
702 if (verboseLevel > 2) G4cout << " DET < 0 : tuning failed" << G4endl;
703 return false;
704 }
705
706 // Tuning allowed only for non-negative determinant
707 G4double x1 = -(W + std::sqrt(DET));
708 G4double x2 = -(W - std::sqrt(DET));
709
710 // choose the appropriate solution
711 G4bool xset = false;
712 G4double x = 0.0;
713
714 if (mom_non_cons.e() > 0.0) { // x has to be > 0.0
715 if (x1 > 0.0) {
716 if (R + Q * x1 >= 0.0) {
717 x = x1;
718 xset = true;
719 }
720 }
721 if (!xset && x2 > 0.0) {
722 if (R + Q * x2 >= 0.0) {
723 x = x2;
724 xset = true;
725 }
726 }
727 } else {
728 if (x1 < 0.0) {
729 if (R + Q * x1 >= 0.) {
730 x = x1;
731 xset = true;
732 }
733 }
734 if (!xset && x2 < 0.0) {
735 if (R + Q * x2 >= 0.0) {
736 x = x2;
737 xset = true;
738 }
739 }
740 } // if(mom_non_cons.e() > 0.0)
741
742 if (!xset) {
743 if (verboseLevel > 2) G4cout << " no appropriate solution found" << G4endl;
744 return false;
745 }
746
747 mom1[mom_ind] += x; // retune momentums
748 mom2[mom_ind] -= x;
749 return true;
750}
std::vector< G4InuclElementaryParticle >::iterator particleIterator
Definition: G4BigBanger.cc:64
std::vector< G4InuclNuclei >::const_iterator nucleiIterator
std::vector< G4InuclNuclei >::iterator nucleiIterator
std::vector< G4Fragment >::iterator fragmentIterator
std::vector< G4InuclElementaryParticle >::iterator particleIterator
std::vector< G4ReactionProduct * > G4ReactionProductVector
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
void setVectM(const Hep3Vector &spatial, double mass)
Hep3Vector vect() const
const G4InuclElementaryParticle & getParticle() const
G4int numberOfOutgoingParticles() const
G4int getTotalStrangeness() const
G4LorentzVector getTotalOutputMomentum() const
G4CollisionOutput & operator=(const G4CollisionOutput &right)
G4int getTotalBaryonNumber() const
void removeRecoilFragment(G4int index=-1)
void boostToLabFrame(const G4LorentzConvertor &convertor)
void rotateEvent(const G4LorentzRotation &rotate)
void removeOutgoingNucleus(G4int index)
void printCollisionOutput(std::ostream &os=G4cout) const
void addOutgoingParticle(const G4InuclElementaryParticle &particle)
G4int getTotalCharge() const
const G4Fragment & getRecoilFragment(G4int index=0) const
void setOnShell(G4InuclParticle *bullet, G4InuclParticle *target)
G4int numberOfOutgoingNuclei() const
void add(const G4CollisionOutput &right)
void trivialise(G4InuclParticle *bullet, G4InuclParticle *target)
void addOutgoingNuclei(const std::vector< G4InuclNuclei > &nuclea)
G4int numberOfFragments() const
void removeOutgoingParticle(G4int index)
void addOutgoingParticles(const std::vector< G4InuclElementaryParticle > &particles)
static G4Electron * Electron()
Definition: G4Electron.cc:93
G4LorentzVector getMomentum() const
G4bool reflectionNeeded() const
G4LorentzVector backToTheLab(const G4LorentzVector &mom) const
G4LorentzVector rotate(const G4LorentzVector &mom) const
G4int GetAtomicNumber() const
G4int GetAtomicMass() const
const G4String & GetParticleName() const
#define W
Definition: crc32.c:84