ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4FissionProductYieldDist.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4FissionProductYieldDist.cc
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  * File: G4FissionProductYieldDist.cc
28  * Author: B. Wendt (wendbryc@isu.edu)
29  *
30  * Created on May 11, 2011, 12:04 PM
31  */
32 
33 /* * * * * * * * * * * * * * * * References * * * * * * * * * * * * * * * *
34  * *
35  * 1. "Systematics of fission fragment total kinetic energy release", *
36  * V. E. Viola, K. Kwiatkowski, and M. Walker, Physical Review C, 31.4, *
37  * April 1985 *
38  * 2. "Reactor Handbook", United States Atomic Energy Commission, *
39  * III.A:Physics, 1962 *
40  * 3. "Properties of the Alpha Particles Emitted in the Spontaneous Fission *
41  * of Cf252", Z. Fraenkel and S. G. Thompson, Physical Review Letters, *
42  * 13.14, October 1964 *
43  * *
44  * * * * * * * * * * * * * * * * References * * * * * * * * * * * * * * * */
45 
46 
47 //#include <ios>
48 //#include <iostream>
49 
50 #include "G4Alpha.hh"
51 #include "G4Gamma.hh"
52 #include "G4Ions.hh"
53 #include "G4Neutron.hh"
54 //#include "G4NeutronHPNames.hh"
55 #include "G4NucleiProperties.hh"
56 #include "G4ParticleTable.hh"
57 #include "G4ThreeVector.hh"
58 #include "Randomize.hh"
59 #include "G4UImanager.hh"
60 #include "globals.hh"
61 #include "G4Exp.hh"
62 #include "G4SystemOfUnits.hh"
63 #include "G4HadFinalState.hh"
64 #include "G4DynamicParticle.hh"
66 #include "G4ReactionProduct.hh"
67 
68 #include "G4ArrayOps.hh"
69 #include "G4ENDFTapeRead.hh"
71 #include "G4FFGDebuggingMacros.hh"
72 #include "G4FFGDefaultValues.hh"
73 #include "G4FFGEnumerations.hh"
74 #include "G4FPYNubarValues.hh"
75 #include "G4FPYSamplingOps.hh"
76 #include "G4FPYTreeStructures.hh"
78 #include "G4Pow.hh"
79 
80 using CLHEP::pi;
81 
84  G4FFGEnumerations::MetaState WhichMetaState,
86  G4FFGEnumerations::YieldType WhichYieldType,
87  std::istringstream& dataStream )
88 : Isotope_(WhichIsotope),
89  MetaState_(WhichMetaState),
90  Cause_(WhichCause),
91  YieldType_(WhichYieldType),
92  Verbosity_(G4FFGDefaultValues::Verbosity)
93 {
95 
96  try
97  {
98  // Initialize the class
99  Initialize(dataStream);
100  } catch (std::exception& e)
101  {
103  throw e;
104  }
105 
107 }
108 
111  G4FFGEnumerations::MetaState WhichMetaState,
113  G4FFGEnumerations::YieldType WhichYieldType,
115  std::istringstream& dataStream)
116 : Isotope_(WhichIsotope),
117  MetaState_(WhichMetaState),
118  Cause_(WhichCause),
119  YieldType_(WhichYieldType),
120  Verbosity_(Verbosity)
121 {
123 
124  try
125  {
126  // Initialize the class
127  Initialize(dataStream);
128  } catch (std::exception& e)
129  {
131  throw e;
132  }
133 
135 }
136 
138 Initialize( std::istringstream& dataStream )
139 {
141 
142  IncidentEnergy_ = 0.0;
144  AlphaProduction_ = 0;
145  SetNubar();
146 
147  // Set miscellaneous variables
148  AlphaDefinition_ = reinterpret_cast<G4Ions*>(G4Alpha::Definition());
149  NeutronDefinition_ = reinterpret_cast<G4Ions*>(G4Neutron::Definition());
152 
153  // Construct G4NeutronHPNames: provides access to the element names
155  // Get the pointer to G4ParticleTable: stores all G4Ions
157  // Construct the pointer to the random engine
158  // TODO Make G4FPSamplingOps a singleton so that only one instance is used across all classes
160 
161  try
162  {
163  // Read in and sort the probability data
164  ENDFData_ = new G4ENDFTapeRead(dataStream,
165  YieldType_,
166  Cause_,
167  Verbosity_);
168 // ENDFData_ = new G4ENDFTapeRead(MakeDirectoryName(),
169 // MakeFileName(Isotope_, MetaState_),
170 // YieldType_,
171 // Cause_);
177  MakeTrees();
179  } catch (std::exception& e)
180  {
181  delete ElementNames_;
182  delete RandomEngine_;
183 
185  throw e;
186  }
187 
189 }
190 
193 {
195 
196  // Check to see if the user has set the alpha production to a somewhat
197  // reasonable level
199 
200  // Generate the new G4DynamicParticle pointers to identify key locations in
201  // the G4DynamicParticle chain that will be passed to the G4FissionEvent
202  G4ReactionProduct* FirstDaughter = NULL;
203  G4ReactionProduct* SecondDaughter = NULL;
204  std::vector< G4ReactionProduct* >* Alphas = new std::vector< G4ReactionProduct* >;
205  std::vector< G4ReactionProduct* >* Neutrons = new std::vector< G4ReactionProduct* >;
206  std::vector< G4ReactionProduct* >* Gammas = new std::vector< G4ReactionProduct* >;
207 
208  // Generate all the nucleonic fission products
209  // How many nucleons do we have to work with?
210  //TK modified 131108
211  //const G4int ParentA = Isotope_ % 1000;
212  //const G4int ParentZ = (Isotope_ - ParentA) / 1000;
213  const G4int ParentA = (Isotope_/10) % 1000;
214  const G4int ParentZ = ((Isotope_/10) - ParentA) / 1000;
215  RemainingA_ = ParentA;
216  RemainingZ_ = ParentZ;
217 
218  // Don't forget the extra nucleons depending on the fission cause
219  switch(Cause_)
220  {
222  ++RemainingA_;
223  break;
224 
226  ++RemainingZ_;
227  break;
228 
231  default:
232  // Nothing to do here
233  break;
234  }
235 
236  // Ternary fission can be set by the user. Thus, it is necessary to
237  // sample the alpha particle first and the first daughter product
238  // second. See the discussion in
239  // G4FissionProductYieldDist::G4GetFissionProduct() for more information
240  // as to why the fission events are sampled this way.
241  GenerateAlphas(Alphas);
242 
243  // Generate the first daughter product
244  FirstDaughter = new G4ReactionProduct(GetFissionProduct());
245  RemainingA_ -= FirstDaughter->GetDefinition()->GetAtomicMass();
246  RemainingZ_ -= FirstDaughter->GetDefinition()->GetAtomicNumber();
248  {
251 
252  G4cout << " -- First daughter product sampled" << G4endl;
254  G4cout << " Name: " << FirstDaughter->GetDefinition()->GetParticleName() << G4endl;
256  G4cout << " Z: " << FirstDaughter->GetDefinition()->GetAtomicNumber() << G4endl;
258  G4cout << " A: " << FirstDaughter->GetDefinition()->GetAtomicMass() << G4endl;
260  G4cout << " Meta State: " << (FirstDaughter->GetDefinition()->GetPDGEncoding() % 10) << G4endl;
261  }
262 
263  GenerateNeutrons(Neutrons);
264 
265  // Now that all the nucleonic particles have been generated, we can
266  // calculate the composition of the second daughter product.
267  G4int NewIsotope = RemainingZ_ * 1000 + RemainingA_;
269  if(Verbosity_ & G4FFGEnumerations::DAUGHTER_INFO)
270  {
273 
274  G4cout << " -- Second daughter product sampled" << G4endl;
276  G4cout << " Name: " << SecondDaughter->GetDefinition()->GetParticleName() << G4endl;
278  G4cout << " Z: " << SecondDaughter->GetDefinition()->GetAtomicNumber() << G4endl;
280  G4cout << " A: " << SecondDaughter->GetDefinition()->GetAtomicMass() << G4endl;
282  G4cout << " Meta State: " << (SecondDaughter->GetDefinition()->GetPDGEncoding() % 10) << G4endl;
283  }
284 
285  // Calculate how much kinetic energy will be available
286  // 195 to 205 MeV are available in a fission reaction, but about 20 MeV
287  // are from delayed sources. We are concerned only with prompt sources,
288  // so sample a Gaussian distribution about 20 MeV and subtract the
289  // result from the total available energy. Also, the energy of fission
290  // neutrinos is neglected. Fission neutrinos would add ~11 MeV
291  // additional energy to the fission. (Ref 2)
292  // Finally, add in the kinetic energy contribution of the fission
293  // inducing particle, if any.
294  const G4double TotalKE = RandomEngine_->G4SampleUniform(195.0, 205.0) * MeV
295  - RandomEngine_->G4SampleGaussian(20.0, 3.0) * MeV
296  + IncidentEnergy_;
297  RemainingEnergy_ = TotalKE;
298 
299  // Calculate the energies of the alpha particles and neutrons
300  // Once again, since the alpha particles are user defined, we must
301  // sample their kinetic energy first. SampleAlphaEnergies() returns the
302  // amount of energy consumed by the alpha particles, so remove the total
303  // energy alloted to the alpha particles from the available energy
304  SampleAlphaEnergies(Alphas);
305 
306  // Second, the neutrons are sampled from the Watt fission spectrum.
307  SampleNeutronEnergies(Neutrons);
308 
309  // Calculate the total energy available to the daughter products
310  // A Gaussian distribution about the average calculated energy with
311  // a standard deviation of 1.5 MeV (Ref. 2) is used. Since the energy
312  // distribution is dependant on the alpha particle generation and the
313  // Watt fission sampling for neutrons, we only have the left-over energy
314  // to work with for the fission daughter products.
315  G4double FragmentsKE;
316  G4int icounter=0;
317  G4int icounter_max=1024;
318  do
319  {
320  icounter++;
321  if ( icounter > icounter_max ) {
322  G4cout << "Loop-counter exceeded the threshold value at " << __LINE__ << "th line of " << __FILE__ << "." << G4endl;
323  break;
324  }
325  FragmentsKE = RandomEngine_->G4SampleGaussian(RemainingEnergy_, 1.5 *MeV);
326  } while(FragmentsKE > RemainingEnergy_); // Loop checking, 11.05.2015, T. Koi
327 
328  // Make sure that we don't produce any sub-gamma photons
329  if((RemainingEnergy_ - FragmentsKE) / (100 * keV) < 1.0)
330  {
331  FragmentsKE = RemainingEnergy_;
332  }
333 
334  // This energy has now been allotted to the fission fragments.
335  // Subtract FragmentsKE from the total available fission energy.
336  RemainingEnergy_ -= FragmentsKE;
337 
338  // Sample the energies of the gamma rays
339  // Assign the remainder, if any, of the energy to the gamma rays
340  SampleGammaEnergies(Gammas);
341 
342  // Prepare to balance the momenta of the system
343  // We will need these for sampling the angles and balancing the momenta
344  // of all the fission products
345  G4double NumeratorSqrt, NumeratorOther, Denominator;
346  G4double Theta, Phi, Magnitude;
347  G4ThreeVector Direction;
348  G4ParticleMomentum ResultantVector(0, 0, 0);
349 
350  if(Alphas->size() > 0)
351  {
352  // Sample the angles of the alpha particles and neutrons, then calculate
353  // the total moment contribution to the system
354  // The average angle of the alpha particles with respect to the
355  // light fragment is dependent on the ratio of the kinetic energies.
356  // This equation was determined by performing a fit on data from
357  // Ref. 3 using the website:
358  // http://soft.arquimedex.com/linear_regression.php
359  //
360  // RatioOfKE Angle (rad) Angle (degrees)
361  // 1.05 1.257 72
362  // 1.155 1.361 78
363  // 1.28 1.414 81
364  // 1.5 1.518 87
365  // 1.75 1.606 92
366  // 1.9 1.623 93
367  // 2.2 1.728 99
368  // This equation generates the angle in radians. If the RatioOfKE is
369  // greater than 2.25 the angle defaults to 1.3963 rad (100 degrees)
370  G4double MassRatio = FirstDaughter->GetDefinition()->GetPDGMass() / SecondDaughter->GetDefinition()->GetPDGMass();
371 
372  // Invert the mass ratio if the first daughter product is the lighter fragment
373  if(MassRatio < 1)
374  {
375  MassRatio = 1 / MassRatio;
376  }
377 
378  // The empirical equation is valid for mass ratios up to 2.75
379  if(MassRatio > 2.75)
380  {
381  MassRatio = 2.75;
382  }
383  const G4double MeanAlphaAngle = 0.3644 * MassRatio * MassRatio * MassRatio
384  - 1.9766 * MassRatio * MassRatio
385  + 3.8207 * MassRatio
386  - 0.9917;
387 
388  // Sample the directions of the alpha particles with respect to the
389  // light fragment. For the moment we will assume that the light
390  // fragment is traveling along the z-axis in the positive direction.
391  const G4double MeanAlphaAngleStdDev = 0.0523598776;
392  G4double PlusMinus;
393 
394  for(unsigned int i = 0; i < Alphas->size(); ++i)
395  {
396  PlusMinus = std::acos(RandomEngine_->G4SampleGaussian(0, MeanAlphaAngleStdDev)) - (pi / 2);
397  Theta = MeanAlphaAngle + PlusMinus;
398  if(Theta < 0)
399  {
400  Theta = 0.0 - Theta;
401  } else if(Theta > pi)
402  {
403  Theta = (2 * pi - Theta);
404  }
406 
407  Direction.setRThetaPhi(1.0, Theta, Phi);
408  Magnitude = std::sqrt(2 * Alphas->at(i)->GetKineticEnergy() * Alphas->at(i)->GetDefinition()->GetPDGMass());
409  Alphas->at(i)->SetMomentum(Direction * Magnitude);
410  ResultantVector += Alphas->at(i)->GetMomentum();
411  }
412  }
413 
414  // Sample the directions of the neutrons.
415  if(Neutrons->size() != 0)
416  {
417  for(unsigned int i = 0; i < Neutrons->size(); ++i)
418  {
419  Theta = std::acos(RandomEngine_->G4SampleUniform(-1, 1));
421 
422  Direction.setRThetaPhi(1.0, Theta, Phi);
423  Magnitude = std::sqrt(2 * Neutrons->at(i)->GetKineticEnergy() * Neutrons->at(i)->GetDefinition()->GetPDGMass());
424  Neutrons->at(i)->SetMomentum(Direction * Magnitude);
425  ResultantVector += Neutrons->at(i)->GetMomentum();
426  }
427  }
428 
429  // Sample the directions of the gamma rays
430  if(Gammas->size() != 0)
431  {
432  for(unsigned int i = 0; i < Gammas->size(); ++i)
433  {
434  Theta = std::acos(RandomEngine_->G4SampleUniform(-1, 1));
436 
437  Direction.setRThetaPhi(1.0, Theta, Phi);
438  Magnitude = Gammas->at(i)->GetKineticEnergy() / CLHEP::c_light;
439  Gammas->at(i)->SetMomentum(Direction * Magnitude);
440  ResultantVector += Gammas->at(i)->GetMomentum();
441  }
442  }
443 
444  // Calculate the momenta of the two daughter products
445  G4ReactionProduct* LightFragment;
446  G4ReactionProduct* HeavyFragment;
447  G4ThreeVector LightFragmentDirection;
448  G4ThreeVector HeavyFragmentDirection;
449  G4double ResultantX, ResultantY, ResultantZ;
450  ResultantX = ResultantVector.getX();
451  ResultantY = ResultantVector.getY();
452  ResultantZ = ResultantVector.getZ();
453 
454  if(FirstDaughter->GetDefinition()->GetPDGMass() < SecondDaughter->GetDefinition()->GetPDGMass())
455  {
456  LightFragment = FirstDaughter;
457  HeavyFragment = SecondDaughter;
458  } else
459  {
460  LightFragment = SecondDaughter;
461  HeavyFragment = FirstDaughter;
462  }
463  const G4double LightFragmentMass = LightFragment->GetDefinition()->GetPDGMass();
464  const G4double HeavyFragmentMass = HeavyFragment->GetDefinition()->GetPDGMass();
465 
466  LightFragmentDirection.setRThetaPhi(1.0, 0, 0);
467 
468  // Fit the momenta of the daughter products to the resultant vector of
469  // the remaining fission products. This will be done in the Cartesian
470  // coordinate system, not spherical. This is done using the following
471  // table listing the system momenta and the corresponding equations:
472  // X Y Z
473  //
474  // A 0 0 P
475  //
476  // B -R_x -R_y -P - R_z
477  //
478  // R R_x R_y R_z
479  //
480  // v = sqrt(2*m*k) -> k = v^2/(2*m)
481  // tk = k_A + k_B
482  // k_L = P^2/(2*m_L)
483  // k_H = ((-R_x)^2 + (-R_y)^2 + (-P - R_z)^2)/(2*m_H)
484  // where:
485  // P: momentum of the light daughter product
486  // R: the remaining fission products' resultant vector
487  // v: momentum
488  // m: mass
489  // k: kinetic energy
490  // tk: total kinetic energy available to the daughter products
491  //
492  // Below is the solved form for P, with the solution generated using
493  // the WolframAlpha website:
494  // http://www.wolframalpha.com/input/?i=
495  // solve+((-x)^2+%2B+(-y)^2+%2B+(-P-z)^2)%2F(2*B)+%2B+L^2%2F(2*A)+%3D+k+
496  // for+P
497  //
498  //
499  // nsqrt = sqrt(m_L*(m_L*(2*m_H*tk - R_x^2 - R_y^2) +
500  // m_H*(2*m_H*tk - R_x^2 - R_y^2 - R_z^2))
501  NumeratorSqrt = std::sqrt(LightFragmentMass *
502  (LightFragmentMass * (2 * HeavyFragmentMass * FragmentsKE
503  - ResultantX * ResultantX
504  - ResultantY * ResultantY)
505  + HeavyFragmentMass * (2 * HeavyFragmentMass * FragmentsKE
506  - ResultantX * ResultantX
507  - ResultantY * ResultantY
508  - ResultantZ - ResultantZ)));
509 
510  // nother = m_L*R_z
511  NumeratorOther = LightFragmentMass * ResultantZ;
512 
513  // denom = m_L + m_H
514  Denominator = LightFragmentMass + HeavyFragmentMass;
515 
516  // P = (nsqrt + nother) / denom
517  const G4double LightFragmentMomentum = (NumeratorSqrt + NumeratorOther) / Denominator;
518  const G4double HeavyFragmentMomentum = std::sqrt(ResultantX * ResultantX
519  + ResultantY * ResultantY
520  + G4Pow::GetInstance()->powN(LightFragmentMomentum + ResultantZ, 2));
521 
522  // Finally! We now have everything we need for the daughter products
523  LightFragment->SetMomentum(LightFragmentDirection * LightFragmentMomentum);
524  HeavyFragmentDirection.setX(-ResultantX);
525  HeavyFragmentDirection.setY(-ResultantY);
526  HeavyFragmentDirection.setZ((-LightFragmentMomentum - ResultantZ));
527  // Don't forget to normalize the vector to the unit sphere
528  HeavyFragmentDirection.setR(1.0);
529  HeavyFragment->SetMomentum(HeavyFragmentDirection * HeavyFragmentMomentum);
530 
531  if(Verbosity_ & (G4FFGEnumerations::DAUGHTER_INFO | G4FFGEnumerations::MOMENTUM_INFO))
532  {
535 
536  G4cout << " -- Daugher product momenta finalized" << G4endl;
538  }
539 
540  // Load all the particles into a contiguous set
541  //TK modifed 131108
542  //G4DynamicParticleVector* FissionProducts = new G4DynamicParticleVector(2 + Alphas->size() + Neutrons->size() + Gammas->size());
543  G4DynamicParticleVector* FissionProducts = new G4DynamicParticleVector();
544  // Load the fission fragments
545  FissionProducts->push_back(MakeG4DynamicParticle(LightFragment));
546  FissionProducts->push_back(MakeG4DynamicParticle(HeavyFragment));
547  // Load the neutrons
548  for(unsigned int i = 0; i < Neutrons->size(); i++)
549  {
550  FissionProducts->push_back(MakeG4DynamicParticle(Neutrons->at(i)));
551  }
552  // Load the gammas
553  for(unsigned int i = 0; i < Gammas->size(); i++)
554  {
555  FissionProducts->push_back(MakeG4DynamicParticle(Gammas->at(i)));
556  }
557  // Load the alphas
558  for(unsigned int i = 0; i < Alphas->size(); i++)
559  {
560  FissionProducts->push_back(MakeG4DynamicParticle(Alphas->at(i)));
561  }
562 
563  // Rotate the system to a random location so that the light fission fragment
564  // is not always traveling along the positive z-axis
565  // Sample Theta and Phi.
566  G4ThreeVector RotationAxis;
567 
568  Theta = std::acos(RandomEngine_->G4SampleUniform(-1, 1));
570  RotationAxis.setRThetaPhi(1.0, Theta, Phi);
571 
572  // We will also check the net momenta
573  ResultantVector.set(0.0, 0.0, 0.0);
574  for(unsigned int i = 0; i < FissionProducts->size(); i++)
575  {
576  Direction = FissionProducts->at(i)->GetMomentumDirection();
577  Direction.rotateUz(RotationAxis);
578  FissionProducts->at(i)->SetMomentumDirection(Direction);
579  ResultantVector += FissionProducts->at(i)->GetMomentum();
580  }
581 
582  // Warn if the sum momenta of the system is not within a reasonable
583  // tolerance
584  G4double PossibleImbalance = ResultantVector.mag();
585  if(PossibleImbalance > 0.01)
586  {
587  std::ostringstream Temp;
588  Temp << "Momenta imbalance of ";
589  Temp << PossibleImbalance / (MeV / CLHEP::c_light);
590  Temp << " MeV/c in the system";
591  G4Exception("G4FissionProductYieldDist::G4GetFission()",
592  Temp.str().c_str(),
593  JustWarning,
594  "Results may not be valid");
595  }
596 
597  // Clean up
598  delete FirstDaughter;
599  delete SecondDaughter;
603 
605  return FissionProducts;
606 }
607 
610 {
612 
614 
616  return Product;
617 }
618 
620 G4SetAlphaProduction(G4double WhatAlphaProduction)
621 {
623 
624  AlphaProduction_ = WhatAlphaProduction;
625 
627 }
628 
630 G4SetEnergy( G4double WhatIncidentEnergy )
631 {
633 
635  {
636  IncidentEnergy_ = WhatIncidentEnergy;
637  } else
638  {
639  IncidentEnergy_ = 0 * GeV;
640  }
641 
643 }
644 
646 G4SetTernaryProbability( G4double WhatTernaryProbability )
647 {
649 
650  TernaryProbability_ = WhatTernaryProbability;
651 
653 }
654 
657 {
659 
661 
662  ENDFData_->G4SetVerbosity(Verbosity_);
663  RandomEngine_->G4SetVerbosity(Verbosity_);
664 
666 }
667 
670 {
672 
673  // This provides comfortable breathing room at 16 MeV per alpha
674  if(AlphaProduction_ > 10)
675  {
676  AlphaProduction_ = 10;
677  } else if(AlphaProduction_ < -7)
678  {
679  AlphaProduction_ = -7;
680  }
681 
683 }
684 
686 FindParticle( G4double RandomParticle )
687 {
689 
690  // Determine which energy group is currently in use
691  G4bool isExact = false;
692  G4bool lowerExists = false;
693  G4bool higherExists = false;
694  G4int energyGroup;
695  for(energyGroup = 0; energyGroup < YieldEnergyGroups_; energyGroup++)
696  {
697  if(IncidentEnergy_ == YieldEnergies_[energyGroup])
698  {
699  isExact = true;
700  break;
701  }
702 
703  if(energyGroup == 0 && IncidentEnergy_ < YieldEnergies_[energyGroup])
704  {
705  // Break if the energy is less than the lowest energy
706  higherExists = true;
707  break;
708  } else if(energyGroup == YieldEnergyGroups_ - 1)
709  {
710  // The energy is greater than any values in the yield data.
711  lowerExists = true;
712  break;
713  } else
714  {
715  // Break if the energy is less than the lowest energy
716  if(IncidentEnergy_ > YieldEnergies_[energyGroup])
717  {
718  energyGroup--;
719  lowerExists = true;
720  higherExists = true;
721  break;
722  }
723  }
724  }
725 
726  // Determine which particle it is
727  G4Ions* FoundParticle = NULL;
728  if(isExact || YieldEnergyGroups_ == 1)
729  {
730  // Determine which tree contains the random value
731  G4int tree;
732  for(tree = 0; tree < TreeCount_; tree++)
733  {
734  // Break if a tree is identified as containing the random particle
735  if(RandomParticle <= Trees_[tree].ProbabilityRangeEnd[energyGroup])
736  {
737  break;
738  }
739  }
740  ProbabilityBranch* Branch = Trees_[tree].Trunk;
741 
742  // Iteratively traverse the tree until the particle addressed by the random
743  // variable is found
744  G4bool RangeIsSmaller;
745  G4bool RangeIsGreater;
746  while((RangeIsSmaller = (RandomParticle < Branch->ProbabilityRangeBottom[energyGroup]))
747  || (RangeIsGreater = (RandomParticle > Branch->ProbabilityRangeTop[energyGroup])))
748  // Loop checking, 11.05.2015, T. Koi
749  {
750  if(RangeIsSmaller)
751  {
752  Branch = Branch->Left;
753  } else {
754  Branch = Branch->Right;
755  }
756  }
757 
758  FoundParticle = Branch->Particle;
759  } else if(lowerExists && higherExists)
760  {
761  // We need to do some interpolation
762  FoundParticle = FindParticleInterpolation(RandomParticle, energyGroup);
763  } else
764  {
765  // We need to do some extrapolation
766  FoundParticle = FindParticleExtrapolation(RandomParticle, lowerExists);
767  }
768 
769  // Return the particle
771  return FoundParticle;
772 }
773 
776  G4bool LowerEnergyGroupExists )
777 {
779 
780  G4Ions* FoundParticle = NULL;
781  G4int NearestEnergy;
782  G4int NextNearestEnergy;
783 
784  // Check to see if we are extrapolating above or below the data set
785  if(LowerEnergyGroupExists == true)
786  {
787  NearestEnergy = YieldEnergyGroups_ - 1;
788  NextNearestEnergy = NearestEnergy - 1;
789  } else
790  {
791  NearestEnergy = 0;
792  NextNearestEnergy = 1;
793  }
794 
795  for(G4int Tree = 0; Tree < TreeCount_ && FoundParticle == NULL; Tree++)
796  {
797  FoundParticle = FindParticleBranchSearch(Trees_[Tree].Trunk,
798  RandomParticle,
799  NearestEnergy,
800  NextNearestEnergy);
801  }
802 
804  return FoundParticle;
805 }
806 
809  G4int LowerEnergyGroup )
810 {
812 
813  G4Ions* FoundParticle = NULL;
814  G4int HigherEnergyGroup = LowerEnergyGroup + 1;
815 
816  for(G4int Tree = 0; Tree < TreeCount_ && FoundParticle == NULL; Tree++)
817  {
818  FoundParticle = FindParticleBranchSearch(Trees_[Tree].Trunk,
819  RandomParticle,
820  LowerEnergyGroup,
821  HigherEnergyGroup);
822  }
823 
825  return FoundParticle;
826 }
827 
830  G4double RandomParticle,
831  G4int EnergyGroup1,
832  G4int EnergyGroup2 )
833 {
835 
836  G4Ions* Particle;
837 
838  // Verify that the branch exists
839  if(Branch == NULL)
840  {
841  Particle = NULL;
842  } else if(EnergyGroup1 >= Branch->IncidentEnergiesCount
843  || EnergyGroup2 >= Branch->IncidentEnergiesCount
844  || EnergyGroup1 == EnergyGroup2
845  || Branch->IncidentEnergies[EnergyGroup1] == Branch->IncidentEnergies[EnergyGroup2])
846  {
847  // Set NULL if any invalid conditions exist
848  Particle = NULL;
849  } else
850  {
851  // Everything check out - proceed
852  G4Ions* FoundParticle = NULL;
853  G4double Intercept;
854  G4double Slope;
855  G4double RangeAtIncidentEnergy;
856  G4double Denominator = Branch->IncidentEnergies[EnergyGroup1] - Branch->IncidentEnergies[EnergyGroup2];
857 
858  // Calculate the lower probability bounds
859  Slope = (Branch->ProbabilityRangeBottom[EnergyGroup1] - Branch->ProbabilityRangeBottom[EnergyGroup2]) / Denominator;
860  Intercept = Branch->ProbabilityRangeBottom[EnergyGroup1] - Slope * Branch->IncidentEnergies[EnergyGroup1];
861  RangeAtIncidentEnergy = Slope * IncidentEnergy_ + Intercept;
862 
863  // Go right if the particle is below the probability bounds
864  if(RandomParticle < RangeAtIncidentEnergy)
865  {
866  FoundParticle = FindParticleBranchSearch(Branch->Left,
867  RandomParticle,
868  EnergyGroup1,
869  EnergyGroup2);
870  } else
871  {
872  // Calculate the upper probability bounds
873  Slope = (Branch->ProbabilityRangeTop[EnergyGroup1] - Branch->ProbabilityRangeTop[EnergyGroup2]) / Denominator;
874  Intercept = Branch->ProbabilityRangeTop[EnergyGroup1] - Slope * Branch->IncidentEnergies[EnergyGroup1];
875  RangeAtIncidentEnergy = Slope * IncidentEnergy_ + Intercept;
876 
877  // Go left if the particle is above the probability bounds
878  if(RandomParticle > RangeAtIncidentEnergy)
879  {
880  FoundParticle = FindParticleBranchSearch(Branch->Right,
881  RandomParticle,
882  EnergyGroup1,
883  EnergyGroup2);
884  } else
885  {
886  // If the particle is bounded then we found it!
887  FoundParticle = Branch->Particle;
888  }
889  }
890 
891  Particle = FoundParticle;
892  }
893 
895  return Particle;
896 }
897 
899 GenerateAlphas( std::vector< G4ReactionProduct* >* Alphas )
900 {
902 
903  // Throw the dice to determine if ternary fission occurs
905  if(MakeAlphas)
906  {
907  G4int NumberOfAlphasToProduce;
908 
909  // Determine how many alpha particles to produce for the ternary fission
910  if(AlphaProduction_ < 0)
911  {
912  NumberOfAlphasToProduce = RandomEngine_->G4SampleIntegerGaussian(AlphaProduction_ * -1,
913  1,
915  } else
916  {
917  NumberOfAlphasToProduce = (G4int)AlphaProduction_;
918  }
919 
920  //TK modifed 131108
921  //Alphas->resize(NumberOfAlphasToProduce);
922  for(int i = 0; i < NumberOfAlphasToProduce; i++)
923  {
924  // Set the G4Ions as an alpha particle
925  Alphas->push_back(new G4ReactionProduct(AlphaDefinition_));
926 
927  // Remove 4 nucleons (2 protons and 2 neutrons) for each alpha added
928  RemainingZ_ -= 2;
929  RemainingA_ -= 4;
930  }
931  }
932 
934 }
935 
937 GenerateNeutrons( std::vector< G4ReactionProduct* >* Neutrons )
938 {
940 
941  G4int NeutronProduction;
943 
944  //TK modifed 131108
945  //Neutrons->resize(NeutronProduction);
946  for(int i = 0; i < NeutronProduction; i++)
947  {
948  // Define the fragment as a neutron
949  Neutrons->push_back(new G4ReactionProduct(NeutronDefinition_));
950 
951  // Remove 1 nucleon for each neutron added
952  RemainingA_--;
953  }
954 
956 }
957 
960  //TK modified 131108
961  //G4FFGEnumerations::MetaState MetaState )
962  G4FFGEnumerations::MetaState /*MetaState*/ )
963 {
965 
966  G4Ions* Temp;
967 
968  // Break Product down into its A and Z components
969  G4int A = Product % 1000; // Extract A
970  G4int Z = (Product - A) / 1000; // Extract Z
971 
972  // Check to see if the particle is registered using the PDG code
973  // TODO Add metastable state when supported by G4IonTable::GetIon()
974  Temp = reinterpret_cast<G4Ions*>(IonTable_->GetIon(Z, A));
975 
976  // Removed in favor of the G4IonTable::GetIon() method
977 // // Register the particle if it does not exist
978 // if(Temp == NULL)
979 // {
980 // // Define the particle properties
981 // G4String Name = MakeIsotopeName(Product, MetaState);
982 // // Calculate the rest mass using a function already in Geant4
983 // G4double Mass = G4NucleiProperties::
984 // GetNuclearMass((double)A, (double)Z );
985 // G4double Charge = Z*eplus;
986 // G4int BaryonNum = A;
987 // G4bool Stable = TRUE;
988 //
989 // // I am unsure about the following properties:
990 // // 2*Spin, Parity, C-conjugation, 2*Isospin, 2*Isospin3, G-parity.
991 // // Perhaps is would be a good idea to have a physicist familiar with
992 // // Geant4 nomenclature to review and correct these properties.
993 // Temp = new G4Ions (
994 // // Name Mass Width Charge
995 // Name, Mass, 0.0, Charge,
996 //
997 // // 2*Spin Parity C-conjugation 2*Isospin
998 // 0, 1, 0, 0,
999 //
1000 // // 2*Isospin3 G-parity Type Lepton number
1001 // 0, 0, "nucleus", 0,
1002 //
1003 // // Baryon number PDG encoding Stable Lifetime
1004 // BaryonNum, PDGCode, Stable, -1,
1005 //
1006 // // Decay table Shortlived SubType Anti_encoding
1007 // NULL, FALSE, "generic", 0,
1008 //
1009 // // Excitation
1010 // 0.0);
1011 // Temp->SetPDGMagneticMoment(0.0);
1012 //
1013 // // Declare that there is no anti-particle
1014 // Temp->SetAntiPDGEncoding(0);
1015 //
1016 // // Define the processes to use in transporting the particles
1017 // std::ostringstream osAdd;
1018 // osAdd << "/run/particle/addProcManager " << Name;
1019 // G4String cmdAdd = osAdd.str();
1020 //
1021 // // set /control/verbose 0
1022 // G4int tempVerboseLevel = G4UImanager::GetUIpointer()->GetVerboseLevel();
1023 // G4UImanager::GetUIpointer()->SetVerboseLevel(0);
1024 //
1025 // // issue /run/particle/addProcManage
1026 // G4UImanager::GetUIpointer()->ApplyCommand(cmdAdd);
1027 //
1028 // // retrieve /control/verbose
1029 // G4UImanager::GetUIpointer()->SetVerboseLevel(tempVerboseLevel);
1030 // }
1031 
1033  return Temp;
1034 }
1035 
1038 {
1040 
1041  // Generate the file location starting in the Geant4 data directory
1042  std::ostringstream DirectoryName;
1043  DirectoryName << std::getenv("G4NEUTRONHPDATA") << G4FFGDefaultValues::ENDFFissionDataLocation;
1044 
1045  // Return the directory structure
1047  return DirectoryName.str();
1048 }
1049 
1053 {
1055 
1056 
1057  // Create the unique identifying name for the particle
1058  std::ostringstream FileName;
1059 
1060  // Determine if a leading 0 is needed (ZZZAAA or 0ZZAAA)
1061  if(Isotope < 100000)
1062  {
1063  FileName << "0";
1064  }
1065 
1066  // Add the name of the element and the extension
1067  FileName << MakeIsotopeName(Isotope, MetaState) << ".fpy";
1068 
1070  return FileName.str();
1071 }
1072 
1075 {
1077 
1078  G4DynamicParticle* DynamicParticle = new G4DynamicParticle(ReactionProduct->GetDefinition(), ReactionProduct->GetMomentum());
1079 
1081  return DynamicParticle;
1082 }
1083 
1087 {
1089 
1090  // Break Product down into its A and Z components
1091  G4int A = Isotope % 1000;
1092  G4int Z = (Isotope - A) / 1000;
1093 
1094  // Create the unique identifying name for the particle
1095  std::ostringstream IsotopeName;
1096 
1097  IsotopeName << Z << "_" << A;
1098 
1099  // If it is metastable then append "m" to the name
1100  if(MetaState != G4FFGEnumerations::GROUND_STATE)
1101  {
1102  IsotopeName << "m";
1103 
1104  // If it is a second isomeric state then append "2" to the name
1105  if(MetaState == G4FFGEnumerations::META_2)
1106  {
1107  IsotopeName << "2";
1108  }
1109  }
1110  // Add the name of the element and the extension
1111  IsotopeName << "_" << ElementNames_->theString[Z - 1];
1112 
1114  return IsotopeName.str();
1115 }
1116 
1118 MakeTrees( void )
1119 {
1121 
1122  // Allocate the space
1123  // We will make each tree a binary search
1124  // The maximum number of iterations required to find a single fission product
1125  // based on it's probability is defined by the following:
1126  // x = number of fission products
1127  // Trees = T(x) = ceil( ln(x) )
1128  // Rows/Tree = R(x) = ceil(( sqrt( (8 * x / T(x)) + 1) - 1) / 2)
1129  // Maximum = M(x) = T(x) + R(x)
1130  // Results: x => M(x)
1131  // 10 5
1132  // 100 10
1133  // 1000 25
1134  // 10000 54
1135  // 100000 140
1138 
1139  // Initialize the range of each node
1140  for(G4int i = 0; i < TreeCount_; i++)
1141  {
1143  Trees_[i].Trunk = NULL;
1144  Trees_[i].BranchCount = 0;
1145  Trees_[i].IsEnd = FALSE;
1146  }
1147  // Mark the last tree as the ending tree
1148  Trees_[TreeCount_ - 1].IsEnd = TRUE;
1149 
1151 }
1152 
1155 {
1157 
1158  G4int ProductCount = ENDFData_->G4GetNumberOfFissionProducts();
1159  BranchCount_ = 0;
1161 
1162  // Loop through all the products
1163  for(G4int i = 0; i < ProductCount; i++)
1164  {
1165  // Acquire the data and sort it
1167  }
1168 
1169  // Generate the true normalization factor, since round-off errors may result
1170  // in non-singular normalization of the data files. Also, reset DataTotal_
1171  // since it is used by Renormalize() to set the probability segments.
1174 
1175  // Go through all the trees one at a time
1176  for(G4int i = 0; i < TreeCount_; i++)
1177  {
1178  Renormalize(Trees_[i].Trunk);
1179  // Set the max range of the tree to DataTotal
1180  G4ArrayOps::Copy(YieldEnergyGroups_, Trees_[i].ProbabilityRangeEnd, DataTotal_);
1181  }
1182 
1184 }
1185 
1188 {
1190 
1191  // Check to see if Branch exists. Branch will be a null pointer if it
1192  // doesn't exist
1193  if(Branch != NULL)
1194  {
1195  // Call the lower branch to set the probability segment first, since it
1196  // supposed to have a lower probability segment that this node
1197  Renormalize(Branch->Left);
1198 
1199  // Set this node as the next sequential probability segment
1204 
1205  // Now call the upper branch to set those probability segments
1206  Renormalize(Branch->Right);
1207  }
1208 
1210 }
1211 
1213 SampleAlphaEnergies( std::vector< G4ReactionProduct* >* Alphas )
1214 {
1216 
1217  // The condition of sampling more energy from the fission products than is
1218  // alloted is statistically unfavorable, but it could still happen. The
1219  // do-while loop prevents such an occurrence from happening
1220  G4double MeanAlphaEnergy = 16.0;
1221  G4double TotalAlphaEnergy;
1222 
1223  do
1224  {
1225  G4double AlphaEnergy;
1226  TotalAlphaEnergy = 0;
1227 
1228  // Walk through the alpha particles one at a time and sample each's
1229  // energy
1230  for(unsigned int i = 0; i < Alphas->size(); i++)
1231  {
1232  AlphaEnergy = RandomEngine_->G4SampleGaussian(MeanAlphaEnergy,
1233  2.35,
1235  // Assign the energy to the alpha particle
1236  Alphas->at(i)->SetKineticEnergy(AlphaEnergy);
1237 
1238  // Add up the total amount of kinetic energy consumed.
1239  TotalAlphaEnergy += AlphaEnergy;
1240  }
1241 
1242  // If true, decrement the mean alpha energy by 0.1 and try again.
1243  MeanAlphaEnergy -= 0.1;
1244  } while(TotalAlphaEnergy >= RemainingEnergy_); // Loop checking, 11.05.2015, T. Koi
1245 
1246  // Subtract the total amount of energy that was assigned.
1247  RemainingEnergy_ -= TotalAlphaEnergy;
1248 
1250 }
1251 
1253 SampleGammaEnergies( std::vector< G4ReactionProduct* >* Gammas )
1254 {
1256 
1257  // Make sure that there is energy to assign to the gamma rays
1258  if(RemainingEnergy_ != 0)
1259  {
1260  G4double SampleEnergy;
1261 
1262  // Sample from RemainingEnergy until it is all gone. Also,
1263  // RemainingEnergy should not be smaller than
1264  // G4FFGDefaultValues::MeanGammaEnergy. This will prevent the
1265  // sampling of a fractional portion of the Gaussian distribution
1266  // in an attempt to find a new gamma ray energy.
1267  G4int icounter=0;
1268  G4int icounter_max=1024;
1269  while(RemainingEnergy_ >= G4FFGDefaultValues::MeanGammaEnergy ) // Loop checking, 11.05.2015, T. Koi
1270  {
1271  icounter++;
1272  if ( icounter > icounter_max ) {
1273  G4cout << "Loop-counter exceeded the threshold value at " << __LINE__ << "th line of " << __FILE__ << "." << G4endl;
1274  break;
1275  }
1276  SampleEnergy = RandomEngine_->
1278  // Make sure that we didn't sample more energy than was available
1279  if(SampleEnergy <= RemainingEnergy_)
1280  {
1281  // If this energy assignment would leave less energy than the
1282  // 'intrinsic' minimal energy of a gamma ray then just assign
1283  // all of the remaining energy
1284  if(RemainingEnergy_ - SampleEnergy < 100 * keV)
1285  {
1286  SampleEnergy = RemainingEnergy_;
1287  }
1288 
1289  // Create the new particle
1290  Gammas->push_back(new G4ReactionProduct());
1291 
1292  // Set the properties
1293  Gammas->back()->SetDefinition(GammaDefinition_);
1294  Gammas->back()->SetTotalEnergy(SampleEnergy);
1295 
1296  // Calculate how much is left
1297  RemainingEnergy_ -= SampleEnergy;
1298  }
1299  }
1300 
1301  // If there is anything left over, the energy must be above 100 keV but
1302  // less than G4FFGDefaultValues::MeanGammaEnergy. Arbitrarily assign
1303  // RemainingEnergy to a new particle
1304  if(RemainingEnergy_ > 0)
1305  {
1306  SampleEnergy = RemainingEnergy_;
1307  Gammas->push_back(new G4ReactionProduct());
1308 
1309  // Set the properties
1310  Gammas->back()->SetDefinition(GammaDefinition_);
1311  Gammas->back()->SetTotalEnergy(SampleEnergy);
1312 
1313  // Calculate how much is left
1314  RemainingEnergy_ -= SampleEnergy;
1315  }
1316  }
1317 
1319 }
1320 
1322 SampleNeutronEnergies( std::vector< G4ReactionProduct* >* Neutrons )
1323 {
1325 
1326  // The condition of sampling more energy from the fission products than is
1327  // alloted is statistically unfavorable, but it could still happen. The
1328  // do-while loop prevents such an occurrence from happening
1329  G4double TotalNeutronEnergy;
1330  G4double NeutronEnergy;
1331 
1332  // Make sure that we don't sample more energy than is available
1333  G4int icounter=0;
1334  G4int icounter_max=1024;
1335  do
1336  {
1337  icounter++;
1338  if ( icounter > icounter_max ) {
1339  G4cout << "Loop-counter exceeded the threshold value at " << __LINE__ << "th line of " << __FILE__ << "." << G4endl;
1340  break;
1341  }
1342  TotalNeutronEnergy = 0;
1343 
1344  // Walk through the neutrons one at a time and sample the energies.
1345  // The gamma rays have not yet been sampled, so the last neutron will
1346  // have a NULL value for NextFragment
1347  for(unsigned int i = 0; i < Neutrons->size(); i++)
1348  {
1349  // Assign the energy to the neutron
1351  Neutrons->at(i)->SetKineticEnergy(NeutronEnergy);
1352 
1353  // Add up the total amount of kinetic energy consumed.
1354  TotalNeutronEnergy +=NeutronEnergy;
1355  }
1356  } while (TotalNeutronEnergy > RemainingEnergy_); // Loop checking, 11.05.2015, T. Koi
1357 
1358  // Subtract the total amount of energy that was assigned.
1359  RemainingEnergy_ -= TotalNeutronEnergy;
1360 
1362 }
1363 
1365 SetNubar( void )
1366 {
1368 
1369  G4int* WhichNubar;
1370  G4int* NubarWidth;
1371  G4double XFactor, BFactor;
1372 
1374  {
1375  WhichNubar = const_cast<G4int*>(&SpontaneousNubar_[0][0]);
1376  NubarWidth = const_cast<G4int*>(&SpontaneousNubarWidth_[0][0]);
1377  } else
1378  {
1379  WhichNubar = const_cast<G4int*>(&NeutronInducedNubar_[0][0]);
1380  NubarWidth = const_cast<G4int*>(&NeutronInducedNubarWidth_[0][0]);
1381  }
1382 
1383  XFactor = G4Pow::GetInstance()->powA(10.0, -13.0);
1384  BFactor = G4Pow::GetInstance()->powA(10.0, -4.0);
1385  Nubar_ = *(WhichNubar + 1) * IncidentEnergy_ * XFactor
1386  + *(WhichNubar + 2) * BFactor;
1387  while(*WhichNubar != -1) // Loop checking, 11.05.2015, T. Koi
1388  {
1389  if(*WhichNubar == Isotope_)
1390  {
1391  Nubar_ = *(WhichNubar + 1) * IncidentEnergy_ * XFactor
1392  + *(WhichNubar + 2) * BFactor;
1393 
1394  break;
1395  }
1396  WhichNubar += 3;
1397  }
1398 
1399  XFactor = G4Pow::GetInstance()->powN((G4double)10, -6);
1400  NubarWidth_ = *(NubarWidth + 1) * XFactor;
1401  while(*WhichNubar != -1) // Loop checking, 11.05.2015, T. Koi
1402  {
1403  if(*WhichNubar == Isotope_)
1404  {
1405  NubarWidth_ = *(NubarWidth + 1) * XFactor;
1406 
1407  break;
1408  }
1409  WhichNubar += 2;
1410  }
1411 
1413 }
1414 
1417 {
1419 
1420  // Initialize the new branch
1421  ProbabilityBranch* NewBranch = new ProbabilityBranch;
1423  NewBranch->Left = NULL;
1424  NewBranch->Right = NULL;
1425  NewBranch->Particle = GetParticleDefinition(YieldData->GetProduct(), YieldData->GetMetaState());
1426  NewBranch->IncidentEnergies = new G4double[YieldEnergyGroups_];
1427  NewBranch->ProbabilityRangeTop = new G4double[YieldEnergyGroups_];
1428  NewBranch->ProbabilityRangeBottom = new G4double[YieldEnergyGroups_];
1429  G4ArrayOps::Copy(YieldEnergyGroups_, NewBranch->ProbabilityRangeTop, YieldData->GetYieldProbability());
1430  G4ArrayOps::Copy(YieldEnergyGroups_, NewBranch->IncidentEnergies, YieldEnergies_);
1432 
1433  // Check to see if the this is the smallest/largest particle. First, check
1434  // to see if this is the first particle in the system
1435  if(SmallestZ_ == NULL)
1436  {
1437  SmallestZ_ = SmallestA_ = LargestZ_ = LargestA_ = NewBranch->Particle;
1438  } else
1439  {
1440  G4bool IsSmallerZ = NewBranch->Particle->GetAtomicNumber() < SmallestZ_->GetAtomicNumber();
1441  G4bool IsSmallerA = NewBranch->Particle->GetAtomicMass() < SmallestA_->GetAtomicMass();
1442  G4bool IsLargerZ = NewBranch->Particle->GetAtomicNumber() > LargestZ_->GetAtomicNumber();
1443  G4bool IsLargerA = NewBranch->Particle->GetAtomicMass() > LargestA_->GetAtomicMass();
1444 
1445  if(IsSmallerZ)
1446  {
1447  SmallestZ_ = NewBranch->Particle;
1448  }
1449 
1450  if(IsLargerZ)
1451  {
1452  LargestA_ = NewBranch->Particle;
1453  }
1454 
1455  if(IsSmallerA)
1456  {
1457  SmallestA_ = NewBranch->Particle;
1458  }
1459 
1460  if(IsLargerA)
1461  {
1462  LargestA_ = NewBranch->Particle;
1463  }
1464  }
1465 
1466  // Place the new branch
1467  // Determine which tree the new branch goes into
1468  G4int WhichTree = (G4int)floor((G4double)(BranchCount_ % TreeCount_));
1469  ProbabilityBranch** WhichBranch = &(Trees_[WhichTree].Trunk);
1470  Trees_[WhichTree].BranchCount++;
1471 
1472  // Search for the position
1473  // Determine where the branch goes
1474  G4int BranchPosition = (G4int)floor((G4double)(BranchCount_ / TreeCount_)) + 1;
1475 
1476  // Run through the tree until the end branch is reached
1477  while(BranchPosition > 1) // Loop checking, 11.05.2015, T. Koi
1478  {
1479  if(BranchPosition & 1)
1480  {
1481  // If the 1's bit is on then move to the next 'right' branch
1482  WhichBranch = &((*WhichBranch)->Right);
1483  } else
1484  {
1485  // If the 1's bit is off then move to the next 'down' branch
1486  WhichBranch = &((*WhichBranch)->Left);
1487  }
1488 
1489  BranchPosition >>= 1;
1490  }
1491 
1492  *WhichBranch = NewBranch;
1493  BranchCount_++;
1494 
1496 }
1497 
1500 {
1502 
1503  // Burn each tree, one by one
1504  G4int WhichTree = 0;
1505  while(Trees_[WhichTree].IsEnd != TRUE) // Loop checking, 11.05.2015, T. Koi
1506  {
1507  BurnTree(Trees_[WhichTree].Trunk);
1508  delete Trees_[WhichTree].Trunk;
1509  delete[] Trees_[WhichTree].ProbabilityRangeEnd;
1510  WhichTree++;
1511  }
1512 
1513  // Delete each dynamically allocated variable
1514  delete ENDFData_;
1515  delete[] Trees_;
1516  delete[] DataTotal_;
1517  delete[] MaintainNormalizedData_;
1518  delete ElementNames_;
1519  delete RandomEngine_;
1520 
1522 }
1523 
1526 {
1528 
1529  // Check to see it Branch exists. Branch will be a null pointer if it
1530  // doesn't exist
1531  if(Branch)
1532  {
1533  // Burn down before you burn up
1534  BurnTree(Branch->Left);
1535  delete Branch->Left;
1536  BurnTree(Branch->Right);
1537  delete Branch->Right;
1538 
1539  delete[] Branch->IncidentEnergies;
1540  delete[] Branch->ProbabilityRangeTop;
1541  delete[] Branch->ProbabilityRangeBottom;
1542  }
1543 
1545 }
1546