EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_iplanes.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ iplanes 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: Iwan Kawrakow, 2005
25 #
26 # Contributors: Frederic Tessier
27 # Marc Chamberland
28 # Hannah Gallop
29 #
30 ###############################################################################
31 */
32 
33 
39 #include "egs_iplanes.h"
40 #include "egs_input.h"
41 #include "egs_transformations.h"
42 #include "egs_functions.h"
43 #include "egs_math.h"
44 
45 #include <vector>
46 
47 using namespace std;
48 
49 string EGS_IPlanes::type = "EGS_IPlanes";
50 string EGS_RadialRepeater::type = "EGS_RadialRepeater";
51 
52 static bool EGS_IPLANES_LOCAL inputSet = false;
53 
54 EGS_IPlanes::EGS_IPlanes(const EGS_Vector &Xo, const EGS_Vector &A, int np,
55  const EGS_Float *angles, const string &Name, bool degree) :
56  EGS_BaseGeometry(Name), xo(Xo), axis(A) {
57  nreg = 2*np;
58  a = new EGS_Vector[nreg];
59  d = new EGS_Float[nreg];
60  int j;
61  EGS_Float phi180 = M_PI;
62  if (degree) {
63  phi180 = 180;
64  }
65  EGS_RotationMatrix R(axis);
66  for (j=0; j<nreg; j++) {
67  EGS_Float phi;
68  if (j < np) {
69  phi = angles[j];
70  }
71  else {
72  phi = angles[j-np] + phi180;
73  }
74  if (degree) {
75  phi *= (M_PI/180);
76  }
77  EGS_Float cphi = cos(phi), sphi = sin(phi);
78  a[j] = EGS_Vector(-sphi,cphi,0)*R;
79  d[j] = a[j]*xo;
80  }
81 }
82 
84  int np, const EGS_Vector *aj, const EGS_Float *dj,
85  const string &Name) : EGS_BaseGeometry(Name), xo(Xo), axis(A) {
86  nreg = np;
87  a = new EGS_Vector[nreg];
88  d = new EGS_Float[nreg];
89  int j;
90  for (j=0; j<nreg; j++) {
91  a[j] = aj[j];
92  d[j] = dj[j];
93  }
94 }
95 
97  int np, EGS_Float first, const string &Name) :
98  EGS_BaseGeometry(Name), xo(Xo), axis(A) {
99  nreg = np;
100  EGS_Float dphi = 2*M_PI/nreg;
101  EGS_RotationMatrix R(axis);
102  a = new EGS_Vector[nreg];
103  d = new EGS_Float[nreg];
104  for (int j=0; j<nreg; j++) {
105  EGS_Float phi = first + dphi*j;
106  EGS_Float cphi = cos(phi), sphi = sin(phi);
107  a[j] = EGS_Vector(-sphi,cphi,0)*R;
108  d[j] = a[j]*xo;
109  }
110 }
111 
112 EGS_IPlanes::~EGS_IPlanes() {
113  delete [] a;
114  delete [] d;
115 }
116 
117 int EGS_IPlanes::isWhere(const EGS_Vector &x) {
118  EGS_Float aux_old = a[0]*x;
119  for (int j=1; j<nreg; j++) {
120  EGS_Float aux = a[j]*x;
121  if (aux_old >= d[j-1] && aux < d[j]) {
122  return j-1;
123  }
124  aux_old = aux;
125  }
126  return nreg-1;
127 }
128 
129 int EGS_IPlanes::inside(const EGS_Vector &x) {
130  EGS_Float aux_old = a[0]*x;
131  for (int j=1; j<nreg; j++) {
132  EGS_Float aux = a[j]*x;
133  if (aux_old >= d[j-1] && aux < d[j]) {
134  return j-1;
135  }
136  aux_old = aux;
137  }
138  return nreg-1;
139 }
140 
141 int EGS_IPlanes::howfar(int ireg, const EGS_Vector &x,
142  const EGS_Vector &u, EGS_Float &t, int *newmed, EGS_Vector *normal) {
143  if (ireg < 0) {
144  egsFatal("EGS_IPlanes::howfar: ireg (%d) can not be negative\n",ireg);
145  }
146  EGS_Float t1 = t, t2 = t;
147  EGS_Float up = a[ireg]*u;
148  int inew = ireg;
149  if (up < 0) {
150  t1 = (d[ireg] - a[ireg]*x)/up;
151  if (t1 <= t) {
152  t = t1;
153  inew = ireg-1;
154  if (inew < 0) {
155  inew = nreg-1;
156  }
157  if (newmed) {
158  *newmed = medium(inew);
159  }
160  if (normal) {
161  *normal = a[ireg];
162  }
163  }
164  }
165  int j = ireg+1;
166  if (j >= nreg) {
167  j = 0;
168  }
169  up = a[j]*u;
170  if (up > 0) {
171  t2 = (d[j] - a[j]*x)/up;
172  if (t2 < t) {
173  t = t2;
174  inew = j;
175  if (newmed) {
176  *newmed = medium(inew);
177  }
178  if (normal) {
179  *normal = a[j]*(-1);
180  }
181  }
182  }
183  return inew;
184 }
185 
186 EGS_Float EGS_IPlanes::hownear(int ireg, const EGS_Vector &x) {
187  if (ireg < 0) {
188  egsFatal("EGS_IPlanes::hownear: ireg (%d) can not be negative\n",ireg);
189  }
190  EGS_Float t1 = a[ireg]*x - d[ireg];
191  int j = ireg+1;
192  if (j >= nreg) {
193  j = 0;
194  }
195  EGS_Float t2 = d[j] - a[j]*x;
196  return min(t1,t2);
197 }
198 
199 void EGS_IPlanes::printInfo() const {
201  egsInformation(" axis: Xo = (%g,%g,%g) a = (%g,%g,%g)\n",xo.x,xo.y,xo.z,
202  axis.x,axis.y,axis.z);
204  "\n=======================================================\n");
205 }
206 
207 /***************************************************************************/
208 
209 EGS_RadialRepeater::EGS_RadialRepeater(const EGS_Vector &Xo,
210  const EGS_Vector &A, int np, EGS_BaseGeometry *G,
211  EGS_Float first, const string &Name) : EGS_BaseGeometry(Name), g(G) {
212  EGS_Float dphi = 2*M_PI/np;
213  iplanes = new EGS_IPlanes(Xo,A,np,first-dphi/2);
214  //iplanes = new EGS_IPlanes(Xo,A,np,first);
215  //iplanes = new EGS_IPlanes(Xo,A,np,(EGS_Float)0);
216  g->ref();
217  iplanes->ref();
218  nrep = np;
219  ng = g->regions();
220  nreg = nrep*ng + 1;
221  //EGS_Float dphi = 2*M_PI/np;
222  R = new EGS_RotationMatrix [nrep];
223  EGS_RotationMatrix Ro(A);
224  for (int j=0; j<nrep; j++) {
225  //EGS_Float phi = first + dphi*(0.5+j);
226  //EGS_Float phi = dphi*(0.5+j);
227  EGS_Float phi = dphi*j;
228  R[j] = Ro.inverse()*EGS_RotationMatrix::rotZ(-phi)*Ro;
229  }
230  phi_o = first;
231  xo = Xo;
232 }
233 
234 EGS_RadialRepeater::~EGS_RadialRepeater() {
235  delete [] R;
236  if (!iplanes->deref()) {
237  delete iplanes;
238  }
239  if (!g->deref()) {
240  delete g;
241  }
242 }
243 
244 void EGS_RadialRepeater::printInfo() const {
246  egsInformation("%d uniformely rotated replicas of geometry %s with "
247  "phi_o=%g degrees\n",nrep,g->getName().c_str(),
248  phi_o*180./M_PI);
249  EGS_Vector xo(iplanes->getAxisXo()), axis(iplanes->getAxisDirection());
250  egsInformation("Axis of rotation is xo=(%g,%g,%g) a=(%g,%g,%g)\n",
251  xo.x,xo.y,xo.z,axis.x,axis.y,axis.z);
252  const char *med_name = getMediumName(med);
253  if (med_name) {
254  egsInformation("space is filled with %s\n",med_name);
255  }
256  else {
257  egsInformation("space is filled with vacuum\n");
258  }
259  egsInformation("Repeated geometry:\n");
260  g->printInfo();
261 }
262 
263 extern "C" {
264  static void setInputs() {
265  inputSet = true;
266 
267  setBaseGeometryInputs();
268 
269  geomBlockInput->getSingleInput("library")->setValues({"egs_iplanes"});
270 
271  // Format: name, isRequired, description, vector string of allowed values
272  auto typePtr = geomBlockInput->addSingleInput("type", false, "The type of iplane", {"EGS_RadialRepeater"});
273 
274  geomBlockInput->addSingleInput("axis", true, "A list of three coordinates of a point on the axis and three direction cosines defining the axis direction");
275 
276  // EGS_IPlane
277  auto anglesPtr = geomBlockInput->addSingleInput("angles", false, "A list of angles of rotation around the axis for the planes in degrees, must be in increasing order and between 0 and 180");
278  auto anglesRadPtr = geomBlockInput->addSingleInput("angles in radian", false, "A list of angles of rotation around the axis for the planes in degrees, in increasing order");
279  // Only one of these two inputs can be included
280  anglesRadPtr->addDependency(anglesPtr, "", true);
281  anglesRadPtr->addDependency(typePtr, "", true);
282  anglesPtr->addDependency(anglesRadPtr, "", true);
283  anglesPtr->addDependency(typePtr, "", true);
284 
285  // EGS_RadialRepeater
286  auto geoPtr = geomBlockInput->addSingleInput("repeated geometry", true, "The exsisting geometry that is repeated");
287  geoPtr->addDependency(typePtr, "EGS_RadialRepeater");
288  auto numPtr = geomBlockInput->addSingleInput("number of repetitions", true, "The number of times the geometry is repeated");
289  numPtr->addDependency(typePtr, "EGS_RadialRepeater");
290  auto medPtr = geomBlockInput->addSingleInput("medium", false, "The medium with which the space outside the replicated geometry is filled");
291  medPtr->addDependency(typePtr, "EGS_RadialRepeater");
292  auto firstanglePtr = geomBlockInput->addSingleInput("first angle", false, "First angle of the repetitions, phi_o, in degrees");
293  firstanglePtr->addDependency(typePtr, "EGS_RadialRepeater");
294  auto firstangleRadPtr = geomBlockInput->addSingleInput("first angle in radians", false, "First angle of the repetitions, phi_o, in radians");
295  firstangleRadPtr->addDependency(typePtr, "EGS_RadialRepeater");
296 
297  // Only one of these two inputs can be included
298  firstangleRadPtr->addDependency(firstanglePtr, "", true);
299  firstanglePtr->addDependency(firstangleRadPtr, "", true);
300  }
301 
302  EGS_IPLANES_EXPORT string getExample() {
303  string example;
304  example = {
305  R"(
306  # Example of egs_iplanes
307  #:start geometry:
308  library = egs_iplanes
309  name = my_iplane
310  axis = 0 0 0 0 0 1
311  angles = 0 30 60 90 120 150
312  :stop geometry:
313 
314  # Example of EGS_RadialRepeater
315  #:start geometry:
316  library = egs_iplanes
317  type = EGS_RadialRepeater
318  axis = 0 0 1 0 0 1
319  number of repetitions = 5
320  repeated geometry = my_geom
321  # use with geometry called my_geom
322 )"};
323  return example;
324  }
325 
326  EGS_IPLANES_EXPORT shared_ptr<EGS_BlockInput> getInputs() {
327  if(!inputSet) {
328  setInputs();
329  }
330  return geomBlockInput;
331  }
332 
333  EGS_IPLANES_EXPORT EGS_BaseGeometry *createGeometry(EGS_Input *input) {
334  if (!input) {
335  egsWarning("createGeometry(iplanes): null input?\n");
336  return 0;
337  }
338  vector<EGS_Float> axis;
339  EGS_Vector xo, a(0,0,1);
340  int err = input->getInput("axis",axis);
341  if (!err && axis.size() == 6) {
342  xo = EGS_Vector(axis[0],axis[1],axis[2]);
343  a = EGS_Vector(axis[3],axis[4],axis[5]);
344  a.normalize();
345  }
346  else egsWarning("createGeometry(iplanes): wrong/missing axis input\n"
347  " using Xo=(0,0,0), a=(0,0,1)\n");
348  string type;
349  err = input->getInput("type",type);
350  if (!err && (type == "EGS_RadialRepeater" || type == "repeater")) {
351  int np;
352  err = input->getInput("number of repetitions",np);
353  if (err || np < 2) {
354  egsWarning("createGeometry(iplanes): missing/wrong "
355  "'number of repetitions' input\n");
356  return 0;
357  }
358  string gname;
359  err = input->getInput("repeated geometry",gname);
360  if (err) {
361  egsWarning("createGeometry(iplanes): missing 'repeated geometry'"
362  " input\n");
363  return 0;
364  }
366  if (!g) {
367  egsWarning("createGeometry(iplanes): no geometry named %s exists\n",
368  gname.c_str());
369  return 0;
370  }
371  EGS_Float phi_o = 0;
372  EGS_Float tmp1,tmp2;
373  err = input->getInput("first angle",tmp1);
374  int err1 = input->getInput("first angle in radians",tmp2);
375  if (!err) {
376  phi_o = tmp1*M_PI/180;
377  }
378  else if (!err1) {
379  phi_o = tmp2;
380  }
381  EGS_RadialRepeater *result = new EGS_RadialRepeater(xo,a,np,g,phi_o);
382  result->setName(input);
383  result->setBoundaryTolerance(input);
384  string medium;
385  err = input->getInput("medium",medium);
386  if (!err) {
387  result->setMedium(medium);
388  }
389  result->setRLabels(input);
390  result->setLabels(input);
391  return result;
392  }
393 
394  vector<EGS_Float> angles;
395  err = input->getInput("angles",angles);
396  bool is_degree = true;
397  EGS_Float max_angle = 180;
398  if (err) {
399  err = input->getInput("angles in radian",angles);
400  if (err) {
401  egsWarning("createGeometry(iplanes): wrong/missing 'angles' or "
402  "'angles in radian' input\n");
403  return 0;
404  }
405  is_degree = false;
406  max_angle = M_PI;
407  }
408  EGS_Float *ang = new EGS_Float [angles.size()];
409  for (int j=0; j<angles.size(); j++) {
410  ang[j] = angles[j];
411  /*
412  if( ang[j] < 0 || ang[j] > max_angle ) {
413  egsWarning("createGeometry(iplanes): angle must be between 0 and "
414  "%g\n",max_angle); delete [] ang; return 0;
415  }
416  */
417  if (j > 0) {
418  if (ang[j] <= ang[j-1]) {
419  egsWarning("createGeometry(iplanes): angles must be ordered"
420  " in increasing order\n");
421  delete [] ang;
422  return 0;
423  }
424  }
425  }
426  int nang = angles.size();
427  EGS_Float ang_diff = ang[nang-1]-ang[0];
428  if (ang_diff > max_angle) {
429  egsWarning("createGeometry(iplanes): difference between first and last"
430  " angle must be less then 180 degrees.\n");
431  if (is_degree)
432  egsWarning(" Your input: first angle=%g, last angle=%g,"
433  " difference=%g\n",ang[0],ang[nang-1],ang[nang-1]-ang[0]);
434  else
435  egsWarning(" Your input: first angle=%g, last angle=%g,"
436  " difference=%g\n",ang[0]*180/M_PI,ang[nang-1]*180/M_PI,
437  (ang[nang-1]-ang[0])*180/M_PI);
438  delete [] ang;
439  return 0;
440  }
441  EGS_BaseGeometry *g = new EGS_IPlanes(xo,a,angles.size(),ang,"",is_degree);
442  delete [] ang;
443  g->setName(input);
444  g->setBoundaryTolerance(input);
445  g->setMedia(input);
446  g->setLabels(input);
447  return g;
448  }
449 
450  void EGS_RadialRepeater::setRLabels(EGS_Input *input) {
451 
452  // radial repeater labels
453  string inp;
454  int err;
455  err = input->getInput("set repeater label", inp);
456  if (!err) {
457  iplanes->setLabels(inp);
458  }
459  }
460 
461 
462  void EGS_RadialRepeater::getLabelRegions(const string &str, vector<int> &regs, bool sanitize) {
463 
464  vector<int> local_regs;
465 
466  // label in repeated geometry
467  local_regs.clear();
468  g->getLabelRegions(str, local_regs, sanitize);
469  for (int i=0; i<nrep; i++) {
470  for (int r=0; r<local_regs.size(); r++) {
471  regs.push_back(ng*i + local_regs[r]);
472  }
473  }
474 
475  // labels defined in iplanes
476  local_regs.clear();
477  iplanes->getLabelRegions(str, local_regs, sanitize);
478  for (int i=0; i<local_regs.size(); i++) {
479  for (int r=0; r<ng; r++) {
480  regs.push_back(ng*local_regs[i] + r);
481  }
482  }
483 
484  // label defined in self (repeater input block)
485  EGS_BaseGeometry::getLabelRegions(str, regs, sanitize);
486 
487  }
488 
489 }
Base geometry class. Every geometry class must be derived from EGS_BaseGeometry.
int deref()
Decrease the reference count to this geometry.
void setMedia(EGS_Input *inp)
Set the media in the geometry from the input pointed to by inp.
int nreg
Number of local regions in this geometry.
void setName(EGS_Input *inp)
Set the name of the geometry from the input inp.
void setMedium(const string &Name)
Set all regions to a medium with name Name.
const string & getName() const
Get the name of this geometry.
int med
Medium index.
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.
virtual void printInfo() const
Print information about this geometry.
static EGS_BaseGeometry * getGeometry(const string &Name)
Get a pointer to the geometry named Name.
static const char * getMediumName(int ind)
Get the name of medium with index ind.
void setBoundaryTolerance(EGS_Input *inp)
Set the value of the boundary tolerance from the input inp.
virtual void getLabelRegions(const string &str, vector< int > &regs, bool sanitize=true)
Get the list of all regions labeled with str.
A set of planes intersecting in the same axis.
Definition: egs_iplanes.h:150
EGS_IPlanes(const EGS_Vector &Xo, const EGS_Vector &A, int np, const EGS_Float *angles, const string &Name="", bool degree=true)
Construct a set of intersecting planes (iplanes)
Definition: egs_iplanes.cpp:54
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
A radial geometry replicator.
Definition: egs_iplanes.h:341
A class for vector rotations.
static EGS_RotationMatrix rotZ(EGS_Float cphi, EGS_Float sphi)
Returns a rotation around the z-axis by the angle with cphi, sphi = .
A class representing 3D vectors.
Definition: egs_vector.h:57
EGS_Float y
y-component
Definition: egs_vector.h:62
EGS_Float z
z-component
Definition: egs_vector.h:63
EGS_Float x
x-component
Definition: egs_vector.h:61
Global egspp functions header file.
EGS_GLIB_EXPORT EGS_BaseGeometry * createGeometry(EGS_Input *input)
Definition: egs_glib.cpp:84
EGS_Input class header file.
Intersecting planes: header.
Attempts to fix broken math header files.
EGS_AffineTransform and EGS_RotationMatrix class header file.
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
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.