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 #
29 ###############################################################################
30 */
31 
32 
38 #include "egs_iplanes.h"
39 #include "egs_input.h"
40 #include "egs_transformations.h"
41 #include "egs_functions.h"
42 #include "egs_math.h"
43 
44 #include <vector>
45 
46 using namespace std;
47 
48 string EGS_IPlanes::type = "EGS_IPlanes";
49 string EGS_RadialRepeater::type = "EGS_RadialRepeater";
50 
51 EGS_IPlanes::EGS_IPlanes(const EGS_Vector &Xo, const EGS_Vector &A, int np,
52  const EGS_Float *angles, const string &Name, bool degree) :
53  EGS_BaseGeometry(Name), xo(Xo), axis(A) {
54  nreg = 2*np;
55  a = new EGS_Vector[nreg];
56  d = new EGS_Float[nreg];
57  int j;
58  EGS_Float phi180 = M_PI;
59  if (degree) {
60  phi180 = 180;
61  }
62  EGS_RotationMatrix R(axis);
63  for (j=0; j<nreg; j++) {
64  EGS_Float phi;
65  if (j < np) {
66  phi = angles[j];
67  }
68  else {
69  phi = angles[j-np] + phi180;
70  }
71  if (degree) {
72  phi *= (M_PI/180);
73  }
74  EGS_Float cphi = cos(phi), sphi = sin(phi);
75  a[j] = EGS_Vector(-sphi,cphi,0)*R;
76  d[j] = a[j]*xo;
77  }
78 }
79 
81  int np, const EGS_Vector *aj, const EGS_Float *dj,
82  const string &Name) : EGS_BaseGeometry(Name), xo(Xo), axis(A) {
83  nreg = np;
84  a = new EGS_Vector[nreg];
85  d = new EGS_Float[nreg];
86  int j;
87  for (j=0; j<nreg; j++) {
88  a[j] = aj[j];
89  d[j] = dj[j];
90  }
91 }
92 
94  int np, EGS_Float first, const string &Name) :
95  EGS_BaseGeometry(Name), xo(Xo), axis(A) {
96  nreg = np;
97  EGS_Float dphi = 2*M_PI/nreg;
98  EGS_RotationMatrix R(axis);
99  a = new EGS_Vector[nreg];
100  d = new EGS_Float[nreg];
101  for (int j=0; j<nreg; j++) {
102  EGS_Float phi = first + dphi*j;
103  EGS_Float cphi = cos(phi), sphi = sin(phi);
104  a[j] = EGS_Vector(-sphi,cphi,0)*R;
105  d[j] = a[j]*xo;
106  }
107 }
108 
109 EGS_IPlanes::~EGS_IPlanes() {
110  delete [] a;
111  delete [] d;
112 }
113 
114 int EGS_IPlanes::isWhere(const EGS_Vector &x) {
115  EGS_Float aux_old = a[0]*x;
116  for (int j=1; j<nreg; j++) {
117  EGS_Float aux = a[j]*x;
118  if (aux_old >= d[j-1] && aux < d[j]) {
119  return j-1;
120  }
121  aux_old = aux;
122  }
123  return nreg-1;
124 }
125 
126 int EGS_IPlanes::inside(const EGS_Vector &x) {
127  EGS_Float aux_old = a[0]*x;
128  for (int j=1; j<nreg; j++) {
129  EGS_Float aux = a[j]*x;
130  if (aux_old >= d[j-1] && aux < d[j]) {
131  return j-1;
132  }
133  aux_old = aux;
134  }
135  return nreg-1;
136 }
137 
138 int EGS_IPlanes::howfar(int ireg, const EGS_Vector &x,
139  const EGS_Vector &u, EGS_Float &t, int *newmed, EGS_Vector *normal) {
140  if (ireg < 0) {
141  egsFatal("EGS_IPlanes::howfar: ireg (%d) can not be negative\n",ireg);
142  }
143  EGS_Float t1 = t, t2 = t;
144  EGS_Float up = a[ireg]*u;
145  int inew = ireg;
146  if (up < 0) {
147  t1 = (d[ireg] - a[ireg]*x)/up;
148  if (t1 <= t) {
149  t = t1;
150  inew = ireg-1;
151  if (inew < 0) {
152  inew = nreg-1;
153  }
154  if (newmed) {
155  *newmed = medium(inew);
156  }
157  if (normal) {
158  *normal = a[ireg];
159  }
160  }
161  }
162  int j = ireg+1;
163  if (j >= nreg) {
164  j = 0;
165  }
166  up = a[j]*u;
167  if (up > 0) {
168  t2 = (d[j] - a[j]*x)/up;
169  if (t2 < t) {
170  t = t2;
171  inew = j;
172  if (newmed) {
173  *newmed = medium(inew);
174  }
175  if (normal) {
176  *normal = a[j]*(-1);
177  }
178  }
179  }
180  return inew;
181 }
182 
183 EGS_Float EGS_IPlanes::hownear(int ireg, const EGS_Vector &x) {
184  if (ireg < 0) {
185  egsFatal("EGS_IPlanes::hownear: ireg (%d) can not be negative\n",ireg);
186  }
187  EGS_Float t1 = a[ireg]*x - d[ireg];
188  int j = ireg+1;
189  if (j >= nreg) {
190  j = 0;
191  }
192  EGS_Float t2 = d[j] - a[j]*x;
193  return min(t1,t2);
194 }
195 
196 void EGS_IPlanes::printInfo() const {
198  egsInformation(" axis: Xo = (%g,%g,%g) a = (%g,%g,%g)\n",xo.x,xo.y,xo.z,
199  axis.x,axis.y,axis.z);
201  "\n=======================================================\n");
202 }
203 
204 /***************************************************************************/
205 
206 EGS_RadialRepeater::EGS_RadialRepeater(const EGS_Vector &Xo,
207  const EGS_Vector &A, int np, EGS_BaseGeometry *G,
208  EGS_Float first, const string &Name) : EGS_BaseGeometry(Name), g(G) {
209  EGS_Float dphi = 2*M_PI/np;
210  iplanes = new EGS_IPlanes(Xo,A,np,first-dphi/2);
211  //iplanes = new EGS_IPlanes(Xo,A,np,first);
212  //iplanes = new EGS_IPlanes(Xo,A,np,(EGS_Float)0);
213  g->ref();
214  iplanes->ref();
215  nrep = np;
216  ng = g->regions();
217  nreg = nrep*ng + 1;
218  //EGS_Float dphi = 2*M_PI/np;
219  R = new EGS_RotationMatrix [nrep];
220  EGS_RotationMatrix Ro(A);
221  for (int j=0; j<nrep; j++) {
222  //EGS_Float phi = first + dphi*(0.5+j);
223  //EGS_Float phi = dphi*(0.5+j);
224  EGS_Float phi = dphi*j;
225  R[j] = Ro.inverse()*EGS_RotationMatrix::rotZ(-phi)*Ro;
226  }
227  phi_o = first;
228  xo = Xo;
229 }
230 
231 EGS_RadialRepeater::~EGS_RadialRepeater() {
232  delete [] R;
233  if (!iplanes->deref()) {
234  delete iplanes;
235  }
236  if (!g->deref()) {
237  delete g;
238  }
239 }
240 
241 void EGS_RadialRepeater::printInfo() const {
243  egsInformation("%d uniformely rotated replicas of geometry %s with "
244  "phi_o=%g degrees\n",nrep,g->getName().c_str(),
245  phi_o*180./M_PI);
246  EGS_Vector xo(iplanes->getAxisXo()), axis(iplanes->getAxisDirection());
247  egsInformation("Axis of rotation is xo=(%g,%g,%g) a=(%g,%g,%g)\n",
248  xo.x,xo.y,xo.z,axis.x,axis.y,axis.z);
249  const char *med_name = getMediumName(med);
250  if (med_name) {
251  egsInformation("space is filled with %s\n",med_name);
252  }
253  else {
254  egsInformation("space is filled with vacuum\n");
255  }
256  egsInformation("Repeated geometry:\n");
257  g->printInfo();
258 }
259 
260 extern "C" {
261 
262  EGS_IPLANES_EXPORT EGS_BaseGeometry *createGeometry(EGS_Input *input) {
263  if (!input) {
264  egsWarning("createGeometry(iplanes): null input?\n");
265  return 0;
266  }
267  vector<EGS_Float> axis;
268  EGS_Vector xo, a(0,0,1);
269  int err = input->getInput("axis",axis);
270  if (!err && axis.size() == 6) {
271  xo = EGS_Vector(axis[0],axis[1],axis[2]);
272  a = EGS_Vector(axis[3],axis[4],axis[5]);
273  a.normalize();
274  }
275  else egsWarning("createGeometry(iplanes): wrong/missing axis input\n"
276  " using Xo=(0,0,0), a=(0,0,1)\n");
277  string type;
278  err = input->getInput("type",type);
279  if (!err && (type == "EGS_RadialRepeater" || type == "repeater")) {
280  int np;
281  err = input->getInput("number of repetitions",np);
282  if (err || np < 2) {
283  egsWarning("createGeometry(iplanes): missing/wrong "
284  "'number of repetitions' input\n");
285  return 0;
286  }
287  string gname;
288  err = input->getInput("repeated geometry",gname);
289  if (err) {
290  egsWarning("createGeometry(iplanes): missing 'repeated geometry'"
291  " input\n");
292  return 0;
293  }
295  if (!g) {
296  egsWarning("createGeometry(iplanes): no geometry named %s exists\n",
297  gname.c_str());
298  return 0;
299  }
300  EGS_Float phi_o = 0;
301  EGS_Float tmp1,tmp2;
302  err = input->getInput("first angle",tmp1);
303  int err1 = input->getInput("first angle in radians",tmp2);
304  if (!err) {
305  phi_o = tmp1*M_PI/180;
306  }
307  else if (!err1) {
308  phi_o = tmp2;
309  }
310  EGS_RadialRepeater *result = new EGS_RadialRepeater(xo,a,np,g,phi_o);
311  result->setName(input);
312  result->setBoundaryTolerance(input);
313  string medium;
314  err = input->getInput("medium",medium);
315  if (!err) {
316  result->setMedium(medium);
317  }
318  result->setRLabels(input);
319  result->setLabels(input);
320  return result;
321  }
322 
323  vector<EGS_Float> angles;
324  err = input->getInput("angles",angles);
325  bool is_degree = true;
326  EGS_Float max_angle = 180;
327  if (err) {
328  err = input->getInput("angles in radian",angles);
329  if (err) {
330  egsWarning("createGeometry(iplanes): wrong/missing 'angles' or "
331  "'angles in radian' input\n");
332  return 0;
333  }
334  is_degree = false;
335  max_angle = M_PI;
336  }
337  EGS_Float *ang = new EGS_Float [angles.size()];
338  for (int j=0; j<angles.size(); j++) {
339  ang[j] = angles[j];
340  /*
341  if( ang[j] < 0 || ang[j] > max_angle ) {
342  egsWarning("createGeometry(iplanes): angle must be between 0 and "
343  "%g\n",max_angle); delete [] ang; return 0;
344  }
345  */
346  if (j > 0) {
347  if (ang[j] <= ang[j-1]) {
348  egsWarning("createGeometry(iplanes): angles must be ordered"
349  " in increasing order\n");
350  delete [] ang;
351  return 0;
352  }
353  }
354  }
355  int nang = angles.size();
356  EGS_Float ang_diff = ang[nang-1]-ang[0];
357  if (ang_diff > max_angle) {
358  egsWarning("createGeometry(iplanes): difference between first and last"
359  " angle must be less then 180 degrees.\n");
360  if (is_degree)
361  egsWarning(" Your input: first angle=%g, last angle=%g,"
362  " difference=%g\n",ang[0],ang[nang-1],ang[nang-1]-ang[0]);
363  else
364  egsWarning(" Your input: first angle=%g, last angle=%g,"
365  " difference=%g\n",ang[0]*180/M_PI,ang[nang-1]*180/M_PI,
366  (ang[nang-1]-ang[0])*180/M_PI);
367  delete [] ang;
368  return 0;
369  }
370  EGS_BaseGeometry *g = new EGS_IPlanes(xo,a,angles.size(),ang,"",is_degree);
371  delete [] ang;
372  g->setName(input);
373  g->setBoundaryTolerance(input);
374  g->setMedia(input);
375  g->setLabels(input);
376  return g;
377  }
378 
379  void EGS_RadialRepeater::setRLabels(EGS_Input *input) {
380 
381  // radial repeater labels
382  string inp;
383  int err;
384  err = input->getInput("set repeater label", inp);
385  if (!err) {
386  iplanes->setLabels(inp);
387  }
388  }
389 
390 
391  void EGS_RadialRepeater::getLabelRegions(const string &str, vector<int> &regs) {
392 
393  vector<int> local_regs;
394 
395  // label in repeated geometry
396  local_regs.clear();
397  g->getLabelRegions(str, local_regs);
398  for (int i=0; i<nrep; i++) {
399  for (int r=0; r<local_regs.size(); r++) {
400  regs.push_back(ng*i + local_regs[r]);
401  }
402  }
403 
404  // labels defined in iplanes
405  local_regs.clear();
406  iplanes->getLabelRegions(str, local_regs);
407  for (int i=0; i<local_regs.size(); i++) {
408  for (int r=0; r<ng; r++) {
409  regs.push_back(ng*local_regs[i] + r);
410  }
411  }
412 
413  // label defined in self (repeater input block)
415 
416  }
417 
418 }
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.
virtual void getLabelRegions(const string &str, vector< int > &regs)
Get the list of all regions labeled with str.
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.
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:51
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:338
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:57
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.