コード例 #1
0
ファイル: structure.py プロジェクト: bungun/conrad
	def A_mean(self, A_mean=None):
		if A_mean is not None:
			if not isinstance(A_mean, ndarray):
				raise TypeError('if argument "A_mean" is provided, it '
								'must be of type {}'.format(ndarray))
			elif not A_mean.size in A_mean.shape:
				raise ValueError('if argument "A_mean" is provided, it must be'
								 ' a row or column vector. shape of argument: '
								 '{}'.format(A_mean.shape))
			else:
				if self.__A_full is not None:
					if len(A_mean) != self.__A_full.shape[1]:
						raise ValueError('field "A_full" already set; '
										 'proposed value for "A_mean" '
										 'must have same number of entries '
										 '({}) as columns in A_full ({})'
										 ''.format(len(A_mean),
										 self.__A_full.shape[1]))
				self.__A_mean = vec(A_mean)
		elif self.__A_full is not None:
			if not sparse_or_dense(self.A_full):
				raise TypeError('cannot calculate structure.A_mean from'
								'structure.A_full: A_full must be one of'
								' ({},{},{})'.format(ndarray, csc_matrix,
								csr_matrix))
			else:
				self.__A_mean = self.A_full.sum(0) / self.A_full.shape[0]
				if not isinstance(self.A_full, ndarray):
					self.__A_mean = vec(self.__A_mean)
コード例 #2
0
ファイル: structure.py プロジェクト: wentaohub/conrad
 def A_mean(self, A_mean=None):
     if A_mean is not None:
         if not isinstance(A_mean, np.ndarray):
             raise TypeError('if argument "A_mean" is provided, it must be '
                             'of type {}'.format(np.ndarray))
         elif not A_mean.size in A_mean.shape:
             raise ValueError(
                 'if argument "A_mean" is provided, it must be '
                 'a row or column vector. shape of argument: {}'
                 ''.format(A_mean.shape))
         else:
             if self.__A_full is not None:
                 if len(A_mean) != self.__A_full.shape[1]:
                     raise ValueError(
                         'field "A_full" already set; proposed '
                         'value for "A_mean" must have same '
                         'number of entries ({}) as columns in '
                         'A_full ({})'.format(len(A_mean),
                                              self.__A_full.shape[1]))
         self.__A_mean = vec(A_mean)
     elif self.__A_full is not None:
         if not sparse_or_dense(self.A_full):
             raise TypeError('cannot calculate structure.A_mean from'
                             'structure.A_full: A_full must be one of '
                             '({},{},{})'.format(np.ndarray, sp.csc_matrix,
                                                 sp.csr_matrix))
         else:
             if isinstance(self.A_full, np.ndarray):
                 self.__A_mean = np.dot(self.voxel_weights, self.A_full)
             else:
                 self.__A_mean = vec(self.voxel_weights * self.A_full)
             self.__A_mean /= float(self.weighted_size)
コード例 #3
0
ファイル: vector.py プロジェクト: wentaohub/conrad
	def data(self, data):
		self._validate(data)
		if isinstance(data, dict):
			data_contiguous = data.pop('contiguous', None)
			if data_contiguous is not None:
				self.data = data_contiguous
				if len(data) == 0:
					return

			for k in data:
				data[k] = vec(data[k]).astype(float)
			size = sum(w.size for w in data.values())
		else:
			data = vec(data).astype(float)
			size = data.size

		if self.size is not None and self.size != size:
			raise ValueError(
					'length of input data does not match known length '
					'of {}'.format(WeightVector))
		else:
			self.__size = size

		if isinstance(data, dict):
			self.__slices.update(data)
			if data_contiguous is not None:
				self.data = data_contiguous
		else:
			self.__data = data
コード例 #4
0
 def primal_eval(self, y, voxel_weights=None):
     residuals = vec(y) - float(self.deadzone_dose)
     residuals *= residuals > 0
     if voxel_weights is None:
         return self.weight * np.sum(residuals)
     else:
         return self.weight * np.dot(voxel_weights, residuals)
コード例 #5
0
ファイル: structure.py プロジェクト: bungun/conrad
	def calc_y(self, x):
		"""
		Calculate voxel doses as :attr:`Structure.y` = :attr:`Structure.A` * ``x``.

		Arguments:
			x: Vector-like input of beam intensities.

		Returns:
			None
		"""

		# calculate dose from input vector x:
		# 	y = Ax
		x = vec(x)
		if isinstance(self.A, (csr_matrix, csc_matrix)):
			self.__y = squeeze(self.A * x)
		elif isinstance(self.A, ndarray):
			self.__y = self.A.dot(x)

		self.__y_mean = self.A_mean.dot(x)
		if isinstance(self.__y_mean, ndarray):
			self.__y_mean = self.__y_mean[0]

		# make DVH curve from calculated dose
		self.dvh.data = self.__y
コード例 #6
0
ファイル: physics.py プロジェクト: wentaohub/conrad
    def indices_by_label(label_vector, label, vector_name):
        """
		Retrieve indices of vector entries corresponding to a given value.

		Arguments:
			label_vector: Vector of values to search for entries
				corresponding
			label: Value to find.
			vector_name (:obj:`str`): Name of vector, for use in
				exception messages.

		Returns:
			:class:`~numpy.ndarray`: Vector of indices at which the
			entries of ``label_vector`` are equal to ``label``.

		Raises:
			ValueError: If ``label_vector`` is ``None``.
			KeyError: If ``label`` not found in ``label_vector``.

		"""
        if label_vector is None:
            raise ValueError('`{}.{}` not set, retrieval by label '
                             'impossible'.format(DoseFrame, vector_name))

        indices = listmap(
            lambda x: x[0],
            listfilter(lambda x: x[1] == label, enumerate(label_vector)))
        if len(indices) == 0:
            raise KeyError('label {} not found in entries of field '
                           '"{}"'.format(label, vector_name))

        return vec(indices)
コード例 #7
0
ファイル: structure.py プロジェクト: wentaohub/conrad
    def calc_y(self, x):
        """
		Calculate voxel doses as:
		attr:`Structure.y` = :attr:`Structure.A` * ``x``.

		Arguments:
			x: Vector-like input of beam intensities.

		Returns:
			None
		"""

        # calculate dose from input vector x:
        # 	y = Ax
        x = vec(x)
        if isinstance(self.A, (sp.csr_matrix, sp.csc_matrix)):
            self.__y = np.squeeze(self.A * x)
        elif isinstance(self.A, np.ndarray):
            self.__y = self.A.dot(x)

        self.__y_mean = self.A_mean.dot(x)
        if isinstance(self.__y_mean, np.ndarray):
            self.__y_mean = self.__y_mean[0]

        # make DVH curve from calculated dose
        if self.y is not None:
            self.dvh.data = self.y
コード例 #8
0
ファイル: physics.py プロジェクト: wentaohub/conrad
 def beam_labels(self, beam_labels):
     if self.beams in (None, np.nan):
         self.beams = len(beam_labels)
     if len(beam_labels) != self.beams:
         raise ValueError('length of `beam labels` ({}) must match '
                          'number of beams in frame ({})'
                          ''.format(len(beam_labels), self.beams))
     self.__beam_labels = vec(beam_labels).astype(int)
コード例 #9
0
ファイル: physics.py プロジェクト: wentaohub/conrad
 def voxel_labels(self, voxel_labels):
     if self.voxels in (None, np.nan):
         self.voxels = len(voxel_labels)
     if len(voxel_labels) != self.voxels:
         raise ValueError('length of "voxel labels" ({}) must match '
                          'number of voxels in frame ({})'
                          ''.format(len(voxel_labels), self.voxels))
     self.__voxel_labels = vec(voxel_labels).astype(int)
コード例 #10
0
 def dual_expr_pogs(self, size, voxel_weights=None):
     if OPTKIT_INSTALLED:
         weights = 1. if voxel_weights is None else vec(voxel_weights)
         return ok.api.PogsObjective(size,
                                     h='Zero',
                                     d=-float(self.deadzone_dose) * weights)
     else:
         raise NotImplementedError
コード例 #11
0
    def dual_domain_constraints(self, nu_var, voxel_weights=None):
        """
		Return the constraint :math:`0 \le \nu \le w`.
		"""
        if voxel_weights is None:
            voxel_weights = 1
        else:
            voxel_weights = vec(voxel_weights)
        return [nu_var <= voxel_weights * self.weight, nu_var >= 0]
コード例 #12
0
ファイル: physics.py プロジェクト: wentaohub/conrad
 def split_dose_by_label(self, dose_vector, labels):
     if isinstance(dose_vector, dict):
         doses = dose_vector
     else:
         y = vec(dose_vector)
         if y.size != self.voxels:
             raise ValueError('input vector must match voxel dimension of '
                              'current dose frame')
         doses = {label: y[self.frame.voxel_lookup_by_label(label)]}
コード例 #13
0
 def primal_expr_pogs(self, size, voxel_weights=None):
     if OPTKIT_INSTALLED:
         weights = 1. if voxel_weights is None else vec(voxel_weights)
         return ok.api.PogsObjective(size,
                                     h='Abs',
                                     b=float(self.deadzone_dose),
                                     c=weights * self.weight / 2.,
                                     d=weights * self.weight / 2.)
     else:
         raise NotImplementedError
コード例 #14
0
ファイル: structure.py プロジェクト: bungun/conrad
	def voxel_weights(self, weights):
		if self.size in (None, nan, 0):
			raise ValueError('structure size must be defined to add '
							 'voxel weights')
		if len(weights) != self.size:
			raise ValueError('length of input "weights" ({}) does not '
							 'match structure size ({}) of this {} '
							 'object'
							 ''.format(len(weights), self.size, Structure))
		if any(weights < 0):
			raise ValueError('negative voxel weights not allowed')
		self.__voxel_weights = vec(weights)
コード例 #15
0
    def primal_eval(self, y, voxel_weights=None):
        r"""
		Return :math:`w_+ \omega^T(y-d)_+ + w_-\omega^T(y-d)_-`, for
		:math:`\omega \equiv` ``voxel weights``.
		"""
        residuals = vec(y) - float(self.target_dose)
        if voxel_weights is None:
            return float(self.weight_abs * np.linalg.norm(residuals, 1) +
                         self.weight_linear * np.sum(residuals))
        else:
            return float(self.weight_abs *
                         np.dot(voxel_weights, np.abs(residuals)) +
                         self.weight_linear * np.dot(voxel_weights, residuals))
コード例 #16
0
ファイル: objectives.py プロジェクト: wentaohub/conrad
    def dual_domain_constraints(self, nu_var, voxel_weights=None):
        """
		Return the constraint :math:`-w_- \le \nu \le w_+`.
		"""
        upper_bound = self.weight_overdose
        lower_bound = -self.weight_underdose
        if voxel_weights is None:
            voxel_weights = 1
        else:
            voxel_weights = vec(voxel_weights)
        return [
            nu_var <= voxel_weights * upper_bound,
            nu_var >= voxel_weights * lower_bound
        ]
コード例 #17
0
ファイル: dose.py プロジェクト: bungun/conrad
	def get_maxmargin_fulfillers(self, y, had_slack=False):
		r"""
		Get indices to values of ``y`` deepest in feasible set.

		In particular, given ``len(y)``, if ``m`` voxels are
		required to respect this :class:`PercentileConstraint` exactly,
		``y`` is assumed to contain at least ``m`` entries that respect
		the constraint (for instance, ``y`` is generated by a convex
		program that includes a convex restriction of the dose
		constraint).

		Procedure.

		.. math::
		   :nowrap:

		   \begin{array}{rl}
		   \mathbf{0.} & \mbox{Define} \\
		   	& p = \mbox{percent non-violating} \cdot \mbox{structure size}
			    = \mbox{percent non-violating} \cdot \mathbf{len}(y) \\
		   \mathbf{1.} & \mbox{Get margins: } y - \mbox{dose bound}. \\
		   \mathbf{2.} & \mbox{Sort margin indices by margin values.} \\
		   \mathbf{3.} & \mbox{If upper constraint, return indices of
		   $p$ most negative entries}. \\
		   \mathbf{4.} & \mbox{If lower constraint, return indices of
		   $p$ most positive entries}. \\
		   \end{array}

		Arguments:
			y: Vector-like input data of length ``m``.
			had_slack (:obj:`bool`, optional): Define margin relative to
				slack-modulated dose value instead of the base dose
				value of this :class:`PercentileConstraint`.

		Returns:
			:class:`numpy.ndarray`: Vector of indices that yield the
			``p`` entries of ``y`` that fulfill this
			:class:`PercentileConstraint` with the greatest margin.
		"""
		fraction = self.percentile.fraction
		non_viol = (1 - fraction) if self.upper else fraction
		n_returned = int(ceil(non_viol * len(y)))

		start = 0 if self.upper else -n_returned
		end = n_returned if self.upper else None
		dose = self.dose_achieved.value if had_slack else self.dose.value
		return (vec(y) - dose).argsort()[start:end]
コード例 #18
0
ファイル: constraints.py プロジェクト: wentaohub/conrad
    def get_maxmargin_fulfillers(self, y, had_slack=False):
        r"""
		Get indices to values of ``y`` deepest in feasible set.

		In particular, given ``len(y)``, if ``m`` voxels are
		required to respect this :class:`PercentileConstraint` exactly,
		``y`` is assumed to contain at least ``m`` entries that respect
		the constraint (for instance, ``y`` is generated by a convex
		program that includes a convex restriction of the dose
		constraint).

		Procedure.

		.. math::
		   :nowrap:

		   \begin{array}{rl}
		   \mathbf{0.} & \mbox{Define} \\
		   	& p = \mbox{percent non-violating} \cdot \mbox{structure size}
			    = \mbox{percent non-violating} \cdot \mathbf{len}(y) \\
		   \mathbf{1.} & \mbox{Get margins: } y - \mbox{dose bound}. \\
		   \mathbf{2.} & \mbox{Sort margin indices by margin values.} \\
		   \mathbf{3.} & \mbox{If upper constraint, return indices of
		   $p$ most negative entries}. \\
		   \mathbf{4.} & \mbox{If lower constraint, return indices of
		   $p$ most positive entries}. \\
		   \end{array}

		Arguments:
			y: Vector-like input data of length ``m``.
			had_slack (:obj:`bool`, optional): Define margin relative to
				slack-modulated dose value instead of the base dose
				value of this :class:`PercentileConstraint`.

		Returns:
			:class:`numpy.ndarray`: Vector of indices that yield the
			``p`` entries of ``y`` that fulfill this
			:class:`PercentileConstraint` with the greatest margin.
		"""
        fraction = self.percentile.fraction
        non_viol = (1 - fraction) if self.upper else fraction
        n_returned = int(np.ceil(non_viol * len(y)))

        start = 0 if self.upper else -n_returned
        end = n_returned if self.upper else None
        dose = self.dose_achieved.value if had_slack else self.dose.value
        return (vec(y) - dose).argsort()[start:end]
コード例 #19
0
ファイル: mapping.py プロジェクト: wentaohub/conrad
	def __init__(self, map_vector, target_dimension=None):
		r"""
		Initialize a one-to-one or many-to-one discrete relation.

		The size of the first set/vector space is taken to be the
		length of ``map_vector``, and the size of the second set/vector
		space is taken to be implied by the (base-``0``) value of the
		largest entry in ``map_vector``.

		Arguments:
			map_vector: Vector-like array of :obj:`int`, representing
				mapping. Let v be the input vector. Then the relation
				maps the i'th entry of the first set to the v[i]'th
				entry of the second set.
		"""
		self.__forwardmap = vec(map_vector).astype(int)
		self.__n_frame0 = len(self.__forwardmap)
		self.__n_frame1 = self.__forwardmap.max() + 1
コード例 #20
0
ファイル: mappings.py プロジェクト: bungun/conrad
	def __init__(self, map_vector):
		"""
		Initialize a one-to-one or many-to-one discrete relation.

		The size of the first set/vector space is taken to be the
		length of ``map_vector``, and the size of the second set/vector
		space is taken to be implied by the (base-``0``) value of the
		largest entry in ``map_vector``.

		Arguments:
			map_vector: Vector-like array of :obj:`int`, representing
				mapping. Let v be the input vector. Then the relation
				maps the i'th entry of the first set to the v[i]'th
				entry of the second set.
		"""
		self.__forwardmap = vec(map_vector).astype(int)
		self.__n_frame0 = len(self.__forwardmap)
		self.__n_frame1 = self.__forwardmap.max() + 1
コード例 #21
0
ファイル: structure.py プロジェクト: wentaohub/conrad
 def voxel_weights(self, weights):
     if self.size in (None, np.nan, 0):
         raise ValueError('structure size must be defined to add voxel '
                          'weights')
     if len(weights) != self.size and np.sum(weights) != self.size:
         raise ValueError('either the length ({}) or sum ({}) of input '
                          '`weights` does not match structure size ({}) '
                          'of this {} object'.format(
                              len(weights), np.sum(weights), self.size,
                              Structure))
     if any(weights < 0):
         raise ValueError('negative voxel weights not allowed')
     self.__voxel_weights = vec(weights)
     self.__weighted_size = np.sum(self.__voxel_weights)
     self.objective.normalization = 1. / self.weighted_size
     if self.weighted_size != self.size and self.A_full is not None:
         # Pass "None" to self.A_mean setter to trigger calculation of
         # mean dose matrix from full dose matrix.
         self.A_mean = None
     if self.y is not None:
         self.__y_mean = np.dot(self.voxel_weights,
                                self.y) / self.weighted_size
コード例 #22
0
ファイル: structure.py プロジェクト: wentaohub/conrad
    def assign_dose(self, y):
        """
		Assign dose vector to structure.

		Arguments:
			y: Vector-like input of voxel doses.

		Returns:
			None

		Raises:
			ValueError: if structure size is known and incompatible with
				length of ``y``.
		"""
        y = vec(y)
        if self.size is None:
            self.size = y.size
        elif self.size != y.size:
            raise ValueError('size of dose vector ({}) incompatible with size '
                             'of structure ({})'.format(y.size, self.size))
        self.__y = y
        self.__y_mean = np.dot(self.voxel_weights, y) / self.weighted_size
        self.dvh.data = self.__y
コード例 #23
0
ファイル: test_visualization.py プロジェクト: bungun/conrad
		def test_case_plotter_set_display_groups(self):
			self.case.anatomy.label_order = [0, 1, 2]

			cp = CasePlotter(self.case)
			if cp is None:
				return

			cp.set_display_groups('together')
			self.assert_vector_equal(
					vec(list(cp.dvh_plot.series_panels.values())),
					vec([1, 1, 1]) )

			cp.set_display_groups('separate')
			self.assert_vector_equal(
					vec(list(cp.dvh_plot.series_panels.values())),
					vec([1, 2, 3]) )

			cp.set_display_groups('list', [('PTV',), ('OAR1', 'OAR2')])
			self.assert_vector_equal(
					vec(list(cp.dvh_plot.series_panels.values())),
					vec([1, 2, 2]) )