Expand description
Amorphous binary-collision-approximation (BCA) transport in a layered or voxelised target, with full recoil cascades.
§Model
The target is any Geometry: a Stack of
layers or a VoxelGrid, whose regions are
homogeneous, structureless (amorphous). A particle alternates straight
free flights and binary elastic collisions with target atoms, losing
energy continuously to electrons along each flight. This is the
amorphous-target BCA of J. P. Biersack and L. G. Haggmark, Nucl. Instrum.
Methods 174 (1980) 257 (TRIM), within the general BCA framework of M. T.
Robinson and I. M. Torrens, Phys. Rev. B 9 (1974) 5008 and the treatment
in W. Eckstein, Computer Simulation of Ion-Solid Interactions
(Springer, 1991). Everything here is implemented from those
publications; no code from the Tier B/C programs named in
CONTRIBUTING.md was consulted.
One history:
- The primary enters at the geometry’s entry point (the origin of the
front face of a stack; the centre of the front face of a voxel grid
unless
Bca::with_entry_pointchooses another) with the beam’s direction. - Free flight of length
tau * lambda(MeanFreePath), with the electronic lossN S_e(E) staken at the energy at the start of the segment (Bragg additivity over the layer composition,crate::ion::stopping::bragg). - Collision with a partner drawn by stoichiometry, at impact parameter
p = p_max sqrt(R)(uniform over the disc of radiusp_max) and a uniform azimuth. The centre-of-mass angle comes from theScatteringTable; lab angles and the transferTfromkinematics. - Recoil: if
T > E_d(the partner’s displacement energy) the atom is displaced with energyT - E_b(the lattice bindingE_bstays in the lattice). OtherwiseTstays in the lattice at the site. This is the displacement criterion of Biersack and Haggmark (1980) and Eckstein (1991). Displaced atoms are followed in turn as full cascades (BcaConfig::follow_recoils), from an explicit stack (no recursion), and draw from the same per-history random stream, so the stream is keyed on the primary index only and results do not depend on the thread count. - A particle stops when its energy falls below its cutoff
(
BcaConfig::primary_cutoff_ev,BcaConfig::recoil_cutoff_ev), or leaves through the front or back face if it can overcome the planar surface barrier (kinematics::refract_out); otherwise it is reflected specularly back into the target.
§Free-path convention and layer boundaries
Particle::layer is the particle’s region in the geometry: the layer
index in a stack, the flat voxel index in a voxel grid. Material data
(scattering, stopping, energies) is cached per material, shared by all
voxels of that material. The surface barrier of an escaping atom uses the
E_s of the material it leaves from and the actual outward normal of the
face (see kinematics::refract_out_normal); a particle that cannot
escape is reflected specularly about that normal. Escapes through the
lateral faces of a voxel grid are reported as Face::Side and counted
in EnergyBudget::lateral. crate::tally::ion::IonTally and the CLI
tallies describe stacks only; use crate::tally::voxel::VoxelTally,
SummaryTally or a custom BcaTally for voxel runs.
A flight is drawn as a dimensionless number of mean free paths tau and
converted to a length with the local lambda. When a flight reaches a
change of material (or a periodic wrap of a voxel grid) it is truncated
exactly there, the electronic loss for the truncated length is applied,
the material is switched, and the flight continues in the new region
with the unused part tau - s/lambda (the flight is not redrawn). A
voxel face between voxels of one material is not an event; the region a
flight ends in is still tracked (Geometry::flight), so the collision,
its tallies and its recoils carry the region of the collision site. The
collision happens in the material where the flight ends, with a partner
and p_max from that material. For exponential paths this is exact by
memorylessness; for the constant path it means a layer split of one
material changes nothing but floating-point rounding,
which the split_layer_is_equivalent test checks.
§Weak collisions (optional)
With the constant free path every flight ends in one collision with
p <= p_max, and the nuclear loss of collisions with p > p_max is
dropped, while the electronic loss of the flight is charged in full. At
cascade-tail energies (a few to tens of eV) the dropped part is large: for
Cu on Cu with the ZBL potential the disc p <= p_max carries 45 % of the
nuclear stopping cross section at 5 eV and 54 % at 10 eV, so the
electronic share of a cascade comes out far too high (issue #64; the level-1
check damage.cascade_electronic_share measures it).
BcaConfig::weak_collisions = K adds the “weak” collisions of
W. Moller and W. Eckstein, TRIDYN - Binary collision simulation of atomic
collisions and dynamic composition changes in solids, report IPP 9/64,
Max-Planck-Institut fur Plasmaphysik, Garching (1988) (the long write-up
of Comput. Phys. Commun. 51 (1988) 355), read at
https://pure.mpg.de/rest/items/item_2131703/component/file_2131702/content.
Read only the report body, PDF pp. 1-47: never Appendix 1 (the TRIDYN
program listing, PDF pp. 48-86), which is Tier C (see CONTRIBUTING.md).
Quoted:
- p. 14: “‘weak’ collisions might occur with more distant atoms which
might contribute to energy loss and angular deflection. The present
version allows up to three additional weak collisions with impact
parameters larger than
p_max, each of them representing one additional atomic volume”, with eq. (9) replaced by eq. (26),p_k^weak = p_max sqrt(k + r_p),k = 1, 2, 3(r_puniform in[0, 1)): thek-th partner is uniform over the annulus betweenp_max sqrt(k)andp_max sqrt(k + 1), of areapi p_max^2. Fig. 3 (p. 11) draws the first-order partner at its own azimuth. - p. 26: “the weak collision loop is entered which finally defines new directions after each of the simultaneous collisions. (Actually, the last passage of the weak collision loop represents the hard collision.) A primary recoil may be generated and stored for each hard collision.”
- p. 35: the program sums the elastic energy transfers of the weak and hard collisions, and their local inelastic (Oen-Robinson) losses.
- Figs. 7 and 8, pp. 29-30 (flow charts of the projectile and cascade loops): inside the weak-collision loop, after the partner’s species, azimuth and impact parameter are drawn, a “Target beyond Surf.?” test skips the passage when the partner would lie outside the target; and “Elastic Energy Loss” is applied once, after the loop.
So each collision step here is: the K weak collisions, k = 1..K, each
with a partner drawn by stoichiometry, p = p_max sqrt(k + R) and a
uniform azimuth, then the hard collision with p = p_max sqrt(R). Each
deflects the particle and takes its transfer T; under
ElectronicLoss::EquipartitionLsOr each also takes its Oen-Robinson
local loss, so the local half is sampled out to p_max sqrt(K + 1). A weak
collision never makes a recoil: its T stays in the lattice at the site
(LatticeDeposit::Weak, counted in EnergyBudget::lattice). Random
draws per weak collision: partner, R, azimuth, in that order and before
the hard collision’s, so K = 0 draws exactly what the engine drew before
the option existed and reproduces it bit for bit.
Surface test. As in Figs. 7 and 8, a weak collision whose partner would
lie in front of the front surface (in vacuum) is skipped; its draws are
still made. The partner sits at distance p from the path on the side
opposite to the deflection (where a hard collision sends its recoil). In
TRIDYN the test also covers the hard collision (the loop’s last passage);
here it does not, because that would change the engine without weak
collisions, which this option leaves untouched. Whether the hard
collision should be tested too is left as a separate model decision. The
back face of a finite target is not tested: the flow charts test “the
surface” only.
Deviation from TRIDYN: the energy of each collision. The flow charts
apply the elastic loss once, after the loop, and p. 35 sums the
transfers, so in TRIDYN every collision of a step is evaluated at the
energy the step starts with. Here each is evaluated at the energy left
after the previous one (and in the direction after it), so no transfer
can exceed the particle’s energy. Evaluated at the starting energy, the
summed transfers of a slow atom often exceed its energy, and the report
shows no rule for that case: for Ar 1 keV on Cu with E_d = E_s and
K = 3, 18 % of the binary collisions would need a clamp, about 200 eV per
ion in all, and the sputter yield would depend on how the clamp is
applied. Measured on that problem (20 000 ions, seed 1): 0.882 as here;
0.875 with only the weak collisions at the starting energy (each transfer
clamped to the energy left, the hard collision at the energy left); 0.976
with every collision at the starting energy and each transfer clamped in
loop order. Since the clamp is not in the source, the sequential choice
is kept.
With K weak collisions the nuclear loss per path is the stopping cross
section integrated to p_max sqrt(K + 1) instead of p_max (93 % of the
full value at 5 eV for Cu on Cu with K = 3). It is available with
MeanFreePath::Constant only (p_max is the constant-path radius);
MeanFreePath::EnergyDependent rejects it, since that convention drops
small-angle collisions by design.
Default 0, because there is no single published convention: Biersack
and Haggmark (1980), whose constant free path this engine follows, use one
collision per flight; TRIDYN allows up to three (the report read does not
give a default); SDTrimSP, a TRIDYN descendant, defaults to two for
projectiles and two for recoils (iwc, iwcr: A. Mutzke et al.,
SDTrimSP Version 6.00, report IPP 2019-02 (2019), Table 13, p. 73,
“number of ring cylinders for weak simultaneous collisions”); and the
RustBCA manual documents weak_collision_order with a default of 0 (its
GitHub wiki, “Standalone Code: Input File”; manual only, Tier B).
The option is not a free improvement, which is the other reason it is off
by default. It brings the electronic share of a cascade in line with the
Lindhard partition integral equation solved for the engine’s own inputs
(level-1 rows damage.cascade_electronic_share.*: for Cu on Cu at 1 keV
about 0.79 without weak collisions and 0.35 with K = 3, against 0.38).
But a weak transfer stays in the lattice, and at a few eV it is a large
part of the energy (Cu on Cu at 5 eV, ZBL: on average 46, 25 and 13 % in
the first three annuli), so slow atoms near the surface stop sooner: the
Ar 1 keV on Cu sputter yield with E_d = E_s falls from 1.93 to 0.88 with
K = 3 (0.66 without the surface test; docs/validation.md, level 2).
Use it for the energy partition (damage energy, electronic share); its
effect on yields is large and has not been checked against measured
yields.
§Energy bookkeeping
Every energy change is subtracted from the particle and added to exactly
one field of an EnergyBudget, so each history conserves energy up to
rounding (EnergyBudget::residual). Electronic losses larger than the
particle’s energy are clamped to it.
Vacancy, interstitial and replacement counts, and the NRT damage estimate,
are kept by the tally crate::tally::IonTally from the events reported
here (crate::ion::damage has the models).
§Crystal regions
Everything above is the amorphous partner model. Bca::with_crystal
switches chosen regions to the crystal flight model (partners from an
explicit lattice, in crystal); the other regions, and engines that do
not call it, are untouched and bit-identical to the amorphous engine.
§Not modelled here (see the issue tracker)
Damage accumulation in crystal regions (the lattice there is perfect,
static or thermally vibrating; the local Oen-Robinson loss of
ElectronicLoss::EquipartitionLsOr is taken at every lattice partner,
see crystal), target composition changes with fluence, and refraction
of the incident beam at the entrance surface (negligible at keV energies).
Re-exports§
pub use crystal::CrystalMetadata;pub use crystal::CrystalTarget;pub use crystal::Thermal;pub use crystal::ThermalMetadata;pub use tally::BcaTally;pub use tally::ElectronicChannel;pub use tally::EnergyBudget;pub use tally::Face;pub use tally::LatticeDeposit;pub use tally::SummaryTally;
Modules§
- crystal
- The crystal flight model: collision partners taken from explicit lattice sites instead of a random impact parameter (step 20b of the M2 crystal plan), optionally displaced by thermal vibration (step 21b).
- kinematics
- Two-body elastic kinematics, direction rotation and planar surface refraction. Pure functions, no state.
- tally
- What the BCA engine reports, and a small built-in summary tally.
Structs§
- Bca
- The BCA engine for one beam, target and configuration.
- BcaConfig
- Run configuration.
- Beam
- The incident beam.
- Divergence
Metadata - Run metadata of a beam divergence (
Bca::divergence_metadata): the distribution, its width and the incidence policy, so a result states the spread it was run with. - History
Buffers - Reusable working memory for
Bca::history_in: the stack of particles still to be followed and the per-flight scratch. A history that runs in buffers which have already seen a cascade as large allocates nothing, so a worker thread allocates only while its buffers grow to the largest cascade it meets, not per history and not per collision. - Particle
- A moving or stopped particle.
Enums§
- BcaError
- Errors from setting up or running the engine.
- Electronic
Loss - Electronic energy-loss treatment.
- History
Error - Why a single history failed.
- Mean
Free Path - How free-flight lengths and the impact-parameter limit are chosen.
Constants§
- DIVERGENCE_
STREAM_ WORD - Word position (in the 32-bit words of the ChaCha stream) of the segment
of a history’s random stream that beam-divergence draws come from:
2^65. The transport draws start at word 0 and never reach it, and it is disjoint from the thermal-displacement segment (2^66) and the crystal-shift segment (2^67) (each is far shorter than the gap to the next), so enabling divergence leaves every other draw of the history unchanged. - MAX_
DIVERGENCE_ ATTEMPTS - Most deflected directions drawn for one primary before
Bca::with_divergence’s inward conditioning gives up withBcaError::BeamDivergence. For the small-angle spreads the input front end accepts, one draw is inward with probability about one half or more, so exhausting 1000 attempts has probability below2^-1000; the bound only guarantees that a pathological setting cannot hang a run. - MAX_
WEAK_ COLLISIONS - Largest
BcaConfig::weak_collisions: “up to three additional weak collisions” (Moller and Eckstein, IPP 9/64 (1988), p. 14).