radiological_material_clearance_finder/lib.rs
1//! Clearance indexes for a radiological material.
2//!
3//! Give it a nuclide inventory and it tells you whether the material meets the
4//! clearance, exemption or disposal limits of the UK, German, US, EU and IAEA
5//! regulations, and by how much.
6//!
7//! ```
8//! use radiological_material_clearance_finder::{
9//! clearance_index, get_limit_set, ClearanceOptions, Material,
10//! };
11//!
12//! let steel = Material::from_atom_counts([("Fe56", 8.4e22), ("Co60", 2.1e9), ("Cs137", 3.1e8)])?;
13//! let set = get_limit_set("UK_EPR16_out_of_scope")?;
14//! let result = clearance_index(&steel, &set, ClearanceOptions::default())?;
15//! assert!(!result.clearable());
16//! assert_eq!(result.dominant(1)[0].0, "Co60");
17//! # Ok::<(), radiological_material_clearance_finder::Error>(())
18//! ```
19//!
20//! Every regulation here uses the same arithmetic, a sum of activity-to-limit
21//! ratios that must stay below one. What differs is the tables, and those are
22//! data compiled into the crate: see [`limit_sets`] for what is available and
23//! [`get_limit_set`] for the provenance of any one of them.
24//!
25//! A transport or transmutation code with its own material type hands over its
26//! atom densities in atoms per barn-cm, and its volume if total activity is
27//! wanted:
28//!
29//! ```
30//! # use std::collections::HashMap;
31//! use radiological_material_clearance_finder::Material;
32//!
33//! let atoms_per_barn_cm: HashMap<String, f64> =
34//! [("Fe56".to_string(), 0.0849), ("Co60".to_string(), 1e-10)].into();
35//! let inventory = Material::from_atom_densities(atoms_per_barn_cm)?.with_volume(1000.0)?;
36//! assert!((inventory.mass_density()? - 7.89).abs() < 0.01);
37//! # Ok::<(), radiological_material_clearance_finder::Error>(())
38//! ```
39
40pub mod classify;
41pub mod cooling;
42pub mod decay;
43pub mod error;
44mod fmt;
45pub mod index;
46pub mod limits;
47pub mod material;
48pub mod nuclide;
49
50pub use classify::{
51 alpha_activity, beta_gamma_activity, nrc_waste_class, uk_waste_category, NrcWasteClass,
52 UkCategory, UkWasteCategory,
53};
54pub use cooling::{index_series, time_to_clear};
55pub use decay::{DecayData, AVOGADRO, BECQUEREL_PER_CURIE};
56pub use error::{Error, Result};
57pub use index::{
58 clearable_routes, clearance_index, clearance_indices, ClearanceOptions, ClearanceResult,
59 EQUILIBRIUM_TOLERANCE,
60};
61pub use limits::{
62 get_limit_set, limit_sets, register_limit_set, DynamicRule, LimitSet, LimitSetData,
63};
64pub use material::{ActivityUnit, Material};
65
66/// Sum of floats starting from +0.0.
67///
68/// `Iterator::sum` on floats starts from -0.0, so an empty sum, such as the
69/// index of a material with nothing limited, would print as "-0".
70pub(crate) fn total<I, T>(values: I) -> f64
71where
72 I: IntoIterator<Item = T>,
73 T: std::borrow::Borrow<f64>,
74{
75 values.into_iter().fold(0.0, |acc, v| acc + *v.borrow())
76}