KAHIBARO
Discord Login Register

3.4. Functions

Defining functions

In Python, a function is a reusable block of code that performs a specific task. For GATE simulations, you will often wrap parts of your setup, such as geometry, sources, or actors, into functions so that your scripts become easier to read, test, and reuse.

You define a function with the keyword def, followed by a name, parentheses, and a colon. The code inside the function is indented. A very simple function looks like this:

python
def say_hello():
    print("Hello from my GATE simulation!")

The name say_hello can be anything that follows Python naming rules. It should start with a letter or underscore, contain only letters, digits, or underscores, and should describe what the function does. For example, for GATE it is common to use names like create_world, add_sources, or configure_actors.

To run the code inside a function, you have to call it by using its name followed by parentheses:

python
say_hello()

In a GATE context, you might define a function that receives a simulation object and modifies it. Here is a simple example that assumes you already created a simulation object sim elsewhere:

python
def add_world(sim):
    world = sim.world
    world.size = [1.0, 1.0, 1.0]
    world.material = "G4_AIR"

This function does not create the simulation, it only configures the world volume. The function itself does not run the simulation, it prepares part of the setup. Separating these ideas keeps your main script short and clear.

Using functions gives you several advantages. You can reuse the same code to build similar scanners or phantoms, change parameters in one place instead of many, and test parts of your simulation in isolation. For a larger GATE project, you will naturally end up with many small, focused functions instead of a single long script.

Function parameters

Most useful functions need information from the outside world. In Python, this information is passed using parameters. Parameters are names inside the parentheses in the function definition. When you call the function, you give concrete values to these parameters, called arguments.

Here is a simple example that creates a box detector volume with a configurable size:

python
def add_box_detector(sim, name, size_xyz, material):
    vol = sim.add_volume("Box", name)
    vol.size = size_xyz
    vol.material = material

In this definition, sim, name, size_xyz, and material are parameters. When you call the function, you supply arguments:

python
add_box_detector(
    sim,
    name="detector",
    size_xyz=[5.0, 5.0, 2.0],
    material="G4_WATER"
)

These arguments can be passed by position or by name. Using names, as in the example above, often makes simulation scripts easier to read, especially when there are many parameters such as sizes, positions, energies, or activities.

You can also give parameters default values. This is very useful in GATE to define standard configurations, while still allowing overrides:

python
def add_water_box(sim, name="water_box", size_xyz=[10.0, 10.0, 10.0]):
    vol = sim.add_volume("Box", name)
    vol.size = size_xyz
    vol.material = "G4_WATER"

Now the function can be called with or without specifying all parameters:

python
# Uses default name and size
add_water_box(sim)
# Override only the size
add_water_box(sim, size_xyz=[20.0, 20.0, 5.0])

You can also use keyword-only arguments to make scripts safer and more explicit. One simple pattern is to accept a dictionary of settings or require keywords for some parameters that you do not want to be passed by position:

python
def configure_source(sim, *, particle, energy_keV, activity_Bq):
    src = sim.add_source("GenericSource", "src")
    src.particle = particle
    src.energy.mono = energy_keV
    src.activity = activity_Bq

Here the * means that particle, energy_keV, and activity_Bq must be passed by name, not by position. This prevents confusion between energy and activity, which is especially important when both appear as numbers.

Working with parameters in this way lets you build flexible functions that describe scanner modules, beam lines, or dose scoring setups, and then reuse them in many different simulations simply by changing the arguments.

Return values

A function can send a result back to the caller using the return statement. This result is called the return value. If you do not explicitly return anything, Python returns None by default.

For GATE scripts, it is often useful to return created objects, such as volumes, sources, or actors, so that the calling code can further modify them if needed.

Here is a function that creates a box detector and returns it:

python
def create_box_detector(sim, name, size_xyz, material):
    vol = sim.add_volume("Box", name)
    vol.size = size_xyz
    vol.material = material
    return vol

You can then call this function and store the returned volume:

python
det = create_box_detector(
    sim,
    name="detector",
    size_xyz=[5.0, 5.0, 2.0],
    material="G4_LYSO"
)
det.translation = [0.0, 0.0, 10.0]

The function hides the repetitive creation steps, and the calling code focuses on high level configuration.

A function can also return more than one value. Internally, Python packs them into a tuple. This is useful when one function sets up several related parts of a simulation, such as a source and an actor:

python
def create_source_and_dose_actor(sim, activity_Bq):
    src = sim.add_source("GenericSource", "src")
    src.particle = "gamma"
    src.activity = activity_Bq
    dose = sim.add_actor("DoseActor", "dose")
    dose.output = "dose.mhd"
    return src, dose

You can receive these results in separate variables:

python
source, dose_actor = create_source_and_dose_actor(sim, activity_Bq=1e6)

Sometimes you do not need to return anything. In that case, the function simply modifies the objects you pass in. This is common for configuration functions:

python
def configure_pet_physics(sim):
    sim.physics_list = "G4EmStandardPhysics"

Such functions are still very useful because they keep your main script readable.

In mathematical contexts, you may work with functions that return numbers or arrays. For example, you could compute a simple analytical attenuation factor using the exponential law:

python
import math
def attenuation_factor(mu, thickness_cm):
    return math.exp(-mu * thickness_cm)

You could then compare this result with simulated transmission from GATE.

Important rule: A function stops executing as soon as a return statement is reached. Any code written after return in the same block will not run.

By defining clear return values, you make your GATE simulation code modular and predictable. Each function answers a single question or performs a specific setup step, and the returned values make the flow of data through your simulation explicit.

Views: 11

Comments

Please login to add a comment.

Don't have an account? Register now!