Skip to content

Commit 8bf1b0f

Browse files
committed
Added CI test and updated documentation to referance fusion.param file in it
1 parent bdb86e4 commit 8bf1b0f

File tree

17 files changed

+1417
-168
lines changed

17 files changed

+1417
-168
lines changed

docs/source/usage/workflows/fusionReactions.rst

Lines changed: 31 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,21 @@ Species Definition Requirements
1111
-------------------------------
1212
All species participating in fusion reactions must be defined with ``massRatio`` and ``chargeRatio`` flags. These are mandatory for the fusion algorithms to function correctly.
1313

14-
To simplify defining particle masses relative to the electron mass, PIConGPU provides a constant for the atomic mass unit (``amu``). This constant is the ratio of one atomic mass unit to the electron rest mass. You can use it in ``speciesDefinition.param`` as follows:
14+
To simplify defining particle masses relative to the electron mass, you can define an atomic mass unit (``amu``) constant. This constant is the ratio of one atomic mass unit to the electron rest mass:
1515

16-
.. code-block:: cpp
17-
18-
#include "picongpu/unitless/simulation.unitless"
19-
20-
// Atomic mass unit in electron masses (amu/me)
21-
constexpr float_X amu = 1.0_X / sim.fusion.electronMassAMU;
22-
23-
// Deuteron species
24-
value_identifier(float_X, MassRatioDeuterons, 2.013553212745*amu);
25-
value_identifier(float_X, ChargeRatioDeuterons, 1.0);
16+
.. literalinclude:: ../../../../share/picongpu/tests/Fusion/include/picongpu/param/speciesDefinition.param
17+
:language: cpp
18+
:start-after: doc-include-start: amu-definition
19+
:end-before: doc-include-end: amu-definition
20+
:dedent:
2621

27-
using ParticleFlagsDeuterons = MakeSeq_t<
28-
particlePusher<UsedParticlePusher>,
29-
shape<UsedParticleShape>,
30-
interpolation<UsedField2Particle>,
31-
massRatio<MassRatioDeuterons>, // Required for fusion
32-
chargeRatio<ChargeRatioDeuterons> // Required for fusion
33-
>;
22+
Example species definition for deuterons:
3423

35-
using PIC_Deuterons = Particles<PMACC_CSTRING("d"), ParticleFlagsDeuterons, DefaultParticleAttributes>;
24+
.. literalinclude:: ../../../../share/picongpu/tests/Fusion/include/picongpu/param/speciesDefinition.param
25+
:language: cpp
26+
:start-after: doc-include-start: deuteron-definition
27+
:end-before: doc-include-end: deuteron-definition
28+
:dedent:
3629

3730
Important: Mass ratios must be as precise as possible since fusion energy release is calculated from the mass deficit between reactants and products.
3831

@@ -92,92 +85,34 @@ This is the easiest fusion reaction to achieve and is commonly used in fusion en
9285
The cross-section parameters are based on the Bosch-Hale parameterization from experimental data
9386
(Source: https://hdl.handle.net/11858/00-001M-0000-0027-6535-1, page 29).
9487

95-
.. code-block:: cpp
96-
97-
struct DT
98-
{
99-
//! Reactant species: Deuterium and Tritium
100-
using reactants = pmacc::mp_list<Pair<PIC_Tritons, PIC_Deuterons>>;
101-
102-
//! Filter for reactants (mandatory for ColliderFromStruct)
103-
//! Use filter::All to include all particles, or define custom filters
104-
using FilterPair = OneFilter<filter::All>;
105-
106-
//! Product species: Neutron and Helium-4
107-
using products = pmacc::mp_list<Pair<PIC_Neutrons, PIC_He4>>;
108-
109-
/** Cross-section parameters for D-T fusion */
110-
struct Params
111-
{
112-
//! Gamow constant: BG = π·α·Z₁·Z₂·√(2·μ·c²) in keV^(1/2)
113-
//! where α is the fine structure constant, Z₁,Z₂ are charges, μ is reduced mass
114-
static constexpr float_X BG = 34.3827_X;
115-
116-
//! Bosch-Hale parameterization coefficients for D-T cross-section
117-
//! These coefficients fit experimental cross-section data
118-
static constexpr float_X A1 = 6.927e4_X;
119-
static constexpr float_X A2 = 7.454e8_X;
120-
static constexpr float_X A3 = 2.050e6_X;
121-
static constexpr float_X A4 = 5.2002e4_X;
122-
static constexpr float_X A5 = 0.0_X;
123-
124-
//! Additional Bosch-Hale coefficients
125-
static constexpr float_X B1 = 6.38e1_X;
126-
static constexpr float_X B2 = -9.95e-1_X;
127-
static constexpr float_X B3 = 6.981e-5_X;
128-
static constexpr float_X B4 = 1.728e-4_X;
129-
};
130-
131-
//! Cross-section calculation using Bosch-Hale parameterization
132-
//! Returns cross-section in milli-barns
133-
using CrossSectionInterpolator = relativistic::FusionFunctor<Params>;
134-
};
88+
.. literalinclude:: ../../../../share/picongpu/tests/Fusion/include/picongpu/param/fusion.param
89+
:language: cpp
90+
:start-after: doc-include-start: DT-reaction
91+
:end-before: doc-include-end: DT-reaction
92+
:dedent:
13593

13694
2) Configure the fusion pipeline
13795

138-
.. code-block:: cpp
139-
140-
// Single reaction
141-
using FusionPipeline = pmacc::mp_list<ColliderFromStruct<DT>>;
142-
143-
// Multiple reactions (processed sequentially)
144-
using FusionPipeline = pmacc::mp_list<
145-
ColliderFromStruct<DT>,
146-
ColliderFromStruct<DD_branch1>,
147-
ColliderFromStruct<DD_branch2>
148-
>;
149-
150-
.. note:: Alternative explicit form
96+
.. literalinclude:: ../../../../share/picongpu/tests/Fusion/include/picongpu/param/fusion.param
97+
:language: cpp
98+
:start-after: doc-include-start: fusion-pipeline
99+
:end-before: doc-include-end: fusion-pipeline
100+
:dedent:
151101

152-
You can also define the fusion pipeline using the explicit ``Collider`` template:
102+
.. note:: Multiple reactions
153103

154-
.. code-block:: cpp
155-
156-
using FusionPipeline = pmacc::mp_list<
157-
Collider<DT_He4n::CrossSectionInterpolator, DT_He4n::reactants, DT_He4n::products, OneFilter<filter::All>>,
158-
Collider<DD_Tp::CrossSectionInterpolator, DD_Tp::reactants, DD_Tp::products, OneFilter<filter::All>>,
159-
Collider<DD_He3n::CrossSectionInterpolator, DD_He3n::reactants, DD_He3n::products, OneFilter<filter::All>>,
160-
Collider<He3D_He4p::CrossSectionInterpolator, He3D_He4p::reactants, He3D_He4p::products, OneFilter<filter::All>>,
161-
Collider<He3T_He4D::CrossSectionInterpolator, He3T_He4D::reactants, He3T_He4D::products, OneFilter<filter::All>>,
162-
Collider<TT_He4nn::CrossSectionInterpolator, TT_He4nn::reactants, TT_He4nn::products, OneFilter<filter::All>>,
163-
Collider<Bp_He4He4::CrossSectionInterpolator, Bp_He4He4::reactants, Bp_He4He4::products, OneFilter<filter::All>>
164-
>;
104+
You can add multiple reactions to the pipeline by defining additional reaction structs
105+
and adding them to the ``FusionPipeline`` list. The reactions are processed sequentially
106+
in the order they appear.
165107

166108
Simulation Parameters
167109
---------------------
168110

169-
.. code-block:: cpp
170-
171-
// Memory allocation control
172-
constexpr uint32_t cellListChunkSize = TYPICAL_PARTICLES_PER_CELL;
173-
174-
// Product weighting thresholds
175-
constexpr float_X productMinWeighting = 16.1;
176-
constexpr uint32_t maxFmult = 1e6;
177-
178-
// Debug flags
179-
constexpr bool debugFusion = false;
180-
constexpr bool alwaysFuseQ = false; // Force 100% fusion probability
111+
.. literalinclude:: ../../../../share/picongpu/tests/Fusion/include/picongpu/param/fusion.param
112+
:language: cpp
113+
:start-after: doc-include-start: simulation-parameters
114+
:end-before: doc-include-end: simulation-parameters
115+
:dedent:
181116

182117
.. note:: Fusion production multiplier (Fmult)
183118

include/picongpu/param/fusion.param

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -49,35 +49,12 @@ namespace picongpu
4949
*/
5050
constexpr uint32_t cellListChunkSize = TYPICAL_PARTICLES_PER_CELL;
5151

52-
/** Minimum weighting threshold for fusion product macro-particles.
52+
/** Maximum allowed fusion reaction rate multiplier per time step.
5353
*
54-
* Sets the minimum allowed weighting (statistical weight) for newly created
55-
* product macro-particles. When the fusion production multiplier (Fmult) would
56-
* create products lighter than this threshold, Fmult is reduced to ensure
57-
* products have at least this weighting. Lower values allow more, lighter products
58-
* but increase memory usage and computation time.
54+
* This is used to increase the number of product particles while simultaneously decreasing the weight of
55+
* each product particle to improve statistics of fusion products.
5956
*/
60-
constexpr float_X productMinWeighting = 16.1;
61-
62-
/** Maximum fusion production multiplier (Fmult).
63-
*
64-
* Controls how the consumed reactant weight is split into multiple product
65-
* macro-particles. Higher values create more, lighter products (down to the
66-
* productMinWeighting threshold). Lower values create fewer, heavier products.
67-
*
68-
* Algorithm per fused pair:
69-
* - Start with Fmult = maxFmult
70-
* - Compute productWeighting = minWeighting / Fmult
71-
* - If productWeighting < productMinWeighting, reduce Fmult to
72-
* max(1, minWeighting / productMinWeighting) and recompute
73-
*
74-
* The base productWeighting is then distributed across reactant sites and
75-
* product species while conserving total weight.
76-
*
77-
* Note: This distribution can result in creation of product particles with
78-
* weighting smaller than productMinWeighting.
79-
*/
80-
constexpr uint32_t maxFmult = 1'000'000;
57+
constexpr float_X maxFmult = 1e6;
8158

8259
/** Enable debug output for fusion processes.
8360
*

include/picongpu/particles/fusion/InterCollision.hpp

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,7 @@ namespace picongpu::particles::fusion
183183
worker.sync();
184184
detail::maxArrayDestroy<false>(worker, nppc, numCellsPerSuperCell);
185185
// now in nppc[0] we have the maximum number of particles in the supercell
186-
onlyMaster(
187-
[&]()
188-
{
189-
maxNumParticlesInCell = nppc[0];
190-
});
186+
onlyMaster([&]() { maxNumParticlesInCell = nppc[0]; });
191187
// don't need sync
192188

193189
// --- 4. Shuffle Particle Lists ---
@@ -480,7 +476,7 @@ namespace picongpu::particles::fusion
480476
for(uint32_t chunkStart = 0; chunkStart < maxNumParticles; chunkStart += numPairsAtOnce)
481477
{
482478
// Parallel grid-stride loop over the current chunk
483-
constexpr uint32_t step = std::min(worker.numWorkers(), numPairsAtOnce);
479+
uint32_t step = std::min(worker.numWorkers(), numPairsAtOnce);
484480
for(int i = chunkStart + worker.workerIdx();
485481
i < chunkStart + numPairsAtOnce && i < maxNumParticles;
486482
i += step)
@@ -499,7 +495,7 @@ namespace picongpu::particles::fusion
499495
// P = n_min * n_a / n_ba * minWeighting * dt * (Fmult*sigma*v_rel*gamma_cm) <- inside fuse()
500496
float_X const probabilityCorrectionFactor
501497
= minReactantDensity * correctionFactor[cellIdx] * sim.pic.getDt();
502-
498+
503499
// Fusion multiplier - can be changed inside fuse() if probability > 1
504500
float_X Fmult = maxFmult;
505501

@@ -525,7 +521,7 @@ namespace picongpu::particles::fusion
525521
{
526522
// because we could change Fmult inside fuser (because the probability might have been >1)
527523
float_X productWeighting = minWeighting / Fmult;
528-
524+
529525
weightingArray[i] = productWeighting; // no atomic needed because i is unique per thread
530526

531527
uint32_t freeIndex = alpaka::atomicAdd(
@@ -614,17 +610,25 @@ namespace picongpu::particles::fusion
614610
// no fusion happened for this pair
615611
if(weightingArray[i] == 0._X)
616612
continue;
617-
613+
618614
if constexpr(debugFusion)
619-
if(weightingArray[i] < 0._X){
620-
printf("Error: negative weighting in fusion reaction! weightingArray[%d] = %f\n", i, weightingArray[i]);
615+
if(weightingArray[i] < 0._X)
616+
{
617+
printf(
618+
"Error: negative weighting in fusion reaction! weightingArray[%d] = %f\n",
619+
i,
620+
weightingArray[i]);
621621
// print fmult and weightingR1 and weightingR2
622622
float_X weightingR1 = accessor1[i % size1][weighting_];
623623
float_X weightingR2 = accessor2[i % size2][weighting_];
624624
printf("weightingR1 = %f, weightingR2 = %f\n", weightingR1, weightingR2);
625625
printf("Fmult = %f\n", maxFmult);
626626
// print the number of particles in longer list
627-
printf("size1 = %d, size2 = %d, weightingArraySize = %d\n", size1, size2, weightingArraySize);
627+
printf(
628+
"size1 = %d, size2 = %d, weightingArraySize = %d\n",
629+
size1,
630+
size2,
631+
weightingArraySize);
628632
continue;
629633
}
630634
float_X const oldWeighting1 = accessor1[i % size1][weighting_];
@@ -642,32 +646,35 @@ namespace picongpu::particles::fusion
642646
accessor1[i % size1][multiMask_] = (accessor1[i % size1][weighting_] > 1e-6_X);
643647
accessor2[i % size2][multiMask_] = (accessor2[i % size2][weighting_] > 1e-6_X);
644648

645-
649+
646650
// print i and weighting array
647651
if constexpr(debugFusion)
648-
if((((i==0 && alwaysFuseQ) || !alwaysFuseQ) || accessor1[i % size1][multiMask_]==0 || accessor2[i % size2][multiMask_]==0)){
649-
650-
printf("worker %d: cell %d, i %d, weightingArray %f, new weighting1 %f, new weighting2 %f, old weighting1 %f, old weighting2 %f, difference 1 %f, difference 2 %f\n",
651-
worker.workerIdx(),
652-
cellIdx,
653-
i,
654-
weightingArray[i],
655-
accessor1[i % size1][weighting_],
656-
accessor2[i % size2][weighting_],
657-
oldWeighting1,
658-
oldWeighting2,
659-
oldWeighting1 - accessor1[i % size1][weighting_],
660-
oldWeighting2 - accessor2[i % size2][weighting_]);
661-
652+
if((((i == 0 && alwaysFuseQ) || !alwaysFuseQ) || accessor1[i % size1][multiMask_] == 0
653+
|| accessor2[i % size2][multiMask_] == 0))
654+
{
655+
printf(
656+
"worker %d: cell %d, i %d, weightingArray %f, new weighting1 %f, new weighting2 "
657+
"%f, old weighting1 %f, old weighting2 %f, difference 1 %f, difference 2 %f\n",
658+
worker.workerIdx(),
659+
cellIdx,
660+
i,
661+
weightingArray[i],
662+
accessor1[i % size1][weighting_],
663+
accessor2[i % size2][weighting_],
664+
oldWeighting1,
665+
oldWeighting2,
666+
oldWeighting1 - accessor1[i % size1][weighting_],
667+
oldWeighting2 - accessor2[i % size2][weighting_]);
668+
662669
// print the multimask as well
663-
printf("worker %d: cell %d, i %d, multiMask1 %d, multiMask2 %d\n",
670+
printf(
671+
"worker %d: cell %d, i %d, multiMask1 %d, multiMask2 %d\n",
664672
worker.workerIdx(),
665673
cellIdx,
666674
i,
667675
accessor1[i % size1][multiMask_],
668676
accessor2[i % size2][multiMask_]);
669-
670-
}
677+
}
671678
}
672679
worker.sync();
673680
}

include/picongpu/particles/fusion/detail/arrayHelpers.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ namespace picongpu::particles::fusion::detail
5252

5353
template<bool debug = false, typename T_worker, typename T_arr>
5454
DINLINE void maxArrayDestroy(T_worker const& worker, T_arr& arr, int const& size)
55-
{
55+
{
5656
if(worker.workerIdx() == 0)
5757
{
5858
auto maxVal = arr[0];
5959
for(int i = 1; i < size; ++i)
6060
{
61-
if (arr[i] > maxVal)
61+
if(arr[i] > maxVal)
6262
{
6363
maxVal = arr[i];
6464
}

include/picongpu/particles/fusion/relativistic/FusionAlgorithm.hpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -309,18 +309,18 @@ namespace picongpu::particles::fusion::relativistic
309309

310310
float_X sigma_picArea = crossSection(fusionVar.E_r * convToKeV) * millibarn_to_picArea;
311311
float_X P = probabilityFactor * sigma_picArea * fusionVar.V_rel_mag * fusionVar.gamma_cm;
312-
313-
if(P > 1.0_COLL){
312+
313+
if(P > 1.0_COLL)
314+
{
314315
// print warning
315-
printf(
316-
"Warning: Fusion probability exceeds 1.0 (P: %e) the process will be underestimated.\n",
317-
P);
318-
P= 1.0_COLL;
316+
printf("Warning: Fusion probability exceeds 1.0 (P: %e) the process will be underestimated.\n", P);
317+
P = 1.0_COLL;
319318
Fmult = 1.0_COLL;
320319
}
321-
else if(P>0._COLL){
322-
// limit P to not more than 0.99_COLL
323-
float_X const maxFmult = 0.99_COLL/P;
320+
else if(P > 0._COLL)
321+
{
322+
// limit P to not more than 0.99_COLL
323+
float_X const maxFmult = 0.99_COLL / P;
324324
Fmult = std::min(Fmult, maxFmult);
325325
P *= Fmult;
326326
}
@@ -412,15 +412,14 @@ namespace picongpu::particles::fusion::relativistic
412412
fusionVar.P<T_Product0Box, T_Product1Box>(dir);
413413
mom0 = fusionVar.P0();
414414
mom1 = fusionVar.P1();
415-
415+
416416
if constexpr(debugFusion)
417417
{
418-
if((mom0 == float3_X{0.0_X, 0.0_X, 0.0_X})
419-
|| (mom1 == float3_X{0.0_X, 0.0_X, 0.0_X})){
418+
if((mom0 == float3_X{0.0_X, 0.0_X, 0.0_X}) || (mom1 == float3_X{0.0_X, 0.0_X, 0.0_X}))
419+
{
420420
printf("Error: Fusion produced zero momentum products.\n");
421421
}
422422
}
423-
424423
}
425424
else
426425
{

0 commit comments

Comments
 (0)