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