Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/source/user_guide/user_guide_chemistry.rst
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ This combines the main pieces in one small script:
source.position.translation = [0, 0, 0]
source.direction.type = "momentum"
source.direction.momentum = [0, 0, 1]
source.n = 1
source.number_of_primaries = 1

chem_actor = sim.add_actor("ChemicalCountingActor", "chem_actor")
chem_actor.attached_to = target
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ Example:
source.image = "activity_0.mhd"
source.direction.type = "iso"
source.energy.mono = 1 * MeV
source.n = [2000, 2000, 2000]
source.number_of_primaries = [2000, 2000, 2000]

source.add_dynamic_parametrisation(
image=[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ GATE 10
source.position.translation = [1060 * mm, 0 * mm, 0 * mm]
source.direction.type = "focused"
source.direction.focus_point = [1000 * mm, 0 * mm, 0 * mm]
source.n = 720000 / sim.number_of_threads
source.number_of_primaries = 720000
source.visualization.count = 2000
source.visualization.color = "red"
source.visualization.size = 5
Expand Down
9 changes: 6 additions & 3 deletions docs/source/user_guide/user_guide_multijobs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ their output again. This is useful in two main situations:
- local execution on a workstation, where several jobs can run in parallel on
the same machine
- server execution, where the split jobs are submitted to a scheduler such as
Slurm or HTCondor
Slurm, HTCondor or PBS.

This section focuses on the current user-facing workflow in GATE 10.

Expand Down Expand Up @@ -186,8 +186,8 @@ Server-based execution
Server-based multi-job execution is intended to be file-based:

1. prepare a campaign folder containing ``simulation.json`` and the required
input files, probably locally
2. transfer the campaign folder to the server
input files, probably locally. To create the ```simulation.json`` file, you can use ``sim.to_json_file()`` in your script instead of ``sim.run(...)``.
2. transfer the campaign folder to the server. Be aware of the paths used in the .json file for material database or other input files. They should be valid on the server.
3. split the simulation on the server
4. submit the child jobs through a scheduler
5. inspect job status
Expand Down Expand Up @@ -246,6 +246,9 @@ As a convenience, the command also looks for a default file named
``jobs_backend_options.json`` inside the campaign folder when no
``--backend-options-json`` or ``--backend`` argument is provided.

You can find examples you can adapt in the ``contrib/cluster`` folder for slurm and pbs backends.
The backend options are usually site-specific and should be adapted to the target server.


.. Example: Slurm
.. ~~~~~~~~~~~~~~
Expand Down
2 changes: 1 addition & 1 deletion docs/source/user_guide/user_guide_optical_photons.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Optical photon polarization is not yet implemented. A random polarization is the
source.particle = 'opticalphoton'
source.position.type = 'point'
source.position.translation = [0, 0, 0]
source.n = 100
source.number_of_primaries = 100
source.energy.mono = 1.9*eV
source.mother = 'world
source.direction.type = "iso"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ a source description to the simulation, you do:
.. code:: python

source1 = sim.add_source('GenericSource', 'source1')
source1.n = 100
source1.number_of_primaries = 100

source2 = sim.add_source('VoxelSource', 'source2')
source2.activity = 10 * g4_units.Bq

There are several source types, each one with different parameter. In
this example, ``source1.n`` indicates that this source will generate 100
this example, ``source1.number_of_primaries`` indicates that this source will generate 100
Events. The second source manages the time and will generate 10 Events
per second, so according to the simulation run timing, a different
number of Events will be generated.
Expand Down Expand Up @@ -59,11 +59,11 @@ A minimal working example would be:
.. code:: python

source = sim.add_source("GenericSource", "mySource")
source.n = [10000, 150000, 36]
source.number_of_primaries = [10000, 150000, 36]

sim.run_timing_intervals = [[0, 1 * sec], [2 * sec, 2.5 * sec], [4 * sec, 5 * sec]]

Please note that sim.run_timing_intervals must have the same length as source.n.
Please note that ``sim.run_timing_intervals`` must have the same length as ``source.number_of_primaries``.
By default, all particles of a given run will be emitted at a timestamp equal to the minimum time of the corresponding timing interval.

Coordinate system
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ All parameters are stored into a dict-like structure (a Box). Particle
can be ‘gamma’, ‘e+’, ‘e-’, ‘proton’ (all Geant4 names). The number of
particles that will be generated by the source can be described by an
activity ``source.activity = 10 * MBq`` or by a number of particle
``source.n = 100``.
``source.number_of_primaries = 100``.

The positions from where the particles will be generated are defined by a
shape (‘box’, ‘sphere’, ‘point’, ‘disc’), defined by several parameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ a 120 MeV/n carbon ion beam.
source.energy.mono = 1440 * MeV
source.particle = "ion 6 12" # carbon
source.position.translation = [100 * mm, 0 * mm, 0 * cm]
source.n = 20000
source.number_of_primaries = 20000
source.direction.partPhSp_x = [
2.3335754 * mm,
2.3335754 * mrad,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ simulation:
# tps
n_sim = 80000 # particles to simulate per beam
tps = sim.add_source("TreatmentPlanPBSource", "TPSource")
tps.n = n_sim
tps.number_of_primaries = n_sim
tps.beam_model = beamline
tps.plan_path = ref_path / "TreatmentPlan2Spots.txt"
tps.beam_nr = 1
Expand Down
2 changes: 1 addition & 1 deletion docs/source/user_guide/user_guide_sources.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Alternatively, you can specify the fixed number of primary particles to be gener

.. code-block:: python

source1.n = 100
source1.number_of_primaries = 100

Note, however, that certain functionality regarding simulations with multiple runs is currently not supported when sources specify the fixed number of particles as above.

Expand Down
11 changes: 10 additions & 1 deletion opengate/actors/biasingactors.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,11 +418,20 @@ class ScatterSplittingFreeFlightActor(
False,
{"doc": "Print debug information during the stepping action of the actor."},
),
"particles": (
[
"gamma",
],
{
"doc": "For scatter splitting free flight, only gamma is supported",
"override": True,
"read_only": True,
},
),
}

# Do NOT work with GammaGeneralProc
processes = ["compt", "phot", "conv", "Rayl"]
particles = ["gamma"]

user_output_config = {
"info": {
Expand Down
48 changes: 18 additions & 30 deletions opengate/actors/digitizers.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,12 +466,6 @@ class DigitizerBlurringActor(DigitizerWithRootOutput, g4.GateDigitizerBlurringAc
"doc": "FIXME",
},
),
"blur_fwhm": (
None,
{
"doc": "FIXME",
},
),
"blur_reference_value": (
0,
{
Expand Down Expand Up @@ -503,6 +497,14 @@ def __initcpp__(self):
g4.GateDigitizerBlurringActor.__init__(self, self.user_info)
self.AddActions({"StartSimulationAction", "EndSimulationAction"})

@property
def blur_fwhm(self):
return self.blur_sigma / fwhm_to_sigma

@blur_fwhm.setter
def blur_fwhm(self, value):
self.blur_sigma = value * fwhm_to_sigma

def resolve_and_validate_config(self, context=None):
super().resolve_and_validate_config(context=context)
self.initialize_blurring_parameters()
Expand All @@ -523,13 +525,6 @@ def initialize_blurring_parameters(self):
self.set_param_linear()

def set_param_gauss(self):
if self.blur_fwhm is not None and self.blur_sigma is not None:
fatal(
f"Error, use blur_sigma or blur_fwhm, not both "
f"(there are: {self.blur_sigma} and {self.blur_fwhm}"
)
if self.blur_fwhm is not None:
self.blur_sigma = self.blur_fwhm * fwhm_to_sigma
if self.blur_sigma is None:
fatal(f"Error, use blur_sigma or blur_fwhm")
self.blur_reference_value = -1
Expand All @@ -547,7 +542,6 @@ def set_param_inverse_square(self):
f"Error, use positive blur_resolution "
f"(current value = {self.blur_resolution}"
)
self.blur_fwhm = -1
self.blur_sigma = -1
if self.blur_slope is None:
self.blur_slope = 0
Expand Down Expand Up @@ -804,7 +798,6 @@ class DigitizerSpatialBlurringActor(
skip_attributes: List
clear_every: int
blur_attribute: str
blur_fwhm: float
blur_sigma: float
keep_in_solid_limits: bool
use_truncated_Gaussian: bool
Expand Down Expand Up @@ -840,12 +833,6 @@ class DigitizerSpatialBlurringActor(
"doc": "Which attribute to blur, e.g. PostPosition.",
},
),
"blur_fwhm": (
None,
{
"doc": "FWHM for the blurring.",
},
),
"blur_sigma": (
None,
{
Expand Down Expand Up @@ -876,18 +863,19 @@ def __initcpp__(self):
g4.GateDigitizerSpatialBlurringActor.__init__(self, self.user_info)
self.AddActions({"StartSimulationAction", "EndSimulationAction"})

@property
def blur_fwhm(self):
return self.blur_sigma / fwhm_to_sigma

@blur_fwhm.setter
def blur_fwhm(self, value):
if not hasattr(value, "__len__"):
value = [value] * 3
self.blur_sigma = np.array(value) * fwhm_to_sigma

def initialize_blurring_parameters(self):
if self.blur_fwhm is not None and self.blur_sigma is not None:
fatal(
f"Error, use blur_sigma or blur_fwhm, not both "
f"(there are: {self.blur_sigma} and {self.blur_fwhm}"
)
if not hasattr(self.blur_sigma, "__len__"):
self.blur_sigma = [self.blur_sigma] * 3
if not hasattr(self.blur_fwhm, "__len__"):
self.blur_fwhm = [self.blur_fwhm] * 3
if self.blur_fwhm is not None:
self.blur_sigma = np.array(self.blur_fwhm) * fwhm_to_sigma
if self.blur_sigma is None:
fatal(f"Error, use blur_sigma or blur_fwhm")

Expand Down
4 changes: 4 additions & 0 deletions opengate/bin/opengate_jobs_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ def _resolve_backend_configuration(campaign_dir, backend, backend_options_json):
@click.option(
"--backend",
default=None,
type=click.Choice(
["local_pool", "local_sequential", "htcondor", "slurm", "pbs"],
case_sensitive=False,
),
help="Execution backend to use. If omitted, the command looks for jobs_backend_options.json in CAMPAIGN_DIR.",
)
@click.option(
Expand Down
40 changes: 40 additions & 0 deletions opengate/contrib/cluster/pbs/opengate_job.pbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash -x
#PBS -l walltime=10:00:00
#PBS -N opengate
#PBS -l nodes=1:ppn=1
#PBS -l mem=10gb
#PBS -o opengate.out
#PBS -e opengate.err

function error {
echo "ERROR: $1"
exit 1
}

function warning {
echo "WARNING: $1"
}

date
test -f ${HOME}/.bashrc && echo "Sourcing bashrc" && source ${HOME}/.bashrc
set -u

echo "Checking"
uname -a
echo "JOBDIR=${JOBDIR:?"unknown JOBDIR"}"

echo Using $(which python)
test -d "${JOBDIR}" || error "invalid macro"


# Enforce one thread
ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=1

echo "Lauching macro"
date
cd ${JOBDIR}
cd ..
opengate_job_runner --backend "slurm" ${JOBDIR} || error "gate failed"
date

echo "Success!!!"
10 changes: 10 additions & 0 deletions opengate/contrib/cluster/pbs/pbs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"backend": "pbs",
"backend_options": {
"submit_binary": "qsub",
"submit_filename": "opengate_job.pbs",
"command_line_args": [
"-V"
]
}
}
41 changes: 41 additions & 0 deletions opengate/contrib/cluster/slurm/opengate_job.slurm
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash -x
#SBATCH --mem=20000 # Memory in MB per default
#SBATCH --time=10:00:00
#SBATCH --ntasks=1
#SBATCH --output=Seq%j.out # nom du fichier de sortie
#SBATCH --error=Seq%j.out # nom du fichier d'erreur (ici en commun avec la sortie)



function error {
echo "ERROR: $1"
exit 1
}

function warning {
echo "WARNING: $1"
}

date
test -f ${HOME}/.bashrc && echo "Sourcing bashrc" && source ${HOME}/.bashrc
set -u

echo "Checking"
uname -a
echo "JOBDIR=${JOBDIR:?"unknown JOBDIR"}"

echo Using $(which python)
test -d "${JOBDIR}" || error "invalid macro"


# Enforce one thread
ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=1

echo "Lauching macro"
date
cd ${JOBDIR}
cd ..
opengate_job_runner --backend "slurm" ${JOBDIR} || error "gate failed"
date

echo "Success!!!"
10 changes: 10 additions & 0 deletions opengate/contrib/cluster/slurm/slurm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"backend": "slurm",
"backend_options": {
"submit_binary": "sbatch",
"submit_filename": "opengate_job.slurm",
"command_line_args": [
"--export=ALL"
]
}
}
2 changes: 1 addition & 1 deletion opengate/contrib/linacs/elektaversa.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ def add_cone(sim, p):
ff_base.color = yellow
ff_base.material = "flattening_filter_material_stain_steel"

cons_1 = volumes.ConsVolume(name=f"{linac_name}_flattening_filter_cons_1")
cons_1 = volumes.ConsVolume(name=f"{linac_name}_flattening_filter_cons_1_bis")
cons_1.rmin1 = 77 / 2 * mm
cons_1.rmax1 = 93 / 2 * mm
cons_1.rmin2 = 77 / 2 * mm
Expand Down
9 changes: 6 additions & 3 deletions opengate/geometry/solids.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,13 @@ def from_dictionary(self, d):
"The provided dictionary does not contain an entry 'creator_volumes'."
)
for i, cv in enumerate(creator_volumes):
try:
vol = self.volume_manager.volumes[cv["user_info"]["name"]]
except KeyError:
if self.volume_manager is None:
vol = create_gate_object_from_dict(cv)
else:
try:
vol = self.volume_manager.volumes[cv["user_info"]["name"]]
except KeyError:
vol = create_gate_object_from_dict(cv)

self.creator_volumes[i] = vol
self.creator_volumes[i].from_dictionary(cv)
Expand Down
Loading
Loading