| 
 | 1 | +# %% [markdown]  | 
 | 2 | +"""# Example for proton dose calculation using the FRED engine."""  | 
 | 3 | +# %% [markdown]  | 
 | 4 | +# This example demonstrates how to use the pyRadPlan library to perform proton dose calculations using the FRED Monte Carlo engine.  | 
 | 5 | + | 
 | 6 | +# For installation instructions, please refer to https://www.fred-mc.org/  | 
 | 7 | + | 
 | 8 | +# To display this script in a Jupyter Notebook, you need to install jupytext via pip and run the following command.  | 
 | 9 | +# This will create a .ipynb file in the same directory:  | 
 | 10 | + | 
 | 11 | +# ```bash  | 
 | 12 | +# pip install jupytext  | 
 | 13 | +# jupytext --to notebook path/to/this/file/proton_MC_FRED.py  | 
 | 14 | + | 
 | 15 | +# %%  | 
 | 16 | +# Import necessary libraries  | 
 | 17 | +import logging  | 
 | 18 | +import numpy as np  | 
 | 19 | + | 
 | 20 | +from pyRadPlan import (  | 
 | 21 | +    IonPlan,  | 
 | 22 | +    generate_stf,  | 
 | 23 | +    calc_dose_influence,  | 
 | 24 | +    calc_dose_forward,  | 
 | 25 | +    load_tg119,  | 
 | 26 | +    fluence_optimization,  | 
 | 27 | +    plot_slice,  | 
 | 28 | +)  | 
 | 29 | + | 
 | 30 | +from pyRadPlan.optimization.objectives import SquaredDeviation, SquaredOverdosing, MeanDose  | 
 | 31 | + | 
 | 32 | +logging.basicConfig(level=logging.INFO)  | 
 | 33 | + | 
 | 34 | +# %%  | 
 | 35 | +# Load TG119 (provided within pyRadPlan)  | 
 | 36 | +ct, cst = load_tg119()  | 
 | 37 | + | 
 | 38 | +# %% [markdown]  | 
 | 39 | +# In this section, we create a proton therapy plan using the FRED engine.  | 
 | 40 | +# First, we define the parameters for the steering information (`prop_stf`).  | 
 | 41 | +# Next, we specify the settings for dose calculation (`prop_dose_calc`),  | 
 | 42 | +# including compatibility with different FRED versions through `dij_format_version`.  | 
 | 43 | +# Finally, we configure the optimization parameters (`prop_opt`), as demonstrated in previous examples.  | 
 | 44 | + | 
 | 45 | +# Use less histories and beams when experimenting. This reduces computation time significantly.  | 
 | 46 | + | 
 | 47 | +# %%  | 
 | 48 | +pln = IonPlan(radiation_mode="protons", machine="Generic")  | 
 | 49 | +pln.prop_stf = {  | 
 | 50 | +    "gantry_angles": [0, 180],  # define gantry angles for n beams  | 
 | 51 | +    "couch_angles": [0, 0],  | 
 | 52 | +    "longitudinal_spot_spacing": 2.0,  | 
 | 53 | +    "iso_center": np.array([[-5.0, -5.0, -5.0], [-5.0, -5.0, -5.0]]),  # two beams  | 
 | 54 | +    "bixel_width": 10,  | 
 | 55 | +    "add_margin": 1,  | 
 | 56 | +}  | 
 | 57 | +pln.prop_dose_calc = {  | 
 | 58 | +    "engine": "FRED",  # Use the FRED engine for dose calculation  | 
 | 59 | +    "fred_version": "3.76.0",  # std: "3.70.0"  | 
 | 60 | +    "use_gpu": True,  # std: True | one has to set GPU = 1 using 'fred -config' manually!  | 
 | 61 | +    "calc_let": False,  # std: False  | 
 | 62 | +    "scorers": ["Dose"],  # std: ["Dose"]  | 
 | 63 | +    "room_material": "Air",  # vacuum | std: Air  | 
 | 64 | +    "print_output": False,  | 
 | 65 | +    "num_histories_per_beamlet": 2e3,  # use less histories for faster computation (e.g. 2e2) or less beams  | 
 | 66 | +    # "dij_format_version": "31", # 20/30 for fred 3.70.0 and 21/31 for fred 3.76.0  | 
 | 67 | +    # "save_input": "path/to/save/input",  | 
 | 68 | +    # "save_output": "path/to/save/output", # or True (for current dir)/False | std: False (using temp path)  | 
 | 69 | +    # "use_output": "path/to/use/output",  # skips output file generation if only 'use_output_file' is set and not 'save_output_file'  | 
 | 70 | +}  | 
 | 71 | + | 
 | 72 | +pln.prop_opt = {"solver": "scipy"}  | 
 | 73 | + | 
 | 74 | +# %% [markdown]  | 
 | 75 | +# Generate Steering Geometry ("stf")  | 
 | 76 | +# %%  | 
 | 77 | +stf = generate_stf(ct, cst, pln)  | 
 | 78 | + | 
 | 79 | +# %% [markdown]  | 
 | 80 | +# Run calc_dose_influence (dose influence matrix)  | 
 | 81 | +# %%  | 
 | 82 | +dij = calc_dose_influence(ct, cst, stf, pln)  | 
 | 83 | + | 
 | 84 | +# %% [markdown]  | 
 | 85 | +# Define cst objectives and run fluence optimization  | 
 | 86 | +# %%  | 
 | 87 | +cst.vois[0].objectives = [SquaredOverdosing(priority=100.0, d_max=1.0)]  # OAR  | 
 | 88 | +cst.vois[1].objectives = [SquaredDeviation(priority=1000.0, d_ref=3.0)]  # Target  | 
 | 89 | +cst.vois[2].objectives = [  | 
 | 90 | +    MeanDose(priority=1.0, d_ref=0.0),  | 
 | 91 | +    SquaredOverdosing(priority=10.0, d_max=2.0),  | 
 | 92 | +]  # BODY  | 
 | 93 | + | 
 | 94 | +fluence = fluence_optimization(ct, cst, stf, dij, pln)  | 
 | 95 | + | 
 | 96 | +# %% [markdown]  | 
 | 97 | +# Compute dose distribution and other quantities given in pln.prop_opt  | 
 | 98 | +# %%  | 
 | 99 | +result_opt = dij.compute_result_ct_grid(fluence)  | 
 | 100 | + | 
 | 101 | +# %% [markdown]  | 
 | 102 | +# Visualize the results  | 
 | 103 | +# %%  | 
 | 104 | + | 
 | 105 | +# Choose a slice to visualize  | 
 | 106 | +view_slice = int(np.round(ct.size[2] / 2))  | 
 | 107 | + | 
 | 108 | +plot_slice(  | 
 | 109 | +    ct=ct,  | 
 | 110 | +    cst=cst,  | 
 | 111 | +    overlay=result_opt["physical_dose"],  | 
 | 112 | +    view_slice=view_slice,  | 
 | 113 | +    plane="axial",  | 
 | 114 | +    overlay_unit="Gy",  | 
 | 115 | +)  | 
 | 116 | + | 
 | 117 | +# %% [markdown]  | 
 | 118 | +# You can also run calc_dose_forward (direct dose calculation) without optimization.  | 
 | 119 | +# %%  | 
 | 120 | +# Set run_direct_dose_calc to True to perform direct dose calculation  | 
 | 121 | +run_direct_dose_calc = False  | 
 | 122 | +if run_direct_dose_calc:  | 
 | 123 | +    result_fwd = calc_dose_forward(ct, cst, stf, pln, np.ones(stf.total_number_of_bixels))  | 
0 commit comments