EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_dynamic_geometry.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ dynamic_geometry geometry
5 # Copyright (C) 2015 National Research Council Canada
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 # FOR 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: Alexandre Demelo, 2023
25 #
26 # Contributors: Reid Townson
27 #
28 ###############################################################################
29 */
30 
31 
37 #include "egs_dynamic_geometry.h"
38 #include "egs_input.h"
39 #include "egs_functions.h"
40 
41 // ----------------------------------------------------------------------------
42 // Implementation of EGS_DynamicGeometry methods
43 
44 // ----------------------------------------------------------------------------
45 // Avoid using deprecated methods from the base class
46 void EGS_DynamicGeometry::setMedia(EGS_Input *, int, const int *) {
47  egsWarning("EGS_DynamicGeometry::setMedia: don't use this method. Use the\n"
48  " setMedia() methods of the geometry objects that make up this geometry\n");
49 }
50 
51 void EGS_DynamicGeometry::setRelativeRho(int start, int end, EGS_Float rho) {
52  setRelativeRho(0);
53 }
54 
56  egsWarning("EGS_DynamicGeometry::setRelativeRho(): don't use this "
57  "method. Use the \n setRelativeRho() methods of the underlying "
58  "geometry\n");
59 }
60 
61 void EGS_DynamicGeometry::setBScaling(int start, int end, EGS_Float rho) {
62  setBScaling(0);
63 }
64 
66  egsWarning("EGS_DynamicGeometry::setBScaling(): don't use this "
67  "method. Use the \n setBScaling() methods of the underlying "
68  "geometry\n");
69 }
70 
71 // ----------------------------------------------------------------------------
72 // External C function to create EGS_DynamicGeometry
73 extern "C" {
74 
75  EGS_DYNAMIC_GEOMETRY_EXPORT EGS_BaseGeometry *createGeometry(EGS_Input *input) {
76  EGS_BaseGeometry *g = 0;
77  EGS_Input *ij = input->takeInputItem("geometry", false);
78  if (ij) {
80  delete ij;
81  if (!g) {
82  egsWarning("createGeometry(EGS_DynamicGeometry): got a null pointer as a geometry?\n");
83  return 0;
84  }
85  }
86  if (!g) {
87  string gname;
88  int err = input->getInput("my geometry", gname);
89  if (err) {
90  egsWarning("createGeometry(EGS_DynamicGeometry): my geometry must be defined\n either inline or using 'my geometry = some_name'\n");
91  return 0;
92  }
94  if (!g) {
95  egsWarning("createGeometry(EGS_DynamicGeometry): no geometry named %s is defined\n", gname.c_str());
96  return 0;
97  }
98  }
99  g->ref();
100 
101  // Now getting motion information for dynamic component
102  EGS_Input *dyninp = input->takeInputItem("motion");
103 
104  if (dyninp) {
105  EGS_DynamicGeometry *result = new EGS_DynamicGeometry(g, dyninp);
106  result->setName(input);
107  result->setBoundaryTolerance(input);
108  result->setLabels(input);
109  return result;
110  }
111  else {
112  egsWarning("EGS_DynamicGeometry: no control points input.\n");
113  return 0;
114  }
115  }
116 
117  void EGS_DynamicGeometry::getLabelRegions(const string &str, vector<int> &regs) {
118  // label defined in the geometry being transformed
119  g->getLabelRegions(str, regs);
120 
121  // label defined in self (transformation input block)
123  }
124 
126  stringstream itos;
127  ncpts = 0;
128  vector<EGS_Float> point;
129  EGS_ControlPoint cpt;
130  int err;
131  int icpts = 1;
132  itos << icpts;
133  string inputTag = "control point";
134  string inputTag_backCompat = "control point " + itos.str();
135  EGS_Input *currentInput;
136  int rotsize = 0;
137 
138  // Control points read one by one from motion block in dynamic geometry
139  // definition, and saved as a vector to points
140  while (true) {
141  currentInput = dyninp->takeInputItem(inputTag);
142  if (!currentInput || currentInput->getInput(inputTag, point)) {
143  currentInput = dyninp->takeInputItem(inputTag_backCompat);
144  if (!currentInput || currentInput->getInput(inputTag_backCompat, point)) {
145  delete currentInput;
146  break;
147  }
148  }
149  delete currentInput;
150 
151  // Checking the size to make sure it is a valid control point input
152  if (point.size() != 6 && point.size() != 7) {
153  egsWarning("EGS_DynamicGeometry: Control point %i must specify either 6 or 7 values.\n", icpts);
154  }
155  else {
156  if (ncpts == 0) {
157  // Variable to make sure all control point definitions have consistent formats
158  rotsize = point.size();
159  }
160 
161  // Make sure each time index is larger than the last
162  if (ncpts > 0 && point[0] < cpts[ncpts - 1].time) {
163  egsWarning("EGS_DynamicGeometry: Time index of control point %i < time index of control point %i\n", icpts, ncpts);
164  }
165 
166  // Checks that time index is valid (larger than zero)
167  else if (point[0] < 0.0) {
168  egsWarning("EGS_DynamicGeometry: Time index of control point %i < 0.0\n", icpts);
169  }
170 
171  // Checks that control point formats follow the first
172  else if (ncpts > 0 && point.size() != rotsize) {
173  egsWarning("EGS_DynamicGeometry: Rotation definition inconsistent \n");
174  }
175  else {
176  ncpts++;
177  if (ncpts == 1 && point[0] > 0.0) {
178  egsWarning("EGS_DynamicGeometry: Time index of control point 1 > 0.0. This will generate many warning messages.\n");
179  }
180  vector<EGS_Float> T_vect; // Vector storing translation information
181  vector<EGS_Float> R_vect; // Vector storing rotation information
182 
183  // Add translation coordinates to the translation vector
184  T_vect.push_back(point[1]);
185  T_vect.push_back(point[2]);
186  T_vect.push_back(point[3]);
187 
188  // Add rotation coordinates to rotation vector (cases
189  // differentiate cpt formats, 6 is 2 rotation parameters, 7
190  // is 3) In each case vector order is determined by format
191  // of EGS_rotationMatrix constructor (EGS_Float arguments)
192  if (point.size() == 6) {
193  R_vect.push_back(point[6]); // Rotation about z
194  R_vect.push_back(point[4]); // Rotation about x
195  } // 2 number case
196  if (point.size() == 7) {
197  R_vect.push_back(point[4]);
198  R_vect.push_back(point[5]); // Rotation about y
199  R_vect.push_back(point[6]); // Rotation about z
200  } // 3 number case
201 
202  // Add it to the vector of control points
203  cpt.time = point[0];
204  cpt.trnsl = T_vect;
205  cpt.rot = R_vect;
206  cpts.push_back(cpt);
207  icpts++;
208  itos.str("");
209  itos << icpts;
210 
211  // Define next control point i string for getInput in while condition
212  inputTag_backCompat = "control point " + itos.str();
213  }
214  }
215  }
216  if (ncpts <= 1) {
217  egsFatal("EGS_DynamicGeometry: Not enough or missing control points.\n");
218  }
219  if (cpts[ncpts - 1].time == 0.0) {
220  egsFatal("EGS_DynamicGeometry: Time index of last control point = 0. Something's wrong.\n");
221  }
222  else {
223 
224  // Normalize time index to max. value
225  for (int i = 0; i <= ncpts - 1; i++) {
226  cpts[i].time /= cpts[ncpts - 1].time;
227  }
228  }
229 
230  // Sets position to initial time in egs_view upon opening
231  updatePosition(0);
232  }
233 
235  int iindex = 0;
236  int i;
237 
238  // The following loop determines which 2 control points the current time
239  // index falls between
240  for (i = 0; i < ncpts; i++) {
241  if (rand < cpts[i].time - epsilon) {
242  iindex = i;
243  break;
244  }
245  }
246 
247  if (i == ncpts) {
248  egsWarning("EGS_DynamicGeometry: could not locate control point.\n");
249  return 1;
250  }
251 
252  // Below 3 vectors are defined, a vector containing the lower bound
253  // translation coordinates, a vector containing the upper bound
254  // translation coordinates, and a vector for the sampled translation
255  // coordinates
256  vector<EGS_Float> translation_LB = cpts[iindex - 1].trnsl;
257  vector<EGS_Float> translation_UB = cpts[iindex].trnsl;
258  vector<EGS_Float> translation_samp;
259 
260  // The following is a factor (between 0 and 1) used for sampling.
261  // Essentially, it represents the fractional position within the
262  // interval
263  EGS_Float factor = (rand - cpts[iindex - 1].time) / (cpts[iindex].time - cpts[iindex - 1].time);
264 
265  // Translations are given as the lower bound plus the length of the
266  // interval multiplied by the fractional position factor. So its
267  // essentially lower bound + n% of the interval length
268  translation_samp.push_back(translation_LB[0] + (translation_UB[0] - translation_LB[0]) * factor);
269  translation_samp.push_back(translation_LB[1] + (translation_UB[1] - translation_LB[1]) * factor);
270  translation_samp.push_back(translation_LB[2] + (translation_UB[2] - translation_LB[2]) * factor);
271 
272  // Update the translation coordinates in the current state control point object
273  gipt.trnsl = translation_samp;
274 
275  // Again 3 vectors defined, lower bound, upper bound, and sampled, this
276  // time for rotation coordinates
277  vector<EGS_Float> rotation_LB = cpts[iindex - 1].rot;
278  vector<EGS_Float> rotation_UB = cpts[iindex].rot;
279  vector<EGS_Float> rotation_samp;
280 
281  // Now set rotations. Current coordinates computed as before
282  // (lowerbound+n% of interval length), but now we also convert degrees
283  // to radians These must be done case by case (since order of arguments
284  // matters)
285  if (cpts[iindex].rot.size() == 2) {
286  rotation_samp.push_back((rotation_LB[0] + (rotation_UB[0] - rotation_LB[0]) * factor) * (M_PI / 180));
287  rotation_samp.push_back((rotation_LB[1] + (rotation_UB[1] - rotation_LB[1]) * factor) * (M_PI / 180));
288  }
289  else if (cpts[iindex].rot.size() == 3) {
290  rotation_samp.push_back((rotation_LB[0] + (rotation_UB[0] - rotation_LB[0]) * factor) * (M_PI / 180));
291  rotation_samp.push_back((rotation_LB[1] + (rotation_UB[1] - rotation_LB[1]) * factor) * (M_PI / 180));
292  rotation_samp.push_back((rotation_LB[2] + (rotation_UB[2] - rotation_LB[2]) * factor) * (M_PI / 180));
293  }
294  else {
295  egsWarning("EGS_DynamicGeometry: Invalid number of rotation parameters\n");
296  }
297 
298  // Update the rotation coordinates in the current state control point object
299  gipt.rot = rotation_samp;
300 
301  return 0;
302  }
303 
305  const EGS_Vector &u, EGS_GeometryIntersections *isections) {
306  EGS_Vector xt(x), ut(u);
307  T.inverseTransform(xt);
308  T.rotateInverse(ut);
309  return g->computeIntersections(ireg, n, xt, ut, isections);
310  }
311 
312  bool EGS_DynamicGeometry::isRealRegion(int ireg) const {
313  return g->isRealRegion(ireg);
314  }
315 
317  EGS_Vector xt(x);
318  T.inverseTransform(xt);
319  return g->isInside(xt);
320  }
321 
323  EGS_Vector xt(x);
324  T.inverseTransform(xt);
325  return g->isWhere(xt);
326  }
327 
329  return isWhere(x);
330  }
331 
332  int EGS_DynamicGeometry::medium(int ireg) const {
333  return g->medium(ireg);
334  }
335 
336  EGS_Float EGS_DynamicGeometry::howfarToOutside(int ireg, const EGS_Vector &x,
337  const EGS_Vector &u) {
338  return ireg >= 0 ? g->howfarToOutside(ireg, x * T, u * T.getRotation()) : 0;
339  }
340 
341  int EGS_DynamicGeometry::howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u,
342  EGS_Float &t, int *newmed, EGS_Vector *normal) {
343  EGS_Vector xt(x), ut(u);
344  T.inverseTransform(xt);
345  T.rotateInverse(ut);
346  int inew = g->howfar(ireg, xt, ut, t, newmed, normal);
347  if (inew != ireg && normal) {
348  *normal = T.getRotation() * (*normal);
349  }
350  return inew;
351  }
352 
353  EGS_Float EGS_DynamicGeometry::hownear(int ireg, const EGS_Vector &x) {
354  EGS_Vector xt(x);
355  T.inverseTransform(xt);
356  return g->hownear(ireg, xt);
357  }
358 
360  return g->getMaxStep();
361  }
362 
363  bool EGS_DynamicGeometry::hasBooleanProperty(int ireg, EGS_BPType prop) const {
364  return g->hasBooleanProperty(ireg, prop);
365  }
366 
368  g->setBooleanProperty(prop);
369  }
370 
372  g->addBooleanProperty(bit);
373  }
374 
375  void EGS_DynamicGeometry::setBooleanProperty(EGS_BPType prop, int start, int end, int step) {
376  g->setBooleanProperty(prop, start, end, step);
377  }
378 
379  void EGS_DynamicGeometry::addBooleanProperty(int bit, int start, int end, int step) {
380  g->addBooleanProperty(bit, start, end, step);
381  }
382 
383  const string &EGS_DynamicGeometry::getType() const {
384  return type;
385  }
386 
387  EGS_Float EGS_DynamicGeometry::getRelativeRho(int ireg) const {
388  return g->getRelativeRho(ireg);
389  }
390 
391  EGS_Float EGS_DynamicGeometry::getBScaling(int ireg) const {
392  return g->getBScaling(ireg);
393  }
394 
396  int errg = 1;
397  EGS_ControlPoint gipt;
398 
399  // Get the source from active application to extract time
401  while (errg) {
402  // Get time from source if it exists (otherwise gives -1)
403  ptime = app->getTimeIndex();
404  if (ptime < 0) {
405  // If no time is given by the source, randomly sample from 0 to 1
406  ptime = rndm->getUniform();
407  // Set randomly sampled time index for all objects in the
408  // simulation (through base source)
410  }
411  // Run the `getCoordGeom` method that will sample the control points
412  // given to find the transformation that will be applied for the
413  // current history
414  errg = getCoordGeom(ptime, gipt);
415  }
416 
417  // Create and set the current geometry transformation using the sampled
418  // coordinates from `getCoordGeom`. This is where the overloaded
419  // `EGS_AffineTransform` is used
421  setTransformation(*tDG);
422 
423  // Call `getNextGeom` on base geometry in case there are lower-level
424  // dynamic geometries
425  g->getNextGeom(rndm);
426  }
427 
428  void EGS_DynamicGeometry::updatePosition(EGS_Float time) {
429  int errg = 1;
430  EGS_ControlPoint gipt;
431 
432  // Run the `getCoordGeom` method that will use the control points given
433  // to find the transformation that will be applied for the current time
434  // index
435  errg = getCoordGeom(time, gipt);
436 
437  // Create and set the geometry transform with the updated coordinates
439  setTransformation(*tDG);
440 
441  // Call `updatePosition` on the base to allow lower-level geometries to
442  // update as needed
443  g->updatePosition(time);
444  }
445 
446  void EGS_DynamicGeometry::containsDynamic(bool &hasdynamic) {
447  // If the dynamic geometry implementation of `containsDynamic` is
448  // called, the simulation does indeed contain a dynamic geometry, so the
449  // boolean flag is set to true
450  hasdynamic = true;
451  }
452 
453 }
A class providing affine transformations.
static EGS_AffineTransform * getTransformation(EGS_Input *inp)
Constructs an affine transformation object from the input pointed to by inp and returns a pointer to ...
const EGS_RotationMatrix & getRotation() const
Returns the rotation matrix of the affine transformation object.
void rotateInverse(EGS_Vector &v) const
Applies the inverse rotation to the vector v.
void inverseTransform(EGS_Vector &v) const
Applies the inverse transformation to the vector v.
Base class for advanced EGSnrc C++ applications.
static EGS_Application * activeApplication()
Get the active application.
EGS_Float getTimeIndex()
Returns the value of the time synchronization parameter.
void setTimeIndex(EGS_Float temp_time)
Base geometry class. Every geometry class must be derived from EGS_BaseGeometry.
virtual int computeIntersections(int ireg, int n, const EGS_Vector &x, const EGS_Vector &u, EGS_GeometryIntersections *isections)
Calculates intersection distances to region boundaries.
virtual EGS_Float hownear(int ireg, const EGS_Vector &x)=0
Calculate the distance to a boundary for position x in any direction.
virtual bool hasBooleanProperty(int ireg, EGS_BPType prop) const
Is the boolean property prop set for region ireg ?
virtual EGS_Float howfarToOutside(int ireg, const EGS_Vector &x, const EGS_Vector &u)
virtual EGS_Float getBScaling(int ireg) const
Get the B field scaling factor in region ireg.
static EGS_BaseGeometry * createSingleGeometry(EGS_Input *inp)
Create a single geometry from the input inp.
virtual void getLabelRegions(const string &str, vector< int > &regs)
Get the list of all regions labeled with str.
virtual int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u, EGS_Float &t, int *newmed=0, EGS_Vector *normal=0)=0
Calculate the distance to a boundary from x along the direction u.
virtual bool isRealRegion(int ireg) const
Returnes true if ireg is a real region, false otherwise.
void setName(EGS_Input *inp)
Set the name of the geometry from the input inp.
virtual bool isInside(const EGS_Vector &x)=0
Is the position x inside the geometry?
virtual EGS_Float getRelativeRho(int ireg) const
Get the relative mass density in region ireg.
virtual void setBooleanProperty(EGS_BPType prop)
Set the boolean properties of the entire geometry to prop.
virtual int getMaxStep() const
Returns the maximum number of steps through the geometry.
EGS_Application * app
The application this object belongs to.
virtual int medium(int ireg) const
Returns the medium index in region ireg.
int setLabels(EGS_Input *input)
Set the labels from an input block.
int ref()
Increase the reference count to this geometry.
static EGS_BaseGeometry * getGeometry(const string &Name)
Get a pointer to the geometry named Name.
virtual void addBooleanProperty(int bit)
Add a boolean property for the entire geometry by setting the bit'th bit.
void setBoundaryTolerance(EGS_Input *inp)
Set the value of the boundary tolerance from the input inp.
virtual int isWhere(const EGS_Vector &x)=0
In which region is poisition x?
A dynamic geometry.
void setBooleanProperty(EGS_BPType prop)
Sets a boolean property for the dynamic geometry.
int ncpts
Number of control points.
EGS_BaseGeometry * g
The geometry undergoing dynamic motion.
void getNextGeom(EGS_RandomGenerator *rndm)
Updates the next particle state for geometries. It is tasked with determining the next state of the d...
bool isInside(const EGS_Vector &x)
Checks if a point is inside the dynamic geometry.
void setTransformation(EGS_AffineTransform t)
Sets the current state transform of the geometry. This is called when checking location....
int getMaxStep() const
Returns the maximum step allowed for the dynamic geometry.
void containsDynamic(bool &hasdynamic)
Determines whether the simulation geometry contains a dynamic geometry.
int computeIntersections(int ireg, int n, const EGS_Vector &x, const EGS_Vector &u, EGS_GeometryIntersections *isections)
Computes intersections of a particle with the dynamic geometry.
EGS_Float hownear(int ireg, const EGS_Vector &x)
Computes the distance to the nearest boundary.
EGS_Float howfarToOutside(int ireg, const EGS_Vector &x, const EGS_Vector &u)
Computes the distance to the outside of the dynamic geometry.
void getLabelRegions(const string &str, vector< int > &regs)
Retrieves regions labeled with a given string.
string type
The geometry type.
void buildDynamicGeometry(EGS_BaseGeometry *g, EGS_Input *dyninp)
Builds the dynamic geometry using input specifications.
void updatePosition(EGS_Float time)
Updates the position of the dynamic geometry to the specified time.
void setMedia(EGS_Input *inp, int, const int *)
Don't define media in the transformed geometry definition.
EGS_Float getRelativeRho(int ireg) const
Gets the relative density of a region in the dynamic geometry.
vector< EGS_ControlPoint > cpts
Control points for dynamic motion.
int getCoordGeom(EGS_Float rand, EGS_ControlPoint &gipt)
Extract coordinates for the next dynamic geometry position.
bool hasBooleanProperty(int ireg, EGS_BPType prop) const
Checks if the dynamic geometry has a specific boolean property in a region.
EGS_AffineTransform T
Affine transformation representing the current state.
EGS_Float ptime
Time index corresponding to the particle.
const string & getType() const
Returns the type of the dynamic geometry.
void addBooleanProperty(int bit)
Adds a boolean property for the dynamic geometry.
void setBScaling(int start, int end, EGS_Float bf)
Sets the magnetic field scaling factor for a range of regions in the dynamic geometry.
bool isRealRegion(int ireg) const
Checks if a region is real.
int medium(int ireg) const
Returns the medium index of a region.
int isWhere(const EGS_Vector &x)
Checks the location of a point.
void setRelativeRho(int start, int end, EGS_Float rho)
Sets the relative density for a range of regions in the dynamic geometry.
int inside(const EGS_Vector &x)
Alias for isWhere method.
EGS_Float getBScaling(int ireg) const
Gets the magnetic field scaling factor for a region in the dynamic geometry.
int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u, EGS_Float &t, int *newmed=0, EGS_Vector *normal=0)
Computes the distance to the nearest boundary.
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
EGS_Input * takeInputItem(const string &key, bool self=true)
Get the property named key.
Definition: egs_input.cpp:226
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:338
Base random number generator class. All random number generators should be derived from this class.
Definition: egs_rndm.h:67
EGS_Float getUniform()
Returns a random number uniformly distributed between zero (inclusive) and 1 (exclusive).
Definition: egs_rndm.h:103
A class representing 3D vectors.
Definition: egs_vector.h:57
A dynamic geometry: header.
Global egspp functions header file.
EGS_GLIB_EXPORT EGS_BaseGeometry * createGeometry(EGS_Input *input)
Definition: egs_glib.cpp:57
EGS_Input class header file.
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
const EGS_Float epsilon
The epsilon constant for floating point comparisons.
Definition: egs_functions.h:62
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.
Structure to store control point information for dynamic geometry.
vector< EGS_Float > rot
Vector specifying rotation.
EGS_Float time
Time index for control point.
vector< EGS_Float > trnsl
Vector specifying x, y, z translation.