EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_cylinders.h
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ cylinders geometry headers
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: Ernesto Mainegra-Hing
27 # Reid Townson
28 # Hubert Ho
29 # Marc Chamberland
30 # Max Orok
31 #
32 ###############################################################################
33 */
34 
35 
41 #ifndef EGS_CYLINDERS_
42 #define EGS_CYLINDERS_
43 
44 #include "egs_base_geometry.h"
45 #include "egs_projectors.h"
46 #include "egs_math.h"
47 #include "egs_functions.h"
48 
49 #include <vector>
50 using namespace std;
51 
52 #ifdef WIN32
53 
54  #ifdef BUILD_CYLINDERS_DLL
55  #define EGS_CYLINDERS_EXPORT __declspec(dllexport)
56  #else
57  #define EGS_CYLINDERS_EXPORT __declspec(dllimport)
58  #endif
59  #define EGS_CYLINDERS_LOCAL
60 
61 #else
62 
63  #ifdef HAVE_VISIBILITY
64  #define EGS_CYLINDERS_EXPORT __attribute__ ((visibility ("default")))
65  #define EGS_CYLINDERS_LOCAL __attribute__ ((visibility ("hidden")))
66  #else
67  #define EGS_CYLINDERS_EXPORT
68  #define EGS_CYLINDERS_LOCAL
69  #endif
70 
71 #endif
72 
139 template <class T>
140 class EGS_CYLINDERS_EXPORT EGS_CylindersT : public EGS_BaseGeometry {
141 protected:
142 
143  EGS_Float *R,
144  *R2;
146  T a;
147 
148 #ifdef CYL_DEBUG
149  EGS_Vector last_x, last_u;
150  EGS_Float last_t, last_d, last_B, last_A;
151  int last_ireg, last_dir;
152 #endif
153 
154 public:
155 
161  if (nreg) {
162  delete [] R;
163  delete [] R2;
164  }
165  };
166 
174  EGS_CylindersT(int nc, const EGS_Float *radius,
175  const EGS_Vector &position, const string &Name,
176  const T &A) : EGS_BaseGeometry(Name), xo(position), a(A) {
177  if (nc>0) {
178  R=new EGS_Float [nc];
179  R2=new EGS_Float [nc];
180 
181  for (int i=0; i<nc; i++) {
182  R[i]=radius[i];
183  R2[i]=radius[i]*radius[i];
184  }
185  nreg=nc;
186  }
187  };
188 
190  EGS_CylindersT(const vector<EGS_Float> &radius,
191  const EGS_Vector &position, const string &Name,
192  const T &A) : EGS_BaseGeometry(Name), xo(position), a(A) {
193  if (radius.size()>0) {
194  R=new EGS_Float [radius.size()];
195  R2=new EGS_Float [radius.size()];
196 
197  for (std::size_t i=0; i<radius.size(); i++) {
198  R[i]=radius[i];
199  R2[i]=radius[i]*radius[i];
200  }
201  nreg=radius.size();
202  }
203  };
204 
205  bool isInside(const EGS_Vector &x) {
206  EGS_Vector rc(x-xo);
207  EGS_Float rp=a*rc, rho_sq=rc.length2()-rp*rp;
208  if (rho_sq>R2[nreg-1]) {
209  return false;
210  }
211  return true;
212  };
213 
214  int isWhere(const EGS_Vector &x) {
215  EGS_Vector rc(x-xo);
216  EGS_Float rp=a*rc, rho_sq=rc.length2()-rp*rp;
217  if (rho_sq>R2[nreg-1]) {
218  return -1;
219  }
220  if (rho_sq<R2[0]) {
221  return 0;
222  }
223  return findRegion(rho_sq,nreg-1,R2)+1;
224  };
225 
226  int inside(const EGS_Vector &x) {
227  EGS_Vector rc(x-xo);
228  EGS_Float
229  rp=a*rc,
230  rho_sq=rc.length2()-rp*rp;
231 
232  if (rho_sq>R2[nreg-1]) {
233  return -1; // outside all cylinders
234  }
235  if (rho_sq<R2[0]) {
236  return 0; // inside central cylinder
237  }
238 
239  // find particle region
240  int ic=0,oc=nreg,ms;
241  while (oc-ic>1) {
242  ms=(ic+oc)/2;
243  if (rho_sq<R2[ms]) {
244  oc=ms;
245  }
246  else {
247  ic=ms;
248  }
249  }
250  return oc;
251  };
252 
253  EGS_Float howfarToOutside(int ireg, const EGS_Vector &x,
254  const EGS_Vector &u) {
255  if (ireg < 0) {
256  return 0;
257  }
258  EGS_Float up=a*u;
259  if (fabs(up)>=1) {
260  return veryFar; // parallel to axis
261  }
262  EGS_Float A=1-up*up;
263  EGS_Vector rc(x-xo);
264  EGS_Float rcp=a*rc, urc=u*rc;
265  EGS_Float C=rc.length2()-rcp*rcp-R2[nreg-1];
266  if (C >= 0) {
267  return 0; // outside within precision
268  }
269  EGS_Float B=urc-up*rcp;
270  EGS_Float Dsq = sqrt(B*B-A*C);
271  EGS_Float d = B > 0 ? -C/(Dsq + B) : (Dsq - B)/A;
272  return d;
273  };
274 
275  int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u,
276  EGS_Float &t, int *newmed = 0, EGS_Vector *normal = 0) {
277 
278  EGS_Float d=veryFar; // large distance to any boundry
279 
280  // projections
281  double up=a*u;
282  if (fabs(up)>=1) {
283  return ireg; // parallel to cylinder axis
284  }
285  double A=1-up*up; // d^2 coefficient
286 
287  int dir=-1; // direction entering or exiting cylinder boundry
288 
289  EGS_Vector rc(x-xo);
290  double rcp=a*rc, urc=u*rc;
291  double B=urc-up*rcp; // d^1 coefficient
292 
293  EGS_Float rad=0;
294 
295  // in any region?
296  if (ireg>=0) {
297 
298  double C=rc.length2()-rcp*rcp-R2[ireg]; // d^0 coefficient
299 
300  // B>=0 ... particle travelling radially outwards
301  if (B>=0 || !ireg) { // OR it is IN the centre cylinder
302  rad = -R[ireg];
303  dir=ireg+1;
304  if (dir >= nreg) {
305  dir = -1;
306  }
307  double Dsq = B*B-A*C;
308  if (Dsq > 0) {
309  Dsq = sqrt(Dsq);
310  }
311  else {
312  if (Dsq < -boundaryTolerance) egsWarning("\nEGS_CylindersT::howfar(): "
313  "the particle may not be in the region\n we think it "
314  "is as Dsq = %g\n",Dsq);
315  Dsq = 0;
316  }
317  //d=-B+sqrt(B*B-A*C);
318  d = B > 0 ? -C/(Dsq + B) : (Dsq - B)/A;
319  if (d < 0) {
320  if (C > boundaryTolerance) {
321  egsWarning("\nEGS_CylindersT::howfar(): the particle "
322  "may not be in the region\n we think it is as "
323  "Cout = %g\n",C);
324  egsWarning(" ireg=%d R2=%g R2[%d]=%g\n",ireg,
325  rc.length2()-rcp*rcp,ireg,R2[ireg]);
326  egsWarning("x=(%g,%g,%g) u=(%g,%g,%g)\n",
327  x.x,x.y,x.z,u.x,u.y,u.z);
328  egsWarning("B=%g A=%g\n",B,A);
329 #ifdef CYL_DEBUG
330  egsWarning("last:\n");
331  egsWarning("x=(%g,%g,%g) u=(%g,%g,%g)\n",
332  last_x.x,last_x.y,last_x.z,last_u.x,last_u.y,last_u.z);
333  egsWarning("B=%g A=%g ireg=%d inew=%d\n",
334  last_B,last_A,last_ireg,last_dir);
335  egsWarning("t=%g d=%g\n",last_t,last_d);
336 #endif
337  }
338  d = halfBoundaryTolerance;
339  }
340  }
341 
342  // check for intersection with inner cylinder
343  else {
344  double dR2=R2[ireg]-R2[ireg-1];
345  C+=dR2;
346  double D_sq=B*B-A*C;
347 
348  if (D_sq<=0) { // outer cylinder intersection
349  rad = -R[ireg];
350  dir=ireg+1;
351  if (dir >= nreg) {
352  dir = -1;
353  }
354  /*
355  D_sq+=A*C; // should we not use
356  C-=dR2; // d = -B + sqrt(D_sq+A*dR2)
357  d=-B+sqrt(D_sq-A*C); // instead?
358  */
359  D_sq += A*dR2;
360  if (D_sq > 0) {
361  D_sq = sqrt(D_sq);
362  }
363  else {
364  if (D_sq < -boundaryTolerance)
365  egsWarning("\nEGS_CylindersT::howfar(): the "
366  "particle may not be in the region\n we think "
367  "it is as D_sq = %g\n",D_sq);
368  D_sq = 0;
369  }
370  d = (D_sq - B)/A;
371  }
372 
373  else { // inner cylinder intersection
374  dir=ireg-1;
375  rad = R[dir];
376  //d=-B-sqrt(D_sq);
377  d = C/(sqrt(D_sq) - B);
378  if (d < 0) {
379  if (C < -boundaryTolerance) egsWarning("EGS_CylindersT::howfar(): "
380  "the particle may not be in the region we think it "
381  "is as Cin = %g\n",C);
382  d = halfBoundaryTolerance;
383  }
384  }
385  }
386  }
387 
388  else { // outside all regions
389  if (B<0) { // particle travelling radially inwards
390  double C=rc.length2()-rcp*rcp-R2[nreg-1],
391  D_sq=B*B-A*C;
392 
393  if (D_sq>0) { // cylinder intersection
394  dir=nreg-1;
395  rad = R[dir];
396  //d=-B-sqrt(D_sq);
397  d = C/(sqrt(D_sq) - B);
398  if (d < 0) {
399  if (C < -boundaryTolerance) {
400  egsWarning("EGS_CylindersT::howfar(): "
401  "we think that the particle is outside, but C=%g\n",C);
402  egsWarning(" d=%g B=%g D_sq=%g\n",d,B,D_sq);
403  egsWarning(" ireg=%d x=(%g,%g,%g) u=(%g,%g,%g)\n",
404  ireg,x.x,x.y,x.z,u.x,u.y,u.z);
405  }
406  d = halfBoundaryTolerance;
407  }
408  }
409  }
410  else {
411  return ireg;
412  }
413  }
414  //d/=A;
415 
416 #ifdef CYL_DEBUG
417  if (isnan(d)) {
418  egsWarning("d is nan: A=%g B=%g ireg=%d R2=%g\n",
419  A,B,ireg,rc.length2()-rcp*rcp);
420  }
421 
422  last_x = x;
423  last_u = u;
424  last_B = B;
425  last_A = A;
426  last_ireg = ireg;
427  last_dir = dir;
428  last_t = t;
429  last_d = d;
430 #endif
431 
432  // correct t-step
433  if (d<t) {
434  t=d;
435  if (newmed) {
436  if (dir >= 0) {
437  *newmed = medium(dir);
438  }
439  else {
440  *newmed=-1;
441  }
442  }
443  if (normal) {
444  EGS_Vector n(rc + u*t - a*(rcp+up*t));
445  *normal = n*(1/rad);
446  }
447  return dir;
448  }
449  return ireg;
450  };
451 
452  EGS_Float hownear(int ireg, const EGS_Vector &x) {
453  EGS_Vector rc(x-xo);
454  EGS_Float
455  rcp=a*rc,
456  rho=sqrt(rc.length2()-rcp*rcp);
457 
458  // check outer cylinder first if inside geometry
459  if (ireg>=0) {
460  EGS_Float d=R[ireg]-rho;
461 
462  if (ireg) {
463  EGS_Float dd=rho-R[ireg-1];
464  if (dd<d) {
465  d=dd;
466  }
467  }
468 
469  return d;
470 
471  }
472 
473  else {
474  return rho-R[nreg-1];
475  }
476  };
477 
478  int getMaxStep() const {
479  return 2*nreg + 1;
480  };
481 
482  const string &getType() const {
483  return a.getType();
484  };
485 
486  void printInfo() const {
488  a.printInfo();
489  egsInformation(" midpoint of cylinders = (%g,%g,%g)\n",xo.x,xo.y,xo.z);
490  egsInformation(" cylinder radii = ");
491  for (int j=0; j<nreg; j++) {
492  egsInformation("%g ",R[j]);
493  }
494  egsInformation("\n");
495  egsInformation("=====================================================\n");
496  };
497 };
498 
503 
504 #endif
Base geometry class. Every geometry class must be derived from EGS_BaseGeometry.
virtual void printInfo() const
Print information about this geometry.
A set of concentric cylinders.
EGS_Float * R2
Radii squared.
EGS_CylindersT(int nc, const EGS_Float *radius, const EGS_Vector &position, const string &Name, const T &A)
Construct a set of concentric cylinders.
EGS_Float * R
Radii.
EGS_CylindersT(const vector< EGS_Float > &radius, const EGS_Vector &position, const string &Name, const T &A)
This is an overloaded member function, provided for convenience. It differs from the above function o...
T a
The projection operator.
EGS_Vector xo
A point on the cylinder axis.
~EGS_CylindersT()
Desctructor.
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
EGS_BaseGeometry class header file.
Global egspp functions header file.
Attempts to fix broken math header files.
EGS_Projector and EGS_2DVector 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 egsWarning
Always use this function for reporting warnings.
const EGS_Float veryFar
A very large float.