3.6 NumPy Basics
Table of Contents
Arrays
NumPy is a Python library that provides fast numerical arrays, which are central to data handling and analysis for GATE simulations. Instead of working with individual numbers or Python lists, you will usually store large collections of values such as energy spectra, dose distributions, or coordinates in NumPy arrays.
To start using NumPy you typically import it and give it a short alias:
import numpy as np
A NumPy array, or ndarray, is a grid of values of the same type, indexed by integers. You can create a simple one dimensional array from a Python list:
a = np.array([1, 2, 3, 4])
print(a) # [1 2 3 4]
print(a.shape) # (4,)
print(a.dtype) # usually int64 or int32
Here shape tells you the size of each dimension. (4,) means one dimension with length 4.
Two dimensional arrays are useful for tables or images:
b = np.array([[1, 2, 3],
[4, 5, 6]])
print(b.shape) # (2, 3)You can also create arrays filled with zeros or ones, or a range of values, which is helpful when preparing data structures for analysis of GATE output:
zeros = np.zeros((3, 3)) # 3x3 matrix of zeros
ones = np.ones((2, 4)) # 2x4 matrix of ones
r = np.arange(0, 10, 2) # [0 2 4 6 8]
x = np.linspace(0.0, 1.0, 5) # [0. 0.25 0.5 0.75 1. ]Indexing lets you access or modify individual elements or slices. Indexing starts at zero:
value = a[0] # first element
b[0, 1] = 10 # first row, second column set to 10
row = b[1, :] # second row
col = b[:, 2] # third column
sub = b[0:2, 1:3] # rows 0–1, columns 1–2 (a 2x2 block)In GATE related work arrays often represent energy values, positions, times, or voxel indices. Efficient indexing makes it easy to select subsets, such as all events in a specific detector or all voxels in a region.
Mathematical operations
NumPy is designed for fast mathematical operations on entire arrays without writing Python loops. When you apply an operation to an array, it usually happens element by element.
Elementwise arithmetic works as you might expect:
a = np.array([1.0, 2.0, 3.0])
b = np.array([0.5, 1.0, 1.5])
c = a + b # [1.5 3. 4.5]
d = a - b # [0.5 1. 1.5]
e = a * b # [0.5 2. 4.5]
f = a / 2.0 # [0.5 1. 1.5]You can easily compute statistics for spectra or distributions, for example to summarize GATE output:
energy = np.array([500, 510, 495, 505, 515]) # keV
mean_E = energy.mean()
std_E = energy.std()
min_E = energy.min()
max_E = energy.max()To combine arrays as matrices, NumPy provides matrix multiplication. This is useful when applying rotation matrices to 3D coordinates, for example for detector geometry or coordinate transformations:
coords = np.array([[1.0, 0.0, 0.0]]) # one point
Rz = np.array([[0.0, -1.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 0.0, 1.0]])
rotated = coords @ Rz.T
The @ operator performs matrix multiplication, here applying the rotation matrix to the coordinate vector.
Broadcasting is a feature that lets NumPy automatically expand arrays when shapes are compatible. It allows you to apply operations between arrays of different sizes without explicit loops. For example, converting an array of energies from keV to MeV:
keV = np.array([140.0, 511.0, 662.0]) # keV
MeV = keV / 1000.0 # broadcasting with scalar 1000.0Or shifting all event times by a constant offset:
times = np.array([1.2, 3.4, 5.6]) # ns
corrected_times = times - times.min()You can also apply common mathematical functions to entire arrays. These functions operate elementwise:
angles_deg = np.array([0.0, 30.0, 60.0, 90.0])
angles_rad = np.deg2rad(angles_deg)
sine = np.sin(angles_rad)
log_counts = np.log10(np.array([1, 10, 100, 1000]))
For many GATE analyses you will use NumPy to build histograms, such as energy spectra or depth dose curves. The function np.histogram returns bin contents and edges:
energies = np.array([499, 502, 511, 520, 530]) # keV
hist, bin_edges = np.histogram(energies, bins=5, range=(480, 540))
Here hist is an array with counts per bin, which can later be plotted or saved.
Important: Use NumPy array operations instead of Python for loops whenever possible. Vectorized operations are usually much faster and more reliable for large GATE datasets, such as millions of events or voxels.
Random numbers
Monte Carlo simulations rely on random numbers to sample physical processes. In GATE the underlying engine uses its own random number generators, but in Python you often use NumPy random numbers to prepare inputs, perform simple tests, or analyze results.
NumPy provides a modern random number generator through np.random.default_rng. It can be initialized with a seed to control reproducibility:
rng = np.random.default_rng(seed=12345)Using the same seed will produce the same random sequence. Changing the seed gives a different sequence.
You can draw random samples from various distributions. For example, to simulate measurement noise or to sample positions and energies for simple tests:
# Uniform distribution between 0 and 1
u = rng.random(5) # array of 5 values in [0, 1)
# Normal (Gaussian) distribution
noise = rng.normal(loc=0.0, scale=1.0, size=1000)
# Integers, for example random detector IDs
det_ids = rng.integers(low=0, high=10, size=20) # 0 to 9Sampling from uniform and normal distributions is very common in detector modeling and in post processing of GATE output. For example, you might blur ideal deposited energies with a Gaussian to mimic finite energy resolution:
true_energy = np.array([511.0, 511.0, 511.0]) # keV
sigma = 50.0 # keV
measured_energy = true_energy + rng.normal(0.0, sigma, size=true_energy.shape)You can also sample random positions in simple shapes. For instance, a uniform point source in a cube of side length 2 cm centered at the origin:
size_cm = 2.0
positions = (rng.random((1000, 3)) - 0.5) * size_cm # 1000 random (x, y, z)For reproducible analysis of GATE simulations you should record the seed values you use in Python, especially when you add random blurring or generate synthetic test data.
Rule: If you need repeatable results in analysis scripts, always create a Generator with a fixed seed using np.random.default_rng(seed) and use that object for all random sampling. This helps you reproduce figures and checks that depend on random numbers.
Views: 14
KAHIBARO