Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/geometry/solids/specific/src/G4TwistTrapAlphaSide.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  1 //
  2 // ********************************************************************
  3 // * License and Disclaimer                                           *
  4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.                             *
 10 // *                                                                  *
 11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                                                  *
 18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // ********************************************************************
 25 //
 26 // G4TwistTrapAlphaSide implementation
 27 //
 28 // Author: 18/03/2005 - O.Link (Oliver.Link@cern.ch)
 29 // --------------------------------------------------------------------
 30 
 31 #include <cmath>
 32 
 33 #include "G4TwistTrapAlphaSide.hh"
 34 #include "G4PhysicalConstants.hh"
 35 #include "G4JTPolynomialSolver.hh"
 36 
 37 //=====================================================================
 38 //* constructors ------------------------------------------------------
 39 
 40 G4TwistTrapAlphaSide::
 41 G4TwistTrapAlphaSide(const G4String& name,
 42                      G4double      PhiTwist,  // twist angle
 43                      G4double      pDz,       // half z lenght
 44                      G4double      pTheta,    // direction between end planes
 45                      G4double      pPhi,      // by polar and azimutal angles
 46                      G4double      pDy1,      // half y length at -pDz
 47                      G4double      pDx1,      // half x length at -pDz,-pDy
 48                      G4double      pDx2,      // half x length at -pDz,+pDy
 49                      G4double      pDy2,      // half y length at +pDz
 50                      G4double      pDx3,      // half x length at +pDz,-pDy
 51                      G4double      pDx4,      // half x length at +pDz,+pDy
 52                      G4double      pAlph,     // tilt angle at +pDz
 53                      G4double      AngleSide  // parity
 54                                              )
 55   : G4VTwistSurface(name)
 56 {
 57   fAxis[0]    = kYAxis; // in local coordinate system
 58   fAxis[1]    = kZAxis;
 59   fAxisMin[0] = -kInfinity ;  // Y Axis boundary
 60   fAxisMax[0] = kInfinity ;   //   depends on z !!
 61   fAxisMin[1] = -pDz ;      // Z Axis boundary
 62   fAxisMax[1] = pDz ;
 63   
 64   fDx1  = pDx1 ;
 65   fDx2  = pDx2 ;
 66   fDx3  = pDx3 ;
 67   fDx4  = pDx4 ;
 68 
 69   fDy1   = pDy1 ;
 70   fDy2   = pDy2 ;
 71 
 72   fDz   = pDz ;
 73 
 74   fAlph = pAlph  ;
 75   fTAlph = std::tan(fAlph) ;
 76 
 77   fTheta = pTheta ;
 78   fPhi   = pPhi ;
 79 
 80   // precalculate frequently used parameters
 81   fDx4plus2  = fDx4 + fDx2 ;
 82   fDx4minus2 = fDx4 - fDx2 ;
 83   fDx3plus1  = fDx3 + fDx1 ; 
 84   fDx3minus1 = fDx3 - fDx1 ;
 85   fDy2plus1  = fDy2 + fDy1 ;
 86   fDy2minus1 = fDy2 - fDy1 ;
 87 
 88   fa1md1 = 2*fDx2 - 2*fDx1  ; 
 89   fa2md2 = 2*fDx4 - 2*fDx3 ;
 90 
 91   fPhiTwist = PhiTwist ;    // dphi
 92   fAngleSide = AngleSide ;  // 0,90,180,270 deg
 93 
 94   fdeltaX = 2 * fDz * std::tan(fTheta) * std::cos(fPhi);
 95     // dx in surface equation
 96   fdeltaY = 2 * fDz * std::tan(fTheta) * std::sin(fPhi);
 97     // dy in surface equation
 98   
 99   fRot.rotateZ( AngleSide ) ; 
100   
101   fTrans.set(0, 0, 0);  // No Translation
102   fIsValidNorm = false;
103   
104   SetCorners() ;
105   SetBoundaries() ;
106 }
107 
108 
109 //=====================================================================
110 //* Fake default constructor ------------------------------------------
111 
112 G4TwistTrapAlphaSide::G4TwistTrapAlphaSide( __void__& a )
113   : G4VTwistSurface(a)
114 {
115 }
116 
117 
118 //=====================================================================
119 //* destructor --------------------------------------------------------
120 
121 G4TwistTrapAlphaSide::~G4TwistTrapAlphaSide() = default;
122 
123 
124 //=====================================================================
125 //* GetNormal ---------------------------------------------------------
126 
127 G4ThreeVector
128 G4TwistTrapAlphaSide::GetNormal(const G4ThreeVector& tmpxx, 
129                                       G4bool isGlobal) 
130 {
131    // GetNormal returns a normal vector at a surface (or very close
132    // to surface) point at tmpxx.
133    // If isGlobal=true, it returns the normal in global coordinate.
134    //
135 
136    G4ThreeVector xx;
137    if (isGlobal)
138    {
139       xx = ComputeLocalPoint(tmpxx);
140       if ((xx - fCurrentNormal.p).mag() < 0.5 * kCarTolerance)
141       {
142          return ComputeGlobalDirection(fCurrentNormal.normal);
143       }
144    }
145    else
146    {
147       xx = tmpxx;
148       if (xx == fCurrentNormal.p)
149       {
150          return fCurrentNormal.normal;
151       }
152    }
153 
154    G4double phi ;
155    G4double u ;
156 
157    GetPhiUAtX(xx,phi,u) ;   // phi,u for point xx close to surface 
158 
159    G4ThreeVector normal =  NormAng(phi,u) ;  // the normal vector at phi,u
160 
161 #ifdef G4TWISTDEBUG
162    G4cout  << "normal vector = " << normal << G4endl ;
163    G4cout << "phi = " << phi << " , u = " << u << G4endl ;
164 #endif
165 
166    if (isGlobal)
167    {
168       fCurrentNormal.normal = ComputeGlobalDirection(normal.unit());
169    }
170    else
171    {
172       fCurrentNormal.normal = normal.unit();
173    }
174 
175    return fCurrentNormal.normal;
176 }
177 
178 //=====================================================================
179 //* DistanceToSurface -------------------------------------------------
180 
181 G4int
182 G4TwistTrapAlphaSide::DistanceToSurface(const G4ThreeVector& gp,
183                                         const G4ThreeVector& gv,
184                                               G4ThreeVector  gxx[],
185                                               G4double       distance[],
186                                               G4int          areacode[],
187                                               G4bool         isvalid[],
188                                               EValidate      validate)
189 {
190   static const G4double pihalf = pi/2 ;
191   const G4double ctol = 0.5 * kCarTolerance;
192 
193   G4bool IsParallel = false ;
194   G4bool IsConverged =  false ;
195 
196   G4int nxx = 0 ;  // number of physical solutions
197 
198   fCurStatWithV.ResetfDone(validate, &gp, &gv);
199 
200   if (fCurStatWithV.IsDone())
201   {
202     for (G4int i=0; i<fCurStatWithV.GetNXX(); ++i)
203     {
204       gxx[i] = fCurStatWithV.GetXX(i);
205       distance[i] = fCurStatWithV.GetDistance(i);
206       areacode[i] = fCurStatWithV.GetAreacode(i);
207       isvalid[i]  = fCurStatWithV.IsValid(i);
208     }
209     return fCurStatWithV.GetNXX();
210   }
211   else  // initialise
212   {
213     for (G4int j=0; j<G4VSURFACENXX ; ++j)
214     {
215       distance[j] = kInfinity;
216       areacode[j] = sOutside;
217       isvalid[j]  = false;
218       gxx[j].set(kInfinity, kInfinity, kInfinity);
219     }
220   }
221 
222   G4ThreeVector p = ComputeLocalPoint(gp);
223   G4ThreeVector v = ComputeLocalDirection(gv);
224   
225 #ifdef G4TWISTDEBUG
226   G4cout << "Local point p = " << p << G4endl ;
227   G4cout << "Local direction v = " << v << G4endl ; 
228 #endif
229 
230   G4double phi,u ;  // parameters
231 
232   // temporary variables
233 
234   G4double      tmpdist = kInfinity ;
235   G4ThreeVector tmpxx;
236   G4int         tmpareacode = sOutside ;
237   G4bool        tmpisvalid  = false ;
238 
239   std::vector<Intersection> xbuf ;
240   Intersection xbuftmp ;
241   
242   // prepare some variables for the intersection finder
243 
244   G4double L = 2*fDz ;
245 
246   G4double phixz = fPhiTwist * ( p.x() * v.z() - p.z() * v.x() ) ;
247   G4double phiyz = fPhiTwist * ( p.y() * v.z() - p.z() * v.y() ) ;
248 
249 
250   // special case vz = 0
251 
252   if ( v.z() == 0. )
253   {
254     if ( std::fabs(p.z()) <= L )   // intersection possible in z
255     {
256       phi = p.z() * fPhiTwist / L ;  // phi is determined by the z-position 
257       u = (fDy1*(4*(-(fdeltaY*phi*v.x()) + fPhiTwist*p.y()*v.x()
258                     + fdeltaX*phi*v.y() - fPhiTwist*p.x()*v.y())
259                  + ((fDx3plus1 + fDx4plus2)*fPhiTwist
260                  +  2*(fDx3minus1 + fDx4minus2)*phi)
261                      *(v.y()*std::cos(phi) - v.x()*std::sin(phi))))
262          /(fPhiTwist*(4*fDy1* v.x() - (fa1md1 + 4*fDy1*fTAlph)*v.y())
263                     *std::cos(phi) + fPhiTwist*(fa1md1*v.x()
264                        + 4*fDy1*(fTAlph*v.x() + v.y()))*std::sin(phi));
265       xbuftmp.phi = phi ;
266       xbuftmp.u = u ;
267       xbuftmp.areacode = sOutside ;
268       xbuftmp.distance = kInfinity ;
269       xbuftmp.isvalid = false ;
270 
271       xbuf.push_back(xbuftmp) ;  // store it to xbuf
272     }
273     else   // no intersection possible
274     {
275       distance[0] = kInfinity;
276       gxx[0].set(kInfinity,kInfinity,kInfinity);
277       isvalid[0] = false ;
278       areacode[0] = sOutside ;
279       fCurStatWithV.SetCurrentStatus(0, gxx[0], distance[0],
280                                      areacode[0], isvalid[0],
281                                      0, validate, &gp, &gv);
282       return 0;
283     }  // end std::fabs(p.z() <= L 
284   } // end v.z() == 0
285   else  // general solution for non-zero vz
286   {
287 
288     G4double c[8],srd[7],si[7] ;  
289 
290     c[7] = 57600*
291       fDy1*(fa1md1*phiyz + 
292             fDy1*(-4*phixz + 4*fTAlph*phiyz
293                  + (fDx3plus1 + fDx4plus2)*fPhiTwist*v.z())) ;
294     c[6] = -57600*
295       fDy1*(4*fDy1*(phiyz + 2*fDz*v.x() + fTAlph*(phixz - 2*fDz*v.y()))
296           - 2*fDy1*(2*fdeltaX + fDx3minus1 + fDx4minus2
297                   - 2*fdeltaY*fTAlph)*v.z()
298           + fa1md1*(phixz - 2*fDz*v.y() + fdeltaY*v.z()));
299     c[5] = 4800*
300       fDy1*(fa1md1*(-5*phiyz - 24*fDz*v.x() + 12*fdeltaX*v.z()) + 
301             fDy1*(20*phixz - 4*(5*fTAlph*phiyz + 24*fDz*fTAlph*v.x()
302                    + 24*fDz*v.y()) + (48*fdeltaY + (fDx3plus1 + fDx4plus2)
303                                     *fPhiTwist + 48*fdeltaX*fTAlph)*v.z()));
304     c[4] = 4800*
305       fDy1*(fa1md1*(phixz - 10*fDz*v.y() + 5*fdeltaY*v.z())
306           + 2*fDy1*(2*phiyz + 20*fDz*v.x()
307                    + (-10*fdeltaX + fDx3minus1 + fDx4minus2)*v.z()
308                    + 2*fTAlph*(phixz - 10*fDz*v.y() + 5*fdeltaY*v.z())));
309     c[3] = -96*
310       fDy1*(-(fa1md1*(phiyz + 100*fDz*v.x() - 50*fdeltaX*v.z()))
311           + fDy1*(4*phixz - 400*fDz*v.y()
312                   + (200*fdeltaY - (fDx3plus1 + fDx4plus2)*fPhiTwist)*v.z()
313                   - 4*fTAlph*(phiyz + 100*fDz*v.x() - 50*fdeltaX*v.z())));
314     c[2] = 32*
315       fDy1*(4*fDy1*(7*fTAlph*phixz + 7*phiyz - 6*fDz*v.x() + 6*fDz*fTAlph*v.y())
316           + 6*fDy1*(2*fdeltaX+fDx3minus1+fDx4minus2-2*fdeltaY*fTAlph)*v.z()
317           + fa1md1*(7*phixz + 6*fDz*v.y() - 3*fdeltaY*v.z()));
318     c[1] = -8*
319       fDy1*(fa1md1*(-9*phiyz - 56*fDz*v.x() + 28*fdeltaX*v.z())
320           + 4*fDy1*(9*phixz - 9*fTAlph*phiyz - 56*fDz*fTAlph*v.x()
321                   - 56*fDz*v.y() + 28*(fdeltaY + fdeltaX*fTAlph)*v.z()));
322     c[0] = 72*
323       fDy1*(fa1md1*(2*fDz*v.y() - fdeltaY*v.z())
324           + fDy1*(-8*fDz*v.x() + 8*fDz*fTAlph*v.y()
325                 + 4*fdeltaX*v.z() - 4*fdeltaY*fTAlph*v.z()));
326 
327 #ifdef G4TWISTDEBUG
328     G4cout << "coef = " << c[0] << " " 
329            <<  c[1] << " "  
330            <<  c[2] << " "  
331            <<  c[3] << " "  
332            <<  c[4] << " "  
333            <<  c[5] << " "  
334            <<  c[6] << " "  
335            <<  c[7] << G4endl ; 
336 #endif    
337 
338     G4JTPolynomialSolver trapEq ;
339     G4int num = trapEq.FindRoots(c,7,srd,si);
340 
341     for (G4int i = 0 ; i<num ; i++ )   // loop over all math solutions
342     {  
343       if ( si[i]==0.0 )  // only real solutions
344       { 
345 #ifdef G4TWISTDEBUG
346         G4cout << "Solution " << i << " : " << srd[i] << G4endl ;
347 #endif
348         phi = std::fmod(srd[i] , pihalf)  ;
349         u   = (fDy1*(4*(phiyz + 2*fDz*phi*v.y() - fdeltaY*phi*v.z())
350                      - ((fDx3plus1 + fDx4plus2)*fPhiTwist
351                        + 2*(fDx3minus1 + fDx4minus2)*phi)*v.z()*std::sin(phi)))
352              /(fPhiTwist*v.z()*(4*fDy1*std::cos(phi)
353                              + (fa1md1 + 4*fDy1*fTAlph)*std::sin(phi)));        
354         xbuftmp.phi = phi ;
355         xbuftmp.u = u ;
356         xbuftmp.areacode = sOutside ;
357         xbuftmp.distance = kInfinity ;
358         xbuftmp.isvalid = false ;
359         
360         xbuf.push_back(xbuftmp) ;  // store it to xbuf
361       
362 #ifdef G4TWISTDEBUG
363         G4cout << "solution " << i << " = " << phi << " , " << u  << G4endl ;
364 #endif
365       }  // end if real solution
366     }  // end loop i    
367   }    // end general case
368 
369   nxx = (G4int)xbuf.size() ;  // save the number of  solutions
370 
371   G4ThreeVector xxonsurface  ;    // point on surface
372   G4ThreeVector surfacenormal  ;  // normal vector  
373   G4double deltaX;  // distance between intersection point and point on surface
374   G4double theta;   // angle between track and surfacenormal
375   G4double factor;  // a scaling factor
376   G4int maxint=30;  // number of iterations
377 
378   for (auto & k : xbuf)
379   {
380 #ifdef G4TWISTDEBUG
381     G4cout << "Solution " << k << " : " 
382            << "reconstructed phiR = " << xbuf[k].phi
383            << ", uR = " << xbuf[k].u << G4endl ; 
384 #endif
385     
386     phi = k.phi ;  // get the stored values for phi and u
387     u = k.u ;
388 
389     IsConverged = false ;   // no convergence at the beginning
390     
391     for ( G4int i = 1 ; i<maxint ; ++i )
392     {
393       xxonsurface = SurfacePoint(phi,u) ;
394       surfacenormal = NormAng(phi,u) ;
395 
396       tmpdist = DistanceToPlaneWithV(p, v, xxonsurface, surfacenormal, tmpxx); 
397       deltaX = ( tmpxx - xxonsurface ).mag() ; 
398       theta = std::fabs(std::acos(v*surfacenormal) - pihalf) ;
399       if ( theta < 0.001 )
400       { 
401         factor = 50 ;
402         IsParallel = true ;
403       }
404       else
405       {
406         factor = 1 ;
407       }
408 
409 #ifdef G4TWISTDEBUG
410       G4cout << "Step i = " << i << ", distance = " << tmpdist
411              << ", " << deltaX << G4endl ;
412       G4cout << "X = " << tmpxx << G4endl ;
413 #endif
414       
415       GetPhiUAtX(tmpxx, phi, u) ;
416         // the new point xx is accepted and phi/u replaced
417       
418 #ifdef G4TWISTDEBUG
419       G4cout << "approximated phi = " << phi << ", u = " << u << G4endl ; 
420 #endif
421       
422       if ( deltaX <= factor*ctol ) { IsConverged = true ; break ; }
423       
424     }  // end iterative loop (i)
425     
426     if ( std::fabs(tmpdist)<ctol ) { tmpdist = 0 ; }
427 
428 #ifdef G4TWISTDEBUG
429     G4cout << "refined solution "  << phi << " , " << u  <<  G4endl ;
430     G4cout << "distance = " << tmpdist << G4endl ;
431     G4cout << "local X = " << tmpxx << G4endl ;
432 #endif
433     
434     tmpisvalid = false ;  // init 
435 
436     if ( IsConverged )
437     {
438       if (validate == kValidateWithTol)
439       {
440         tmpareacode = GetAreaCode(tmpxx);
441         if (!IsOutside(tmpareacode))
442         {
443           if (tmpdist >= 0) tmpisvalid = true;
444         }
445       }
446       else if (validate == kValidateWithoutTol)
447       {
448         tmpareacode = GetAreaCode(tmpxx, false);
449         if (IsInside(tmpareacode))
450         {
451           if (tmpdist >= 0) { tmpisvalid = true; }
452         }
453       }
454       else  // kDontValidate
455       {
456         G4Exception("G4TwistTrapAlphaSide::DistanceToSurface()",
457                     "GeomSolids0001", FatalException,
458                     "Feature NOT implemented !");
459       }
460     } 
461     else
462     {
463       tmpdist = kInfinity;     // no convergence after 10 steps 
464       tmpisvalid = false ;     // solution is not vaild
465     }  
466 
467     // store the found values
468     // 
469     k.xx = tmpxx ;
470     k.distance = tmpdist ;
471     k.areacode = tmpareacode ;
472     k.isvalid = tmpisvalid ;
473 
474   }  // end loop over physical solutions (variable k)
475 
476   std::sort(xbuf.begin() , xbuf.end(), DistanceSort ) ;  // sorting
477 
478 #ifdef G4TWISTDEBUG
479   G4cout << G4endl << "list xbuf after sorting : " << G4endl ;
480   G4cout << G4endl << G4endl ;
481 #endif
482 
483   // erase identical intersection (within kCarTolerance) 
484   //
485   xbuf.erase( std::unique(xbuf.begin(), xbuf.end() , EqualIntersection ),
486               xbuf.end() );
487 
488 
489   // add guesses
490   //
491   auto nxxtmp = (G4int)xbuf.size() ;
492 
493   if ( nxxtmp<2 || IsParallel  )  // positive end
494   {
495 
496 #ifdef G4TWISTDEBUG
497     G4cout << "add guess at +z/2 .. " << G4endl ;
498 #endif
499 
500     phi = fPhiTwist/2 ;
501     u   = 0 ;
502     
503     xbuftmp.phi = phi ;
504     xbuftmp.u = u ;
505     xbuftmp.areacode = sOutside ;
506     xbuftmp.distance = kInfinity ;
507     xbuftmp.isvalid = false ;
508     
509     xbuf.push_back(xbuftmp) ;  // store it to xbuf
510 
511 #ifdef G4TWISTDEBUG
512     G4cout << "add guess at -z/2 .. " << G4endl ;
513 #endif
514 
515     phi = -fPhiTwist/2 ;
516     u   = 0 ;
517     
518     xbuftmp.phi = phi ;
519     xbuftmp.u = u ;
520     xbuftmp.areacode = sOutside ;
521     xbuftmp.distance = kInfinity ;
522     xbuftmp.isvalid = false ;
523     
524     xbuf.push_back(xbuftmp) ;  // store it to xbuf
525 
526     for ( std::size_t k = nxxtmp ; k<xbuf.size() ; ++k )
527     {
528 
529 #ifdef G4TWISTDEBUG
530       G4cout << "Solution " << k << " : " 
531              << "reconstructed phiR = " << xbuf[k].phi
532              << ", uR = " << xbuf[k].u << G4endl ; 
533 #endif
534       
535       phi = xbuf[k].phi ;  // get the stored values for phi and u
536       u   = xbuf[k].u ;
537 
538       IsConverged = false ;   // no convergence at the beginning
539       
540       for ( G4int i = 1 ; i<maxint ; ++i )
541       {
542         xxonsurface = SurfacePoint(phi,u) ;
543         surfacenormal = NormAng(phi,u) ;
544         tmpdist = DistanceToPlaneWithV(p, v, xxonsurface, surfacenormal, tmpxx);
545         deltaX = ( tmpxx - xxonsurface ).mag();
546         theta = std::fabs(std::acos(v*surfacenormal) - pihalf);
547         if ( theta < 0.001 )
548         { 
549           factor = 50 ;    
550         }
551         else
552         {
553           factor = 1 ;
554         }
555         
556 #ifdef G4TWISTDEBUG
557         G4cout << "Step i = " << i << ", distance = " << tmpdist
558                << ", " << deltaX << G4endl
559                << "X = " << tmpxx << G4endl ;
560 #endif
561 
562         GetPhiUAtX(tmpxx, phi, u) ;
563           // the new point xx is accepted and phi/u replaced
564       
565 #ifdef G4TWISTDEBUG
566         G4cout << "approximated phi = " << phi << ", u = " << u << G4endl ; 
567 #endif
568       
569         if ( deltaX <= factor*ctol ) { IsConverged = true ; break ; }
570       
571       }  // end iterative loop (i)
572     
573       if ( std::fabs(tmpdist)<ctol )  { tmpdist = 0; }
574 
575 #ifdef G4TWISTDEBUG
576       G4cout << "refined solution "  << phi << " , " << u  <<  G4endl ;
577       G4cout << "distance = " << tmpdist << G4endl ;
578       G4cout << "local X = " << tmpxx << G4endl ;
579 #endif
580 
581       tmpisvalid = false ;  // init 
582 
583       if ( IsConverged )
584       {
585         if (validate == kValidateWithTol)
586         {
587           tmpareacode = GetAreaCode(tmpxx);
588           if (!IsOutside(tmpareacode))
589           {
590             if (tmpdist >= 0)  { tmpisvalid = true; }
591           }
592         }
593         else if (validate == kValidateWithoutTol)
594         {
595           tmpareacode = GetAreaCode(tmpxx, false);
596           if (IsInside(tmpareacode))
597           {
598             if (tmpdist >= 0)  { tmpisvalid = true; }
599           }
600         }
601         else  // kDontValidate
602         {
603           G4Exception("G4TwistedBoxSide::DistanceToSurface()",
604                       "GeomSolids0001", FatalException,
605                       "Feature NOT implemented !");
606         }
607       } 
608       else
609       {
610         tmpdist = kInfinity;     // no convergence after 10 steps 
611         tmpisvalid = false ;     // solution is not vaild
612       }  
613 
614       // store the found values
615       //
616       xbuf[k].xx = tmpxx ;
617       xbuf[k].distance = tmpdist ;
618       xbuf[k].areacode = tmpareacode ;
619       xbuf[k].isvalid = tmpisvalid ;
620 
621     }  // end loop over physical solutions 
622   }  // end less than 2 solutions
623 
624   // sort again
625   std::sort(xbuf.begin() , xbuf.end(), DistanceSort ) ;  // sorting
626 
627   // erase identical intersection (within kCarTolerance) 
628   xbuf.erase( std::unique(xbuf.begin(), xbuf.end() , EqualIntersection ) ,
629               xbuf.end() );
630 
631 #ifdef G4TWISTDEBUG
632   G4cout << G4endl << "list xbuf after sorting : " << G4endl ;
633   G4cout << G4endl << G4endl ;
634 #endif
635 
636   nxx = (G4int)xbuf.size() ;   // determine number of solutions again.
637 
638   for ( G4int i = 0 ; i<(G4int)xbuf.size() ; ++i )
639   {
640     distance[i] = xbuf[i].distance;
641     gxx[i]      = ComputeGlobalPoint(xbuf[i].xx);
642     areacode[i] = xbuf[i].areacode ;
643     isvalid[i]  = xbuf[i].isvalid ;
644     
645     fCurStatWithV.SetCurrentStatus(i, gxx[i], distance[i], areacode[i],
646                                      isvalid[i], nxx, validate, &gp, &gv);
647 #ifdef G4TWISTDEBUG
648     G4cout << "element Nr. " << i 
649            << ", local Intersection = " << xbuf[i].xx 
650            << ", distance = " << xbuf[i].distance 
651            << ", u = " << xbuf[i].u 
652            << ", phi = " << xbuf[i].phi 
653            << ", isvalid = " << xbuf[i].isvalid 
654            << G4endl ;
655 #endif
656 
657   }  // end for( i ) loop
658 
659 #ifdef G4TWISTDEBUG
660   G4cout << "G4TwistTrapAlphaSide finished " << G4endl ;
661   G4cout << nxx << " possible physical solutions found" << G4endl ;
662   for ( G4int k= 0 ; k< nxx ; k++ )
663   {
664     G4cout << "global intersection Point found: " << gxx[k] << G4endl ;
665     G4cout << "distance = " << distance[k] << G4endl ;
666     G4cout << "isvalid = " << isvalid[k] << G4endl ;
667   }
668 #endif
669 
670   return nxx ;
671 }
672 
673 
674 //=====================================================================
675 //* DistanceToSurface -------------------------------------------------
676 
677 G4int
678 G4TwistTrapAlphaSide::DistanceToSurface(const G4ThreeVector& gp,
679                                               G4ThreeVector  gxx[],
680                                               G4double       distance[],
681                                               G4int          areacode[])
682 {  
683    const G4double ctol = 0.5 * kCarTolerance;
684 
685    fCurStat.ResetfDone(kDontValidate, &gp);
686 
687    if (fCurStat.IsDone())
688    {
689       for (G4int i=0; i<fCurStat.GetNXX(); ++i)
690       {
691          gxx[i] = fCurStat.GetXX(i);
692          distance[i] = fCurStat.GetDistance(i);
693          areacode[i] = fCurStat.GetAreacode(i);
694       }
695       return fCurStat.GetNXX();
696    }
697    else  // initialize
698    {
699       for (G4int i=0; i<G4VSURFACENXX; ++i)
700       {
701          distance[i] = kInfinity;
702          areacode[i] = sOutside;
703          gxx[i].set(kInfinity, kInfinity, kInfinity);
704       }
705    }
706 
707    G4ThreeVector p = ComputeLocalPoint(gp);
708    G4ThreeVector xx;  // intersection point
709    G4ThreeVector xxonsurface ; // interpolated intersection point 
710 
711    // the surfacenormal at that surface point
712    //
713    G4double phiR = 0  ;
714    G4double uR = 0 ;
715 
716    G4ThreeVector surfacenormal ; 
717    G4double deltaX, uMax ;
718    G4double halfphi = 0.5*fPhiTwist ;
719    
720    for ( G4int i = 1 ; i<20 ; ++i )
721    {
722      xxonsurface = SurfacePoint(phiR,uR) ;
723      surfacenormal = NormAng(phiR,uR) ;
724      distance[0] = DistanceToPlane(p,xxonsurface,surfacenormal,xx); // new XX
725      deltaX = ( xx - xxonsurface ).mag() ; 
726 
727 #ifdef G4TWISTDEBUG
728      G4cout << "i = " << i << ", distance = " << distance[0]
729             << ", " << deltaX << G4endl
730             << "X = " << xx << G4endl ;
731 #endif
732 
733      // the new point xx is accepted and phi/psi replaced
734      //
735      GetPhiUAtX(xx, phiR, uR) ;
736      
737      if ( deltaX <= ctol ) { break ; }
738    }
739 
740    // check validity of solution ( valid phi,psi ) 
741 
742    uMax = GetBoundaryMax(phiR) ;
743 
744    if (  phiR > halfphi ) { phiR =  halfphi ; }
745    if ( phiR < -halfphi ) { phiR = -halfphi ; }
746    if ( uR > uMax )  { uR = uMax ;  }
747    if ( uR < -uMax ) { uR = -uMax ; }
748 
749    xxonsurface = SurfacePoint(phiR,uR) ;
750    distance[0] = (  p - xx ).mag() ;
751    if ( distance[0] <= ctol ) { distance[0] = 0 ; } 
752 
753    // end of validity 
754 
755 #ifdef G4TWISTDEBUG
756    G4cout << "refined solution "  << phiR << " , " << uR << " , " << G4endl ;
757    G4cout << "distance = " << distance[0] << G4endl ;
758    G4cout << "X = " << xx << G4endl ;
759 #endif
760 
761    G4bool isvalid = true;
762    gxx[0]      = ComputeGlobalPoint(xx);
763    
764 #ifdef G4TWISTDEBUG
765    G4cout << "intersection Point found: " << gxx[0] << G4endl ;
766    G4cout << "distance = " << distance[0] << G4endl ;
767 #endif
768 
769    fCurStat.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
770                             isvalid, 1, kDontValidate, &gp);
771    return 1;
772 }
773 
774 
775 //=====================================================================
776 //* GetAreaCode -------------------------------------------------------
777 
778 G4int
779 G4TwistTrapAlphaSide::GetAreaCode(const G4ThreeVector& xx, G4bool withTol)
780 {
781    // We must use the function in local coordinate system.
782    // See the description of DistanceToSurface(p,v).
783    
784    const G4double ctol = 0.5 * kCarTolerance;
785 
786    G4double phi ;
787    G4double yprime ;
788    GetPhiUAtX(xx, phi,yprime ) ;
789 
790    G4double fYAxisMax =  GetBoundaryMax(phi) ;
791    G4double fYAxisMin =  GetBoundaryMin(phi) ;
792 
793 #ifdef G4TWISTDEBUG
794    G4cout << "GetAreaCode: phi = " << phi << G4endl ;
795    G4cout << "GetAreaCode: yprime = " << yprime << G4endl ;
796    G4cout << "Intervall is " << fYAxisMin << " to " << fYAxisMax << G4endl ;
797 #endif
798 
799    G4int areacode = sInside;
800    
801    if (fAxis[0] == kYAxis && fAxis[1] == kZAxis)
802    {
803       G4int zaxis = 1;
804 
805       if (withTol)
806       {
807         G4bool isoutside   = false;
808         
809         // test boundary of yaxis
810 
811          if (yprime < fYAxisMin + ctol)
812          {
813             areacode |= (sAxis0 & (sAxisY | sAxisMin)) | sBoundary; 
814             if (yprime <= fYAxisMin - ctol)  { isoutside = true; }
815 
816          }
817          else if (yprime > fYAxisMax - ctol)
818          {
819             areacode |= (sAxis0 & (sAxisY | sAxisMax)) | sBoundary;
820             if (yprime >= fYAxisMax + ctol)  { isoutside = true; }
821          }
822 
823          // test boundary of z-axis
824 
825          if (xx.z() < fAxisMin[zaxis] + ctol)
826          {
827             areacode |= (sAxis1 & (sAxisZ | sAxisMin)); 
828 
829             if   ((areacode & sBoundary) != 0)   // xx is on the corner
830               { areacode |= sCorner; }
831 
832             else
833               { areacode |= sBoundary; }
834             if (xx.z() <= fAxisMin[zaxis] - ctol)  { isoutside = true; }
835          }
836          else if (xx.z() > fAxisMax[zaxis] - ctol)
837          {
838             areacode |= (sAxis1 & (sAxisZ | sAxisMax));
839 
840             if   ((areacode & sBoundary) != 0)   // xx is on the corner
841                { areacode |= sCorner; }
842             else
843                { areacode |= sBoundary; }
844             if (xx.z() >= fAxisMax[zaxis] + ctol)  { isoutside = true; }
845          }
846 
847          // if isoutside = true, clear inside bit.             
848          // if not on boundary, add axis information.             
849          
850          if (isoutside)
851          {
852             G4int tmpareacode = areacode & (~sInside);
853             areacode = tmpareacode;
854          }
855          else if ((areacode & sBoundary) != sBoundary)
856          {
857             areacode |= (sAxis0 & sAxisY) | (sAxis1 & sAxisZ);
858          }           
859          
860       }
861       else
862       {
863          // boundary of y-axis
864 
865          if (yprime < fYAxisMin )
866          {
867             areacode |= (sAxis0 & (sAxisY | sAxisMin)) | sBoundary;
868          }
869          else if (yprime > fYAxisMax)
870          {
871             areacode |= (sAxis0 & (sAxisY | sAxisMax)) | sBoundary;
872          }
873          
874          // boundary of z-axis
875 
876          if (xx.z() < fAxisMin[zaxis])
877          {
878             areacode |= (sAxis1 & (sAxisZ | sAxisMin));
879             if   ((areacode & sBoundary) != 0)   // xx is on the corner
880               { areacode |= sCorner; }
881             else
882               { areacode |= sBoundary; }
883          }
884          else if (xx.z() > fAxisMax[zaxis])
885          {
886             areacode |= (sAxis1 & (sAxisZ | sAxisMax)) ;
887             if   ((areacode & sBoundary) != 0)   // xx is on the corner
888               { areacode |= sCorner; }
889             else
890               { areacode |= sBoundary; }
891          }
892 
893          if ((areacode & sBoundary) != sBoundary)
894          {
895             areacode |= (sAxis0 & sAxisY) | (sAxis1 & sAxisZ);
896          }           
897       }
898       return areacode;
899    }
900    else
901    {
902       G4Exception("G4TwistTrapAlphaSide::GetAreaCode()",
903                   "GeomSolids0001", FatalException,
904                   "Feature NOT implemented !");
905    }
906    return areacode;
907 }
908 
909 //=====================================================================
910 //* SetCorners() ------------------------------------------------------
911 
912 void G4TwistTrapAlphaSide::SetCorners()
913 {
914 
915   // Set Corner points in local coodinate.   
916 
917   if (fAxis[0] == kYAxis && fAxis[1] == kZAxis)
918   {
919     
920     G4double x, y, z;
921 
922     // corner of Axis0min and Axis1min
923     //
924     x = -fdeltaX/2. + (fDx1 - fDy1*fTAlph)*std::cos(fPhiTwist/2.)
925       - fDy1*std::sin(fPhiTwist/2.);
926     y = -fdeltaY/2. - fDy1*std::cos(fPhiTwist/2.)
927       + (-fDx1 + fDy1*fTAlph)*std::sin(fPhiTwist/2.);
928     z = -fDz ;
929 
930     //    G4cout << "SetCorners: " << x << ", " << y << ", " << z << G4endl ;
931 
932     SetCorner(sC0Min1Min, x, y, z);
933       
934     // corner of Axis0max and Axis1min
935     //
936     x = -fdeltaX/2. + (fDx2 + fDy1*fTAlph)*std::cos(fPhiTwist/2.)
937       + fDy1*std::sin(fPhiTwist/2.);
938     y = -fdeltaY/2. + fDy1*std::cos(fPhiTwist/2.)
939       - (fDx2 + fDy1*fTAlph)*std::sin(fPhiTwist/2.);
940     z = -fDz ;
941 
942     //    G4cout << "SetCorners: " << x << ", " << y << ", " << z << G4endl ;
943 
944     SetCorner(sC0Max1Min, x, y, z);
945       
946     // corner of Axis0max and Axis1max
947     //
948     x = fdeltaX/2. + (fDx4 + fDy2*fTAlph)*std::cos(fPhiTwist/2.)
949       - fDy2*std::sin(fPhiTwist/2.);
950     y = fdeltaY/2. + fDy2*std::cos(fPhiTwist/2.)
951       + (fDx4 + fDy2*fTAlph)*std::sin(fPhiTwist/2.);
952     z = fDz ;
953     
954     //    G4cout << "SetCorners: " << x << ", " << y << ", " << z << G4endl ;
955     
956     SetCorner(sC0Max1Max, x, y, z);
957 
958     // corner of Axis0min and Axis1max
959     x = fdeltaX/2. + (fDx3 - fDy2*fTAlph)*std::cos(fPhiTwist/2.)
960       + fDy2*std::sin(fPhiTwist/2.) ;
961     y = fdeltaY/2. - fDy2*std::cos(fPhiTwist/2.)
962       + (fDx3 - fDy2*fTAlph)*std::sin(fPhiTwist/2.) ;
963     z = fDz ;
964 
965     //    G4cout << "SetCorners: " << x << ", " << y << ", " << z << G4endl ;
966 
967     SetCorner(sC0Min1Max, x, y, z);
968 
969   }
970   else
971   {
972     G4Exception("G4TwistTrapAlphaSide::SetCorners()",
973                 "GeomSolids0001", FatalException,
974                 "Method NOT implemented !");
975   }
976 }
977 
978 //=====================================================================
979 //* SetBoundaries() ---------------------------------------------------
980 
981 void G4TwistTrapAlphaSide::SetBoundaries()
982 {
983    // Set direction-unit vector of boundary-lines in local coodinate. 
984    //   
985 
986   G4ThreeVector direction;
987    
988   if (fAxis[0] == kYAxis && fAxis[1] == kZAxis)
989   {     
990     // sAxis0 & sAxisMin
991     direction = GetCorner(sC0Min1Max) - GetCorner(sC0Min1Min);
992     direction = direction.unit();
993     SetBoundary(sAxis0 & (sAxisY | sAxisMin), direction, 
994                 GetCorner(sC0Min1Min), sAxisZ) ;
995       
996       // sAxis0 & sAxisMax
997     direction = GetCorner(sC0Max1Max) - GetCorner(sC0Max1Min);
998     direction = direction.unit();
999     SetBoundary(sAxis0 & (sAxisY | sAxisMax), direction, 
1000                 GetCorner(sC0Max1Min), sAxisZ);
1001     
1002     // sAxis1 & sAxisMin
1003     direction = GetCorner(sC0Max1Min) - GetCorner(sC0Min1Min);
1004     direction = direction.unit();
1005     SetBoundary(sAxis1 & (sAxisZ | sAxisMin), direction, 
1006                 GetCorner(sC0Min1Min), sAxisY);
1007     
1008     // sAxis1 & sAxisMax
1009     direction = GetCorner(sC0Max1Max) - GetCorner(sC0Min1Max);
1010     direction = direction.unit();
1011     SetBoundary(sAxis1 & (sAxisZ | sAxisMax), direction, 
1012                 GetCorner(sC0Min1Max), sAxisY);
1013     
1014   }
1015   else
1016   {
1017     G4Exception("G4TwistTrapAlphaSide::SetCorners()",
1018                 "GeomSolids0001", FatalException,
1019                 "Feature NOT implemented !");
1020   }
1021 }
1022 
1023 //=====================================================================
1024 //* GetPhiUAtX --------------------------------------------------------
1025 
1026 void
1027 G4TwistTrapAlphaSide::GetPhiUAtX( const G4ThreeVector& p, G4double& phi, G4double& u ) 
1028 {
1029   // find closest point XX on surface for a given point p
1030   // X0 is a point on the surface,  d is the direction
1031   // ( both for a fixed z = pz)
1032   
1033   // phi is given by the z coordinate of p
1034 
1035   phi =  p.z()/(2*fDz)*fPhiTwist ;
1036   u = (fPhiTwist*(2*fDx1*fDx1 - 2*fDx2*fDx2 - fa1md1*(fDx3 + fDx4)
1037              - 4*(fDx3plus1 + fDx4plus2)*fDy1*fTAlph)
1038              - 2*(2*fDx1*fDx1 - 2*fDx2*fDx2 + fa1md1*(fDx3 + fDx4)
1039                 + 4*(fDx3minus1 + fDx4minus2)*fDy1*fTAlph)*phi
1040              - 4*(fa1md1*(fdeltaX*phi - fPhiTwist*p.x())
1041              + 4*fDy1*(fdeltaY*phi + fdeltaX*fTAlph*phi
1042                      - fPhiTwist*(fTAlph*p.x() + p.y())))*std::cos(phi)
1043              - 4*(fa1md1*fdeltaY*phi - 4*fdeltaX*fDy1*phi
1044                 + 4*fdeltaY*fDy1*fTAlph*phi + 4*fDy1*fPhiTwist*p.x()
1045                 - fPhiTwist*(fa1md1 + 4*fDy1*fTAlph)*p.y())*std::sin(phi))
1046        /(fDy1* fPhiTwist*((std::fabs(((fa1md1 + 4*fDy1*fTAlph)*std::cos(phi))
1047                           /fDy1 - 4*std::sin(phi)))
1048                         *(std::fabs(((fa1md1 + 4*fDy1*fTAlph)*std::cos(phi))
1049                           /fDy1 - 4*std::sin(phi)))
1050              + (std::fabs(4*std::cos(phi)
1051                 + ((fa1md1 + 4*fDy1*fTAlph)*std::sin(phi))/fDy1))
1052              * (std::fabs(4*std::cos(phi)
1053                 + ((fa1md1 + 4*fDy1*fTAlph)*std::sin(phi))/fDy1)))) ;
1054 }
1055 
1056 //=====================================================================
1057 //* ProjectPoint ------------------------------------------------------
1058 
1059 G4ThreeVector
1060 G4TwistTrapAlphaSide::ProjectPoint(const G4ThreeVector& p, G4bool isglobal) 
1061 {
1062   // Get Rho at p.z() on Hyperbolic Surface.
1063 
1064   G4ThreeVector tmpp;
1065   if (isglobal)
1066   {
1067      tmpp = fRot.inverse()*p - fTrans;
1068   }
1069   else
1070   {
1071      tmpp = p;
1072   }
1073 
1074   G4double phi ;
1075   G4double u ;
1076 
1077   GetPhiUAtX( tmpp, phi, u ) ;
1078     // calculate (phi, u) for a point p close the surface
1079   
1080   G4ThreeVector xx = SurfacePoint(phi,u) ;
1081     // transform back to cartesian coordinates
1082 
1083   if (isglobal)
1084   {
1085      return (fRot * xx + fTrans);
1086   }
1087   else
1088   {
1089      return xx;
1090   }
1091 }
1092 
1093 //=====================================================================
1094 //* GetFacets ---------------------------------------------------------
1095 
1096 void
1097 G4TwistTrapAlphaSide::GetFacets( G4int k, G4int n, G4double xyz[][3],
1098                                  G4int faces[][4], G4int iside ) 
1099 {
1100 
1101   G4double phi ;
1102   G4double b ;   
1103 
1104   G4double z, u ;     // the two parameters for the surface equation
1105   G4ThreeVector p ;  // a point on the surface, given by (z,u)
1106 
1107   G4int nnode ;
1108   G4int nface ;
1109 
1110   // calculate the (n-1)*(k-1) vertices
1111 
1112   for ( G4int i = 0 ; i<n ; ++i )
1113   {
1114     z = -fDz+i*(2.*fDz)/(n-1) ;
1115     phi = z*fPhiTwist/(2*fDz) ;
1116     b = GetValueB(phi) ;
1117 
1118     for ( G4int j = 0 ; j<k ; ++j )
1119     {
1120       nnode = GetNode(i,j,k,n,iside) ;
1121       u = -b/2 +j*b/(k-1) ;
1122       p = SurfacePoint(phi,u,true) ;  // surface point in global coordinates
1123 
1124       xyz[nnode][0] = p.x() ;
1125       xyz[nnode][1] = p.y() ;
1126       xyz[nnode][2] = p.z() ;
1127 
1128       if ( i<n-1 && j<k-1 )  // conterclock wise filling 
1129       {
1130         nface = GetFace(i,j,k,n,iside) ;
1131         faces[nface][0] = GetEdgeVisibility(i,j,k,n,0,-1)
1132                         * (GetNode(i  ,j  ,k,n,iside)+1) ;  // f77 numbering
1133         faces[nface][1] = GetEdgeVisibility(i,j,k,n,1,-1)
1134                         * (GetNode(i  ,j+1,k,n,iside)+1) ;
1135         faces[nface][2] = GetEdgeVisibility(i,j,k,n,2,-1)
1136                         * (GetNode(i+1,j+1,k,n,iside)+1) ;
1137         faces[nface][3] = GetEdgeVisibility(i,j,k,n,3,-1)
1138                         * (GetNode(i+1,j  ,k,n,iside)+1) ;
1139       }
1140     }
1141   }
1142 }
1143