332 lines
9.5 KiB
Rust
332 lines
9.5 KiB
Rust
//! 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(¶ms).unwrap();
|
||
let deserialized: BioheatParams = serde_json::from_str(&json).unwrap();
|
||
assert_eq!(params.tissue.tissue_type, deserialized.tissue.tissue_type);
|
||
}
|
||
}
|