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