Materials-Science
Nuclear isotopes, radioactive decay chains, radiation dose, and hazardous chemical substances with toxicological thresholds and unit conversions.
Namespace: CSharpNumerics.Physics.Materials
using CSharpNumerics.Physics.Materials.Nuclear.Isotopes;
using CSharpNumerics.Physics.Materials.Nuclear.Decay;
using CSharpNumerics.Physics.Materials.Nuclear.DecayChains;
using CSharpNumerics.Physics.Materials.Nuclear.RadiationDose;
using CSharpNumerics.Physics.Materials.Chemical;
π§ͺ Isotopes & Libraryβ
// Built-in isotopes
Isotope cs = Isotope.Cs137; // Cs-137: tΒ½ = 30.17 years
Isotope iodine = Isotope.I131; // I-131: tΒ½ = 8.02 days
// Lookup by name
Isotope sr = IsotopeLibrary.Get("Sr90");
bool found = IsotopeLibrary.TryGet("Co60", out Isotope co);
// Properties
double halfLife = cs.HalfLifeSeconds; // ~9.51e8 s
double lambda = cs.Lambda; // decay constant (ln2/tΒ½)
double activity = cs.SpecificActivityBqKg; // Bq per kg
bool stable = Isotope.Ba137.IsStable; // true
// Filter by element
var caesiumIsotopes = IsotopeLibrary.ByElement(55); // Z = 55
// Register custom isotope at runtime
IsotopeLibrary.Register(new Isotope("Pu239", 94, 239, 7.6e11, 2.3e9,
DecayMode.Alpha, 0.0, 4.4e-5, 0));
βοΈ Radioactive Decayβ
// Simple decay
double a0 = Decay.Activity(massKg: 0.001, Isotope.Cs137); // initial Bq
double aT = Decay.ActivityAtTime(a0, timeSeconds: 3600, Isotope.Cs137);
double remaining = Decay.RemainingMass(0.001, 3600, Isotope.Cs137);
Decay chains β Bateman equations for sequential decay:
// Decay chain (Bateman equations)
var chain = DecayChain.Cs137Chain(); // Cs137 β Ba137m β Ba137
double[] masses = chain.Evolve(
initialMasses: new[] { 1.0, 0.0, 0.0 },
timeSeconds: 3600);
double[] activities = chain.EvolveActivity(
new[] { 1.0, 0.0, 0.0 }, 3600); // Bq for each isotope
// I-131 chain
var iChain = DecayChain.I131Chain(); // I131 β Xe131
β’οΈ Radiation Doseβ
// Point-source dose rate (inverse-square law)
double svPerHour = RadiationDose.DoseRate(
activityBq: 1e9, distanceM: 1.0, Isotope.Cs137);
// Ground-shine dose (deposition on surface)
double sv = RadiationDose.GroundShineDose(
depositionBqM2: 1e6, Isotope.Cs137, timeSeconds: 3600);
// Inhalation dose
double inhDose = RadiationDose.InhalationDose(
concentrationBqM3: 100,
breathingRateM3s: RadiationDose.DefaultBreathingRate,
exposureTimeSeconds: 3600,
Isotope.Cs137);
π Chemical Materialsβ
Namespace: CSharpNumerics.Physics.Materials.Chemical
Model hazardous chemical substances with toxicological thresholds (IDLH, ERPG, LC50, TLV) and unit conversions (kg/mΒ³ β ppm). Integrates with the GIS dispersion pipeline via .WithMaterial(Materials.Chemical("Cl2")).
Built-in substances
| Formula | Name | MW (g/mol) | IDLH (ppm) | ERPG-2 (ppm) | ERPG-3 (ppm) | Phase |
|---|---|---|---|---|---|---|
| Clβ | Chlorine | 70.9 | 10 | 3 | 20 | Gas |
| NHβ | Ammonia | 17.0 | 300 | 200 | 1000 | Gas |
| HβS | Hydrogen Sulfide | 34.1 | 50 | 30 | 100 | Gas |
| CHβ | Methane | 16.0 | N/A* | 5000 | 50000 | Gas |
| CβHβ | Propane | 44.1 | 2100 | 5000 | 17000 | Liquefied gas |
*Simple asphyxiant β no toxicity-based IDLH.
Substance lookup & custom registration
using CSharpNumerics.Physics.Materials.Chemical;
// Static instances
ChemicalSubstance cl = ChemicalSubstance.Chlorine;
ChemicalSubstance nh3 = ChemicalSubstance.Ammonia;
// Library lookup (case-insensitive)
ChemicalSubstance h2s = ChemicalLibrary.Get("H2S");
bool found = ChemicalLibrary.TryGet("CH4", out ChemicalSubstance methane);
// Properties
double mw = cl.MolarMass; // 70.906 g/mol
double idlh = cl.IDLH; // 10 ppm
double erpg2 = cl.ERPG2; // 3 ppm
double vapDens = cl.VapourDensity; // 2.49 (heavier than air)
// Register custom substance
ChemicalLibrary.Register(new ChemicalSubstance(
"COCl2", "Phosgene", "75-44-5",
98.92, 3.4, 8.3, PhaseAtSTP.Gas,
idlh: 2, erpg2: 0.5, erpg3: 1.5, lc50: 5,
tlvTwa: 0.1, tlvStel: 0.3));
Unit conversion (kg/mΒ³ β ppm)
// Convert mass concentration to ppm at 20Β°C, 1 atm
double ppm = cl.KgM3ToPpm(2.95e-6); // β 1 ppm
double kgm3 = cl.PpmToKgM3(10); // IDLH in kg/mΒ³
GIS pipeline integration
using CSharpNumerics.Physics.Materials;
// Attach chemical material to a dispersion scenario
var result = RiskScenario
.ForGaussianPlume(5.0)
.FromSource(new Vector(0, 0, 10))
.WithWind(5, new Vector(1, 0, 0))
.WithStability(StabilityClass.D)
.WithMaterial(Materials.Chemical("Cl2")) // β chemical
.OverGrid(new GeoGrid(-500, 500, -500, 500, 0, 100, 50))
.OverTime(0, 3600, 60)
.RunSingle();
// Snapshot layers: "ppm" and "toxicDose" (ppmΒ·s)
double[] ppmLayer = result.Snapshots[0].GetLayer("ppm");
double[] toxDose = result.Snapshots[0].GetLayer("toxicDose");
// IDLH exceedance polygon (Cl2 IDLH = 10 ppm)
var idlhZone = result.GeneratePeakExposurePolygon(10, "ppm");
// ERPG-2 exceedance polygon (3 ppm)
var erpg2Zone = result.GeneratePeakExposurePolygon(3, "ppm");
// Integrated toxic dose polygon
var integratedZone = result.GenerateIntegratedExposurePolygon(
threshold: 1000, layerName: "toxicDose"); // 1000 ppmΒ·s
π§± Engineering Materialsβ
The EngineeringMaterial immutable struct bundles thermo-mechanical-electrical properties for multiphysics simulations. The EngineeringLibrary provides common pre-defined materials.
Namespace: CSharpNumerics.Physics.Materials.Engineering
Material Properties
| Property | Unit | Description |
|---|---|---|
ThermalConductivity | W/(mΒ·K) | Heat conduction coefficient |
SpecificHeat | J/(kgΒ·K) | Specific heat capacity |
Density | kg/mΒ³ | Mass density |
DynamicViscosity | PaΒ·s | Dynamic viscosity |
ElectricPermittivity | F/m | Dielectric permittivity |
YoungsModulus | Pa | Young's modulus |
PoissonsRatio | β | Poisson's ratio |
Computed properties:
| Computed | Formula | Description |
|---|---|---|
ThermalDiffusivity | Heat diffusion rate | |
KinematicViscosity | Flow diffusion rate |
Pre-defined Materials
using CSharpNumerics.Physics.Materials.Engineering;
var steel = EngineeringLibrary.Steel; // E=200 GPa, k=50 W/(mΒ·K)
var al = EngineeringLibrary.Aluminum; // E=69 GPa, k=237 W/(mΒ·K)
var cu = EngineeringLibrary.Copper; // E=117 GPa, k=401 W/(mΒ·K)
var water = EngineeringLibrary.Water; // ΞΌ=1e-3 PaΒ·s, Ο=1000 kg/mΒ³
var air = EngineeringLibrary.Air; // ΞΌ=1.81e-5 PaΒ·s
var conc = EngineeringLibrary.Concrete; // E=30 GPa
var glass = EngineeringLibrary.Glass; // E=70 GPa
double alpha = steel.ThermalDiffusivity; // k/(ΟΒ·cp)
double nu = water.KinematicViscosity; // ΞΌ/Ο
Custom Materials
var titanium = new EngineeringMaterial(
name: "Titanium",
thermalConductivity: 21.9, // W/(mΒ·K)
specificHeat: 523, // J/(kgΒ·K)
density: 4507, // kg/mΒ³
dynamicViscosity: 0, // not a fluid
electricPermittivity: 0,
youngsModulus: 116e9, // Pa
poissonsRatio: 0.34);
π² Fuel Models (Anderson 13)β
The FuelModel readonly struct holds Rothermel fuel parameters. All 13 standard Anderson models are pre-loaded in FuelLibrary.
// All models are in SI units
FuelModel chaparral = FuelLibrary.Get(FuelModelType.Chaparral);
// chaparral.SurfaceAreaToVolumeRatio = 4921 (1/m)
// chaparral.FuelBedDepth = 1.829 (m)
// chaparral.OvendryFuelLoad = 3.663 (kg/mΒ²)
// chaparral.MoistureOfExtinction = 0.20
// Iterate all models
foreach (var fuel in FuelLibrary.All)
Console.WriteLine($"{fuel.Type}: Ξ΄={fuel.FuelBedDepth:F3} m");
// Register a custom fuel model at runtime
FuelLibrary.Register(new FuelModel(
(FuelModelType)99, "Custom Sage", sigma: 5000,
delta: 0.5, w0: 1.2, Mx: 0.25, h: 18000));
| Model | Type | Ο (1/m) | Ξ΄ (m) | wβ (kg/mΒ²) | Mβ |
|---|---|---|---|---|---|
| 1 | Short Grass | 11,483 | 0.305 | 0.166 | 0.12 |
| 2 | Timber/Grass Understory | 3,281 | 0.305 | 0.897 | 0.15 |
| 3 | Tall Grass | 4,921 | 0.762 | 0.675 | 0.25 |
| 4 | Chaparral | 6,562 | 1.829 | 3.663 | 0.20 |
| 5 | Brush | 6,562 | 0.610 | 0.784 | 0.20 |
| 6 | Dormant Brush | 5,741 | 0.762 | 0.672 | 0.25 |
| 7 | Southern Rough | 5,741 | 0.762 | 0.529 | 0.40 |
| 8 | Closed Timber Litter | 6,562 | 0.061 | 1.121 | 0.30 |
| 9 | Hardwood Litter | 8,202 | 0.061 | 0.327 | 0.25 |
| 10 | Timber/Litter Understory | 6,562 | 0.305 | 1.121 | 0.25 |
| 11 | Light Logging Slash | 4,921 | 0.305 | 1.345 | 0.15 |
| 12 | Medium Logging Slash | 4,921 | 0.701 | 3.363 | 0.20 |
| 13 | Heavy Logging Slash | 4,921 | 0.914 | 5.604 | 0.25 |
π¦ Optical Materialsβ
Pre-defined media are available via OpticalMaterialLibrary or the Materials.Optical() factory:
using CSharpNumerics.Physics.Materials;
using CSharpNumerics.Physics.Optics;
var diamond = OpticalMaterialLibrary.Diamond; // n=2.417
var bk7 = Materials.Optical("CrownGlass"); // factory lookup
var flint = Materials.Optical("SF11"); // n=1.7847, low Abbe -> high dispersion
π Aquatic Contaminantsβ
Pre-loaded contaminant library with decay, adsorption, and toxicity data:
Namespace: CSharpNumerics.Physics.Materials.Water
using CSharpNumerics.Physics.Materials.Water;
// Built-in contaminants: Cs137, Sr90, I131, Benzene, Toluene, Cyanide,
// Mercury, Lead, Arsenic, EColi, Enterococcus, GenericHeat
var cs137 = ContaminantLibrary.Get("Cs-137");
// cs137.HalfLifeSeconds β 9.5Γ10βΈ, cs137.PartitionCoefficient = 1000, etc.
var benzene = AquaticContaminant.Benzene;
bool isConservative = benzene.IsConservative; // false (has half-life)
double lambda = benzene.DecayConstant; // ln(2) / tΒ½
// Create a custom contaminant
var custom = new AquaticContaminant("PFOS",
ContaminantType.Chemical,
halfLifeSeconds: 0, // persistent (conservative tracer)
partitionCoefficient: 10,
toxicityThresholdMgL: 0.00007,
lethalThresholdMgL: 50);
ContaminantLibrary.Register(custom);
Pre-defined Contaminants
| Contaminant | Type | Half-life | Kd (L/kg) | Toxicity (mg/L) |
|---|---|---|---|---|
| Cs-137 | Radioactive | 30.17 yr | 1000 | 0.002 |
| Sr-90 | Radioactive | 28.8 yr | 200 | 0.008 |
| I-131 | Radioactive | 8.02 d | 10 | 0.003 |
| Benzene | Chemical | 180 d | 1.8 | 0.005 |
| Cyanide | Chemical | β | 0 | 0.07 |
| Mercury | Chemical | β | 5000 | 0.001 |
| E. coli | Biological | 2 d | 0 | 0.0001 |
π¦ Biological Materials β Bioaerosol Agentsβ
Namespace: CSharpNumerics.Physics.Materials.Biological
Model biological aerosol agents (viruses, bacteria, spores) with viability decay, unit-mass conversion (kg/mΒ³ β units/mΒ³), and screening-level infectious dose layers. Integrates with the GIS dispersion pipeline via Materials.Biological("Virus").
Agent propertiesβ
| Property | Description |
|---|---|
Code | Short identifier for lookup (e.g. "Virus") |
Name | Human-readable name |
Classification | BiologicalAgentClass enum: Virus, Bacteria, Spore |
TypicalDiameterMicrons | Representative aerodynamic diameter (Β΅m) |
UnitMassKg | Mass of one biological unit (kg) β converts kg/mΒ³ β units/mΒ³ |
ViabilityHalfLifeSeconds | Screening half-life for viability in air (seconds) |
IsPersistent | true when viability is treated as non-decaying |
Built-in agentsβ
| Code | Name | Class | Diameter (Β΅m) | Unit mass (kg) | Viability tΒ½ |
|---|---|---|---|---|---|
| Virus | Generic Viral Aerosol | Virus | 0.12 | 1 Γ 10β»ΒΉβΈ | 6 h |
| Bacteria | Generic Bacterial Aerosol | Bacteria | 1.5 | 1 Γ 10β»ΒΉβ΅ | 12 h |
| Spore | Generic Biological Spore | Spore | 2.5 | 3 Γ 10β»ΒΉβ΅ | 7 d |
Agent lookup & custom registrationβ
using CSharpNumerics.Physics.Materials.Biological;
// Static instances
BiologicalAgent virus = BiologicalAgent.GenericVirus;
BiologicalAgent bacteria = BiologicalAgent.GenericBacteria;
BiologicalAgent spore = BiologicalAgent.GenericSpore;
// Library lookup (case-insensitive, supports aliases)
BiologicalAgent v = BiologicalLibrary.Get("virus");
BiologicalAgent s = BiologicalLibrary.Get("Spores"); // alias
bool found = BiologicalLibrary.TryGet("bacteria", out BiologicalAgent b);
// All registered agents (de-duplicated)
IReadOnlyCollection<BiologicalAgent> all = BiologicalLibrary.All();
// Register custom agent with aliases
BiologicalLibrary.Register(
new BiologicalAgent(
code: "Anthrax",
name: "Bacillus anthracis spore",
classification: BiologicalAgentClass.Spore,
typicalDiameterMicrons: 1.5,
unitMassKg: 1e-15,
viabilityHalfLifeSeconds: 30 * 24 * 3600), // 30 days
"anthrax", "b.anthracis");
Unit conversion (kg/mΒ³ β units/mΒ³)β
BiologicalAgent bacteria = BiologicalAgent.GenericBacteria;
// Convert mass concentration to biological units per mΒ³
double units = bacteria.KgM3ToUnitsPerM3(2.5e-12); // 2500 units/mΒ³
double kgm3 = bacteria.UnitsPerM3ToKgM3(units); // round-trip
// Viability fraction at a given time
double fraction = bacteria.ViabilityFractionAt(6 * 3600); // after 6 h
GIS pipeline integrationβ
using CSharpNumerics.Physics.Materials;
// Attach biological material to a dispersion scenario
var sim = new PlumeSimulator(
2.0, 8, new Vector(1, 0, 0), 50,
new Vector(0, 0, 50), StabilityClass.D);
sim.Material = Materials.Biological("Bacteria");
var snaps = sim.Run(grid, tf);
// Snapshot layers: "bioUnits", "viableBioUnits", and "infectiousDose"
double[] bioUnits = snaps[0].GetLayer("bioUnits");
double[] viable = snaps[0].GetLayer("viableBioUnits");
double[] infectious = snaps[0].GetLayer("infectiousDose");
The viableBioUnits layer applies exponential viability decay based on the agent's half-life, so viable counts decrease over successive time steps while raw bioUnits reflect total transported mass only.