19#include "marley/ExitChannel.hh"
20#include "marley/Generator.hh"
21#include "marley/Logger.hh"
22#include "marley/MassTable.hh"
23#include "marley/HauserFeshbachDecay.hh"
24#include "marley/StructureDatabase.hh"
25#include "marley/marley_utils.hh"
26#include "marley/hepmc3_utils.hh"
29 const std::shared_ptr< HepMC3::GenParticle >&
32 Exi_( Exi ), twoJi_( twoJi ), Pi_( Pi )
34 build_exit_channels( sdb );
37void marley::HauserFeshbachDecay::build_exit_channels(
41 exit_channels_.clear();
43 int pdgi = compound_nucleus_->pid();
44 int Zi = marley_utils::get_particle_Z( pdgi );
45 int Ai = marley_utils::get_particle_A( pdgi );
48 int qi = marley_hepmc3::get_particle_charge( *compound_nucleus_ );
60 MARLEY_LOG( DEBUG,
"physics.deexcitation.hauser" ) <<
"Building exit"
61 " channels for PDG " << pdgi <<
" (Z=" << Zi <<
", A=" << Ai
62 <<
") at Ex = " << Exi_ <<
" MeV, 2J = " << twoJi_ <<
", P = " << Pi_;
64 for (
const auto& pair : sdb.
fragments() ) {
72 int Zf = Zi - f.
get_Z();
73 int Af = Ai - f.
get_A();
74 int pdg_final = marley_utils::get_nucleus_pid( Zf, Af );
79 if ( Zf < 0 || Af < 1 )
continue;
82 if ( Zf == 0 && Af > 1 )
continue;
86 if ( f.
get_A() > Af )
continue;
92 double Sa = mt.get_fragment_separation_energy( Zi, Ai, fragment_pid );
101 double Exf_max = Exi_ - Sa;
106 if ( Exf_max <= 0. )
continue;
123 if ( levels.size() > 0 ) E_c_min = levels.back()->energy();
131 for (
const auto& level : levels) {
132 double Exf = level->energy();
133 if ( Exf < Exf_max ) {
136 auto ec = std::make_unique< marley::FragmentDiscreteExitChannel >(
137 pdgi, qi, Exi_, twoJi_, Pi_, rho_i, sdb, *level, f );
139 total_width_ += ec->width();
140 MARLEY_LOG( TRACE,
"physics.deexcitation.hauser.widths" )
141 <<
" fragment " << marley_utils::particle_symbols.at( fragment_pid )
142 <<
" -> discrete level at " << Exf <<
" MeV, width = "
143 << ec->width() <<
" MeV";
145 exit_channels_.push_back( std::move(ec) );
153 if ( Exf_max > E_c_min ) {
156 auto ec = std::make_unique< marley::FragmentContinuumExitChannel >(
157 pdgi, qi, Exi_, twoJi_, Pi_, rho_i, sdb, E_c_min, f );
159 total_width_ += ec->width();
160 MARLEY_LOG( TRACE,
"physics.deexcitation.hauser.widths" )
161 <<
" fragment " << marley_utils::particle_symbols.at( fragment_pid )
162 <<
" -> continuum [" << E_c_min <<
", " << Exf_max <<
"] MeV,"
163 <<
" width = " << ec->width() <<
" MeV";
165 exit_channels_.push_back( std::move(ec) );
188 if ( levels.size() > 0 ) E_c_min = levels.back()->energy();
190 for (
const auto& level_f : levels) {
191 double Exf = level_f->energy();
193 auto ec = std::make_unique< marley::GammaDiscreteExitChannel >( pdgi,
194 qi, Exi_, twoJi_, Pi_, rho_i, sdb, *level_f );
196 total_width_ += ec->width();
197 MARLEY_LOG( TRACE,
"physics.deexcitation.hauser.widths" )
198 <<
" gamma -> discrete level at " << Exf <<
" MeV, width = "
199 << ec->width() <<
" MeV";
201 exit_channels_.push_back( std::move(ec) );
209 if ( Exi_ > E_c_min ) {
213 auto ec = std::make_unique< marley::GammaContinuumExitChannel >( pdgi,
214 qi, Exi_, twoJi_, Pi_, rho_i, sdb, E_c_min );
216 total_width_ += ec->width();
217 MARLEY_LOG( TRACE,
"physics.deexcitation.hauser.widths" )
218 <<
" gamma -> continuum [" << E_c_min <<
", " << Exi_ <<
"] MeV,"
219 <<
" width = " << ec->width() <<
" MeV";
221 exit_channels_.push_back( std::move(ec) );
224 MARLEY_LOG( DEBUG,
"physics.deexcitation.hauser" ) <<
"Total compound"
225 " nucleus width = " << total_width_ <<
" MeV ("
226 << exit_channels_.size() <<
" exit channels)";
231 std::shared_ptr< HepMC3::GenParticle >& emitted_particle,
232 std::shared_ptr< HepMC3::GenParticle >& residual_nucleus,
237 ec->do_decay( Exf, twoJf, Pf, compound_nucleus_, emitted_particle,
238 residual_nucleus, qIon, gen );
245 out <<
"Compound nucleus " << compound_nucleus_->pid()
246 <<
" with Ex = " << Exi_ <<
", spin = " << twoJi_ / 2;
247 if (twoJi_ % 2) out <<
".5";
248 out <<
", and parity = " << Pi_ <<
'\n';
249 out <<
"Total width = " << total_width_ <<
" MeV\n";
250 out <<
"Mean lifetime = " << marley_utils::hbar / total_width_ <<
" s\n";
251 for (
const auto& ec : exit_channels_) {
252 double width = ec->width();
253 bool continuum = ec->is_continuum();
254 bool frag = ec->emits_fragment();
255 int pdg = ec->emitted_particle_pdg();
256 std::string symbol = marley_utils::particle_symbols.at( pdg );
258 if ( frag ) out << symbol;
259 else out <<
"gamma-ray";
260 if ( continuum ) out <<
" emission to the continuum width = ";
263 if ( !dec )
throw marley::Error(
"Dynamic cast failed in marley::"
264 "HauserFeshbachDecay::print()" );
265 out <<
" emission to level at " << dec->get_final_level().energy()
268 out << width <<
" MeV\n";
272const std::unique_ptr< marley::ExitChannel >&
277 if ( total_width_ <= 0. )
throw marley::Error(
"Cannot sample an exit channel"
278 " for a Hauser-Feshbach decay. All partial decay widths are zero." );
282 const auto widths_begin
284 const auto widths_end
287 std::discrete_distribution<size_t> exit_channel_dist( widths_begin,
291 const auto& ec = exit_channels_.at( exit_channel_index );
294 double width_ec = ec->width();
295 double branching = ( total_width_ > 0. ) ? ( width_ec / total_width_ ) : 0.;
296 int ec_pdg = ec->emitted_particle_pdg();
297 std::string ec_symbol = marley_utils::particle_symbols.count( ec_pdg )
298 ? marley_utils::particle_symbols.at( ec_pdg ) : std::to_string( ec_pdg );
299 MARLEY_LOG( DEBUG,
"physics.deexcitation.hauser" ) <<
"Selected exit channel:"
300 " emits " << ec_symbol
301 << ( ec->is_continuum() ?
" to continuum" :
" to discrete level" )
302 <<
", width = " << width_ec <<
" MeV"
303 <<
", branching fraction = " << branching;
Discrete level and γ-ray data for a specific nuclide.
const std::vector< std::unique_ptr< marley::Level > > & get_levels() const
Get a const reference to the vector that holds the Level objects.
Abstract base class for ExitChannel objects that lead to discrete nuclear levels in the final state.
Base class for all exceptions thrown by MARLEY functions.
Abstract base class for compound nucleus de-excitation channels.
static marley::IteratorToPointerMember< It, double > make_width_iterator(It it)
Convert an iterator that points to an ExitChannel object into an iterator to the ExitChannel's width_...
Simple container for storing reference data about each of the nuclear fragments considered by MARLEY'...
int get_Z() const
Get the atomic number of this fragment.
int get_A() const
Get the mass number of this fragment.
int get_pid() const
Get the PDG particle ID for this fragment.
The MARLEY Event generator.
auto sample_from_distribution(RandomNumberDistribution &rnd) -> decltype(std::declval< RandomNumberDistribution & >().operator()(std::declval< std::mt19937_64 & >()))
Sample from an arbitrary probability distribution (defined here as any object that implements an oper...
const marley::ExitChannel & do_decay(double &Exf, int &twoJf, marley::Parity &Pf, std::shared_ptr< HepMC3::GenParticle > &emitted_particle, std::shared_ptr< HepMC3::GenParticle > &residual_nucleus, int &qIon, marley::Generator &gen)
Simulates a decay of the compound nucleus.
void print(std::ostream &out) const
Print information about the possible decay channels to a std::ostream.
HauserFeshbachDecay(const std::shared_ptr< HepMC3::GenParticle > &compound_nucleus, double Exi, int twoJi, marley::Parity Pi, marley::StructureDatabase &sdb)
const std::unique_ptr< marley::ExitChannel > & sample_exit_channel(marley::Generator &gen) const
Helper function for do_decay(). Samples an ExitChannel using the partial decay widths as weights.
Abstract base class for models of nuclear level densities.
virtual double level_density(double Ex)=0
static const MassTable & Instance()
Get a const reference to the singleton instance of the MassTable.
Type-safe representation of a parity value (either +1 or -1)
Container for nuclear structure information organized by nuclide.
static const std::map< int, marley::Fragment > & fragments()
Retrieves a const reference to the table of Fragment objects.
marley::DecayScheme * get_decay_scheme(const int particle_id)
Retrieves discrete level data from the database.
marley::LevelDensityModel & get_level_density_model(const int nucleus_pid)
Retrieves a level density model object from the database, creating it if one did not already exist.