EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_focal_spot_source.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ source with gaussian distribution in XY and UV
5 # Copyright (C) 2025 Marvin Apel
6 #
7 # This file is part of EGSnrc.
8 #
9 # EGSnrc is free software: you can redistribute it and/or modify it under
10 # the terms of the GNU Affero General Public License as published by the
11 # Free Software Foundation, either version 3 of the License, or (at your
12 # option) any later version.
13 #
14 # EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 # A PARTICULAR PURPOSE. See the GNU Affero General Public License for
17 # more details.
18 #
19 # You should have received a copy of the GNU Affero General Public License
20 # along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
21 #
22 ###############################################################################
23 #
24 # Author: Marvin Apel, 2025
25 #
26 # Contributors:
27 #
28 ###############################################################################
29 */
30 
31 
38 #include "egs_focal_spot_source.h"
39 #include "egs_input.h"
40 
41 static bool EGS_FOCAL_SPOT_LOCAL inputSet = false;
42 
44  EGS_BaseSimpleSource(input,f), valid(true) {
45  // read required inputs
46  if (input->getInput("z position",z_pos)) {
47  egsWarning("EGS_FocalSpot: missing input for parameter 'z position'\n");
48  valid = false;
49  }
50 
51  if (input->getInput("spatial spread x",sigma_x_space)) {
52  egsWarning("EGS_FocalSpot: missing input for parameter 'spatial spread x\n");
53  valid = false;
54  }
55  else if (sigma_x_space <= 0) {
56  egsWarning("EGS_FocalSpot: 'spatial spread x' must be positive (got %g)\n",
57  sigma_x_space);
58  valid = false;
59  }
60 
61  if (input->getInput("spatial spread y",sigma_y_space)) {
62  egsWarning("EGS_FocalSpot: missing input for parameter 'spatial spread y'\n");
63  valid = false;
64  }
65  else if (sigma_y_space <= 0) {
66  egsWarning("EGS_FocalSpot: 'spatial spread y' must be positive (got %g)\n",
67  sigma_y_space);
68  valid = false;
69  }
70 
71  //read optional inputs for cutoff
72  int err_cut_x = input->getInput("spatial cutoff x",space_cutoff_x);
73  int err_cut_y = input->getInput("spatial cutoff y",space_cutoff_y);
74  input->getInput("x translation",x_translation);
75  input->getInput("y translation",y_translation);
76  input->getInput("angular spread x",sigma_x_angle);
77  input->getInput("angular spread y",sigma_y_angle);
78 
79  // if no input for spatial cutoff is available set it to 5*standard deviation
80  space_cutoff_x = (err_cut_x) ? 5*sigma_x_space : space_cutoff_x;
81  space_cutoff_y = (err_cut_y) ? 5*sigma_y_space : space_cutoff_y;
82 
83  // guard against negative or zero cutoff values
84  if (space_cutoff_x <= 0 || space_cutoff_y <= 0) {
85  egsFatal("EGS_FocalSpot: spatial cutoff values must be positive "
86  "(got cutoff_x=%g, cutoff_y=%g)\n",
87  space_cutoff_x, space_cutoff_y);
88  }
89 
90  angle_mode = 0;
91  if ((sigma_x_angle != 0) || (sigma_y_angle != 0)) {
92  is_deviating = true;
93  // Set angle_mode for sampling of direction of motion (default is u.x=u.y=0, u.z=1)
94  if ((sigma_x_angle != 0) && (sigma_y_angle != 0)) {
95  // 1 - deviation from z-axis in both directions !
96  angle_mode = 1;
97  }
98  else if (sigma_x_angle != 0) {
99  // 2 - only deviation along x-axis
100  angle_mode = 2;
101  }
102  else if (sigma_y_angle != 0) {
103  // 3 - only deviation along y-axis
104  angle_mode = 3;
105  }
106  }
107 
108  // If z of rotation is read in test if the input aligns with the requirements !
109  if (!input->getInput("z of rotation",z_point_of_rotation)) {
110  is_rotated = true;
111  if (z_point_of_rotation >= z_pos) {
112  egsWarning("EGS_FocalSpot: wrong input for variable 'z of rotation'\n \
113  The requirement z of rotation < z position needs to be fullfilled !\n");
114  valid = false;
115  }
116  }
117 
118  // Test if focal spot will be rotated and if input is valid
119  bool err_x = abs(input->getInput("x rotation",x_rotation));
120  bool err_y = abs(input->getInput("y rotation",y_rotation));
121 
122  if ((x_rotation<=-90) || (x_rotation>=90)) {
123  egsWarning("EGS_FocalSpot: wrong input for variable 'x rotation' the value should be within -90 degrees < x rotation < 90 degrees\n");
124  valid = false;
125  }
126 
127  if ((y_rotation<=-90) || (y_rotation>=90)) {
128  egsWarning("EGS_FocalSpot: wrong input for variable 'y rotation' the value should be within -90 degrees < y rotation < 90 degrees\n");
129  valid = false;
130  }
131 
132  // If one of the rotations is turned on test if the z position of the rotation exists or not !
133  if ((!err_x || !err_y) && !is_rotated) {
134  egsWarning("EGS_FocalSpot: missing input for variable 'z of rotation'\n");
135  valid = false;
136  }
137 
138  setUp();
139 }
140 
142  otype = "EGS_FocalSpot";
143  if (!isValid()) {
144  description = "Invalid focal spot source";
145  }
146  else {
147  description = "A focal spot of ";
148  description += s->getType();
149  if (q == -1) {
150  description += " electrons";
151  }
152  else if (q == 0) {
153  description += " photons";
154  }
155  else if (q == 1) {
156  description += " positrons";
157  }
158  else {
159  description += " an unknown particle type";
160  }
161  // Output Spatial Distribution Information
162  description += " at a constant z "+ to_string(z_pos) +" cm\n";
163  //
164  description += " that has a spatial distribution described by a 2D Gaussian with\n";
165  description += " - " + to_string(sigma_x_space) + " cm standard deviation in x (Cutoff at: "+ to_string(space_cutoff_x) +" cm)\n";
166  description += " - " + to_string(sigma_y_space) + " cm standard deviation in y (Cutoff at: "+ to_string(space_cutoff_y) +" cm)\n";
167  description += " Around the point ("+to_string(x_translation)+"cm,"+to_string(y_translation)+"cm)\n";
168  // Output Angular Distribution Information
169  if (is_deviating) {
170  description += " The sampling of the direction vector determines the azimuth depending on the polar arc with \n";
171  if (sigma_x_angle) {
172  description += " - " + to_string(sigma_x_angle) + " degree standard deviation along x \n";
173  }
174  if (sigma_y_angle) {
175  description += " - " + to_string(sigma_y_angle) + " degree standard deviation along y \n";
176  }
177  // Convert Units after reporting to log
178  sigma_x_angle = sigma_x_angle*DEGREE_TO_RAD; //CONVERT UNITS
179  sigma_y_angle = sigma_y_angle*DEGREE_TO_RAD; //CONVERT UNITS
180  }
181  else {
182  description += " The initial direction of motion is constant and pointing along the z-axis.\n";
183  }
184  // Output Information on Rotation of focal spot
185  if (is_rotated) {
186  // EGSnrc convention: positive angle = clockwise viewed from positive end of axis
188  EGS_Vector pivot(0, 0, z_point_of_rotation);
189  EGS_Vector t = pivot - R*pivot;
190  rotation = EGS_AffineTransform(R, t);
191  }
192  }
193 }
194 
195 
196 extern "C" {
197 
198  static void setInputs() {
199  inputSet = true;
200 
201  setBaseSourceInputs();
202 
203  srcBlockInput->getSingleInput("library")->setValues({"egs_focal_spot_source"});
204 
205  // Format: name, isRequired, description, vector string of allowed values
206  srcBlockInput->addSingleInput("z position", true, "The z position of the source");
207  srcBlockInput->addSingleInput("spatial spread x", true, "The standard deviation of the source along x");
208  srcBlockInput->addSingleInput("spatial spread y", true, "The standard deviation of the source along y");
209  srcBlockInput->addSingleInput("spatial cutoff x", false, "Particles will not be generated outside [x0-cutoff, x0+cutoff]");
210  srcBlockInput->addSingleInput("spatial cutoff y", false, "Particles will not be generated outside [y0-cutoff, y0+cutoff]");
211  srcBlockInput->addSingleInput("angular spread x", false, "The standard deviation in degrees from the z-axis toward x");
212  srcBlockInput->addSingleInput("angular spread y", false, "The standard deviation in degrees from the z-axis toward y");
213  srcBlockInput->addSingleInput("x translation", false, "An offset from the origin along x");
214  srcBlockInput->addSingleInput("y translation", false, "An offset from the origin along y");
215  srcBlockInput->addSingleInput("z of rotation", false, "The z position for the point of rotation");
216  srcBlockInput->addSingleInput("x rotation", false, "A rotation clockwise when viewed from the +x axis, in degrees");
217  srcBlockInput->addSingleInput("y rotation", false, "A rotation clockwise when viewed from the +y axis, in degrees");
218  }
219 
220  EGS_FOCAL_SPOT_EXPORT string getExample() {
221  string example;
222  example = {
223  R"(
224  # Example of egs_focal_spot_source
225  #:start source:
226  library = egs_focal_spot_source
227  name = focal_spot_test
228  z position = 1 # cm
229  spatial spread x = 0.2 # cm standard deviation always never FWHM
230  spatial spread y = 0.2 # cm standard deviation always never FWHM
231  spatial cutoff x = 0.3 # cm particles will not be generated outside [x0-cutoff, x0+cutoff] (optional)
232  spatial cutoff y = 0.3 # cm particles will not be generated outside [y0-cutoff, y0+cutoff] (optional)
233  angular spread x = 1.5 # degrees (optional) (standard deviation from z-axis)
234  angular spread y = 0.9 # degrees (optional) (standard deviation from z-axis)
235  x translation = 0 # cm (optional)
236  y translation = 0 # cm (optional)
237  z of rotation = 0 # cm (optional)
238  x rotation = 1 # degrees, clockwise when viewed from +x axis
239  y rotation = 0 # degrees, clockwise when viewed from +y axis
240  :start spectrum:
241  definition of the spectrum
242  :stop spectrum:
243  charge = -1 or 0 or 1 for electrons or photons or positrons
244  :stop source:
245 )"};
246  return example;
247  }
248 
249  EGS_FOCAL_SPOT_EXPORT shared_ptr<EGS_BlockInput> getInputs() {
250  if(!inputSet) {
251  setInputs();
252  }
253  return srcBlockInput;
254  }
255 
256  EGS_FOCAL_SPOT_EXPORT EGS_BaseSource *createSource(EGS_Input *input,
257  EGS_ObjectFactory *f) {
258  return createSourceTemplate<EGS_FocalSpot>(input,f,"focal spot");
259  }
260 
261 }
A class providing affine transformations.
Base class for 'simple' particle sources.
int q
The charge of this simple source.
EGS_BaseSpectrum * s
The energy spectrum of this source.
Base source class. All particle sources must be derived from this class.
string description
A short source description.
const string & getType() const
Get the spectrum type.
int angle_mode
rotation about z_point_of_rotation
EGS_FocalSpot(EGS_Input *, EGS_ObjectFactory *f=0)
Constructor All Inputs are read in from the input file non is Construct a focal spot (corresponding t...
void setUp()
Sets up the source type and description.
static constexpr double DEGREE_TO_RAD
governs angular sampling
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
int getInput(const string &key, vector< string > &values) const
Assign values to an array of strings from an input identified by key.
Definition: egs_input.cpp:341
An object factory.
string otype
The object type.
A class for vector rotations.
static EGS_RotationMatrix rotY(EGS_Float cphi, EGS_Float sphi)
Returns a rotation around the y-axis by the angle with cphi, sphi = .
static EGS_RotationMatrix rotX(EGS_Float cphi, EGS_Float sphi)
Returns a rotation around the x-axis by the angle with cphi, sphi = .
A class representing 3D vectors.
Definition: egs_vector.h:57
A source with gaussian distribution for XY and UV that is an expanded version of BEAMnrc's ISOURC19.
EGS_Input class header file.
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.