MU Density

Summary

A suite of functions to determine the MU Density for a range of formats:

>>> from pymedphys.mudensity import (
...     calc_mu_density,
...     calc_single_control_point,
...     single_mlc_pair,
...     get_grid,
...     display_mu_density
... )

Warning

Although this is a useful tool in the toolbox for patient specific IMRT QA, in and of itself it is not a sufficient stand in replacement. This tool does not verify that the reported dose within the treatment planning system is delivered by the Linac.

Deficiencies or limitations in the agreement between the treatment planning system’s beam model and the Linac delivery will not be able to be highlighted by this tool. An example might be an overly modulated beam with many thin sweeping strips, the Linac may deliver those control points with positional accuracy but if the beam model in the TPS cannot sufficiently accurately model the dose effects of those MLC control points the dose delivery will not sufficiently agree with the treatment plan. In this case however, this tool will say everything is in agreement.

It also may be the case that due to a hardware or calibration fault the Linac itself may be incorrectly reporting its MLC and/or Jaw postions. In this case the logfile record can agree exactly with the planned positions while the true real world positions be in significant deviation.

The impact of these issues may be able to be limited by including with this tool an automated independent IMRT 3-D dose calculation tool as well as a daily automated MLC/jaw logfile to EPI to baseline agreement test that moves the EPI so as to measure the full set of leaf pairs and the full range of MLC and Jaw travel.

(Source code, png, hires.png, pdf)

../../_images/mudensity.png

(Source code, png, hires.png, pdf)

../../_images/single_leaf.png

API

pymedphys.mudensity.calc_mu_density(mu, mlc, jaw, grid_resolution=1, max_leaf_gap=400, leaf_pair_widths=(5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5), min_step_per_pixel=10)[source]

Determine the MU Density.

Both jaw and mlc positions are defined in bipolar format for each control point. A negative value indicates travel over the isocentre. All positional arguments are defined at the isocentre projection with the units of mm.

Parameters:
  • mu (numpy.ndarray) – 1-D array containing an MU value for each control point.
  • mlc (numpy.ndarray) –

    3-D array containing the MLC positions

    axis 0: control point
    axis 1: mlc pair
    axis 2: leaf bank
  • jaw (numpy.ndarray) –

    2-D array containing the jaw positions.

    axis 0: control point
    axis 1: diaphragm
  • grid_resolution (float, optional) – The calc grid resolution. Defaults to 1 mm.
  • max_leaf_gap (float, optional) – The maximum possible distance between opposing leaves. Defaults to 400 mm.
  • leaf_pair_widths (tuple, optional) – The widths of each leaf pair in the MLC limiting device. The number of entries in the tuples defines the number of leaf pairs. Each entry itself defines that particular leaf pair width. Defaults to 80 leaf pairs each 5 mm wide.
  • min_step_per_pixel (int, optional) – The minimum number of time steps used per pixel for each control point. Defaults to 10.
Returns:

mu_density

2-D array containing the calculated mu density.

axis 0: jaw direction
axis 1: mlc direction

Return type:

numpy.ndarray

Examples

>>> import numpy as np
>>>
>>> from pymedphys_analysis.mudensity import (
...     calc_mu_density, get_grid, display_mu_density)
>>>
>>> leaf_pair_widths = (5, 5, 5)
>>> max_leaf_gap = 10
>>> mu = np.array([0, 2, 5, 10])
>>> mlc = np.array([
...     [
...         [1, 1],
...         [2, 2],
...         [3, 3]
...     ],
...     [
...         [2, 2],
...         [3, 3],
...         [4, 4]
...     ],
...     [
...         [-2, 3],
...         [-2, 4],
...         [-2, 5]
...     ],
...     [
...         [0, 0],
...         [0, 0],
...         [0, 0]
...     ]
... ])
>>> jaw = np.array([
...     [7.5, 7.5],
...     [7.5, 7.5],
...     [-2, 7.5],
...     [0, 0]
... ])
>>>
>>> grid = get_grid(
...    max_leaf_gap=max_leaf_gap, leaf_pair_widths=leaf_pair_widths)
>>> grid['mlc']
array([-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.])
>>>
>>> grid['jaw']
array([-8., -7., -6., -5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,
        5.,  6.,  7.,  8.])
>>>
>>> mu_density = calc_mu_density(
...    mu, mlc, jaw, max_leaf_gap=max_leaf_gap,
...    leaf_pair_widths=leaf_pair_widths)
>>> display_mu_density(grid, mu_density)
>>>
>>> np.round(mu_density, 1)
array([[0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],
       [0. , 0. , 0. , 0.3, 1.9, 2.2, 1.9, 0.4, 0. , 0. , 0. ],
       [0. , 0. , 0. , 0.4, 2.2, 2.5, 2.2, 0.6, 0. , 0. , 0. ],
       [0. , 0. , 0. , 0.4, 2.4, 2.8, 2.5, 0.8, 0. , 0. , 0. ],
       [0. , 0. , 0. , 0.4, 2.5, 3.1, 2.8, 1. , 0. , 0. , 0. ],
       [0. , 0. , 0. , 0.4, 2.5, 3.4, 3.1, 1.3, 0. , 0. , 0. ],
       [0. , 0. , 0.4, 2.3, 3.2, 3.7, 3.7, 3.5, 1.6, 0. , 0. ],
       [0. , 0. , 0.4, 2.3, 3.2, 3.8, 4. , 3.8, 1.9, 0.1, 0. ],
       [0. , 0. , 0.4, 2.3, 3.2, 3.8, 4.3, 4.1, 2.3, 0.1, 0. ],
       [0. , 0. , 0.4, 2.3, 3.2, 3.9, 5.2, 4.7, 2.6, 0.2, 0. ],
       [0. , 0. , 0.4, 2.3, 3.2, 3.8, 5.4, 6.6, 3.8, 0.5, 0. ],
       [0. , 0.3, 2.2, 3. , 3.5, 4. , 5.1, 7.5, 6.7, 3.9, 0.5],
       [0. , 0.3, 2.2, 3. , 3.5, 4. , 4.7, 6.9, 6.7, 3.9, 0.5],
       [0. , 0.3, 2.2, 3. , 3.5, 4. , 4.5, 6.3, 6.4, 3.9, 0.5],
       [0. , 0.3, 2.2, 3. , 3.5, 4. , 4.5, 5.6, 5.7, 3.8, 0.5],
       [0. , 0.3, 2.2, 3. , 3.5, 4. , 4.5, 5.1, 5.1, 3.3, 0.5],
       [0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ]])

MU Density from a Mosaiq record

>>> from pymedphys_analysis.mudensity import (
...     calc_mu_density, get_grid, display_mu_density)
>>>
>>> from pymedphys_databases.msq import (
...     mosaiq_connect, multi_fetch_and_verify_mosaiq)
>>>
>>> def mu_density_from_mosaiq(msq_server_name, field_id):
...     with mosaiq_connect(msq_server_name) as cursor:
...         delivery_data = multi_fetch_and_verify_mosaiq(
...             cursor, field_id)
...
...
...     mu = delivery_data.monitor_units
...     mlc = delivery_data.mlc
...     jaw = delivery_data.jaw
...
...     grid = get_grid()
...     mu_density = calc_mu_density(mu, mlc, jaw)
...     display_mu_density(grid, mu_density)
>>>
>>> mu_density_from_mosaiq('a_server_name', 11111) 

MU Density from a logfile at a given filepath

>>> from pymedphys_analysis.mudensity import (
...     calc_mu_density, get_grid, display_mu_density)
>>>
>>> from pymedphys_fileformats.trf import delivery_data_from_logfile
>>>
>>> def mu_density_from_logfile(filepath):
...     delivery_data = delivery_data_from_logfile(filepath)
...
...     mu = delivery_data.monitor_units
...     mlc = delivery_data.mlc
...     jaw = delivery_data.jaw
...
...     grid = get_grid()
...     mu_density = calc_mu_density(mu, mlc, jaw)
...     display_mu_density(grid, mu_density)
>>>
>>> mu_density_from_logfile(r"a/path/goes/here") 

(Source code, png, hires.png, pdf)

../../_images/mudensity.png
pymedphys.mudensity.calc_single_control_point(mlc, jaw, delivered_mu=1, leaf_pair_widths=(5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5), grid_resolution=1, min_step_per_pixel=10)[source]

Calculate the MU Density for a single control point.

Examples

>>> import numpy as np
>>> from pymedphys_analysis.mudensity import (
...     calc_single_control_point, display_mu_density)
>>>
>>> leaf_pair_widths = (2, 2)
>>> mlc = np.array([
...     [
...         [1, 1],
...         [2, 2],
...     ],
...     [
...         [2, 2],
...         [3, 3],
...     ]
... ])
>>> jaw = np.array([
...     [1.5, 1.2],
...     [1.5, 1.2]
... ])
>>> grid, mu_density = calc_single_control_point(
...     mlc, jaw, leaf_pair_widths=leaf_pair_widths)
>>> display_mu_density(grid, mu_density)
>>>
>>> grid['mlc']
array([-3., -2., -1.,  0.,  1.,  2.,  3.])
>>>
>>> grid['jaw']
array([-1.5, -0.5,  0.5,  1.5])
>>>
>>> np.round(mu_density, 2)
array([[0.  , 0.07, 0.43, 0.5 , 0.43, 0.07, 0.  ],
       [0.  , 0.14, 0.86, 1.  , 0.86, 0.14, 0.  ],
       [0.14, 0.86, 1.  , 1.  , 1.  , 0.86, 0.14],
       [0.03, 0.17, 0.2 , 0.2 , 0.2 , 0.17, 0.03]])
pymedphys.mudensity.single_mlc_pair(left_mlc, right_mlc, grid_resolution=1, min_step_per_pixel=10)[source]

Calculate the MU Density of a single leaf pair.

Examples

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>>
>>> from pymedphys_analysis.mudensity import single_mlc_pair
>>>
>>> mlc_left = (-2.3, 3.1)  # (start position, end position)
>>> mlc_right = (0, 7.7)
>>>
>>> x, mu_density = single_mlc_pair(mlc_left, mlc_right)
>>> fig = plt.plot(x, mu_density, '-o')
>>>
>>> x
array([-2., -1.,  0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.])
>>>
>>> np.round(mu_density, 3)
array([0.064, 0.244, 0.408, 0.475, 0.53 , 0.572, 0.481, 0.352, 0.224,
       0.096, 0.004])

(Source code, png, hires.png, pdf)

../../_images/single_leaf.png
pymedphys.mudensity.get_grid(max_leaf_gap=400, grid_resolution=1, leaf_pair_widths=(5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5))[source]

Get the MU Density grid for plotting purposes.

Examples

See pymedphys.mudensity.calc_mu_density.

pymedphys.mudensity.display_mu_density(grid, mu_density, grid_resolution=None)[source]

Prints a colour plot of the MU Density.

Examples

See pymedphys.mudensity.calc_mu_density.