X-Ray Sub-Module

x-ray utilities module

pyPenred.simulation.xray.anodeSim(density: SupportsFloat | SupportsIndex, composition: Sequence[tuple[SupportsInt | SupportsIndex, SupportsFloat | SupportsIndex]], anode_angle: SupportsFloat | SupportsIndex, kvp: SupportsFloat | SupportsIndex, histories: SupportsFloat | SupportsIndex = 10000.0, min_energy: SupportsFloat | SupportsIndex = -1.0, bins: SupportsInt | SupportsIndex = 200, pixel_size: SupportsFloat | SupportsIndex = 0.1, max_angle: SupportsFloat | SupportsIndex = 80.0, save_distributions: bool = True, verbose: SupportsInt | SupportsIndex = 1) → tuple

Simulates an electron beam impinging on an anode with no filter.

Parameters:
  • density (float) – Anode density in g/cm^3.

  • composition (list[tuple[int, float]]) – List of (Z, weight fraction) for material composition.

  • anode_angle (float) – Anode angle in degrees.

  • kvp (float) – Beam KVP value.

  • histories (float, optional) – Number of histories to simulate.

  • min_energy (float, optional) – Minimum energy to record in keV. Defaults to kvp/10.

  • bins (int, optional) – Number of spectrum bins.

  • pixel_size (float, optional) – Pixel size in cm.

  • max_angle (float, optional) – Maximum angle for scattered particles, in degrees.

  • save_distributions (bool) – If enabled, saves the spectrum and spatial distributions in files ready to be used by deviceSim.

  • verbose (int, optional) – Verbosity level.

Returns:

A tuple with the following information, in order:
  • Energy limits for the generated spectrum (emin, emax) in keV

  • A 1D numpy array with the resulting gamma spectrum (prob/hist)

  • A 1D numpy array with the uncertainty for each gamma spectrum bin

  • X limits for spatial distribution (xmin, xmax) in cm

  • Y limits for spatial distribution (ymin, ymax) in cm

  • A 2D numpy array with the resulting gamma spatial distribution (prob/hist)

  • A 2D numpy array with the uncertainty for each spatial distribution bin

  • The distance between the anode collision point and the recorded spatial distribution center

Return type:

tuple

Raises:

ValueError – Incompatible value has been provided.

Example

#!/usr/bin/env python3
import matplotlib.pyplot as plt
import numpy as np
import pyPenred

# Run the simulation and store the results
results = pyPenred.simulation.xray.anodeSim(density=10.0, composition=((74,1),), anode_angle=13, kvp=100.0, histories=1.0e5)

# Extract energy and spatial ranges
eLimits = results[0]
xLimits = results[3]
yLimits = results[4]

# Produce X data for spectrum plot
e_plot = np.linspace(eLimits[0], eLimits[1], len(results[1]))

# Plot the spectrum
plt.plot(e_plot, results[1])
plt.title("Anode spectrum")
plt.xlabel("keV")
plt.ylabel("Prob/hist")
plt.savefig('anode-spectrum.png')

# Plot the spatial distribution
plt.imshow(results[5],
           extent=[xLimits[0], xLimits[1], yLimits[0], yLimits[1]],
           aspect='auto',
           origin='lower',
           cmap='viridis')

plt.colorbar()
plt.xlabel("X cm")
plt.ylabel("Y cm")
plt.savefig('anode-spatial-distrib.png')
pyPenred.simulation.xray.deviceSim(detector_position: Annotated[Sequence[SupportsFloat | SupportsIndex], 'FixedSize(3)'] = [0.0, 0.0, 0.0], focal_spot: SupportsFloat | SupportsIndex = 0.0, inherent_filter_width: SupportsFloat | SupportsIndex = -1.0, min_energy: SupportsFloat | SupportsIndex = 10.0, kvp: SupportsFloat | SupportsIndex = 100.0, anode_z: SupportsInt | SupportsIndex = 74, anode_angle: SupportsFloat | SupportsIndex = 13.0, psf_file: str = '', psf_translation: Annotated[Sequence[SupportsFloat | SupportsIndex], 'FixedSize(3)'] = [0.0, 0.0, 0.0], psf_rotation: Annotated[Sequence[SupportsFloat | SupportsIndex], 'FixedSize(3)'] = [0.0, 0.0, 0.0], spatial_distribution: str = '', energy_distribution: str = '', distribution_to_detector: SupportsFloat | SupportsIndex = -1.0, source_to_filter: SupportsFloat | SupportsIndex = 7.0, source_to_detector: SupportsFloat | SupportsIndex = 14.0, filters: Sequence[tuple[SupportsFloat | SupportsIndex, SupportsFloat | SupportsIndex, Sequence[tuple[SupportsInt | SupportsIndex, SupportsFloat | SupportsIndex]]]] = [], histories: SupportsFloat | SupportsIndex = 100000.0, max_time: SupportsFloat | SupportsIndex = 600.0, detector_dx: SupportsFloat | SupportsIndex = 50.0, detector_dy: SupportsFloat | SupportsIndex = 50.0, detector_dz: SupportsFloat | SupportsIndex = 1.0, detector_ideal: bool = True, detector_material: tuple[SupportsFloat | SupportsIndex, Sequence[tuple[SupportsInt | SupportsIndex, SupportsFloat | SupportsIndex]]] = (0.0, []), xbins: SupportsInt | SupportsIndex = 100, ybins: SupportsInt | SupportsIndex = 100, ebins: SupportsInt | SupportsIndex = 200, threads: SupportsInt | SupportsIndex = 0, seed_pair: SupportsInt | SupportsIndex = 0, user_tallies: dict = {}, user_geometry: dict = {}, geometry_materials: Sequence[tuple[SupportsFloat | SupportsIndex, Sequence[tuple[SupportsInt | SupportsIndex, SupportsFloat | SupportsIndex]]]] = [], create_detected_psf: bool = False, create_filtered_psf: bool = False, create_filtered_distrib: bool = False, print_config: bool = False, dump_read: str = '', dump_write: str = '', dump_interval: SupportsFloat | SupportsIndex = -1.0, verbose: SupportsInt | SupportsIndex = 1) → simulator

Simulates an electron beam impinging on an anode and records the resulting photon spectrum and spatial distribution. Alternatively, the simulation can be carried out from a Phase Space File (PSF) or sampling the initial photons from 2D (x,y) and 4D (E,x,y,z) spatial and energetic distributions respectively. Both, PSF and distributions can be obtained using this tool, enabling the ‘create_filtered_psf’ or ‘create_filtered_distrib’ options.

Parameters:
  • detector_position (tuple[float, float, float]) – Detector position in cm. This point is interpreted as the center of the detector’s top face in Z axis.

  • focal_spot (float) – Focal spot size of the beam in cm.

  • inherent_filter_width (float) – Width in cm for the inherent filter. Set to zero or a negative value to disable it.

  • min_energy (float) – Minimum photon energy to be recorded, in keV.

  • kvp (float) – Peak kilovoltage (kVp) of the beam.

  • anode_z (int) – Atomic number (Z) of the anode material.

  • anode_angle (float) – Angle of the anode in degrees.

  • psf_file (str) – Filename of the phase space file to be used as source.

  • psf_translation (list) – Translation to be applied to particles stored in the PSF (dx,dy,dz).

  • psf_rotation (list) – Euler angles to rotate the PSF’s particles. Rotation is performed around the Z,Y,Z axis, in that order. Notice the detector position is below the source position (-Z direction).

  • spatial_distribution (str) – Path to the 2D spatial distribution (x,y) to be used as a source.

  • energy_distribution (str) – Path to the 4D energy distribution (e,x,y,z) to be used as a source.

  • distribution_to_detector (float) – Distance between the detector and the spatial source distribution

  • source_to_filter (float) – Distance from source to the first filter in cm.

  • source_to_detector (float) – Distance from source to the detector in cm.

  • filters (list) – List of additional filters beyond the inherent one. Each filter should be defined as: (width_cm, density_g_cm3, [(Z1, fraction1), (Z2, fraction2), …])

  • histories (float) – Number of Monte Carlo histories (Beam electrons).

  • max_time (float) – Maximum simulation run time in seconds.

  • detector_dx (float) – Detector size in the X direction in cm.

  • detector_dy (float) – Detector size in the Y direction in cm.

  • detector_dz (float) – Detector depth in the Z direction in cm.

  • detector_ideal (bool) – Enables/disables ideal detection, i.e. perfect absorber.

  • detector_material (list) – Detector material for non-ideal detectors. The material must be defined as: (density, [(Z1, fraction1), (Z2, fraction2), …])

  • xbins (int) – Number of bins (pixels) along the X axis.

  • ybins (int) – Number of bins (pixels) along the Y axis.

  • ebins (int) – Number of energy bins for the spectrum.

  • threads (int) – Number of threads to use. If 0, use all available CPU cores.

  • seed_pair (int) – Seed pair index for RNG initialization. Must be less than 1001.

  • user_tallies (dict) – Configuration of additional tallies provided by the user.

  • user_geometry (dict) – Configuration of additional geometry provided by the user.

  • geometry_materials (list) – List of extra materials used in the user-defined geometry. Each material should be defined as: (density, [(Z1, fraction1), (Z2, fraction2), …])

  • create_detected_psf (bool) – If enabled, saves a PSF with the gammas reaching the detector. Only one PSF type can be created.

  • create_filtered_psf (bool) – If enabled, saves a PSF with the gammas just crossing the last filter. Only one PSF type can be created.

  • create_filtered_distrib (bool) – If enabled, saves the distribution of gammas just crossing the last filter. If no filter is configured (including inherent filtering), the scoring volume is set before the inherent filter position.

  • print_config (bool) – Prints the configuration using the penRed internal format. Only for debug purposes.

  • dump_read (str) – Specify the dumps’ base-filename to be used to resume the simulation

  • dump_write (str) – Specify the dumps’ base-filename to save the simulation status

  • dump_interval (float) – Specify the time interval, in seconds, to store simulation state dumps

  • verbose (int) – Verbosity level (higher values provide more output).

Returns:

Configured and executed ‘simulator’ object

Raises:

ValueError – Incompatible value has been provided.

Example

import matplotlib.pyplot as plt
import numpy as np
import pyPenred

sim = pyPenred.simulation.xray.deviceSim(ebins=100, inherent_filter_width=0.15, anode_angle=16, source_to_detector=100.0, max_time=600, histories=1.0e8)

# Plot spatial distribution results manually
results = sim.getResults(tallies=["SpatialDetector"])["SpatialDetector"][0].data()

# Extract spatial ranges
xLimits = results[0][3]
yLimits = results[0][2]

# Plot it
plt.figure(figsize=(6,5))
plt.imshow(data,
           origin='lower',
           extent=[xLimits[0], xLimits[1], yLimits[0], yLimits[1]],
           cmap='viridis',
           aspect='equal')
plt.xlabel('x (cm)')
plt.ylabel('y (cm)')
plt.colorbar(label='Total counts')
plt.title('Energy-integrated detector image')
plt.savefig("spatial-distrib.png", dpi=300)
plt.close()

# Plot detected spectrum
resultsSpec = sim.getResults(tallies=["SpectrumDetector"])["SpectrumDetector"][0]
resultSpec.plot("spectrum")