// // ******************************************************************** // * License and Disclaimer * // * * // * The Geant4 software is copyright of the Copyright Holders of * // * the Geant4 Collaboration. It is provided under the terms and * // * conditions of the Geant4 Software License, included in the file * // * LICENSE and available at http://cern.ch/geant4/license . These * // * include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GEANT4 collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the Geant4 Software license. * // ******************************************************************** // // $Id: G4SimpleLocator.cc,v 1.6 2010/07/13 15:59:42 gcosmo Exp $ // GEANT4 tag $Name: geant4-09-04-ref-00 $ // // Class G4SimpleLocator implementation // // 27.10.08 - Tatiana Nikitina. // --------------------------------------------------------------------------- #include #include "G4ios.hh" #include "G4SimpleLocator.hh" G4SimpleLocator::G4SimpleLocator(G4Navigator *theNavigator) : G4VIntersectionLocator(theNavigator) { } G4SimpleLocator::~G4SimpleLocator() { } // -------------------------------------------------------------------------- // G4bool G4PropagatorInField::LocateIntersectionPoint( // const G4FieldTrack& CurveStartPointVelocity, // A // const G4FieldTrack& CurveEndPointVelocity, // B // const G4ThreeVector& TrialPoint, // E // G4FieldTrack& IntersectedOrRecalculated // Output // G4bool& recalculated ) // Out // -------------------------------------------------------------------------- // // Function that returns the intersection of the true path with the surface // of the current volume (either the external one or the inner one with one // of the daughters: // // A = Initial point // B = another point // // Both A and B are assumed to be on the true path: // // E is the first point of intersection of the chord AB with // a volume other than A (on the surface of A or of a daughter) // // Convention of Use : // i) If it returns "true", then IntersectionPointVelocity is set // to the approximate intersection point. // ii) If it returns "false", no intersection was found. // The validity of IntersectedOrRecalculated depends on 'recalculated' // a) if latter is false, then IntersectedOrRecalculated is invalid. // b) if latter is true, then IntersectedOrRecalculated is // the new endpoint, due to a re-integration. // -------------------------------------------------------------------------- // NOTE: implementation taken from G4PropagatorInField // G4bool G4SimpleLocator::EstimateIntersectionPoint( const G4FieldTrack& CurveStartPointVelocity, // A const G4FieldTrack& CurveEndPointVelocity, // B const G4ThreeVector& TrialPoint, // E G4FieldTrack& IntersectedOrRecalculatedFT, // Output G4bool& recalculatedEndPoint, // Out G4double &fPreviousSafety, //In/Out G4ThreeVector &fPreviousSftOrigin) //In/Out { // Find Intersection Point ( A, B, E ) of true path AB - start at E. G4bool found_approximate_intersection = false; G4bool there_is_no_intersection = false; G4FieldTrack CurrentA_PointVelocity = CurveStartPointVelocity; G4FieldTrack CurrentB_PointVelocity = CurveEndPointVelocity; G4ThreeVector CurrentE_Point = TrialPoint; G4FieldTrack ApproxIntersecPointV(CurveEndPointVelocity); // FT-Def-Construct G4double NewSafety = 0.0; G4bool last_AF_intersection = false; G4bool final_section = true; // Shows whether current section is last // (i.e. B=full end) recalculatedEndPoint = false; G4bool restoredFullEndpoint = false; G4int substep_no = 0; G4int oldprc; // cout/cerr precision settings // Limits for substep number // const G4int max_substeps = 100000000; // Test 120 (old value 100 ) const G4int warn_substeps = 1000; // 100 // Statistics for substeps // static G4int max_no_seen= -1; static G4int trigger_substepno_print= warn_substeps - 20; #ifdef G4DEBUG_FIELD static G4double tolerance= 1.0e-8; G4ThreeVector StartPosition= CurveStartPointVelocity.GetPosition(); if( (TrialPoint - StartPosition).mag() < tolerance * mm ) { G4cerr << "WARNING - G4SimpleLocator::EstimateIntersectionPoint()" << G4endl << " Intermediate F point is on top of starting point A." << G4endl; G4Exception("G4SimpleLocator::EstimateIntersectionPoint()", "IntersectionPointIsAtStart", JustWarning, "Intersection point F is exactly at start point A." ); } #endif do { G4ThreeVector Point_A = CurrentA_PointVelocity.GetPosition(); G4ThreeVector Point_B = CurrentB_PointVelocity.GetPosition(); // F = a point on true AB path close to point E // (the closest if possible) // ApproxIntersecPointV = GetChordFinderFor() ->ApproxCurvePointV( CurrentA_PointVelocity, CurrentB_PointVelocity, CurrentE_Point, GetEpsilonStepFor()); // The above method is the key & most intuitive part ... #ifdef G4DEBUG_FIELD if( ApproxIntersecPointV.GetCurveLength() > CurrentB_PointVelocity.GetCurveLength() * (1.0 + tolerance) ) { G4cerr << "ERROR - G4SimpleLocator::EstimateIntersectionPoint()" << G4endl << " Intermediate F point is more advanced than" << " endpoint B." << G4endl; G4Exception("G4SimpleLocator::EstimateIntersectionPoint()", "IntermediatePointConfusion", FatalException, "Intermediate F point is past end B point" ); } #endif G4ThreeVector CurrentF_Point= ApproxIntersecPointV.GetPosition(); // First check whether EF is small - then F is a good approx. point // Calculate the length and direction of the chord AF // G4ThreeVector ChordEF_Vector = CurrentF_Point - CurrentE_Point; if ( ChordEF_Vector.mag2() <= sqr(GetDeltaIntersectionFor()) ) { found_approximate_intersection = true; // Create the "point" return value // IntersectedOrRecalculatedFT = ApproxIntersecPointV; IntersectedOrRecalculatedFT.SetPosition( CurrentE_Point ); if ( GetAdjustementOfFoundIntersection() ) { // Try to Get Correction of IntersectionPoint using SurfaceNormal() // G4ThreeVector IP; G4ThreeVector MomentumDir= ApproxIntersecPointV.GetMomentumDirection(); G4bool goodCorrection = AdjustmentOfFoundIntersection( Point_A, CurrentE_Point, CurrentF_Point, MomentumDir, last_AF_intersection, IP, NewSafety, fPreviousSafety, fPreviousSftOrigin ); if(goodCorrection) { IntersectedOrRecalculatedFT = ApproxIntersecPointV; IntersectedOrRecalculatedFT.SetPosition(IP); } } // Note: in order to return a point on the boundary, // we must return E. But it is F on the curve. // So we must "cheat": we are using the position at point E // and the velocity at point F !!! // // This must limit the length we can allow for displacement! } else // E is NOT close enough to the curve (ie point F) { // Check whether any volumes are encountered by the chord AF // --------------------------------------------------------- // First relocate to restore any Voxel etc information // in the Navigator before calling ComputeStep() // GetNavigatorFor()->LocateGlobalPointWithinVolume( Point_A ); G4ThreeVector PointG; // Candidate intersection point G4double stepLengthAF; G4bool Intersects_AF = IntersectChord( Point_A, CurrentF_Point, NewSafety,fPreviousSafety, fPreviousSftOrigin, stepLengthAF, PointG ); last_AF_intersection = Intersects_AF; if( Intersects_AF ) { // G is our new Candidate for the intersection point. // It replaces "E" and we will repeat the test to see if // it is a good enough approximate point for us. // B <- F // E <- G CurrentB_PointVelocity = ApproxIntersecPointV; CurrentE_Point = PointG; // By moving point B, must take care if current // AF has no intersection to try current FB!! // final_section= false; #ifdef G4VERBOSE if( fVerboseLevel > 3 ) { G4cout << "G4PiF::LI> Investigating intermediate point" << " at s=" << ApproxIntersecPointV.GetCurveLength() << " on way to full s=" << CurveEndPointVelocity.GetCurveLength() << G4endl; } #endif } else // not Intersects_AF { // In this case: // There is NO intersection of AF with a volume boundary. // We must continue the search in the segment FB! // GetNavigatorFor()->LocateGlobalPointWithinVolume( CurrentF_Point ); G4double stepLengthFB; G4ThreeVector PointH; // Check whether any volumes are encountered by the chord FB // --------------------------------------------------------- G4bool Intersects_FB = IntersectChord( CurrentF_Point, Point_B, NewSafety,fPreviousSafety, fPreviousSftOrigin, stepLengthFB, PointH ); if( Intersects_FB ) { // There is an intersection of FB with a volume boundary // H <- First Intersection of Chord FB // H is our new Candidate for the intersection point. // It replaces "E" and we will repeat the test to see if // it is a good enough approximate point for us. // Note that F must be in volume volA (the same as A) // (otherwise AF would meet a volume boundary!) // A <- F // E <- H // CurrentA_PointVelocity = ApproxIntersecPointV; CurrentE_Point = PointH; } else // not Intersects_FB { // There is NO intersection of FB with a volume boundary if( final_section ) { // If B is the original endpoint, this means that whatever // volume(s) intersected the original chord, none touch the // smaller chords we have used. // The value of 'IntersectedOrRecalculatedFT' returned is // likely not valid there_is_no_intersection = true; // real final_section } else { // We must restore the original endpoint CurrentA_PointVelocity = CurrentB_PointVelocity; // Got to B CurrentB_PointVelocity = CurveEndPointVelocity; restoredFullEndpoint = true; } } // Endif (Intersects_FB) } // Endif (Intersects_AF) // Ensure that the new endpoints are not further apart in space // than on the curve due to different errors in the integration // G4double linDistSq, curveDist; linDistSq = ( CurrentB_PointVelocity.GetPosition() - CurrentA_PointVelocity.GetPosition() ).mag2(); curveDist = CurrentB_PointVelocity.GetCurveLength() - CurrentA_PointVelocity.GetCurveLength(); // Change this condition for very strict parameters of propagation // if( curveDist*curveDist*(1+2* GetEpsilonStepFor()) < linDistSq ) { // Re-integrate to obtain a new B // G4FieldTrack newEndPointFT = ReEstimateEndpoint( CurrentA_PointVelocity, CurrentB_PointVelocity, linDistSq, // to avoid recalculation curveDist ); G4FieldTrack oldPointVelB = CurrentB_PointVelocity; CurrentB_PointVelocity = newEndPointFT; if( (final_section)) // real final section { recalculatedEndPoint = true; IntersectedOrRecalculatedFT = newEndPointFT; // So that we can return it, if it is the endpoint! } } if( curveDist < 0.0 ) { G4cerr << "ERROR - G4SimpleLocator::EstimateIntersectionPoint()" << G4endl << " Error in advancing propagation." << G4endl; fVerboseLevel = 5; // Print out a maximum of information printStatus( CurrentA_PointVelocity, CurrentB_PointVelocity, -1.0, NewSafety, substep_no ); G4cerr << " Point A (start) is " << CurrentA_PointVelocity << G4endl; G4cerr << " Point B (end) is " << CurrentB_PointVelocity << G4endl; G4cerr << " Curve distance is " << curveDist << G4endl; G4cerr << G4endl << "The final curve point is not further along" << " than the original!" << G4endl; if( recalculatedEndPoint ) { G4cerr << "Recalculation of EndPoint was called with fEpsStep= " << GetEpsilonStepFor() << G4endl; } oldprc = G4cerr.precision(20); G4cerr << " Point A (Curve start) is " << CurveStartPointVelocity << G4endl; G4cerr << " Point B (Curve end) is " << CurveEndPointVelocity << G4endl; G4cerr << " Point A (Current start) is " << CurrentA_PointVelocity << G4endl; G4cerr << " Point B (Current end) is " << CurrentB_PointVelocity << G4endl; G4cerr << " Point E (Trial Point) is " << CurrentE_Point << G4endl; G4cerr << " Point F (Intersection) is " << ApproxIntersecPointV << G4endl; G4cerr << " LocateIntersection parameters are : Substep no= " << substep_no << G4endl; G4cerr.precision(oldprc); G4Exception("G4SimpleLocator::EstimateIntersectionPoint()", "FatalError", FatalException, "Error in advancing propagation."); } if(restoredFullEndpoint) { final_section = restoredFullEndpoint; restoredFullEndpoint = false; } } // EndIf ( E is close enough to the curve, ie point F. ) // tests ChordAF_Vector.mag() <= maximum_lateral_displacement #ifdef G4DEBUG_LOCATE_INTERSECTION if( substep_no >= trigger_substepno_print ) { G4cout << "Difficulty in converging in " << "G4SimpleLocator::EstimateIntersectionPoint():" << G4endl << " Substep no = " << substep_no << G4endl; if( substep_no == trigger_substepno_print ) { printStatus( CurveStartPointVelocity, CurveEndPointVelocity, -1.0, NewSafety, 0); } G4cout << " State of point A: "; printStatus( CurrentA_PointVelocity, CurrentA_PointVelocity, -1.0, NewSafety, substep_no-1, 0); G4cout << " State of point B: "; printStatus( CurrentA_PointVelocity, CurrentB_PointVelocity, -1.0, NewSafety, substep_no); } #endif substep_no++; } while ( ( ! found_approximate_intersection ) && ( ! there_is_no_intersection ) && ( substep_no <= max_substeps) ); // UNTIL found or failed if( substep_no > max_no_seen ) { max_no_seen = substep_no; if( max_no_seen > warn_substeps ) { trigger_substepno_print = max_no_seen-20; // Want to see last 20 steps } } if( ( substep_no >= max_substeps) && !there_is_no_intersection && !found_approximate_intersection ) { G4cerr << "WARNING - G4SimpleLocator::EstimateIntersectionPoint()" << G4endl << " Convergence is requiring too many substeps: " << substep_no << G4endl; G4cerr << " Abandoning effort to intersect. " << G4endl; G4cerr << " Information on start & current step follows in cout." << G4endl; G4cout << "WARNING - G4SimpleLocator::EstimateIntersectionPoint()" << G4endl << " Convergence is requiring too many substeps: " << substep_no << G4endl; G4cout << " Found intersection = " << found_approximate_intersection << G4endl << " Intersection exists = " << !there_is_no_intersection << G4endl; G4cout << " Start and Endpoint of Requested Step:" << G4endl; printStatus( CurveStartPointVelocity, CurveEndPointVelocity, -1.0, NewSafety, 0); G4cout << G4endl; G4cout << " 'Bracketing' starting and endpoint of current Sub-Step" << G4endl; printStatus( CurrentA_PointVelocity, CurrentA_PointVelocity, -1.0, NewSafety, substep_no-1); printStatus( CurrentA_PointVelocity, CurrentB_PointVelocity, -1.0, NewSafety, substep_no); G4cout << G4endl; oldprc = G4cout.precision(10); G4double done_len = CurrentA_PointVelocity.GetCurveLength(); G4double full_len = CurveEndPointVelocity.GetCurveLength(); G4cout << "ERROR - G4SimpleLocator::EstimateIntersectionPoint()" << G4endl << " Undertaken only length: " << done_len << " out of " << full_len << " required." << G4endl; G4cout << " Remaining length = " << full_len - done_len << G4endl; G4cout.precision(oldprc); G4Exception("G4SimpleLocator::EstimateIntersectionPoint()", "UnableToLocateIntersection", FatalException, "Too many substeps while trying to locate intersection."); } else if( substep_no >= warn_substeps ) { oldprc= G4cout.precision(10); G4cout << "WARNING - G4SimpleLocator::EstimateIntersectionPoint()" << G4endl << " Undertaken length: " << CurrentB_PointVelocity.GetCurveLength(); G4cout << " - Needed: " << substep_no << " substeps." << G4endl << " Warning level = " << warn_substeps << " and maximum substeps = " << max_substeps << G4endl; G4cout.precision(oldprc); G4Exception("G4SimpleLocator::EstimateIntersectionPoint()", "DifficultyToLocateIntersection", JustWarning, "Many substeps while trying to locate intersection."); } return !there_is_no_intersection; // Success or failure }