51constexpr G4double R0 = 1.3 * CLHEP::fermi;
57 (3. / 5.) * (CLHEP::elm_coupling / R0) * std::cbrt(1. / (1. + Kappa));
59 std::uint32_t atomicMassSum = 0.;
60 std::uint32_t chargeSum = 0.;
62 for (
const auto fragmentPtr : split) {
63 auto mass =
static_cast<std::uint32_t
>(fragmentPtr->GetAtomicMass());
64 auto charge =
static_cast<std::uint32_t
>(fragmentPtr->GetChargeNumber());
65 CoulombEnergy += std::pow(charge, 2) / std::cbrt(
static_cast<G4double>(mass));
66 atomicMassSum += mass;
71 std::pow(
static_cast<G4double>(chargeSum), 2) / std::cbrt(
static_cast<G4double>(atomicMassSum));
72 return -COEF * CoulombEnergy;
79 for (
const auto fragmentPtr : split) {
80 factor *= fragmentPtr->GetPolarization();
88 auto kineticEnergy = totalEnergy;
89 for (
const auto fragmentPtr : split) {
90 kineticEnergy -= fragmentPtr->GetTotalEnergy();
94 if (kineticEnergy <= 0.) {
105 for (
const auto fragmentPtr : split) {
106 const auto fragmentMass = fragmentPtr->GetMass();
107 massProduct *= fragmentMass;
108 massSum += fragmentMass;
110 if (0.0 >= massSum) {
return 1.0; }
111 auto massFactor = massProduct / massSum;
112 massFactor *= std::sqrt(massFactor);
116std::size_t Factorial(
const std::size_t n)
118 std::size_t factorial = 1;
119 for (std::size_t i = 2; i <=
n; ++i) {
128 std::vector<G4FermiAtomicMass> masses(split.size());
129 std::transform(split.begin(), split.end(), masses.begin(),
131 std::sort(masses.begin(), masses.end());
137 std::size_t repeatCount = 1;
138 for (std::size_t i = 1; i < masses.size(); ++i) {
139 if (masses[i] != masses[i - 1]) {
140 factor *=
static_cast<G4double>(Factorial(repeatCount));
145 factor *=
static_cast<G4double>(Factorial(repeatCount));
153 std::pow(R0 / CLHEP::hbarc, 3) * Kappa * std::sqrt(2.0 / CLHEP::pi) / 3.0;
155 return std::pow(COEF *
static_cast<G4double>(atomicMass), fragmentsCount - 1);
158G4double GammaFactor(std::size_t fragmentsCount)
167 if (fragmentsCount % 2 == 0) {
168 gamma *= std::sqrt(CLHEP::pi);
178 const auto kineticEnergy = KineticEnergy(split, totalEnergy);
181 if (kineticEnergy <= 0.) {
185 const auto power = 3.0 *
static_cast<G4double>(split.size() - 1) / 2.0 - 1.;
186 const auto kineticFactor = std::pow(kineticEnergy, power);
189 const auto spinFactor = SpinFactor(split);
192 const auto massFactor = MassFactor(split);
195 const auto coef = ConstFactor(atomicMass, split.size());
198 const auto gamma = GammaFactor(split.size());
201 const auto permutationFactor = ConfigurationFactor(split);
203 return coef * kineticFactor * massFactor * spinFactor / (permutationFactor * gamma);
208constexpr std::size_t ExpectedSplitSize = 100;
213 "Non valid arguments A = " << nucleiData.
atomicMass
217 <=
static_cast<std::uint32_t
>(nucleiData.
atomicMass),
218 "Non physical arguments = " << nucleiData.
atomicMass
222std::vector<G4FermiFragmentVector> PossibleSplits(
const G4FermiPartition& massPartition,
226 const auto fragmentCount = massPartition.size();
229 std::size_t splitsCount = 1;
230 for (std::size_t fragmentIdx = 0; fragmentIdx < fragmentCount; ++fragmentIdx) {
233 if (splitsCount == 0) {
243 std::size_t groupSize = splitsCount;
244 for (std::size_t fragmentIdx = 0; fragmentIdx < fragmentCount; ++fragmentIdx) {
245 const auto fragmentRange =
249 const std::size_t multiplicity = std::distance(fragmentRange.begin(), fragmentRange.end());
250 groupSize /= multiplicity;
253 for (
const auto fragmentPtr : fragmentRange) {
254 for (std::size_t pos = 0; pos < groupSize; ++pos) {
255 splits[
offset + pos][fragmentIdx] = fragmentPtr;
263 for (
auto& split : splits) {
264 std::sort(split.begin(), split.end(), std::greater<>());
267 const auto uniqueEndIt = std::unique(splits.begin(), splits.end());
268 splits.resize(uniqueEndIt - splits.begin());
276 std::vector<G4FermiFragmentVector> splits;
282 std::vector<G4FermiFragmentVector>& splits)
284 ThrowOnInvalidInputs(nucleiData);
286 splits.reserve(ExpectedSplitSize);
289 const auto maxFragmentsCount =
static_cast<std::uint32_t
>(nucleiData.
atomicMass);
291 for (std::uint32_t fragmentCount = 2; fragmentCount <= maxFragmentsCount; ++fragmentCount) {
297 if (
auto partitionSplits = PossibleSplits(massPartition, chargePartition);
298 !partitionSplits.empty()) {
299 splits.insert(splits.end(), std::make_move_iterator(partitionSplits.begin()),
300 std::make_move_iterator(partitionSplits.end()));
#define FERMI_ASSERT_MSG(COND, MSG)
std::vector< std::uint32_t > G4FermiPartition
G4ThreadLocal T * G4GeomSplitter< T >::offset
std::vector< const G4VFermiFragmentAN * > G4FermiFragmentVector
static G4FermiFragmentPoolAN & Instance()
static void GenerateSplits(G4FermiNucleiData nucleiData, std::vector< G4FermiFragmentVector > &splits)
static G4double DecayWeight(const G4FermiFragmentVector &split, G4FermiAtomicMass atomicMass, G4double totalEnergy)
G4FermiAtomicMass GetAtomicMass() const
G4double CoulombBarrier(const G4int Z1, const G4int A1, const G4int Z2, const G4int A2, const G4double exc)
G4FermiChargeNumber chargeNumber
G4FermiAtomicMass atomicMass