52# define G4FERMI_VERBOSE 1
54# define G4FERMI_VERBOSE 0
57#define FERMI_LOG_MSG(verbosity, level, msg) \
59 if (G4FERMI_VERBOSE) { \
60 if ((verbosity) >= (level)) { \
61 G4cout << __FILE__ << ':' << __LINE__ << " in function \"" << __FUNCTION__ << "\"\n" \
69#define FERMI_LOG_WARN(verbosity, msg) FERMI_LOG_MSG(verbosity, FERMI_WARN, msg)
70#define FERMI_LOG_DEBUG(verbosity, msg) FERMI_LOG_MSG(verbosity, FERMI_DEBUG, msg)
74constexpr const char* SPACES_OFFSET =
" ";
76std::size_t SampleWeightDistribution(
const std::vector<G4double>& weights)
78 const auto totalWeight = std::accumulate(weights.begin(), weights.end(), 0.);
81 const auto targetWeight = G4RandFlat::shoot() * totalWeight;
83 for (std::size_t i = 0; i < weights.size(); ++i) {
84 cummulativeWeight += weights[i];
86 if (cummulativeWeight >= targetWeight) {
91 return weights.size() - 1;
94G4String LogProducts(
const std::vector<G4FermiParticle>& particles)
96 std::ostringstream out;
99 for (
const auto& particle : particles) {
100 out << SPACES_OFFSET << particle <<
";\n";
104 return std::move(out).str();
116 std::ostringstream out;
119 for (
const auto fragmentPtr : split) {
120 out << SPACES_OFFSET << *fragmentPtr <<
";\n";
124 return std::move(out).str();
129 const auto mass =
static_cast<std::uint32_t
>(atomicMass);
130 const auto charge =
static_cast<std::uint32_t
>(chargeNumber);
131 return (mass * (mass + 1)) / 2 + charge;
135G4FermiBreakUpAN::PossibleSplits::PossibleSplits(
const G4FermiAtomicMass maxAtomicMass)
137 const auto maxMass =
static_cast<std::uint32_t
>(maxAtomicMass);
138 splits_.resize(maxMass * (maxMass + 1) / 2);
141const std::vector<G4FermiFragmentVector>&
142G4FermiBreakUpAN::PossibleSplits::GetSplits(
const G4FermiAtomicMass atomicMass,
143 const G4FermiChargeNumber chargeNumber)
const
145 const auto slot = GetSlot(atomicMass, chargeNumber);
146 return splits_.at(slot);
149void G4FermiBreakUpAN::PossibleSplits::InsertSplits(
const G4FermiAtomicMass atomicMass,
150 const G4FermiChargeNumber chargeNumber,
151 std::vector<G4FermiFragmentVector>&& splits)
153 const auto slot = GetSlot(atomicMass, chargeNumber);
155 if (slot >= splits_.size()) {
156 splits_.resize(slot +
static_cast<std::uint32_t
>(atomicMass));
159 splits_[slot] = std::move(splits);
165 verbosity_(verbosity)
173 FERMI_LOG_DEBUG(verbosity_,
"G4FermiParticle is stable with excitation energy = "
180 "Selecting Split for " << particle <<
" from " << splits.size() <<
" splits");
181 if (splits.empty()) {
188 weights_.resize(splits.size());
189 std::transform(splits.begin(), splits.end(), weights_.begin(),
191 totalEnergy = particle.
GetMomentum().
m()](
const auto& split) {
192 return G4FermiSplitter::DecayWeight(split, atomicMass, totalEnergy);
195 if (std::all_of(weights_.begin(), weights_.end(), [](
auto weight) { return weight == 0.; })) {
200 const auto& chosenSplit = splits[SampleWeightDistribution(weights_)];
202 "From " << splits.size() <<
" splits chosen split: " << LogSplit(chosenSplit));
204 return SplitToParticles(particle, chosenSplit);
222 splits_ = PossibleSplits();
223 for (
auto a = 1; a < MAX_A; ++a) {
224 for (
auto z = 0; z <= a; ++z) {
228 splits_.InsertSplits(atomicMass, chargeNumber,
236 return Z < MAX_Z &&
A < MAX_A;
241 if (theNucleus ==
nullptr || results ==
nullptr) {
243 ed <<
"G4Fragment or result G4FragmentVector is not set in FermiBreakUp";
248 const auto particle =
251 const auto fragments =
BreakItUp(particle);
254 if (fragments.size() <= 1) {
return; }
260 for (
const auto& fragment : fragments) {
262 static_cast<G4int>(fragment.GetChargeNumber()),
263 fragment.GetMomentum());
264 results->push_back(fr);
265 fr->SetCreationTime(creationTime);
266 fr->SetCreatorModelID(secID_);
270std::vector<G4FermiParticle>
271G4FermiBreakUpAN::SplitToParticles(
const G4FermiParticle& sourceParticle,
274 std::vector<G4double> splitMasses(split.size());
275 std::transform(split.begin(), split.end(), splitMasses.begin(),
279 std::vector<G4LorentzVector> particlesMomentum
282 if (particlesMomentum.empty()) {
283 return {sourceParticle};
287 std::vector<G4FermiParticle> particleSplit;
288 particleSplit.reserve(2 * split.size());
290 for (std::size_t fragmentIdx = 0; fragmentIdx < split.size(); ++fragmentIdx) {
291 const auto fragmentMomentum =
292 ChangeFrameOfReference(particlesMomentum[fragmentIdx], boostVector);
293 split[fragmentIdx]->AppendDecayFragments(fragmentMomentum, particleSplit);
296 FERMI_LOG_DEBUG(verbosity_,
"Break up products: " << LogProducts(particleSplit));
297 return particleSplit;
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
#define FERMI_LOG_DEBUG(verbosity, msg)
constexpr G4int FERMI_DEBUG
#define FERMI_ASSERT_MSG(COND, MSG)
std::vector< G4Fragment * > G4FragmentVector
CLHEP::HepLorentzVector G4LorentzVector
CLHEP::Hep3Vector G4ThreeVector
std::vector< const G4VFermiFragmentAN * > G4FermiFragmentVector
Hep3Vector boostVector() const
static void ConstructParticle()
void BreakFragment(G4FragmentVector *results, G4Fragment *theNucleus) override
G4bool IsApplicable(G4int Z, G4int A, G4double eexc) const override
G4FermiBreakUpAN(G4int verbosity=0)
void Initialise() override
std::vector< G4FermiParticle > BreakItUp(const G4FermiParticle &nucleus) const
void Initialize(const DataSource &dataSource)
static G4FermiFragmentPoolAN & Instance()
static G4FermiNucleiProperties & Instance()
const G4LorentzVector & GetMomentum() const
G4double GetExcitationEnergy() const
G4FermiAtomicMass GetAtomicMass() const
G4FermiChargeNumber GetChargeNumber() const
std::vector< G4LorentzVector > CalculateDecay(const G4LorentzVector &totalMomentum, const std::vector< G4double > &fragmentsMass) const
static void GenerateSplits(G4FermiNucleiData nucleiData, std::vector< G4FermiFragmentVector > &splits)
const G4LorentzVector & GetMomentum() const
G4double GetCreationTime() const
static G4double GetNuclearMass(const G4double A, const G4double Z)
G4double GetTotalEnergy() const