EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
sources/egs_point_source/egs_point_source.cpp

A point source is a special case of an isotropic source . Due to its simplicity, it provides a good example for discussing the implementation of a new source class.

The point source header file egs_point_source.h includes the base source header file, the header file of the EGS_Vector class to gain access to the methods manipulating 3D vectors, and the random number generator (RNG) header file to get access to the declaration of the various RNG methods needed to sample particles

#include "egs_vector.h"
#include "egs_rndm.h"
It then defines a macro EGS_POINT_SOURCE_EXPORT that will be used to mark DSO symbols as exports when building the point source DSO and as imports when linking against the DSO:
#ifdef WIN32
#ifdef BUILD_POINT_SOURCE_DLL
#define EGS_POINT_SOURCE_EXPORT __declspec(dllexport)
#else
#define EGS_POINT_SOURCE_EXPORT __declspec(dllimport)
#endif
#define EGS_POINT_SOURCE_LOCAL
#else
#ifdef HAVE_VISIBILITY
#define EGS_POINT_SOURCE_EXPORT __attribute__ ((visibility ("default")))
#define EGS_POINT_SOURCE_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define EGS_POINT_SOURCE_EXPORT
#define EGS_POINT_SOURCE_LOCAL
#endif
#endif

We derive the point source class from EGS_BaseSimpleSource instead of EGS_BaseSource because a point source is a "simple" source (i.e consists of a spectrum and an energy-independent probability distribution for position and direction):

class EGS_POINT_SOURCE_EXPORT EGS_PointSource : public EGS_BaseSimpleSource {
bool valid;
public:
The private variables xo (point source position) and valid will be set in the constructors (see below). We provide two methods for constructing a point source: directly by passing a charge, a spectrum, a source position and a name to the constructor,
EGS_PointSource(int Q, EGS_BaseSpectrum *Spec, const EGS_Vector &Xo,
const string &Name="", EGS_ObjectFactory *f=0) :
EGS_BaseSimpleSource(Q,Spec,Name,f), xo(Xo), valid(true) {
setUp();
};
and from the information provided by an EGS_Input object
The implementation of the second constructor is in the .cpp file and will be discussed below.

The main method that must be implemented in a derived simple source class is getPositionDirection() to sample the position and direction of a single particle and to set its statistical weight

void getPositionDirection(EGS_RandomGenerator *rndm,
EGS_Vector &x, EGS_Vector &u, EGS_Float &wt) {
Sampling the particle position for a point source is easy: it is simply the point source position
x = xo;
Sampling the direction is also easy: one samples $u_z$ uniformely between -1 and 1, picks a random azimuthal angle $\phi$ between 0 and $2 \pi$ and sets $ u_x = \sqrt{1 - u_z^2} \cos \phi, u_y = \sqrt{1 - u_z^2} \sin \phi$:
u.z = 2*rndm->getUniform()-1;
EGS_Float sinz = 1-u.z*u.z;
if (sinz > epsilon) {
sinz = sqrt(sinz);
EGS_Float cphi, sphi;
rndm->getAzimuth(cphi,sphi);
u.x = sinz*cphi;
u.y = sinz*sphi;
}
else {
The statistical weight of the particle is always unity
u.x = 0;
u.y = 0;
}
wt = 1;
};

The next function to implement is getFluence(), which should return the particle "fluence" emitted so far by the source. We arbitrarily decide to define the "fluence" of our point source to be the number of particles emitted by the source (we also could have picked the number of particles per unit solid angle or real fluence at a certain distance from the source) and therefore the getFluence() implementation is very easy:

EGS_Float getFluence() const {
return count;
};
Here, count is a protected data member inhereted from EGS_BaseSimpleSource, which is initialized to zero in the simple source constructor and is incremented by one in each invocation of the getNextParticle() function.

The next task is to implement the functions that store the state of a point source object to a data stream and restore the state from a data stream. This is needed for the ability to restart simulations. Because our source class is very simple, no data needs to be stored/restored in addition to the data already stored/restored by EGS_BaseSource and EGS_BaseSimpleSource. The implementation of these functions is therefore extremely simple:

bool storeFluenceState(ostream &) const {
return true;
};
bool setFluenceState(istream &) {

The next step in the header file is to provide a isValid function, which should return true, if the source object is valid and false otherwise (e.g. it does not have a spectrum). isValid() is needed so that the createSource() function that must be provided by the source DSO (see below) can be implemented by simply using the template createSourceTemplate():

return true;
};
bool isValid() const {

The final step in the point source declaration is to specify a protected function that will be used to set up the source type and description

return (valid && s != 0);
};

The egs_point_source.cpp file provides implementation of the constructor that creates a point source object from information stored in an EGS_Input object, the setUp() function and the C-style source creation function createSource() that must be provided by each source DSO. It includes the point source header file and the input object header file

#include "egs_input.h"

The point source constructor calls the base simple source constructor passing the input as argument

EGS_BaseSimpleSource(input,f), xo(), valid(true) {
This sets the name of the source from the name key, sets the charge from a charge key and constructs the spectrum from the information in a spectrum composite property using EGS_BaseSpectrum::createSpectrum(). The only task remaining for a complete point source definition is to determine the position of the source:
vector<EGS_Float> pos;
int err = input->getInput("position",pos);
The position was successfully set if err=0 and the number of inputs to the position key is exactly 3 (defining a 3D position), otherwise a warning is issued and the source is set to be invalid:
if (!err && pos.size() == 3) {
xo = EGS_Vector(pos[0],pos[1],pos[2]);
}
The source type and description is then set using setUp().
else {
egsWarning("EGS_PointSource: missing/wrong 'position' input\n");
valid = false;
}

The implementation of the setUp function sets the type string to "EGS_PointSource" and the description string to a short sentence constructed from the charge and spectrum type:

setUp();
}
otype = "EGS_PointSource";
if (!isValid()) {
description = "Invalid point source";
}

The createSource C-style function implementation simply uses the createSourceTemplate() function:

else {
description = "Point source with ";
description += s->getType();
if (q == -1) {
description += ", electrons";
}
else if (q == 0) {
description += ", photons";
}
The conditions for being able to use createSourceTemplate() to construct a source are

This completes the implementation of our point source class.

The Makefile is very similar to the Makefile of a geometry DSO (see e.g. this example): we include the egspp config setting for the make system,

include $(EGS_CONFIG)
include $(SPEC_DIR)egspp.spec
include $(SPEC_DIR)egspp_$(my_machine).conf
set the pre-processor defines to include the BUILD_POINT_SOURCE_DLL macro,
DEFS = $(DEF1) -DBUILD_POINT_SOURCE_DLL
define the DSO name and files needed to build the DSO,
library = egs_point_source
lib_files = egs_point_source
set the dependences to be set of header files common for all sources,
my_deps = $(common_source_deps)
extra_dep = $(addprefix $(DSOLIBS), $(my_deps))
include the rules for building a DSO,
include $(SPEC_DIR)egspp_libs.spec
and make the dependences take effect
$(make_depend)

We can now build our point source DSO by typing make and use it for simulations by including input such as

:start source:
    library = egs_points_source
    name = some_name
    charge = -1
    :start spectrum:
       definition of a spectrum
    :stop spectrum:
    position = 15 -3 7
:stop source:

in the source definition section of the input file.

This is the complete Makefile:

###############################################################################
#
# EGSnrc egs++ makefile to build point source
# Copyright (C) 2015 National Research Council Canada
#
# This file is part of EGSnrc.
#
# EGSnrc is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
# more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
#
# Author: Iwan Kawrakow, 2005
#
# Contributors:
#
###############################################################################
include $(EGS_CONFIG)
include $(SPEC_DIR)egspp.spec
include $(SPEC_DIR)egspp_$(my_machine).conf
DEFS = $(DEF1) -DBUILD_POINT_SOURCE_DLL
library = egs_point_source
lib_files = egs_point_source
my_deps = $(common_source_deps)
extra_dep = $(addprefix $(DSOLIBS), $(my_deps))
include $(SPEC_DIR)egspp_libs.spec
$(make_depend)

This is the complete header file:

/*
###############################################################################
#
# EGSnrc egs++ point source headers
# Copyright (C) 2015 National Research Council Canada
#
# This file is part of EGSnrc.
#
# EGSnrc is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
# more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
#
# Author: Iwan Kawrakow, 2005
#
# Contributors: Frederic Tessier
# Reid Townson
#
###############################################################################
*/
#ifndef EGS_POINT_SOURCE_
#define EGS_POINT_SOURCE_
#include "egs_vector.h"
#include "egs_rndm.h"
#ifdef WIN32
#ifdef BUILD_POINT_SOURCE_DLL
#define EGS_POINT_SOURCE_EXPORT __declspec(dllexport)
#else
#define EGS_POINT_SOURCE_EXPORT __declspec(dllimport)
#endif
#define EGS_POINT_SOURCE_LOCAL
#else
#ifdef HAVE_VISIBILITY
#define EGS_POINT_SOURCE_EXPORT __attribute__ ((visibility ("default")))
#define EGS_POINT_SOURCE_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define EGS_POINT_SOURCE_EXPORT
#define EGS_POINT_SOURCE_LOCAL
#endif
#endif
class EGS_POINT_SOURCE_EXPORT EGS_PointSource : public EGS_BaseSimpleSource {
bool valid;
public:
EGS_PointSource(int Q, EGS_BaseSpectrum *Spec, const EGS_Vector &Xo,
const string &Name="", EGS_ObjectFactory *f=0) :
EGS_BaseSimpleSource(Q,Spec,Name,f), xo(Xo), valid(true) {
setUp();
};
EGS_Vector &x, EGS_Vector &u, EGS_Float &wt) {
x = xo;
u.z = 2*rndm->getUniform()-1;
EGS_Float sinz = 1-u.z*u.z;
if (sinz > epsilon) {
sinz = sqrt(sinz);
EGS_Float cphi, sphi;
rndm->getAzimuth(cphi,sphi);
u.x = sinz*cphi;
u.y = sinz*sphi;
}
else {
u.x = 0;
u.y = 0;
}
wt = 1;
};
EGS_Float getFluence() const {
return count;
};
bool storeFluenceState(ostream &) const {
return true;
};
bool setFluenceState(istream &) {
return true;
};
bool isValid() const {
return (valid && s != 0);
};
protected:
void setUp();
};
#endif

This is the complete source file:

/*
###############################################################################
#
# EGSnrc egs++ point source
# Copyright (C) 2015 National Research Council Canada
#
# This file is part of EGSnrc.
#
# EGSnrc is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
# more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
#
# Author: Iwan Kawrakow, 2005
#
# Contributors:
#
###############################################################################
*/
#include "egs_input.h"
EGS_BaseSimpleSource(input,f), xo(), valid(true) {
vector<EGS_Float> pos;
int err = input->getInput("position",pos);
if (!err && pos.size() == 3) {
xo = EGS_Vector(pos[0],pos[1],pos[2]);
}
else {
egsWarning("EGS_PointSource: missing/wrong 'position' input\n");
valid = false;
}
setUp();
}
otype = "EGS_PointSource";
if (!isValid()) {
description = "Invalid point source";
}
else {
description = "Point source with ";
if (q == -1) {
description += ", electrons";
}
else if (q == 0) {
description += ", photons";
}
else if (q == 1) {
description += ", positrons";
}
else {
description += ", unknown particle type";
}
}
}
extern "C" {
EGS_POINT_SOURCE_EXPORT EGS_BaseSource *createSource(EGS_Input *input,
return createSourceTemplate<EGS_PointSource>(input,f,"point source");
}
}