Problem 1052

Summary: Infinite loop in G4SubtractionSolid::DistanceToIn()
Product: Geant4 Reporter: Svetlana Biktemerova <biktem>
Component: geometry/solidsAssignee: Vladimir.Grichine
Status: RESOLVED INVALID    
Severity: minor CC: mario.alemi, tatiana.nikitina
Priority: P5    
Version: 9.2   
Hardware: All   
OS: All   

Description Svetlana Biktemerova 2009-03-10 10:27:13 CET
from http://hypernews.slac.stanford.edu/HyperNews/geant4/get/geometry/956.html

The next code leads Geant4 to the infinite loop. 

//___________________________________________________________________________________________________________________________
void test(){
     const char* nms[]={"kOutside","kSurface","kInside"};

     double t_dz=0.3392505000;
     double t_rad=85.94;
     double p_rmz=85.9400000000;
     double p_rpz=99.2300000000;
     double p_hz=0.3392505000;

     G4Paraboloid* par = new G4Paraboloid("par",p_hz,p_rmz,p_rpz);
     G4DisplacedSolid* pard=new G4DisplacedSolid("disp_par",par,new G4RotationMatrix(0.,180.*deg,0.),G4ThreeVector(0.,0.,0.));
     G4Tubs* t=new G4Tubs("absorber",0.,t_rad,t_dz,0.*deg,360.*deg);
     G4SubtractionSolid* seg1 = new G4SubtractionSolid("par1_i",pard,t,0,0);

     G4ThreeVector v(-82.1262056167, 40.0738142048, 0.0732052691);
     G4ThreeVector dir(-0.00013143732014871606, 0.00006413537198823375,-0.99999998930544242715);
     dir=dir.unit();

     printf("%20.10f %20s %20.10f\n",v.x(),nms[t->Inside(v)],t->DistanceToOut(v,dir));
     printf("%20.10f %20s %20.10f\n",v.x(),nms[pard->Inside(v)],pard->DistanceToIn(v,dir));

     G4ThreeVector v0(-81.97424905536260553163, 39.99966638606156266178, 1156.18746249999981046130);
     printf("infinite_loop...\n");
     seg1->DistanceToIn(v0,dir);
     printf("finished...\n");
}
//___________________________________________________________________________________________________________________________

The reason is printed to the output: both constituents solid say that point "v" is outside, and both of them return 0.0 as distance to in/out. 

G4SubtractionSolid::DistanceToIn() uses the "while" loop:
//___________________________________________________________________________________________________________________________
while( Inside(p+dist*v) == kOutside )  // pushing loop
{
  disTmp = fPtrSolidB->DistanceToOut(p+dist*v,v) ;
  dist += disTmp ;

  if( Inside(p+dist*v) == kOutside ){ 
    disTmp = fPtrSolidA->DistanceToIn(p+dist*v,v) ;
    if(disTmp == kInfinity){return kInfinity;}                 
    dist += disTmp ;
  }
}
//___________________________________________________________________________________________________________________________

as "disTmp" is always 0., this loop is infinite. I suggest to add a simple check: if both "disTmp" are zeroes, move them manually by a small number, like 1.e-9. 

It also seems that other G4BooleanSolids are also "dangerous", but I do not have exact examples for them. 

best regards, Svetlana Biktemerova
Comment 1 tatiana.nikitina 2009-08-04 15:20:19 CEST
Dear Svetlana,

 The infinite loop is caused by the wrong way of using boolean operations.
 In your case two solids have touching surfaces, when you subtract such solids, you will have a inconsistency. To avoid this kind of problem, you can make one solid smaller by a small value(normally 1.e-6 mm), then you will not have a problem with touching surfaces.   

 Best Regards,
 Tatiana Nikitina
Comment 2 Svetlana Biktemerova 2009-09-18 11:16:46 CEST
Dear Tatiana,

I'm sorry for inconvenience  and thank you.

But, am I right that this problem is still can be valid for the 
"intersection part" of volumes which are in G4SubtractionSolid, although 
the infinity loop will be caused much rarely?
Comment 3 tatiana.nikitina 2009-09-18 14:10:47 CEST
Dear Svetlana,

 If a boolean operation is defined correctly and your application still enter in the Infinite Loop, that means the wrong replay of one of the solids used for the boolean operation. This is an error of the solid and not of the boolean operation.
 
 Best Regards,
 Tatiana Nikitina