Files
rustytorch/demos/bioheat-shared/src/physics.rs
T
2026-03-04 00:08:42 +00:00

332 lines
9.5 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Physics parameters for Pennes Bioheat equation
//!
//! The Pennes bioheat equation models heat transfer in biological tissue:
//! ```text
//! ρc(∂T/∂t) = k∇²T + ωb·ρb·cb·(Ta - T) + Qm + Qs
//! ```
use serde::{Deserialize, Serialize};
/// Type of biological tissue with predefined thermal properties
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum TissueType {
/// Healthy liver tissue (most common for RF ablation)
#[default]
Liver,
/// Kidney tissue
Kidney,
/// Tumor tissue (generally lower perfusion)
Tumor,
/// Skeletal muscle
Muscle,
/// Adipose (fat) tissue
Fat,
/// Custom tissue with user-defined properties
Custom,
}
impl TissueType {
/// Get all available tissue types
#[must_use]
pub fn all() -> &'static [Self] {
&[
Self::Liver,
Self::Kidney,
Self::Tumor,
Self::Muscle,
Self::Fat,
]
}
/// Get display name for the tissue type
#[must_use]
pub fn display_name(&self) -> &'static str {
match self {
Self::Liver => "Liver",
Self::Kidney => "Kidney",
Self::Tumor => "Tumor",
Self::Muscle => "Muscle",
Self::Fat => "Fat",
Self::Custom => "Custom",
}
}
}
/// Thermal properties of biological tissue
///
/// All values are in SI units.
/// Reference: Pennes HH. Analysis of Tissue and Arterial Blood Temperatures
/// in the Resting Human Forearm. J Appl Physiol. 1948.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct TissueProperties {
/// Tissue type for identification
pub tissue_type: TissueType,
/// Tissue density (kg/m³)
/// Typical range: 900-1100 kg/m³
pub density: f32,
/// Specific heat capacity (J/kg/K)
/// Typical range: 3000-4000 J/kg/K
pub specific_heat: f32,
/// Thermal conductivity (W/m/K)
/// Typical range: 0.3-0.6 W/m/K
pub thermal_conductivity: f32,
/// Blood perfusion rate (1/s or mL/mL/s)
/// This is volumetric perfusion: blood volume per tissue volume per second
/// Typical range: 0.0001-0.02 1/s
pub blood_perfusion: f32,
/// Metabolic heat generation (W/m³)
/// Typical range: 400-5000 W/m³
pub metabolic_heat: f32,
}
impl TissueProperties {
/// Create properties for healthy liver tissue
/// Reference: IT'IS Foundation tissue properties database
#[must_use]
pub fn liver() -> Self {
Self {
tissue_type: TissueType::Liver,
density: 1079.0, // kg/m³
specific_heat: 3540.0, // J/kg/K
thermal_conductivity: 0.52, // W/m/K
blood_perfusion: 0.0167, // 1/s (high perfusion organ)
metabolic_heat: 4200.0, // W/m³
}
}
/// Create properties for kidney tissue
#[must_use]
pub fn kidney() -> Self {
Self {
tissue_type: TissueType::Kidney,
density: 1050.0,
specific_heat: 3900.0,
thermal_conductivity: 0.54,
blood_perfusion: 0.0833, // Very high perfusion
metabolic_heat: 5000.0,
}
}
/// Create properties for tumor tissue
/// Tumors typically have reduced blood flow compared to surrounding tissue
#[must_use]
pub fn tumor() -> Self {
Self {
tissue_type: TissueType::Tumor,
density: 1050.0,
specific_heat: 3600.0,
thermal_conductivity: 0.50,
blood_perfusion: 0.005, // Lower perfusion than healthy tissue
metabolic_heat: 5000.0, // Often higher metabolic rate
}
}
/// Create properties for skeletal muscle
#[must_use]
pub fn muscle() -> Self {
Self {
tissue_type: TissueType::Muscle,
density: 1090.0,
specific_heat: 3421.0,
thermal_conductivity: 0.49,
blood_perfusion: 0.0005, // Low at rest, increases with activity
metabolic_heat: 684.0,
}
}
/// Create properties for adipose (fat) tissue
#[must_use]
pub fn fat() -> Self {
Self {
tissue_type: TissueType::Fat,
density: 911.0,
specific_heat: 2348.0,
thermal_conductivity: 0.21, // Low thermal conductivity
blood_perfusion: 0.0003, // Low perfusion
metabolic_heat: 300.0,
}
}
/// Create properties from tissue type
#[must_use]
pub fn from_type(tissue_type: TissueType) -> Self {
match tissue_type {
TissueType::Liver => Self::liver(),
TissueType::Kidney => Self::kidney(),
TissueType::Tumor => Self::tumor(),
TissueType::Muscle => Self::muscle(),
TissueType::Fat => Self::fat(),
TissueType::Custom => Self::liver(), // Default to liver for custom
}
}
/// Thermal diffusivity α = k / (ρc) in m²/s
#[must_use]
pub fn thermal_diffusivity(&self) -> f32 {
self.thermal_conductivity / (self.density * self.specific_heat)
}
/// Product ρc (volumetric heat capacity) in J/m³/K
#[must_use]
pub fn volumetric_heat_capacity(&self) -> f32 {
self.density * self.specific_heat
}
}
impl Default for TissueProperties {
fn default() -> Self {
Self::liver()
}
}
/// Properties of blood for perfusion term
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub struct BloodProperties {
/// Blood density (kg/m³)
pub density: f32,
/// Blood specific heat (J/kg/K)
pub specific_heat: f32,
/// Arterial blood temperature (°C)
pub arterial_temperature: f32,
}
impl BloodProperties {
/// Standard human blood properties
#[must_use]
pub fn human() -> Self {
Self {
density: 1060.0, // kg/m³
specific_heat: 3617.0, // J/kg/K
arterial_temperature: 37.0, // °C (body core temperature)
}
}
}
impl Default for BloodProperties {
fn default() -> Self {
Self::human()
}
}
/// Complete bioheat parameters for simulation
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct BioheatParams {
/// Tissue properties
pub tissue: TissueProperties,
/// Blood properties
pub blood: BloodProperties,
/// Body/boundary temperature (°C)
/// Temperature at the domain boundary (far from probe)
pub body_temperature: f32,
}
impl BioheatParams {
/// Create parameters for liver ablation
#[must_use]
pub fn liver_ablation() -> Self {
Self {
tissue: TissueProperties::liver(),
blood: BloodProperties::human(),
body_temperature: 37.0,
}
}
/// Create parameters for tumor in liver
#[must_use]
pub fn liver_tumor() -> Self {
Self {
tissue: TissueProperties::tumor(),
blood: BloodProperties::human(),
body_temperature: 37.0,
}
}
/// Create parameters from tissue type
#[must_use]
pub fn from_tissue_type(tissue_type: TissueType) -> Self {
Self {
tissue: TissueProperties::from_type(tissue_type),
blood: BloodProperties::human(),
body_temperature: 37.0,
}
}
/// Calculate the perfusion coefficient: ωb * ρb * cb
/// Units: W/m³/K
#[must_use]
pub fn perfusion_coefficient(&self) -> f32 {
self.tissue.blood_perfusion * self.blood.density * self.blood.specific_heat
}
/// Temperature at which tissue is considered ablated (°C)
/// Cell death occurs rapidly above 60°C (coagulative necrosis)
pub const ABLATION_THRESHOLD: f32 = 60.0;
/// Temperature at which tissue desiccates/chars (°C)
/// Above 100°C, water boils and tissue chars
pub const DESICCATION_THRESHOLD: f32 = 100.0;
}
impl Default for BioheatParams {
fn default() -> Self {
Self::liver_ablation()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tissue_properties() {
let liver = TissueProperties::liver();
assert_eq!(liver.tissue_type, TissueType::Liver);
assert!(liver.density > 1000.0);
assert!(liver.thermal_conductivity > 0.0);
}
#[test]
fn test_thermal_diffusivity() {
let liver = TissueProperties::liver();
let alpha = liver.thermal_diffusivity();
// Typical soft tissue diffusivity: ~1.5e-7 m²/s
assert!(alpha > 1e-8 && alpha < 1e-6);
}
#[test]
fn test_perfusion_coefficient() {
let params = BioheatParams::liver_ablation();
let coeff = params.perfusion_coefficient();
// Should be positive and significant for liver
assert!(coeff > 10000.0); // W/m³/K
}
#[test]
fn test_tissue_type_from() {
for tissue_type in TissueType::all() {
let props = TissueProperties::from_type(*tissue_type);
assert_eq!(props.tissue_type, *tissue_type);
}
}
#[test]
fn test_serialize_tissue_type() {
let tissue = TissueType::Liver;
let json = serde_json::to_string(&tissue).unwrap();
assert_eq!(json, "\"Liver\"");
}
#[test]
fn test_serialize_params() {
let params = BioheatParams::liver_ablation();
let json = serde_json::to_string(&params).unwrap();
let deserialized: BioheatParams = serde_json::from_str(&json).unwrap();
assert_eq!(params.tissue.tissue_type, deserialized.tissue.tissue_type);
}
}