Source code for toor.DetectionLayout.Semicondutors.cztgeometry

import numpy as np


[docs] class CZTModule(object): def __init__(self): """ This class defines the geometry of one CZT Module in its coordinating system. Attributes: _origin (np.ndarray): The origin of the coordinating system, represented as a numpy array of three floats. _moduleNumber (int): The number of the CZT module. _numberOfPixels (np.ndarray): The number of pixels in the module, represented as a numpy array of two integers. _pixelSize (np.ndarray): The size of the pixels in meters, represented as a numpy array of two floats. _pixelSizeFronteir (np.ndarray): The size of the pixels in the frontiers in meters, represented as a numpy array of two floats. _pixelSpacingX (float): The spacing between the pixels in the x axis. _pixelSpacingY (float): The spacing between the pixels in the y axis. _edgeSpacingX (float): The spacing between the edges of the detector and the pixels in the x axis. _edgeSpacingY (float): The spacing between the edges of the detector and the pixels in the y axis. _detectorSizeX (float): The size of the detector in the x axis. _detectorSizeY (float): The size of the detector in the y axis. _cztThickness (float): The thickness of the CZT detector. _initialMatrix (np.ndarray): A matrix representing the initial coordinates of the pixels in the module. alphaRotation (float): The rotation angle around the x axis. betaRotation (float): The rotation angle around the y axis. sigmaRotation (float): The rotation angle around the z axis. xTranslation (float): The translation distance in the x axis. yTranslation (float): The translation distance in the y axis. zTranslation (float): The translation distance in the z axis. """ self._origin = np.array([0, 0, 0], dtype=np.float32) # the origin of the module self._moduleNumber = int(1) # the number of the module self._numberOfPixels = np.array([16, 16], dtype=int) # the number of pixels in the module self._pixelSize = np.array([1.5, 1.5], dtype=np.float32) # the size of the pixels in milimeters self._pixelSizeFronteir = np.array([1.3, 1.3], dtype=np.float32) # the size of the pixels in the frontiers in milimeters self._pixelSpacingX = float(0.1) # the spacing between the pixels in the x axis self._pixelSpacingY = float(0.1) # the spacing between the pixels in the y axis self._edgeSpacingX = float(0.15) # the spacing between the edges of the detectors modules self._edgeSpacingY = float(0.15) # the spacing between the edges of the detectors modules self._detectorSizeX = (self.numberOfPixels[0] - 2) * self.pixelSize[0] + ( self.numberOfPixels[0] - 1) * self.pixelSpacingX + \ 2 * (self._edgeSpacingX + self._pixelSizeFronteir[0]) # self._detectorSizeX = 1.6 * 16 self._detectorSizeY = (self.numberOfPixels[1] - 2) * self.pixelSize[1] + ( self.numberOfPixels[1] - 1) * self.pixelSpacingX + \ 2 * (self._edgeSpacingX + self._pixelSizeFronteir[1]) self._cztThickness = float(5) # mm self._initialMatrix = None self.alphaRotation = 0 self.betaRotation = 0 self.sigmaRotation = 0 self.xTranslation = 0 self.yTranslation = 0 self.zTranslation = 0
[docs] def calculateInitialMatrix(self): """ Calculates the initial matrix representing the coordinates of the pixels in the module. The matrix is stored in the `initialMatrix` attribute. Returns: np.ndarray: The initial matrix of the CZT module. """ x_step = (self._pixelSize[0] + self._pixelSpacingX) # the step in the x axis y_step = (self._pixelSize[1] + self._pixelSpacingY) # the step in the y axis y = np.arange(0, self._numberOfPixels[0] * x_step, x_step) - (self._numberOfPixels[0] - 1) * x_step / 2 # corrections for the fronteirs y[0] += np.abs(self.pixelSize[0] - self._pixelSizeFronteir[0]) / 2 y[-1] -= np.abs(self.pixelSize[0] - self._pixelSizeFronteir[0]) / 2 z = np.arange(0, self._numberOfPixels[1] * y_step, y_step) - (self._numberOfPixels[1] - 1) * y_step / 2 # corrections for the fronteirs z[0] += np.abs(self.pixelSize[1] - self._pixelSizeFronteir[1]) / 2 z[-1] -= np.abs(self.pixelSize[1] - self._pixelSizeFronteir[1]) / 2 yy, zz = np.meshgrid(y, z) # zz, yy = np.meshgrid(z, y) y = np.reshape(yy, yy.shape[0] * yy.shape[1]) x = np.zeros(y.shape) z = np.reshape(zz, zz.shape[0] * zz.shape[1]) self._initialMatrix = np.array([x, y, z], dtype=np.float32) return self._initialMatrix
@property def initialMatrix(self): return self._initialMatrix
[docs] def rotateAndTranslate(self, alpha=0, beta=0, sigma=0, x=0, y=0, z=0, angunit="deg"): """ Rotates and translates the initial matrix according to the given angles and translations. Args: alpha (float): The angle of rotation around the x axis. beta (float): The angle of rotation around the y axis. sigma (float): The angle of rotation around the z axis. x (float): The translation in the x axis. y (float): The translation in the y axis. z (float): The translation in the z axis. angunit (str): The unit of the angles. Default is "deg" for degrees. """ self.alphaRotation += alpha self.betaRotation += beta self.sigmaRotation += sigma self.xTranslation += x self.yTranslation += y self.zTranslation += z if angunit == "deg": alpha = np.deg2rad(alpha) beta = np.deg2rad(beta) sigma = np.deg2rad(sigma) A = np.array([[np.cos(sigma) * np.cos(beta), -np.sin(sigma) * np.cos(alpha) + np.cos(sigma) * np.sin(beta) * np.sin(alpha), np.sin(sigma) * np.sin(alpha) + np.cos(sigma) * np.sin(beta) * np.cos(alpha), x], [np.sin(sigma) * np.cos(beta), np.cos(sigma) * np.cos(alpha) + np.sin(sigma) * np.sin(beta) * np.sin(alpha), -np.cos(sigma) * np.sin(alpha) + np.sin(sigma) * np.sin(beta) * np.cos(alpha), y], [-np.sin(beta), np.cos(beta) * np.sin(alpha), np.cos(beta) * np.cos(alpha), z], [0, 0, 0, 1]], dtype=np.float32) B = np.ones((4, self._initialMatrix.shape[1])) B[0:3] = self._initialMatrix self._initialMatrix = np.array([A[0, 0] * B[0] + A[0, 1] * B[1] + A[0, 2] * B[2] + A[0, 3] * B[3], A[1, 0] * B[0] + A[1, 1] * B[1] + A[1, 2] * B[2] + A[1, 3] * B[3], A[2, 0] * B[0] + A[2, 1] * B[1] + A[2, 2] * B[2] + A[2, 3] * B[3]], dtype=np.float32)
@property def origin(self): return self._origin
[docs] def updateOrigin(self, value): if self._origin != value: if isinstance(value, list): value = np.array(value) else: raise TypeError self._origin = value return self._origin
@property def moduleNumber(self): return self._moduleNumber
[docs] def updateModuleNumber(self, value): if self._moduleNumber != value: self._moduleNumber = value return self._moduleNumber
@property def numberOfPixels(self): return self._numberOfPixels
[docs] def updateNumberOfPixels(self, xValue, yValue): arr = np.array([xValue, yValue]) if self._numberOfPixels != arr: self._numberOfPixels = arr return self._numberOfPixels
@property def pixelSize(self): return self._pixelSize
[docs] def updatePixelSize(self, width, height): arr = np.array([width, height]) if self._pixelSize != arr: self._pixelSize = arr return self._pixelSize
@property def pixelSpacingX(self): return self._pixelSpacingX
[docs] def updatepixelSpacingX(self, value): if self._pixelSpacingX != value: self._pixelSpacingX = value return self._pixelSpacingX
@property def pixelSpacingY(self): return self._pixelSpacingY
[docs] def updatepixelSpacingY(self, value): if self._pixelSpacingY != value: self._pixelSpacingY = value return self._pixelSpacingX
@property def cztThickness(self): return self._cztThickness
[docs] def updatecztThickness(self, value): if self._cztThickness != value: self._cztThickness = value return self._cztThickness
@property def detectorSizeX(self): return self._detectorSizeX
[docs] def updateDetectorSizeX(self, value): if self._detectorSizeX != value: self._detectorSizeX = value return self._detectorSizeX
@property def detectorSizeY(self): return self._detectorSizeY
[docs] def updateDetectorSizeY(self, value): if self._detectorSizeY != value: self._detectorSizeY = value return self._detectorSizeY