From 5cc92e54478193b314f31045031f9ad978b04482 Mon Sep 17 00:00:00 2001 From: Luca Fedeli Date: Wed, 4 May 2022 18:47:35 +0200 Subject: [PATCH 01/63] initial work --- .../BackTransformParticleFunctor.cpp | 3 + Source/Initialization/PlasmaInjector.cpp | 5 +- Source/Particles/CMakeLists.txt | 1 + .../Particles/Deposition/CurrentDeposition.H | 1 + Source/Particles/Gather/GetExternalFields.H | 1 + Source/Particles/Make.package | 1 + Source/Particles/SpeciesPhysicalProperties.H | 197 +++--------------- .../Particles/SpeciesPhysicalProperties.cpp | 124 +++++++++++ 8 files changed, 167 insertions(+), 166 deletions(-) create mode 100644 Source/Particles/SpeciesPhysicalProperties.cpp diff --git a/Source/Diagnostics/ComputeDiagFunctors/BackTransformParticleFunctor.cpp b/Source/Diagnostics/ComputeDiagFunctors/BackTransformParticleFunctor.cpp index e62b18a2785..fc3aee298c8 100644 --- a/Source/Diagnostics/ComputeDiagFunctors/BackTransformParticleFunctor.cpp +++ b/Source/Diagnostics/ComputeDiagFunctors/BackTransformParticleFunctor.cpp @@ -5,9 +5,12 @@ * License: BSD-3-Clause-LBNL */ #include "BackTransformParticleFunctor.H" + #include "Particles/Pusher/GetAndSetPosition.H" #include "Particles/WarpXParticleContainer.H" +#include "Utils/WarpXConst.H" #include "WarpX.H" + #include #include #include diff --git a/Source/Initialization/PlasmaInjector.cpp b/Source/Initialization/PlasmaInjector.cpp index e3bfaa2c9c8..fa61df4823e 100644 --- a/Source/Initialization/PlasmaInjector.cpp +++ b/Source/Initialization/PlasmaInjector.cpp @@ -125,7 +125,10 @@ PlasmaInjector::PlasmaInjector (int ispecies, const std::string& name) std::string physical_species_s; bool species_is_specified = pp_species_name.query("species_type", physical_species_s); if (species_is_specified){ - physical_species = species::from_string( physical_species_s ); + const auto physical_species_from_string = species::from_string( physical_species_s ); + WARPX_ALWAYS_ASSERT_WITH_MESSAGE(physical_species_from_string, + physical_species_s + " does not exist!"); + physical_species = physical_species_from_string.value(); charge = species::get_charge( physical_species ); mass = species::get_mass( physical_species ); } diff --git a/Source/Particles/CMakeLists.txt b/Source/Particles/CMakeLists.txt index 6dd553f2415..4fd69f8539e 100644 --- a/Source/Particles/CMakeLists.txt +++ b/Source/Particles/CMakeLists.txt @@ -8,6 +8,7 @@ target_sources(WarpX WarpXParticleContainer.cpp LaserParticleContainer.cpp ParticleBoundaryBuffer.cpp + SpeciesPhysicalProperties.cpp ) #add_subdirectory(Algorithms) diff --git a/Source/Particles/Deposition/CurrentDeposition.H b/Source/Particles/Deposition/CurrentDeposition.H index f508871c672..edeaba7cd63 100644 --- a/Source/Particles/Deposition/CurrentDeposition.H +++ b/Source/Particles/Deposition/CurrentDeposition.H @@ -12,6 +12,7 @@ #include "Particles/Pusher/GetAndSetPosition.H" #include "Particles/ShapeFactors.H" #include "Utils/WarpXAlgorithmSelection.H" +#include "Utils/WarpXConst.H" #ifdef WARPX_DIM_RZ # include "Utils/WarpX_Complex.H" #endif diff --git a/Source/Particles/Gather/GetExternalFields.H b/Source/Particles/Gather/GetExternalFields.H index 3c1dfdf60d9..94ae2d59c71 100644 --- a/Source/Particles/Gather/GetExternalFields.H +++ b/Source/Particles/Gather/GetExternalFields.H @@ -4,6 +4,7 @@ #include "Particles/Pusher/GetAndSetPosition.H" #include "Particles/WarpXParticleContainer_fwd.H" +#include "Utils/WarpXConst.H" #include #include diff --git a/Source/Particles/Make.package b/Source/Particles/Make.package index d0f7fc87040..58cbe11a980 100644 --- a/Source/Particles/Make.package +++ b/Source/Particles/Make.package @@ -6,6 +6,7 @@ CEXE_sources += PhotonParticleContainer.cpp CEXE_sources += LaserParticleContainer.cpp CEXE_sources += ParticleBoundaryBuffer.cpp CEXE_sources += ParticleBoundaries.cpp +CEXE_sources += SpeciesPhysicalProperties.cpp include $(WARPX_HOME)/Source/Particles/Algorithms/Make.package include $(WARPX_HOME)/Source/Particles/Pusher/Make.package diff --git a/Source/Particles/SpeciesPhysicalProperties.H b/Source/Particles/SpeciesPhysicalProperties.H index b70f95c5014..4382ac02ee5 100644 --- a/Source/Particles/SpeciesPhysicalProperties.H +++ b/Source/Particles/SpeciesPhysicalProperties.H @@ -8,13 +8,9 @@ #ifndef WARPX_SPECIESPHYSICALPROPERTIES_H_ #define WARPX_SPECIESPHYSICALPROPERTIES_H_ -#include "Utils/WarpXConst.H" - -#include #include -#include -#include +#include #include enum struct PhysicalSpecies{unspecified=0, electron, positron, photon, hydrogen, helium, boron, @@ -22,166 +18,37 @@ enum struct PhysicalSpecies{unspecified=0, electron, positron, photon, hydrogen, namespace species { - AMREX_FORCE_INLINE - PhysicalSpecies from_string(std::string species) - { - if( species=="unspecified" ) - return PhysicalSpecies::unspecified; - if( species=="electron" ) - return PhysicalSpecies::electron; - if( species=="positron" ) - return PhysicalSpecies::positron; - if( species=="photon" ) - return PhysicalSpecies::photon; - if( species=="hydrogen" ) - return PhysicalSpecies::hydrogen; - if( species=="proton" ) - return PhysicalSpecies::hydrogen; - if( species=="helium" ) - return PhysicalSpecies::helium; - if( species=="alpha" ) - return PhysicalSpecies::helium; - if( species=="boron" ) - return PhysicalSpecies::boron; - if( species=="boron10" ) - return PhysicalSpecies::boron10; - if( species=="boron11" ) - return PhysicalSpecies::boron11; - if( species=="carbon" ) - return PhysicalSpecies::carbon; - if( species=="nitrogen" ) - return PhysicalSpecies::nitrogen; - if( species=="oxygen" ) - return PhysicalSpecies::oxygen; - if( species=="argon" ) - return PhysicalSpecies::argon; - if( species=="copper" ) - return PhysicalSpecies::copper; - if( species=="xenon" ) - return PhysicalSpecies::xenon; - amrex::Abort("unknown PhysicalSpecies"); - return PhysicalSpecies::unspecified; - } - - AMREX_FORCE_INLINE - amrex::Real get_charge (PhysicalSpecies ps) - { - switch(ps) { - case PhysicalSpecies::unspecified: - return std::numeric_limits::quiet_NaN(); - case PhysicalSpecies::electron: - return -PhysConst::q_e; - case PhysicalSpecies::positron: - return PhysConst::q_e; - case PhysicalSpecies::photon: - return 0.; - case PhysicalSpecies::hydrogen: - return PhysConst::q_e; - case PhysicalSpecies::helium: - return PhysConst::q_e * amrex::Real(2.0); - case PhysicalSpecies::boron: - return PhysConst::q_e * amrex::Real(5.0); - case PhysicalSpecies::boron10: - return PhysConst::q_e * amrex::Real(5.0); - case PhysicalSpecies::boron11: - return PhysConst::q_e * amrex::Real(5.0); - case PhysicalSpecies::carbon: - return PhysConst::q_e * amrex::Real(6.0); - case PhysicalSpecies::nitrogen: - return PhysConst::q_e * amrex::Real(7.0); - case PhysicalSpecies::oxygen: - return PhysConst::q_e * amrex::Real(8.0); - case PhysicalSpecies::argon: - return PhysConst::q_e * amrex::Real(18.0); - case PhysicalSpecies::copper: - return PhysConst::q_e * amrex::Real(29.0); - case PhysicalSpecies::xenon: - return PhysConst::q_e * amrex::Real(54.0); - default: - amrex::Abort("unknown PhysicalSpecies"); - return 0.; - } - } - - AMREX_FORCE_INLINE - amrex::Real get_mass (PhysicalSpecies ps) - { - switch(ps) { - case PhysicalSpecies::unspecified: - return std::numeric_limits::quiet_NaN(); - case PhysicalSpecies::electron: - return PhysConst::m_e; - case PhysicalSpecies::positron: - return PhysConst::m_e; - case PhysicalSpecies::photon: - return 0.; - case PhysicalSpecies::hydrogen: - return PhysConst::m_p; - case PhysicalSpecies::helium: - return PhysConst::m_p * amrex::Real(3.97369); - case PhysicalSpecies::boron: - return PhysConst::m_p * amrex::Real(10.7319); - case PhysicalSpecies::boron10: - return PhysConst::m_p * amrex::Real(9.94060); - case PhysicalSpecies::boron11: - return PhysConst::m_p * amrex::Real(10.9298); - case PhysicalSpecies::carbon: - return PhysConst::m_e * amrex::Real(22032.0); - case PhysicalSpecies::nitrogen: - return PhysConst::m_e * amrex::Real(25716.9); - case PhysicalSpecies::oxygen: - return PhysConst::m_p * amrex::Real(15.8834); - case PhysicalSpecies::argon: - return PhysConst::m_p * amrex::Real(39.9480); - case PhysicalSpecies::copper: - return PhysConst::m_p * amrex::Real(63.0864); - case PhysicalSpecies::xenon: - return PhysConst::m_p * amrex::Real(131.293); - default: - amrex::Abort("unknown PhysicalSpecies"); - return 0.; - } - } - - AMREX_FORCE_INLINE - std::string get_name (PhysicalSpecies ps) - { - switch(ps) { - case PhysicalSpecies::unspecified: - return "unspecified"; - case PhysicalSpecies::electron: - return "electron"; - case PhysicalSpecies::positron: - return "positron"; - case PhysicalSpecies::photon: - return "photon"; - case PhysicalSpecies::hydrogen: - return "hydrogen"; - case PhysicalSpecies::helium: - return "helium"; - case PhysicalSpecies::boron: - return "boron"; - case PhysicalSpecies::boron10: - return "boron10"; - case PhysicalSpecies::boron11: - return "boron11"; - case PhysicalSpecies::carbon: - return "carbon"; - case PhysicalSpecies::nitrogen: - return "nitrogen"; - case PhysicalSpecies::oxygen: - return "oxygen"; - case PhysicalSpecies::argon: - return "argon"; - case PhysicalSpecies::copper: - return "copper"; - case PhysicalSpecies::xenon: - return "xenon"; - default: - amrex::Abort("unknown PhysicalSpecies"); - return ""; - } - } + /** + * \brief Returns the PhysicalSpecies associated to a given name + * + * \param[in] species_name the name of a species + * \return the PhysicalSpecies corresponding to species_name (if it exists) + */ + std::optional from_string (const std::string& species_name); + + /** + * \brief Returns the charge associated to a PhysicalSpecies + * + * \param[in] ps the PhysicalSpecies + * \return the charge associated to the PhysicalSpecies + */ + amrex::Real get_charge (const PhysicalSpecies& ps); + + /** + * \brief Returns the mass associated to a PhysicalSpecies + * + * \param[in] ps the PhysicalSpecies + * \return the mass associated to the PhysicalSpecies + */ + amrex::Real get_mass (const PhysicalSpecies& ps); + + /** + * \brief Returns the name associated to a PhysicalSpecies + * + * \param[in] ps the PhysicalSpecies + * \return the name associated to the PhysicalSpecies + */ + std::string get_name (const PhysicalSpecies& ps); } #endif // WARPX_SPECIESPHYSICALPROPERTIES_H_ diff --git a/Source/Particles/SpeciesPhysicalProperties.cpp b/Source/Particles/SpeciesPhysicalProperties.cpp new file mode 100644 index 00000000000..b4ed8779126 --- /dev/null +++ b/Source/Particles/SpeciesPhysicalProperties.cpp @@ -0,0 +1,124 @@ +/* Copyright 2021 Luca Fedeli Maxence Thevenet + * + * This file is part of WarpX. + * + * License: BSD-3-Clause-LBNL + */ +#include "SpeciesPhysicalProperties.H" + +#include "Utils/WarpXConst.H" + +#include + +#include +#include +#include + +using namespace species; + +namespace { + struct Properties + { + amrex::Real mass; + amrex::Real charge; + }; + + const auto string_to_species = std::map{ + {"unspecified", PhysicalSpecies::unspecified}, + {"electron" , PhysicalSpecies::electron}, + {"positron" , PhysicalSpecies::positron}, + {"photon" , PhysicalSpecies::photon}, + {"hydrogen" , PhysicalSpecies::hydrogen}, + {"proton" , PhysicalSpecies::hydrogen}, + {"helium" , PhysicalSpecies::helium}, + {"alpha" , PhysicalSpecies::helium}, + {"boron" , PhysicalSpecies::boron}, + {"boron10" , PhysicalSpecies::boron10}, + {"boron11" , PhysicalSpecies::boron11}, + {"carbon" , PhysicalSpecies::carbon}, + {"nitrogen" , PhysicalSpecies::nitrogen}, + {"oxygen" , PhysicalSpecies::oxygen}, + {"argon" , PhysicalSpecies::argon}, + {"copper" , PhysicalSpecies::copper}, + {"xenon" , PhysicalSpecies::xenon} + }; + + const auto species_to_string = std::map{ + {PhysicalSpecies::unspecified, "unspecified"}, + {hysicalSpecies::electron , "electron"}, + {PhysicalSpecies::positron , "positron"}, + {PhysicalSpecies::photon , "photon"}, + {PhysicalSpecies::hydrogen , "hydrogen"}, + {PhysicalSpecies::helium , "helium"}, + {PhysicalSpecies::boron , "boron"}, + {PhysicalSpecies::boron10 , "boron10"}, + {PhysicalSpecies::boron11 , "boron11"}, + {PhysicalSpecies::carbon , "carbon"}, + {PhysicalSpecies::nitrogen , "nitrogen"}, + {PhysicalSpecies::oxygen , "oxygen"}, + {PhysicalSpecies::argon , "argon"}, + {PhysicalSpecies::copper , "copper"}, + {PhysicalSpecies::xenon , "xenon"} + }; + + constexpr auto quiet_NaN = std::numeric_limits::quiet_NaN(); + + const + std::map species_to_properties + { + {PhysicalSpecies::unspecified, + Properties{quiet_NaN, quiet_NaN}}, + {PhysicalSpecies::electron, + Properties{PhysConst::m_e, -PhysConst::q_e}}, + {PhysicalSpecies::positron, + Properties{PhysConst::m_e, PhysConst::q_e}}, + {PhysicalSpecies::photon , + Properties{amrex::Real(0.0), PhysConst::q_e}}, + {PhysicalSpecies::hydrogen, + Properties{PhysConst::m_p, PhysConst::q_e}}, + {PhysicalSpecies::helium, + Properties{PhysConst::m_p * amrex::Real(3.97369), PhysConst::q_e * amrex::Real(2.0)}}, + {PhysicalSpecies::boron, + Properties{PhysConst::m_p * amrex::Real(10.7319), PhysConst::q_e * amrex::Real(5.0)}}, + {PhysicalSpecies::boron10, + Properties{PhysConst::m_p * amrex::Real(9.94060), PhysConst::q_e * amrex::Real(5.0)}}, + {PhysicalSpecies::boron11, + Properties{PhysConst::m_p * amrex::Real(10.9298), PhysConst::q_e * amrex::Real(5.0)}}, + {PhysicalSpecies::carbon, + Properties{PhysConst::m_e * amrex::Real(22032.0), PhysConst::q_e * amrex::Real(6.0)}}, + {PhysicalSpecies::nitrogen, + Properties{PhysConst::m_e * amrex::Real(25716.9), PhysConst::q_e * amrex::Real(7.0)}}, + {PhysicalSpecies::oxygen, + Properties{PhysConst::m_p * amrex::Real(15.8834), PhysConst::q_e * amrex::Real(8.0)}}, + {PhysicalSpecies::argon, + Properties{PhysConst::m_p * amrex::Real(39.9480), PhysConst::q_e * amrex::Real(18.0)}}, + {PhysicalSpecies::copper, + Properties{PhysConst::m_p * amrex::Real(63.0864), PhysConst::q_e * amrex::Real(29.0)}}, + {PhysicalSpecies::xenon, + Properties{hysConst::m_p * amrex::Real(131.293), PhysConst::q_e * amrex::Real(54.0)}} + }; +} + +namespace species +{ + std::optional from_string(std::string species) + { + const auto phys_spec = string_to_species.find(species); + return (phys_spec != species.end())? + phys_spec : std::nullopt; + } + + amrex::Real get_charge (PhysicalSpecies ps) + { + return species_to_properties.at(ps).charge; + } + + amrex::Real get_mass (PhysicalSpecies ps) + { + return species_to_properties.at(ps).mass; + } + + std::string get_name (PhysicalSpecies ps) + { + return species_to_string.at(ps); + } From fc3334dfc25ab6e48b906a627a7523925739d952 Mon Sep 17 00:00:00 2001 From: Luca Fedeli Date: Thu, 5 May 2022 14:32:42 +0200 Subject: [PATCH 02/63] fixed bugs and added species --- Source/Particles/SpeciesPhysicalProperties.H | 7 +- .../Particles/SpeciesPhysicalProperties.cpp | 153 +++++++++++++++--- Source/Utils/ParticleUtils.H | 1 + 3 files changed, 135 insertions(+), 26 deletions(-) diff --git a/Source/Particles/SpeciesPhysicalProperties.H b/Source/Particles/SpeciesPhysicalProperties.H index 4382ac02ee5..ba85a95ace9 100644 --- a/Source/Particles/SpeciesPhysicalProperties.H +++ b/Source/Particles/SpeciesPhysicalProperties.H @@ -13,8 +13,11 @@ #include #include -enum struct PhysicalSpecies{unspecified=0, electron, positron, photon, hydrogen, helium, boron, - boron10, boron11, carbon, nitrogen, oxygen, argon, copper, xenon}; +enum struct PhysicalSpecies{ + unspecified=0, electron, positron, muon, antimuon, photon, hydrogen, protium, deuterium, tritium, proton, + helium, helium3, helium4, alpha, lithium, lithium6, lithium7, beryllium, boron, boron10, boron11, carbon, + carbon12, carbon13, nitrogen, nitrogen14, nitrogen15, oxygen, oxygen16, oxygen17, oxygen18, fluorine, + neon, neon20, neon21, neon22, aluminium, argon, copper, xenon, gold}; namespace species { diff --git a/Source/Particles/SpeciesPhysicalProperties.cpp b/Source/Particles/SpeciesPhysicalProperties.cpp index b4ed8779126..cf562d7c97f 100644 --- a/Source/Particles/SpeciesPhysicalProperties.cpp +++ b/Source/Particles/SpeciesPhysicalProperties.cpp @@ -27,38 +27,88 @@ namespace { {"unspecified", PhysicalSpecies::unspecified}, {"electron" , PhysicalSpecies::electron}, {"positron" , PhysicalSpecies::positron}, + {"muon" , PhysicalSpecies::muon}, + {"antimuon" , PhysicalSpecies::antimuon}, {"photon" , PhysicalSpecies::photon}, {"hydrogen" , PhysicalSpecies::hydrogen}, - {"proton" , PhysicalSpecies::hydrogen}, + {"protium" , PhysicalSpecies::protium}, + {"deuterium" , PhysicalSpecies::deuterium}, + {"tritium" , PhysicalSpecies::tritium}, + {"proton" , PhysicalSpecies::proton}, {"helium" , PhysicalSpecies::helium}, {"alpha" , PhysicalSpecies::helium}, + {"helium3" , PhysicalSpecies::helium3}, + {"helium4" , PhysicalSpecies::helium4}, + {"alpha" , PhysicalSpecies::alpha}, + {"lithium" , PhysicalSpecies::lithium}, + {"lithium6" , PhysicalSpecies::lithium6}, + {"lithium7" , PhysicalSpecies::lithium7}, + {"beryllium" , PhysicalSpecies::beryllium}, {"boron" , PhysicalSpecies::boron}, {"boron10" , PhysicalSpecies::boron10}, {"boron11" , PhysicalSpecies::boron11}, {"carbon" , PhysicalSpecies::carbon}, + {"carbon12" , PhysicalSpecies::carbon12}, + {"carbon13" , PhysicalSpecies::carbon13}, {"nitrogen" , PhysicalSpecies::nitrogen}, + {"nitrogen14" , PhysicalSpecies::nitrogen14}, + {"nitrogen15" , PhysicalSpecies::nitrogen15}, {"oxygen" , PhysicalSpecies::oxygen}, + {"oxygen16" , PhysicalSpecies::oxygen16}, + {"oxygen17" , PhysicalSpecies::oxygen17}, + {"oxygen18" , PhysicalSpecies::oxygen18}, + {"fluorine" , PhysicalSpecies::fluorine}, + {"neon" , PhysicalSpecies::neon}, + {"neon20" , PhysicalSpecies::neon20}, + {"neon21" , PhysicalSpecies::neon21}, + {"neon22" , PhysicalSpecies::neon22}, + {"aluminium" , PhysicalSpecies::aluminium}, {"argon" , PhysicalSpecies::argon}, {"copper" , PhysicalSpecies::copper}, - {"xenon" , PhysicalSpecies::xenon} + {"xenon" , PhysicalSpecies::xenon}, + {"gold" , PhysicalSpecies::gold}, }; const auto species_to_string = std::map{ {PhysicalSpecies::unspecified, "unspecified"}, - {hysicalSpecies::electron , "electron"}, + {PhysicalSpecies::electron , "electron"}, {PhysicalSpecies::positron , "positron"}, + {PhysicalSpecies::muon , "muon"}, + {PhysicalSpecies::antimuon , "antimuon"}, {PhysicalSpecies::photon , "photon"}, {PhysicalSpecies::hydrogen , "hydrogen"}, + {PhysicalSpecies::protium , "protium"}, + {PhysicalSpecies::deuterium , "deuterium"}, + {PhysicalSpecies::tritium , "tritium"}, + {PhysicalSpecies::proton , "proton"}, {PhysicalSpecies::helium , "helium"}, + {PhysicalSpecies::helium3 , "helium3"}, + {PhysicalSpecies::helium4 , "helium4"}, + {PhysicalSpecies::alpha , "alpha"}, + {PhysicalSpecies::lithium , "lithium"}, + {PhysicalSpecies::lithium6 , "lithium6"}, + {PhysicalSpecies::lithium7 , "lithium7"}, + {PhysicalSpecies::beryllium , "beryllium"}, {PhysicalSpecies::boron , "boron"}, {PhysicalSpecies::boron10 , "boron10"}, {PhysicalSpecies::boron11 , "boron11"}, {PhysicalSpecies::carbon , "carbon"}, + {PhysicalSpecies::carbon12 , "carbon12"}, + {PhysicalSpecies::carbon13 , "carbon13"}, {PhysicalSpecies::nitrogen , "nitrogen"}, + {PhysicalSpecies::nitrogen14 , "nitrogen14"}, + {PhysicalSpecies::nitrogen15 , "nitrogen15"}, {PhysicalSpecies::oxygen , "oxygen"}, + {PhysicalSpecies::fluorine , "fluorine"}, + {PhysicalSpecies::neon , "neon"}, + {PhysicalSpecies::neon20 , "neon20"}, + {PhysicalSpecies::neon21 , "neon21"}, + {PhysicalSpecies::neon22 , "neon22"}, + {PhysicalSpecies::aluminium , "aluminium"}, {PhysicalSpecies::argon , "argon"}, {PhysicalSpecies::copper , "copper"}, - {PhysicalSpecies::xenon , "xenon"} + {PhysicalSpecies::xenon , "xenon"}, + {PhysicalSpecies::gold , "gold"} }; constexpr auto quiet_NaN = std::numeric_limits::quiet_NaN(); @@ -69,56 +119,111 @@ namespace { {PhysicalSpecies::unspecified, Properties{quiet_NaN, quiet_NaN}}, {PhysicalSpecies::electron, - Properties{PhysConst::m_e, -PhysConst::q_e}}, + Properties{ PhysConst::m_e, -PhysConst::q_e}}, {PhysicalSpecies::positron, - Properties{PhysConst::m_e, PhysConst::q_e}}, + Properties{ PhysConst::m_e, PhysConst::q_e}}, + {PhysicalSpecies::muon, + Properties{amrex::Real(206.7682830) * PhysConst::m_e, -PhysConst::q_e}}, + {PhysicalSpecies::antimuon, + Properties{amrex::Real(206.7682830) * PhysConst::m_e, PhysConst::q_e}}, {PhysicalSpecies::photon , - Properties{amrex::Real(0.0), PhysConst::q_e}}, + Properties{ amrex::Real(0.0), amrex::Real(0.0)}}, {PhysicalSpecies::hydrogen, - Properties{PhysConst::m_p, PhysConst::q_e}}, + Properties{ amrex::Real(1.008) * PhysConst::m_u, PhysConst::q_e}}, + {PhysicalSpecies::protium, + Properties{ amrex::Real(1.0078) * PhysConst::m_u, PhysConst::q_e}}, + {PhysicalSpecies::deuterium, + Properties{ amrex::Real(2.0141) * PhysConst::m_u, PhysConst::q_e}}, + {PhysicalSpecies::tritium, + Properties{ amrex::Real(3.0160) * PhysConst::m_u, PhysConst::q_e}}, + {PhysicalSpecies::proton, + Properties{ PhysConst::m_p, PhysConst::q_e}}, {PhysicalSpecies::helium, - Properties{PhysConst::m_p * amrex::Real(3.97369), PhysConst::q_e * amrex::Real(2.0)}}, + Properties{ amrex::Real(4.0026) * PhysConst::m_u, amrex::Real(2.0) * PhysConst::q_e}}, + {PhysicalSpecies::helium3, + Properties{ amrex::Real(3.0160) * PhysConst::m_u, amrex::Real(2.0) * PhysConst::q_e}}, + {PhysicalSpecies::helium4, + Properties{ amrex::Real(4.0026) * PhysConst::m_u, amrex::Real(2.0) * PhysConst::q_e}}, + {PhysicalSpecies::alpha, + Properties{ amrex::Real(4.0015) * PhysConst::m_u, amrex::Real(2.0) * PhysConst::q_e}}, + {PhysicalSpecies::lithium, + Properties{ amrex::Real(6.94) * PhysConst::m_u, amrex::Real(3.0) * PhysConst::q_e}}, + {PhysicalSpecies::lithium6, + Properties{ amrex::Real(6.0151) * PhysConst::m_u, amrex::Real(3.0) * PhysConst::q_e}}, + {PhysicalSpecies::lithium7, + Properties{ amrex::Real(7.0160) * PhysConst::m_u, amrex::Real(3.0) * PhysConst::q_e}}, + {PhysicalSpecies::beryllium, + Properties{ amrex::Real(9.0122) * PhysConst::m_u, amrex::Real(4.0) * PhysConst::q_e}}, {PhysicalSpecies::boron, - Properties{PhysConst::m_p * amrex::Real(10.7319), PhysConst::q_e * amrex::Real(5.0)}}, + Properties{ amrex::Real(10.81) * PhysConst::m_u, amrex::Real(5.0) * PhysConst::q_e}}, {PhysicalSpecies::boron10, - Properties{PhysConst::m_p * amrex::Real(9.94060), PhysConst::q_e * amrex::Real(5.0)}}, + Properties{ amrex::Real(10.0129) * PhysConst::m_u, amrex::Real(5.0) * PhysConst::q_e}}, {PhysicalSpecies::boron11, - Properties{PhysConst::m_p * amrex::Real(10.9298), PhysConst::q_e * amrex::Real(5.0)}}, + Properties{ amrex::Real(11.0093) * PhysConst::m_u, amrex::Real(5.0) * PhysConst::q_e}}, {PhysicalSpecies::carbon, - Properties{PhysConst::m_e * amrex::Real(22032.0), PhysConst::q_e * amrex::Real(6.0)}}, + Properties{ amrex::Real(12.011) * PhysConst::m_u, amrex::Real(6.0) * PhysConst::q_e}}, + {PhysicalSpecies::carbon12, + Properties{ amrex::Real(12) * PhysConst::m_u, amrex::Real(6.0) * PhysConst::q_e}}, + {PhysicalSpecies::carbon13, + Properties{ amrex::Real(13.0033) * PhysConst::m_u, amrex::Real(6.0) * PhysConst::q_e}}, {PhysicalSpecies::nitrogen, - Properties{PhysConst::m_e * amrex::Real(25716.9), PhysConst::q_e * amrex::Real(7.0)}}, + Properties{ amrex::Real(14.007) * PhysConst::m_u, amrex::Real(7.0) * PhysConst::q_e}}, + {PhysicalSpecies::nitrogen14, + Properties{ amrex::Real(14.0031) * PhysConst::m_u, amrex::Real(7.0) * PhysConst::q_e}}, + {PhysicalSpecies::nitrogen15, + Properties{ amrex::Real(15.0001) * PhysConst::m_u, amrex::Real(7.0) * PhysConst::q_e}}, {PhysicalSpecies::oxygen, - Properties{PhysConst::m_p * amrex::Real(15.8834), PhysConst::q_e * amrex::Real(8.0)}}, + Properties{ amrex::Real(15.999) * PhysConst::m_u, amrex::Real(8.0) * PhysConst::q_e}}, + {PhysicalSpecies::oxygen16, + Properties{ amrex::Real(15.9949) * PhysConst::m_u, amrex::Real(8.0) * PhysConst::q_e}}, + {PhysicalSpecies::oxygen17, + Properties{ amrex::Real(16.9991) * PhysConst::m_u, amrex::Real(8.0) * PhysConst::q_e}}, + {PhysicalSpecies::oxygen18, + Properties{ amrex::Real(17.9992) * PhysConst::m_u, amrex::Real(8.0) * PhysConst::q_e}}, + {PhysicalSpecies::fluorine, + Properties{ amrex::Real(18.9984) * PhysConst::m_u, amrex::Real(9.0) * PhysConst::q_e}}, + {PhysicalSpecies::neon, + Properties{ amrex::Real(20.1798) * PhysConst::m_u, amrex::Real(10.0) * PhysConst::q_e}}, + {PhysicalSpecies::neon20, + Properties{ amrex::Real(19.9924) * PhysConst::m_u, amrex::Real(10.0) * PhysConst::q_e}}, + {PhysicalSpecies::neon21, + Properties{ amrex::Real(20.9938) * PhysConst::m_u, amrex::Real(10.0) * PhysConst::q_e}}, + {PhysicalSpecies::neon22, + Properties{ amrex::Real(21.9914) * PhysConst::m_u, amrex::Real(10.0) * PhysConst::q_e}}, + {PhysicalSpecies::aluminium, + Properties{ amrex::Real(26.9815) * PhysConst::m_u, amrex::Real(13.0) * PhysConst::q_e}}, {PhysicalSpecies::argon, - Properties{PhysConst::m_p * amrex::Real(39.9480), PhysConst::q_e * amrex::Real(18.0)}}, + Properties{ amrex::Real(39.7924) * PhysConst::m_u, amrex::Real(18.0) * PhysConst::q_e}}, {PhysicalSpecies::copper, - Properties{PhysConst::m_p * amrex::Real(63.0864), PhysConst::q_e * amrex::Real(29.0)}}, + Properties{ amrex::Real(63.546) * PhysConst::m_u, amrex::Real(29.0) * PhysConst::q_e}}, {PhysicalSpecies::xenon, - Properties{hysConst::m_p * amrex::Real(131.293), PhysConst::q_e * amrex::Real(54.0)}} + Properties{ amrex::Real(131.293) * PhysConst::m_u, amrex::Real(54.0) * PhysConst::q_e}}, + {PhysicalSpecies::gold, + Properties{ amrex::Real(196.9666) * PhysConst::m_u, amrex::Real(79.0) * PhysConst::q_e}} }; } namespace species { - std::optional from_string(std::string species) + std::optional from_string(const std::string& species) { const auto phys_spec = string_to_species.find(species); - return (phys_spec != species.end())? - phys_spec : std::nullopt; + return (phys_spec != string_to_species.end())? + std::make_optional(phys_spec->second) : std::nullopt; } - amrex::Real get_charge (PhysicalSpecies ps) + amrex::Real get_charge (const PhysicalSpecies& ps) { return species_to_properties.at(ps).charge; } - amrex::Real get_mass (PhysicalSpecies ps) + amrex::Real get_mass (const PhysicalSpecies& ps) { return species_to_properties.at(ps).mass; } - std::string get_name (PhysicalSpecies ps) + std::string get_name (const PhysicalSpecies& ps) { return species_to_string.at(ps); } +} diff --git a/Source/Utils/ParticleUtils.H b/Source/Utils/ParticleUtils.H index d9cbb92f9d6..c4bcd293b34 100644 --- a/Source/Utils/ParticleUtils.H +++ b/Source/Utils/ParticleUtils.H @@ -8,6 +8,7 @@ #define WARPX_PARTICLE_UTILS_H_ #include "Particles/WarpXParticleContainer.H" +#include "WarpXConst.H" #include #include From d744b7a0619b14940de3f7288797f75840d07d06 Mon Sep 17 00:00:00 2001 From: Luca Fedeli Date: Thu, 5 May 2022 14:43:44 +0200 Subject: [PATCH 03/63] update documentation --- Docs/source/usage/parameters.rst | 15 +++++++++++++-- .../workflows/plot_timestep_duration.rst | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 Docs/source/usage/workflows/plot_timestep_duration.rst diff --git a/Docs/source/usage/parameters.rst b/Docs/source/usage/parameters.rst index abd32175962..fb5bf427033 100644 --- a/Docs/source/usage/parameters.rst +++ b/Docs/source/usage/parameters.rst @@ -570,8 +570,19 @@ Particle initialization * ``.species_type`` (`string`) optional (default `unspecified`) Type of physical species. - Currently, the accepted species are ``"electron"``, ``"positron"``, ``"photon"``, ``"hydrogen"`` (or equivalently ``"proton"``), ``"helium"`` (or equivalently ``"alpha"``), ``"boron"``, ``"carbon"``, ``"oxygen"``, ``"nitrogen"``, ``"argon"``, ``"copper"`` and ``"xenon"``. - Either this or both ``mass`` and ``charge`` have to be specified. + Currently, the accepted species are + ``"electron"``, ``"positron"``, ``"muon"``, ``"antimuon"``, ``"photon"``, ``"proton"`` , ``"alpha"``, + ``"hydrogen"``, ``"protium"``, ``"deuterium"``, ``"tritium"``, ``"helium"``, ``"helium3"``, ``"helium4"``, + ``"lithium"``, ``"lithium6"``, ``"lithium7"``, ``"beryllium"``, ``"boron"``, ``"boron10"``, ``"boron11"``, + ``"carbon"``, ``"carbon12"``, ``"carbon13"``, ``"nitrogen"``, ``"nitrogen14"``, ``"nitrogen15"``, + ``"oxygen"``, ``"oxygen16"``, ``"oxygen17"``, ``"oxygen18"``, ``"fluorine"``, ``"neon"``, ``"neon20"``, + ``"neon21"``, ``"neon22"``, ``"aluminium"``, ``"argon"``, ``"copper"``, ``"xenon"`` and ``"gold"``. + The difference between ``"proton"`` and ``"protium"`` is that the mass of the latter includes also the mass + of the bound electron (same for ``"alpha"`` and ``"helium4"``). When just the name of an element is specified, the mass + is a weighted average of the masses of the stable isotopes. For all the elements with ``Z < 11`` we provide + also the stable isotopes as an option for ``species_type`` (e.g., ``"helium3"`` and ``"helium4"``), as well as all the isotopes + of ``"hydrogen"`` (``"protium"``, ``"deuterium"``, ``"tritium"``). + Either ``species_type`` or both ``mass`` and ``charge`` have to be specified. * ``.charge`` (`float`) optional (default `NaN`) The charge of one `physical` particle of this species. diff --git a/Docs/source/usage/workflows/plot_timestep_duration.rst b/Docs/source/usage/workflows/plot_timestep_duration.rst new file mode 100644 index 00000000000..153edadfdab --- /dev/null +++ b/Docs/source/usage/workflows/plot_timestep_duration.rst @@ -0,0 +1,19 @@ +.. _analyze-timestep-duration: + +Analyze timestep duration +========================= +We provide a simple python script to generate plots of the timestep duration +from the stdandard output of WarpX (provided that ``warpx.verbose`` is set to 1): + +:download:`plot_timestep_duration.py<../../../../Tools/PostProcessing/plot_timestep_duration.py>` . + +If the standard output of a simulation has been redirected to a file named ``log_file``, +the script can be used as follows: + +:: + + python plot_timestep_duration.py log_file + +The script generates two pictures: ``log_file_ts_duration.png``, which shows the duration +of each timestep in seconds as a function of the timestep number, and ``log_file_ts_cumulative_duration.png``, +which depicts the total duration of the simulation as a function of the timestep number. From d76866062fa9caf1963a47b2ab854951d23f44b6 Mon Sep 17 00:00:00 2001 From: Luca Fedeli Date: Wed, 18 May 2022 13:25:43 +0200 Subject: [PATCH 04/63] delete unused file --- .../workflows/plot_timestep_duration.rst | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 Docs/source/usage/workflows/plot_timestep_duration.rst diff --git a/Docs/source/usage/workflows/plot_timestep_duration.rst b/Docs/source/usage/workflows/plot_timestep_duration.rst deleted file mode 100644 index 153edadfdab..00000000000 --- a/Docs/source/usage/workflows/plot_timestep_duration.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _analyze-timestep-duration: - -Analyze timestep duration -========================= -We provide a simple python script to generate plots of the timestep duration -from the stdandard output of WarpX (provided that ``warpx.verbose`` is set to 1): - -:download:`plot_timestep_duration.py<../../../../Tools/PostProcessing/plot_timestep_duration.py>` . - -If the standard output of a simulation has been redirected to a file named ``log_file``, -the script can be used as follows: - -:: - - python plot_timestep_duration.py log_file - -The script generates two pictures: ``log_file_ts_duration.png``, which shows the duration -of each timestep in seconds as a function of the timestep number, and ``log_file_ts_cumulative_duration.png``, -which depicts the total duration of the simulation as a function of the timestep number. From 2e5d076a3fb55c7cf3e4cb86ab2c2b265681fa91 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 31 May 2022 12:00:21 -0700 Subject: [PATCH 05/63] Add properties for neutron, hydrogen isotopes, helium isotopes --- Source/Particles/SpeciesPhysicalProperties.H | 41 +++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/Source/Particles/SpeciesPhysicalProperties.H b/Source/Particles/SpeciesPhysicalProperties.H index b70f95c5014..26cc5ebbdaa 100644 --- a/Source/Particles/SpeciesPhysicalProperties.H +++ b/Source/Particles/SpeciesPhysicalProperties.H @@ -17,8 +17,9 @@ #include #include -enum struct PhysicalSpecies{unspecified=0, electron, positron, photon, hydrogen, helium, boron, - boron10, boron11, carbon, nitrogen, oxygen, argon, copper, xenon}; +enum struct PhysicalSpecies{unspecified=0, electron, positron, photon, neutron, + hydrogen, deuterium, tritium, helium, helium3, helium4, boron, boron10, + boron11, carbon, nitrogen, oxygen, argon, copper, xenon}; namespace species { @@ -33,12 +34,22 @@ namespace species return PhysicalSpecies::positron; if( species=="photon" ) return PhysicalSpecies::photon; + if( species=="photon" ) + return PhysicalSpecies::photon; if( species=="hydrogen" ) return PhysicalSpecies::hydrogen; if( species=="proton" ) return PhysicalSpecies::hydrogen; + if( species=="deuterium" ) + return PhysicalSpecies::deuterium; + if( species=="tritium" ) + return PhysicalSpecies::tritium; if( species=="helium" ) return PhysicalSpecies::helium; + if( species=="helium3" ) + return PhysicalSpecies::helium3; + if( species=="helium4" ) + return PhysicalSpecies::helium3; if( species=="alpha" ) return PhysicalSpecies::helium; if( species=="boron" ) @@ -75,10 +86,20 @@ namespace species return PhysConst::q_e; case PhysicalSpecies::photon: return 0.; + case PhysicalSpecies::neutron: + return 0.; case PhysicalSpecies::hydrogen: return PhysConst::q_e; + case PhysicalSpecies::deuterium: + return PhysConst::q_e; + case PhysicalSpecies::tritium: + return PhysConst::q_e; case PhysicalSpecies::helium: return PhysConst::q_e * amrex::Real(2.0); + case PhysicalSpecies::helium3: + return PhysConst::q_e * amrex::Real(2.0); + case PhysicalSpecies::helium4: + return PhysConst::q_e * amrex::Real(2.0); case PhysicalSpecies::boron: return PhysConst::q_e * amrex::Real(5.0); case PhysicalSpecies::boron10: @@ -115,10 +136,22 @@ namespace species return PhysConst::m_e; case PhysicalSpecies::photon: return 0.; + case PhysicalSpecies::neutron: + return PhysConst::m_p * amrex::Real(1.0013784193052508); + case PhysicalSpecies::hydrogen: + return PhysConst::m_p; case PhysicalSpecies::hydrogen: return PhysConst::m_p; + case PhysicalSpecies::deuterium: + return PhysConst::m_p * amrex::Real(1.9990075013626882); + case PhysicalSpecies::tritium: + return PhysConst::m_p * amrex::Real(2.9937170341239963); case PhysicalSpecies::helium: return PhysConst::m_p * amrex::Real(3.97369); + case PhysicalSpecies::helium3: + return PhysConst::m_p * amrex::Real(2.99369); + case PhysicalSpecies::helium4: + return PhysConst::m_p * amrex::Real(3.97314); case PhysicalSpecies::boron: return PhysConst::m_p * amrex::Real(10.7319); case PhysicalSpecies::boron10: @@ -157,6 +190,10 @@ namespace species return "photon"; case PhysicalSpecies::hydrogen: return "hydrogen"; + case PhysicalSpecies::deuterium: + return "deuterium"; + case PhysicalSpecies::tritium: + return "tritium"; case PhysicalSpecies::helium: return "helium"; case PhysicalSpecies::boron: From 029f3e1a5c220ec4f43ddcaea4301d19fc52cf61 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 31 May 2022 12:15:13 -0700 Subject: [PATCH 06/63] Update code to be more consistent --- Source/Particles/SpeciesPhysicalProperties.H | 46 ++++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Source/Particles/SpeciesPhysicalProperties.H b/Source/Particles/SpeciesPhysicalProperties.H index 26cc5ebbdaa..eee0b216ddc 100644 --- a/Source/Particles/SpeciesPhysicalProperties.H +++ b/Source/Particles/SpeciesPhysicalProperties.H @@ -18,7 +18,7 @@ #include enum struct PhysicalSpecies{unspecified=0, electron, positron, photon, neutron, - hydrogen, deuterium, tritium, helium, helium3, helium4, boron, boron10, + hydrogen, hydrogen2, hydrogen3, helium, helium3, helium4, boron, boron10, boron11, carbon, nitrogen, oxygen, argon, copper, xenon}; namespace species @@ -34,22 +34,20 @@ namespace species return PhysicalSpecies::positron; if( species=="photon" ) return PhysicalSpecies::photon; - if( species=="photon" ) - return PhysicalSpecies::photon; - if( species=="hydrogen" ) + if( species=="neutron" ) + return PhysicalSpecies::neutron; + if( (species=="hydrogen") || (species=="proton") ) return PhysicalSpecies::hydrogen; - if( species=="proton" ) - return PhysicalSpecies::hydrogen; - if( species=="deuterium" ) - return PhysicalSpecies::deuterium; - if( species=="tritium" ) - return PhysicalSpecies::tritium; + if( (species=="hydrogen2") || (species=="deuterium") ) + return PhysicalSpecies::hydrogen2; + if (species=="hydrogen3") || (species=="tritium") ) + return PhysicalSpecies::hydrogen3; if( species=="helium" ) return PhysicalSpecies::helium; if( species=="helium3" ) return PhysicalSpecies::helium3; if( species=="helium4" ) - return PhysicalSpecies::helium3; + return PhysicalSpecies::helium4; if( species=="alpha" ) return PhysicalSpecies::helium; if( species=="boron" ) @@ -90,9 +88,9 @@ namespace species return 0.; case PhysicalSpecies::hydrogen: return PhysConst::q_e; - case PhysicalSpecies::deuterium: + case PhysicalSpecies::hydrogen2: return PhysConst::q_e; - case PhysicalSpecies::tritium: + case PhysicalSpecies::hydrogen3: return PhysConst::q_e; case PhysicalSpecies::helium: return PhysConst::q_e * amrex::Real(2.0); @@ -140,12 +138,10 @@ namespace species return PhysConst::m_p * amrex::Real(1.0013784193052508); case PhysicalSpecies::hydrogen: return PhysConst::m_p; - case PhysicalSpecies::hydrogen: - return PhysConst::m_p; - case PhysicalSpecies::deuterium: - return PhysConst::m_p * amrex::Real(1.9990075013626882); - case PhysicalSpecies::tritium: - return PhysConst::m_p * amrex::Real(2.9937170341239963); + case PhysicalSpecies::hydrogen2: + return PhysConst::m_p * amrex::Real(1.99901); + case PhysicalSpecies::hydrogen3: + return PhysConst::m_p * amrex::Real(2.99372); case PhysicalSpecies::helium: return PhysConst::m_p * amrex::Real(3.97369); case PhysicalSpecies::helium3: @@ -190,12 +186,16 @@ namespace species return "photon"; case PhysicalSpecies::hydrogen: return "hydrogen"; - case PhysicalSpecies::deuterium: - return "deuterium"; - case PhysicalSpecies::tritium: - return "tritium"; + case PhysicalSpecies::hydrogen2: + return "hydrogen2"; + case PhysicalSpecies::hydrogen3: + return "hydrogen3"; case PhysicalSpecies::helium: return "helium"; + case PhysicalSpecies::helium: + return "helium3"; + case PhysicalSpecies::helium: + return "helium4"; case PhysicalSpecies::boron: return "boron"; case PhysicalSpecies::boron10: From 8ce861d5362e17f9292d6109d8e75a0b3921f108 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 31 May 2022 12:18:46 -0700 Subject: [PATCH 07/63] Correct typo --- Source/Particles/SpeciesPhysicalProperties.H | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Particles/SpeciesPhysicalProperties.H b/Source/Particles/SpeciesPhysicalProperties.H index eee0b216ddc..90609d56e70 100644 --- a/Source/Particles/SpeciesPhysicalProperties.H +++ b/Source/Particles/SpeciesPhysicalProperties.H @@ -192,9 +192,9 @@ namespace species return "hydrogen3"; case PhysicalSpecies::helium: return "helium"; - case PhysicalSpecies::helium: + case PhysicalSpecies::helium3: return "helium3"; - case PhysicalSpecies::helium: + case PhysicalSpecies::helium4: return "helium4"; case PhysicalSpecies::boron: return "boron"; From f716fea804e89c549742407370e0eb07f85590ab Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 31 May 2022 14:25:17 -0700 Subject: [PATCH 08/63] Parse deuterium-tritium fusion --- .../Collision/BinaryCollision/BinaryCollisionUtils.H | 4 ++-- .../BinaryCollision/BinaryCollisionUtils.cpp | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/BinaryCollisionUtils.H b/Source/Particles/Collision/BinaryCollision/BinaryCollisionUtils.H index c20e9716cd5..2333e1f4102 100644 --- a/Source/Particles/Collision/BinaryCollision/BinaryCollisionUtils.H +++ b/Source/Particles/Collision/BinaryCollision/BinaryCollisionUtils.H @@ -12,9 +12,9 @@ #include "Particles/MultiParticleContainer.H" -enum struct CollisionType { ProtonBoronFusion, Undefined }; +enum struct CollisionType { DeuteriumTritiumFusion, ProtonBoronFusion, Undefined }; -enum struct NuclearFusionType { ProtonBoron, Undefined }; +enum struct NuclearFusionType { DeuteriumTritium, ProtonBoron, Undefined }; namespace BinaryCollisionUtils{ diff --git a/Source/Particles/Collision/BinaryCollision/BinaryCollisionUtils.cpp b/Source/Particles/Collision/BinaryCollision/BinaryCollisionUtils.cpp index 7e78d95ed80..20c8fb18150 100644 --- a/Source/Particles/Collision/BinaryCollision/BinaryCollisionUtils.cpp +++ b/Source/Particles/Collision/BinaryCollision/BinaryCollisionUtils.cpp @@ -26,7 +26,14 @@ namespace BinaryCollisionUtils{ auto& species1 = mypc->GetParticleContainerFromName(species_names[0]); auto& species2 = mypc->GetParticleContainerFromName(species_names[1]); - if ((species1.AmIA() && species2.AmIA()) + if ((species1.AmIA() && species2.AmIA()) + || + (species1.AmIA() && species2.AmIA()) + ) + { + return NuclearFusionType::DeuteriumTritium; + } + else if ((species1.AmIA() && species2.AmIA()) || (species1.AmIA() && species2.AmIA()) ) @@ -56,6 +63,8 @@ namespace BinaryCollisionUtils{ CollisionType nuclear_fusion_type_to_collision_type (const NuclearFusionType fusion_type) { + if (fusion_type == NuclearFusionType::DeuteriumTritium) + return CollisionType::DeuteriumTritiumFusion; if (fusion_type == NuclearFusionType::ProtonBoron) return CollisionType::ProtonBoronFusion; amrex::Abort("Invalid nuclear fusion type"); From 9763ad3baf64e6269641170e4d68eccae9c55ae4 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 31 May 2022 14:47:43 -0700 Subject: [PATCH 09/63] Start putting in place the files for deuterium-tritium --- .../DeuteriumTritiumCrossSection.H | 34 ++++++++++ .../DeuteriumTritiumInitializeMomentum.H | 64 +++++++++++++++++++ .../NuclearFusion/NuclearFusionFunc.H | 13 ++++ 3 files changed, 111 insertions(+) create mode 100644 Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumCrossSection.H create mode 100644 Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumInitializeMomentum.H diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumCrossSection.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumCrossSection.H new file mode 100644 index 00000000000..96c7b2ee3ec --- /dev/null +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumCrossSection.H @@ -0,0 +1,34 @@ +/* Copyright 2022 Remi Lehe + * + * This file is part of WarpX. + * + * License: BSD-3-Clause-LBNL + */ + +#ifndef DEUTERIUM_TRITIUM_FUSION_CROSS_SECTION_H +#define DEUTERIUM_TRITIUM_FUSION_CROSS_SECTION_H + +#include "Utils/WarpXConst.H" + +#include + +#include + +/** + * \brief Computes the total deuterium-tritium fusion cross section. + * + * @param[in] E_kin_star the kinetic energy of the deuterium-tritium pair in its center of mass frame, + * in SI units. + * @return The total cross section in SI units (square meters). + */ +AMREX_GPU_HOST_DEVICE AMREX_INLINE +amrex::ParticleReal DeuteriumTritiumFusionCrossSection (const amrex::ParticleReal& E_kin_star) +{ + using namespace amrex::literals; + + // Convert cross section to SI units: barn to square meter + constexpr auto barn_to_sqm = 1.e-28_prt; + return 0.*barn_to_sqm; +} + +#endif // DEUTERIUM_TRITIUM_TRITIUM_FUSION_CROSS_SECTION_H diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumInitializeMomentum.H new file mode 100644 index 00000000000..42932325746 --- /dev/null +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumInitializeMomentum.H @@ -0,0 +1,64 @@ +/* Copyright 2022 Remi Lehe + * + * This file is part of WarpX. + * + * License: BSD-3-Clause-LBNL + */ + +#ifndef DEUTERIUM_TRITIUM_FUSION_INITIALIZE_MOMENTUM_H +#define DEUTERIUM_TRITIUM_FUSION_INITIALIZE_MOMENTUM_H + +#include "Particles/WarpXParticleContainer.H" +#include "Utils/ParticleUtils.H" +#include "Utils/WarpXConst.H" + +#include +#include +#include + +#include +#include + +namespace { + // Define shortcuts for frequently-used type names + using SoaData_type = WarpXParticleContainer::ParticleTileType::ParticleTileDataType; + using ParticleType = WarpXParticleContainer::ParticleType; + using ParticleBins = amrex::DenseBins; + using index_type = ParticleBins::index_type; + + /** + * \brief This function initializes the momentum of the particles produced from + * deuterium-tritium fusion. + * + * @param[in] soa_1 struct of array data of the first colliding species (can be either deuterium + * or tritium) + * @param[in] soa_2 struct of array data of the second colliding species (can be either deuterium + * or tritium) + * @param[out] ... + * @param[in] idx_1 index of first colliding macroparticle + * @param[in] idx_2 index of second colliding macroparticle + * @param[in]... + * @param[in] m1 mass of first colliding species + * @param[in] m2 mass of second colliding species + * @param[in] engine the random engine + */ + AMREX_GPU_HOST_DEVICE AMREX_INLINE + void DeuteriumTritiumFusionInitializeMomentum ( + const SoaData_type& soa_1, const SoaData_type& soa_2, + SoaData_type& soa_alpha, + const index_type& idx_1, const index_type& idx_2, + const index_type& idx_alpha_start, + const amrex::ParticleReal& m1, const amrex::ParticleReal& m2, + const amrex::RandomEngine& engine) + { + // General notations in this function: + // x_sq denotes the square of x + // x_star denotes the value of x in the proton+boron center of mass frame + // x_Bestar denotes the value of x in the Beryllium rest frame + + using namespace amrex::literals; + } + +} + +#endif // DEUTERIUM_TRITIUM_FUSION_INITIALIZE_MOMENTUM_H diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H index b203955150c..12c020ee997 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H @@ -68,6 +68,19 @@ public: amrex::Vector product_species_name; pp_collision_name.getarr("product_species", product_species_name); + if (m_fusion_type == NuclearFusionType::DeuteriumTritium) + { + WARPX_ALWAYS_ASSERT_WITH_MESSAGE( + product_species_name.size() == 2, + "ERROR: Deuterium-tritium must contain exactly two product species"); + auto& product_species1 = mypc->GetParticleContainerFromName(product_species_name[0]); + auto& product_species2 = mypc->GetParticleContainerFromName(product_species_name[1]); + WARPX_ALWAYS_ASSERT_WITH_MESSAGE( + (product_species.AmIA() && product_species.AmIA()) + || + (product_species.AmIA() && product_species.AmIA()), + "ERROR: Product species of deuterium-tritium fusion must be of type neutron and helium4"); + } if (m_fusion_type == NuclearFusionType::ProtonBoron) { WARPX_ALWAYS_ASSERT_WITH_MESSAGE( From ea3217edc44bfd20e9057ea4e7231bc553037b62 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 31 May 2022 14:55:25 -0700 Subject: [PATCH 10/63] Update documentation --- Docs/source/usage/parameters.rst | 7 ++++++- Source/Particles/SpeciesPhysicalProperties.H | 4 +--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Docs/source/usage/parameters.rst b/Docs/source/usage/parameters.rst index 47670c99b9a..c49227d501e 100644 --- a/Docs/source/usage/parameters.rst +++ b/Docs/source/usage/parameters.rst @@ -573,7 +573,12 @@ Particle initialization * ``.species_type`` (`string`) optional (default `unspecified`) Type of physical species. - Currently, the accepted species are ``"electron"``, ``"positron"``, ``"photon"``, ``"hydrogen"`` (or equivalently ``"proton"``), ``"helium"`` (or equivalently ``"alpha"``), ``"boron"``, ``"carbon"``, ``"oxygen"``, ``"nitrogen"``, ``"argon"``, ``"copper"`` and ``"xenon"``. + Currently, the accepted species are ``"electron"``, ``"positron"``, ``"photon"``, + ``"neutron"``, ``"hydrogen"`` (or equivalently ``"proton"``), ``"deuterium"`` + (or equivalently ``"hydrogen2"``), ``"tritium"`` (or equivalently ``"hydrogen3"``), + ``"helium"`` (or equivalently ``"alpha"``), ``"helium3"``, ``"helium4"``, + ``"boron"``, ``"boron10"``, ``"boron11"``, ``"carbon"``, ``"oxygen"``, + ``"nitrogen"``, ``"argon"``, ``"copper"`` and ``"xenon"``. Either this or both ``mass`` and ``charge`` have to be specified. * ``.charge`` (`float`) optional (default `NaN`) diff --git a/Source/Particles/SpeciesPhysicalProperties.H b/Source/Particles/SpeciesPhysicalProperties.H index 90609d56e70..8e6359efb60 100644 --- a/Source/Particles/SpeciesPhysicalProperties.H +++ b/Source/Particles/SpeciesPhysicalProperties.H @@ -42,14 +42,12 @@ namespace species return PhysicalSpecies::hydrogen2; if (species=="hydrogen3") || (species=="tritium") ) return PhysicalSpecies::hydrogen3; - if( species=="helium" ) + if( (species=="helium") || (species=="alpha") ) return PhysicalSpecies::helium; if( species=="helium3" ) return PhysicalSpecies::helium3; if( species=="helium4" ) return PhysicalSpecies::helium4; - if( species=="alpha" ) - return PhysicalSpecies::helium; if( species=="boron" ) return PhysicalSpecies::boron; if( species=="boron10" ) From c5d067c0f17994dedf790c86f03588b5593c3cb7 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 31 May 2022 15:06:09 -0700 Subject: [PATCH 11/63] Prepare structures for deuterium tritium --- .../NuclearFusion/SingleNuclearFusionEvent.H | 7 ++++++- .../Collision/BinaryCollision/ParticleCreationFunc.H | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/SingleNuclearFusionEvent.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/SingleNuclearFusionEvent.H index 30c054bc4be..c68680b82b5 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/SingleNuclearFusionEvent.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/SingleNuclearFusionEvent.H @@ -8,6 +8,7 @@ #ifndef SINGLE_NUCLEAR_FUSION_EVENT_H_ #define SINGLE_NUCLEAR_FUSION_EVENT_H_ +#include "DeuteriumTritiumFusionCrossSection.H" #include "ProtonBoronFusionCrossSection.H" #include "Particles/Collision/BinaryCollision/BinaryCollisionUtils.H" @@ -111,7 +112,11 @@ void SingleNuclearFusionEvent (const amrex::ParticleReal& u1x, const amrex::Part // Compute fusion cross section as a function of kinetic energy in the center of mass frame auto fusion_cross_section = amrex::ParticleReal(0.); - if (fusion_type == NuclearFusionType::ProtonBoron) + if (fusion_type == NuclearFusionType::DeuteriumTritium) + { + fusion_cross_section = DeuteriumTritiumFusionCrossSection(E_kin_star); + } + else if (fusion_type == NuclearFusionType::ProtonBoron) { fusion_cross_section = ProtonBoronFusionCrossSection(E_kin_star); } diff --git a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H index 6a8387eef8c..a8f8c26ed54 100644 --- a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H +++ b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H @@ -10,6 +10,7 @@ #include "BinaryCollisionUtils.H" +#include "Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionInitializeMomentum.H" #include "Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H" #include "Particles/ParticleCreation/SmartCopy.H" #include "Particles/MultiParticleContainer.H" @@ -208,6 +209,10 @@ public: // Initialize the product particles' momentum, using a function depending on the // specific collision type + if (t_collision_type == CollisionType::DeuteriumTritiumFusion) + { + // TODO DeuteriumTritiumFusionInitializeMomentum + } if (t_collision_type == CollisionType::ProtonBoronFusion) { const index_type product_start_index = products_np_data[0] + 2*p_offsets[i]* From 9549830bc680abf05d6fc1c95ac2a9b7a2e4dd52 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 31 May 2022 15:44:00 -0700 Subject: [PATCH 12/63] Fix typo --- Source/Particles/SpeciesPhysicalProperties.H | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Particles/SpeciesPhysicalProperties.H b/Source/Particles/SpeciesPhysicalProperties.H index 8e6359efb60..7355ee6cc68 100644 --- a/Source/Particles/SpeciesPhysicalProperties.H +++ b/Source/Particles/SpeciesPhysicalProperties.H @@ -40,7 +40,7 @@ namespace species return PhysicalSpecies::hydrogen; if( (species=="hydrogen2") || (species=="deuterium") ) return PhysicalSpecies::hydrogen2; - if (species=="hydrogen3") || (species=="tritium") ) + if( (species=="hydrogen3") || (species=="tritium") ) return PhysicalSpecies::hydrogen3; if( (species=="helium") || (species=="alpha") ) return PhysicalSpecies::helium; From 78be34e803c196f6c965c47c3b713ac3dab4b3e7 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 31 May 2022 22:46:52 -0700 Subject: [PATCH 13/63] Fix compilation --- ...iumCrossSection.H => DeuteriumTritiumFusionCrossSection.H} | 0 ...eMomentum.H => DeuteriumTritiumFusionInitializeMomentum.H} | 0 .../BinaryCollision/NuclearFusion/NuclearFusionFunc.H | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename Source/Particles/Collision/BinaryCollision/NuclearFusion/{DeuteriumTritiumCrossSection.H => DeuteriumTritiumFusionCrossSection.H} (100%) rename Source/Particles/Collision/BinaryCollision/NuclearFusion/{DeuteriumTritiumInitializeMomentum.H => DeuteriumTritiumFusionInitializeMomentum.H} (100%) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumCrossSection.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H similarity index 100% rename from Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumCrossSection.H rename to Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionInitializeMomentum.H similarity index 100% rename from Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumInitializeMomentum.H rename to Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionInitializeMomentum.H diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H index 12c020ee997..a502a5c49c8 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H @@ -76,9 +76,9 @@ public: auto& product_species1 = mypc->GetParticleContainerFromName(product_species_name[0]); auto& product_species2 = mypc->GetParticleContainerFromName(product_species_name[1]); WARPX_ALWAYS_ASSERT_WITH_MESSAGE( - (product_species.AmIA() && product_species.AmIA()) + (product_species1.AmIA() && product_species2.AmIA()) || - (product_species.AmIA() && product_species.AmIA()), + (product_species1.AmIA() && product_species2.AmIA()), "ERROR: Product species of deuterium-tritium fusion must be of type neutron and helium4"); } if (m_fusion_type == NuclearFusionType::ProtonBoron) From d6639d67acdeec97b694e69ce8f1297e11bcf59e Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 2 Jun 2022 14:44:03 -0700 Subject: [PATCH 14/63] Add neutron --- Docs/source/usage/parameters.rst | 2 +- Source/Particles/SpeciesPhysicalProperties.H | 2 +- Source/Particles/SpeciesPhysicalProperties.cpp | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Docs/source/usage/parameters.rst b/Docs/source/usage/parameters.rst index fb5bf427033..0fdd3292b35 100644 --- a/Docs/source/usage/parameters.rst +++ b/Docs/source/usage/parameters.rst @@ -571,7 +571,7 @@ Particle initialization * ``.species_type`` (`string`) optional (default `unspecified`) Type of physical species. Currently, the accepted species are - ``"electron"``, ``"positron"``, ``"muon"``, ``"antimuon"``, ``"photon"``, ``"proton"`` , ``"alpha"``, + ``"electron"``, ``"positron"``, ``"muon"``, ``"antimuon"``, ``"photon"``, ``"neutron"``, ``"proton"`` , ``"alpha"``, ``"hydrogen"``, ``"protium"``, ``"deuterium"``, ``"tritium"``, ``"helium"``, ``"helium3"``, ``"helium4"``, ``"lithium"``, ``"lithium6"``, ``"lithium7"``, ``"beryllium"``, ``"boron"``, ``"boron10"``, ``"boron11"``, ``"carbon"``, ``"carbon12"``, ``"carbon13"``, ``"nitrogen"``, ``"nitrogen14"``, ``"nitrogen15"``, diff --git a/Source/Particles/SpeciesPhysicalProperties.H b/Source/Particles/SpeciesPhysicalProperties.H index ba85a95ace9..0740c14d5de 100644 --- a/Source/Particles/SpeciesPhysicalProperties.H +++ b/Source/Particles/SpeciesPhysicalProperties.H @@ -14,7 +14,7 @@ #include enum struct PhysicalSpecies{ - unspecified=0, electron, positron, muon, antimuon, photon, hydrogen, protium, deuterium, tritium, proton, + unspecified=0, electron, positron, muon, antimuon, photon, neutron, hydrogen, protium, deuterium, tritium, proton, helium, helium3, helium4, alpha, lithium, lithium6, lithium7, beryllium, boron, boron10, boron11, carbon, carbon12, carbon13, nitrogen, nitrogen14, nitrogen15, oxygen, oxygen16, oxygen17, oxygen18, fluorine, neon, neon20, neon21, neon22, aluminium, argon, copper, xenon, gold}; diff --git a/Source/Particles/SpeciesPhysicalProperties.cpp b/Source/Particles/SpeciesPhysicalProperties.cpp index cf562d7c97f..ce1bf1dc62a 100644 --- a/Source/Particles/SpeciesPhysicalProperties.cpp +++ b/Source/Particles/SpeciesPhysicalProperties.cpp @@ -30,6 +30,7 @@ namespace { {"muon" , PhysicalSpecies::muon}, {"antimuon" , PhysicalSpecies::antimuon}, {"photon" , PhysicalSpecies::photon}, + {"neutron" , PhysicalSpecies::neutron}, {"hydrogen" , PhysicalSpecies::hydrogen}, {"protium" , PhysicalSpecies::protium}, {"deuterium" , PhysicalSpecies::deuterium}, @@ -76,6 +77,7 @@ namespace { {PhysicalSpecies::muon , "muon"}, {PhysicalSpecies::antimuon , "antimuon"}, {PhysicalSpecies::photon , "photon"}, + {PhysicalSpecies::neutron , "neutron"}, {PhysicalSpecies::hydrogen , "hydrogen"}, {PhysicalSpecies::protium , "protium"}, {PhysicalSpecies::deuterium , "deuterium"}, @@ -126,8 +128,10 @@ namespace { Properties{amrex::Real(206.7682830) * PhysConst::m_e, -PhysConst::q_e}}, {PhysicalSpecies::antimuon, Properties{amrex::Real(206.7682830) * PhysConst::m_e, PhysConst::q_e}}, - {PhysicalSpecies::photon , + {PhysicalSpecies::photon, Properties{ amrex::Real(0.0), amrex::Real(0.0)}}, + {PhysicalSpecies::neutron, + Properties{amrex::Real(1.0013784193052508) * PhysConst::m_p, amrex::Real(0.0)}}, {PhysicalSpecies::hydrogen, Properties{ amrex::Real(1.008) * PhysConst::m_u, PhysConst::q_e}}, {PhysicalSpecies::protium, From 08cd3047be51b35a87ee57f9f2221cee61f7ed59 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 2 Jun 2022 17:00:28 -0700 Subject: [PATCH 15/63] Add correct formula for the cross-section --- .../DeuteriumTritiumFusionCrossSection.H | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H index 96c7b2ee3ec..ab1ce383053 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H @@ -15,10 +15,10 @@ #include /** - * \brief Computes the total deuterium-tritium fusion cross section. + * \brief Computes the total deuterium-tritium fusion cross section, using + * the analytical fits given in H.-S. Bosch and G.M. Hale 1992 Nucl. Fusion 32 611 * - * @param[in] E_kin_star the kinetic energy of the deuterium-tritium pair in its center of mass frame, - * in SI units. + * @param[in] E_kin_star the kinetic energy of the deuterium-tritium pair in its center of mass frame, in keV. * @return The total cross section in SI units (square meters). */ AMREX_GPU_HOST_DEVICE AMREX_INLINE @@ -26,9 +26,39 @@ amrex::ParticleReal DeuteriumTritiumFusionCrossSection (const amrex::ParticleRea { using namespace amrex::literals; - // Convert cross section to SI units: barn to square meter - constexpr auto barn_to_sqm = 1.e-28_prt; - return 0.*barn_to_sqm; + constexpr amrex::ParticleReal joule_to_keV = 1.e-3_prt/PhysConst::q_e; + const amrex::ParticleReal E_keV = E_kin_star*joule_to_keV; + + // If kinetic energy is 0, return a 0 cross section and avoid later division by 0. + if (E_keV == 0._prt) {return 0._prt;} + + // Compute the Gamow constant B_G (in keV^{1/2}) + // (See Eq. 3 in H.-S. Bosch and G.M. Hale 1992 Nucl. Fusion 32 611) + constexpr amrex::ParticleReal m_D = 1.99901 * PhysConst::m_p; + constexpr amrex::ParticleReal m_T = 2.99372 * PhysConst::m_p; + constexpr amrex::ParticleReal m_reduced = m_D*m_T / (m_D + m_T); + constexpr amrex::ParticleReal B_G = MathConst::pi * PhysConst::alpha * 2 * 3 + * std::sqrt( 2*m_reduced*PhysConst::c*PhysConst::c / (1.e3*PhysConst::q_e) ); + + // Compute astrophysical_factor + // (See Eq. 9 and Table IV in H.-S. Bosch and G.M. Hale 1992 Nucl. Fusion 32 611) + constexpr amrex::ParticleReal A1 = 6.927e4; + constexpr amrex::ParticleReal A2 = 7.454e8; + constexpr amrex::ParticleReal A3 = 2.050e6; + constexpr amrex::ParticleReal A4 = 5.2002e4; + constexpr amrex::ParticleReal B1 = 6.38e1; + constexpr amrex::ParticleReal B2 = -9.95e-1; + constexpr amrex::ParticleReal B3 = 6.981e-5; + constexpr amrex::ParticleReal B4 = 1.728e-4; + + amrex::ParticleReal astrophysical_factor = + (A1 + E_keV*(A2 + E_keV*(A3 + E_keV*A4))) / + (1 + E_keV*(B1 + E_keV*(B2 + E_keV*(B3 + E_keV*B4)))); + + // Compute cross-section in SI units + // (See Eq. 8 in H.-S. Bosch and G.M. Hale 1992 Nucl. Fusion 32 611) + constexpr amrex::ParticleReal millibarn_to_sqm = 1.e-31_prt; + return millibarn_to_sqm * astrophysical_factor/E_keV * std::exp(-B_G/std::sqrt(E_keV)); } #endif // DEUTERIUM_TRITIUM_TRITIUM_FUSION_CROSS_SECTION_H From 139eebfc9fc0fb7d44ed57c850ba6489d52ca12b Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 2 Jun 2022 17:02:40 -0700 Subject: [PATCH 16/63] Correct compilation error --- .../NuclearFusion/DeuteriumTritiumFusionCrossSection.H | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H index ab1ce383053..0b3e2006cbc 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H @@ -18,7 +18,7 @@ * \brief Computes the total deuterium-tritium fusion cross section, using * the analytical fits given in H.-S. Bosch and G.M. Hale 1992 Nucl. Fusion 32 611 * - * @param[in] E_kin_star the kinetic energy of the deuterium-tritium pair in its center of mass frame, in keV. + * @param[in] E_kin_star the kinetic energy of the deuterium-tritium pair in its center of mass frame, in SI units. * @return The total cross section in SI units (square meters). */ AMREX_GPU_HOST_DEVICE AMREX_INLINE @@ -37,8 +37,8 @@ amrex::ParticleReal DeuteriumTritiumFusionCrossSection (const amrex::ParticleRea constexpr amrex::ParticleReal m_D = 1.99901 * PhysConst::m_p; constexpr amrex::ParticleReal m_T = 2.99372 * PhysConst::m_p; constexpr amrex::ParticleReal m_reduced = m_D*m_T / (m_D + m_T); - constexpr amrex::ParticleReal B_G = MathConst::pi * PhysConst::alpha * 2 * 3 - * std::sqrt( 2*m_reduced*PhysConst::c*PhysConst::c / (1.e3*PhysConst::q_e) ); + amrex::ParticleReal B_G = MathConst::pi * PhysConst::alpha * 2._prt * 3._prt + * std::sqrt( 2._prt*m_reduced*PhysConst::c*PhysConst::c / (1.e3_prt*PhysConst::q_e) ); // Compute astrophysical_factor // (See Eq. 9 and Table IV in H.-S. Bosch and G.M. Hale 1992 Nucl. Fusion 32 611) From c6e7c923dec252baf05661448b90f0f67562169a Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 2 Jun 2022 19:57:23 -0700 Subject: [PATCH 17/63] Fix nuclear fusion --- .../Collision/BinaryCollision/BinaryCollisionUtils.cpp | 4 ++-- .../BinaryCollision/NuclearFusion/NuclearFusionFunc.H | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/BinaryCollisionUtils.cpp b/Source/Particles/Collision/BinaryCollision/BinaryCollisionUtils.cpp index 7e78d95ed80..cc0c70fceb2 100644 --- a/Source/Particles/Collision/BinaryCollision/BinaryCollisionUtils.cpp +++ b/Source/Particles/Collision/BinaryCollision/BinaryCollisionUtils.cpp @@ -26,9 +26,9 @@ namespace BinaryCollisionUtils{ auto& species1 = mypc->GetParticleContainerFromName(species_names[0]); auto& species2 = mypc->GetParticleContainerFromName(species_names[1]); - if ((species1.AmIA() && species2.AmIA()) + if ((species1.AmIA() && species2.AmIA()) || - (species1.AmIA() && species2.AmIA()) + (species1.AmIA() && species2.AmIA()) ) { return NuclearFusionType::ProtonBoron; diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H index b203955150c..88964e0b877 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H @@ -75,8 +75,8 @@ public: "ERROR: Proton-boron must contain exactly one product species"); auto& product_species = mypc->GetParticleContainerFromName(product_species_name[0]); WARPX_ALWAYS_ASSERT_WITH_MESSAGE( - product_species.AmIA(), - "ERROR: Product species of proton-boron fusion must be of type helium"); + product_species.AmIA(), + "ERROR: Product species of proton-boron fusion must be of type alpha"); } // default fusion multiplier From 6ab97ecb626f5de10d490e2da6a7364f3874327e Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Fri, 3 Jun 2022 09:15:38 -0700 Subject: [PATCH 18/63] Reset benchmarks --- .../benchmarks_json/multi_J_2d_psatd.json | 44 +++++++++---------- .../benchmarks_json/multi_J_2d_psatd_pml.json | 42 +++++++++--------- .../benchmarks_json/multi_J_rz_psatd.json | 42 +++++++++--------- 3 files changed, 64 insertions(+), 64 deletions(-) diff --git a/Regression/Checksum/benchmarks_json/multi_J_2d_psatd.json b/Regression/Checksum/benchmarks_json/multi_J_2d_psatd.json index d32d0cda569..8b871fbbdda 100644 --- a/Regression/Checksum/benchmarks_json/multi_J_2d_psatd.json +++ b/Regression/Checksum/benchmarks_json/multi_J_2d_psatd.json @@ -2,50 +2,50 @@ "driver": { "particle_cpu": 0.0, "particle_id": 5000050000.0, - "particle_momentum_x": 1.453995090219512e-16, + "particle_momentum_x": 1.4539940634099901e-16, "particle_momentum_y": 0.0, - "particle_momentum_z": 9.822790382172495e-09, - "particle_position_x": 0.4000037672274389, + "particle_momentum_z": 9.822790382172482e-09, + "particle_position_x": 0.40000376722750486, "particle_position_y": 30.100865423602578, "particle_weight": 124830181489215.27 }, "lev=0": { "Bx": 0.0, - "By": 923881.0964785999, + "By": 923881.627616788, "Bz": 0.0, - "Ex": 271447039750131.97, + "Ex": 271447156686106.3, "Ey": 0.0, - "Ez": 93015825054581.75, - "F": 6524.797420832107, + "Ez": 93015806626847.92, + "F": 6524.75796370838, "G": 0.0, - "divE": 2.511362881062318e+19, - "jx": 1.0071952338125634e+16, + "divE": 2.5113652133379535e+19, + "jx": 1.0071954084855112e+16, "jy": 0.0, - "jz": 6.431542670364866e+16, - "rho": 220510357.0126665, - "rho_driver": 2562225.1199331186, + "jz": 6.4315500079457544e+16, + "rho": 220510584.78675658, + "rho_driver": 2562225.119933119, "rho_driver_back": 0.0, - "rho_plasma_e": 1359622974.0040407, - "rho_plasma_p": 1361225480.3414695 + "rho_plasma_e": 1359622972.6072302, + "rho_plasma_p": 1361225477.6776037 }, "plasma_e": { "particle_cpu": 29652.0, "particle_id": 1194907032.0, - "particle_momentum_x": 7.2453531836034e-19, + "particle_momentum_x": 7.245362943456111e-19, "particle_momentum_y": 0.0, - "particle_momentum_z": 2.3479174018295152e-17, - "particle_position_x": 1.392419701091952, - "particle_position_y": 10.079133650581543, + "particle_momentum_z": 2.3479175722902974e-17, + "particle_position_x": 1.3924196999819647, + "particle_position_y": 10.079133709990238, "particle_weight": 6.643024495443786e+16 }, "plasma_p": { "particle_cpu": 29696.0, "particle_id": 1202173888.0, - "particle_momentum_x": 1.451501460012071e-18, + "particle_momentum_x": 1.4515027408919092e-18, "particle_momentum_y": 0.0, - "particle_momentum_z": 4.005705789722352e-14, - "particle_position_x": 1.3456480188944573, - "particle_position_y": 10.082154729747618, + "particle_momentum_z": 4.008583335222013e-14, + "particle_position_x": 1.345647984351348, + "particle_position_y": 10.082154763152218, "particle_weight": 6.652881944445523e+16 } } \ No newline at end of file diff --git a/Regression/Checksum/benchmarks_json/multi_J_2d_psatd_pml.json b/Regression/Checksum/benchmarks_json/multi_J_2d_psatd_pml.json index d4d56eea570..15a77d5e5c0 100644 --- a/Regression/Checksum/benchmarks_json/multi_J_2d_psatd_pml.json +++ b/Regression/Checksum/benchmarks_json/multi_J_2d_psatd_pml.json @@ -2,50 +2,50 @@ "driver": { "particle_cpu": 0.0, "particle_id": 5000050000.0, - "particle_momentum_x": 1.4499934898508315e-16, + "particle_momentum_x": 1.4499924704466542e-16, "particle_momentum_y": 0.0, - "particle_momentum_z": 9.822790382300442e-09, - "particle_position_x": 0.40000376757269557, + "particle_momentum_z": 9.82279038230043e-09, + "particle_position_x": 0.4000037675727611, "particle_position_y": 30.100865423602578, "particle_weight": 124830181489215.27 }, "lev=0": { "Bx": 0.0, - "By": 921660.3791780534, + "By": 921660.8978659188, "Bz": 0.0, - "Ex": 270876373466331.25, + "Ex": 270876493491643.72, "Ey": 0.0, - "Ez": 92624942849290.58, - "F": 6183.089569602618, + "Ez": 92624928289782.67, + "F": 6183.053934691087, "G": 0.0, - "divE": 2.519019708946362e+19, - "jx": 1.0172819575614014e+16, + "divE": 2.5190221277716443e+19, + "jx": 1.0172820296985254e+16, "jy": 0.0, - "jz": 6.385273746740672e+16, - "rho": 220331681.67046365, + "jz": 6.385280627174476e+16, + "rho": 220331916.84576574, "rho_driver": 2562225.119933118, "rho_driver_back": 0.0, - "rho_plasma_e": 1359499350.2687225, - "rho_plasma_p": 1361225460.3586755 + "rho_plasma_e": 1359499348.832252, + "rho_plasma_p": 1361225457.7092004 }, "plasma_e": { "particle_cpu": 29647.0, "particle_id": 1194856401.0, - "particle_momentum_x": 7.187004715206369e-19, + "particle_momentum_x": 7.187014141480275e-19, "particle_momentum_y": 0.0, - "particle_momentum_z": 2.346497069529724e-17, - "particle_position_x": 1.3919451702129872, - "particle_position_y": 10.07681584795493, + "particle_momentum_z": 2.3464972406746717e-17, + "particle_position_x": 1.3919451689290652, + "particle_position_y": 10.07681590718761, "particle_weight": 6.641904330784497e+16 }, "plasma_p": { "particle_cpu": 29696.0, "particle_id": 1202173888.0, - "particle_momentum_x": 1.4494684060818139e-18, + "particle_momentum_x": 1.4494696792808645e-18, "particle_momentum_y": 0.0, - "particle_momentum_z": 4.005707216626881e-14, - "particle_position_x": 1.3456480686756227, - "particle_position_y": 10.082154799552143, + "particle_momentum_z": 4.00858476212274e-14, + "particle_position_x": 1.345648034097414, + "particle_position_y": 10.082154832906486, "particle_weight": 6.652881944445523e+16 } } \ No newline at end of file diff --git a/Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json b/Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json index 9f00c914745..a095b042659 100644 --- a/Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json +++ b/Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json @@ -6,40 +6,40 @@ "particle_momentum_y": 8.719285567351437e-16, "particle_momentum_z": 5.461771334692466e-13, "particle_position_x": 6.269566322411488, - "particle_position_y": 17.93420080596407, - "particle_theta": 1570790.043609588, + "particle_position_y": 17.934200805964075, + "particle_theta": 1570790.0436095877, "particle_weight": 6241484108.424456 }, "lev=0": { - "By": 24912.66213622398, - "Ex": 4667305981763.072, - "Ez": 4307437907855.343, - "jx": 362736023475894.4, - "jz": 1937267309900551.0, - "rho": 5308545.334478145, - "rho_driver": 6288266.101815153, - "rho_plasma_e": 49569864.07552357, - "rho_plasma_p": 50769175.53040837 + "By": 24912.66262617112, + "Ex": 4667306707740.952, + "Ez": 4307437889665.741, + "jx": 362735946859133.25, + "jz": 1937267341438018.5, + "rho": 5308546.10760024, + "rho_driver": 6288266.101815152, + "rho_plasma_e": 49569864.00561153, + "rho_plasma_p": 50769174.575747415 }, "plasma_e": { "particle_cpu": 12650.0, "particle_id": 159086515.0, - "particle_momentum_x": 6.658110480654614e-20, - "particle_momentum_y": 6.738986103368656e-20, - "particle_momentum_z": 2.846571070844049e-20, - "particle_position_x": 1.142336749037713, - "particle_position_y": 0.6139715590982434, + "particle_momentum_x": 6.658111450308696e-20, + "particle_momentum_y": 6.738987086219168e-20, + "particle_momentum_z": 2.8465711111032466e-20, + "particle_position_x": 1.142336749571497, + "particle_position_y": 0.6139715590488816, "particle_theta": 20188.939948727297, "particle_weight": 1002457942911.3788 }, "plasma_p": { "particle_cpu": 12650.0, "particle_id": 163728835.0, - "particle_momentum_x": 6.640191214031372e-20, - "particle_momentum_y": 6.767586994284535e-20, - "particle_momentum_z": 5.584762252475822e-20, - "particle_position_x": 1.13652015776656, - "particle_position_y": 0.6152066993974457, + "particle_momentum_x": 6.640192785220438e-20, + "particle_momentum_y": 6.767588624594766e-20, + "particle_momentum_z": 5.584761199543091e-20, + "particle_position_x": 1.136520160120179, + "particle_position_y": 0.6152066982335147, "particle_theta": 20286.92798337582, "particle_weight": 1002457942911.3788 } From 6f7e7c070c9536360765e1c88eb1395e41a06c70 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Fri, 3 Jun 2022 14:33:09 -0700 Subject: [PATCH 19/63] Prepare creation functor for 2-product fusion --- .../BinaryCollision/BinaryCollision.H | 6 +++-- .../DeuteriumTritiumFusionCrossSection.H | 2 +- ...H => TwoProductFusionInitializeMomentum.H} | 24 ++++++++---------- .../BinaryCollision/ParticleCreationFunc.H | 25 +++++++++++++++---- 4 files changed, 36 insertions(+), 21 deletions(-) rename Source/Particles/Collision/BinaryCollision/NuclearFusion/{DeuteriumTritiumFusionInitializeMomentum.H => TwoProductFusionInitializeMomentum.H} (71%) diff --git a/Source/Particles/Collision/BinaryCollision/BinaryCollision.H b/Source/Particles/Collision/BinaryCollision/BinaryCollision.H index fd33c0ff459..b1c1ebd934f 100644 --- a/Source/Particles/Collision/BinaryCollision/BinaryCollision.H +++ b/Source/Particles/Collision/BinaryCollision/BinaryCollision.H @@ -219,6 +219,7 @@ public: amrex::Vector tile_products; amrex::Vector get_position_products; amrex::Vector products_np; + amrex::Vector products_mass; constexpr int getpos_offset = 0; for (int i = 0; i < n_product_species; i++) { @@ -227,6 +228,7 @@ public: get_position_products.push_back(GetParticlePosition(ptile_product, getpos_offset)); products_np.push_back(ptile_product.numParticles()); + products_mass.push_back(product_species_vector[i]->getMass()); } auto tile_products_data = tile_products.data(); @@ -358,7 +360,7 @@ public: const amrex::Vector num_added = m_copy_transform_functor(n_total_pairs, soa_1, soa_1, tile_products_data, particle_ptr_1, particle_ptr_1, m1, m1, - p_mask, products_np, + products_mass, p_mask, products_np, copy_species1, copy_species2, p_pair_indices_1, p_pair_indices_2, p_pair_reaction_weight); @@ -519,7 +521,7 @@ public: const amrex::Vector num_added = m_copy_transform_functor(n_total_pairs, soa_1, soa_2, tile_products_data, particle_ptr_1, particle_ptr_2, m1, m2, - p_mask, products_np, + products_mass, p_mask, products_np, copy_species1, copy_species2, p_pair_indices_1, p_pair_indices_2, p_pair_reaction_weight); diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H index 0b3e2006cbc..a02c88cdc20 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H @@ -38,7 +38,7 @@ amrex::ParticleReal DeuteriumTritiumFusionCrossSection (const amrex::ParticleRea constexpr amrex::ParticleReal m_T = 2.99372 * PhysConst::m_p; constexpr amrex::ParticleReal m_reduced = m_D*m_T / (m_D + m_T); amrex::ParticleReal B_G = MathConst::pi * PhysConst::alpha * 2._prt * 3._prt - * std::sqrt( 2._prt*m_reduced*PhysConst::c*PhysConst::c / (1.e3_prt*PhysConst::q_e) ); + * std::sqrt( 2._prt*m_reduced*PhysConst::c*PhysConst::c * joule_to_keV ); // Compute astrophysical_factor // (See Eq. 9 and Table IV in H.-S. Bosch and G.M. Hale 1992 Nucl. Fusion 32 611) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H similarity index 71% rename from Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionInitializeMomentum.H rename to Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H index 42932325746..3d2fdd0bb83 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionInitializeMomentum.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H @@ -5,8 +5,8 @@ * License: BSD-3-Clause-LBNL */ -#ifndef DEUTERIUM_TRITIUM_FUSION_INITIALIZE_MOMENTUM_H -#define DEUTERIUM_TRITIUM_FUSION_INITIALIZE_MOMENTUM_H +#ifndef TWO_PRODUCT_FUSION_INITIALIZE_MOMENTUM_H +#define TWO_PRODUCT_FUSION_INITIALIZE_MOMENTUM_H #include "Particles/WarpXParticleContainer.H" #include "Utils/ParticleUtils.H" @@ -27,12 +27,14 @@ namespace { using index_type = ParticleBins::index_type; /** - * \brief This function initializes the momentum of the particles produced from - * deuterium-tritium fusion. + * \brief This function initializes the momentum of the product particles, + * in a fusion event where only two products are produced. + * (In this case, conservation of energy and momentum determines + * the amplitude of the momentum of the particles exactly.) + * We assume that the emission of the product is isotropic in the center-of-mass frame * - * @param[in] soa_1 struct of array data of the first colliding species (can be either deuterium - * or tritium) - * @param[in] soa_2 struct of array data of the second colliding species (can be either deuterium + * @param[in] soa_1 struct of array data of the first colliding species + * @param[in] soa_2 struct of array data of the second colliding species * or tritium) * @param[out] ... * @param[in] idx_1 index of first colliding macroparticle @@ -43,7 +45,7 @@ namespace { * @param[in] engine the random engine */ AMREX_GPU_HOST_DEVICE AMREX_INLINE - void DeuteriumTritiumFusionInitializeMomentum ( + void TwoProductFusionInitializeMomentum ( const SoaData_type& soa_1, const SoaData_type& soa_2, SoaData_type& soa_alpha, const index_type& idx_1, const index_type& idx_2, @@ -51,14 +53,10 @@ namespace { const amrex::ParticleReal& m1, const amrex::ParticleReal& m2, const amrex::RandomEngine& engine) { - // General notations in this function: - // x_sq denotes the square of x - // x_star denotes the value of x in the proton+boron center of mass frame - // x_Bestar denotes the value of x in the Beryllium rest frame using namespace amrex::literals; } } -#endif // DEUTERIUM_TRITIUM_FUSION_INITIALIZE_MOMENTUM_H +#endif // TWO_PRODUCT_FUSION_INITIALIZE_MOMENTUM_H diff --git a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H index a8f8c26ed54..7d996fb8ea0 100644 --- a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H +++ b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H @@ -10,7 +10,7 @@ #include "BinaryCollisionUtils.H" -#include "Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionInitializeMomentum.H" +#include "Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H" #include "Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H" #include "Particles/ParticleCreation/SmartCopy.H" #include "Particles/MultiParticleContainer.H" @@ -78,6 +78,7 @@ public: * reaches 0. * @param[in] m1 mass of the first colliding particle species * @param[in] m2 mass of the second colliding particle species + * @param[in] products_mass array storing the mass of product particles * @param[in] p_mask a mask that is 1 if binary collision has resulted in particle creation * event, 0 otherwise. * @param[in] products_np array storing the number of existing product particles in that tile @@ -103,6 +104,7 @@ public: ParticleTileType** AMREX_RESTRICT tile_products, ParticleType* particle_ptr_1, ParticleType* particle_ptr_2, const amrex::ParticleReal& m1, const amrex::ParticleReal& m2, + const amrex::Vector& products_mass, const index_type* AMREX_RESTRICT p_mask, const amrex::Vector& products_np, const SmartCopy* AMREX_RESTRICT copy_species1, @@ -209,10 +211,6 @@ public: // Initialize the product particles' momentum, using a function depending on the // specific collision type - if (t_collision_type == CollisionType::DeuteriumTritiumFusion) - { - // TODO DeuteriumTritiumFusionInitializeMomentum - } if (t_collision_type == CollisionType::ProtonBoronFusion) { const index_type product_start_index = products_np_data[0] + 2*p_offsets[i]* @@ -221,6 +219,22 @@ public: p_pair_indices_1[i], p_pair_indices_2[i], product_start_index, m1, m2, engine); } + else + { + // TODO: Assert that there are exactly 2 products + + amrex::ParticleReal fusion_energy = 0; + if (t_collision_type == CollisionType::DeuteriumTritiumFusion) { + fusion_energy = 17.6e6 * PhysConst::q_e; // 17.6 MeV + } +/* TwoProductFusionInitializeMomentum(soa_1, soa_2, + soa_products_data[0], soa_products_data[1], + p_pair_indices_1[i], p_pair_indices_2[i], + products_np_data[0] + 2*p_offsets[i]*p_num_products_device[0], + products_np_data[1] + 2*p_offsets[i]*p_num_products_device[1], + m1, m2, fusion_energy, engine); */ + } + } }); @@ -265,6 +279,7 @@ public: ParticleTileType** /*tile_products*/, ParticleType* /*particle_ptr_1*/, ParticleType* /*particle_ptr_2*/, const amrex::ParticleReal& /*m1*/, const amrex::ParticleReal& /*m2*/, + const amrex::Vector& /*products_mass*/, const index_type* /*p_mask*/, const amrex::Vector& /*products_np*/, const SmartCopy* /*copy_species1*/, const SmartCopy* /*copy_species2*/, const index_type* /*p_pair_indices_1*/, const index_type* /*p_pair_indices_2*/, From ff08305e50853deb71572d75615bf90f362cc9da Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Fri, 3 Jun 2022 16:29:43 -0700 Subject: [PATCH 20/63] First implementation of momentum initialization --- .../TwoProductFusionInitializeMomentum.H | 115 +++++++++++++++++- .../BinaryCollision/ParticleCreationFunc.H | 7 +- .../BinaryCollision/ParticleCreationFunc.cpp | 13 ++ 3 files changed, 129 insertions(+), 6 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H index 3d2fdd0bb83..2f5f96d48a8 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H @@ -47,14 +47,123 @@ namespace { AMREX_GPU_HOST_DEVICE AMREX_INLINE void TwoProductFusionInitializeMomentum ( const SoaData_type& soa_1, const SoaData_type& soa_2, - SoaData_type& soa_alpha, + SoaData_type& soa_product1, SoaData_type& soa_product2, const index_type& idx_1, const index_type& idx_2, - const index_type& idx_alpha_start, + const index_type& idx_product1_start, const index_type& idx_product2_start, const amrex::ParticleReal& m1, const amrex::ParticleReal& m2, + const amrex::ParticleReal& mp1, const amrex::ParticleReal& mp2, + const amrex::ParticleReal& E_fusion, const amrex::RandomEngine& engine) { - using namespace amrex::literals; + + constexpr amrex::ParticleReal c_sq = PhysConst::c * PhysConst::c; + constexpr amrex::ParticleReal inv_csq = 1._prt / ( c_sq ); + // Rest energy of incident particles + const amrex::ParticleReal E_rest_in = (m1 + m2)*c_sq; + // Rest energy of products + const amrex::ParticleReal E_rest_out = (mp1 + mp2)*c_sq; + + // Normalized momentum of colliding particles + const amrex::ParticleReal u1x = soa_1.m_rdata[PIdx::ux][idx_1]; + const amrex::ParticleReal u1y = soa_1.m_rdata[PIdx::uy][idx_1]; + const amrex::ParticleReal u1z = soa_1.m_rdata[PIdx::uz][idx_1]; + const amrex::ParticleReal u2x = soa_2.m_rdata[PIdx::ux][idx_2]; + const amrex::ParticleReal u2y = soa_2.m_rdata[PIdx::uy][idx_2]; + const amrex::ParticleReal u2z = soa_2.m_rdata[PIdx::uz][idx_2]; + + // Compute Lorentz factor gamma in the lab frame + const amrex::ParticleReal g1 = std::sqrt( 1._prt + (u1x*u1x+u1y*u1y+u1z*u1z)*inv_csq ); + const amrex::ParticleReal g2 = std::sqrt( 1._prt + (u2x*u2x+u2y*u2y+u2z*u2z)*inv_csq ); + + // Compute momenta + const amrex::ParticleReal p1x = u1x * m1; + const amrex::ParticleReal p1y = u1y * m1; + const amrex::ParticleReal p1z = u1z * m1; + const amrex::ParticleReal p2x = u2x * m2; + const amrex::ParticleReal p2y = u2y * m2; + const amrex::ParticleReal p2z = u2z * m2; + // Square norm of the total (sum between the two particles) momenta in the lab frame + auto constexpr pow2 = [](double const x) { return x*x; }; + const amrex::ParticleReal p_total_sq = pow2(p1x+p2x) + + pow2(p1y+p2y) + + pow2(p1z+p2z); + + // Total energy of incident species in the lab frame + const amrex::ParticleReal E_lab = (m1 * g1 + m2 * g2) * c_sq; + // Total energy squared of proton+boron in the center of mass frame, calculated using the + // Lorentz invariance of the four-momentum norm + const amrex::ParticleReal E_star_sq = E_lab*E_lab - c_sq*p_total_sq; + // Total energy squared of the products in the center of mass frame + // In principle, the term - E_rest_in + E_rest_out + E_fusion is not needed and equal to + // zero (i.e. the energy liberated during fusion is equal to the mass difference). However, + // due to possible inconsistencies in how the mass is defined in the code, it is + // probably more robust to subtract the rest masses and to add the fusion energy to the + // total kinetic energy. + const amrex::ParticleReal E_star_f_sq = pow2(std::sqrt(E_star_sq) + - E_rest_in + E_rest_out + E_fusion); + + // Square of the norm of the momentum of the products in the center of mass frame + // Formula obtained by inverting E^2 = p^2*c^2 + m^2*c^4 in the COM frame for each particle + auto constexpr pow3 = [](double const x) { return x*x*x; }; + const amrex::ParticleReal p_star_f_sq = + E_star_f_sq*0.25_prt*inv_csq - (mp1*mp1 + mp2*mp2)*c_sq*0.5_prt + + pow3(c_sq)*0.25_prt * pow2(mp1*mp1 - mp2*mp2) / E_star_f_sq; + + // Compute momentum of first alpha in the center of mass frame, assuming isotropic + // distribution + amrex::ParticleReal px_star, py_star, pz_star; + ParticleUtils::RandomizeVelocity(px_star, py_star, pz_star, std::sqrt(p_star_f_sq), + engine); + + // Next step is to convert momenta to lab frame + amrex::ParticleReal px_out1, py_out1, pz_out1; + // Preliminary calculation: compute center of mass velocity vc + const amrex::ParticleReal mass_g = m1 * g1 + m2 * g2; + const amrex::ParticleReal vcx = (p1x+p2x) / mass_g; + const amrex::ParticleReal vcy = (p1y+p2y) / mass_g; + const amrex::ParticleReal vcz = (p1z+p2z) / mass_g; + const amrex::ParticleReal vc_sq = vcx*vcx + vcy*vcy + vcz*vcz; + + // Convert momentum of first alpha to lab frame, using equation (13) of F. Perez et al., + // Phys.Plasmas.19.083104 (2012) + if ( vc_sq > std::numeric_limits::min() ) + { + const amrex::ParticleReal gc = 1._prt / std::sqrt( 1._prt - vc_sq*inv_csq ); + const amrex::ParticleReal g_star = std::sqrt(1._prt + p_star_f_sq / (mp1*mp1*c_sq)); + const amrex::ParticleReal vcDps = vcx*px_star + vcy*py_star + vcz*pz_star; + const amrex::ParticleReal factor0 = (gc-1._prt)/vc_sq; + const amrex::ParticleReal factor = factor0*vcDps + mp1*g_star*gc; + px_out1 = px_star + vcx * factor; + py_out1 = py_star + vcy * factor; + pz_out1 = pz_star + vcz * factor; + } + else // If center of mass velocity is zero, we are already in the lab frame + { + px_out1 = px_star; + py_out1 = py_star; + pz_out1 = pz_star; + } + + // Compute momentum of beryllium in lab frame, using total momentum conservation + const amrex::ParticleReal px_out2 = p1x + p2x - px_out1; + const amrex::ParticleReal py_out2 = p1y + p2y - py_out1; + const amrex::ParticleReal pz_out2 = p1z + p2z - pz_out1; + + // Fill momentum of product species (note that we actually + // create 4 products, 2 at the position of each incident particle) + soa_product1.m_rdata[PIdx::ux][idx_product1_start] = px_out1/mp1; + soa_product1.m_rdata[PIdx::uy][idx_product1_start] = py_out1/mp1; + soa_product1.m_rdata[PIdx::uz][idx_product1_start] = pz_out1/mp1; + soa_product1.m_rdata[PIdx::ux][idx_product1_start + 1] = px_out1/mp1; + soa_product1.m_rdata[PIdx::uy][idx_product1_start + 1] = py_out1/mp1; + soa_product1.m_rdata[PIdx::uz][idx_product1_start + 1] = pz_out1/mp1; + soa_product2.m_rdata[PIdx::ux][idx_product2_start] = px_out2/mp2; + soa_product2.m_rdata[PIdx::uy][idx_product2_start] = py_out2/mp2; + soa_product2.m_rdata[PIdx::uz][idx_product2_start] = pz_out2/mp2; + soa_product2.m_rdata[PIdx::ux][idx_product2_start + 1] = px_out2/mp2; + soa_product2.m_rdata[PIdx::uy][idx_product2_start + 1] = py_out2/mp2; + soa_product2.m_rdata[PIdx::uz][idx_product2_start + 1] = pz_out2/mp2; } } diff --git a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H index 7d996fb8ea0..c4d8b73b664 100644 --- a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H +++ b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H @@ -225,14 +225,15 @@ public: amrex::ParticleReal fusion_energy = 0; if (t_collision_type == CollisionType::DeuteriumTritiumFusion) { - fusion_energy = 17.6e6 * PhysConst::q_e; // 17.6 MeV + fusion_energy = 17.6e6_prt * PhysConst::q_e; // 17.6 MeV } -/* TwoProductFusionInitializeMomentum(soa_1, soa_2, + // TODO: Add exception for other collision types + TwoProductFusionInitializeMomentum(soa_1, soa_2, soa_products_data[0], soa_products_data[1], p_pair_indices_1[i], p_pair_indices_2[i], products_np_data[0] + 2*p_offsets[i]*p_num_products_device[0], products_np_data[1] + 2*p_offsets[i]*p_num_products_device[1], - m1, m2, fusion_energy, engine); */ + m1, m2, products_mass[0], products_mass[1], fusion_energy, engine); } } diff --git a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.cpp b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.cpp index ba6b20f1ba4..9603877611e 100644 --- a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.cpp +++ b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.cpp @@ -34,6 +34,19 @@ ParticleCreationFunc::ParticleCreationFunc (const std::string collision_name, m_num_products_device.push_back(3); #endif } + else if (m_collision_type == CollisionType::DeuteriumTritiumFusion) + { + m_num_product_species = 2; + m_num_products_host.push_back(1); + m_num_products_host.push_back(1); +#ifndef AMREX_USE_GPU + // On CPU, the device vector can be filled immediatly + m_num_products_device.push_back(1); + m_num_products_device.push_back(1); +#endif + } + // TODO: Raise error otherwise + #ifdef AMREX_USE_GPU m_num_products_device.resize(m_num_product_species); amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, m_num_products_host.begin(), From 428a179640519aa05753753427c2d397c8c2327c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 3 Jun 2022 23:30:17 +0000 Subject: [PATCH 21/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../Collision/BinaryCollision/ParticleCreationFunc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.cpp b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.cpp index 9603877611e..41e10434f02 100644 --- a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.cpp +++ b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.cpp @@ -42,7 +42,7 @@ ParticleCreationFunc::ParticleCreationFunc (const std::string collision_name, #ifndef AMREX_USE_GPU // On CPU, the device vector can be filled immediatly m_num_products_device.push_back(1); - m_num_products_device.push_back(1); + m_num_products_device.push_back(1); #endif } // TODO: Raise error otherwise From fa01fdd43f2bc9ec343dcc191c4500326f48a810 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 7 Jun 2022 13:31:17 -0700 Subject: [PATCH 22/63] Use utility function for fusion --- .../TwoProductFusionInitializeMomentum.H | 132 +++------------ .../NuclearFusion/TwoProductFusionUtil.H | 155 ++++++++++++++++++ 2 files changed, 182 insertions(+), 105 deletions(-) create mode 100644 Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionUtil.H diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H index 2f5f96d48a8..dcb3e7fd4b5 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H @@ -8,6 +8,7 @@ #ifndef TWO_PRODUCT_FUSION_INITIALIZE_MOMENTUM_H #define TWO_PRODUCT_FUSION_INITIALIZE_MOMENTUM_H +#include "TwoProductFusionUtil.H" #include "Particles/WarpXParticleContainer.H" #include "Utils/ParticleUtils.H" #include "Utils/WarpXConst.H" @@ -57,115 +58,36 @@ namespace { { using namespace amrex::literals; - constexpr amrex::ParticleReal c_sq = PhysConst::c * PhysConst::c; - constexpr amrex::ParticleReal inv_csq = 1._prt / ( c_sq ); - // Rest energy of incident particles - const amrex::ParticleReal E_rest_in = (m1 + m2)*c_sq; - // Rest energy of products - const amrex::ParticleReal E_rest_out = (mp1 + mp2)*c_sq; - - // Normalized momentum of colliding particles - const amrex::ParticleReal u1x = soa_1.m_rdata[PIdx::ux][idx_1]; - const amrex::ParticleReal u1y = soa_1.m_rdata[PIdx::uy][idx_1]; - const amrex::ParticleReal u1z = soa_1.m_rdata[PIdx::uz][idx_1]; - const amrex::ParticleReal u2x = soa_2.m_rdata[PIdx::ux][idx_2]; - const amrex::ParticleReal u2y = soa_2.m_rdata[PIdx::uy][idx_2]; - const amrex::ParticleReal u2z = soa_2.m_rdata[PIdx::uz][idx_2]; - - // Compute Lorentz factor gamma in the lab frame - const amrex::ParticleReal g1 = std::sqrt( 1._prt + (u1x*u1x+u1y*u1y+u1z*u1z)*inv_csq ); - const amrex::ParticleReal g2 = std::sqrt( 1._prt + (u2x*u2x+u2y*u2y+u2z*u2z)*inv_csq ); - - // Compute momenta - const amrex::ParticleReal p1x = u1x * m1; - const amrex::ParticleReal p1y = u1y * m1; - const amrex::ParticleReal p1z = u1z * m1; - const amrex::ParticleReal p2x = u2x * m2; - const amrex::ParticleReal p2y = u2y * m2; - const amrex::ParticleReal p2z = u2z * m2; - // Square norm of the total (sum between the two particles) momenta in the lab frame - auto constexpr pow2 = [](double const x) { return x*x; }; - const amrex::ParticleReal p_total_sq = pow2(p1x+p2x) + - pow2(p1y+p2y) + - pow2(p1z+p2z); - - // Total energy of incident species in the lab frame - const amrex::ParticleReal E_lab = (m1 * g1 + m2 * g2) * c_sq; - // Total energy squared of proton+boron in the center of mass frame, calculated using the - // Lorentz invariance of the four-momentum norm - const amrex::ParticleReal E_star_sq = E_lab*E_lab - c_sq*p_total_sq; - // Total energy squared of the products in the center of mass frame - // In principle, the term - E_rest_in + E_rest_out + E_fusion is not needed and equal to - // zero (i.e. the energy liberated during fusion is equal to the mass difference). However, - // due to possible inconsistencies in how the mass is defined in the code, it is - // probably more robust to subtract the rest masses and to add the fusion energy to the - // total kinetic energy. - const amrex::ParticleReal E_star_f_sq = pow2(std::sqrt(E_star_sq) - - E_rest_in + E_rest_out + E_fusion); - - // Square of the norm of the momentum of the products in the center of mass frame - // Formula obtained by inverting E^2 = p^2*c^2 + m^2*c^4 in the COM frame for each particle - auto constexpr pow3 = [](double const x) { return x*x*x; }; - const amrex::ParticleReal p_star_f_sq = - E_star_f_sq*0.25_prt*inv_csq - (mp1*mp1 + mp2*mp2)*c_sq*0.5_prt + - pow3(c_sq)*0.25_prt * pow2(mp1*mp1 - mp2*mp2) / E_star_f_sq; - - // Compute momentum of first alpha in the center of mass frame, assuming isotropic - // distribution - amrex::ParticleReal px_star, py_star, pz_star; - ParticleUtils::RandomizeVelocity(px_star, py_star, pz_star, std::sqrt(p_star_f_sq), - engine); - - // Next step is to convert momenta to lab frame - amrex::ParticleReal px_out1, py_out1, pz_out1; - // Preliminary calculation: compute center of mass velocity vc - const amrex::ParticleReal mass_g = m1 * g1 + m2 * g2; - const amrex::ParticleReal vcx = (p1x+p2x) / mass_g; - const amrex::ParticleReal vcy = (p1y+p2y) / mass_g; - const amrex::ParticleReal vcz = (p1z+p2z) / mass_g; - const amrex::ParticleReal vc_sq = vcx*vcx + vcy*vcy + vcz*vcz; - - // Convert momentum of first alpha to lab frame, using equation (13) of F. Perez et al., - // Phys.Plasmas.19.083104 (2012) - if ( vc_sq > std::numeric_limits::min() ) - { - const amrex::ParticleReal gc = 1._prt / std::sqrt( 1._prt - vc_sq*inv_csq ); - const amrex::ParticleReal g_star = std::sqrt(1._prt + p_star_f_sq / (mp1*mp1*c_sq)); - const amrex::ParticleReal vcDps = vcx*px_star + vcy*py_star + vcz*pz_star; - const amrex::ParticleReal factor0 = (gc-1._prt)/vc_sq; - const amrex::ParticleReal factor = factor0*vcDps + mp1*g_star*gc; - px_out1 = px_star + vcx * factor; - py_out1 = py_star + vcy * factor; - pz_out1 = pz_star + vcz * factor; - } - else // If center of mass velocity is zero, we are already in the lab frame - { - px_out1 = px_star; - py_out1 = py_star; - pz_out1 = pz_star; - } - - // Compute momentum of beryllium in lab frame, using total momentum conservation - const amrex::ParticleReal px_out2 = p1x + p2x - px_out1; - const amrex::ParticleReal py_out2 = p1y + p2y - py_out1; - const amrex::ParticleReal pz_out2 = p1z + p2z - pz_out1; + amrex::ParticleReal ux1_out = 0.0, uy1_out = 0.0, uz1_out = 0.0; + amrex::ParticleReal ux2_out = 0.0, uy2_out = 0.0, uz2_out = 0.0; + + TwoProductFusionComputeProductMomenta( + soa_1.m_rdata[PIdx::ux][idx_1], + soa_1.m_rdata[PIdx::uy][idx_1], + soa_1.m_rdata[PIdx::uz][idx_1], m1, + soa_2.m_rdata[PIdx::ux][idx_2], + soa_2.m_rdata[PIdx::uy][idx_2], + soa_2.m_rdata[PIdx::uz][idx_2], m2, + ux1_out, uy1_out, uz1_out, mp1, + uy2_out, uy2_out, uz2_out, mp2, + E_fusion, + engine); // Fill momentum of product species (note that we actually // create 4 products, 2 at the position of each incident particle) - soa_product1.m_rdata[PIdx::ux][idx_product1_start] = px_out1/mp1; - soa_product1.m_rdata[PIdx::uy][idx_product1_start] = py_out1/mp1; - soa_product1.m_rdata[PIdx::uz][idx_product1_start] = pz_out1/mp1; - soa_product1.m_rdata[PIdx::ux][idx_product1_start + 1] = px_out1/mp1; - soa_product1.m_rdata[PIdx::uy][idx_product1_start + 1] = py_out1/mp1; - soa_product1.m_rdata[PIdx::uz][idx_product1_start + 1] = pz_out1/mp1; - soa_product2.m_rdata[PIdx::ux][idx_product2_start] = px_out2/mp2; - soa_product2.m_rdata[PIdx::uy][idx_product2_start] = py_out2/mp2; - soa_product2.m_rdata[PIdx::uz][idx_product2_start] = pz_out2/mp2; - soa_product2.m_rdata[PIdx::ux][idx_product2_start + 1] = px_out2/mp2; - soa_product2.m_rdata[PIdx::uy][idx_product2_start + 1] = py_out2/mp2; - soa_product2.m_rdata[PIdx::uz][idx_product2_start + 1] = pz_out2/mp2; + soa_product1.m_rdata[PIdx::ux][idx_product1_start] = ux1_out; + soa_product1.m_rdata[PIdx::uy][idx_product1_start] = uy1_out; + soa_product1.m_rdata[PIdx::uz][idx_product1_start] = uz1_out; + soa_product1.m_rdata[PIdx::ux][idx_product1_start + 1] = ux1_out; + soa_product1.m_rdata[PIdx::uy][idx_product1_start + 1] = uy1_out; + soa_product1.m_rdata[PIdx::uz][idx_product1_start + 1] = uz1_out; + soa_product2.m_rdata[PIdx::ux][idx_product2_start] = ux2_out; + soa_product2.m_rdata[PIdx::uy][idx_product2_start] = uy2_out; + soa_product2.m_rdata[PIdx::uz][idx_product2_start] = uz2_out; + soa_product2.m_rdata[PIdx::ux][idx_product2_start + 1] = ux2_out; + soa_product2.m_rdata[PIdx::uy][idx_product2_start + 1] = uy2_out; + soa_product2.m_rdata[PIdx::uz][idx_product2_start + 1] = uz2_out; } - } #endif // TWO_PRODUCT_FUSION_INITIALIZE_MOMENTUM_H diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionUtil.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionUtil.H new file mode 100644 index 00000000000..a2423391bc0 --- /dev/null +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionUtil.H @@ -0,0 +1,155 @@ +/* Copyright 2022 Remi Lehe + * + * This file is part of WarpX. + * + * License: BSD-3-Clause-LBNL + */ + +#ifndef TWO_PRODUCT_FUSION_UTIL_H +#define TWO_PRODUCT_FUSION_UTIL_H + +#include "Utils/ParticleUtils.H" +#include "Utils/WarpXConst.H" + +#include +#include + +#include +#include + +namespace { + /** + * \brief TODO + * @param[in] soa_1 struct of array data of the first colliding species + * @param[in] soa_2 struct of array data of the second colliding species + * or tritium) + * @param[out] ... + * @param[in] idx_1 index of first colliding macroparticle + * @param[in] idx_2 index of second colliding macroparticle + * @param[in]... + * @param[in] m1 mass of first colliding species + * @param[in] m2 mass of second colliding species + * @param[in] engine the random engine + */ + AMREX_GPU_HOST_DEVICE AMREX_INLINE + void TwoProductFusionComputeProductMomenta ( + const amrex::ParticleReal& u1x_in, + const amrex::ParticleReal& u1y_in, + const amrex::ParticleReal& u1z_in, + const amrex::ParticleReal& m1_in, + const amrex::ParticleReal& u2x_in, + const amrex::ParticleReal& u2y_in, + const amrex::ParticleReal& u2z_in, + const amrex::ParticleReal& m2_in, + amrex::ParticleReal& u1x_out, + amrex::ParticleReal& u1y_out, + amrex::ParticleReal& u1z_out, + const amrex::ParticleReal& m1_out, + amrex::ParticleReal& u2x_out, + amrex::ParticleReal& u2y_out, + amrex::ParticleReal& u2z_out, + const amrex::ParticleReal& m2_out, + const amrex::ParticleReal& E_fusion, + const amrex::RandomEngine& engine ) + { + using namespace amrex::literals; + + constexpr amrex::ParticleReal c_sq = PhysConst::c * PhysConst::c; + constexpr amrex::ParticleReal inv_csq = 1._prt / ( c_sq ); + // Rest energy of incident particles + const amrex::ParticleReal E_rest_in = (m1_in + m2_in)*c_sq; + // Rest energy of products + const amrex::ParticleReal E_rest_out = (m1_out + m2_out)*c_sq; + + // Compute Lorentz factor gamma in the lab frame + const amrex::ParticleReal g1_in = std::sqrt( 1._prt + + (u1x_in * u1x_in + u1y_in * u1y_in + u1z_in*u1z_in)*inv_csq ); + const amrex::ParticleReal g2_in = std::sqrt( 1._prt + + (u2x_out*u2x_out + u2y_out*u2y_out + u2z_out*u2z_out)*inv_csq ); + + // Compute momenta + const amrex::ParticleReal p1x_in = u1x_in * m1_in; + const amrex::ParticleReal p1y_in = u1y_in * m1_in; + const amrex::ParticleReal p1z_in = u1z_in * m1_in; + const amrex::ParticleReal p2x_in = u2x_in * m2_in; + const amrex::ParticleReal p2y_in = u2y_in * m2_in; + const amrex::ParticleReal p2z_in = u2z_in * m2_in; + // Square norm of the total (sum between the two particles) momenta in the lab frame + auto constexpr pow2 = [](double const x) { return x*x; }; + const amrex::ParticleReal p_total_sq = pow2(p1x_in+p2x_in) + + pow2(p1y_in+p2y_in) + + pow2(p1z_in+p2z_in); + + // Total energy of incident species in the lab frame + const amrex::ParticleReal E_lab = (m1_in * g1_in + m2_in * g2_in) * c_sq; + // Total energy squared of proton+boron in the center of mass frame, calculated using the + // Lorentz invariance of the four-momentum norm + const amrex::ParticleReal E_star_sq = E_lab*E_lab - c_sq*p_total_sq; + // Total energy squared of the products in the center of mass frame + // In principle, the term - E_rest_in + E_rest_out + E_fusion is not needed and equal to + // zero (i.e. the energy liberated during fusion is equal to the mass difference). However, + // due to possible inconsistencies in how the mass is defined in the code, it is + // probably more robust to subtract the rest masses and to add the fusion energy to the + // total kinetic energy. + const amrex::ParticleReal E_star_f_sq = pow2(std::sqrt(E_star_sq) + - E_rest_in + E_rest_out + E_fusion); + + // Square of the norm of the momentum of the products in the center of mass frame + // Formula obtained by inverting E^2 = p^2*c^2 + m^2*c^4 in the COM frame for each particle + auto constexpr pow3 = [](double const x) { return x*x*x; }; + const amrex::ParticleReal p_star_f_sq = + E_star_f_sq*0.25_prt*inv_csq - (m1_out*m1_out + m2_out*m2_out)*c_sq*0.5_prt + + pow3(c_sq)*0.25_prt * pow2(m1_out*m1_out - m2_out*m2_out) / E_star_f_sq; + + // Compute momentum of first alpha in the center of mass frame, assuming isotropic + // distribution + amrex::ParticleReal px_star, py_star, pz_star; + ParticleUtils::RandomizeVelocity(px_star, py_star, pz_star, std::sqrt(p_star_f_sq), + engine); + + // Next step is to convert momenta to lab frame + amrex::ParticleReal p1x_out, p1y_out, p1z_out; + // Preliminary calculation: compute center of mass velocity vc + const amrex::ParticleReal mass_g = m1_in * g1_in + m2_in * g2_in; + const amrex::ParticleReal vcx = (p1x_in+p2x_in) / mass_g; + const amrex::ParticleReal vcy = (p1y_in+p2y_in) / mass_g; + const amrex::ParticleReal vcz = (p1z_in+p2z_in) / mass_g; + const amrex::ParticleReal vc_sq = vcx*vcx + vcy*vcy + vcz*vcz; + + // Convert momentum of first alpha to lab frame, using equation (13) of F. Perez et al., + // Phys.Plasmas.19.083104 (2012) + if ( vc_sq > std::numeric_limits::min() ) + { + const amrex::ParticleReal gc = 1._prt / std::sqrt( 1._prt - vc_sq*inv_csq ); + const amrex::ParticleReal g_star = std::sqrt(1._prt + p_star_f_sq / (m1_out*m1_out*c_sq)); + const amrex::ParticleReal vcDps = vcx*px_star + vcy*py_star + vcz*pz_star; + const amrex::ParticleReal factor0 = (gc-1._prt)/vc_sq; + const amrex::ParticleReal factor = factor0*vcDps + m1_out*g_star*gc; + p1x_out = px_star + vcx * factor; + p1y_out = py_star + vcy * factor; + p1z_out = pz_star + vcz * factor; + } + else // If center of mass velocity is zero, we are already in the lab frame + { + p1x_out = px_star; + p1y_out = py_star; + p1z_out = pz_star; + } + + // Compute momentum of beryllium in lab frame, using total momentum conservation + const amrex::ParticleReal p2x_out = p1x_in + p2x_in - p1x_out; + const amrex::ParticleReal p2y_out = p1y_in + p2y_in - p1y_out; + const amrex::ParticleReal p2z_out = p1z_in + p2z_in - p1z_out; + + // Fill momentum of product species (note that we actually + // create 4 products, 2 at the position of each incident particle) + u1x_out = p1x_out/m1_out; + u1y_out = p1y_out/m1_out; + u1z_out = p1z_out/m1_out; + u2x_out = p2x_out/m2_out; + u2y_out = p2y_out/m2_out; + u2z_out = p2z_out/m2_out; + } +} + +#endif // TWO_PRODUCT_FUSION_UTIL_H From 88fcaf57bc062523ed932c472a278ae754922c0b Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 7 Jun 2022 13:36:45 -0700 Subject: [PATCH 23/63] Minor modification of variable names --- .../TwoProductFusionInitializeMomentum.H | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H index dcb3e7fd4b5..dc230c67b33 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H @@ -34,25 +34,25 @@ namespace { * the amplitude of the momentum of the particles exactly.) * We assume that the emission of the product is isotropic in the center-of-mass frame * - * @param[in] soa_1 struct of array data of the first colliding species - * @param[in] soa_2 struct of array data of the second colliding species + * @param[in] soa1_in struct of array data of the first colliding species + * @param[in] soa2_in struct of array data of the second colliding species * or tritium) * @param[out] ... - * @param[in] idx_1 index of first colliding macroparticle - * @param[in] idx_2 index of second colliding macroparticle + * @param[in] idx1_in index of first colliding macroparticle + * @param[in] idx2_in index of second colliding macroparticle * @param[in]... - * @param[in] m1 mass of first colliding species - * @param[in] m2 mass of second colliding species + * @param[in] m1_in mass of first colliding species + * @param[in] m2_in mass of second colliding species * @param[in] engine the random engine */ AMREX_GPU_HOST_DEVICE AMREX_INLINE void TwoProductFusionInitializeMomentum ( - const SoaData_type& soa_1, const SoaData_type& soa_2, - SoaData_type& soa_product1, SoaData_type& soa_product2, - const index_type& idx_1, const index_type& idx_2, - const index_type& idx_product1_start, const index_type& idx_product2_start, - const amrex::ParticleReal& m1, const amrex::ParticleReal& m2, - const amrex::ParticleReal& mp1, const amrex::ParticleReal& mp2, + const SoaData_type& soa1_in, const SoaData_type& soa2_in, + SoaData_type& soa1_out, SoaData_type& soa2_out, + const index_type& idx1_in, const index_type& idx2_in, + const index_type& idx1_out_start, const index_type& idx2_out_start, + const amrex::ParticleReal& m1_in, const amrex::ParticleReal& m2_in, + const amrex::ParticleReal& m1_out, const amrex::ParticleReal& m2_out, const amrex::ParticleReal& E_fusion, const amrex::RandomEngine& engine) { @@ -62,31 +62,31 @@ namespace { amrex::ParticleReal ux2_out = 0.0, uy2_out = 0.0, uz2_out = 0.0; TwoProductFusionComputeProductMomenta( - soa_1.m_rdata[PIdx::ux][idx_1], - soa_1.m_rdata[PIdx::uy][idx_1], - soa_1.m_rdata[PIdx::uz][idx_1], m1, - soa_2.m_rdata[PIdx::ux][idx_2], - soa_2.m_rdata[PIdx::uy][idx_2], - soa_2.m_rdata[PIdx::uz][idx_2], m2, - ux1_out, uy1_out, uz1_out, mp1, - uy2_out, uy2_out, uz2_out, mp2, + soa1_in.m_rdata[PIdx::ux][idx1_in], + soa1_in.m_rdata[PIdx::uy][idx1_in], + soa1_in.m_rdata[PIdx::uz][idx1_in], m1_in, + soa2_in.m_rdata[PIdx::ux][idx2_in], + soa2_in.m_rdata[PIdx::uy][idx2_in], + soa2_in.m_rdata[PIdx::uz][idx2_in], m2_in, + ux1_out, uy1_out, uz1_out, m1_out, + uy2_out, uy2_out, uz2_out, m2_out, E_fusion, engine); // Fill momentum of product species (note that we actually // create 4 products, 2 at the position of each incident particle) - soa_product1.m_rdata[PIdx::ux][idx_product1_start] = ux1_out; - soa_product1.m_rdata[PIdx::uy][idx_product1_start] = uy1_out; - soa_product1.m_rdata[PIdx::uz][idx_product1_start] = uz1_out; - soa_product1.m_rdata[PIdx::ux][idx_product1_start + 1] = ux1_out; - soa_product1.m_rdata[PIdx::uy][idx_product1_start + 1] = uy1_out; - soa_product1.m_rdata[PIdx::uz][idx_product1_start + 1] = uz1_out; - soa_product2.m_rdata[PIdx::ux][idx_product2_start] = ux2_out; - soa_product2.m_rdata[PIdx::uy][idx_product2_start] = uy2_out; - soa_product2.m_rdata[PIdx::uz][idx_product2_start] = uz2_out; - soa_product2.m_rdata[PIdx::ux][idx_product2_start + 1] = ux2_out; - soa_product2.m_rdata[PIdx::uy][idx_product2_start + 1] = uy2_out; - soa_product2.m_rdata[PIdx::uz][idx_product2_start + 1] = uz2_out; + soa1_out.m_rdata[PIdx::ux][idx1_out_start] = ux1_out; + soa1_out.m_rdata[PIdx::uy][idx1_out_start] = uy1_out; + soa1_out.m_rdata[PIdx::uz][idx1_out_start] = uz1_out; + soa1_out.m_rdata[PIdx::ux][idx1_out_start + 1] = ux1_out; + soa1_out.m_rdata[PIdx::uy][idx1_out_start + 1] = uy1_out; + soa1_out.m_rdata[PIdx::uz][idx1_out_start + 1] = uz1_out; + soa2_out.m_rdata[PIdx::ux][idx2_out_start] = ux2_out; + soa2_out.m_rdata[PIdx::uy][idx2_out_start] = uy2_out; + soa2_out.m_rdata[PIdx::uz][idx2_out_start] = uz2_out; + soa2_out.m_rdata[PIdx::ux][idx2_out_start + 1] = ux2_out; + soa2_out.m_rdata[PIdx::uy][idx2_out_start + 1] = uy2_out; + soa2_out.m_rdata[PIdx::uz][idx2_out_start + 1] = uz2_out; } } From 821356dcef5b2a081dbee1e4d01680185984b5f2 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 7 Jun 2022 15:23:28 -0700 Subject: [PATCH 24/63] Fix GPU compilation --- .../Collision/BinaryCollision/ParticleCreationFunc.H | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H index c4d8b73b664..9703afef8ba 100644 --- a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H +++ b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H @@ -145,18 +145,24 @@ public: #ifdef AMREX_USE_GPU amrex::Gpu::DeviceVector device_soa_products(m_num_product_species); amrex::Gpu::DeviceVector device_products_np(m_num_product_species); + amrex::Gpu::DeviceVector device_products_mass(m_num_product_species); amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, soa_products.begin(), soa_products.end(), device_soa_products.begin()); amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, products_np.begin(), products_np.end(), device_products_np.begin()); + amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, products_mass.begin(), + products_mass.end(), + device_products_mass.begin()); amrex::Gpu::streamSynchronize(); SoaData_type* AMREX_RESTRICT soa_products_data = device_soa_products.data(); const index_type* AMREX_RESTRICT products_np_data = device_products_np.data(); + const amrex::Real* AMREX_RESTRICT products_mass_data = device_products_mass.data(); #else SoaData_type* AMREX_RESTRICT soa_products_data = soa_products.data(); const index_type* AMREX_RESTRICT products_np_data = products_np.data(); + const amrex::Real* AMREX_RESTRICT products_mass_data = products_mass.data(); #endif const int t_num_product_species = m_num_product_species; @@ -233,7 +239,7 @@ public: p_pair_indices_1[i], p_pair_indices_2[i], products_np_data[0] + 2*p_offsets[i]*p_num_products_device[0], products_np_data[1] + 2*p_offsets[i]*p_num_products_device[1], - m1, m2, products_mass[0], products_mass[1], fusion_energy, engine); + m1, m2, products_mass_data[0], products_mass_data[1], fusion_energy, engine); } } From ad241178c63c76bc5961103b37345e3ed45ed5d6 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 7 Jun 2022 16:03:33 -0700 Subject: [PATCH 25/63] Fix single precision compilation --- .../NuclearFusion/DeuteriumTritiumFusionCrossSection.H | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H index a02c88cdc20..be3126cdfcf 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H @@ -36,7 +36,7 @@ amrex::ParticleReal DeuteriumTritiumFusionCrossSection (const amrex::ParticleRea // (See Eq. 3 in H.-S. Bosch and G.M. Hale 1992 Nucl. Fusion 32 611) constexpr amrex::ParticleReal m_D = 1.99901 * PhysConst::m_p; constexpr amrex::ParticleReal m_T = 2.99372 * PhysConst::m_p; - constexpr amrex::ParticleReal m_reduced = m_D*m_T / (m_D + m_T); + constexpr amrex::ParticleReal m_reduced = m_D / (1._prt + m_D/m_T); amrex::ParticleReal B_G = MathConst::pi * PhysConst::alpha * 2._prt * 3._prt * std::sqrt( 2._prt*m_reduced*PhysConst::c*PhysConst::c * joule_to_keV ); From ca278c624e5b6d1f0b3dcb607e4c45bd4bdd8307 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Wed, 8 Jun 2022 09:29:28 -0700 Subject: [PATCH 26/63] Update types --- .../Collision/BinaryCollision/ParticleCreationFunc.H | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H index 9703afef8ba..3dc05127648 100644 --- a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H +++ b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H @@ -158,11 +158,11 @@ public: amrex::Gpu::streamSynchronize(); SoaData_type* AMREX_RESTRICT soa_products_data = device_soa_products.data(); const index_type* AMREX_RESTRICT products_np_data = device_products_np.data(); - const amrex::Real* AMREX_RESTRICT products_mass_data = device_products_mass.data(); + const amrex::ParticleReal* AMREX_RESTRICT products_mass_data = device_products_mass.data(); #else SoaData_type* AMREX_RESTRICT soa_products_data = soa_products.data(); const index_type* AMREX_RESTRICT products_np_data = products_np.data(); - const amrex::Real* AMREX_RESTRICT products_mass_data = products_mass.data(); + const amrex::ParticleReal* AMREX_RESTRICT products_mass_data = products_mass.data(); #endif const int t_num_product_species = m_num_product_species; From 2cdd39474da935b06c40a3e51a7c9c80deb138ac Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Wed, 8 Jun 2022 11:19:06 -0700 Subject: [PATCH 27/63] Use util function in P-B fusion --- .../ProtonBoronFusionInitializeMomentum.H | 124 ++++-------------- .../TwoProductFusionInitializeMomentum.H | 2 +- 2 files changed, 28 insertions(+), 98 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H index 4ff93b28502..1a350c88011 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H @@ -8,6 +8,7 @@ #ifndef PROTON_BORON_FUSION_INITIALIZE_MOMENTUM_H #define PROTON_BORON_FUSION_INITIALIZE_MOMENTUM_H +#include "TwoProductFusionUtil.H" #include "Particles/WarpXParticleContainer.H" #include "Utils/ParticleUtils.H" #include "Utils/WarpXConst.H" @@ -87,98 +88,27 @@ namespace { constexpr double mBe_sq = m_beryllium*m_beryllium; constexpr amrex::ParticleReal c_sq = PhysConst::c * PhysConst::c; constexpr amrex::ParticleReal inv_csq = 1._prt / ( c_sq ); - // Rest energy of proton+boron - const amrex::ParticleReal E_rest_pb = (m1 + m2)*c_sq; - // Rest energy of alpha+beryllium - constexpr amrex::ParticleReal E_rest_abe = (m_alpha + m_beryllium)*c_sq; - - // Normalized momentum of colliding particles (proton and boron) - const amrex::ParticleReal u1x = soa_1.m_rdata[PIdx::ux][idx_1]; - const amrex::ParticleReal u1y = soa_1.m_rdata[PIdx::uy][idx_1]; - const amrex::ParticleReal u1z = soa_1.m_rdata[PIdx::uz][idx_1]; - const amrex::ParticleReal u2x = soa_2.m_rdata[PIdx::ux][idx_2]; - const amrex::ParticleReal u2y = soa_2.m_rdata[PIdx::uy][idx_2]; - const amrex::ParticleReal u2z = soa_2.m_rdata[PIdx::uz][idx_2]; - - // Compute Lorentz factor gamma in the lab frame - const amrex::ParticleReal g1 = std::sqrt( 1._prt + (u1x*u1x+u1y*u1y+u1z*u1z)*inv_csq ); - const amrex::ParticleReal g2 = std::sqrt( 1._prt + (u2x*u2x+u2y*u2y+u2z*u2z)*inv_csq ); - - // Compute momenta - const amrex::ParticleReal p1x = u1x * m1; - const amrex::ParticleReal p1y = u1y * m1; - const amrex::ParticleReal p1z = u1z * m1; - const amrex::ParticleReal p2x = u2x * m2; - const amrex::ParticleReal p2y = u2y * m2; - const amrex::ParticleReal p2z = u2z * m2; - // Square norm of the total (sum between the two particles) momenta in the lab frame - auto constexpr pow2 = [](double const x) { return x*x; }; - const amrex::ParticleReal p_total_sq = pow2(p1x+p2x) + - pow2(p1y+p2y) + - pow2(p1z+p2z); - - // Total energy of proton+boron in the lab frame - const amrex::ParticleReal E_lab = (m1 * g1 + m2 * g2) * c_sq; - // Total energy squared of proton+boron in the center of mass frame, calculated using the - // Lorentz invariance of the four-momentum norm - const amrex::ParticleReal E_star_sq = E_lab*E_lab - c_sq*p_total_sq; - // Total energy squared of beryllium+alpha in the center of mass frame - // In principle, the term - E_rest_pb + E_rest_abe + E_fusion is not needed and equal to - // zero (i.e. the energy liberated during fusion is equal to the mass difference). However, - // due to possible inconsistencies in how the mass is defined in the code (e.g. currently, - // the mass of hydrogen is the mass of the proton, not including the electron, while the - // mass of the other elements is the atomic mass, that includes the electrons mass), it is - // probably more robust to subtract the rest masses and to add the fusion energy to the - // total kinetic energy. - const amrex::ParticleReal E_star_f_sq = pow2(std::sqrt(E_star_sq) - - E_rest_pb + E_rest_abe + E_fusion); - - // Square of the norm of the momentum of Beryllium or alpha in the center of mass frame - // Formula obtained by inverting E^2 = p^2*c^2 + m^2*c^4 in the COM frame for each particle - auto constexpr pow3 = [](double const x) { return x*x*x; }; - const amrex::ParticleReal p_star_f_sq = - E_star_f_sq*0.25_prt*inv_csq - (ma_sq + mBe_sq)*c_sq*0.5_prt + - pow3(c_sq)*0.25_prt * pow2(ma_sq - mBe_sq) / E_star_f_sq; - - // Compute momentum of first alpha in the center of mass frame, assuming isotropic - // distribution - amrex::ParticleReal px_star, py_star, pz_star; - ParticleUtils::RandomizeVelocity(px_star, py_star, pz_star, std::sqrt(p_star_f_sq), - engine); - - // Next step is to convert momentum of first alpha to lab frame - amrex::ParticleReal px_alpha1, py_alpha1, pz_alpha1; - // Preliminary calculation: compute center of mass velocity vc - const amrex::ParticleReal mass_g = m1 * g1 + m2 * g2; - const amrex::ParticleReal vcx = (p1x+p2x) / mass_g; - const amrex::ParticleReal vcy = (p1y+p2y) / mass_g; - const amrex::ParticleReal vcz = (p1z+p2z) / mass_g; - const amrex::ParticleReal vc_sq = vcx*vcx + vcy*vcy + vcz*vcz; - - // Convert momentum of first alpha to lab frame, using equation (13) of F. Perez et al., - // Phys.Plasmas.19.083104 (2012) - if ( vc_sq > std::numeric_limits::min() ) - { - const amrex::ParticleReal gc = 1._prt / std::sqrt( 1._prt - vc_sq*inv_csq ); - const amrex::ParticleReal g_star = std::sqrt(1._prt + p_star_f_sq / (ma_sq*c_sq)); - const amrex::ParticleReal vcDps = vcx*px_star + vcy*py_star + vcz*pz_star; - const amrex::ParticleReal factor0 = (gc-1._prt)/vc_sq; - const amrex::ParticleReal factor = factor0*vcDps + m_alpha*g_star*gc; - px_alpha1 = px_star + vcx * factor; - py_alpha1 = py_star + vcy * factor; - pz_alpha1 = pz_star + vcz * factor; - } - else // If center of mass velocity is zero, we are already in the lab frame - { - px_alpha1 = px_star; - py_alpha1 = py_star; - pz_alpha1 = pz_star; - } - // Compute momentum of beryllium in lab frame, using total momentum conservation - const amrex::ParticleReal px_Be = p1x + p2x - px_alpha1; - const amrex::ParticleReal py_Be = p1y + p2y - py_alpha1; - const amrex::ParticleReal pz_Be = p1z + p2z - pz_alpha1; + // Compute the resulting momenta of the alpha and beryllium particles + // produced in the fusion reaction + amrex::ParticleReal ux_alpha1 = 0.0, uy_alpha1 = 0.0, uz_alpha1 = 0.0; + amrex::ParticleReal ux_Be = 0.0, uy_Be = 0.0, uz_Be = 0.0; + TwoProductFusionComputeProductMomenta ( + soa1_in.m_rdata[PIdx::ux][idx1_in], + soa1_in.m_rdata[PIdx::uy][idx1_in], + soa1_in.m_rdata[PIdx::uz][idx1_in], m1, + soa2_in.m_rdata[PIdx::ux][idx2_in], + soa2_in.m_rdata[PIdx::uy][idx2_in], + soa2_in.m_rdata[PIdx::uz][idx2_in], m2, + ux_alpha1, uy_alpha1, uz_alpha1, m_alpha, + ux_Be, uy_Be, uz_Be, m_beryllium, + const amrex::ParticleReal& E_fusion, + const amrex::RandomEngine& engine ) + + // Compute momentum of beryllium in lab frame + const amrex::ParticleReal px_Be = m_beryllium * ux_Be; + const amrex::ParticleReal py_Be = m_beryllium * uy_Be; + const amrex::ParticleReal pz_Be = m_beryllium * uz_Be; // Compute momentum norm of second and third alphas in Beryllium rest frame // Factor 0.5 is here because each alpha only gets half of the decay energy @@ -227,12 +157,12 @@ namespace { // Fill alpha species momentum data with the computed momentum (note that we actually // create 6 alphas, 3 at the position of the proton and 3 at the position of the boron, so // each computed momentum is used twice) - soa_alpha.m_rdata[PIdx::ux][idx_alpha_start] = px_alpha1/m_alpha; - soa_alpha.m_rdata[PIdx::uy][idx_alpha_start] = py_alpha1/m_alpha; - soa_alpha.m_rdata[PIdx::uz][idx_alpha_start] = pz_alpha1/m_alpha; - soa_alpha.m_rdata[PIdx::ux][idx_alpha_start + 1] = px_alpha1/m_alpha; - soa_alpha.m_rdata[PIdx::uy][idx_alpha_start + 1] = py_alpha1/m_alpha; - soa_alpha.m_rdata[PIdx::uz][idx_alpha_start + 1] = pz_alpha1/m_alpha; + soa_alpha.m_rdata[PIdx::ux][idx_alpha_start] = ux_alpha1; + soa_alpha.m_rdata[PIdx::uy][idx_alpha_start] = uy_alpha1; + soa_alpha.m_rdata[PIdx::uz][idx_alpha_start] = uz_alpha1; + soa_alpha.m_rdata[PIdx::ux][idx_alpha_start + 1] = ux_alpha1; + soa_alpha.m_rdata[PIdx::uy][idx_alpha_start + 1] = uy_alpha1; + soa_alpha.m_rdata[PIdx::uz][idx_alpha_start + 1] = uz_alpha1; soa_alpha.m_rdata[PIdx::ux][idx_alpha_start + 2] = px_alpha2/m_alpha; soa_alpha.m_rdata[PIdx::uy][idx_alpha_start + 2] = py_alpha2/m_alpha; soa_alpha.m_rdata[PIdx::uz][idx_alpha_start + 2] = pz_alpha2/m_alpha; diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H index dc230c67b33..8bcc114902f 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H @@ -69,7 +69,7 @@ namespace { soa2_in.m_rdata[PIdx::uy][idx2_in], soa2_in.m_rdata[PIdx::uz][idx2_in], m2_in, ux1_out, uy1_out, uz1_out, m1_out, - uy2_out, uy2_out, uz2_out, m2_out, + ux2_out, uy2_out, uz2_out, m2_out, E_fusion, engine); From 3bc13d4e48aa517e7a30fbcd3f7c502e0a041a9b Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Wed, 8 Jun 2022 11:24:09 -0700 Subject: [PATCH 28/63] Correct compilation errors --- .../ProtonBoronFusionInitializeMomentum.H | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H index 1a350c88011..63ceabc4a27 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H @@ -84,26 +84,23 @@ namespace { // precision anyways. constexpr double m_alpha = PhysConst::m_p * 3.97369_prt; constexpr double m_beryllium = PhysConst::m_p * 7.94748_prt; - constexpr double ma_sq = m_alpha*m_alpha; constexpr double mBe_sq = m_beryllium*m_beryllium; constexpr amrex::ParticleReal c_sq = PhysConst::c * PhysConst::c; - constexpr amrex::ParticleReal inv_csq = 1._prt / ( c_sq ); - + // Compute the resulting momenta of the alpha and beryllium particles // produced in the fusion reaction amrex::ParticleReal ux_alpha1 = 0.0, uy_alpha1 = 0.0, uz_alpha1 = 0.0; amrex::ParticleReal ux_Be = 0.0, uy_Be = 0.0, uz_Be = 0.0; TwoProductFusionComputeProductMomenta ( - soa1_in.m_rdata[PIdx::ux][idx1_in], - soa1_in.m_rdata[PIdx::uy][idx1_in], - soa1_in.m_rdata[PIdx::uz][idx1_in], m1, - soa2_in.m_rdata[PIdx::ux][idx2_in], - soa2_in.m_rdata[PIdx::uy][idx2_in], - soa2_in.m_rdata[PIdx::uz][idx2_in], m2, + soa_1.m_rdata[PIdx::ux][idx_1], + soa_1.m_rdata[PIdx::uy][idx_1], + soa_1.m_rdata[PIdx::uz][idx_1], m1, + soa_2.m_rdata[PIdx::ux][idx_2], + soa_2.m_rdata[PIdx::uy][idx_2], + soa_2.m_rdata[PIdx::uz][idx_2], m2, ux_alpha1, uy_alpha1, uz_alpha1, m_alpha, ux_Be, uy_Be, uz_Be, m_beryllium, - const amrex::ParticleReal& E_fusion, - const amrex::RandomEngine& engine ) + E_fusion, engine); // Compute momentum of beryllium in lab frame const amrex::ParticleReal px_Be = m_beryllium * ux_Be; From eb91623f8bf4471923e73576bc335bb28ac4059a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 8 Jun 2022 18:24:33 +0000 Subject: [PATCH 29/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../NuclearFusion/ProtonBoronFusionInitializeMomentum.H | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H index 63ceabc4a27..27d9671113c 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H @@ -86,7 +86,7 @@ namespace { constexpr double m_beryllium = PhysConst::m_p * 7.94748_prt; constexpr double mBe_sq = m_beryllium*m_beryllium; constexpr amrex::ParticleReal c_sq = PhysConst::c * PhysConst::c; - + // Compute the resulting momenta of the alpha and beryllium particles // produced in the fusion reaction amrex::ParticleReal ux_alpha1 = 0.0, uy_alpha1 = 0.0, uz_alpha1 = 0.0; From d82bb730d82abdc1440e8009ffbd9bb2bc03c4d0 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Wed, 8 Jun 2022 14:58:44 -0700 Subject: [PATCH 30/63] Correct errors --- .../BinaryCollision/NuclearFusion/TwoProductFusionUtil.H | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionUtil.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionUtil.H index a2423391bc0..51baa623ef1 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionUtil.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionUtil.H @@ -63,9 +63,9 @@ namespace { // Compute Lorentz factor gamma in the lab frame const amrex::ParticleReal g1_in = std::sqrt( 1._prt - + (u1x_in * u1x_in + u1y_in * u1y_in + u1z_in*u1z_in)*inv_csq ); + + (u1x_in*u1x_in + u1y_in*u1y_in + u1z_in*u1z_in)*inv_csq ); const amrex::ParticleReal g2_in = std::sqrt( 1._prt - + (u2x_out*u2x_out + u2y_out*u2y_out + u2z_out*u2z_out)*inv_csq ); + + (u2x_in*u2x_in + u2y_in*u2y_in + u2z_in*u2z_in)*inv_csq ); // Compute momenta const amrex::ParticleReal p1x_in = u1x_in * m1_in; @@ -101,7 +101,7 @@ namespace { E_star_f_sq*0.25_prt*inv_csq - (m1_out*m1_out + m2_out*m2_out)*c_sq*0.5_prt + pow3(c_sq)*0.25_prt * pow2(m1_out*m1_out - m2_out*m2_out) / E_star_f_sq; - // Compute momentum of first alpha in the center of mass frame, assuming isotropic + // Compute momentum of first product in the center of mass frame, assuming isotropic // distribution amrex::ParticleReal px_star, py_star, pz_star; ParticleUtils::RandomizeVelocity(px_star, py_star, pz_star, std::sqrt(p_star_f_sq), @@ -141,8 +141,7 @@ namespace { const amrex::ParticleReal p2y_out = p1y_in + p2y_in - p1y_out; const amrex::ParticleReal p2z_out = p1z_in + p2z_in - p1z_out; - // Fill momentum of product species (note that we actually - // create 4 products, 2 at the position of each incident particle) + // Compute the momentum of the product species u1x_out = p1x_out/m1_out; u1y_out = p1y_out/m1_out; u1z_out = p1z_out/m1_out; From 323950d333571b7aec9bfca947d1b8b679fd8968 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 9 Jun 2022 13:51:20 -0700 Subject: [PATCH 31/63] Update values of mass and charge --- Docs/source/usage/parameters.rst | 10 +- Source/Particles/SpeciesPhysicalProperties.H | 2 +- .../Particles/SpeciesPhysicalProperties.cpp | 242 +++++++++++------- 3 files changed, 154 insertions(+), 100 deletions(-) diff --git a/Docs/source/usage/parameters.rst b/Docs/source/usage/parameters.rst index 6f6ad281713..d152bd76073 100644 --- a/Docs/source/usage/parameters.rst +++ b/Docs/source/usage/parameters.rst @@ -575,16 +575,16 @@ Particle initialization Type of physical species. Currently, the accepted species are ``"electron"``, ``"positron"``, ``"muon"``, ``"antimuon"``, ``"photon"``, ``"neutron"``, ``"proton"`` , ``"alpha"``, - ``"hydrogen"``, ``"protium"``, ``"deuterium"``, ``"tritium"``, ``"helium"``, ``"helium3"``, ``"helium4"``, + ``"hydrogen1"`` (a.k.a. ``"protium"``), ``"hydrogen2"`` (a.k.a. ``"deuterium"``), ``"hydrogen3"`` (a.k.a.``"tritium"``), + ``"helium"``, ``"helium3"``, ``"helium4"``, ``"lithium"``, ``"lithium6"``, ``"lithium7"``, ``"beryllium"``, ``"boron"``, ``"boron10"``, ``"boron11"``, ``"carbon"``, ``"carbon12"``, ``"carbon13"``, ``"nitrogen"``, ``"nitrogen14"``, ``"nitrogen15"``, ``"oxygen"``, ``"oxygen16"``, ``"oxygen17"``, ``"oxygen18"``, ``"fluorine"``, ``"neon"``, ``"neon20"``, ``"neon21"``, ``"neon22"``, ``"aluminium"``, ``"argon"``, ``"copper"``, ``"xenon"`` and ``"gold"``. - The difference between ``"proton"`` and ``"protium"`` is that the mass of the latter includes also the mass - of the bound electron (same for ``"alpha"`` and ``"helium4"``). When just the name of an element is specified, the mass + The difference between ``"proton"`` and ``"hydrogen1"`` is that the mass of the latter includes also the mass + of the bound electron (same for ``"alpha"`` and ``"helium4"``). When only the name of an element is specified, the mass is a weighted average of the masses of the stable isotopes. For all the elements with ``Z < 11`` we provide - also the stable isotopes as an option for ``species_type`` (e.g., ``"helium3"`` and ``"helium4"``), as well as all the isotopes - of ``"hydrogen"`` (``"protium"``, ``"deuterium"``, ``"tritium"``). + also the stable isotopes as an option for ``species_type`` (e.g., ``"helium3"`` and ``"helium4"``). Either ``species_type`` or both ``mass`` and ``charge`` have to be specified. * ``.charge`` (`float`) optional (default `NaN`) diff --git a/Source/Particles/SpeciesPhysicalProperties.H b/Source/Particles/SpeciesPhysicalProperties.H index 0740c14d5de..affb7a58551 100644 --- a/Source/Particles/SpeciesPhysicalProperties.H +++ b/Source/Particles/SpeciesPhysicalProperties.H @@ -14,7 +14,7 @@ #include enum struct PhysicalSpecies{ - unspecified=0, electron, positron, muon, antimuon, photon, neutron, hydrogen, protium, deuterium, tritium, proton, + unspecified=0, electron, positron, muon, antimuon, photon, neutron, proton, hydrogen1, hydrogen2, hydrogen3, helium, helium3, helium4, alpha, lithium, lithium6, lithium7, beryllium, boron, boron10, boron11, carbon, carbon12, carbon13, nitrogen, nitrogen14, nitrogen15, oxygen, oxygen16, oxygen17, oxygen18, fluorine, neon, neon20, neon21, neon22, aluminium, argon, copper, xenon, gold}; diff --git a/Source/Particles/SpeciesPhysicalProperties.cpp b/Source/Particles/SpeciesPhysicalProperties.cpp index ce1bf1dc62a..fdb9179d89b 100644 --- a/Source/Particles/SpeciesPhysicalProperties.cpp +++ b/Source/Particles/SpeciesPhysicalProperties.cpp @@ -32,12 +32,15 @@ namespace { {"photon" , PhysicalSpecies::photon}, {"neutron" , PhysicalSpecies::neutron}, {"hydrogen" , PhysicalSpecies::hydrogen}, - {"protium" , PhysicalSpecies::protium}, - {"deuterium" , PhysicalSpecies::deuterium}, - {"tritium" , PhysicalSpecies::tritium}, + {"hydrogen1" , PhysicalSpecies::hydrogen1}, + {"protium" , PhysicalSpecies::hydrogen1}, + {"hydrogen2" , PhysicalSpecies::hydrogen2}, + {"deuterium" , PhysicalSpecies::hydrogen2}, + {"hydrogen3" , PhysicalSpecies::hydrogen3}, + {"tritium" , PhysicalSpecies::hydrogen3}, {"proton" , PhysicalSpecies::proton}, {"helium" , PhysicalSpecies::helium}, - {"alpha" , PhysicalSpecies::helium}, + {"alpha" , PhysicalSpecies::alpha}, {"helium3" , PhysicalSpecies::helium3}, {"helium4" , PhysicalSpecies::helium4}, {"alpha" , PhysicalSpecies::alpha}, @@ -72,16 +75,16 @@ namespace { const auto species_to_string = std::map{ {PhysicalSpecies::unspecified, "unspecified"}, - {PhysicalSpecies::electron , "electron"}, + {PhysicalSpecies::electron , "electron"}, {PhysicalSpecies::positron , "positron"}, {PhysicalSpecies::muon , "muon"}, {PhysicalSpecies::antimuon , "antimuon"}, {PhysicalSpecies::photon , "photon"}, {PhysicalSpecies::neutron , "neutron"}, {PhysicalSpecies::hydrogen , "hydrogen"}, - {PhysicalSpecies::protium , "protium"}, - {PhysicalSpecies::deuterium , "deuterium"}, - {PhysicalSpecies::tritium , "tritium"}, + {PhysicalSpecies::hydrogen1 , "hydrogen1"}, + {PhysicalSpecies::hydrogen2 , "hydrogen2"}, + {PhysicalSpecies::hydrogen3 , "hydrogen3"}, {PhysicalSpecies::proton , "proton"}, {PhysicalSpecies::helium , "helium"}, {PhysicalSpecies::helium3 , "helium3"}, @@ -115,95 +118,146 @@ namespace { constexpr auto quiet_NaN = std::numeric_limits::quiet_NaN(); + // The atomic mass data below is from this NIST page + // https://physics.nist.gov/cgi-bin/Compositions/stand_alone.pl?ele=&ascii=ascii2&isotype=some const std::map species_to_properties { - {PhysicalSpecies::unspecified, - Properties{quiet_NaN, quiet_NaN}}, - {PhysicalSpecies::electron, - Properties{ PhysConst::m_e, -PhysConst::q_e}}, - {PhysicalSpecies::positron, - Properties{ PhysConst::m_e, PhysConst::q_e}}, - {PhysicalSpecies::muon, - Properties{amrex::Real(206.7682830) * PhysConst::m_e, -PhysConst::q_e}}, - {PhysicalSpecies::antimuon, - Properties{amrex::Real(206.7682830) * PhysConst::m_e, PhysConst::q_e}}, - {PhysicalSpecies::photon, - Properties{ amrex::Real(0.0), amrex::Real(0.0)}}, - {PhysicalSpecies::neutron, - Properties{amrex::Real(1.0013784193052508) * PhysConst::m_p, amrex::Real(0.0)}}, - {PhysicalSpecies::hydrogen, - Properties{ amrex::Real(1.008) * PhysConst::m_u, PhysConst::q_e}}, - {PhysicalSpecies::protium, - Properties{ amrex::Real(1.0078) * PhysConst::m_u, PhysConst::q_e}}, - {PhysicalSpecies::deuterium, - Properties{ amrex::Real(2.0141) * PhysConst::m_u, PhysConst::q_e}}, - {PhysicalSpecies::tritium, - Properties{ amrex::Real(3.0160) * PhysConst::m_u, PhysConst::q_e}}, - {PhysicalSpecies::proton, - Properties{ PhysConst::m_p, PhysConst::q_e}}, - {PhysicalSpecies::helium, - Properties{ amrex::Real(4.0026) * PhysConst::m_u, amrex::Real(2.0) * PhysConst::q_e}}, - {PhysicalSpecies::helium3, - Properties{ amrex::Real(3.0160) * PhysConst::m_u, amrex::Real(2.0) * PhysConst::q_e}}, - {PhysicalSpecies::helium4, - Properties{ amrex::Real(4.0026) * PhysConst::m_u, amrex::Real(2.0) * PhysConst::q_e}}, - {PhysicalSpecies::alpha, - Properties{ amrex::Real(4.0015) * PhysConst::m_u, amrex::Real(2.0) * PhysConst::q_e}}, - {PhysicalSpecies::lithium, - Properties{ amrex::Real(6.94) * PhysConst::m_u, amrex::Real(3.0) * PhysConst::q_e}}, - {PhysicalSpecies::lithium6, - Properties{ amrex::Real(6.0151) * PhysConst::m_u, amrex::Real(3.0) * PhysConst::q_e}}, - {PhysicalSpecies::lithium7, - Properties{ amrex::Real(7.0160) * PhysConst::m_u, amrex::Real(3.0) * PhysConst::q_e}}, - {PhysicalSpecies::beryllium, - Properties{ amrex::Real(9.0122) * PhysConst::m_u, amrex::Real(4.0) * PhysConst::q_e}}, - {PhysicalSpecies::boron, - Properties{ amrex::Real(10.81) * PhysConst::m_u, amrex::Real(5.0) * PhysConst::q_e}}, - {PhysicalSpecies::boron10, - Properties{ amrex::Real(10.0129) * PhysConst::m_u, amrex::Real(5.0) * PhysConst::q_e}}, - {PhysicalSpecies::boron11, - Properties{ amrex::Real(11.0093) * PhysConst::m_u, amrex::Real(5.0) * PhysConst::q_e}}, - {PhysicalSpecies::carbon, - Properties{ amrex::Real(12.011) * PhysConst::m_u, amrex::Real(6.0) * PhysConst::q_e}}, - {PhysicalSpecies::carbon12, - Properties{ amrex::Real(12) * PhysConst::m_u, amrex::Real(6.0) * PhysConst::q_e}}, - {PhysicalSpecies::carbon13, - Properties{ amrex::Real(13.0033) * PhysConst::m_u, amrex::Real(6.0) * PhysConst::q_e}}, - {PhysicalSpecies::nitrogen, - Properties{ amrex::Real(14.007) * PhysConst::m_u, amrex::Real(7.0) * PhysConst::q_e}}, - {PhysicalSpecies::nitrogen14, - Properties{ amrex::Real(14.0031) * PhysConst::m_u, amrex::Real(7.0) * PhysConst::q_e}}, - {PhysicalSpecies::nitrogen15, - Properties{ amrex::Real(15.0001) * PhysConst::m_u, amrex::Real(7.0) * PhysConst::q_e}}, - {PhysicalSpecies::oxygen, - Properties{ amrex::Real(15.999) * PhysConst::m_u, amrex::Real(8.0) * PhysConst::q_e}}, - {PhysicalSpecies::oxygen16, - Properties{ amrex::Real(15.9949) * PhysConst::m_u, amrex::Real(8.0) * PhysConst::q_e}}, - {PhysicalSpecies::oxygen17, - Properties{ amrex::Real(16.9991) * PhysConst::m_u, amrex::Real(8.0) * PhysConst::q_e}}, - {PhysicalSpecies::oxygen18, - Properties{ amrex::Real(17.9992) * PhysConst::m_u, amrex::Real(8.0) * PhysConst::q_e}}, - {PhysicalSpecies::fluorine, - Properties{ amrex::Real(18.9984) * PhysConst::m_u, amrex::Real(9.0) * PhysConst::q_e}}, - {PhysicalSpecies::neon, - Properties{ amrex::Real(20.1798) * PhysConst::m_u, amrex::Real(10.0) * PhysConst::q_e}}, - {PhysicalSpecies::neon20, - Properties{ amrex::Real(19.9924) * PhysConst::m_u, amrex::Real(10.0) * PhysConst::q_e}}, - {PhysicalSpecies::neon21, - Properties{ amrex::Real(20.9938) * PhysConst::m_u, amrex::Real(10.0) * PhysConst::q_e}}, - {PhysicalSpecies::neon22, - Properties{ amrex::Real(21.9914) * PhysConst::m_u, amrex::Real(10.0) * PhysConst::q_e}}, - {PhysicalSpecies::aluminium, - Properties{ amrex::Real(26.9815) * PhysConst::m_u, amrex::Real(13.0) * PhysConst::q_e}}, - {PhysicalSpecies::argon, - Properties{ amrex::Real(39.7924) * PhysConst::m_u, amrex::Real(18.0) * PhysConst::q_e}}, - {PhysicalSpecies::copper, - Properties{ amrex::Real(63.546) * PhysConst::m_u, amrex::Real(29.0) * PhysConst::q_e}}, - {PhysicalSpecies::xenon, - Properties{ amrex::Real(131.293) * PhysConst::m_u, amrex::Real(54.0) * PhysConst::q_e}}, - {PhysicalSpecies::gold, - Properties{ amrex::Real(196.9666) * PhysConst::m_u, amrex::Real(79.0) * PhysConst::q_e}} + {PhysicalSpecies::unspecified, Properties{ + quiet_NaN, + quiet_NaN}}, + {PhysicalSpecies::electron, Properties{ + PhysConst::m_e, + -PhysConst::q_e}}, + {PhysicalSpecies::positron, Properties{ + PhysConst::m_e, + PhysConst::q_e}}, + {PhysicalSpecies::muon, Properties{ + amrex::Real(206.7682830) * PhysConst::m_e, + -PhysConst::q_e}}, + {PhysicalSpecies::antimuon, Properties{ + amrex::Real(206.7682830) * PhysConst::m_e, + PhysConst::q_e}}, + {PhysicalSpecies::photon, Properties{ + amrex::Real(0.0), + amrex::Real(0.0)}}, + {PhysicalSpecies::neutron, Properties{ + amrex::Real(1.0013784193052508) * PhysConst::m_p, + amrex::Real(0.0)}}, + {PhysicalSpecies::proton, Properties{ + PhysConst::m_p, + PhysConst::q_e}}, + {PhysicalSpecies::hydrogen, Properties{ + amrex::Real(1.00797) * PhysConst::m_u, + amrex::Real(1) * PhysConst::q_e}}, + {PhysicalSpecies::hydrogen1, Properties{ + amrex::Real(1.00782503223) * PhysConst::m_u, + amrex::Real(1) * PhysConst::q_e}}, + {PhysicalSpecies::hydrogen2, Properties{ + amrex::Real(2.01410177812) * PhysConst::m_u, + amrex::Real(1) * PhysConst::q_e}}, + {PhysicalSpecies::hydrogen3, Properties{ + amrex::Real(3.0160492779) * PhysConst::m_u, + amrex::Real(1) * PhysConst::q_e}}, + {PhysicalSpecies::helium, Properties{ + amrex::Real(4.002602) * PhysConst::m_u, + amrex::Real(2) * PhysConst::q_e}}, + {PhysicalSpecies::helium3, Properties{ + amrex::Real(3.0160293201) * PhysConst::m_u, + amrex::Real(2) * PhysConst::q_e}}, + {PhysicalSpecies::helium4, Properties{ + amrex::Real(4.00260325413) * PhysConst::m_u, + amrex::Real(2) * PhysConst::q_e}}, + {PhysicalSpecies::alpha, Properties{ + amrex::Real(4.00260325413) * PhysConst::m_u - amrex::Real(2) * PhysConst::m_e, + amrex::Real(2) * PhysConst::q_e}}, + {PhysicalSpecies::lithium, Properties{ + amrex::Real(6.967) * PhysConst::m_u, + amrex::Real(3) * PhysConst::q_e}}, + {PhysicalSpecies::lithium6, Properties{ + amrex::Real(6.0151228874) * PhysConst::m_u, + amrex::Real(3) * PhysConst::q_e}}, + {PhysicalSpecies::lithium7, Properties{ + amrex::Real(7.0160034366) * PhysConst::m_u, + amrex::Real(3) * PhysConst::q_e}}, + {PhysicalSpecies::beryllium, Properties{ + amrex::Real(9.0121831) * PhysConst::m_u, + amrex::Real(4) * PhysConst::q_e}}, + {PhysicalSpecies::beryllium9, Properties{ + amrex::Real(9.012183065) * PhysConst::m_u, + amrex::Real(4) * PhysConst::q_e}}, + {PhysicalSpecies::boron, Properties{ + amrex::Real(10.813) * PhysConst::m_u, + amrex::Real(5) * PhysConst::q_e}}, + {PhysicalSpecies::boron10, Properties{ + amrex::Real(10.01293695) * PhysConst::m_u, + amrex::Real(5) * PhysConst::q_e}}, + {PhysicalSpecies::boron11, Properties{ + amrex::Real(11.00930536) * PhysConst::m_u, + amrex::Real(5) * PhysConst::q_e}}, + {PhysicalSpecies::carbon, Properties{ + amrex::Real(12.0106) * PhysConst::m_u, + amrex::Real(6) * PhysConst::q_e}}, + {PhysicalSpecies::carbon12, Properties{ + amrex::Real(12.0000000) * PhysConst::m_u, + amrex::Real(6) * PhysConst::q_e}}, + {PhysicalSpecies::carbon13, Properties{ + amrex::Real(13.00335483507) * PhysConst::m_u, + amrex::Real(6) * PhysConst::q_e}}, + {PhysicalSpecies::carbon14, Properties{ + amrex::Real(14.0032419884) * PhysConst::m_u, + amrex::Real(6) * PhysConst::q_e}}, + {PhysicalSpecies::nitrogen, Properties{ + amrex::Real(14.00685) * PhysConst::m_u, + amrex::Real(7) * PhysConst::q_e}}, + {PhysicalSpecies::nitrogen14, Properties{ + amrex::Real(14.00307400443) * PhysConst::m_u, + amrex::Real(7) * PhysConst::q_e}}, + {PhysicalSpecies::nitrogen15, Properties{ + amrex::Real(15.00010889888) * PhysConst::m_u, + amrex::Real(7) * PhysConst::q_e}}, + {PhysicalSpecies::oxygen, Properties{ + amrex::Real(15.9994) * PhysConst::m_u, + amrex::Real(8) * PhysConst::q_e}}, + {PhysicalSpecies::oxygen16, Properties{ + amrex::Real(15.99491461957) * PhysConst::m_u, + amrex::Real(8) * PhysConst::q_e}}, + {PhysicalSpecies::oxygen17, Properties{ + amrex::Real(16.99913175650) * PhysConst::m_u, + amrex::Real(8) * PhysConst::q_e}}, + {PhysicalSpecies::oxygen18, Properties{ + amrex::Real(17.99915961286) * PhysConst::m_u, + amrex::Real(8) * PhysConst::q_e}}, + {PhysicalSpecies::fluorine, Properties{ + amrex::Real(18.998403163) * PhysConst::m_u, + amrex::Real(9) * PhysConst::q_e}}, + {PhysicalSpecies::fluorine19, Properties{ + amrex::Real(18.99840316273) * PhysConst::m_u, + amrex::Real(9) * PhysConst::q_e}}, + {PhysicalSpecies::neon, Properties{ + amrex::Real(20.1797) * PhysConst::m_u, + amrex::Real(10) * PhysConst::q_e}}, + {PhysicalSpecies::neon20, Properties{ + amrex::Real(19.9924401762) * PhysConst::m_u, + amrex::Real(10) * PhysConst::q_e}}, + {PhysicalSpecies::neon21, Properties{ + amrex::Real(20.993846685) * PhysConst::m_u, + amrex::Real(10) * PhysConst::q_e}}, + {PhysicalSpecies::neon22, Properties{ + amrex::Real(21.991385114) * PhysConst::m_u, + amrex::Real(10) * PhysConst::q_e}}, + {PhysicalSpecies::argon, Properties{ + amrex::Real(39.948) * PhysConst::m_u, + amrex::Real(18) * PhysConst::q_e}}, + {PhysicalSpecies::copper, Properties{ + amrex::Real(63.546) * PhysConst::m_u, + amrex::Real(29) * PhysConst::q_e}}, + {PhysicalSpecies::xenon, Properties{ + amrex::Real(131.293) * PhysConst::m_u, + amrex::Real(54) * PhysConst::q_e}}, + {PhysicalSpecies::gold, Properties{ + amrex::Real(196.966569) * PhysConst::m_u, + amrex::Real(79) * PhysConst::q_e}}, }; } From 61b07698e223adf41bac542b90430963c0e570be Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 9 Jun 2022 14:03:06 -0700 Subject: [PATCH 32/63] Correct compilation error --- Source/Particles/SpeciesPhysicalProperties.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/Particles/SpeciesPhysicalProperties.cpp b/Source/Particles/SpeciesPhysicalProperties.cpp index fdb9179d89b..dfde25ec65d 100644 --- a/Source/Particles/SpeciesPhysicalProperties.cpp +++ b/Source/Particles/SpeciesPhysicalProperties.cpp @@ -62,6 +62,7 @@ namespace { {"oxygen17" , PhysicalSpecies::oxygen17}, {"oxygen18" , PhysicalSpecies::oxygen18}, {"fluorine" , PhysicalSpecies::fluorine}, + {"fluorine19" , PhysicalSpecies::fluorine19}, {"neon" , PhysicalSpecies::neon}, {"neon20" , PhysicalSpecies::neon20}, {"neon21" , PhysicalSpecies::neon21}, @@ -104,7 +105,11 @@ namespace { {PhysicalSpecies::nitrogen14 , "nitrogen14"}, {PhysicalSpecies::nitrogen15 , "nitrogen15"}, {PhysicalSpecies::oxygen , "oxygen"}, + {PhysicalSpecies::oxygen16 , "oxygen16"}, + {PhysicalSpecies::oxygen17 , "oxygen17"}, + {PhysicalSpecies::oxygen18 , "oxygen18"}, {PhysicalSpecies::fluorine , "fluorine"}, + {PhysicalSpecies::fluorine19 , "fluorine19"}, {PhysicalSpecies::neon , "neon"}, {PhysicalSpecies::neon20 , "neon20"}, {PhysicalSpecies::neon21 , "neon21"}, From bbf95b8f47cbe44ac7f82fdfb03ed93b235fc8ca Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 9 Jun 2022 21:04:06 +0000 Subject: [PATCH 33/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- Source/Particles/SpeciesPhysicalProperties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Particles/SpeciesPhysicalProperties.cpp b/Source/Particles/SpeciesPhysicalProperties.cpp index dfde25ec65d..1d2eeb993e0 100644 --- a/Source/Particles/SpeciesPhysicalProperties.cpp +++ b/Source/Particles/SpeciesPhysicalProperties.cpp @@ -109,7 +109,7 @@ namespace { {PhysicalSpecies::oxygen17 , "oxygen17"}, {PhysicalSpecies::oxygen18 , "oxygen18"}, {PhysicalSpecies::fluorine , "fluorine"}, - {PhysicalSpecies::fluorine19 , "fluorine19"}, + {PhysicalSpecies::fluorine19 , "fluorine19"}, {PhysicalSpecies::neon , "neon"}, {PhysicalSpecies::neon20 , "neon20"}, {PhysicalSpecies::neon21 , "neon21"}, From 70c5fe68d5d70ef2ef09bec1a28cb01fe5c98abc Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 9 Jun 2022 14:06:38 -0700 Subject: [PATCH 34/63] Correct compilation error --- Source/Particles/SpeciesPhysicalProperties.H | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Particles/SpeciesPhysicalProperties.H b/Source/Particles/SpeciesPhysicalProperties.H index affb7a58551..00ec413d60d 100644 --- a/Source/Particles/SpeciesPhysicalProperties.H +++ b/Source/Particles/SpeciesPhysicalProperties.H @@ -17,7 +17,7 @@ enum struct PhysicalSpecies{ unspecified=0, electron, positron, muon, antimuon, photon, neutron, proton, hydrogen1, hydrogen2, hydrogen3, helium, helium3, helium4, alpha, lithium, lithium6, lithium7, beryllium, boron, boron10, boron11, carbon, carbon12, carbon13, nitrogen, nitrogen14, nitrogen15, oxygen, oxygen16, oxygen17, oxygen18, fluorine, - neon, neon20, neon21, neon22, aluminium, argon, copper, xenon, gold}; + fluorine19, neon, neon20, neon21, neon22, aluminium, argon, copper, xenon, gold}; namespace species { From 65409f4e9932c852bc792145375113fe865311ed Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 9 Jun 2022 14:14:06 -0700 Subject: [PATCH 35/63] Correct compilation error --- Source/Particles/SpeciesPhysicalProperties.H | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Particles/SpeciesPhysicalProperties.H b/Source/Particles/SpeciesPhysicalProperties.H index 00ec413d60d..d8d401659d4 100644 --- a/Source/Particles/SpeciesPhysicalProperties.H +++ b/Source/Particles/SpeciesPhysicalProperties.H @@ -14,7 +14,7 @@ #include enum struct PhysicalSpecies{ - unspecified=0, electron, positron, muon, antimuon, photon, neutron, proton, hydrogen1, hydrogen2, hydrogen3, + unspecified=0, electron, positron, muon, antimuon, photon, neutron, proton, hydrogen, hydrogen1, hydrogen2, hydrogen3, helium, helium3, helium4, alpha, lithium, lithium6, lithium7, beryllium, boron, boron10, boron11, carbon, carbon12, carbon13, nitrogen, nitrogen14, nitrogen15, oxygen, oxygen16, oxygen17, oxygen18, fluorine, fluorine19, neon, neon20, neon21, neon22, aluminium, argon, copper, xenon, gold}; From c82c8e7e974b22249b7dd0167842a21c4d4b2c06 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 9 Jun 2022 14:26:43 -0700 Subject: [PATCH 36/63] Correct compilation error --- Source/Particles/SpeciesPhysicalProperties.H | 4 ++-- Source/Particles/SpeciesPhysicalProperties.cpp | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Source/Particles/SpeciesPhysicalProperties.H b/Source/Particles/SpeciesPhysicalProperties.H index d8d401659d4..dba12e353f5 100644 --- a/Source/Particles/SpeciesPhysicalProperties.H +++ b/Source/Particles/SpeciesPhysicalProperties.H @@ -15,8 +15,8 @@ enum struct PhysicalSpecies{ unspecified=0, electron, positron, muon, antimuon, photon, neutron, proton, hydrogen, hydrogen1, hydrogen2, hydrogen3, - helium, helium3, helium4, alpha, lithium, lithium6, lithium7, beryllium, boron, boron10, boron11, carbon, - carbon12, carbon13, nitrogen, nitrogen14, nitrogen15, oxygen, oxygen16, oxygen17, oxygen18, fluorine, + helium, helium3, helium4, alpha, lithium, lithium6, lithium7, beryllium, beryllium9, boron, boron10, boron11, carbon, + carbon12, carbon13, carbon14, nitrogen, nitrogen14, nitrogen15, oxygen, oxygen16, oxygen17, oxygen18, fluorine, fluorine19, neon, neon20, neon21, neon22, aluminium, argon, copper, xenon, gold}; namespace species diff --git a/Source/Particles/SpeciesPhysicalProperties.cpp b/Source/Particles/SpeciesPhysicalProperties.cpp index 1d2eeb993e0..9c357bf0e83 100644 --- a/Source/Particles/SpeciesPhysicalProperties.cpp +++ b/Source/Particles/SpeciesPhysicalProperties.cpp @@ -48,12 +48,14 @@ namespace { {"lithium6" , PhysicalSpecies::lithium6}, {"lithium7" , PhysicalSpecies::lithium7}, {"beryllium" , PhysicalSpecies::beryllium}, + {"beryllium9" , PhysicalSpecies::beryllium9}, {"boron" , PhysicalSpecies::boron}, {"boron10" , PhysicalSpecies::boron10}, {"boron11" , PhysicalSpecies::boron11}, {"carbon" , PhysicalSpecies::carbon}, {"carbon12" , PhysicalSpecies::carbon12}, {"carbon13" , PhysicalSpecies::carbon13}, + {"carbon14" , PhysicalSpecies::carbon14}, {"nitrogen" , PhysicalSpecies::nitrogen}, {"nitrogen14" , PhysicalSpecies::nitrogen14}, {"nitrogen15" , PhysicalSpecies::nitrogen15}, @@ -95,12 +97,14 @@ namespace { {PhysicalSpecies::lithium6 , "lithium6"}, {PhysicalSpecies::lithium7 , "lithium7"}, {PhysicalSpecies::beryllium , "beryllium"}, + {PhysicalSpecies::beryllium9 , "beryllium9"}, {PhysicalSpecies::boron , "boron"}, {PhysicalSpecies::boron10 , "boron10"}, {PhysicalSpecies::boron11 , "boron11"}, {PhysicalSpecies::carbon , "carbon"}, {PhysicalSpecies::carbon12 , "carbon12"}, {PhysicalSpecies::carbon13 , "carbon13"}, + {PhysicalSpecies::carbon14 , "carbon14"}, {PhysicalSpecies::nitrogen , "nitrogen"}, {PhysicalSpecies::nitrogen14 , "nitrogen14"}, {PhysicalSpecies::nitrogen15 , "nitrogen15"}, From 9510deea1828e08a8326ec91563990e6d424cadf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 9 Jun 2022 21:27:03 +0000 Subject: [PATCH 37/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- Source/Particles/SpeciesPhysicalProperties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Particles/SpeciesPhysicalProperties.cpp b/Source/Particles/SpeciesPhysicalProperties.cpp index 9c357bf0e83..8086b14bd29 100644 --- a/Source/Particles/SpeciesPhysicalProperties.cpp +++ b/Source/Particles/SpeciesPhysicalProperties.cpp @@ -55,7 +55,7 @@ namespace { {"carbon" , PhysicalSpecies::carbon}, {"carbon12" , PhysicalSpecies::carbon12}, {"carbon13" , PhysicalSpecies::carbon13}, - {"carbon14" , PhysicalSpecies::carbon14}, + {"carbon14" , PhysicalSpecies::carbon14}, {"nitrogen" , PhysicalSpecies::nitrogen}, {"nitrogen14" , PhysicalSpecies::nitrogen14}, {"nitrogen15" , PhysicalSpecies::nitrogen15}, From 2a41771987abf300c9b5a63a01300ea9516e89a1 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 9 Jun 2022 16:47:12 -0700 Subject: [PATCH 38/63] Reset benchmark --- .../benchmarks_json/multi_J_2d_psatd_pml.json | 40 +++++++++---------- .../benchmarks_json/multi_J_rz_psatd.json | 36 ++++++++--------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Regression/Checksum/benchmarks_json/multi_J_2d_psatd_pml.json b/Regression/Checksum/benchmarks_json/multi_J_2d_psatd_pml.json index 15a77d5e5c0..86cd8e09b1f 100644 --- a/Regression/Checksum/benchmarks_json/multi_J_2d_psatd_pml.json +++ b/Regression/Checksum/benchmarks_json/multi_J_2d_psatd_pml.json @@ -2,50 +2,50 @@ "driver": { "particle_cpu": 0.0, "particle_id": 5000050000.0, - "particle_momentum_x": 1.4499924704466542e-16, + "particle_momentum_x": 1.4499925126853143e-16, "particle_momentum_y": 0.0, "particle_momentum_z": 9.82279038230043e-09, - "particle_position_x": 0.4000037675727611, + "particle_position_x": 0.4000037675727584, "particle_position_y": 30.100865423602578, "particle_weight": 124830181489215.27 }, "lev=0": { "Bx": 0.0, - "By": 921660.8978659188, + "By": 921660.8763744916, "Bz": 0.0, - "Ex": 270876493491643.72, + "Ex": 270876488518506.03, "Ey": 0.0, - "Ez": 92624928289782.67, - "F": 6183.053934691087, + "Ez": 92624928893088.9, + "F": 6183.05541122242, "G": 0.0, - "divE": 2.5190221277716443e+19, - "jx": 1.0172820296985254e+16, + "divE": 2.5190220275534684e+19, + "jx": 1.0172820267112668e+16, "jy": 0.0, - "jz": 6.385280627174476e+16, - "rho": 220331916.84576574, + "jz": 6.3852803420999176e+16, + "rho": 220331907.1018316, "rho_driver": 2562225.119933118, "rho_driver_back": 0.0, - "rho_plasma_e": 1359499348.832252, - "rho_plasma_p": 1361225457.7092004 + "rho_plasma_e": 1359499348.8917723, + "rho_plasma_p": 1361225457.8189807 }, "plasma_e": { "particle_cpu": 29647.0, "particle_id": 1194856401.0, - "particle_momentum_x": 7.187014141480275e-19, + "particle_momentum_x": 7.187013750906501e-19, "particle_momentum_y": 0.0, - "particle_momentum_z": 2.3464972406746717e-17, - "particle_position_x": 1.3919451689290652, - "particle_position_y": 10.07681590718761, + "particle_momentum_z": 2.3464972335833197e-17, + "particle_position_x": 1.3919451689822666, + "particle_position_y": 10.076815904733323, "particle_weight": 6.641904330784497e+16 }, "plasma_p": { "particle_cpu": 29696.0, "particle_id": 1202173888.0, - "particle_momentum_x": 1.4494696792808645e-18, + "particle_momentum_x": 1.4494696265263356e-18, "particle_momentum_y": 0.0, - "particle_momentum_z": 4.00858476212274e-14, - "particle_position_x": 1.345648034097414, - "particle_position_y": 10.082154832906486, + "particle_momentum_z": 4.0084654499150134e-14, + "particle_position_x": 1.3456480355301481, + "particle_position_y": 10.08215483152446, "particle_weight": 6.652881944445523e+16 } } \ No newline at end of file diff --git a/Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json b/Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json index a095b042659..536df09393a 100644 --- a/Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json +++ b/Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json @@ -11,35 +11,35 @@ "particle_weight": 6241484108.424456 }, "lev=0": { - "By": 24912.66262617112, - "Ex": 4667306707740.952, - "Ez": 4307437889665.741, - "jx": 362735946859133.25, - "jz": 1937267341438018.5, - "rho": 5308546.10760024, + "By": 24912.66260587033, + "Ex": 4667306677660.305, + "Ez": 4307437890419.4253, + "jx": 362735950033724.2, + "jz": 1937267340131275.2, + "rho": 5308546.075566203, "rho_driver": 6288266.101815152, - "rho_plasma_e": 49569864.00561153, - "rho_plasma_p": 50769174.575747415 + "rho_plasma_e": 49569864.00850832, + "rho_plasma_p": 50769174.61530346 }, "plasma_e": { "particle_cpu": 12650.0, "particle_id": 159086515.0, - "particle_momentum_x": 6.658111450308696e-20, - "particle_momentum_y": 6.738987086219168e-20, - "particle_momentum_z": 2.8465711111032466e-20, - "particle_position_x": 1.142336749571497, - "particle_position_y": 0.6139715590488816, + "particle_momentum_x": 6.65811141013141e-20, + "particle_momentum_y": 6.738987045495091e-20, + "particle_momentum_z": 2.846571109435123e-20, + "particle_position_x": 1.1423367495493797, + "particle_position_y": 0.6139715590509269, "particle_theta": 20188.939948727297, "particle_weight": 1002457942911.3788 }, "plasma_p": { "particle_cpu": 12650.0, "particle_id": 163728835.0, - "particle_momentum_x": 6.640192785220438e-20, - "particle_momentum_y": 6.767588624594766e-20, - "particle_momentum_z": 5.584761199543091e-20, - "particle_position_x": 1.136520160120179, - "particle_position_y": 0.6152066982335147, + "particle_momentum_x": 6.640192720118765e-20, + "particle_momentum_y": 6.767588557043428e-20, + "particle_momentum_z": 5.58476124317102e-20, + "particle_position_x": 1.1365201600226575, + "particle_position_y": 0.6152066982817419, "particle_theta": 20286.92798337582, "particle_weight": 1002457942911.3788 } From 24d1fc7b65423e5dff9257f5730711d174a7299c Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 9 Jun 2022 16:48:22 -0700 Subject: [PATCH 39/63] Use helium particle in proton-boron, to avoid resetting benchmark --- Examples/Modules/nuclear_fusion/inputs_3d | 10 +++++----- .../BinaryCollision/NuclearFusion/NuclearFusionFunc.H | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/inputs_3d b/Examples/Modules/nuclear_fusion/inputs_3d index babd2655da3..910729edc3b 100644 --- a/Examples/Modules/nuclear_fusion/inputs_3d +++ b/Examples/Modules/nuclear_fusion/inputs_3d @@ -63,7 +63,7 @@ boron1.momentum_function_uz(x,y,z) = -sqrt(2*m_reduced*Energy_step*(floor(z)**2) boron1.do_not_push = 1 boron1.do_not_deposit = 1 -alpha1.species_type = alpha +alpha1.species_type = helium alpha1.do_not_push = 1 alpha1.do_not_deposit = 1 @@ -94,7 +94,7 @@ boron2.momentum_distribution_type = "constant" boron2.do_not_push = 1 boron2.do_not_deposit = 1 -alpha2.species_type = alpha +alpha2.species_type = helium alpha2.do_not_push = 1 alpha2.do_not_deposit = 1 @@ -120,7 +120,7 @@ boron3.theta = temperature/(m_b11*clight**2) boron3.do_not_push = 1 boron3.do_not_deposit = 1 -alpha3.species_type = alpha +alpha3.species_type = helium alpha3.do_not_push = 1 alpha3.do_not_deposit = 1 @@ -145,7 +145,7 @@ boron4.momentum_distribution_type = "constant" boron4.do_not_push = 1 boron4.do_not_deposit = 1 -alpha4.species_type = alpha +alpha4.species_type = helium alpha4.do_not_push = 1 alpha4.do_not_deposit = 1 @@ -168,7 +168,7 @@ boron5.momentum_distribution_type = "constant" boron5.do_not_push = 1 boron5.do_not_deposit = 1 -alpha5.species_type = alpha +alpha5.species_type = helium alpha5.do_not_push = 1 alpha5.do_not_deposit = 1 diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H index 88964e0b877..be1d9622edc 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H @@ -75,7 +75,7 @@ public: "ERROR: Proton-boron must contain exactly one product species"); auto& product_species = mypc->GetParticleContainerFromName(product_species_name[0]); WARPX_ALWAYS_ASSERT_WITH_MESSAGE( - product_species.AmIA(), + product_species.AmIA(), "ERROR: Product species of proton-boron fusion must be of type alpha"); } From 73c8d9d0be8417d5cd08a23daeebbc322c984808 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Fri, 10 Jun 2022 08:48:26 -0700 Subject: [PATCH 40/63] Fixed proton-boron test --- Source/Particles/SpeciesPhysicalProperties.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Particles/SpeciesPhysicalProperties.cpp b/Source/Particles/SpeciesPhysicalProperties.cpp index 8086b14bd29..13432bf99b3 100644 --- a/Source/Particles/SpeciesPhysicalProperties.cpp +++ b/Source/Particles/SpeciesPhysicalProperties.cpp @@ -169,7 +169,7 @@ namespace { amrex::Real(3.0160492779) * PhysConst::m_u, amrex::Real(1) * PhysConst::q_e}}, {PhysicalSpecies::helium, Properties{ - amrex::Real(4.002602) * PhysConst::m_u, + PhysConst::m_p * amrex::Real(3.97369), amrex::Real(2) * PhysConst::q_e}}, {PhysicalSpecies::helium3, Properties{ amrex::Real(3.0160293201) * PhysConst::m_u, @@ -202,7 +202,7 @@ namespace { amrex::Real(10.01293695) * PhysConst::m_u, amrex::Real(5) * PhysConst::q_e}}, {PhysicalSpecies::boron11, Properties{ - amrex::Real(11.00930536) * PhysConst::m_u, + PhysConst::m_p * amrex::Real(10.9298), amrex::Real(5) * PhysConst::q_e}}, {PhysicalSpecies::carbon, Properties{ amrex::Real(12.0106) * PhysConst::m_u, From 5c31035884b82b5b85ad2c1705576968decc704c Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 21 Jun 2022 05:32:39 -0700 Subject: [PATCH 41/63] Revert "Fixed proton-boron test" This reverts commit 73c8d9d0be8417d5cd08a23daeebbc322c984808. --- Source/Particles/SpeciesPhysicalProperties.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Particles/SpeciesPhysicalProperties.cpp b/Source/Particles/SpeciesPhysicalProperties.cpp index 13432bf99b3..8086b14bd29 100644 --- a/Source/Particles/SpeciesPhysicalProperties.cpp +++ b/Source/Particles/SpeciesPhysicalProperties.cpp @@ -169,7 +169,7 @@ namespace { amrex::Real(3.0160492779) * PhysConst::m_u, amrex::Real(1) * PhysConst::q_e}}, {PhysicalSpecies::helium, Properties{ - PhysConst::m_p * amrex::Real(3.97369), + amrex::Real(4.002602) * PhysConst::m_u, amrex::Real(2) * PhysConst::q_e}}, {PhysicalSpecies::helium3, Properties{ amrex::Real(3.0160293201) * PhysConst::m_u, @@ -202,7 +202,7 @@ namespace { amrex::Real(10.01293695) * PhysConst::m_u, amrex::Real(5) * PhysConst::q_e}}, {PhysicalSpecies::boron11, Properties{ - PhysConst::m_p * amrex::Real(10.9298), + amrex::Real(11.00930536) * PhysConst::m_u, amrex::Real(5) * PhysConst::q_e}}, {PhysicalSpecies::carbon, Properties{ amrex::Real(12.0106) * PhysConst::m_u, From 542d2cbcc0ab4b0899f93716376fb7ca00daf03c Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 5 Jul 2022 05:52:30 -0700 Subject: [PATCH 42/63] Incorporate Neil's recommendations --- .../Modules/nuclear_fusion/analysis_proton_boron_fusion.py | 6 +++--- Examples/Modules/nuclear_fusion/inputs_3d | 2 +- .../NuclearFusion/ProtonBoronFusionInitializeMomentum.H | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/analysis_proton_boron_fusion.py b/Examples/Modules/nuclear_fusion/analysis_proton_boron_fusion.py index 140c281cc7b..37b680deea1 100755 --- a/Examples/Modules/nuclear_fusion/analysis_proton_boron_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_proton_boron_fusion.py @@ -66,9 +66,9 @@ MeV_to_Joule = scc.e*1e6 barn_to_square_meter = 1.e-28 m_p = scc.m_p # Proton mass -m_b = 10.9298*m_p # Boron 11 mass +m_b = 11.00930536*scc.m_u # Boron 11 mass m_reduced = m_p*m_b/(m_p+m_b) -m_a = 3.97369*m_p # Alpha mass +m_a = 4.002602*scc.m_u # Alpha mass m_be = 7.94748*m_p # Beryllium 8 mass Z_boron = 5. Z_proton = 1. @@ -381,7 +381,7 @@ def p_sq_boron_frame_to_E_COM_frame(p_proton_sq): E_com = np.sqrt(E_lab**2 - p_proton_sq*scc.c**2) # Corresponding kinetic energy E_com_kin = E_com - (m_b+scc.m_p)*scc.c**2 - return E_com_kin + return E_com_kin*(p_proton_sq>0.) def p_sq_to_kinetic_energy(p_sq, m): ## Returns the kinetic energy of a particle as a function of its squared momentum. diff --git a/Examples/Modules/nuclear_fusion/inputs_3d b/Examples/Modules/nuclear_fusion/inputs_3d index 910729edc3b..73f0d52a523 100644 --- a/Examples/Modules/nuclear_fusion/inputs_3d +++ b/Examples/Modules/nuclear_fusion/inputs_3d @@ -32,7 +32,7 @@ algo.particle_shape = 1 particles.species_names = proton1 boron1 alpha1 proton2 boron2 alpha2 proton3 boron3 alpha3 proton4 boron4 alpha4 proton5 boron5 alpha5 -my_constants.m_b11 = 10.9298*m_p # Boron 11 mass +my_constants.m_b11 = 11.00930536*m_u # Boron 11 mass my_constants.m_reduced = m_p*m_b11/(m_p+m_b11) my_constants.keV_to_J = 1.e3*q_e my_constants.Energy_step = 22. * keV_to_J diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H index 9a63874fddb..085fc597f58 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/ProtonBoronFusionInitializeMomentum.H @@ -81,7 +81,7 @@ namespace { // which can cause compilation to fail or generate a warning, so we're explicitly setting // them as double. Note that nuclear fusion module does not currently work with single // precision anyways. - constexpr double m_alpha = PhysConst::m_p * 3.97369_prt; + constexpr double m_alpha = PhysConst::m_u * 4.002602_prt; constexpr double m_beryllium = PhysConst::m_p * 7.94748_prt; constexpr double mBe_sq = m_beryllium*m_beryllium; constexpr amrex::ParticleReal c_sq = PhysConst::c * PhysConst::c; From b228c29fbcae6ee13a65ea78098886b2c4ee01ae Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 5 Jul 2022 13:10:52 -0700 Subject: [PATCH 43/63] Reset benchmarks --- .../benchmarks_json/LaserIonAcc2d.json | 32 +++---- .../PlasmaAccelerationBoost2d.json | 32 +++---- .../Proton_Boron_Fusion_3D.json | 80 ++++++++--------- .../benchmarks_json/background_mcc.json | 24 ++--- .../background_mcc_dp_psp.json | 24 ++--- .../benchmarks_json/embedded_circle.json | 36 ++++---- .../benchmarks_json/multi_J_2d_psatd.json | 86 +++++------------- .../benchmarks_json/multi_J_2d_psatd_pml.json | 88 +++++-------------- 8 files changed, 158 insertions(+), 244 deletions(-) diff --git a/Regression/Checksum/benchmarks_json/LaserIonAcc2d.json b/Regression/Checksum/benchmarks_json/LaserIonAcc2d.json index a092c777f5b..a276d6032a1 100644 --- a/Regression/Checksum/benchmarks_json/LaserIonAcc2d.json +++ b/Regression/Checksum/benchmarks_json/LaserIonAcc2d.json @@ -2,37 +2,37 @@ "electrons": { "particle_cpu": 0.0, "particle_id": 2101654260.0, - "particle_momentum_x": 3.8190076010374515e-19, + "particle_momentum_x": 3.819011093562328e-19, "particle_momentum_y": 0.0, - "particle_momentum_z": 1.6442919198257052e-18, - "particle_position_x": 0.008132686110435036, - "particle_position_y": 0.030529759951728817, + "particle_momentum_z": 1.6442909854275157e-18, + "particle_position_x": 0.008132686101590795, + "particle_position_y": 0.030529760810180325, "particle_weight": 2.641331189632942e+17 }, "hydrogen": { "particle_cpu": 0.0, "particle_id": 8663540542.0, - "particle_momentum_x": 2.2442930534191287e-18, + "particle_momentum_x": 2.2442952799834144e-18, "particle_momentum_y": 0.0, - "particle_momentum_z": 1.084110863159823e-18, + "particle_momentum_z": 1.0841140295639398e-18, "particle_orig_x": 0.008258544921875001, "particle_orig_z": 0.0366896337890625, - "particle_position_x": 0.008258183385255663, - "particle_position_y": 0.03668783554837751, + "particle_position_x": 0.008258183633694481, + "particle_position_y": 0.036687836783915156, "particle_weight": 2.701906737218416e+17 }, "lev=0": { "Bx": 0.0, - "By": 11393535.73084639, + "By": 11393530.864665572, "Bz": 0.0, - "Ex": 2033400430027297.5, + "Ex": 2033401599040428.8, "Ey": 0.0, - "Ez": 316047261967858.8, - "jx": 1.6346708093212e+19, + "Ez": 316047997346965.6, + "jx": 1.634666300264935e+19, "jy": 0.0, - "jz": 8.884557829033169e+18, - "rho": 61729754469.05863, - "rho_electrons": 17451988254912.61, - "rho_hydrogen": 17441820007044.357 + "jz": 8.884561198935773e+18, + "rho": 61730016945.00626, + "rho_electrons": 17451988195798.281, + "rho_hydrogen": 17441819816491.93 } } \ No newline at end of file diff --git a/Regression/Checksum/benchmarks_json/PlasmaAccelerationBoost2d.json b/Regression/Checksum/benchmarks_json/PlasmaAccelerationBoost2d.json index 89d62990447..5b99c69ce5b 100644 --- a/Regression/Checksum/benchmarks_json/PlasmaAccelerationBoost2d.json +++ b/Regression/Checksum/benchmarks_json/PlasmaAccelerationBoost2d.json @@ -20,21 +20,21 @@ "particle_weight": 93622636116911.45 }, "lev=0": { - "Bx": 0.3939499531816347, - "By": 9563.615022656986, - "Bz": 0.3591030695780064, - "Ex": 1057402535431.5992, - "Ey": 144244335.4692135, - "Ez": 3010491709181.335, - "jx": 3227914399.2203197, - "jy": 5068791609.127958, - "jz": 102420312561236.62 + "Bx": 0.3939499531816364, + "By": 9563.615022656964, + "Bz": 0.3591030695780125, + "Ex": 1057402535431.6746, + "Ey": 144244335.46922195, + "Ez": 3010491709181.3467, + "jx": 3227914369.7171793, + "jy": 5068791609.12788, + "jz": 102420312561226.17 }, "plasma_e": { "particle_cpu": 504.0, "particle_id": 236124.0, - "particle_momentum_x": 1.2615128163446419e-23, - "particle_momentum_y": 1.5392234050947253e-27, + "particle_momentum_x": 1.2615128163589931e-23, + "particle_momentum_y": 1.5392234051130659e-27, "particle_momentum_z": 1.3694904132251956e-18, "particle_position_x": 0.01771877489382093, "particle_position_y": 0.020620065534187347, @@ -43,11 +43,11 @@ "plasma_p": { "particle_cpu": 504.0, "particle_id": 272412.0, - "particle_momentum_x": 1.2615099271970135e-23, - "particle_momentum_y": 1.5392492676794249e-27, - "particle_momentum_z": 2.514586739414616e-15, - "particle_position_x": 0.017718749986442184, - "particle_position_y": 0.02062006546318014, + "particle_momentum_x": 1.2615099272124483e-23, + "particle_momentum_y": 1.53924926768808e-27, + "particle_momentum_z": 2.51631809113383e-15, + "particle_position_x": 0.017718749986451513, + "particle_position_y": 0.020620065463180168, "particle_weight": 727797380314273.1 } } \ No newline at end of file diff --git a/Regression/Checksum/benchmarks_json/Proton_Boron_Fusion_3D.json b/Regression/Checksum/benchmarks_json/Proton_Boron_Fusion_3D.json index 32e2da2bc94..e63a64a2703 100644 --- a/Regression/Checksum/benchmarks_json/Proton_Boron_Fusion_3D.json +++ b/Regression/Checksum/benchmarks_json/Proton_Boron_Fusion_3D.json @@ -2,43 +2,43 @@ "alpha1": { "particle_cpu": 60780.0, "particle_id": 1351279015596.0, - "particle_momentum_x": 4.659632892446219e-15, - "particle_momentum_y": 4.617309311289228e-15, - "particle_momentum_z": 4.617390264429112e-15, + "particle_momentum_x": 4.659631949650719e-15, + "particle_momentum_y": 4.617308377231923e-15, + "particle_momentum_z": 4.617389330519975e-15, "particle_position_x": 453219.3436004627, - "particle_position_y": 457393.4211433249, + "particle_position_y": 457393.42114332493, "particle_position_z": 970481.0580153911, - "particle_weight": 1.904380063679924e-27 + "particle_weight": 1.9043802455895325e-27 }, "alpha2": { "particle_cpu": 54528.0, "particle_id": 1211463810981.0, - "particle_momentum_x": 4.071679285778659e-15, - "particle_momentum_y": 4.119641921839256e-15, - "particle_momentum_z": 4.181785619797154e-15, + "particle_momentum_x": 4.071678402460901e-15, + "particle_momentum_y": 4.1196410276880726e-15, + "particle_momentum_z": 4.181784710058622e-15, "particle_position_x": 405848.1200755021, - "particle_position_y": 408011.5319128882, + "particle_position_y": 408011.53191288817, "particle_position_z": 866330.5923068221, - "particle_weight": 1.926173353413784e+19 + "particle_weight": 1.9261737121655108e+19 }, "alpha3": { "particle_cpu": 6252.0, "particle_id": 153642773313.0, - "particle_momentum_x": 4.853583107582054e-16, - "particle_momentum_y": 4.797298533911113e-16, - "particle_momentum_z": 4.759502498651132e-16, + "particle_momentum_x": 4.853582081563116e-16, + "particle_momentum_y": 4.797297548379446e-16, + "particle_momentum_z": 4.759501504671248e-16, "particle_position_x": 51342.57223394147, "particle_position_y": 50913.6612890173, - "particle_position_z": 101306.340590083, - "particle_weight": 1.036014694926736e+28 + "particle_position_z": 101306.34059008301, + "particle_weight": 1.0360147595748265e+28 }, "alpha4": { "particle_cpu": 307200.0, "particle_id": 7431218688000.0, - "particle_momentum_x": 2.337391296198344e-14, - "particle_momentum_y": 2.343942459367338e-14, - "particle_momentum_z": 2.355941676163024e-14, - "particle_position_x": 2457367.458278153, + "particle_momentum_x": 2.3373908106523292e-14, + "particle_momentum_y": 2.3439419725501755e-14, + "particle_momentum_z": 2.3559411845892612e-14, + "particle_position_x": 2457367.4582781526, "particle_position_y": 2457512.044373058, "particle_position_z": 4914475.776513073, "particle_weight": 3072.000000000002 @@ -46,11 +46,11 @@ "alpha5": { "particle_cpu": 307200.0, "particle_id": 7619962368000.0, - "particle_momentum_x": 2.333624736682437e-14, - "particle_momentum_y": 2.345594456920183e-14, - "particle_momentum_z": 2.357453114426799e-14, + "particle_momentum_x": 2.333624251961068e-14, + "particle_momentum_y": 2.3455939695798916e-14, + "particle_momentum_z": 2.3574526216382372e-14, "particle_position_x": 2457556.857163842, - "particle_position_y": 2457059.635379324, + "particle_position_y": 2457059.6353793237, "particle_position_z": 4915847.043341331, "particle_weight": 3.0719999999999984e-18 }, @@ -59,7 +59,7 @@ "particle_id": 78643205120000.0, "particle_momentum_x": 0.0, "particle_momentum_y": 0.0, - "particle_momentum_z": 2.524243076150406e-13, + "particle_momentum_z": 2.524242836246531e-13, "particle_position_x": 40958301.591654316, "particle_position_y": 40961136.14476712, "particle_position_z": 81920546.19181262, @@ -74,18 +74,18 @@ "particle_position_x": 409798.0158217681, "particle_position_y": 409670.9858143465, "particle_position_z": 819255.8152412223, - "particle_weight": 1.0239999999360338e+29 + "particle_weight": 1.0239999999357942e+29 }, "boron3": { "particle_cpu": 512000.0, "particle_id": 11639194112000.0, - "particle_momentum_x": 9.277703190700158e-15, - "particle_momentum_y": 9.268420145552847e-15, - "particle_momentum_z": 9.279457128810487e-15, - "particle_position_x": 4096178.166422465, - "particle_position_y": 4096499.706038672, + "particle_momentum_x": 9.277692671587846e-15, + "particle_momentum_y": 9.268409636965691e-15, + "particle_momentum_z": 9.279446607709548e-15, + "particle_position_x": 4096178.1664224654, + "particle_position_y": 4096499.7060386725, "particle_position_z": 8191465.586938233, - "particle_weight": 5.119654661768357e+31 + "particle_weight": 5.119654661746806e+31 }, "boron5": { "particle_cpu": 51200.0, @@ -93,7 +93,7 @@ "particle_momentum_x": 0.0, "particle_momentum_y": 0.0, "particle_momentum_z": 0.0, - "particle_position_x": 409547.3312927569, + "particle_position_x": 409547.33129275695, "particle_position_y": 409518.5558814353, "particle_position_z": 819306.5006950963, "particle_weight": 1023.9999999999999 @@ -106,7 +106,7 @@ "particle_id": 26214405120000.0, "particle_momentum_x": 0.0, "particle_momentum_y": 0.0, - "particle_momentum_z": 2.524243076150406e-13, + "particle_momentum_z": 2.524242836246531e-13, "particle_position_x": 40960140.72983793, "particle_position_y": 40959772.69310104, "particle_position_z": 81919021.52308556, @@ -121,18 +121,18 @@ "particle_position_x": 4095630.698135355, "particle_position_y": 4096073.5517983637, "particle_position_z": 8191737.5566503005, - "particle_weight": 1.022781024071589e+29 + "particle_weight": 1.0227810240713489e+29 }, "proton3": { "particle_cpu": 307181.0, "particle_id": 6731321892958.0, - "particle_momentum_x": 1.684351051519872e-15, - "particle_momentum_y": 1.682381896868337e-15, - "particle_momentum_z": 1.679996145653965e-15, + "particle_momentum_x": 1.6843510515198723e-15, + "particle_momentum_y": 1.6823818968683368e-15, + "particle_momentum_z": 1.6799961456539653e-15, "particle_position_x": 2457338.899376694, "particle_position_y": 2457069.647393952, "particle_position_z": 4914642.288898885, - "particle_weight": 1.023654661768358e+31 + "particle_weight": 1.0236546617468092e+31 }, "proton4": { "particle_cpu": 51200.0, @@ -151,8 +151,8 @@ "particle_momentum_x": 0.0, "particle_momentum_y": 0.0, "particle_momentum_z": 1.7581275870306353e-15, - "particle_position_x": 409638.287761857, - "particle_position_y": 409501.3225783394, + "particle_position_x": 409638.28776185703, + "particle_position_y": 409501.32257833943, "particle_position_z": 819309.1804186807, "particle_weight": 1.0240000000000003e+38 } diff --git a/Regression/Checksum/benchmarks_json/background_mcc.json b/Regression/Checksum/benchmarks_json/background_mcc.json index af6475b6a44..28480ffe4a2 100644 --- a/Regression/Checksum/benchmarks_json/background_mcc.json +++ b/Regression/Checksum/benchmarks_json/background_mcc.json @@ -2,25 +2,25 @@ "electrons": { "particle_cpu": 187518.0, "particle_id": 58269281905.0, - "particle_momentum_x": 1.011638818579948e-18, - "particle_momentum_y": 2.819742987610991e-19, - "particle_momentum_z": 2.809194032686416e-19, - "particle_position_x": 17136.0186544969, - "particle_position_y": 936.3651769904283, + "particle_momentum_x": 1.0116388186647586e-18, + "particle_momentum_y": 2.8197429874443205e-19, + "particle_momentum_z": 2.809194032519318e-19, + "particle_position_x": 17136.01865460215, + "particle_position_y": 936.3651769897449, "particle_weight": 61113170379.63868 }, "he_ions": { "particle_cpu": 262836.0, "particle_id": 206754755365.0, - "particle_momentum_x": 2.883077691926682e-18, - "particle_momentum_y": 2.195706192591097e-18, - "particle_momentum_z": 2.198217877500162e-18, - "particle_position_x": 17607.42545807472, - "particle_position_y": 1100.024786059285, + "particle_momentum_x": 2.8830766335132965e-18, + "particle_momentum_y": 2.1957048705835945e-18, + "particle_momentum_z": 2.198216553980008e-18, + "particle_position_x": 17607.425457521826, + "particle_position_y": 1100.0247860591508, "particle_weight": 71976747650.1465 }, "lev=0": { - "rho_electrons": 0.03566284217155322, - "rho_he_ions": 0.04192588072776678 + "rho_electrons": 0.035662842171864814, + "rho_he_ions": 0.041925880726395526 } } \ No newline at end of file diff --git a/Regression/Checksum/benchmarks_json/background_mcc_dp_psp.json b/Regression/Checksum/benchmarks_json/background_mcc_dp_psp.json index 4b779e655bc..aec36e4c5be 100644 --- a/Regression/Checksum/benchmarks_json/background_mcc_dp_psp.json +++ b/Regression/Checksum/benchmarks_json/background_mcc_dp_psp.json @@ -2,25 +2,25 @@ "electrons": { "particle_cpu": 187506.0, "particle_id": 58260371529.0, - "particle_momentum_x": 1.011437761051452e-18, - "particle_momentum_y": 2.818489820307945e-19, - "particle_momentum_z": 2.810005779603514e-19, - "particle_position_x": 17134.12316775415, - "particle_position_y": 935.6698541530053, + "particle_momentum_x": 1.0114377612798924e-18, + "particle_momentum_y": 2.8184898200776714e-19, + "particle_momentum_z": 2.810005779758007e-19, + "particle_position_x": 17134.123168296646, + "particle_position_y": 935.6698541620412, "particle_weight": 61112621534.71875 }, "he_ions": { "particle_cpu": 262803.0, "particle_id": 206741084466.0, - "particle_momentum_x": 2.882594194576035e-18, - "particle_momentum_y": 2.19602229398326e-18, - "particle_momentum_z": 2.198235662538558e-18, - "particle_position_x": 17605.83295227928, - "particle_position_y": 1099.980517380142, + "particle_momentum_x": 2.8825928770053435e-18, + "particle_momentum_y": 2.1960207748059422e-18, + "particle_momentum_z": 2.1982341415215343e-18, + "particle_position_x": 17605.83295166959, + "particle_position_y": 1099.9805173814, "particle_weight": 71973184795.40625 }, "lev=0": { - "rho_electrons": 0.03566096918916276, - "rho_he_ions": 0.04192386049475352 + "rho_electrons": 0.03566096918517184, + "rho_he_ions": 0.04192386049381602 } } \ No newline at end of file diff --git a/Regression/Checksum/benchmarks_json/embedded_circle.json b/Regression/Checksum/benchmarks_json/embedded_circle.json index 6bb0faa05ff..d17fb86e6be 100644 --- a/Regression/Checksum/benchmarks_json/embedded_circle.json +++ b/Regression/Checksum/benchmarks_json/embedded_circle.json @@ -1,27 +1,27 @@ { "ar_ions": { "particle_cpu": 31743.0, - "particle_id": 3219974926.0, - "particle_momentum_x": 2.673080656628151e-18, - "particle_momentum_y": 2.6734826129917346e-18, - "particle_momentum_z": 2.6677137825404595e-18, - "particle_position_x": 3.174244144020173, - "particle_position_y": 3.1742742523212426, - "particle_weight": 988078308.1054688 + "particle_id": 3219840760.0, + "particle_momentum_x": 2.656937628868437e-18, + "particle_momentum_y": 2.6462397149880108e-18, + "particle_momentum_z": 2.653197184723758e-18, + "particle_position_x": 3.174140583032092, + "particle_position_y": 3.174226960143397, + "particle_weight": 988047180.1757812 }, "electrons": { - "particle_cpu": 30723.0, - "particle_id": 1040042009.0, - "particle_momentum_x": 2.99271246971674e-20, - "particle_momentum_y": 3.014893117483374e-20, - "particle_momentum_z": 3.016015662279529e-20, - "particle_position_x": 3.072306870914145, - "particle_position_y": 3.072501289015288, - "particle_weight": 956421203.6132812 + "particle_cpu": 30736.0, + "particle_id": 1041926893.0, + "particle_momentum_x": 3.017862149732503e-20, + "particle_momentum_y": 3.016284742627221e-20, + "particle_momentum_z": 3.026716864845998e-20, + "particle_position_x": 3.077259990879374, + "particle_position_y": 3.0760809372537063, + "particle_weight": 957635192.8710938 }, "lev=0": { - "phi": 56898.115832092146, - "rho_ar_ions": 257.8023434408326, - "rho_electrons": 250.15834020610757 + "phi": 56891.444043840616, + "rho_ar_ions": 257.79395973399653, + "rho_electrons": 250.42393788893844 } } \ No newline at end of file diff --git a/Regression/Checksum/benchmarks_json/multi_J_2d_psatd.json b/Regression/Checksum/benchmarks_json/multi_J_2d_psatd.json index fba2944de70..b205ebce78b 100644 --- a/Regression/Checksum/benchmarks_json/multi_J_2d_psatd.json +++ b/Regression/Checksum/benchmarks_json/multi_J_2d_psatd.json @@ -2,92 +2,50 @@ "driver": { "particle_cpu": 0.0, "particle_id": 5000050000.0, -<<<<<<< HEAD - "particle_momentum_x": 1.4539940634099901e-16, + "particle_momentum_x": 1.4539941020025028e-16, "particle_momentum_y": 0.0, - "particle_momentum_z": 9.822790382172482e-09, - "particle_position_x": 0.40000376722750486, -======= - "particle_momentum_x": 1.4539950862665395e-16, - "particle_momentum_y": 0.0, - "particle_momentum_z": 9.822790382172455e-09, - "particle_position_x": 0.40000376722743924, ->>>>>>> development + "particle_momentum_z": 9.822790382172444e-09, + "particle_position_x": 0.4000037672275025, "particle_position_y": 30.100865423602578, "particle_weight": 124830181489215.27 }, "lev=0": { "Bx": 0.0, -<<<<<<< HEAD - "By": 923881.627616788, - "Bz": 0.0, - "Ex": 271447156686106.3, - "Ey": 0.0, - "Ez": 93015806626847.92, - "F": 6524.75796370838, - "G": 0.0, - "divE": 2.5113652133379535e+19, - "jx": 1.0071954084855112e+16, - "jy": 0.0, - "jz": 6.4315500079457544e+16, - "rho": 220510584.78675658, - "rho_driver": 2562225.119933119, - "rho_driver_back": 0.0, - "rho_plasma_e": 1359622972.6072302, - "rho_plasma_p": 1361225477.6776037 -======= - "By": 923872.859945843, + "By": 923873.3689884299, "Bz": 0.0, - "Ex": 271445847158043.47, + "Ex": 271445959245867.38, "Ey": 0.0, - "Ez": 93017427963875.12, - "F": 6525.367402828258, + "Ez": 93017410300609.08, + "F": 6525.329585276354, "G": 0.0, - "divE": 2.511375187843704e+19, - "jx": 1.007185165524125e+16, + "divE": 2.511377423363695e+19, + "jx": 1.0071853348781318e+16, "jy": 0.0, - "jz": 6.431576337481891e+16, - "rho": 220511207.32501236, - "rho_driver": 2562225.119933119, + "jz": 6.431583372170538e+16, + "rho": 220511427.01289138, + "rho_driver": 2562225.119933118, "rho_driver_back": 0.0, - "rho_plasma_e": 1359622971.7373238, - "rho_plasma_p": 1361225480.346084 ->>>>>>> development + "rho_plasma_e": 1359622970.398378, + "rho_plasma_p": 1361225477.7925916 }, "plasma_e": { "particle_cpu": 29652.0, "particle_id": 1194907032.0, -<<<<<<< HEAD - "particle_momentum_x": 7.245362943456111e-19, + "particle_momentum_x": 7.24535866217633e-19, "particle_momentum_y": 0.0, - "particle_momentum_z": 2.3479175722902974e-17, - "particle_position_x": 1.3924196999819647, - "particle_position_y": 10.079133709990238, -======= - "particle_momentum_x": 7.245349306901261e-19, - "particle_momentum_y": 0.0, - "particle_momentum_z": 2.3479179887756406e-17, - "particle_position_x": 1.392419539654138, - "particle_position_y": 10.079133897885754, ->>>>>>> development + "particle_momentum_z": 2.3479181521728354e-17, + "particle_position_x": 1.3924195384912583, + "particle_position_y": 10.079133954833015, "particle_weight": 6.643024495443786e+16 }, "plasma_p": { "particle_cpu": 29696.0, "particle_id": 1202173888.0, -<<<<<<< HEAD - "particle_momentum_x": 1.4515027408919092e-18, - "particle_momentum_y": 0.0, - "particle_momentum_z": 4.008583335222013e-14, - "particle_position_x": 1.345647984351348, - "particle_position_y": 10.082154763152218, -======= - "particle_momentum_x": 1.451501915278136e-18, + "particle_momentum_x": 1.4515031430944076e-18, "particle_momentum_y": 0.0, - "particle_momentum_z": 4.005705789406174e-14, - "particle_position_x": 1.345648018905137, - "particle_position_y": 10.08215472964829, ->>>>>>> development + "particle_momentum_z": 4.0084640226979506e-14, + "particle_position_x": 1.3456479857933001, + "particle_position_y": 10.082154761668846, "particle_weight": 6.652881944445523e+16 } } \ No newline at end of file diff --git a/Regression/Checksum/benchmarks_json/multi_J_2d_psatd_pml.json b/Regression/Checksum/benchmarks_json/multi_J_2d_psatd_pml.json index 4f52a90844a..02ffb91077e 100644 --- a/Regression/Checksum/benchmarks_json/multi_J_2d_psatd_pml.json +++ b/Regression/Checksum/benchmarks_json/multi_J_2d_psatd_pml.json @@ -2,94 +2,50 @@ "driver": { "particle_cpu": 0.0, "particle_id": 5000050000.0, -<<<<<<< HEAD - "particle_momentum_x": 1.4499925126853143e-16, + "particle_momentum_x": 1.4499925060974604e-16, "particle_momentum_y": 0.0, - "particle_momentum_z": 9.82279038230043e-09, - "particle_position_x": 0.4000037675727584, -======= - "particle_momentum_x": 1.449993483262996e-16, - "particle_momentum_y": 0.0, - "particle_momentum_z": 9.822790382300402e-09, - "particle_position_x": 0.400003767572696, ->>>>>>> development + "particle_momentum_z": 9.82279038230039e-09, + "particle_position_x": 0.4000037675727589, "particle_position_y": 30.100865423602578, "particle_weight": 124830181489215.27 }, "lev=0": { "Bx": 0.0, -<<<<<<< HEAD - "By": 921660.8763744916, - "Bz": 0.0, - "Ex": 270876488518506.03, - "Ey": 0.0, - "Ez": 92624928893088.9, - "F": 6183.05541122242, - "G": 0.0, - "divE": 2.5190220275534684e+19, - "jx": 1.0172820267112668e+16, - "jy": 0.0, - "jz": 6.3852803420999176e+16, - "rho": 220331907.1018316, - "rho_driver": 2562225.119933118, - "rho_driver_back": 0.0, - "rho_plasma_e": 1359499348.8917723, - "rho_plasma_p": 1361225457.8189807 - }, - "plasma_e": { - "particle_cpu": 29647.0, - "particle_id": 1194856401.0, - "particle_momentum_x": 7.187013750906501e-19, - "particle_momentum_y": 0.0, - "particle_momentum_z": 2.3464972335833197e-17, - "particle_position_x": 1.3919451689822666, - "particle_position_y": 10.076815904733323, - "particle_weight": 6.641904330784497e+16 -======= - "By": 921659.2047215957, + "By": 921659.7003424203, "Bz": 0.0, - "Ex": 270877084380906.22, + "Ex": 270877199432990.72, "Ey": 0.0, - "Ez": 92626603051693.27, - "F": 6184.06416309773, + "Ez": 92626589083860.39, + "F": 6184.029984601904, "G": 0.0, - "divE": 2.519002692443211e+19, - "jx": 1.0172599655812156e+16, + "divE": 2.519005022753751e+19, + "jx": 1.0172600337490698e+16, "jy": 0.0, - "jz": 6.385227447336726e+16, - "rho": 220316369.1396134, - "rho_driver": 2562225.119933118, + "jz": 6.3852340601837256e+16, + "rho": 220316594.2695177, + "rho_driver": 2562225.1199331186, "rho_driver_back": 0.0, - "rho_plasma_e": 1359476241.7588131, - "rho_plasma_p": 1361225460.3717313 + "rho_plasma_e": 1359476240.39297, + "rho_plasma_p": 1361225457.832027 }, "plasma_e": { "particle_cpu": 29646.0, "particle_id": 1194846491.0, - "particle_momentum_x": 7.183638384394021e-19, + "particle_momentum_x": 7.183647425698553e-19, "particle_momentum_y": 0.0, - "particle_momentum_z": 2.346425019530925e-17, - "particle_position_x": 1.391891175298253, - "particle_position_y": 10.07633717300163, + "particle_momentum_z": 2.3464251836665685e-17, + "particle_position_x": 1.3918911743233844, + "particle_position_y": 10.076337229777174, "particle_weight": 6.641680297852639e+16 ->>>>>>> development }, "plasma_p": { "particle_cpu": 29696.0, "particle_id": 1202173888.0, -<<<<<<< HEAD - "particle_momentum_x": 1.4494696265263356e-18, - "particle_momentum_y": 0.0, - "particle_momentum_z": 4.0084654499150134e-14, - "particle_position_x": 1.3456480355301481, - "particle_position_y": 10.08215483152446, -======= - "particle_momentum_x": 1.4494632574716746e-18, + "particle_momentum_x": 1.4494644790319828e-18, "particle_momentum_y": 0.0, - "particle_momentum_z": 4.0057072158337995e-14, - "particle_position_x": 1.3456480684446548, - "particle_position_y": 10.082154799435534, ->>>>>>> development + "particle_momentum_z": 4.008465449121937e-14, + "particle_position_x": 1.3456480352993405, + "particle_position_y": 10.082154831407932, "particle_weight": 6.652881944445523e+16 } } \ No newline at end of file From 665451f3505693ee33a316311fd4d4157e849115 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 5 Jul 2022 14:45:46 -0700 Subject: [PATCH 44/63] Correct compilation errors --- .../NuclearFusion/TwoProductFusionUtil.H | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionUtil.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionUtil.H index cbc380b9b7f..a440109d0b9 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionUtil.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionUtil.H @@ -92,11 +92,7 @@ namespace { pow2(p1y_in+p2y_in) + pow2(p1z_in+p2z_in); -<<<<<<< HEAD - // Total energy of incident species in the lab frame -======= // Total energy of incident macroparticles in the lab frame ->>>>>>> improve_SpeciesPhysicalProperties const amrex::ParticleReal E_lab = (m1_in * g1_in + m2_in * g2_in) * c_sq; // Total energy squared of proton+boron in the center of mass frame, calculated using the // Lorentz invariance of the four-momentum norm @@ -132,11 +128,7 @@ namespace { const amrex::ParticleReal vcz = (p1z_in+p2z_in) / mass_g; const amrex::ParticleReal vc_sq = vcx*vcx + vcy*vcy + vcz*vcz; -<<<<<<< HEAD - // Convert momentum of first alpha to lab frame, using equation (13) of F. Perez et al., -======= // Convert momentum of first product to lab frame, using equation (13) of F. Perez et al., ->>>>>>> improve_SpeciesPhysicalProperties // Phys.Plasmas.19.083104 (2012) if ( vc_sq > std::numeric_limits::min() ) { @@ -161,11 +153,7 @@ namespace { const amrex::ParticleReal p2y_out = p1y_in + p2y_in - p1y_out; const amrex::ParticleReal p2z_out = p1z_in + p2z_in - p1z_out; -<<<<<<< HEAD - // Compute the momentum of the product species -======= // Compute the momentum of the product macroparticles ->>>>>>> improve_SpeciesPhysicalProperties u1x_out = p1x_out/m1_out; u1y_out = p1y_out/m1_out; u1z_out = p1z_out/m1_out; From 284f37062729e4fa80bc6b2b4345b02e4ebb96b8 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Mon, 11 Jul 2022 01:05:58 -0700 Subject: [PATCH 45/63] Add new deuterium tritium automated test --- .../nuclear_fusion/inputs_deuterium_tritium | 90 +++++++++++++++++++ .../{inputs_3d => inputs_proton_boron} | 0 Regression/WarpX-tests.ini | 18 +++- 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 Examples/Modules/nuclear_fusion/inputs_deuterium_tritium rename Examples/Modules/nuclear_fusion/{inputs_3d => inputs_proton_boron} (100%) diff --git a/Examples/Modules/nuclear_fusion/inputs_deuterium_tritium b/Examples/Modules/nuclear_fusion/inputs_deuterium_tritium new file mode 100644 index 00000000000..ba4c88f6a8a --- /dev/null +++ b/Examples/Modules/nuclear_fusion/inputs_deuterium_tritium @@ -0,0 +1,90 @@ +################################# +####### GENERAL PARAMETERS ###### +################################# +## With these parameters, each cell has a size of exactly 1 by 1 by 1 +max_step = 1 +amr.n_cell = 8 8 16 +amr.max_grid_size = 8 +amr.blocking_factor = 8 +amr.max_level = 0 +geometry.dims = 3 +geometry.prob_lo = 0. 0. 0. +geometry.prob_hi = 8. 8. 16. + +################################# +###### Boundary Condition ####### +################################# +boundary.field_lo = periodic periodic periodic +boundary.field_hi = periodic periodic periodic + +################################# +############ NUMERICS ########### +################################# +warpx.verbose = 1 +warpx.cfl = 1.0 + +# Order of particle shape factors +algo.particle_shape = 1 + +################################# +############ PLASMA ############# +################################# +particles.species_names = deuterium1 tritium1 helium1 neutron1 + +my_constants.m_deuterium = 2.01410177812*m_u +my_constants.m_tritium = 3.0160492779*m_u +my_constants.m_reduced = m_deuterium*m_tritium/(m_deuterium+m_tritium) +my_constants.keV_to_J = 1.e3*q_e +my_constants.Energy_step = 22. * keV_to_J + +my_constants.background_dens = 1.e26 +my_constants.beam_dens = 1.e20 + +deuterium1.species_type = deuterium +deuterium1.injection_style = "NRandomPerCell" +deuterium1.num_particles_per_cell = 10000 +deuterium1.profile = constant +deuterium1.density = 1. +deuterium1.momentum_distribution_type = "parse_momentum_function" +deuterium1.momentum_function_ux(x,y,z) = 0. +deuterium1.momentum_function_uy(x,y,z) = 0. +## Thanks to the floor, all particles in the same cell have the exact same momentum +deuterium1.momentum_function_uz(x,y,z) = sqrt(2*m_reduced*Energy_step*(floor(z)**2))/(m_deuterium*clight) +deuterium1.do_not_push = 1 +deuterium1.do_not_deposit = 1 + +tritium1.species_type = tritium +tritium1.injection_style = "NRandomPerCell" +tritium1.num_particles_per_cell = 10000 +tritium1.profile = constant +tritium1.density = 1. +tritium1.momentum_distribution_type = "parse_momentum_function" +tritium1.momentum_function_ux(x,y,z) = 0. +tritium1.momentum_function_uy(x,y,z) = 0. +## Thanks to the floor, all particles in the same cell have the exact same momentum +tritium1.momentum_function_uz(x,y,z) = -sqrt(2*m_reduced*Energy_step*(floor(z)**2))/(m_tritium*clight) +tritium1.do_not_push = 1 +tritium1.do_not_deposit = 1 + +helium1.species_type = helium4 +helium1.do_not_push = 1 +helium1.do_not_deposit = 1 + +neutron1.species_type = neutron +neutron1.do_not_push = 1 +neutron1.do_not_deposit = 1 + +################################# +############ COLLISION ########## +################################# +collisions.collision_names = DTF1 +DTF1.species = deuterium1 tritium1 +DTF1.product_species = helium1 neutron1 +DTF1.type = nuclearfusion +DTF1.fusion_multiplier = 1.e50 + +# Diagnostics +diagnostics.diags_names = diag1 +diag1.intervals = 1 +diag1.diag_type = Full +diag1.fields_to_plot = rho diff --git a/Examples/Modules/nuclear_fusion/inputs_3d b/Examples/Modules/nuclear_fusion/inputs_proton_boron similarity index 100% rename from Examples/Modules/nuclear_fusion/inputs_3d rename to Examples/Modules/nuclear_fusion/inputs_proton_boron diff --git a/Regression/WarpX-tests.ini b/Regression/WarpX-tests.ini index 50d43bc5ce6..bd3c1ad0bb3 100644 --- a/Regression/WarpX-tests.ini +++ b/Regression/WarpX-tests.ini @@ -2170,7 +2170,7 @@ aux1File = Regression/PostProcessingUtils/post_processing_utils.py [Proton_Boron_Fusion_3D] buildDir = . -inputFile = Examples/Modules/nuclear_fusion/inputs_3d +inputFile = Examples/Modules/nuclear_fusion/inputs_proton_boron runtime_params = warpx.do_dynamic_scheduling=0 warpx.serialize_initial_conditions=1 dim = 3 addToCompileString = @@ -2184,6 +2184,22 @@ compileTest = 0 doVis = 0 analysisRoutine = Examples/Modules/nuclear_fusion/analysis_proton_boron_fusion.py +[Deuterium_Tritium_Fusion_3D] +buildDir = . +inputFile = Examples/Modules/nuclear_fusion/inputs_deuterium_tritium +runtime_params = warpx.do_dynamic_scheduling=0 warpx.serialize_initial_conditions=1 +dim = 3 +addToCompileString = +cmakeSetupOpts = -DWarpX_DIMS=3 +restartTest = 0 +useMPI = 1 +numprocs = 2 +useOMP = 1 +numthreads = 2 +compileTest = 0 +doVis = 0 +analysisRoutine = Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py + [Maxwell_Hybrid_QED_solver] buildDir = . inputFile = Examples/Tests/Maxwell_Hybrid_QED/inputs_2d From c3cff64b220f18400b1fe624f2c7c3cd7630ff16 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Mon, 11 Jul 2022 02:31:09 -0700 Subject: [PATCH 46/63] Correct formula of cross-section --- .../nuclear_fusion/inputs_deuterium_tritium | 49 +++++++++++++++++-- .../DeuteriumTritiumFusionCrossSection.H | 2 +- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/inputs_deuterium_tritium b/Examples/Modules/nuclear_fusion/inputs_deuterium_tritium index ba4c88f6a8a..9f5ce8b8bfc 100644 --- a/Examples/Modules/nuclear_fusion/inputs_deuterium_tritium +++ b/Examples/Modules/nuclear_fusion/inputs_deuterium_tritium @@ -29,7 +29,7 @@ algo.particle_shape = 1 ################################# ############ PLASMA ############# ################################# -particles.species_names = deuterium1 tritium1 helium1 neutron1 +particles.species_names = deuterium1 tritium1 helium1 neutron1 deuterium2 tritium2 helium2 neutron2 my_constants.m_deuterium = 2.01410177812*m_u my_constants.m_tritium = 3.0160492779*m_u @@ -37,9 +37,6 @@ my_constants.m_reduced = m_deuterium*m_tritium/(m_deuterium+m_tritium) my_constants.keV_to_J = 1.e3*q_e my_constants.Energy_step = 22. * keV_to_J -my_constants.background_dens = 1.e26 -my_constants.beam_dens = 1.e20 - deuterium1.species_type = deuterium deuterium1.injection_style = "NRandomPerCell" deuterium1.num_particles_per_cell = 10000 @@ -74,15 +71,57 @@ neutron1.species_type = neutron neutron1.do_not_push = 1 neutron1.do_not_deposit = 1 +my_constants.background_dens = 1.e26 +my_constants.beam_dens = 1.e20 + +deuterium2.species_type = deuterium +deuterium2.injection_style = "NRandomPerCell" +deuterium2.num_particles_per_cell = 1000 +deuterium2.profile = "parse_density_function" +## A tenth of the macroparticles in each cell is made of immobile high-density background deuteriums. +## The other nine tenths are made of fast low-density beam deuteriums. +deuterium2.density_function(x,y,z) = if(y - floor(y) < 0.1, 10.*background_dens, 10./9.*beam_dens) +deuterium2.momentum_distribution_type = "parse_momentum_function" +deuterium2.momentum_function_ux(x,y,z) = 0. +deuterium2.momentum_function_uy(x,y,z) = 0. +deuterium2.momentum_function_uz(x,y,z) = "if(y - floor(y) < 0.1, + 0., sqrt(2*m_p*Energy_step*(floor(z)**2))/(m_deuterium*clight))" +deuterium2.do_not_push = 1 +deuterium2.do_not_deposit = 1 + +tritium2.species_type = tritium +tritium2.injection_style = "NRandomPerCell" +tritium2.num_particles_per_cell = 100 +tritium2.profile = constant +tritium2.density = background_dens +tritium2.momentum_distribution_type = "constant" +tritium2.do_not_push = 1 +tritium2.do_not_deposit = 1 + +helium2.species_type = helium4 +helium2.do_not_push = 1 +helium2.do_not_deposit = 1 + +neutron2.species_type = neutron +neutron2.do_not_push = 1 +neutron2.do_not_deposit = 1 + ################################# ############ COLLISION ########## ################################# -collisions.collision_names = DTF1 +collisions.collision_names = DTF1 DTF2 + DTF1.species = deuterium1 tritium1 DTF1.product_species = helium1 neutron1 DTF1.type = nuclearfusion DTF1.fusion_multiplier = 1.e50 +DTF2.species = deuterium2 tritium2 +DTF2.product_species = helium2 neutron2 +DTF2.type = nuclearfusion +DTF2.fusion_multiplier = 1.e15 +DTF2.fusion_probability_target_value = 0.02 + # Diagnostics diagnostics.diags_names = diag1 diag1.intervals = 1 diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H index be3126cdfcf..587e1178437 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H @@ -37,7 +37,7 @@ amrex::ParticleReal DeuteriumTritiumFusionCrossSection (const amrex::ParticleRea constexpr amrex::ParticleReal m_D = 1.99901 * PhysConst::m_p; constexpr amrex::ParticleReal m_T = 2.99372 * PhysConst::m_p; constexpr amrex::ParticleReal m_reduced = m_D / (1._prt + m_D/m_T); - amrex::ParticleReal B_G = MathConst::pi * PhysConst::alpha * 2._prt * 3._prt + amrex::ParticleReal B_G = MathConst::pi * PhysConst::alpha * 1._prt * 1._prt * std::sqrt( 2._prt*m_reduced*PhysConst::c*PhysConst::c * joule_to_keV ); // Compute astrophysical_factor From 67d0ff1eed81fa6795002d3995aac48f7efda074 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Mon, 11 Jul 2022 02:41:30 -0700 Subject: [PATCH 47/63] Correct cross-section --- .../analysis_deuterium_tritium_fusion.py | 728 ++++++++++++++++++ .../DeuteriumTritiumFusionCrossSection.H | 4 +- 2 files changed, 730 insertions(+), 2 deletions(-) create mode 100755 Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py diff --git a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py new file mode 100755 index 00000000000..3d546e655b4 --- /dev/null +++ b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py @@ -0,0 +1,728 @@ +#! /usr/bin/env python +# Copyright 2021 Neil Zaim +# +# This file is part of WarpX. +# +# License: BSD-3-Clause-LBNL + +import os +import sys + +import yt + +sys.path.insert(1, '../../../../warpx/Regression/Checksum/') +import checksumAPI +import numpy as np +import scipy.constants as scc + +## This script performs various checks for the proton boron nuclear fusion module. The simulation +## that we check is made of 5 different tests, each with different proton, boron and alpha species. +## +## The first test is performed in the proton-boron center of mass frame. It could correspond to the +## physical case of a proton beam colliding with a boron beam. The kinetic energy of the colliding +## particles depends on the cell number in the z direction and varies in the few keV to few MeV +## range. All the particles within a cell have the exact same momentum, which allows detailed +## checks of the energy of produced alpha particles. The proton and boron species have the same +## density and number of particles in this test. The number of produced alphas is much smaller than +## the initial number of protons and borons. +## +## The second test is performed in the boron rest frame. It corresponds to the physical case of a +## low density proton beam colliding with a high-density proton+boron target. The energy of the +## proton beam is varied in the few keV to few MeV range, depending on the cell number in the z +## direction. As in the previous case, all the particles within a cell have the exact same +## momentum, which allows detailed checks of the energy of produced alpha particles. In this test, +## there are 100 immobile boron and 100 immobile proton macroparticles per cell, as well as 900 +## beam proton macroparticles per cell. The density of the immobile particles is 6 orders of +## magnitude higher than the number of beam particles, which means that they have a much higher +## weight. This test is similar to the example given in section 3 of Higginson et al., +## Journal of Computation Physics, 388 439–453 (2019), which was found to be sensitive to the way +## unsampled pairs are accounted for. As before, the number of produced alphas is much smaller than +## the initial number of protons and borons. +## +## The third test corresponds to a Maxwellian plasma with a 44 keV temperature. The alpha yield is +## directly compared to the analytical fits of W.M. Nevins and R. Swain, Nuclear Fusion, 40, 865 +## (2000) for a thermal plasma. +## +## The fourth test corresponds to a plasma with an extremely small boron density, so that all boron +## macroparticles should have disappeared by the end of the simulation, which we verify. +## +## The fifth test is exactly the same as the fourth test, except that the +## fusion_probability_threshold parameter is increased to an excessive value. Because of that, we +## severely underestimate the fusion yield and boron macroparticles remain at the end of the +## simulation, which we verify. +## +## In all simulations, we check particle number, charge, momentum and energy conservation and +## perform basic checks regarding the produced particles. When possible, we also compare the number +## of produced macroparticles, fusion yield and energy of the produced particles to theoretical +## values. +## +## Please be aware that the relative tolerances are often set empirically in this analysis script, +## so it would not be surprising that some tolerances need to be increased in the future. + +default_tol = 1.e-12 # Default relative tolerance + +## Define reactants and products +reactant_species = ['deuterium', 'tritium'] +product_species = ['helium', 'neutron'] + +## Some physical parameters +keV_to_Joule = scc.e*1e3 +MeV_to_Joule = scc.e*1e6 +barn_to_square_meter = 1.e-28 +m_p = scc.m_p # Proton mass +m_b = 11.00930536*scc.m_u # Boron 11 mass +m_reduced = m_p*m_b/(m_p+m_b) +m_a = 4.002602*scc.m_u # Alpha mass +m_be = 7.94748*m_p # Beryllium 8 mass +Z_boron = 5. +Z_proton = 1. +E_Gamow = (Z_boron*Z_proton*np.pi*scc.fine_structure)**2*2.*m_reduced*scc.c**2 +E_Gamow_MeV = E_Gamow/MeV_to_Joule +E_Gamow_keV = E_Gamow/keV_to_Joule +E_fusion = 8.59009*MeV_to_Joule # Energy released during p + B -> alpha + Be +E_decay = 0.0918984*MeV_to_Joule # Energy released during Be -> 2*alpha +E_fusion_total = E_fusion + E_decay # Energy released during p + B -> 3*alpha + +## Some numerical parameters for this test +size_x = 8 +size_y = 8 +size_z = 16 +dV_total = size_x*size_y*size_z # Total simulation volume +# Volume of a slice corresponding to a single cell in the z direction. In tests 1 and 2, all the +# particles of a given species in the same slice have the exact same momentum +dV_slice = size_x*size_y +dt = 1./(scc.c*np.sqrt(3.)) +# In test 1 and 2, the energy in cells number i (in z direction) is typically Energy_step * i**2 +Energy_step = 22.*keV_to_Joule + +def is_close(val1, val2, rtol=default_tol, atol=0.): + ## Wrapper around numpy.isclose, used to override the default tolerances. + return np.isclose(val1, val2, rtol=rtol, atol=atol) + +def add_existing_species_to_dict(yt_ad, data_dict, species_name, prefix, suffix): + data_dict[prefix+"_px_"+suffix] = yt_ad[species_name, "particle_momentum_x"].v + data_dict[prefix+"_py_"+suffix] = yt_ad[species_name, "particle_momentum_y"].v + data_dict[prefix+"_pz_"+suffix] = yt_ad[species_name, "particle_momentum_z"].v + data_dict[prefix+"_w_"+suffix] = yt_ad[species_name, "particle_weight"].v + data_dict[prefix+"_id_"+suffix] = yt_ad[species_name, "particle_id"].v + data_dict[prefix+"_cpu_"+suffix] = yt_ad[species_name, "particle_cpu"].v + data_dict[prefix+"_z_"+suffix] = yt_ad[species_name, "particle_position_z"].v + +def add_empty_species_to_dict(data_dict, species_name, prefix, suffix): + data_dict[prefix+"_px_"+suffix] = np.empty(0) + data_dict[prefix+"_py_"+suffix] = np.empty(0) + data_dict[prefix+"_pz_"+suffix] = np.empty(0) + data_dict[prefix+"_w_"+suffix] = np.empty(0) + data_dict[prefix+"_id_"+suffix] = np.empty(0) + data_dict[prefix+"_cpu_"+suffix] = np.empty(0) + data_dict[prefix+"_z_"+suffix] = np.empty(0) + +def add_species_to_dict(yt_ad, data_dict, species_name, prefix, suffix): + try: + ## If species exist, we add its data to the dictionary + add_existing_species_to_dict(yt_ad, data_dict, species_name, prefix, suffix) + except yt.utilities.exceptions.YTFieldNotFound: + ## If species does not exist, we avoid python crash and add empty arrays to the + ## dictionnary. Currently, this happens for the boron species in test number 4, which + ## entirely fuses into alphas. + add_empty_species_to_dict(data_dict, species_name, prefix, suffix) + +def check_particle_number_conservation(data): + # Check consumption of reactants + total_w_reactant1_start = np.sum(data[reactant_species[0] + "_w_start"]) + total_w_reactant1_end = np.sum(data[reactant_species[0] + "_w_end"]) + total_w_reactant2_start = np.sum(data[reactant_species[1] + "_w_start"]) + total_w_reactant2_end = np.sum(data[reactant_species[1] + "_w_end"]) + consumed_reactant1 = total_w_reactant1_start - total_w_reactant1_end + consumed_reactant2 = total_w_reactant2_start - total_w_reactant2_end + assert(consumed_reactant1 >= 0.) + assert(consumed_reactant2 >= 0.) + ## Check that number of consumed reactants are equal + assert_scale = max(total_w_reactant1_start, total_w_reactant2_start) + assert(is_close(consumed_reactant1, consumed_reactant2, rtol = 0., atol = default_tol*assert_scale)) + print( consumed_reactant1, consumed_reactant2, assert_scale, default_tol ) + + # That the number of products corresponds consumed particles + for species_name in product_species: + created_product = np.sum(data[species_name + "_w_end"]) + print(created_product) + assert(created_product >= 0.) + assert(is_close(total_w_reactant1_start, total_w_reactant1_start + created_product)) + assert(is_close(total_w_reactant2_start, total_w_reactant2_start + created_product)) + +def compute_energy_array(data, species_name, suffix, m): + ## Relativistic computation of kinetic energy for a given species + psq_array = data[species_name+'_px_'+suffix]**2 + data[species_name+'_py_'+suffix]**2 + \ + data[species_name+'_pz_'+suffix]**2 + rest_energy = m*scc.c**2 + return np.sqrt(psq_array*scc.c**2 + rest_energy**2) - rest_energy + +def check_energy_conservation(data): + proton_energy_start = compute_energy_array(data, "proton", "start", m_p) + proton_energy_end = compute_energy_array(data, "proton", "end", m_p) + boron_energy_start = compute_energy_array(data, "boron", "start", m_b) + boron_energy_end = compute_energy_array(data, "boron", "end", m_b) + alpha_energy_end = compute_energy_array(data, "alpha", "end", m_a) + total_energy_start = np.sum(proton_energy_start*data["proton_w_start"]) + \ + np.sum(boron_energy_start*data["boron_w_start"]) + total_energy_end = np.sum(proton_energy_end*data["proton_w_end"]) + \ + np.sum(boron_energy_end*data["boron_w_end"]) + \ + np.sum(alpha_energy_end*data["alpha_w_end"]) + ## Factor 3 is here because each nuclear fusion reaction produces 3 alphas + n_fusion_reaction = np.sum(data["alpha_w_end"])/3. + assert(is_close(total_energy_end, + total_energy_start + n_fusion_reaction*E_fusion_total, + rtol = 1.e-8)) + +def check_momentum_conservation(data): + proton_total_px_start = np.sum(data["proton_px_start"]*data["proton_w_start"]) + proton_total_py_start = np.sum(data["proton_py_start"]*data["proton_w_start"]) + proton_total_pz_start = np.sum(data["proton_pz_start"]*data["proton_w_start"]) + proton_total_px_end = np.sum(data["proton_px_end"]*data["proton_w_end"]) + proton_total_py_end = np.sum(data["proton_py_end"]*data["proton_w_end"]) + proton_total_pz_end = np.sum(data["proton_pz_end"]*data["proton_w_end"]) + boron_total_px_start = np.sum(data["boron_px_start"]*data["boron_w_start"]) + boron_total_py_start = np.sum(data["boron_py_start"]*data["boron_w_start"]) + boron_total_pz_start = np.sum(data["boron_pz_start"]*data["boron_w_start"]) + boron_total_px_end = np.sum(data["boron_px_end"]*data["boron_w_end"]) + boron_total_py_end = np.sum(data["boron_py_end"]*data["boron_w_end"]) + boron_total_pz_end = np.sum(data["boron_pz_end"]*data["boron_w_end"]) + alpha_total_px_end = np.sum(data["alpha_px_end"]*data["alpha_w_end"]) + alpha_total_py_end = np.sum(data["alpha_py_end"]*data["alpha_w_end"]) + alpha_total_pz_end = np.sum(data["alpha_pz_end"]*data["alpha_w_end"]) + total_px_start = proton_total_px_start + boron_total_px_start + total_py_start = proton_total_py_start + boron_total_py_start + total_pz_start = proton_total_pz_start + boron_total_pz_start + total_px_end = proton_total_px_end + boron_total_px_end + alpha_total_px_end + total_py_end = proton_total_py_end + boron_total_py_end + alpha_total_py_end + total_pz_end = proton_total_pz_end + boron_total_pz_end + alpha_total_pz_end + ## Absolute tolerance is needed because sometimes the initial momentum is exactly 0 + assert(is_close(total_px_start, total_px_end, atol=1.e-15)) + assert(is_close(total_py_start, total_py_end, atol=1.e-15)) + assert(is_close(total_pz_start, total_pz_end, atol=1.e-15)) + +def check_id(data): + ## Check that all created particles have unique id + cpu identifier (two particles with + ## different cpu can have the same id) + for species_name in product_species: + complex_id = data[species_name + "_id_end"] + 1j*data[species_name + "_cpu_end"] + assert(complex_id.shape == np.unique(complex_id).shape) + +def basic_product_particles_check(data): + ## For each nuclear fusion reaction in the code, we create 6 alpha macroparticles. So the + ## total number of alpha macroparticles must be a multiple of 6. + num_alpha = data["alpha_w_end"].shape[0] + assert(num_alpha%6 == 0) + + ## The weight of the 6 macroparticles coming from a single fusion event should be the same. + ## We verify this here. + assert(np.array_equal(data["alpha_w_end"][::6], data["alpha_w_end"][1::6])) + assert(np.array_equal(data["alpha_w_end"][::6], data["alpha_w_end"][2::6])) + assert(np.array_equal(data["alpha_w_end"][::6], data["alpha_w_end"][3::6])) + assert(np.array_equal(data["alpha_w_end"][::6], data["alpha_w_end"][4::6])) + assert(np.array_equal(data["alpha_w_end"][::6], data["alpha_w_end"][5::6])) + + ## When we create 6 macroparticles, the first has the exact same momentum as the second, the + ## third has the same as the fourth and the fifth has the same as the sixth. We verify this + ## here + assert(np.array_equal(data["alpha_px_end"][::6], data["alpha_px_end"][1::6])) + assert(np.array_equal(data["alpha_py_end"][::6], data["alpha_py_end"][1::6])) + assert(np.array_equal(data["alpha_pz_end"][::6], data["alpha_pz_end"][1::6])) + assert(np.array_equal(data["alpha_px_end"][2::6], data["alpha_px_end"][3::6])) + assert(np.array_equal(data["alpha_py_end"][2::6], data["alpha_py_end"][3::6])) + assert(np.array_equal(data["alpha_pz_end"][2::6], data["alpha_pz_end"][3::6])) + assert(np.array_equal(data["alpha_px_end"][4::6], data["alpha_px_end"][5::6])) + assert(np.array_equal(data["alpha_py_end"][4::6], data["alpha_py_end"][5::6])) + assert(np.array_equal(data["alpha_pz_end"][4::6], data["alpha_pz_end"][5::6])) + +def generic_check(data): + check_particle_number_conservation(data) + #check_energy_conservation(data) + #check_momentum_conservation(data) + check_id(data) + #basic_product_particles_check(data) + +def check_isotropy(data, relative_tolerance): + ## Checks that the alpha particles are emitted isotropically + average_px_sq = np.average(data["alpha_px_end"]*data["alpha_px_end"]) + average_py_sq = np.average(data["alpha_py_end"]*data["alpha_py_end"]) + average_pz_sq = np.average(data["alpha_pz_end"]*data["alpha_pz_end"]) + assert(is_close(average_px_sq, average_py_sq, rtol = relative_tolerance)) + assert(is_close(average_px_sq, average_pz_sq, rtol = relative_tolerance)) + +def astrophysical_factor_lowE(E): + ## E is in keV + ## Returns astrophysical factor in MeV b using the low energy fit in the range E < 400 keV + ## described in equation (2) of W.M. Nevins and R. Swain, Nuclear Fusion, 40, 865 (2000) + C0 = 197. + C1 = 0.24 + C2 = 2.31e-4 + AL = 1.82e4 + EL = 148. + dEL = 2.35 + return C0 + C1*E + C2*E**2 + AL/((E-EL)**2 + dEL**2) + +def astrophysical_factor_midE(E): + ## E is in keV + ## Returns astrophysical factor in MeV b using the mid energy fit in the range + ## 400 keV < E < 642 keV described in equation (3) of W.M. Nevins and R. Swain, + ## Nuclear Fusion, 40, 865 (2000) + D0 = 330. + D1 = 66.1 + D2 = -20.3 + D5 = -1.58 + E_400 = 400. + E_100 = 100. + E_norm = (E - E_400)/E_100 + return D0 + D1*E_norm + D2*E_norm**2 + D5*E_norm**5 + +def astrophysical_factor_highE(E): + ## E is in keV + ## Returns astrophysical factor in MeV b using the high energy fit in the range + ## 642 keV < E < 3500 keV described in equation (4) of W.M. Nevins and R. Swain, + ## Nuclear Fusion, 40, 865 (2000) + A0 = 2.57e6 + A1 = 5.67e5 + A2 = 1.34e5 + A3 = 5.68e5 + E0 = 581.3 + E1 = 1083. + E2 = 2405. + E3 = 3344. + dE0 = 85.7 + dE1 = 234. + dE2 = 138. + dE3 = 309. + B = 4.38 + return A0/((E-E0)**2 + dE0**2) + A1/((E-E1)**2 + dE1**2) + \ + A2/((E-E2)**2 + dE2**2) + A3/((E-E3)**2 + dE3**2) + B + +def astrophysical_factor(E): + ## E is in keV + ## Returns astrophysical factor in MeV b using the fits described in W.M. Nevins + ## and R. Swain, Nuclear Fusion, 40, 865 (2000) + conditions = [E <= 400, E <= 642, E > 642] + choices = [astrophysical_factor_lowE(E), + astrophysical_factor_midE(E), + astrophysical_factor_highE(E)] + return np.select(conditions, choices) + +def pb_cross_section_buck_fit(E): + ## E is in MeV + ## Returns cross section in b using a power law fit of the data presented in Buck et al., + ## Nuclear Physics A, 398(2), 189-202 (1983) in the range E > 3.5 MeV. + E_start_fit = 3.5 + ## Cross section at E = E_start_fit = 3.5 MeV + cross_section_start_fit = 0.2168440845211521 + slope_fit = -2.661840717596765 + return cross_section_start_fit*(E/E_start_fit)**slope_fit + +def pb_cross_section(E): + ## E is in keV + ## Returns cross section in b using the fits described in W.M. Nevins and R. Swain, + ## Nuclear Fusion, 40, 865 (2000) for E < 3.5 MeV and a power law fit of the data presented in + ## Buck et al., Nuclear Physics A, 398(2), 189-202 (1983) for E > 3.5 MeV. + E_MeV = E/1.e3 + conditions = [E <= 3500, E > 3500] + choices = [astrophysical_factor(E)/E_MeV * np.exp(-np.sqrt(E_Gamow_MeV / E_MeV)), + pb_cross_section_buck_fit(E_MeV)] + return np.select(conditions, choices) + +def E_com_to_p_sq_com(m1, m2, E): + ## E is the total (kinetic+mass) energy of a two particle (with mass m1 and m2) system in + ## its center of mass frame, in J. + ## Returns the square norm of the momentum of each particle in that frame. + return E**2/(4.*scc.c**2) - (m1**2 + m2**2)*scc.c**2/2. + \ + scc.c**6/(4.*E**2)*((m1**2 - m2**2)**2) + +def compute_relative_v_com(E): + ## E is the kinetic energy of proton+boron in the center of mass frame, in keV + ## Returns the relative velocity between proton and boron in this frame, in m/s + E_J = E*keV_to_Joule + (m_p + m_b)*scc.c**2 + p_sq = E_com_to_p_sq_com(m_p, m_b, E_J) + p = np.sqrt(p_sq) + gamma_p = np.sqrt(1. + p_sq / (m_p*scc.c)**2) + gamma_b = np.sqrt(1. + p_sq / (m_b*scc.c)**2) + v_p = p/(gamma_p*m_p) + v_b = p/(gamma_b*m_b) + return v_p+v_b + +def expected_alpha_weight_com(E_com, proton_density, boron_density, dV, dt): + ## Computes expected number of produced alpha particles as a function of energy E_com in the + ## center of mass frame. E_com is in keV. + assert(np.all(E_com>=0)) + ## Case E_com == 0 is handled manually to avoid division by zero + conditions = [E_com == 0, E_com > 0] + ## Necessary to avoid division by 0 warning when pb_cross_section is evaluated + E_com_never_zero = np.clip(E_com, 1.e-15, None) + choices = [0., pb_cross_section(E_com_never_zero)*compute_relative_v_com(E_com_never_zero)] + sigma_times_vrel = np.select(conditions, choices) + ## Factor 3 is here because each fusion reaction produces 3 alphas + return 3.*proton_density*boron_density*sigma_times_vrel*barn_to_square_meter*dV*dt + +def check_macroparticle_number(data, fusion_probability_target_value, num_pair_per_cell): + ## Checks that the number of macroparticles is as expected for the first and second tests + + ## The first slice 0 < z < 1 does not contribute to alpha creation + numcells = dV_total - dV_slice + ## In these tests, the fusion_multiplier is so high that the fusion probability per pair is + ## equal to the parameter fusion_probability_target_value + fusion_probability_per_pair = fusion_probability_target_value + expected_fusion_number = numcells*num_pair_per_cell*fusion_probability_per_pair + ## Each fusion event produces 6 alpha macroparticles + expected_macroparticle_number = 6.*expected_fusion_number + std_macroparticle_number = 6.*np.sqrt(expected_fusion_number) + actual_macroparticle_number = data["alpha_w_end"].shape[0] + # 5 sigma test that has an intrinsic probability to fail of 1 over ~2 millions + assert(is_close(actual_macroparticle_number, expected_macroparticle_number, rtol = 0., + atol = 5.*std_macroparticle_number)) + + ## used in subsequent function + return expected_fusion_number + +def p_sq_boron_frame_to_E_COM_frame(p_proton_sq): + # Takes the proton square norm of the momentum in the boron rest frame and returns the total + # kinetic energy in the center of mass frame. Everything is in SI units. + + # Total (kinetic + mass) energy in lab frame + E_lab = np.sqrt(p_proton_sq*scc.c**2 + (m_p*scc.c**2)**2) + m_b*scc.c**2 + # Use invariant E**2 - p**2c**2 of 4-momentum norm to compute energy in center of mass frame + E_com = np.sqrt(E_lab**2 - p_proton_sq*scc.c**2) + # Corresponding kinetic energy + E_com_kin = E_com - (m_b+scc.m_p)*scc.c**2 + return E_com_kin*(p_proton_sq>0.) + +def p_sq_to_kinetic_energy(p_sq, m): + ## Returns the kinetic energy of a particle as a function of its squared momentum. + ## Everything is in SI units. + return np.sqrt(p_sq*scc.c**2 + (m*scc.c**2)**2) - (m*scc.c**2) + +def compute_E_com1(data): + ## Computes kinetic energy (in Joule) in the center of frame for the first test + + ## Square norm of the momentum of proton/boron as a function of cell number in z direction + p_sq = 2.*m_reduced*(Energy_step*np.arange(size_z)**2) + return p_sq_to_kinetic_energy(p_sq, m_b) + p_sq_to_kinetic_energy(p_sq, m_p) + +def compute_E_com2(data): + ## Computes kinetic energy (in Joule) in the center of frame for the second test + + ## Square norm of the momentum of the proton as a function of cell number in z direction + p_proton_sq = 2.*m_p*(Energy_step*np.arange(size_z)**2) + return p_sq_boron_frame_to_E_COM_frame(p_proton_sq) + +def check_alpha_yield(data, expected_fusion_number, E_com, proton_density, boron_density): + ## Checks that the fusion yield is as expected for the first and second tests. + ## Proton and boron densities are in m^-3. + + alpha_weight_theory = expected_alpha_weight_com(E_com/keV_to_Joule, proton_density, + boron_density, dV_slice, dt) + alpha_weight_simulation = np.histogram(data["alpha_z_end"], bins=size_z, range=(0, size_z), + weights = data["alpha_w_end"])[0] + + ## -1 is here because the first slice 0 < z < 1 does not contribute to alpha creation + expected_fusion_number_per_slice = expected_fusion_number/(size_z-1) + relative_std_alpha_weight = 1./np.sqrt(expected_fusion_number_per_slice) + + # 5 sigma test that has an intrinsic probability to fail of 1 over ~2 millions + assert(np.all(is_close(alpha_weight_theory, alpha_weight_simulation, + rtol = 5.*relative_std_alpha_weight))) + +def check_initial_energy1(data, E_com): + ## In WarpX, the initial momentum of the alphas is computed assuming that the fusion process + ## takes place in two steps: + ## (1): proton + boron 11 -> alpha + beryllium 8 + ## (2): beryllium 8 -> alpha + alpha + ## The alpha generated in the first step (labeled alpha1) generally has a different initial + ## energy distribution than the alphas generated in the second step (labeled alpha2 and + ## alpha3). + ## In the first test, we are in the center of mass frame. Therefore, the momentum of alpha1 is + ## entirely determined by the energy in the center of mass frame, so we check in this function + ## that the energy of the alpha1 macroparticles is as expected. On the other hand, the energy + ## of alpha2 and alpha3 follows a continuous distribution within a given range. In this test, + ## we check that this range is as expected by comparing the maximum and minimum energy of the + ## obtained macroparticles to the theoretical maximum and minimum. + ## Note that in the simulations, 6 macroparticles are generated during for each fusion event. + ## The first and second macroparticles are alpha1 particles. The third and fourth are alpha2. + ## The fifth and sixth are alpha3. + + energy_alpha_simulation = compute_energy_array(data, "alpha", "end", m_a) + z_alpha = data["alpha_z_end"] + + # Loop over all slices (i.e. cells in the z direction) + for slice_number in range(1, size_z): + ## Kinetic energy in the lab frame before fusion + E_kinetic_com_before = E_com[slice_number] + ## Total (kinetic + mass) energy in the lab frame after + ## proton + boron 11 -> alpha + beryllium 8 + E_total_com_after = E_kinetic_com_before + E_fusion + (m_a + m_be)*scc.c**2 + ## Corresponding momentum norm squared of alpha1/beryllium + p_sq_after = E_com_to_p_sq_com(m_a, m_be, E_total_com_after) + ## Corresponding kinetic energy for alpha1 + energy_alpha1_theory = p_sq_to_kinetic_energy(p_sq_after, m_a) + ## Corresponding kinetic energy for beryllium + energy_beryllium_theory = p_sq_to_kinetic_energy(p_sq_after, m_be) + ## Corresponding kinetic energy for alpha2 + alpha3 after beryllium decay + energy_alpha2_plus_3_theory = energy_beryllium_theory + E_decay + ## Compute the theoretical maximum and minimum energy of alpha2 and alpha3. This + ## calculation is done nonrelativistically, by noting that the maximum (minimum) energy + ## corresponds to an alpha emitted exactly in the (opposite) direction of the beryllium + ## in the center of mass frame. This calculation involves solving a polynomial equation of + ## order 2 in p_alpha23. + max_p_alpha23 = 0.5*(np.sqrt(p_sq_after) + \ + np.sqrt(4*m_a*energy_alpha2_plus_3_theory - p_sq_after)) + min_p_alpha23 = 0.5*(np.sqrt(p_sq_after) - \ + np.sqrt(4*m_a*energy_alpha2_plus_3_theory - p_sq_after)) + max_energy_alpha23 = max_p_alpha23**2/(2.*m_a) + min_energy_alpha23 = min_p_alpha23**2/(2.*m_a) + + ## Get the energy of all alphas in the slice + energy_alpha_slice = energy_alpha_simulation[(z_alpha >= slice_number)* \ + (z_alpha < (slice_number + 1))] + ## Energy of alphas1 (here, first macroparticle of each fusion event) in the slice + energy_alpha1_simulation = energy_alpha_slice[::6] + ## Energy of alphas2 (here, third macroparticle of each fusion event) in the slice + energy_alpha2_simulation = energy_alpha_slice[2::6] + ## Energy of alphas3 (here, fifth macroparticle of each fusion event) in the slice + energy_alpha3_simulation = energy_alpha_slice[4::6] + + assert(np.all(is_close(energy_alpha1_simulation, energy_alpha1_theory, rtol=5.e-8))) + assert(is_close(np.amax(energy_alpha2_simulation), max_energy_alpha23, rtol=1.e-2)) + assert(is_close(np.amin(energy_alpha2_simulation), min_energy_alpha23, rtol=1.e-2)) + assert(is_close(np.amax(energy_alpha3_simulation), max_energy_alpha23, rtol=1.e-2)) + assert(is_close(np.amin(energy_alpha3_simulation), min_energy_alpha23, rtol=1.e-2)) + +def check_initial_energy2(data): + ## In WarpX, the initial momentum of the alphas is computed assuming that the fusion process + ## takes place in two steps: + ## (1): proton + boron 11 -> alpha + beryllium 8 + ## (2): beryllium 8 -> alpha + alpha + ## The alpha generated in the first step (labeled alpha1) generally has a different initial + ## energy distribution than the alphas generated in the second step (labeled alpha2 and + ## alpha3). + ## In the second test, we are in the boron rest frame. In this case, the momentum of each alpha + ## follows a continuous distribution within a given range. In this function, we verify that + ## this range is as expected by comparing the maximum and minimum energy of the obtained + ## macroparticles to the theoretical maximum and minimum. Be aware that the range for alpha1 + ## is not the same as the range for alpha2 and alpha3 (typically alpha1 particles will carry + ## more energy). + ## Note that in the simulations, 6 macroparticles are generated during for each fusion event. + ## The first and second macroparticles are alpha1 particles. The third and fourth are alpha2. + ## The fifth and sixth are alpha3. + + energy_alpha_simulation = compute_energy_array(data, "alpha", "end", m_a) + z_alpha = data["alpha_z_end"] + + # Loop over all slices (i.e. cells in the z direction) + for slice_number in range(1, size_z): + ## For simplicity, all the calculations in this functino are done nonrelativistically + ## Proton kinetic energy in the lab frame before fusion + E_proton_nonrelativistic = Energy_step*slice_number**2 + ## Corresponding square norm of proton momentum + p_proton_sq = 2.*scc.m_p*E_proton_nonrelativistic + ## Kinetic energy in the lab frame after + ## proton + boron 11 -> alpha + beryllium 8 + E_after_fusion = E_proton_nonrelativistic + E_fusion + + ## Compute the theoretical maximum and minimum energy of alpha1 in the lab frame. This + ## calculation is done by noting that the maximum (minimum) energy corresponds to an alpha + ## emitted exactly in the (opposite) direction of the proton in the lab frame. This + ## calculation involves solving a polynomial equation of order 2 in p_alpha1. + max_p_alpha1 = (m_a/m_be*np.sqrt(p_proton_sq) + \ + np.sqrt(-m_a/m_be*p_proton_sq + 2.*E_after_fusion*m_a*(m_a/m_be + 1.))) / \ + (m_a/m_be + 1.) + min_p_alpha1 = (m_a/m_be*np.sqrt(p_proton_sq) - \ + np.sqrt(-m_a/m_be*p_proton_sq + 2.*E_after_fusion*m_a*(m_a/m_be + 1.))) / \ + (m_a/m_be + 1.) + max_energy_alpha1 = max_p_alpha1**2/(2*m_a) + min_energy_alpha1 = min_p_alpha1**2/(2*m_a) + + ## Corresponding max/min kinetic energy of Beryllium in the lab frame + max_E_beryllium = E_after_fusion - min_energy_alpha1 + min_E_beryllium = E_after_fusion - max_energy_alpha1 + ## Corresponding max/min momentum square of Beryllium in the lab frame + max_p_sq_beryllium = 2.*m_be*max_E_beryllium + min_p_sq_beryllium = 2.*m_be*min_E_beryllium + ## Corresponding max/min kinetic energy in the lab frame for alpha2 + alpha3 after + ## Beryllium decay + max_energy_alpha2_plus_3 = max_E_beryllium + E_decay + min_energy_alpha2_plus_3 = min_E_beryllium + E_decay + + ## Compute the theoretical maximum and minimum energy of alpha2 and alpha3 in the lab + ## frame. This calculation is done by noting that the maximum (minimum) energy corresponds + ## to an alpha emitted exactly in the (opposite) direction of a beryllium with energy + ## max_E_beryllium (min_E_beryllium). This calculation involves solving a polynomial + ## equation of order 2 in p_alpha23. + max_p_alpha23 = 0.5*(np.sqrt(max_p_sq_beryllium) + \ + np.sqrt(4*m_a*max_energy_alpha2_plus_3 - max_p_sq_beryllium)) + min_p_alpha23 = 0.5*(np.sqrt(min_p_sq_beryllium) - \ + np.sqrt(4*m_a*min_energy_alpha2_plus_3 - min_p_sq_beryllium)) + max_energy_alpha23 = max_p_alpha23**2/(2*m_a) + min_energy_alpha23 = min_p_alpha23**2/(2*m_a) + + ## Get the energy of all alphas in the slice + energy_alpha_slice = energy_alpha_simulation[(z_alpha >= slice_number)* \ + (z_alpha < (slice_number + 1))] + ## Energy of alphas1 (here, first macroparticle of each fusion event) in the slice + energy_alpha1_simulation = energy_alpha_slice[::6] + ## Energy of alphas2 (here, third macroparticle of each fusion event) in the slice + energy_alpha2_simulation = energy_alpha_slice[2::6] + ## Energy of alphas3 (here, fifth macroparticle of each fusion event) in the slice + energy_alpha3_simulation = energy_alpha_slice[4::6] + + assert(is_close(np.amax(energy_alpha1_simulation), max_energy_alpha1, rtol=1.e-2)) + assert(is_close(np.amin(energy_alpha1_simulation), min_energy_alpha1, rtol=1.e-2)) + ## Tolerance is quite high below because we don't have a lot of alphas to produce good + ## statistics and an event like alpha1 emitted exactly in direction of proton & alpha2 + ## emitted exactly in direction opposite to Beryllium is somewhat rare. + assert(is_close(np.amax(energy_alpha2_simulation), max_energy_alpha23, rtol=2.5e-1)) + assert(is_close(np.amin(energy_alpha2_simulation), min_energy_alpha23, rtol=2.5e-1)) + assert(is_close(np.amax(energy_alpha3_simulation), max_energy_alpha23, rtol=2.5e-1)) + assert(is_close(np.amin(energy_alpha3_simulation), min_energy_alpha23, rtol=2.5e-1)) + +def check_xy_isotropy(data): + ## Checks that the alpha particles are emitted isotropically in x and y + average_px_sq = np.average(data["alpha_px_end"]*data["alpha_px_end"]) + average_py_sq = np.average(data["alpha_py_end"]*data["alpha_py_end"]) + average_pz_sq = np.average(data["alpha_pz_end"]*data["alpha_pz_end"]) + assert(is_close(average_px_sq, average_py_sq, rtol = 5.e-2)) + assert(average_pz_sq > average_px_sq) + assert(average_pz_sq > average_py_sq) + +def sigmav_thermal_fit_lowE_nonresonant(T): + ## Temperature T is in keV + ## Returns the nonresonant average of cross section multiplied by relative velocity in m^3/s, + ## in the range T <= 70 keV, as described by equation 9 of W.M. Nevins and R. Swain, + ## Nuclear Fusion, 40, 865 (2000). + E0 = (E_Gamow_keV/4.)**(1./3.) * T**(2./3.) + DE0 = 4.*np.sqrt(T*E0/3.) + C0 = 197.*1.e3 + C1 = 0.24*1.e3 + C2 = 2.31e-4*1.e3 + tau = 3.*E0/T + Seff = C0*(1.+5./(12.*tau)) + C1*(E0+35./36.*T) + C2*(E0**2 + 89./36.*E0*T) + ## nonresonant sigma times vrel, in barn meter per second + sigmav_nr_bmps = np.sqrt(2*T*keV_to_Joule/m_reduced) * DE0*Seff/T**2 * np.exp(-tau) + ## Return result in cubic meter per second + return sigmav_nr_bmps*barn_to_square_meter + +def sigmav_thermal_fit_lowE_resonant(T): + ## Temperature T is in keV + ## Returns the resonant average of cross section multiplied by relative velocity in m^3/s, + ## in the range T <= 70 keV, as described by equation 11 of W.M. Nevins and R. Swain, + ## Nuclear Fusion, 40, 865 (2000). + return 5.41e-21 * np.exp(-148./T) / T**(3./2.) + +def sigmav_thermal_fit_lowE(T): + ## Temperature T is in keV + ## Returns the average of cross section multiplied by relative velocity in m^3/s, using the + ## fits described in section 3.1 of W.M. Nevins and R. Swain, Nuclear Fusion, 40, 865 (2000). + ## The fits are valid for T <= 70 keV. + return sigmav_thermal_fit_lowE_nonresonant(T) + sigmav_thermal_fit_lowE_resonant(T) + +def expected_alpha_thermal(T, proton_density, boron_density, dV, dt): + ## Computes the expected number of produced alpha particles when the protons and borons follow + ## a Maxwellian distribution with a temperature T, in keV. This uses the thermal fits described + ## in W.M. Nevins and R. Swain, Nuclear Fusion, 40, 865 (2000). + + ## The fit used here is only valid in the range T <= 70 keV. + assert((T >=0) and (T<=70)) + sigma_times_vrel = sigmav_thermal_fit_lowE(T) + ## Factor 3 is here because each fusion event produces 3 alphas. + return 3.*proton_density*boron_density*sigma_times_vrel*dV*dt + +def check_thermal_alpha_yield(data): + ## Checks that the number of alpha particles in test3 is as expected + Temperature = 44. # keV + proton_density = 1.e28 # m^-3 + boron_density = 5.e28 # m^-3 + + alpha_weight_theory = expected_alpha_thermal(Temperature, proton_density, boron_density, + dV_total, dt) + alpha_weight_simulation = np.sum(data["alpha_w_end"]) + + assert(is_close(alpha_weight_theory, alpha_weight_simulation, rtol = 2.e-1)) + +def boron_remains(data): + ## Checks whether there remains boron macroparticles at the end of the test + n_boron_left = data["boron_w_end"].shape[0] + return (n_boron_left > 0) + +def specific_check1(data): + check_isotropy(data, relative_tolerance = 3.e-2) + expected_fusion_number = check_macroparticle_number(data, + fusion_probability_target_value = 0.002, + num_pair_per_cell = 10000) + E_com = compute_E_com1(data) + check_alpha_yield(data, expected_fusion_number, E_com, proton_density = 1., + boron_density = 1.) + check_initial_energy1(data, E_com) + +def specific_check2(data): + check_xy_isotropy(data) + ## Only 900 particles pairs per cell here because we ignore the 10% of protons that are at rest + expected_fusion_number = check_macroparticle_number(data, + fusion_probability_target_value = 0.02, + num_pair_per_cell = 900) + E_com = compute_E_com2(data) + check_alpha_yield(data, expected_fusion_number, E_com, proton_density = 1.e20, + boron_density = 1.e26) + check_initial_energy2(data) + +def specific_check3(data): + check_isotropy(data, relative_tolerance = 1.e-1) + check_thermal_alpha_yield(data) + +def specific_check4(data): + ## In test 4, the boron initial density is so small that all borons should have fused within a + ## timestep dt. We thus assert that no boron remains at the end of the simulation. + assert(not boron_remains(data)) + +def specific_check5(data): + ## Test 5 is similar to test 4, expect that the parameter fusion_probability_threshold is + ## increased to the point that we should severely underestimate the fusion yield. Consequently, + ## there should still be borons at the end of the test, which we verify here. + assert(boron_remains(data)) + +def check_charge_conservation(rho_start, rho_end): + assert(np.all(is_close(rho_start, rho_end, rtol=2.e-11))) + +def main(): + filename_end = sys.argv[1] + filename_start = filename_end[:-4] + '0000' + ds_end = yt.load(filename_end) + ds_start = yt.load(filename_start) + ad_end = ds_end.all_data() + ad_start = ds_start.all_data() + field_data_end = ds_end.covering_grid(level=0, left_edge=ds_end.domain_left_edge, + dims=ds_end.domain_dimensions) + field_data_start = ds_start.covering_grid(level=0, left_edge=ds_start.domain_left_edge, + dims=ds_start.domain_dimensions) + + ntests = 2 + for i in range(1, ntests+1): + data = {} + + for species_name in reactant_species: + add_species_to_dict(ad_start, data, species_name+str(i), species_name, "start") + add_species_to_dict(ad_start, data, species_name+str(i), species_name, "end") + + for species_name in product_species: + add_species_to_dict(ad_end, data, species_name+str(i), species_name, "end") + + # General checks that are performed for all tests + generic_check(data) + + # Checks that are specific to test number i + # TODO: activate code below + # eval("specific_check"+str(i)+"(data)") + + rho_start = field_data_start["rho"].to_ndarray() + rho_end = field_data_end["rho"].to_ndarray() + check_charge_conservation(rho_start, rho_end) + + test_name = os.path.split(os.getcwd())[1] + checksumAPI.evaluate_checksum(test_name, filename_end) + +if __name__ == "__main__": + main() diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H index 587e1178437..34219645591 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H @@ -34,8 +34,8 @@ amrex::ParticleReal DeuteriumTritiumFusionCrossSection (const amrex::ParticleRea // Compute the Gamow constant B_G (in keV^{1/2}) // (See Eq. 3 in H.-S. Bosch and G.M. Hale 1992 Nucl. Fusion 32 611) - constexpr amrex::ParticleReal m_D = 1.99901 * PhysConst::m_p; - constexpr amrex::ParticleReal m_T = 2.99372 * PhysConst::m_p; + constexpr amrex::ParticleReal m_D = 2.01410177812 * PhysConst::m_u; + constexpr amrex::ParticleReal m_T = 3.0160492779 * PhysConst::m_u; constexpr amrex::ParticleReal m_reduced = m_D / (1._prt + m_D/m_T); amrex::ParticleReal B_G = MathConst::pi * PhysConst::alpha * 1._prt * 1._prt * std::sqrt( 2._prt*m_reduced*PhysConst::c*PhysConst::c * joule_to_keV ); From 8137f01a8e0229f775f577943a20084923f66f4d Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Mon, 11 Jul 2022 06:07:14 -0700 Subject: [PATCH 48/63] Improve analysis script --- .../nuclear_fusion/analysis_deuterium_tritium_fusion.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py index 3d546e655b4..9b3d5276d60 100755 --- a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py @@ -140,15 +140,13 @@ def check_particle_number_conservation(data): ## Check that number of consumed reactants are equal assert_scale = max(total_w_reactant1_start, total_w_reactant2_start) assert(is_close(consumed_reactant1, consumed_reactant2, rtol = 0., atol = default_tol*assert_scale)) - print( consumed_reactant1, consumed_reactant2, assert_scale, default_tol ) # That the number of products corresponds consumed particles for species_name in product_species: created_product = np.sum(data[species_name + "_w_end"]) - print(created_product) assert(created_product >= 0.) - assert(is_close(total_w_reactant1_start, total_w_reactant1_start + created_product)) - assert(is_close(total_w_reactant2_start, total_w_reactant2_start + created_product)) + assert(is_close(total_w_reactant1_start, total_w_reactant1_end + created_product)) + assert(is_close(total_w_reactant2_start, total_w_reactant2_end + created_product)) def compute_energy_array(data, species_name, suffix, m): ## Relativistic computation of kinetic energy for a given species @@ -705,7 +703,7 @@ def main(): for species_name in reactant_species: add_species_to_dict(ad_start, data, species_name+str(i), species_name, "start") - add_species_to_dict(ad_start, data, species_name+str(i), species_name, "end") + add_species_to_dict(ad_end, data, species_name+str(i), species_name, "end") for species_name in product_species: add_species_to_dict(ad_end, data, species_name+str(i), species_name, "end") From 637ea1bf44051ccf4585c0541c3182f1fdf278c3 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Mon, 11 Jul 2022 06:38:34 -0700 Subject: [PATCH 49/63] Add test of energy conservation --- .../analysis_deuterium_tritium_fusion.py | 122 +++--------------- 1 file changed, 21 insertions(+), 101 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py index 9b3d5276d60..14cdd237d67 100755 --- a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py @@ -65,23 +65,20 @@ reactant_species = ['deuterium', 'tritium'] product_species = ['helium', 'neutron'] +from scipy.constants import m_u, m_p +mass = { + 'deuterium': 2.01410177812*m_u, + 'tritium': 3.0160492779*m_u, + 'helium': 4.00260325413*m_u, + 'neutron': 1.0013784193052508*m_p +} + ## Some physical parameters keV_to_Joule = scc.e*1e3 MeV_to_Joule = scc.e*1e6 barn_to_square_meter = 1.e-28 -m_p = scc.m_p # Proton mass -m_b = 11.00930536*scc.m_u # Boron 11 mass -m_reduced = m_p*m_b/(m_p+m_b) -m_a = 4.002602*scc.m_u # Alpha mass -m_be = 7.94748*m_p # Beryllium 8 mass -Z_boron = 5. -Z_proton = 1. -E_Gamow = (Z_boron*Z_proton*np.pi*scc.fine_structure)**2*2.*m_reduced*scc.c**2 -E_Gamow_MeV = E_Gamow/MeV_to_Joule -E_Gamow_keV = E_Gamow/keV_to_Joule -E_fusion = 8.59009*MeV_to_Joule # Energy released during p + B -> alpha + Be -E_decay = 0.0918984*MeV_to_Joule # Energy released during Be -> 2*alpha -E_fusion_total = E_fusion + E_decay # Energy released during p + B -> 3*alpha + +E_fusion = 17.6*MeV_to_Joule # Energy released during the fusion reaction ## Some numerical parameters for this test size_x = 8 @@ -156,20 +153,17 @@ def compute_energy_array(data, species_name, suffix, m): return np.sqrt(psq_array*scc.c**2 + rest_energy**2) - rest_energy def check_energy_conservation(data): - proton_energy_start = compute_energy_array(data, "proton", "start", m_p) - proton_energy_end = compute_energy_array(data, "proton", "end", m_p) - boron_energy_start = compute_energy_array(data, "boron", "start", m_b) - boron_energy_end = compute_energy_array(data, "boron", "end", m_b) - alpha_energy_end = compute_energy_array(data, "alpha", "end", m_a) - total_energy_start = np.sum(proton_energy_start*data["proton_w_start"]) + \ - np.sum(boron_energy_start*data["boron_w_start"]) - total_energy_end = np.sum(proton_energy_end*data["proton_w_end"]) + \ - np.sum(boron_energy_end*data["boron_w_end"]) + \ - np.sum(alpha_energy_end*data["alpha_w_end"]) - ## Factor 3 is here because each nuclear fusion reaction produces 3 alphas - n_fusion_reaction = np.sum(data["alpha_w_end"])/3. + total_energy_start = 0 + for species_name in reactant_species: + total_energy_start += np.sum( data[species_name + "_w_start"] * \ + compute_energy_array(data, species_name, "start", mass[species_name]) ) + total_energy_end = 0 + for species_name in product_species + reactant_species: + total_energy_end += np.sum( data[species_name + "_w_end"] * \ + compute_energy_array(data, species_name, "end", mass[species_name]) ) + n_fusion_reaction = np.sum(data[product_species[0] + "_w_end"]) assert(is_close(total_energy_end, - total_energy_start + n_fusion_reaction*E_fusion_total, + total_energy_start + n_fusion_reaction*E_fusion, rtol = 1.e-8)) def check_momentum_conservation(data): @@ -235,7 +229,7 @@ def basic_product_particles_check(data): def generic_check(data): check_particle_number_conservation(data) - #check_energy_conservation(data) + check_energy_conservation(data) #check_momentum_conservation(data) check_id(data) #basic_product_particles_check(data) @@ -587,65 +581,6 @@ def check_xy_isotropy(data): assert(average_pz_sq > average_px_sq) assert(average_pz_sq > average_py_sq) -def sigmav_thermal_fit_lowE_nonresonant(T): - ## Temperature T is in keV - ## Returns the nonresonant average of cross section multiplied by relative velocity in m^3/s, - ## in the range T <= 70 keV, as described by equation 9 of W.M. Nevins and R. Swain, - ## Nuclear Fusion, 40, 865 (2000). - E0 = (E_Gamow_keV/4.)**(1./3.) * T**(2./3.) - DE0 = 4.*np.sqrt(T*E0/3.) - C0 = 197.*1.e3 - C1 = 0.24*1.e3 - C2 = 2.31e-4*1.e3 - tau = 3.*E0/T - Seff = C0*(1.+5./(12.*tau)) + C1*(E0+35./36.*T) + C2*(E0**2 + 89./36.*E0*T) - ## nonresonant sigma times vrel, in barn meter per second - sigmav_nr_bmps = np.sqrt(2*T*keV_to_Joule/m_reduced) * DE0*Seff/T**2 * np.exp(-tau) - ## Return result in cubic meter per second - return sigmav_nr_bmps*barn_to_square_meter - -def sigmav_thermal_fit_lowE_resonant(T): - ## Temperature T is in keV - ## Returns the resonant average of cross section multiplied by relative velocity in m^3/s, - ## in the range T <= 70 keV, as described by equation 11 of W.M. Nevins and R. Swain, - ## Nuclear Fusion, 40, 865 (2000). - return 5.41e-21 * np.exp(-148./T) / T**(3./2.) - -def sigmav_thermal_fit_lowE(T): - ## Temperature T is in keV - ## Returns the average of cross section multiplied by relative velocity in m^3/s, using the - ## fits described in section 3.1 of W.M. Nevins and R. Swain, Nuclear Fusion, 40, 865 (2000). - ## The fits are valid for T <= 70 keV. - return sigmav_thermal_fit_lowE_nonresonant(T) + sigmav_thermal_fit_lowE_resonant(T) - -def expected_alpha_thermal(T, proton_density, boron_density, dV, dt): - ## Computes the expected number of produced alpha particles when the protons and borons follow - ## a Maxwellian distribution with a temperature T, in keV. This uses the thermal fits described - ## in W.M. Nevins and R. Swain, Nuclear Fusion, 40, 865 (2000). - - ## The fit used here is only valid in the range T <= 70 keV. - assert((T >=0) and (T<=70)) - sigma_times_vrel = sigmav_thermal_fit_lowE(T) - ## Factor 3 is here because each fusion event produces 3 alphas. - return 3.*proton_density*boron_density*sigma_times_vrel*dV*dt - -def check_thermal_alpha_yield(data): - ## Checks that the number of alpha particles in test3 is as expected - Temperature = 44. # keV - proton_density = 1.e28 # m^-3 - boron_density = 5.e28 # m^-3 - - alpha_weight_theory = expected_alpha_thermal(Temperature, proton_density, boron_density, - dV_total, dt) - alpha_weight_simulation = np.sum(data["alpha_w_end"]) - - assert(is_close(alpha_weight_theory, alpha_weight_simulation, rtol = 2.e-1)) - -def boron_remains(data): - ## Checks whether there remains boron macroparticles at the end of the test - n_boron_left = data["boron_w_end"].shape[0] - return (n_boron_left > 0) - def specific_check1(data): check_isotropy(data, relative_tolerance = 3.e-2) expected_fusion_number = check_macroparticle_number(data, @@ -667,21 +602,6 @@ def specific_check2(data): boron_density = 1.e26) check_initial_energy2(data) -def specific_check3(data): - check_isotropy(data, relative_tolerance = 1.e-1) - check_thermal_alpha_yield(data) - -def specific_check4(data): - ## In test 4, the boron initial density is so small that all borons should have fused within a - ## timestep dt. We thus assert that no boron remains at the end of the simulation. - assert(not boron_remains(data)) - -def specific_check5(data): - ## Test 5 is similar to test 4, expect that the parameter fusion_probability_threshold is - ## increased to the point that we should severely underestimate the fusion yield. Consequently, - ## there should still be borons at the end of the test, which we verify here. - assert(boron_remains(data)) - def check_charge_conservation(rho_start, rho_end): assert(np.all(is_close(rho_start, rho_end, rtol=2.e-11))) From b11812de097d8c120b952460559af23a76258d5b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 13:39:31 +0000 Subject: [PATCH 50/63] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../nuclear_fusion/analysis_deuterium_tritium_fusion.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py index 14cdd237d67..5ce761b6d56 100755 --- a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py @@ -65,7 +65,8 @@ reactant_species = ['deuterium', 'tritium'] product_species = ['helium', 'neutron'] -from scipy.constants import m_u, m_p +from scipy.constants import m_p, m_u + mass = { 'deuterium': 2.01410177812*m_u, 'tritium': 3.0160492779*m_u, From eb76522bbb04eec7f8c8d35d7fae380dbfe982fd Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Mon, 11 Jul 2022 06:52:45 -0700 Subject: [PATCH 51/63] Add test of conservation of momentum --- .../analysis_deuterium_tritium_fusion.py | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py index 14cdd237d67..5568af5c799 100755 --- a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py @@ -167,27 +167,27 @@ def check_energy_conservation(data): rtol = 1.e-8)) def check_momentum_conservation(data): - proton_total_px_start = np.sum(data["proton_px_start"]*data["proton_w_start"]) - proton_total_py_start = np.sum(data["proton_py_start"]*data["proton_w_start"]) - proton_total_pz_start = np.sum(data["proton_pz_start"]*data["proton_w_start"]) - proton_total_px_end = np.sum(data["proton_px_end"]*data["proton_w_end"]) - proton_total_py_end = np.sum(data["proton_py_end"]*data["proton_w_end"]) - proton_total_pz_end = np.sum(data["proton_pz_end"]*data["proton_w_end"]) - boron_total_px_start = np.sum(data["boron_px_start"]*data["boron_w_start"]) - boron_total_py_start = np.sum(data["boron_py_start"]*data["boron_w_start"]) - boron_total_pz_start = np.sum(data["boron_pz_start"]*data["boron_w_start"]) - boron_total_px_end = np.sum(data["boron_px_end"]*data["boron_w_end"]) - boron_total_py_end = np.sum(data["boron_py_end"]*data["boron_w_end"]) - boron_total_pz_end = np.sum(data["boron_pz_end"]*data["boron_w_end"]) - alpha_total_px_end = np.sum(data["alpha_px_end"]*data["alpha_w_end"]) - alpha_total_py_end = np.sum(data["alpha_py_end"]*data["alpha_w_end"]) - alpha_total_pz_end = np.sum(data["alpha_pz_end"]*data["alpha_w_end"]) - total_px_start = proton_total_px_start + boron_total_px_start - total_py_start = proton_total_py_start + boron_total_py_start - total_pz_start = proton_total_pz_start + boron_total_pz_start - total_px_end = proton_total_px_end + boron_total_px_end + alpha_total_px_end - total_py_end = proton_total_py_end + boron_total_py_end + alpha_total_py_end - total_pz_end = proton_total_pz_end + boron_total_pz_end + alpha_total_pz_end + total_px_start = 0 + total_py_start = 0 + total_pz_start = 0 + for species_name in reactant_species: + total_px_start += np.sum( + data[species_name+'_px_start'] * data[species_name+'_w_start']) + total_py_start += np.sum( + data[species_name+'_py_start'] * data[species_name+'_w_start']) + total_pz_start += np.sum( + data[species_name+'_pz_start'] * data[species_name+'_w_start']) + total_px_end = 0 + total_py_end = 0 + total_pz_end = 0 + for species_name in reactant_species + product_species: + total_px_end += np.sum( + data[species_name+'_px_end'] * data[species_name+'_w_end']) + total_py_end += np.sum( + data[species_name+'_py_end'] * data[species_name+'_w_end']) + total_pz_end += np.sum( + data[species_name+'_pz_end'] * data[species_name+'_w_end']) + ## Absolute tolerance is needed because sometimes the initial momentum is exactly 0 assert(is_close(total_px_start, total_px_end, atol=1.e-15)) assert(is_close(total_py_start, total_py_end, atol=1.e-15)) @@ -230,7 +230,7 @@ def basic_product_particles_check(data): def generic_check(data): check_particle_number_conservation(data) check_energy_conservation(data) - #check_momentum_conservation(data) + check_momentum_conservation(data) check_id(data) #basic_product_particles_check(data) From a61aef31d1c0a6c6dd398efcb8c357d1e25d75a4 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Mon, 11 Jul 2022 08:06:34 -0700 Subject: [PATCH 52/63] Progress in analysis script --- .../analysis_deuterium_tritium_fusion.py | 238 ++++++------------ 1 file changed, 76 insertions(+), 162 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py index 5568af5c799..a912c6750ea 100755 --- a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py @@ -65,13 +65,13 @@ reactant_species = ['deuterium', 'tritium'] product_species = ['helium', 'neutron'] -from scipy.constants import m_u, m_p mass = { - 'deuterium': 2.01410177812*m_u, - 'tritium': 3.0160492779*m_u, - 'helium': 4.00260325413*m_u, - 'neutron': 1.0013784193052508*m_p + 'deuterium': 2.01410177812*scc.m_u, + 'tritium': 3.0160492779*scc.m_u, + 'helium': 4.00260325413*scc.m_u, + 'neutron': 1.0013784193052508*scc.m_p } +m_reduced = np.product([mass[s] for s in reactant_species])/np.sum([mass[s] for s in reactant_species]) ## Some physical parameters keV_to_Joule = scc.e*1e3 @@ -200,39 +200,11 @@ def check_id(data): complex_id = data[species_name + "_id_end"] + 1j*data[species_name + "_cpu_end"] assert(complex_id.shape == np.unique(complex_id).shape) -def basic_product_particles_check(data): - ## For each nuclear fusion reaction in the code, we create 6 alpha macroparticles. So the - ## total number of alpha macroparticles must be a multiple of 6. - num_alpha = data["alpha_w_end"].shape[0] - assert(num_alpha%6 == 0) - - ## The weight of the 6 macroparticles coming from a single fusion event should be the same. - ## We verify this here. - assert(np.array_equal(data["alpha_w_end"][::6], data["alpha_w_end"][1::6])) - assert(np.array_equal(data["alpha_w_end"][::6], data["alpha_w_end"][2::6])) - assert(np.array_equal(data["alpha_w_end"][::6], data["alpha_w_end"][3::6])) - assert(np.array_equal(data["alpha_w_end"][::6], data["alpha_w_end"][4::6])) - assert(np.array_equal(data["alpha_w_end"][::6], data["alpha_w_end"][5::6])) - - ## When we create 6 macroparticles, the first has the exact same momentum as the second, the - ## third has the same as the fourth and the fifth has the same as the sixth. We verify this - ## here - assert(np.array_equal(data["alpha_px_end"][::6], data["alpha_px_end"][1::6])) - assert(np.array_equal(data["alpha_py_end"][::6], data["alpha_py_end"][1::6])) - assert(np.array_equal(data["alpha_pz_end"][::6], data["alpha_pz_end"][1::6])) - assert(np.array_equal(data["alpha_px_end"][2::6], data["alpha_px_end"][3::6])) - assert(np.array_equal(data["alpha_py_end"][2::6], data["alpha_py_end"][3::6])) - assert(np.array_equal(data["alpha_pz_end"][2::6], data["alpha_pz_end"][3::6])) - assert(np.array_equal(data["alpha_px_end"][4::6], data["alpha_px_end"][5::6])) - assert(np.array_equal(data["alpha_py_end"][4::6], data["alpha_py_end"][5::6])) - assert(np.array_equal(data["alpha_pz_end"][4::6], data["alpha_pz_end"][5::6])) - def generic_check(data): check_particle_number_conservation(data) check_energy_conservation(data) check_momentum_conservation(data) check_id(data) - #basic_product_particles_check(data) def check_isotropy(data, relative_tolerance): ## Checks that the alpha particles are emitted isotropically @@ -242,83 +214,22 @@ def check_isotropy(data, relative_tolerance): assert(is_close(average_px_sq, average_py_sq, rtol = relative_tolerance)) assert(is_close(average_px_sq, average_pz_sq, rtol = relative_tolerance)) -def astrophysical_factor_lowE(E): - ## E is in keV - ## Returns astrophysical factor in MeV b using the low energy fit in the range E < 400 keV - ## described in equation (2) of W.M. Nevins and R. Swain, Nuclear Fusion, 40, 865 (2000) - C0 = 197. - C1 = 0.24 - C2 = 2.31e-4 - AL = 1.82e4 - EL = 148. - dEL = 2.35 - return C0 + C1*E + C2*E**2 + AL/((E-EL)**2 + dEL**2) - -def astrophysical_factor_midE(E): - ## E is in keV - ## Returns astrophysical factor in MeV b using the mid energy fit in the range - ## 400 keV < E < 642 keV described in equation (3) of W.M. Nevins and R. Swain, - ## Nuclear Fusion, 40, 865 (2000) - D0 = 330. - D1 = 66.1 - D2 = -20.3 - D5 = -1.58 - E_400 = 400. - E_100 = 100. - E_norm = (E - E_400)/E_100 - return D0 + D1*E_norm + D2*E_norm**2 + D5*E_norm**5 - -def astrophysical_factor_highE(E): - ## E is in keV - ## Returns astrophysical factor in MeV b using the high energy fit in the range - ## 642 keV < E < 3500 keV described in equation (4) of W.M. Nevins and R. Swain, - ## Nuclear Fusion, 40, 865 (2000) - A0 = 2.57e6 - A1 = 5.67e5 - A2 = 1.34e5 - A3 = 5.68e5 - E0 = 581.3 - E1 = 1083. - E2 = 2405. - E3 = 3344. - dE0 = 85.7 - dE1 = 234. - dE2 = 138. - dE3 = 309. - B = 4.38 - return A0/((E-E0)**2 + dE0**2) + A1/((E-E1)**2 + dE1**2) + \ - A2/((E-E2)**2 + dE2**2) + A3/((E-E3)**2 + dE3**2) + B - -def astrophysical_factor(E): - ## E is in keV - ## Returns astrophysical factor in MeV b using the fits described in W.M. Nevins - ## and R. Swain, Nuclear Fusion, 40, 865 (2000) - conditions = [E <= 400, E <= 642, E > 642] - choices = [astrophysical_factor_lowE(E), - astrophysical_factor_midE(E), - astrophysical_factor_highE(E)] - return np.select(conditions, choices) - -def pb_cross_section_buck_fit(E): - ## E is in MeV - ## Returns cross section in b using a power law fit of the data presented in Buck et al., - ## Nuclear Physics A, 398(2), 189-202 (1983) in the range E > 3.5 MeV. - E_start_fit = 3.5 - ## Cross section at E = E_start_fit = 3.5 MeV - cross_section_start_fit = 0.2168440845211521 - slope_fit = -2.661840717596765 - return cross_section_start_fit*(E/E_start_fit)**slope_fit - -def pb_cross_section(E): - ## E is in keV - ## Returns cross section in b using the fits described in W.M. Nevins and R. Swain, - ## Nuclear Fusion, 40, 865 (2000) for E < 3.5 MeV and a power law fit of the data presented in - ## Buck et al., Nuclear Physics A, 398(2), 189-202 (1983) for E > 3.5 MeV. - E_MeV = E/1.e3 - conditions = [E <= 3500, E > 3500] - choices = [astrophysical_factor(E)/E_MeV * np.exp(-np.sqrt(E_Gamow_MeV / E_MeV)), - pb_cross_section_buck_fit(E_MeV)] - return np.select(conditions, choices) +def cross_section( E_keV ): + ## Returns cross section in b, using the analytical fits given + ## in H.-S. Bosch and G.M. Hale 1992 Nucl. Fusion 32 611 + joule_to_keV = 1.e-3/scc.e + B_G = scc.pi * scc.alpha * np.sqrt( 2.*m_reduced * scc.c**2 * joule_to_keV ); + A1 = 6.927e4; + A2 = 7.454e8; + A3 = 2.050e6; + A4 = 5.2002e4; + B1 = 6.38e1; + B2 = -9.95e-1; + B3 = 6.981e-5; + B4 = 1.728e-4; + astrophysical_factor = (A1 + E_keV*(A2 + E_keV*(A3 + E_keV*A4))) / (1 + E_keV*(B1 + E_keV*(B2 + E_keV*(B3 + E_keV*B4)))); + millibarn_to_barn = 1.e-3; + return millibarn_to_barn * astrophysical_factor/E_keV * np.exp(-B_G/np.sqrt(E_keV)) def E_com_to_p_sq_com(m1, m2, E): ## E is the total (kinetic+mass) energy of a two particle (with mass m1 and m2) system in @@ -328,29 +239,30 @@ def E_com_to_p_sq_com(m1, m2, E): scc.c**6/(4.*E**2)*((m1**2 - m2**2)**2) def compute_relative_v_com(E): - ## E is the kinetic energy of proton+boron in the center of mass frame, in keV - ## Returns the relative velocity between proton and boron in this frame, in m/s - E_J = E*keV_to_Joule + (m_p + m_b)*scc.c**2 - p_sq = E_com_to_p_sq_com(m_p, m_b, E_J) + ## E is the kinetic energy of reactants in the center of mass frame, in keV + ## Returns the relative velocity between reactants in this frame, in m/s + m0 = mass[reactant_species[0]] + m1 = mass[reactant_species[1]] + E_J = E*keV_to_Joule + (m0 + m1)*scc.c**2 + p_sq = E_com_to_p_sq_com(m0, m1, E_J) p = np.sqrt(p_sq) - gamma_p = np.sqrt(1. + p_sq / (m_p*scc.c)**2) - gamma_b = np.sqrt(1. + p_sq / (m_b*scc.c)**2) - v_p = p/(gamma_p*m_p) - v_b = p/(gamma_b*m_b) - return v_p+v_b - -def expected_alpha_weight_com(E_com, proton_density, boron_density, dV, dt): - ## Computes expected number of produced alpha particles as a function of energy E_com in the + gamma0 = np.sqrt(1. + p_sq / (m0*scc.c)**2) + gamma1 = np.sqrt(1. + p_sq / (m1*scc.c)**2) + v0 = p/(gamma0*m0) + v1 = p/(gamma1*m1) + return v0+v1 + +def expected_weight_com(E_com, reactant0_density, reactant1_density, dV, dt): + ## Computes expected number of product particles as a function of energy E_com in the ## center of mass frame. E_com is in keV. assert(np.all(E_com>=0)) ## Case E_com == 0 is handled manually to avoid division by zero conditions = [E_com == 0, E_com > 0] ## Necessary to avoid division by 0 warning when pb_cross_section is evaluated E_com_never_zero = np.clip(E_com, 1.e-15, None) - choices = [0., pb_cross_section(E_com_never_zero)*compute_relative_v_com(E_com_never_zero)] + choices = [0., cross_section(E_com_never_zero)*compute_relative_v_com(E_com_never_zero)] sigma_times_vrel = np.select(conditions, choices) - ## Factor 3 is here because each fusion reaction produces 3 alphas - return 3.*proton_density*boron_density*sigma_times_vrel*barn_to_square_meter*dV*dt + return reactant0_density*reactant1_density*sigma_times_vrel*barn_to_square_meter*dV*dt def check_macroparticle_number(data, fusion_probability_target_value, num_pair_per_cell): ## Checks that the number of macroparticles is as expected for the first and second tests @@ -361,10 +273,9 @@ def check_macroparticle_number(data, fusion_probability_target_value, num_pair_p ## equal to the parameter fusion_probability_target_value fusion_probability_per_pair = fusion_probability_target_value expected_fusion_number = numcells*num_pair_per_cell*fusion_probability_per_pair - ## Each fusion event produces 6 alpha macroparticles - expected_macroparticle_number = 6.*expected_fusion_number - std_macroparticle_number = 6.*np.sqrt(expected_fusion_number) - actual_macroparticle_number = data["alpha_w_end"].shape[0] + expected_macroparticle_number = 2*expected_fusion_number + std_macroparticle_number = 2*np.sqrt(expected_fusion_number) + actual_macroparticle_number = data[product_species[0] + "_w_end"].shape[0] # 5 sigma test that has an intrinsic probability to fail of 1 over ~2 millions assert(is_close(actual_macroparticle_number, expected_macroparticle_number, rtol = 0., atol = 5.*std_macroparticle_number)) @@ -372,17 +283,19 @@ def check_macroparticle_number(data, fusion_probability_target_value, num_pair_p ## used in subsequent function return expected_fusion_number -def p_sq_boron_frame_to_E_COM_frame(p_proton_sq): - # Takes the proton square norm of the momentum in the boron rest frame and returns the total +def p_sq_reactant1_frame_to_E_COM_frame(p_reactant0_sq): + # Takes the reactant0 square norm of the momentum in the reactant1 rest frame and returns the total # kinetic energy in the center of mass frame. Everything is in SI units. + m0 = mass[reactant_species[0]] + m1 = mass[reactant_species[1]] # Total (kinetic + mass) energy in lab frame - E_lab = np.sqrt(p_proton_sq*scc.c**2 + (m_p*scc.c**2)**2) + m_b*scc.c**2 + E_lab = np.sqrt(p_reactant0_sq*scc.c**2 + (m0*scc.c**2)**2) + m1*scc.c**2 # Use invariant E**2 - p**2c**2 of 4-momentum norm to compute energy in center of mass frame - E_com = np.sqrt(E_lab**2 - p_proton_sq*scc.c**2) + E_com = np.sqrt(E_lab**2 - p_reactant0_sq*scc.c**2) # Corresponding kinetic energy - E_com_kin = E_com - (m_b+scc.m_p)*scc.c**2 - return E_com_kin*(p_proton_sq>0.) + E_com_kin = E_com - (m1+m0)*scc.c**2 + return E_com_kin*(p_reactant0_sq>0.) def p_sq_to_kinetic_energy(p_sq, m): ## Returns the kinetic energy of a particle as a function of its squared momentum. @@ -394,31 +307,33 @@ def compute_E_com1(data): ## Square norm of the momentum of proton/boron as a function of cell number in z direction p_sq = 2.*m_reduced*(Energy_step*np.arange(size_z)**2) - return p_sq_to_kinetic_energy(p_sq, m_b) + p_sq_to_kinetic_energy(p_sq, m_p) + Ekin = 0 + for species_name in reactant_species: + Ekin += p_sq_to_kinetic_energy( p_sq, mass[species_name] ) + return Ekin def compute_E_com2(data): ## Computes kinetic energy (in Joule) in the center of frame for the second test ## Square norm of the momentum of the proton as a function of cell number in z direction - p_proton_sq = 2.*m_p*(Energy_step*np.arange(size_z)**2) - return p_sq_boron_frame_to_E_COM_frame(p_proton_sq) + p_reactant0_sq = 2.*mass[reactant_species[0]]*(Energy_step*np.arange(size_z)**2) + return p_sq_reactant1_frame_to_E_COM_frame(p_reactant0_sq) -def check_alpha_yield(data, expected_fusion_number, E_com, proton_density, boron_density): +def check_fusion_yield(data, expected_fusion_number, E_com, reactant0_density, reactant1_density): ## Checks that the fusion yield is as expected for the first and second tests. - ## Proton and boron densities are in m^-3. - - alpha_weight_theory = expected_alpha_weight_com(E_com/keV_to_Joule, proton_density, - boron_density, dV_slice, dt) - alpha_weight_simulation = np.histogram(data["alpha_z_end"], bins=size_z, range=(0, size_z), - weights = data["alpha_w_end"])[0] + product_weight_theory = expected_weight_com(E_com/keV_to_Joule, + reactant0_density, reactant1_density, dV_slice, dt) + for species_name in product_species: + product_weight_simulation = np.histogram(data[species_name+"_z_end"], + bins=size_z, range=(0, size_z), weights = data[species_name+"_w_end"])[0] - ## -1 is here because the first slice 0 < z < 1 does not contribute to alpha creation - expected_fusion_number_per_slice = expected_fusion_number/(size_z-1) - relative_std_alpha_weight = 1./np.sqrt(expected_fusion_number_per_slice) + ## -1 is here because the first slice 0 < z < 1 does not contribute to fusion + expected_fusion_number_per_slice = expected_fusion_number/(size_z-1) + relative_std_weight = 1./np.sqrt(expected_fusion_number_per_slice) - # 5 sigma test that has an intrinsic probability to fail of 1 over ~2 millions - assert(np.all(is_close(alpha_weight_theory, alpha_weight_simulation, - rtol = 5.*relative_std_alpha_weight))) + # 5 sigma test that has an intrinsic probability to fail of 1 over ~2 millions + assert(np.all(is_close(product_weight_theory, product_weight_simulation, + rtol = 5.*relative_std_weight))) def check_initial_energy1(data, E_com): ## In WarpX, the initial momentum of the alphas is computed assuming that the fusion process @@ -582,25 +497,25 @@ def check_xy_isotropy(data): assert(average_pz_sq > average_py_sq) def specific_check1(data): - check_isotropy(data, relative_tolerance = 3.e-2) + #check_isotropy(data, relative_tolerance = 3.e-2) expected_fusion_number = check_macroparticle_number(data, fusion_probability_target_value = 0.002, num_pair_per_cell = 10000) E_com = compute_E_com1(data) - check_alpha_yield(data, expected_fusion_number, E_com, proton_density = 1., - boron_density = 1.) - check_initial_energy1(data, E_com) + check_fusion_yield(data, expected_fusion_number, E_com, reactant0_density = 1., + reactant1_density = 1.) + #check_initial_energy1(data, E_com) def specific_check2(data): - check_xy_isotropy(data) - ## Only 900 particles pairs per cell here because we ignore the 10% of protons that are at rest + #check_xy_isotropy(data) + ## Only 900 particles pairs per cell here because we ignore the 10% of reactants that are at rest expected_fusion_number = check_macroparticle_number(data, fusion_probability_target_value = 0.02, num_pair_per_cell = 900) E_com = compute_E_com2(data) - check_alpha_yield(data, expected_fusion_number, E_com, proton_density = 1.e20, - boron_density = 1.e26) - check_initial_energy2(data) + check_fusion_yield(data, expected_fusion_number, E_com, reactant0_density = 1.e20, + reactant1_density = 1.e26) + #check_initial_energy2(data) def check_charge_conservation(rho_start, rho_end): assert(np.all(is_close(rho_start, rho_end, rtol=2.e-11))) @@ -632,8 +547,7 @@ def main(): generic_check(data) # Checks that are specific to test number i - # TODO: activate code below - # eval("specific_check"+str(i)+"(data)") + eval("specific_check"+str(i)+"(data)") rho_start = field_data_start["rho"].to_ndarray() rho_end = field_data_end["rho"].to_ndarray() From d1bd3221c9ebe75c19c318ee118c726c914a003d Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 12 Jul 2022 02:34:19 -0700 Subject: [PATCH 53/63] Fix error in the initial energy of the deuterium particles --- .../nuclear_fusion/analysis_deuterium_tritium_fusion.py | 6 ------ Examples/Modules/nuclear_fusion/inputs_deuterium_tritium | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py index e436ad71acd..1f8534b7d68 100755 --- a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py @@ -65,11 +65,6 @@ reactant_species = ['deuterium', 'tritium'] product_species = ['helium', 'neutron'] -<<<<<<< HEAD -======= -from scipy.constants import m_p, m_u - ->>>>>>> b11812de097d8c120b952460559af23a76258d5b mass = { 'deuterium': 2.01410177812*scc.m_u, 'tritium': 3.0160492779*scc.m_u, @@ -331,7 +326,6 @@ def check_fusion_yield(data, expected_fusion_number, E_com, reactant0_density, r for species_name in product_species: product_weight_simulation = np.histogram(data[species_name+"_z_end"], bins=size_z, range=(0, size_z), weights = data[species_name+"_w_end"])[0] - ## -1 is here because the first slice 0 < z < 1 does not contribute to fusion expected_fusion_number_per_slice = expected_fusion_number/(size_z-1) relative_std_weight = 1./np.sqrt(expected_fusion_number_per_slice) diff --git a/Examples/Modules/nuclear_fusion/inputs_deuterium_tritium b/Examples/Modules/nuclear_fusion/inputs_deuterium_tritium index 9f5ce8b8bfc..575e9c42888 100644 --- a/Examples/Modules/nuclear_fusion/inputs_deuterium_tritium +++ b/Examples/Modules/nuclear_fusion/inputs_deuterium_tritium @@ -85,7 +85,7 @@ deuterium2.momentum_distribution_type = "parse_momentum_function" deuterium2.momentum_function_ux(x,y,z) = 0. deuterium2.momentum_function_uy(x,y,z) = 0. deuterium2.momentum_function_uz(x,y,z) = "if(y - floor(y) < 0.1, - 0., sqrt(2*m_p*Energy_step*(floor(z)**2))/(m_deuterium*clight))" + 0., sqrt(2*m_deuterium*Energy_step*(floor(z)**2))/(m_deuterium*clight))" deuterium2.do_not_push = 1 deuterium2.do_not_deposit = 1 From e29d5ab68019e1cc869e633a2b5aa43ddcfe682e Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 12 Jul 2022 02:38:12 -0700 Subject: [PATCH 54/63] Add check of isotropy --- .../analysis_deuterium_tritium_fusion.py | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py index 1f8534b7d68..c77551d5440 100755 --- a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py @@ -207,12 +207,23 @@ def generic_check(data): check_id(data) def check_isotropy(data, relative_tolerance): - ## Checks that the alpha particles are emitted isotropically - average_px_sq = np.average(data["alpha_px_end"]*data["alpha_px_end"]) - average_py_sq = np.average(data["alpha_py_end"]*data["alpha_py_end"]) - average_pz_sq = np.average(data["alpha_pz_end"]*data["alpha_pz_end"]) - assert(is_close(average_px_sq, average_py_sq, rtol = relative_tolerance)) - assert(is_close(average_px_sq, average_pz_sq, rtol = relative_tolerance)) + ## Checks that the product particles are emitted isotropically + for species_name in product_species: + average_px_sq = np.average(data[species_name+"_px_end"]*data[species_name+"_px_end"]) + average_py_sq = np.average(data[species_name+"_py_end"]*data[species_name+"_py_end"]) + average_pz_sq = np.average(data[species_name+"_pz_end"]*data[species_name+"_pz_end"]) + assert(is_close(average_px_sq, average_py_sq, rtol = relative_tolerance)) + assert(is_close(average_px_sq, average_pz_sq, rtol = relative_tolerance)) + +def check_xy_isotropy(data): + ## Checks that the alpha particles are emitted isotropically in x and y + for species_name in product_species: + average_px_sq = np.average(data[species_name+"_px_end"]*data[species_name+"_px_end"]) + average_py_sq = np.average(data[species_name+"_py_end"]*data[species_name+"_py_end"]) + average_pz_sq = np.average(data[species_name+"_pz_end"]*data[species_name+"_pz_end"]) + assert(is_close(average_px_sq, average_py_sq, rtol = 5.e-2)) + assert(average_pz_sq > average_px_sq) + assert(average_pz_sq > average_py_sq) def cross_section( E_keV ): ## Returns cross section in b, using the analytical fits given @@ -486,17 +497,8 @@ def check_initial_energy2(data): assert(is_close(np.amax(energy_alpha3_simulation), max_energy_alpha23, rtol=2.5e-1)) assert(is_close(np.amin(energy_alpha3_simulation), min_energy_alpha23, rtol=2.5e-1)) -def check_xy_isotropy(data): - ## Checks that the alpha particles are emitted isotropically in x and y - average_px_sq = np.average(data["alpha_px_end"]*data["alpha_px_end"]) - average_py_sq = np.average(data["alpha_py_end"]*data["alpha_py_end"]) - average_pz_sq = np.average(data["alpha_pz_end"]*data["alpha_pz_end"]) - assert(is_close(average_px_sq, average_py_sq, rtol = 5.e-2)) - assert(average_pz_sq > average_px_sq) - assert(average_pz_sq > average_py_sq) - def specific_check1(data): - #check_isotropy(data, relative_tolerance = 3.e-2) + check_isotropy(data, relative_tolerance = 3.e-2) expected_fusion_number = check_macroparticle_number(data, fusion_probability_target_value = 0.002, num_pair_per_cell = 10000) @@ -506,7 +508,7 @@ def specific_check1(data): #check_initial_energy1(data, E_com) def specific_check2(data): - #check_xy_isotropy(data) + check_xy_isotropy(data) ## Only 900 particles pairs per cell here because we ignore the 10% of reactants that are at rest expected_fusion_number = check_macroparticle_number(data, fusion_probability_target_value = 0.02, From a1171506a0a94701ec87fcf2ccb3f3c8fa7326a0 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 12 Jul 2022 02:47:23 -0700 Subject: [PATCH 55/63] Clean up the test script --- .../analysis_deuterium_tritium_fusion.py | 205 ++---------------- 1 file changed, 19 insertions(+), 186 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py index c77551d5440..cb3463a55ee 100755 --- a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py @@ -1,5 +1,5 @@ #! /usr/bin/env python -# Copyright 2021 Neil Zaim +# Copyright 2022 Neil Zaim, Remi Lehe # # This file is part of WarpX. # @@ -15,41 +15,29 @@ import numpy as np import scipy.constants as scc -## This script performs various checks for the proton boron nuclear fusion module. The simulation -## that we check is made of 5 different tests, each with different proton, boron and alpha species. +## This script performs various checks for the fusion module. The simulation +## that we check is made of 2 different tests, each with different reactant and product species. ## -## The first test is performed in the proton-boron center of mass frame. It could correspond to the -## physical case of a proton beam colliding with a boron beam. The kinetic energy of the colliding +## The first test is performed in the center of mass frame of the reactant. It could correspond to the +## physical case of two beams colliding with each other. The kinetic energy of the colliding ## particles depends on the cell number in the z direction and varies in the few keV to few MeV ## range. All the particles within a cell have the exact same momentum, which allows detailed -## checks of the energy of produced alpha particles. The proton and boron species have the same -## density and number of particles in this test. The number of produced alphas is much smaller than -## the initial number of protons and borons. +## checks of the energy of produced alpha particles. The reactant species have the same +## density and number of particles in this test. The number of product species is much smaller than +## the initial number of reactants ## -## The second test is performed in the boron rest frame. It corresponds to the physical case of a -## low density proton beam colliding with a high-density proton+boron target. The energy of the -## proton beam is varied in the few keV to few MeV range, depending on the cell number in the z +## The second test is performed in the rest frame of the second reactant. It corresponds to the +## physical case of a low density beam colliding with a high-density mixed target. The energy of the +## beam particles is varied in the few keV to few MeV range, depending on the cell number in the z ## direction. As in the previous case, all the particles within a cell have the exact same -## momentum, which allows detailed checks of the energy of produced alpha particles. In this test, -## there are 100 immobile boron and 100 immobile proton macroparticles per cell, as well as 900 -## beam proton macroparticles per cell. The density of the immobile particles is 6 orders of +## momentum, which allows detailed checks of the energy of product particles. In this test, +## there are 100 immobile macroparticles for each reactant per cell, as well as 900 +## of the beam reactant macroparticles per cell. The density of the immobile particles is 6 orders of ## magnitude higher than the number of beam particles, which means that they have a much higher ## weight. This test is similar to the example given in section 3 of Higginson et al., ## Journal of Computation Physics, 388 439–453 (2019), which was found to be sensitive to the way -## unsampled pairs are accounted for. As before, the number of produced alphas is much smaller than -## the initial number of protons and borons. -## -## The third test corresponds to a Maxwellian plasma with a 44 keV temperature. The alpha yield is -## directly compared to the analytical fits of W.M. Nevins and R. Swain, Nuclear Fusion, 40, 865 -## (2000) for a thermal plasma. -## -## The fourth test corresponds to a plasma with an extremely small boron density, so that all boron -## macroparticles should have disappeared by the end of the simulation, which we verify. -## -## The fifth test is exactly the same as the fourth test, except that the -## fusion_probability_threshold parameter is increased to an excessive value. Because of that, we -## severely underestimate the fusion yield and boron macroparticles remain at the end of the -## simulation, which we verify. +## unsampled pairs are accounted for. As before, the number of product particles is much smaller than +## the initial number of reactants. ## ## In all simulations, we check particle number, charge, momentum and energy conservation and ## perform basic checks regarding the produced particles. When possible, we also compare the number @@ -120,8 +108,7 @@ def add_species_to_dict(yt_ad, data_dict, species_name, prefix, suffix): add_existing_species_to_dict(yt_ad, data_dict, species_name, prefix, suffix) except yt.utilities.exceptions.YTFieldNotFound: ## If species does not exist, we avoid python crash and add empty arrays to the - ## dictionnary. Currently, this happens for the boron species in test number 4, which - ## entirely fuses into alphas. + ## dictionnary. add_empty_species_to_dict(data_dict, species_name, prefix, suffix) def check_particle_number_conservation(data): @@ -316,7 +303,7 @@ def p_sq_to_kinetic_energy(p_sq, m): def compute_E_com1(data): ## Computes kinetic energy (in Joule) in the center of frame for the first test - ## Square norm of the momentum of proton/boron as a function of cell number in z direction + ## Square norm of the momentum of reactant as a function of cell number in z direction p_sq = 2.*m_reduced*(Energy_step*np.arange(size_z)**2) Ekin = 0 for species_name in reactant_species: @@ -326,7 +313,7 @@ def compute_E_com1(data): def compute_E_com2(data): ## Computes kinetic energy (in Joule) in the center of frame for the second test - ## Square norm of the momentum of the proton as a function of cell number in z direction + ## Square norm of the momentum of reactant0 as a function of cell number in z direction p_reactant0_sq = 2.*mass[reactant_species[0]]*(Energy_step*np.arange(size_z)**2) return p_sq_reactant1_frame_to_E_COM_frame(p_reactant0_sq) @@ -345,158 +332,6 @@ def check_fusion_yield(data, expected_fusion_number, E_com, reactant0_density, r assert(np.all(is_close(product_weight_theory, product_weight_simulation, rtol = 5.*relative_std_weight))) -def check_initial_energy1(data, E_com): - ## In WarpX, the initial momentum of the alphas is computed assuming that the fusion process - ## takes place in two steps: - ## (1): proton + boron 11 -> alpha + beryllium 8 - ## (2): beryllium 8 -> alpha + alpha - ## The alpha generated in the first step (labeled alpha1) generally has a different initial - ## energy distribution than the alphas generated in the second step (labeled alpha2 and - ## alpha3). - ## In the first test, we are in the center of mass frame. Therefore, the momentum of alpha1 is - ## entirely determined by the energy in the center of mass frame, so we check in this function - ## that the energy of the alpha1 macroparticles is as expected. On the other hand, the energy - ## of alpha2 and alpha3 follows a continuous distribution within a given range. In this test, - ## we check that this range is as expected by comparing the maximum and minimum energy of the - ## obtained macroparticles to the theoretical maximum and minimum. - ## Note that in the simulations, 6 macroparticles are generated during for each fusion event. - ## The first and second macroparticles are alpha1 particles. The third and fourth are alpha2. - ## The fifth and sixth are alpha3. - - energy_alpha_simulation = compute_energy_array(data, "alpha", "end", m_a) - z_alpha = data["alpha_z_end"] - - # Loop over all slices (i.e. cells in the z direction) - for slice_number in range(1, size_z): - ## Kinetic energy in the lab frame before fusion - E_kinetic_com_before = E_com[slice_number] - ## Total (kinetic + mass) energy in the lab frame after - ## proton + boron 11 -> alpha + beryllium 8 - E_total_com_after = E_kinetic_com_before + E_fusion + (m_a + m_be)*scc.c**2 - ## Corresponding momentum norm squared of alpha1/beryllium - p_sq_after = E_com_to_p_sq_com(m_a, m_be, E_total_com_after) - ## Corresponding kinetic energy for alpha1 - energy_alpha1_theory = p_sq_to_kinetic_energy(p_sq_after, m_a) - ## Corresponding kinetic energy for beryllium - energy_beryllium_theory = p_sq_to_kinetic_energy(p_sq_after, m_be) - ## Corresponding kinetic energy for alpha2 + alpha3 after beryllium decay - energy_alpha2_plus_3_theory = energy_beryllium_theory + E_decay - ## Compute the theoretical maximum and minimum energy of alpha2 and alpha3. This - ## calculation is done nonrelativistically, by noting that the maximum (minimum) energy - ## corresponds to an alpha emitted exactly in the (opposite) direction of the beryllium - ## in the center of mass frame. This calculation involves solving a polynomial equation of - ## order 2 in p_alpha23. - max_p_alpha23 = 0.5*(np.sqrt(p_sq_after) + \ - np.sqrt(4*m_a*energy_alpha2_plus_3_theory - p_sq_after)) - min_p_alpha23 = 0.5*(np.sqrt(p_sq_after) - \ - np.sqrt(4*m_a*energy_alpha2_plus_3_theory - p_sq_after)) - max_energy_alpha23 = max_p_alpha23**2/(2.*m_a) - min_energy_alpha23 = min_p_alpha23**2/(2.*m_a) - - ## Get the energy of all alphas in the slice - energy_alpha_slice = energy_alpha_simulation[(z_alpha >= slice_number)* \ - (z_alpha < (slice_number + 1))] - ## Energy of alphas1 (here, first macroparticle of each fusion event) in the slice - energy_alpha1_simulation = energy_alpha_slice[::6] - ## Energy of alphas2 (here, third macroparticle of each fusion event) in the slice - energy_alpha2_simulation = energy_alpha_slice[2::6] - ## Energy of alphas3 (here, fifth macroparticle of each fusion event) in the slice - energy_alpha3_simulation = energy_alpha_slice[4::6] - - assert(np.all(is_close(energy_alpha1_simulation, energy_alpha1_theory, rtol=5.e-8))) - assert(is_close(np.amax(energy_alpha2_simulation), max_energy_alpha23, rtol=1.e-2)) - assert(is_close(np.amin(energy_alpha2_simulation), min_energy_alpha23, rtol=1.e-2)) - assert(is_close(np.amax(energy_alpha3_simulation), max_energy_alpha23, rtol=1.e-2)) - assert(is_close(np.amin(energy_alpha3_simulation), min_energy_alpha23, rtol=1.e-2)) - -def check_initial_energy2(data): - ## In WarpX, the initial momentum of the alphas is computed assuming that the fusion process - ## takes place in two steps: - ## (1): proton + boron 11 -> alpha + beryllium 8 - ## (2): beryllium 8 -> alpha + alpha - ## The alpha generated in the first step (labeled alpha1) generally has a different initial - ## energy distribution than the alphas generated in the second step (labeled alpha2 and - ## alpha3). - ## In the second test, we are in the boron rest frame. In this case, the momentum of each alpha - ## follows a continuous distribution within a given range. In this function, we verify that - ## this range is as expected by comparing the maximum and minimum energy of the obtained - ## macroparticles to the theoretical maximum and minimum. Be aware that the range for alpha1 - ## is not the same as the range for alpha2 and alpha3 (typically alpha1 particles will carry - ## more energy). - ## Note that in the simulations, 6 macroparticles are generated during for each fusion event. - ## The first and second macroparticles are alpha1 particles. The third and fourth are alpha2. - ## The fifth and sixth are alpha3. - - energy_alpha_simulation = compute_energy_array(data, "alpha", "end", m_a) - z_alpha = data["alpha_z_end"] - - # Loop over all slices (i.e. cells in the z direction) - for slice_number in range(1, size_z): - ## For simplicity, all the calculations in this functino are done nonrelativistically - ## Proton kinetic energy in the lab frame before fusion - E_proton_nonrelativistic = Energy_step*slice_number**2 - ## Corresponding square norm of proton momentum - p_proton_sq = 2.*scc.m_p*E_proton_nonrelativistic - ## Kinetic energy in the lab frame after - ## proton + boron 11 -> alpha + beryllium 8 - E_after_fusion = E_proton_nonrelativistic + E_fusion - - ## Compute the theoretical maximum and minimum energy of alpha1 in the lab frame. This - ## calculation is done by noting that the maximum (minimum) energy corresponds to an alpha - ## emitted exactly in the (opposite) direction of the proton in the lab frame. This - ## calculation involves solving a polynomial equation of order 2 in p_alpha1. - max_p_alpha1 = (m_a/m_be*np.sqrt(p_proton_sq) + \ - np.sqrt(-m_a/m_be*p_proton_sq + 2.*E_after_fusion*m_a*(m_a/m_be + 1.))) / \ - (m_a/m_be + 1.) - min_p_alpha1 = (m_a/m_be*np.sqrt(p_proton_sq) - \ - np.sqrt(-m_a/m_be*p_proton_sq + 2.*E_after_fusion*m_a*(m_a/m_be + 1.))) / \ - (m_a/m_be + 1.) - max_energy_alpha1 = max_p_alpha1**2/(2*m_a) - min_energy_alpha1 = min_p_alpha1**2/(2*m_a) - - ## Corresponding max/min kinetic energy of Beryllium in the lab frame - max_E_beryllium = E_after_fusion - min_energy_alpha1 - min_E_beryllium = E_after_fusion - max_energy_alpha1 - ## Corresponding max/min momentum square of Beryllium in the lab frame - max_p_sq_beryllium = 2.*m_be*max_E_beryllium - min_p_sq_beryllium = 2.*m_be*min_E_beryllium - ## Corresponding max/min kinetic energy in the lab frame for alpha2 + alpha3 after - ## Beryllium decay - max_energy_alpha2_plus_3 = max_E_beryllium + E_decay - min_energy_alpha2_plus_3 = min_E_beryllium + E_decay - - ## Compute the theoretical maximum and minimum energy of alpha2 and alpha3 in the lab - ## frame. This calculation is done by noting that the maximum (minimum) energy corresponds - ## to an alpha emitted exactly in the (opposite) direction of a beryllium with energy - ## max_E_beryllium (min_E_beryllium). This calculation involves solving a polynomial - ## equation of order 2 in p_alpha23. - max_p_alpha23 = 0.5*(np.sqrt(max_p_sq_beryllium) + \ - np.sqrt(4*m_a*max_energy_alpha2_plus_3 - max_p_sq_beryllium)) - min_p_alpha23 = 0.5*(np.sqrt(min_p_sq_beryllium) - \ - np.sqrt(4*m_a*min_energy_alpha2_plus_3 - min_p_sq_beryllium)) - max_energy_alpha23 = max_p_alpha23**2/(2*m_a) - min_energy_alpha23 = min_p_alpha23**2/(2*m_a) - - ## Get the energy of all alphas in the slice - energy_alpha_slice = energy_alpha_simulation[(z_alpha >= slice_number)* \ - (z_alpha < (slice_number + 1))] - ## Energy of alphas1 (here, first macroparticle of each fusion event) in the slice - energy_alpha1_simulation = energy_alpha_slice[::6] - ## Energy of alphas2 (here, third macroparticle of each fusion event) in the slice - energy_alpha2_simulation = energy_alpha_slice[2::6] - ## Energy of alphas3 (here, fifth macroparticle of each fusion event) in the slice - energy_alpha3_simulation = energy_alpha_slice[4::6] - - assert(is_close(np.amax(energy_alpha1_simulation), max_energy_alpha1, rtol=1.e-2)) - assert(is_close(np.amin(energy_alpha1_simulation), min_energy_alpha1, rtol=1.e-2)) - ## Tolerance is quite high below because we don't have a lot of alphas to produce good - ## statistics and an event like alpha1 emitted exactly in direction of proton & alpha2 - ## emitted exactly in direction opposite to Beryllium is somewhat rare. - assert(is_close(np.amax(energy_alpha2_simulation), max_energy_alpha23, rtol=2.5e-1)) - assert(is_close(np.amin(energy_alpha2_simulation), min_energy_alpha23, rtol=2.5e-1)) - assert(is_close(np.amax(energy_alpha3_simulation), max_energy_alpha23, rtol=2.5e-1)) - assert(is_close(np.amin(energy_alpha3_simulation), min_energy_alpha23, rtol=2.5e-1)) - def specific_check1(data): check_isotropy(data, relative_tolerance = 3.e-2) expected_fusion_number = check_macroparticle_number(data, @@ -505,7 +340,6 @@ def specific_check1(data): E_com = compute_E_com1(data) check_fusion_yield(data, expected_fusion_number, E_com, reactant0_density = 1., reactant1_density = 1.) - #check_initial_energy1(data, E_com) def specific_check2(data): check_xy_isotropy(data) @@ -516,7 +350,6 @@ def specific_check2(data): E_com = compute_E_com2(data) check_fusion_yield(data, expected_fusion_number, E_com, reactant0_density = 1.e20, reactant1_density = 1.e26) - #check_initial_energy2(data) def check_charge_conservation(rho_start, rho_end): assert(np.all(is_close(rho_start, rho_end, rtol=2.e-11))) From e7872501f3cb359fab303e318ab4ffd3585f1c82 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 12 Jul 2022 05:33:26 -0700 Subject: [PATCH 56/63] Rewrite p_sq formula in a way to avoids machine-precision negative numbers --- .../analysis_deuterium_tritium_fusion.py | 4 ++-- .../analysis_proton_boron_fusion.py | 4 ++-- .../NuclearFusion/SingleNuclearFusionEvent.H | 17 +++++++++-------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py index cb3463a55ee..38c31c10edd 100755 --- a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py @@ -233,8 +233,8 @@ def E_com_to_p_sq_com(m1, m2, E): ## E is the total (kinetic+mass) energy of a two particle (with mass m1 and m2) system in ## its center of mass frame, in J. ## Returns the square norm of the momentum of each particle in that frame. - return E**2/(4.*scc.c**2) - (m1**2 + m2**2)*scc.c**2/2. + \ - scc.c**6/(4.*E**2)*((m1**2 - m2**2)**2) + E_ratio = E/((m1+m2)*scc.c**2) + return m1*m2*scc.c**2 * (E_ratio**2 - 1) + (m1-m2)**2*scc.c**2/4 * (E_ratio - 1./E_ratio)**2 def compute_relative_v_com(E): ## E is the kinetic energy of reactants in the center of mass frame, in keV diff --git a/Examples/Modules/nuclear_fusion/analysis_proton_boron_fusion.py b/Examples/Modules/nuclear_fusion/analysis_proton_boron_fusion.py index 37b680deea1..d0e35047741 100755 --- a/Examples/Modules/nuclear_fusion/analysis_proton_boron_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_proton_boron_fusion.py @@ -323,8 +323,8 @@ def E_com_to_p_sq_com(m1, m2, E): ## E is the total (kinetic+mass) energy of a two particle (with mass m1 and m2) system in ## its center of mass frame, in J. ## Returns the square norm of the momentum of each particle in that frame. - return E**2/(4.*scc.c**2) - (m1**2 + m2**2)*scc.c**2/2. + \ - scc.c**6/(4.*E**2)*((m1**2 - m2**2)**2) + E_ratio = E/((m1+m2)*scc.c**2) + return m1*m2*scc.c**2 * (E_ratio**2 - 1) + (m1-m2)**2*scc.c**2/4 * (E_ratio - 1./E_ratio)**2 def compute_relative_v_com(E): ## E is the kinetic energy of proton+boron in the center of mass frame, in keV diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/SingleNuclearFusionEvent.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/SingleNuclearFusionEvent.H index c68680b82b5..4df0c583eae 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/SingleNuclearFusionEvent.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/SingleNuclearFusionEvent.H @@ -76,7 +76,6 @@ void SingleNuclearFusionEvent (const amrex::ParticleReal& u1x, const amrex::Part const amrex::ParticleReal w_max = amrex::max(w1, w2); constexpr auto one_pr = amrex::ParticleReal(1.); - constexpr auto inv_two_pr = amrex::ParticleReal(1./2.); constexpr auto inv_four_pr = amrex::ParticleReal(1./4.); constexpr amrex::ParticleReal c_sq = PhysConst::c * PhysConst::c; constexpr amrex::ParticleReal inv_csq = one_pr / ( c_sq ); @@ -108,7 +107,8 @@ void SingleNuclearFusionEvent (const amrex::ParticleReal& u1x, const amrex::Part const amrex::ParticleReal E_star_sq = E_lab*E_lab - c_sq*p_total_sq; // Kinetic energy in the center of mass frame - const amrex::ParticleReal E_kin_star = std::sqrt(E_star_sq) - (m1 + m2)*c_sq; + const amrex::ParticleReal E_star = std::sqrt(E_star_sq); + const amrex::ParticleReal E_kin_star = E_star - (m1 + m2)*c_sq; // Compute fusion cross section as a function of kinetic energy in the center of mass frame auto fusion_cross_section = amrex::ParticleReal(0.); @@ -123,14 +123,15 @@ void SingleNuclearFusionEvent (const amrex::ParticleReal& u1x, const amrex::Part // Square of the norm of the momentum of one of the particles in the center of mass frame // Formula obtained by inverting E^2 = p^2*c^2 + m^2*c^4 in the COM frame for each particle - auto constexpr pow3 = [](double const x) { return x*x*x; }; - const amrex::ParticleReal p_star_sq = - E_star_sq*inv_four_pr*inv_csq - (m1_sq + m2_sq)*c_sq*inv_two_pr + - pow3(c_sq) * inv_four_pr * pow2(m1_sq - m2_sq) / E_star_sq; + // The expression below is specifically written in a form that avoids returning + // small negative numbers due to machine precision errors, for low-energy particles + const amrex::ParticleReal E_ratio = E_star/((m1 + m2)*c_sq); + const amrex::ParticleReal p_star_sq = m1*m2*c_sq * ( pow2(E_ratio) - one_pr ) + + pow2(m1 - m2)*c_sq*inv_four_pr * pow2( E_ratio - 1._prt/E_ratio ); // Lorentz factors in the center of mass frame - const amrex::ParticleReal g1_star = std::sqrt(1._prt + p_star_sq / (m1_sq*c_sq)); - const amrex::ParticleReal g2_star = std::sqrt(1._prt + p_star_sq / (m2_sq*c_sq)); + const amrex::ParticleReal g1_star = std::sqrt(one_pr + p_star_sq / (m1_sq*c_sq)); + const amrex::ParticleReal g2_star = std::sqrt(one_pr + p_star_sq / (m2_sq*c_sq)); // relative velocity in the center of mass frame const amrex::ParticleReal v_rel = std::sqrt(p_star_sq) * (one_pr/(m1*g1_star) + From b45e99d4950f6905802b196563bb06ca590f1304 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 12 Jul 2022 05:58:13 -0700 Subject: [PATCH 57/63] Add checksum --- .../Deuterium_Tritium_Fusion_3D.json | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 Regression/Checksum/benchmarks_json/Deuterium_Tritium_Fusion_3D.json diff --git a/Regression/Checksum/benchmarks_json/Deuterium_Tritium_Fusion_3D.json b/Regression/Checksum/benchmarks_json/Deuterium_Tritium_Fusion_3D.json new file mode 100644 index 00000000000..8c793d014a5 --- /dev/null +++ b/Regression/Checksum/benchmarks_json/Deuterium_Tritium_Fusion_3D.json @@ -0,0 +1,93 @@ +{ + "deuterium1": { + "particle_cpu": 5120000.0, + "particle_id": 26214405120000.0, + "particle_momentum_x": 0.0, + "particle_momentum_y": 0.0, + "particle_momentum_z": 2.8875978729147693e-13, + "particle_position_x": 40960140.72983793, + "particle_position_y": 40959772.69310104, + "particle_position_z": 81919021.52308556, + "particle_weight": 1024.000000000021 + }, + "deuterium2": { + "particle_cpu": 512000.0, + "particle_id": 10747904512000.0, + "particle_momentum_x": 0.0, + "particle_momentum_y": 0.0, + "particle_momentum_z": 3.356807324363973e-14, + "particle_position_x": 4095630.698135355, + "particle_position_y": 4096073.5517983637, + "particle_position_z": 8191737.5566503005, + "particle_weight": 1.0227810240779905e+29 + }, + "helium1": { + "particle_cpu": 20564.0, + "particle_id": 414455929591.0, + "particle_momentum_x": 1.752459522386588e-15, + "particle_momentum_y": 1.7528165107122235e-15, + "particle_momentum_z": 1.7485096000550826e-15, + "particle_position_x": 154379.32401483235, + "particle_position_y": 152618.63815943015, + "particle_position_z": 325970.4138010667, + "particle_weight": 4.421535775967805e-28 + }, + "helium2": { + "particle_cpu": 18146.0, + "particle_id": 370840895571.0, + "particle_momentum_x": 1.5335366853772491e-15, + "particle_momentum_y": 1.5332896925711041e-15, + "particle_momentum_z": 1.7639633745850731e-15, + "particle_position_x": 137011.89739173267, + "particle_position_y": 136605.24328988983, + "particle_position_z": 290143.4673994485, + "particle_weight": 5.756530048087129e+18 + }, + "lev=0": { + "rho": 0.0 + }, + "neutron1": { + "particle_cpu": 20564.0, + "particle_id": 415194438443.0, + "particle_momentum_x": 1.752459522386588e-15, + "particle_momentum_y": 1.7528165107122235e-15, + "particle_momentum_z": 1.7485096000550826e-15, + "particle_position_x": 154379.32401483235, + "particle_position_y": 152618.63815943015, + "particle_position_z": 325970.4138010667, + "particle_weight": 4.421535775967805e-28 + }, + "neutron2": { + "particle_cpu": 18146.0, + "particle_id": 371427197911.0, + "particle_momentum_x": 1.5335366853772491e-15, + "particle_momentum_y": 1.5332896925711041e-15, + "particle_momentum_z": 1.5497361118073471e-15, + "particle_position_x": 137011.89739173267, + "particle_position_y": 136605.24328988983, + "particle_position_z": 290143.4673994485, + "particle_weight": 5.756530048087129e+18 + }, + "tritium1": { + "particle_cpu": 5120000.0, + "particle_id": 78643205120000.0, + "particle_momentum_x": 0.0, + "particle_momentum_y": 0.0, + "particle_momentum_z": 2.8875978729147693e-13, + "particle_position_x": 40958301.591654316, + "particle_position_y": 40961136.14476712, + "particle_position_z": 81920546.19181262, + "particle_weight": 1024.000000000021 + }, + "tritium2": { + "particle_cpu": 51200.0, + "particle_id": 1103626291200.0, + "particle_momentum_x": 0.0, + "particle_momentum_y": 0.0, + "particle_momentum_z": 0.0, + "particle_position_x": 409798.0158217681, + "particle_position_y": 409670.9858143465, + "particle_position_z": 819255.8152412223, + "particle_weight": 1.0239999999424347e+29 + } +} \ No newline at end of file From 471e2634eb824bcba5b26703a4f7b3bf19ac1587 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Tue, 12 Jul 2022 06:10:56 -0700 Subject: [PATCH 58/63] Clean up code --- .../NuclearFusion/TwoProductFusionInitializeMomentum.H | 9 +++++++-- .../Collision/BinaryCollision/ParticleCreationFunc.H | 5 +---- .../Collision/BinaryCollision/ParticleCreationFunc.cpp | 5 ++++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H index 8bcc114902f..6cb936a4b58 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H @@ -37,12 +37,17 @@ namespace { * @param[in] soa1_in struct of array data of the first colliding species * @param[in] soa2_in struct of array data of the second colliding species * or tritium) - * @param[out] ... + * @param[out] soa1_out struct of array data of the first product species + * @param[out] soa2_out struct of array data of the first product species * @param[in] idx1_in index of first colliding macroparticle * @param[in] idx2_in index of second colliding macroparticle - * @param[in]... + * @param[in] idx1_out index of first product macroparticle + * @param[in] idx2_out index of second product macroparticle * @param[in] m1_in mass of first colliding species * @param[in] m2_in mass of second colliding species + * @param[in] m1_out mass of first product species + * @param[in] m2_out mass of second product species + * @param[in] F_fusion energy released in the fusion reaction * @param[in] engine the random engine */ AMREX_GPU_HOST_DEVICE AMREX_INLINE diff --git a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H index 3dc05127648..ca01ba0a01c 100644 --- a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H +++ b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H @@ -225,15 +225,12 @@ public: p_pair_indices_1[i], p_pair_indices_2[i], product_start_index, m1, m2, engine); } - else + else if (t_collision_type == CollisionType::DeuteriumTritiumFusion) { - // TODO: Assert that there are exactly 2 products - amrex::ParticleReal fusion_energy = 0; if (t_collision_type == CollisionType::DeuteriumTritiumFusion) { fusion_energy = 17.6e6_prt * PhysConst::q_e; // 17.6 MeV } - // TODO: Add exception for other collision types TwoProductFusionInitializeMomentum(soa_1, soa_2, soa_products_data[0], soa_products_data[1], p_pair_indices_1[i], p_pair_indices_2[i], diff --git a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.cpp b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.cpp index 41e10434f02..bab92e48610 100644 --- a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.cpp +++ b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.cpp @@ -45,7 +45,10 @@ ParticleCreationFunc::ParticleCreationFunc (const std::string collision_name, m_num_products_device.push_back(1); #endif } - // TODO: Raise error otherwise + else + { + amrex::Abort("Unknown collision type in ParticleCreationFunc"); + } #ifdef AMREX_USE_GPU m_num_products_device.resize(m_num_product_species); From e6efe570911d67c68e84e48a80f3e11bdf07117e Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Wed, 13 Jul 2022 13:07:12 -0700 Subject: [PATCH 59/63] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Neïl Zaim <49716072+NeilZaim@users.noreply.github.com> --- .../BinaryCollision/NuclearFusion/NuclearFusionFunc.H | 2 +- .../NuclearFusion/TwoProductFusionInitializeMomentum.H | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H index bdd34f933c6..8e4e9d3270d 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H @@ -72,7 +72,7 @@ public: { WARPX_ALWAYS_ASSERT_WITH_MESSAGE( product_species_name.size() == 2, - "ERROR: Deuterium-tritium must contain exactly two product species"); + "ERROR: Deuterium-tritium fusion must contain exactly two product species"); auto& product_species1 = mypc->GetParticleContainerFromName(product_species_name[0]); auto& product_species2 = mypc->GetParticleContainerFromName(product_species_name[1]); WARPX_ALWAYS_ASSERT_WITH_MESSAGE( diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H index 6cb936a4b58..7b378d1f221 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H @@ -36,18 +36,17 @@ namespace { * * @param[in] soa1_in struct of array data of the first colliding species * @param[in] soa2_in struct of array data of the second colliding species - * or tritium) * @param[out] soa1_out struct of array data of the first product species * @param[out] soa2_out struct of array data of the first product species * @param[in] idx1_in index of first colliding macroparticle * @param[in] idx2_in index of second colliding macroparticle - * @param[in] idx1_out index of first product macroparticle - * @param[in] idx2_out index of second product macroparticle + * @param[in] idx1_out_start index of first product macroparticle + * @param[in] idx2_out_start index of second product macroparticle * @param[in] m1_in mass of first colliding species * @param[in] m2_in mass of second colliding species * @param[in] m1_out mass of first product species * @param[in] m2_out mass of second product species - * @param[in] F_fusion energy released in the fusion reaction + * @param[in] E_fusion energy released in the fusion reaction * @param[in] engine the random engine */ AMREX_GPU_HOST_DEVICE AMREX_INLINE From fec693eac32c46b95f7e608fc0d6f3e0c94059b1 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Wed, 13 Jul 2022 13:17:41 -0700 Subject: [PATCH 60/63] Update PR according to comments --- .../nuclear_fusion/analysis_deuterium_tritium_fusion.py | 2 +- .../NuclearFusion/TwoProductFusionInitializeMomentum.H | 4 ++-- .../Collision/BinaryCollision/ParticleCreationFunc.H | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py index 38c31c10edd..e1e3082e3b8 100755 --- a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py @@ -66,7 +66,7 @@ MeV_to_Joule = scc.e*1e6 barn_to_square_meter = 1.e-28 -E_fusion = 17.6*MeV_to_Joule # Energy released during the fusion reaction +E_fusion = 17.5893*MeV_to_Joule # Energy released during the fusion reaction ## Some numerical parameters for this test size_x = 8 diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H index 7b378d1f221..be3f5b2d957 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/TwoProductFusionInitializeMomentum.H @@ -62,8 +62,8 @@ namespace { { using namespace amrex::literals; - amrex::ParticleReal ux1_out = 0.0, uy1_out = 0.0, uz1_out = 0.0; - amrex::ParticleReal ux2_out = 0.0, uy2_out = 0.0, uz2_out = 0.0; + amrex::ParticleReal ux1_out = 0.0_prt, uy1_out = 0.0_prt, uz1_out = 0.0_prt; + amrex::ParticleReal ux2_out = 0.0_prt, uy2_out = 0.0_prt, uz2_out = 0.0_prt; TwoProductFusionComputeProductMomenta( soa1_in.m_rdata[PIdx::ux][idx1_in], diff --git a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H index ca01ba0a01c..510c59094c9 100644 --- a/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H +++ b/Source/Particles/Collision/BinaryCollision/ParticleCreationFunc.H @@ -227,9 +227,9 @@ public: } else if (t_collision_type == CollisionType::DeuteriumTritiumFusion) { - amrex::ParticleReal fusion_energy = 0; + amrex::ParticleReal fusion_energy = 0.0_prt; if (t_collision_type == CollisionType::DeuteriumTritiumFusion) { - fusion_energy = 17.6e6_prt * PhysConst::q_e; // 17.6 MeV + fusion_energy = 17.5893e6_prt * PhysConst::q_e; // 17.6 MeV } TwoProductFusionInitializeMomentum(soa_1, soa_2, soa_products_data[0], soa_products_data[1], From f11f72edc04247dc9a68639ef9bfcaa132a60859 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 14 Jul 2022 01:23:07 -0700 Subject: [PATCH 61/63] Update benchmark --- .../Deuterium_Tritium_Fusion_3D.json | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Regression/Checksum/benchmarks_json/Deuterium_Tritium_Fusion_3D.json b/Regression/Checksum/benchmarks_json/Deuterium_Tritium_Fusion_3D.json index 8c793d014a5..f17d98e86e8 100644 --- a/Regression/Checksum/benchmarks_json/Deuterium_Tritium_Fusion_3D.json +++ b/Regression/Checksum/benchmarks_json/Deuterium_Tritium_Fusion_3D.json @@ -24,9 +24,9 @@ "helium1": { "particle_cpu": 20564.0, "particle_id": 414455929591.0, - "particle_momentum_x": 1.752459522386588e-15, - "particle_momentum_y": 1.7528165107122235e-15, - "particle_momentum_z": 1.7485096000550826e-15, + "particle_momentum_x": 1.7519716491839538e-15, + "particle_momentum_y": 1.7523289312260283e-15, + "particle_momentum_z": 1.7480231586369996e-15, "particle_position_x": 154379.32401483235, "particle_position_y": 152618.63815943015, "particle_position_z": 325970.4138010667, @@ -35,9 +35,9 @@ "helium2": { "particle_cpu": 18146.0, "particle_id": 370840895571.0, - "particle_momentum_x": 1.5335366853772491e-15, - "particle_momentum_y": 1.5332896925711041e-15, - "particle_momentum_z": 1.7639633745850731e-15, + "particle_momentum_x": 1.5330942227771018e-15, + "particle_momentum_y": 1.5328473121602395e-15, + "particle_momentum_z": 1.7635828326228758e-15, "particle_position_x": 137011.89739173267, "particle_position_y": 136605.24328988983, "particle_position_z": 290143.4673994485, @@ -49,9 +49,9 @@ "neutron1": { "particle_cpu": 20564.0, "particle_id": 415194438443.0, - "particle_momentum_x": 1.752459522386588e-15, - "particle_momentum_y": 1.7528165107122235e-15, - "particle_momentum_z": 1.7485096000550826e-15, + "particle_momentum_x": 1.7519716491839538e-15, + "particle_momentum_y": 1.7523289312260283e-15, + "particle_momentum_z": 1.7480231586369996e-15, "particle_position_x": 154379.32401483235, "particle_position_y": 152618.63815943015, "particle_position_z": 325970.4138010667, @@ -60,9 +60,9 @@ "neutron2": { "particle_cpu": 18146.0, "particle_id": 371427197911.0, - "particle_momentum_x": 1.5335366853772491e-15, - "particle_momentum_y": 1.5332896925711041e-15, - "particle_momentum_z": 1.5497361118073471e-15, + "particle_momentum_x": 1.5330942227771018e-15, + "particle_momentum_y": 1.5328473121602395e-15, + "particle_momentum_z": 1.549297051563983e-15, "particle_position_x": 137011.89739173267, "particle_position_y": 136605.24328988983, "particle_position_z": 290143.4673994485, From c2846d85d99dc39429122235010c3fe88e720742 Mon Sep 17 00:00:00 2001 From: Remi Lehe Date: Thu, 14 Jul 2022 11:43:58 -0700 Subject: [PATCH 62/63] Address additional comments --- .../analysis_deuterium_tritium_fusion.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py index e1e3082e3b8..f218df54d70 100755 --- a/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py +++ b/Examples/Modules/nuclear_fusion/analysis_deuterium_tritium_fusion.py @@ -21,8 +21,7 @@ ## The first test is performed in the center of mass frame of the reactant. It could correspond to the ## physical case of two beams colliding with each other. The kinetic energy of the colliding ## particles depends on the cell number in the z direction and varies in the few keV to few MeV -## range. All the particles within a cell have the exact same momentum, which allows detailed -## checks of the energy of produced alpha particles. The reactant species have the same +## range. All the particles within a cell have the exact same momentum. The reactant species have the same ## density and number of particles in this test. The number of product species is much smaller than ## the initial number of reactants ## @@ -30,8 +29,7 @@ ## physical case of a low density beam colliding with a high-density mixed target. The energy of the ## beam particles is varied in the few keV to few MeV range, depending on the cell number in the z ## direction. As in the previous case, all the particles within a cell have the exact same -## momentum, which allows detailed checks of the energy of product particles. In this test, -## there are 100 immobile macroparticles for each reactant per cell, as well as 900 +## momentum. In this test, there are 100 immobile macroparticles for each reactant per cell, as well as 900 ## of the beam reactant macroparticles per cell. The density of the immobile particles is 6 orders of ## magnitude higher than the number of beam particles, which means that they have a much higher ## weight. This test is similar to the example given in section 3 of Higginson et al., @@ -203,7 +201,7 @@ def check_isotropy(data, relative_tolerance): assert(is_close(average_px_sq, average_pz_sq, rtol = relative_tolerance)) def check_xy_isotropy(data): - ## Checks that the alpha particles are emitted isotropically in x and y + ## Checks that the product particles are emitted isotropically in x and y for species_name in product_species: average_px_sq = np.average(data[species_name+"_px_end"]*data[species_name+"_px_end"]) average_py_sq = np.average(data[species_name+"_py_end"]*data[species_name+"_py_end"]) @@ -265,7 +263,7 @@ def expected_weight_com(E_com, reactant0_density, reactant1_density, dV, dt): def check_macroparticle_number(data, fusion_probability_target_value, num_pair_per_cell): ## Checks that the number of macroparticles is as expected for the first and second tests - ## The first slice 0 < z < 1 does not contribute to alpha creation + ## The first slice 0 < z < 1 does not contribute to product species creation numcells = dV_total - dV_slice ## In these tests, the fusion_multiplier is so high that the fusion probability per pair is ## equal to the parameter fusion_probability_target_value From c103462a83a48da55d7c3532a42514b5aafd7eb3 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Tue, 19 Jul 2022 10:27:11 -0700 Subject: [PATCH 63/63] Numerical Literals --- .../NuclearFusion/DeuteriumTritiumFusionCrossSection.H | 2 +- .../Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H index 34219645591..58aaa986b98 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/DeuteriumTritiumFusionCrossSection.H @@ -53,7 +53,7 @@ amrex::ParticleReal DeuteriumTritiumFusionCrossSection (const amrex::ParticleRea amrex::ParticleReal astrophysical_factor = (A1 + E_keV*(A2 + E_keV*(A3 + E_keV*A4))) / - (1 + E_keV*(B1 + E_keV*(B2 + E_keV*(B3 + E_keV*B4)))); + (1_prt + E_keV*(B1 + E_keV*(B2 + E_keV*(B3 + E_keV*B4)))); // Compute cross-section in SI units // (See Eq. 8 in H.-S. Bosch and G.M. Hale 1992 Nucl. Fusion 32 611) diff --git a/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H b/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H index 8e4e9d3270d..2da560ea36b 100644 --- a/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H +++ b/Source/Particles/Collision/BinaryCollision/NuclearFusion/NuclearFusionFunc.H @@ -71,7 +71,7 @@ public: if (m_fusion_type == NuclearFusionType::DeuteriumTritium) { WARPX_ALWAYS_ASSERT_WITH_MESSAGE( - product_species_name.size() == 2, + product_species_name.size() == 2u, "ERROR: Deuterium-tritium fusion must contain exactly two product species"); auto& product_species1 = mypc->GetParticleContainerFromName(product_species_name[0]); auto& product_species2 = mypc->GetParticleContainerFromName(product_species_name[1]);