pub struct Material {
pub comp: BTreeMap<NuclideId, f64>,
/* private fields */
}Expand description
A nuclear material: nuclide masses plus optional density and metadata.
The composition stores absolute masses per nuclide, in grams by convention; only relative amounts matter for fraction-based consumers, which normalize on demand. Density is deliberately separate from the composition: it is a property of the physical stream and is not scaled or combined by the arithmetic operators except where noted.
Combining two materials clears density and metadata (a mixture has no single density); scalar scaling preserves them.
Fields§
§comp: BTreeMap<NuclideId, f64>Stored masses (grams) keyed by nuclide.
Implementations§
Source§impl Material
impl Material
Sourcepub fn from_formula(
formula: &str,
masses: &impl MassProvider,
abundances: &impl AbundanceProvider,
density: Option<f64>,
) -> FormulaResult<Self>
pub fn from_formula( formula: &str, masses: &impl MassProvider, abundances: &impl AbundanceProvider, density: Option<f64>, ) -> FormulaResult<Self>
Build a material from a chemical formula, expanding each element into its naturally occurring isotopes.
Mirrors Material::from_atom_frac: atom counts come from the
parsed formula weighted by natural-abundance fractions, stored masses
are n_i * M_i using masses, and density is attached unchanged.
Fails with the parse/abundance variants of FormulaError for bad
input and with FormulaError::Core wrapping
crate::Error::MissingMass when an isotope’s mass is unknown.
Sourcepub fn expand_elements(
&mut self,
masses: &impl MassProvider,
abundances: &impl AbundanceProvider,
) -> FormulaResult<()>
pub fn expand_elements( &mut self, masses: &impl MassProvider, abundances: &impl AbundanceProvider, ) -> FormulaResult<()>
Replace natural-element placeholder entries with their isotopic breakdown, preserving each entry’s stored mass.
Placeholders follow the mcnp-io inp convention: a bare elemental
zaid (z*1000, AAA == 0) becomes the nucid z * 10_000_000
(is_elemental). Each placeholder of element z holding g
grams is replaced by isotope masses g * x_i * M_i / M̄, where x_i
are the (normalized) natural-abundance fractions and M̄ the
abundance-weighted mean atomic mass — i.e. the same number of atoms
of each isotope as the elemental entry implied. Explicitly named
nuclides are left untouched, so mixed elemental + isotopic
compositions are supported.
Fails with FormulaError::NoAbundanceData when the provider has no
isotopes for an element, or FormulaError::Core wrapping
crate::Error::MissingMass when an isotope mass is unknown.
Sourcepub fn collapse_elements(&self) -> Self
pub fn collapse_elements(&self) -> Self
Inverse grouping of Material::expand_elements: fold every nuclide
into its element’s placeholder row keyed by the natural-element id
z * 10_000_000 (zaid z*1000). Placeholder entries already carry
that key and simply accumulate alongside collapsed nuclides. Density
and metadata are preserved; masses are summed exactly.
Source§impl Material
impl Material
Sourcepub fn from_atom_frac(
atoms: &[(NuclideId, f64)],
masses: &impl MassProvider,
density: Option<f64>,
) -> Result<Self>
pub fn from_atom_frac( atoms: &[(NuclideId, f64)], masses: &impl MassProvider, density: Option<f64>, ) -> Result<Self>
Build a material from atom counts/fractions, converting to masses via
m_i = n_i * M_i with atomic masses from masses.
Entries with zero atom count are skipped. Fails with
crate::Error::MissingMass if any nonzero entry lacks a known
atomic mass.
Sourcepub fn add_nuclide(&mut self, id: NuclideId, mass: f64)
pub fn add_nuclide(&mut self, id: NuclideId, mass: f64)
Add mass grams of id, accumulating when already present.
Sourcepub fn remove_nuclide(&mut self, id: NuclideId) -> Option<f64>
pub fn remove_nuclide(&mut self, id: NuclideId) -> Option<f64>
Remove a nuclide, returning its stored mass if present.
Sourcepub fn set_density(&mut self, density: Option<f64>)
pub fn set_density(&mut self, density: Option<f64>)
Set (or unset) the mass density.
Sourcepub fn set_metadata(&mut self, metadata: Option<Value>)
pub fn set_metadata(&mut self, metadata: Option<Value>)
Replace the free-form metadata.
Sourcepub fn weight_fractions(&self) -> Result<BTreeMap<NuclideId, f64>>
pub fn weight_fractions(&self) -> Result<BTreeMap<NuclideId, f64>>
Normalized weight fractions; they sum to one.
Sourcepub fn atom_fractions(
&self,
masses: &impl MassProvider,
) -> Result<BTreeMap<NuclideId, f64>>
pub fn atom_fractions( &self, masses: &impl MassProvider, ) -> Result<BTreeMap<NuclideId, f64>>
Normalized atom fractions; they sum to one.
Each nuclide contributes moles proportional to mass / M; atomic
masses come from masses.
Sourcepub fn mix_by_mass(parts: &[(&Material, f64)]) -> Result<Self>
pub fn mix_by_mass(parts: &[(&Material, f64)]) -> Result<Self>
Mix streams weighted by relative mass amounts.
Fractions need not sum to one; they are relative weights of each stream’s full mass.
Sourcepub fn mix_by_volume(parts: &[(&Material, f64)]) -> Result<Self>
pub fn mix_by_volume(parts: &[(&Material, f64)]) -> Result<Self>
Mix streams weighted by relative volumes, converting each stream’s
contribution through its own density (m = v * rho). Every input
must have a positive density set.
Sourcepub fn separate(&self, effs: &[(NuclideId, f64)]) -> Result<(Self, Self)>
pub fn separate(&self, effs: &[(NuclideId, f64)]) -> Result<(Self, Self)>
Split this material into product and tails streams by per-nuclide separation efficiency.
Each listed nuclide sends the fraction eff of its stored mass to
the product stream and 1 - eff to the tails stream; nuclides absent
from effs send nothing to product (eff = 0). Mass is conserved
per nuclide: product + tails == self up to floating-point rounding.
Efficiencies must be finite values in [0, 1] (else
crate::Error::InvalidEfficiency); a repeated nuclide keeps its
last-listed efficiency. Both outputs clear density and metadata (a
split stream has no single density), and nuclides with exactly zero
mass on a side are dropped from that side.
Sourcepub fn blend(parts: &[(&Material, f64)]) -> Result<Self>
pub fn blend(parts: &[(&Material, f64)]) -> Result<Self>
Blend streams at fixed ratios with explicit normalization.
Ratios are relative target proportions: they are normalized by their
sum (w_i = r_i / Σr) and the output is the weighted average
Σ w_i · mat_i (density and metadata cleared, as for the arithmetic
operators). Unlike the cycamore mixer this never falls back to a
silent uniform split: an empty slice or an all-zero (or non-finite)
ratio sum fails with crate::Error::Degenerate, and any negative
or non-finite ratio fails with crate::Error::NegativeFraction.
Source§impl Material
impl Material
Sourcepub fn activity(
&self,
analytics: &Analytics<'_>,
) -> Result<BTreeMap<NuclideId, f64>, AnalyticsError>
pub fn activity( &self, analytics: &Analytics<'_>, ) -> Result<BTreeMap<NuclideId, f64>, AnalyticsError>
Activity A = λ·N per nuclide, in becquerels.
Atom counts follow from stored masses through masses
(N = m / (M · u) with u = 1.66053906892e-24 g) and decay
constants through decays. Stable-as-zero: a known atomic mass
with no decay constant is a stable nuclide (λ = 0, mirroring the
chain rule where None decay → 0.0) and contributes exactly 0.0.
Fails with AnalyticsError::Core wrapping
crate::Error::MissingMass when an atomic mass is unknown, so
genuinely unknown nuclides never collapse to silent zeros.
Sourcepub fn specific_activity(
&self,
analytics: &Analytics<'_>,
) -> Result<f64, AnalyticsError>
pub fn specific_activity( &self, analytics: &Analytics<'_>, ) -> Result<f64, AnalyticsError>
Specific activity of the whole material, in Bq/g: total activity
divided by total stored mass. Fails with
AnalyticsError::Core for empty or
non-positive materials; otherwise identical error behavior to
Material::activity.
Sourcepub fn decay_heat(
&self,
analytics: &Analytics<'_>,
energies: &impl DecayEnergyProvider,
) -> Result<BTreeMap<NuclideId, f64>, AnalyticsError>
pub fn decay_heat( &self, analytics: &Analytics<'_>, energies: &impl DecayEnergyProvider, ) -> Result<BTreeMap<NuclideId, f64>, AnalyticsError>
Decay heat per nuclide, in watts: P_i = A_i · E_i.
Activities come from Material::activity (masses via analytics,
decay constants via analytics.decays); mean recoverable energies
per decay come from energies in MeV, converted with
MEV_TO_JOULES. Energies are screening-level placeholders (see
DecayEnergies), so heat numbers are order-of-magnitude checks,
not calorimetry.
Fails with AnalyticsError::MissingEnergy for radioactive
nuclides without a decay-energy row; stable nuclides (zero
activity, hence P = A·E = 0 regardless of E) skip the energy
lookup and contribute exactly 0.0. Otherwise identical error
behavior to Material::activity.
Sourcepub fn total_decay_heat(
&self,
analytics: &Analytics<'_>,
energies: &impl DecayEnergyProvider,
) -> Result<f64, AnalyticsError>
pub fn total_decay_heat( &self, analytics: &Analytics<'_>, energies: &impl DecayEnergyProvider, ) -> Result<f64, AnalyticsError>
Total decay heat of the whole material, in watts: the sum of
Material::decay_heat. Same error behavior.
Sourcepub fn dose_per_g(
&self,
analytics: &Analytics<'_>,
doses: &impl DoseProvider,
pathway: DosePathway,
source: DoseSource,
) -> Result<BTreeMap<NuclideId, f64>, AnalyticsError>
pub fn dose_per_g( &self, analytics: &Analytics<'_>, doses: &impl DoseProvider, pathway: DosePathway, source: DoseSource, ) -> Result<BTreeMap<NuclideId, f64>, AnalyticsError>
Dose per gram per nuclide, mirroring PyNE Material::dose_per_g.
For weight fraction w_i = m_i / m_tot:
dose_i = Ci_per_Bq · N_A · w_i · λ_i · DF_i / M_i (air/soil)
dose_i = pCi_per_Bq · N_A · w_i · λ_i · DF_i / M_i (ingest/inhale)with CI_PER_BQ = 2.7027027e-11, PCI_PER_BQ = 27.027027,
N_A = AVOGADRO (PyNE uses 6.0221415e23; the difference is <0.1 ppm),
λ from analytics.decays, M (g/mol) from analytics.masses, and
DF from doses. Units follow the table: air mrem/h per g per m^3,
soil mrem/h per g per m^2, ingest/inhale mrem per g. The returned
map holds each nuclide’s per-gram contribution; sum for the total.
Screening-level only — not for safety decisions. Stable nuclides
(known mass, λ = 0 or absent) contribute exactly 0.0 and skip the
doses lookup entirely, so no AnalyticsError::MissingDose is
raised for them. Fails with AnalyticsError::MissingDose when a
radioactive nuclide’s factor is absent or negative (-1 GENII/DOE
air sentinel); otherwise identical error behavior to
Material::activity (plus Degenerate for empty materials).
Sourcepub fn total_dose_per_g(
&self,
analytics: &Analytics<'_>,
doses: &impl DoseProvider,
pathway: DosePathway,
source: DoseSource,
) -> Result<f64, AnalyticsError>
pub fn total_dose_per_g( &self, analytics: &Analytics<'_>, doses: &impl DoseProvider, pathway: DosePathway, source: DoseSource, ) -> Result<f64, AnalyticsError>
Total dose per gram of the whole material: the sum of
Material::dose_per_g. Same units and error behavior.
Source§impl Material
impl Material
Sourcepub fn to_xml(&self, name: &str, density: f64, units: &str) -> Result<String>
pub fn to_xml(&self, name: &str, density: f64, units: &str) -> Result<String>
Serialize this material as a <material> XML fragment.
Components are written as weight fractions (wo attributes). The
density and its units are taken from the arguments rather than from
Material::density, matching the free-standing export style.