跳转至

剂量计算

学习目标

通过本文档的学习,你将能够:

  • 理解放射治疗剂量计算的基本原理
  • 掌握常用的剂量计算算法
  • 了解剂量计算的质量保证方法
  • 理解剂量计算在治疗计划中的应用

前置知识

在学习本文档之前,建议你已经掌握:

  • 放射物理学基础
  • 医学影像学基础
  • 基本的数值计算方法
  • 放射治疗系统概述

概述

剂量计算是放射治疗计划系统(TPS)的核心功能,用于精确计算患者体内的辐射剂量分布。准确的剂量计算对于确保治疗效果和患者安全至关重要。

剂量计算基础

1. 基本概念

吸收剂量: - 定义:单位质量物质吸收的辐射能量 - 单位:戈瑞(Gy),1 Gy = 1 J/kg - 临床应用:处方剂量、靶区剂量、危及器官剂量

剂量分布: - 等剂量线:剂量相等的点连接而成的曲线 - 剂量体积直方图(DVH):描述体积与剂量关系的图表 - 剂量梯度:剂量变化的空间速率

2. 影响因素

射线特性: - 射线类型:光子、电子、质子 - 能量:影响穿透深度和剂量分布 - 束流强度:决定剂量率

患者因素: - 组织密度:影响射线衰减 - 组织成分:不同组织的吸收特性 - 体表轮廓:影响射线入射条件

几何因素: - 源皮距(SSD):射线源到皮肤的距离 - 照射野大小:影响散射和剂量分布 - 照射角度:影响剂量分布的空间特性

剂量计算算法

1. 基于测量的算法

百分深度剂量(PDD)法

def calculate_pdd_dose(reference_dose, pdd_value, ssd_correction):
    """
    基于PDD的剂量计算

    参数:
        reference_dose: 参考点剂量 (Gy)
        pdd_value: 百分深度剂量值 (%)
        ssd_correction: SSD修正因子

    返回:
        计算的剂量 (Gy)
    """
    dose = reference_dose * (pdd_value / 100.0) * ssd_correction
    return dose

# 示例
reference_dose = 2.0  # Gy
pdd_at_depth = 85.0   # %
ssd_factor = 1.02
calculated_dose = calculate_pdd_dose(reference_dose, pdd_at_depth, ssd_factor)
print(f"计算剂量: {calculated_dose:.2f} Gy")

组织空气比(TAR)法: - 适用于等中心照射 - 考虑散射和衰减 - 独立于SSD

2. 模型基础算法

笔形束算法(Pencil Beam)

import numpy as np

class PencilBeamCalculator:
    """笔形束剂量计算器"""

    def __init__(self, beam_energy, field_size):
        self.energy = beam_energy
        self.field_size = field_size
        self.kernel = self._load_dose_kernel()

    def _load_dose_kernel(self):
        """加载剂量核"""
        # 简化示例,实际应从测量数据或Monte Carlo计算获得
        return {
            'primary': np.array([1.0, 0.95, 0.90, 0.85]),
            'scatter': np.array([0.1, 0.08, 0.06, 0.04])
        }

    def calculate_dose(self, depth, off_axis_distance):
        """
        计算指定点的剂量

        参数:
            depth: 深度 (cm)
            off_axis_distance: 离轴距离 (cm)

        返回:
            剂量值 (相对单位)
        """
        # 主射线剂量
        primary_dose = self._calculate_primary(depth)

        # 散射剂量
        scatter_dose = self._calculate_scatter(depth, off_axis_distance)

        # 总剂量
        total_dose = primary_dose + scatter_dose

        return total_dose

    def _calculate_primary(self, depth):
        """计算主射线剂量"""
        # 简化的指数衰减模型
        mu = 0.03  # 衰减系数 (cm^-1)
        return np.exp(-mu * depth)

    def _calculate_scatter(self, depth, off_axis):
        """计算散射剂量"""
        # 简化的散射模型
        scatter_factor = 0.1 * np.exp(-0.02 * depth)
        lateral_falloff = np.exp(-0.05 * off_axis**2)
        return scatter_factor * lateral_falloff

# 使用示例
calculator = PencilBeamCalculator(beam_energy=6, field_size=10)
dose = calculator.calculate_dose(depth=10, off_axis_distance=5)
print(f"计算剂量: {dose:.4f}")

卷积/叠加算法(Convolution/Superposition): - 更准确的散射计算 - 考虑组织不均匀性 - 计算速度较快

3. 蒙特卡罗算法

基本原理

import random
import math

class MonteCarloSimulator:
    """简化的蒙特卡罗剂量计算模拟器"""

    def __init__(self, num_particles=10000):
        self.num_particles = num_particles
        self.dose_grid = {}

    def simulate_photon_transport(self, energy, start_pos):
        """
        模拟光子输运

        参数:
            energy: 初始能量 (MeV)
            start_pos: 起始位置 (x, y, z)

        返回:
            能量沉积位置列表
        """
        position = list(start_pos)
        current_energy = energy
        depositions = []

        while current_energy > 0.01:  # 能量阈值
            # 采样自由程
            mean_free_path = self._get_mean_free_path(current_energy)
            distance = -mean_free_path * math.log(random.random())

            # 更新位置
            direction = self._sample_direction()
            position[0] += distance * direction[0]
            position[1] += distance * direction[1]
            position[2] += distance * direction[2]

            # 采样相互作用类型
            interaction = self._sample_interaction(current_energy)

            if interaction == 'photoelectric':
                # 光电效应:全部能量沉积
                depositions.append((tuple(position), current_energy))
                break
            elif interaction == 'compton':
                # 康普顿散射:部分能量沉积
                energy_transfer = self._sample_compton_energy(current_energy)
                depositions.append((tuple(position), energy_transfer))
                current_energy -= energy_transfer
            elif interaction == 'pair_production':
                # 电子对产生
                depositions.append((tuple(position), current_energy - 1.022))
                break

        return depositions

    def _get_mean_free_path(self, energy):
        """获取平均自由程"""
        # 简化模型
        return 5.0 / (1.0 + 0.1 * energy)

    def _sample_direction(self):
        """采样新方向"""
        # 简化:各向同性
        theta = math.acos(2 * random.random() - 1)
        phi = 2 * math.pi * random.random()
        return (
            math.sin(theta) * math.cos(phi),
            math.sin(theta) * math.sin(phi),
            math.cos(theta)
        )

    def _sample_interaction(self, energy):
        """采样相互作用类型"""
        rand = random.random()
        if energy < 0.5:
            return 'photoelectric' if rand < 0.7 else 'compton'
        elif energy < 1.5:
            return 'compton'
        else:
            if rand < 0.6:
                return 'compton'
            else:
                return 'pair_production'

    def _sample_compton_energy(self, energy):
        """采样康普顿散射能量转移"""
        # 简化的Klein-Nishina公式
        return energy * random.random() * 0.5

    def calculate_dose_distribution(self, beam_energy, beam_position):
        """
        计算剂量分布

        参数:
            beam_energy: 束流能量 (MeV)
            beam_position: 束流位置

        返回:
            剂量网格
        """
        print(f"模拟 {self.num_particles} 个粒子...")

        for i in range(self.num_particles):
            depositions = self.simulate_photon_transport(
                beam_energy, 
                beam_position
            )

            # 累积剂量
            for pos, energy in depositions:
                grid_pos = self._position_to_grid(pos)
                if grid_pos not in self.dose_grid:
                    self.dose_grid[grid_pos] = 0.0
                self.dose_grid[grid_pos] += energy

            if (i + 1) % 1000 == 0:
                print(f"  进度: {i + 1}/{self.num_particles}")

        # 归一化
        self._normalize_dose()

        return self.dose_grid

    def _position_to_grid(self, position):
        """将位置转换为网格坐标"""
        grid_size = 1.0  # cm
        return (
            int(position[0] / grid_size),
            int(position[1] / grid_size),
            int(position[2] / grid_size)
        )

    def _normalize_dose(self):
        """归一化剂量"""
        if not self.dose_grid:
            return

        max_dose = max(self.dose_grid.values())
        for pos in self.dose_grid:
            self.dose_grid[pos] /= max_dose

# 使用示例
simulator = MonteCarloSimulator(num_particles=5000)
dose_dist = simulator.calculate_dose_distribution(
    beam_energy=6.0,
    beam_position=(0, 0, 0)
)
print(f"计算完成,网格点数: {len(dose_dist)}")

质量保证

1. 剂量计算验证

基准测试

class DoseCalculationQA:
    """剂量计算质量保证"""

    def __init__(self, calculator):
        self.calculator = calculator
        self.tolerance = 0.02  # 2% 容差

    def verify_homogeneous_phantom(self):
        """验证均匀模体中的剂量计算"""
        test_cases = [
            {'depth': 5, 'field_size': 10, 'expected': 1.00},
            {'depth': 10, 'field_size': 10, 'expected': 0.67},
            {'depth': 20, 'field_size': 10, 'expected': 0.45},
        ]

        results = []
        for case in test_cases:
            calculated = self.calculator.calculate_dose(
                depth=case['depth'],
                field_size=case['field_size']
            )

            difference = abs(calculated - case['expected']) / case['expected']
            passed = difference <= self.tolerance

            results.append({
                'case': case,
                'calculated': calculated,
                'difference': difference * 100,
                'passed': passed
            })

        return results

    def verify_heterogeneous_phantom(self):
        """验证非均匀模体中的剂量计算"""
        # 包含骨骼、肺等不同密度组织的模体
        pass

    def generate_qa_report(self):
        """生成QA报告"""
        print("=" * 60)
        print("剂量计算质量保证报告")
        print("=" * 60)

        # 均匀模体测试
        print("\n1. 均匀模体测试:")
        results = self.verify_homogeneous_phantom()

        for i, result in enumerate(results, 1):
            status = "✓ 通过" if result['passed'] else "✗ 失败"
            print(f"\n  测试 {i}: {status}")
            print(f"    深度: {result['case']['depth']} cm")
            print(f"    野大小: {result['case']['field_size']} cm")
            print(f"    期望值: {result['case']['expected']:.3f}")
            print(f"    计算值: {result['calculated']:.3f}")
            print(f"    差异: {result['difference']:.2f}%")

        # 统计
        passed_count = sum(1 for r in results if r['passed'])
        print(f"\n总计: {passed_count}/{len(results)} 通过")
        print("=" * 60)

2. 临床验证

患者特定QA: - 独立剂量计算验证 - 测量验证(电离室、胶片、二维阵列) - Gamma分析

最佳实践

算法选择

  • 简单几何:笔形束算法
  • 复杂几何:卷积/叠加算法
  • 高精度要求:蒙特卡罗算法
  • 考虑计算时间和精度的平衡

质量控制

  • 定期进行基准测试
  • 验证算法参数配置
  • 记录和分析偏差
  • 建立纠正措施流程

临床应用

  • 理解算法的局限性
  • 在不确定区域增加测量验证
  • 保持算法和测量数据的一致性
  • 定期更新和校准

合规性要求

IEC 60601-2-1

  • 剂量计算精度要求
  • 质量保证程序
  • 文档要求

AAPM TG报告

  • TG-65:组织不均匀性修正
  • TG-105:蒙特卡罗在治疗计划中的应用
  • TG-329:剂量计算算法的质量保证

工具与资源

开源工具

  • TOPAS:基于Geant4的蒙特卡罗工具
  • DOSXYZnrc:EGSnrc的剂量计算工具
  • PRIMO:用户友好的蒙特卡罗界面

商业系统

  • Eclipse(Varian)
  • RayStation(RaySearch)
  • Pinnacle(Philips)

总结

准确的剂量计算是放射治疗的基础。理解不同算法的原理、适用范围和局限性,建立完善的质量保证体系,对于确保治疗的安全性和有效性至关重要。


相关文档: - 放射治疗概述 - 安全互锁系统

参考文献: - AAPM TG-65: Tissue Inhomogeneity Corrections - IAEA TRS-430: Commissioning and Quality Assurance of TPS - Khan's Physics of Radiation Therapy

标签: #放射治疗 #剂量计算 #治疗计划 #医学物理


💬 讨论区

欢迎在这里分享您的想法、提出问题或参与讨论。需要 GitHub 账号登录。