Class: RTKIT::DoseDistribution

Inherits:
Object
  • Object
show all
Defined in:
lib/rtkit/dose_distribution.rb

Overview

Contains DICOM data and methods related to a DoseDistribution, a collection of dose points extracted from a dose volume.

Relations

  • A DoseDistribution belongs to the DoseVolume from which it was created.

  • A DoseDistribution contains various methods to return a Dose (point) instance.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(doses, volume) ⇒ DoseDistribution

Creates a new DoseDistribution instance.

Parameters

  • doses – An array/NArray of doses (floats).

  • volume – The DoseVolume which this DoseDistribution belongs to.

Raises:

  • (ArgumentError)


49
50
51
52
53
54
55
56
# File 'lib/rtkit/dose_distribution.rb', line 49

def initialize(doses, volume)
  #raise ArgumentError, "Invalid argument 'doses'. Expected Array, got #{doses.class}." unless doses.is_a?(Array)
  raise ArgumentError, "Invalid argument 'volume'. Expected DoseVolume, got #{volume.class}." unless volume.is_a?(DoseVolume)
  # Store doses as a sorted (float) NArray:
  @doses = NArray.to_na(doses).sort.to_type(4)
  # Set references:
  @volume = volume
end

Instance Attribute Details

#dosesObject (readonly)

The doses values belonging to this distribution (array of floats).



14
15
16
# File 'lib/rtkit/dose_distribution.rb', line 14

def doses
  @doses
end

#volumeObject (readonly)

The DoseVolume that the DoseDistribution is derived from.



16
17
18
# File 'lib/rtkit/dose_distribution.rb', line 16

def volume
  @volume
end

Class Method Details

.create(bin_volume) ⇒ Object

Creates a new DoseDistribution instance from a BinVolume. The BinVolume is typically defined from a ROI delineation against a DoseVolume. Returns the DoseDistribution instance.

Parameters

  • bin_volume – A BinVolume, referencing a DoseVolume, from which to extract a DoseDistribution.

Raises:

  • (ArgumentError)


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/rtkit/dose_distribution.rb', line 26

def self.create(bin_volume)
  raise ArgumentError, "Invalid argument 'bin_volume'. Expected BinVolume, got #{bin_volume.class}." unless bin_volume.is_a?(BinVolume)
  raise ArgumentError, "Invalid argument 'bin_volume'. It must reference a DoseVolume, got #{bin_volume.bin_images.first.image.series.class}." unless bin_volume.bin_images.first.image.series.is_a?(DoseVolume)
  dose_volume = bin_volume.bin_images.first.image.series
  # Extract a selection of pixel values from the dose images based on the provided binary volume:
  dose_values = NArray.sfloat(0)
  bin_volume.bin_images.each do |bin_image|
    slice_pixel_values = bin_image.image.pixel_values(bin_image.selection)
    slice_dose_values = slice_pixel_values.to_type(4) * bin_image.image.series.scaling
    dose_values = NArray[*dose_values, *slice_dose_values]
  end
  # Create the DoseDistribution instance:
  dd = self.new(dose_values, dose_volume)
  return dd
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?

Returns true if the argument is an instance with attributes equal to self.



60
61
62
63
64
# File 'lib/rtkit/dose_distribution.rb', line 60

def ==(other)
  if other.respond_to?(:to_dose_distribution)
    other.send(:state) == state
  end
end

#d(percent) ⇒ Object

Calculates the dose that at least the specified percentage of the volume receives. Returns a dose (Float) in units of Gy.

Parameters

  • percent – Integer/Float. The percent of the volume which receives a dose higher than the returned dose.

Examples

# Calculate the near minimum dose (e.g. up to 2 % of the volume receives a dose less than this):
near_min = ptv_distribution.d(98)
# Calculate the near maximum dose (e.g. at most 2 % of the volume receives a dose higher than this):
near_max = ptv_distribution.d(2)

Raises:

  • (RangeError)


83
84
85
86
87
# File 'lib/rtkit/dose_distribution.rb', line 83

def d(percent)
  raise RangeError, "Argument 'percent' must be in the range [0-100]." if percent.to_f < 0 or percent.to_f > 100
  d_index = ((@doses.length - 1) * (1 - percent.to_f * 0.01)).round
  return @doses[d_index]
end

#hashObject

Generates a Fixnum hash value for this instance.



91
92
93
# File 'lib/rtkit/dose_distribution.rb', line 91

def hash
  state.hash
end

#hindexObject

Calculates the homogeneity index of the dose distribution. A low (near zero) value corresponds to high homogeneity (e.q. 0.1). Returns the index value as a float.

Notes

  • The homogeneity index is defined as:

HI = ( d(2) - d(98) ) / d(50)
For more details, refer to ICRU Report No. 83, Chapter 3.7.1.

Examples

# Calculate the homogeneity index of the dose distribution of a PTV ROI for a given plan:
homogeneity_index = ptv_distribution.hindex


110
111
112
# File 'lib/rtkit/dose_distribution.rb', line 110

def hindex
  return (d(2) - d(98)) / d(50).to_f
end

#lengthObject Also known as: size

Returns the number of dose values in the DoseDistribution.



116
117
118
# File 'lib/rtkit/dose_distribution.rb', line 116

def length
  @doses.length
end

#maxObject

Calculates the maximum dose.



124
125
126
# File 'lib/rtkit/dose_distribution.rb', line 124

def max
  @doses.max
end

#meanObject

Calculates the arithmethic mean (average) dose.



130
131
132
# File 'lib/rtkit/dose_distribution.rb', line 130

def mean
  @doses.mean
end

#medianObject

Calculates the median dose.



136
137
138
# File 'lib/rtkit/dose_distribution.rb', line 136

def median
  @doses.median
end

#minObject

Calculates the minimum dose.



142
143
144
# File 'lib/rtkit/dose_distribution.rb', line 142

def min
  @doses.min
end

#rmsdevObject

Calculates the root mean square deviation (the population standard deviation).

Notes

  • Uses N in the denominator for calculating the standard deviation of the sample.



152
153
154
# File 'lib/rtkit/dose_distribution.rb', line 152

def rmsdev
  @doses.rmsdev
end

#stddevObject

Calculates the sample standard deviation of the dose distribution.

Notes

  • Uses Bessel’s correction (N-1 in the denominator).



162
163
164
# File 'lib/rtkit/dose_distribution.rb', line 162

def stddev
  @doses.stddev
end

#to_dose_distributionObject

Returns self.



168
169
170
# File 'lib/rtkit/dose_distribution.rb', line 168

def to_dose_distribution
  self
end

#v(dose) ⇒ Object

Calculates the percentage of the volume that receives a dose higher than or equal to the specified dose. Returns a percentage (Float).

Parameters

  • dose – Integer/Float. The dose threshold value to apply to the dose distribution.

Examples

# Calculate the low dose spread (e.g. the percentage of the lung that receives a dose higher than 5 Gy):
coverage_low = lung_distribution.v(5)
# Calculate the high dose spread (e.g. the percentage of the lung that receives a dose higher than 20 Gy):
coverage_high = lung_distribution.v(20)

Raises:

  • (RangeError)


187
188
189
190
191
192
193
# File 'lib/rtkit/dose_distribution.rb', line 187

def v(dose)
  raise RangeError, "Argument 'dose' cannot be negative." if dose.to_f < 0
  # How many dose values are higher than the threshold?
  num_above = (@doses.ge dose.to_f).where.length
  # Divide by total number of elements and convert to percentage:
  return num_above / @doses.length.to_f * 100
end