source: trunk/source/geometry/navigation/src/G4PropagatorInField.cc @ 836

Last change on this file since 836 was 831, checked in by garnier, 16 years ago

import all except CVS

File size: 53.4 KB
Line 
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//
27// $Id: G4PropagatorInField.cc,v 1.42 2008/01/24 08:54:01 gcosmo Exp $
28// GEANT4 tag $Name:  $
29//
30//
31//  This class implements an algorithm to track a particle in a
32//  non-uniform magnetic field. It utilises an ODE solver (with
33//  the Runge - Kutta method) to evolve the particle, and drives it
34//  until the particle has traveled a set distance or it enters a new
35//  volume.
36//                                                                     
37// 14.10.96 John Apostolakis,   design and implementation
38// 17.03.97 John Apostolakis,   renaming new set functions being added
39//
40// ---------------------------------------------------------------------------
41
42#include "G4PropagatorInField.hh"
43#include "G4ios.hh"
44#include <iomanip>
45
46#include "G4ThreeVector.hh"
47#include "G4VPhysicalVolume.hh"
48#include "G4Navigator.hh"
49#include "G4GeometryTolerance.hh"
50#include "G4VCurvedTrajectoryFilter.hh"
51#include "G4ChordFinder.hh"
52
53///////////////////////////////////////////////////////////////////////////
54//
55// Constructors and destructor
56
57G4PropagatorInField::G4PropagatorInField( G4Navigator    *theNavigator, 
58                                          G4FieldManager *detectorFieldMgr )
59  : fDetectorFieldMgr(detectorFieldMgr), 
60    fCurrentFieldMgr(detectorFieldMgr), 
61    fNavigator(theNavigator),
62    End_PointAndTangent(G4ThreeVector(0.,0.,0.),
63                        G4ThreeVector(0.,0.,0.),0.0,0.0,0.0,0.0,0.0),
64    fParticleIsLooping(false),
65    fVerboseLevel(0),
66    fMax_loop_count(1000),
67    fNoZeroStep(0), 
68    fCharge(0.0), fInitialMomentumModulus(0.0), fMass(0.0),
69    fUseSafetyForOptimisation(true),   // (false) is less sensitive to incorrect safety
70    fSetFieldMgr(false),
71    fpTrajectoryFilter( 0 )
72{
73  if(fDetectorFieldMgr) { fEpsilonStep = fDetectorFieldMgr->GetMaximumEpsilonStep();}
74  else                  { fEpsilonStep= 1.0e-5; } 
75  fActionThreshold_NoZeroSteps = 2; 
76  fSevereActionThreshold_NoZeroSteps = 10; 
77  fAbandonThreshold_NoZeroSteps = 50; 
78  fFull_CurveLen_of_LastAttempt = -1; 
79  fLast_ProposedStepLength = -1;
80  fLargestAcceptableStep = 1000.0 * meter;
81
82  fPreviousSftOrigin= G4ThreeVector(0.,0.,0.);
83  fPreviousSafety= 0.0;
84  kCarTolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
85
86  // In case of too slow progress in finding Intersection Point
87  // intermediates Points on the Track must be stored.
88  // Initialise the array of Pointers [max_depth+1] to do this 
89 
90  G4ThreeVector zeroV(0.0,0.0,0.0);
91  for (G4int idepth=0; idepth<max_depth+1; idepth++ )
92  {
93    ptrInterMedFT[ idepth ] = new G4FieldTrack( zeroV, zeroV, 0., 0., 0., 0.);
94  }
95}
96
97G4PropagatorInField::~G4PropagatorInField()
98{
99  for ( G4int idepth=0; idepth<max_depth+1; idepth++)
100  {
101    delete ptrInterMedFT[idepth];
102  }
103}
104
105///////////////////////////////////////////////////////////////////////////
106//
107// Compute the next geometric Step
108
109G4double
110G4PropagatorInField::ComputeStep(
111                G4FieldTrack&      pFieldTrack,
112                G4double           CurrentProposedStepLength,
113                G4double&          currentSafety,                // IN/OUT
114                G4VPhysicalVolume* pPhysVol)
115{
116  // If CurrentProposedStepLength is too small for finding Chords
117  // then return with no action (for now - TODO: some action)
118  //
119  if(CurrentProposedStepLength<kCarTolerance)
120  {
121    return kInfinity;
122  }
123
124  // Introducing smooth trajectory display (jacek 01/11/2002)
125  //
126  if (fpTrajectoryFilter)
127  {
128    fpTrajectoryFilter->CreateNewTrajectorySegment();
129  }
130
131  // Parameters for adaptive Runge-Kutta integration
132 
133  G4double      h_TrialStepSize;        // 1st Step Size
134  G4double      TruePathLength = CurrentProposedStepLength;
135  G4double      StepTaken = 0.0; 
136  G4double      s_length_taken, epsilon ; 
137  G4bool        intersects;
138  G4bool        first_substep = true;
139
140  G4double      NewSafety;
141  fParticleIsLooping = false;
142
143  // If not yet done,
144  //   Set the field manager to the local  one if the volume has one,
145  //                      or to the global one if not
146  //
147  if( !fSetFieldMgr ) fCurrentFieldMgr= FindAndSetFieldManager( pPhysVol ); 
148  // For the next call, the field manager must again be set
149  fSetFieldMgr= false;
150
151  GetChordFinder()->SetChargeMomentumMass(fCharge, fInitialMomentumModulus, fMass); 
152
153  G4FieldTrack  CurrentState(pFieldTrack);
154  G4FieldTrack  OriginalState = CurrentState;
155
156  // If the Step length is "infinite", then an approximate-maximum Step
157  // length (used to calculate the relative accuracy) must be guessed.
158  //
159  if( CurrentProposedStepLength >= fLargestAcceptableStep )
160  {
161    G4ThreeVector StartPointA, VelocityUnit;
162    StartPointA  = pFieldTrack.GetPosition();
163    VelocityUnit = pFieldTrack.GetMomentumDir();
164
165    G4double trialProposedStep = 1.e2 * ( 10.0 * cm + 
166      fNavigator->GetWorldVolume()->GetLogicalVolume()->
167                  GetSolid()->DistanceToOut(StartPointA, VelocityUnit) );
168    CurrentProposedStepLength= std::min( trialProposedStep,
169                                           fLargestAcceptableStep ); 
170  }
171  epsilon = GetDeltaOneStep() / CurrentProposedStepLength;
172  // G4double raw_epsilon= epsilon;
173  G4double epsilonMin= fCurrentFieldMgr->GetMinimumEpsilonStep();
174  G4double epsilonMax= fCurrentFieldMgr->GetMaximumEpsilonStep();; 
175  if( epsilon < epsilonMin ) epsilon = epsilonMin;
176  if( epsilon > epsilonMax ) epsilon = epsilonMax;
177  SetEpsilonStep( epsilon );
178
179  // G4cout << "G4PiF: Epsilon of current step - raw= " << raw_epsilon
180  //        << " final= " << epsilon << G4endl;
181
182  //  Shorten the proposed step in case of earlier problems (zero steps)
183  //
184  if( fNoZeroStep > fActionThreshold_NoZeroSteps )
185  {
186    G4double stepTrial;
187
188    stepTrial= fFull_CurveLen_of_LastAttempt; 
189    if( (stepTrial <= 0.0) && (fLast_ProposedStepLength > 0.0) ) 
190      stepTrial= fLast_ProposedStepLength; 
191
192    G4double decreaseFactor = 0.9; // Unused default
193    if(   (fNoZeroStep < fSevereActionThreshold_NoZeroSteps)
194       && (stepTrial > 1000.0*kCarTolerance) )
195    {
196      // Ensure quicker convergence
197      //
198      decreaseFactor= 0.1;
199    } 
200    else
201    {
202      // We are in significant difficulties, probably at a boundary that
203      // is either geometrically sharp or between very different materials.
204      // Careful decreases to cope with tolerance are required.
205      //
206      if( stepTrial > 1000.0*kCarTolerance )
207        decreaseFactor = 0.25;     // Try slow decreases
208      else if( stepTrial > 100.0*kCarTolerance )
209        decreaseFactor= 0.5;       // Try slower decreases
210      else if( stepTrial > 10.0*kCarTolerance )
211        decreaseFactor= 0.75;      // Try even slower decreases
212      else
213        decreaseFactor= 0.9;       // Try very slow decreases
214     }
215     stepTrial *= decreaseFactor;
216
217#ifdef G4DEBUG_FIELD
218     PrintStepLengthDiagnostic(CurrentProposedStepLength, decreaseFactor,
219                               stepTrial, pFieldTrack);
220#endif
221     if( stepTrial == 0.0 )
222     {
223       G4cout << " G4PropagatorInField::ComputeStep "
224              << " Particle abandoned due to lack of progress in field."
225              << G4endl
226              << " Properties : " << pFieldTrack << " "
227              << G4endl;
228       G4cerr << " G4PropagatorInField::ComputeStep "
229              << "  ERROR : attempting a zero step= " << stepTrial << G4endl
230              << " while attempting to progress after " << fNoZeroStep
231              << " trial steps.  Will abandon step." << G4endl;
232         fParticleIsLooping= true;
233         return 0;  // = stepTrial;
234     }
235     if( stepTrial < CurrentProposedStepLength )
236       CurrentProposedStepLength = stepTrial;
237  }
238  fLast_ProposedStepLength = CurrentProposedStepLength;
239
240  G4int do_loop_count = 0; 
241  do
242  { 
243    G4FieldTrack SubStepStartState = CurrentState;
244    G4ThreeVector SubStartPoint = CurrentState.GetPosition(); 
245
246    if( !first_substep) {
247      fNavigator->LocateGlobalPointWithinVolume( SubStartPoint );
248    }
249
250    // How far to attempt to move the particle !
251    //
252    h_TrialStepSize = CurrentProposedStepLength - StepTaken;
253
254    // Integrate as far as "chord miss" rule allows.
255    //
256    s_length_taken = GetChordFinder()->AdvanceChordLimited( 
257                             CurrentState,    // Position & velocity
258                             h_TrialStepSize,
259                             fEpsilonStep,
260                             fPreviousSftOrigin,
261                             fPreviousSafety
262                             );
263    //  CurrentState is now updated with the final position and velocity.
264
265    fFull_CurveLen_of_LastAttempt = s_length_taken;
266
267    G4ThreeVector  EndPointB = CurrentState.GetPosition(); 
268    G4ThreeVector  InterSectionPointE;
269    G4double       LinearStepLength;
270 
271    // Intersect chord AB with geometry
272    intersects= IntersectChord( SubStartPoint, EndPointB, 
273                                NewSafety,     LinearStepLength, 
274                                InterSectionPointE );
275    // E <- Intersection Point of chord AB and either volume A's surface
276    //                                  or a daughter volume's surface ..
277
278    if( first_substep ) { 
279       currentSafety = NewSafety;
280    } // Updating safety in other steps is potential future extention
281
282    if( intersects )
283    {
284       G4FieldTrack IntersectPointVelct_G(CurrentState);  // FT-Def-Construct
285
286       // Find the intersection point of AB true path with the surface
287       //   of vol(A), if it exists. Start with point E as first "estimate".
288       G4bool recalculatedEndPt= false;
289       G4bool found_intersection = 
290         LocateIntersectionPoint( SubStepStartState, CurrentState, 
291                                  InterSectionPointE, IntersectPointVelct_G,
292                                  recalculatedEndPt);
293       //G4cout<<"In Locate"<<recalculatedEndPt<<"  and V"<<IntersectPointVelct_G.GetPosition()<<G4endl;
294       intersects = intersects && found_intersection;
295       if( found_intersection ) {       
296          End_PointAndTangent= IntersectPointVelct_G;  // G is our EndPoint ...
297          StepTaken = TruePathLength = IntersectPointVelct_G.GetCurveLength()
298                                      - OriginalState.GetCurveLength();
299       } else {
300          // intersects= false;          // "Minor" chords do not intersect
301          if( recalculatedEndPt ){
302             CurrentState= IntersectPointVelct_G; 
303          }
304       }
305    }
306    if( !intersects )
307    {
308      StepTaken += s_length_taken; 
309      // For smooth trajectory display (jacek 01/11/2002)
310      if (fpTrajectoryFilter) {
311        fpTrajectoryFilter->TakeIntermediatePoint(CurrentState.GetPosition());
312      }
313    }
314    first_substep = false;
315
316#ifdef G4DEBUG_FIELD
317    if( fNoZeroStep > fActionThreshold_NoZeroSteps ) {
318      printStatus( SubStepStartState,  // or OriginalState,
319                   CurrentState,  CurrentProposedStepLength, 
320                   NewSafety,     do_loop_count,  pPhysVol );
321    }
322#endif
323#ifdef G4VERBOSE
324    if( (fVerboseLevel > 1) && (do_loop_count > fMax_loop_count-10 )) {
325      if( do_loop_count == fMax_loop_count-9 ){
326        G4cout << "G4PropagatorInField::ComputeStep "
327               << " Difficult track - taking many sub steps." << G4endl;
328      }
329      printStatus( SubStepStartState, CurrentState, CurrentProposedStepLength, 
330                   NewSafety, do_loop_count, pPhysVol );
331    }
332#endif
333
334    do_loop_count++;
335
336  } while( (!intersects )
337        && (StepTaken + kCarTolerance < CurrentProposedStepLength) 
338        && ( do_loop_count < fMax_loop_count ) );
339
340  if( do_loop_count >= fMax_loop_count  )
341  {
342    fParticleIsLooping = true;
343
344    if ( fVerboseLevel > 0 ){
345       G4cout << "G4PropagateInField: Killing looping particle " 
346              // << " of " << energy  << " energy "
347              << " after " << do_loop_count << " field substeps "
348              << " totaling " << StepTaken / mm << " mm " ;
349       if( pPhysVol )
350          G4cout << " in the volume " << pPhysVol->GetName() ; 
351       else
352         G4cout << " in unknown or null volume. " ; 
353       G4cout << G4endl;
354    }
355  }
356
357  if( !intersects )
358  {
359    // Chord AB or "minor chords" do not intersect
360    // B is the endpoint Step of the current Step.
361    //
362    End_PointAndTangent = CurrentState; 
363    TruePathLength = StepTaken;
364  }
365 
366  // Set pFieldTrack to the return value
367  //
368  pFieldTrack = End_PointAndTangent;
369
370#ifdef G4VERBOSE
371  // Check that "s" is correct
372  //
373  if( std::fabs(OriginalState.GetCurveLength() + TruePathLength
374      - End_PointAndTangent.GetCurveLength()) > 3.e-4 * TruePathLength )
375  {
376    G4cerr << " ERROR - G4PropagatorInField::ComputeStep():" << G4endl
377           << " Curve length mis-match, is advancement wrong ? " << G4endl;
378    G4cerr << " The curve length of the endpoint should be: " 
379           << OriginalState.GetCurveLength() + TruePathLength << G4endl
380           << " and it is instead: "
381           << End_PointAndTangent.GetCurveLength() << "." << G4endl
382           << " A difference of: "
383           << OriginalState.GetCurveLength() + TruePathLength
384              - End_PointAndTangent.GetCurveLength() << G4endl;
385    G4cerr << " Original state= " << OriginalState   << G4endl
386           << " Proposed state= " << End_PointAndTangent << G4endl;
387    G4Exception("G4PropagatorInField::ComputeStep()", "IncorrectProposedEndPoint",
388                FatalException, 
389                "Curve length mis-match between original state and proposed endpoint of propagation.");
390  }
391#endif
392
393  // In particular anomalous cases, we can get repeated zero steps
394  // In order to correct this efficiently, we identify these cases
395  // and only take corrective action when they occur.
396  //
397  if( TruePathLength < 0.5*kCarTolerance ) 
398    fNoZeroStep++;
399  else
400    fNoZeroStep = 0;
401
402  if( fNoZeroStep > fAbandonThreshold_NoZeroSteps ) { 
403     fParticleIsLooping = true;
404     G4cout << " WARNING - G4PropagatorInField::ComputeStep():" << G4endl
405            << " Zero progress for "  << fNoZeroStep << " attempted steps." 
406            << G4endl;
407     if ( fVerboseLevel > 2 )
408       G4cout << " Particle that is stuck will be killed." << G4endl;
409     fNoZeroStep = 0; 
410  }
411  //  G4cout << "G4PropagatorInField returns " << TruePathLength << G4endl;
412  return TruePathLength;
413}
414
415// --------------------------------------------------------------------------
416// G4bool
417// G4PropagatorInField::LocateIntersectionPoint(
418//   const G4FieldTrack&       CurveStartPointVelocity,   //  A
419//   const G4FieldTrack&       CurveEndPointVelocity,     //  B
420//   const G4ThreeVector&      TrialPoint,                //  E
421//         G4FieldTrack&       IntersectedOrRecalculated  // Output
422//         G4bool&             recalculated)              // Out
423// --------------------------------------------------------------------------
424//
425// Function that returns the intersection of the true path with the surface
426// of the current volume (either the external one or the inner one with one
427// of the daughters
428//
429//     A = Initial point
430//     B = another point
431//
432// Both A and B are assumed to be on the true path.
433//
434//     E is the first point of intersection of the chord AB with
435//     a volume other than A  (on the surface of A or of a daughter)
436//
437// Convention of Use :
438//     i) If it returns "true", then IntersectionPointVelocity is set
439//       to the approximate intersection point.
440//    ii) If it returns "false", no intersection was found.
441//          The validity of IntersectedOrRecalculated depends on 'recalculated'
442//        a) if latter is false, then IntersectedOrRecalculated is invalid.
443//        b) if latter is true,  then IntersectedOrRecalculated is
444//             the new endpoint, due to a re-integration.
445// --------------------------------------------------------------------------
446
447G4bool
448G4PropagatorInField::LocateIntersectionPoint( 
449  const   G4FieldTrack&       CurveStartPointVelocity,   //  A
450  const   G4FieldTrack&       CurveEndPointVelocity,     //  B
451  const   G4ThreeVector&      TrialPoint,                //  E
452          G4FieldTrack&       IntersectedOrRecalculatedFT, // Out: point found
453          G4bool&             recalculatedEndPoint)        // Out:
454{
455  // Find Intersection Point ( A, B, E )  of true path AB - start at E.
456
457  G4bool found_approximate_intersection = false;
458  G4bool there_is_no_intersection       = false;
459 
460  G4FieldTrack  CurrentA_PointVelocity = CurveStartPointVelocity; 
461  G4FieldTrack  CurrentB_PointVelocity = CurveEndPointVelocity;
462  G4ThreeVector CurrentE_Point = TrialPoint;
463  G4FieldTrack ApproxIntersecPointV(CurveEndPointVelocity); // FT-Def-Construct
464  G4double    NewSafety= -0.0;
465
466  G4bool final_section= true;  // Shows whether current section is last
467                               // (i.e. B=full end)
468  G4bool first_section=true;
469  recalculatedEndPoint= false; 
470
471  G4bool restoredFullEndpoint= false;
472
473  G4int substep_no = 0;
474   
475  // Limits for substep number
476  //
477  const G4int max_substeps=   10000;  // Test 120  (old value 100 )
478  const G4int warn_substeps=   1000;  //      100 
479
480  // Statistics for substeps
481  //
482  static G4int max_no_seen= -1; 
483  static G4int trigger_substepno_print= warn_substeps - 20 ;
484
485  //-------------------------------------------------------------------------- 
486  //  Algoritm for the case if progress in founding intersection is too slow.
487  //  Process is defined too slow if after N=param_substeps advances on the
488  //  path, it will be only 'fraction_done' of the total length.
489  //  In this case the remaining length is divided in two half and
490  //  the loop is restarted for each half. 
491  //  If progress is still too slow, the division in two halfs continue
492  //  until 'max_depth'.
493  //--------------------------------------------------------------------------
494
495  const G4int param_substeps=10; // Test value for the maximum number
496                                 // of substeps
497  const G4double fraction_done=0.3;
498
499  G4bool Second_half=false;      // First half or second half of divided step
500
501  // We need to know this for the 'final_section':
502  // real 'final_section' or first half 'final_section'
503  // In algorithm it is considered that the 'Second_half' is true
504  // and it becomes false only if we are in the first-half of level
505  // depthness or if we are in the first section
506
507  G4int depth=0; // Depth counts how many subdivisions of initial step made
508
509#ifdef G4DEBUG_FIELD
510  static G4double tolerance= 1.0e-8; 
511  G4ThreeVector  StartPosition= CurveStartPointVelocity.GetPosition(); 
512  if( (TrialPoint - StartPosition).mag() < tolerance * mm ) 
513  {
514     G4cerr << "WARNING - G4PropagatorInField::LocateIntersectionPoint()"
515            << G4endl
516            << "          Intermediate F point is on top of starting point A."
517            << G4endl;
518     G4Exception("G4PropagatorInField::LocateIntersectionPoint()", 
519                 "IntersectionPointIsAtStart", JustWarning,
520                 "Intersection point F is exactly at start point A." ); 
521  }
522#endif
523
524  // Intermediates Points on the Track = Subdivided Points must be stored.
525  // Give the initial values to 'InterMedFt'
526  // Important is 'ptrInterMedFT[0]', it saves the 'EndCurvePoint'
527  //
528  *ptrInterMedFT[0] = CurveEndPointVelocity;
529  for (G4int idepth=1; idepth<max_depth+1; idepth++ )
530  {
531    *ptrInterMedFT[idepth]=CurveStartPointVelocity;
532  }
533
534  // 'SubStartPoint' is needed to calculate the length of the divided step
535  //
536  G4FieldTrack SubStart_PointVelocity = CurveStartPointVelocity;
537   
538  do
539  {
540    G4int substep_no_p = 0;
541    G4bool sub_final_section = false; // the same as final_section,
542                                      // but for 'sub_section'
543    do // REPEAT param
544    {
545      G4ThreeVector Point_A = CurrentA_PointVelocity.GetPosition(); 
546      G4ThreeVector Point_B = CurrentB_PointVelocity.GetPosition();
547       
548      // F = a point on true AB path close to point E
549      // (the closest if possible)
550      //
551      ApproxIntersecPointV = GetChordFinder()
552                             ->ApproxCurvePointV( CurrentA_PointVelocity, 
553                                                  CurrentB_PointVelocity, 
554                                                  CurrentE_Point,
555                                                  fEpsilonStep );
556      //  The above method is the key & most intuitive part ...
557
558#ifdef G4DEBUG_FIELD
559      if( ApproxIntersecPointV.GetCurveLength() > 
560          CurrentB_PointVelocity.GetCurveLength() * (1.0 + tolerance) )
561      {
562        G4cerr << "ERROR - G4PropagatorInField::LocateIntersectionPoint()"
563               << G4endl
564               << "        Intermediate F point is more advanced than"
565               << " endpoint B." << G4endl;
566        G4Exception("G4PropagatorInField::LocateIntersectionPoint()", 
567                    "IntermediatePointConfusion", FatalException,
568                    "Intermediate F point is past end B point" ); 
569      }
570#endif
571
572      G4ThreeVector CurrentF_Point= ApproxIntersecPointV.GetPosition();
573
574      // First check whether EF is small - then F is a good approx. point
575      // Calculate the length and direction of the chord AF
576      //
577      G4ThreeVector  ChordEF_Vector = CurrentF_Point - CurrentE_Point;
578
579      if ( ChordEF_Vector.mag2() <= sqr(GetDeltaIntersection()) )
580      {
581        found_approximate_intersection = true;
582
583        // Create the "point" return value
584        //
585        IntersectedOrRecalculatedFT = ApproxIntersecPointV;
586        IntersectedOrRecalculatedFT.SetPosition( CurrentE_Point );
587       
588        // Note: in order to return a point on the boundary,
589        //       we must return E. But it is F on the curve.
590        //       So we must "cheat": we are using the position at point E
591        //       and the velocity at point F !!!
592        //
593        // This must limit the length we can allow for displacement!
594      }
595      else  // E is NOT close enough to the curve (ie point F)
596      {
597        // Check whether any volumes are encountered by the chord AF
598        // ---------------------------------------------------------
599        // First relocate to restore any Voxel etc information
600        // in the Navigator before calling ComputeStep()
601        //
602        fNavigator->LocateGlobalPointWithinVolume( Point_A );
603
604        G4ThreeVector PointG;   // Candidate intersection point
605        G4double stepLengthAF; 
606        G4bool Intersects_AF = IntersectChord( Point_A,   CurrentF_Point,
607                                               NewSafety, stepLengthAF,
608                                               PointG );
609        if( Intersects_AF )
610        {
611          // G is our new Candidate for the intersection point.
612          // It replaces  "E" and we will repeat the test to see if
613          // it is a good enough approximate point for us.
614          //       B    <- F
615          //       E    <- G
616
617          CurrentB_PointVelocity = ApproxIntersecPointV;
618          CurrentE_Point = PointG; 
619
620          // By moving point B, must take care if current
621          // AF has no intersection to try current FB!!
622          //
623          final_section= false; 
624
625#ifdef G4VERBOSE
626          if( fVerboseLevel > 3 )
627          {
628            G4cout << "G4PiF::LI> Investigating intermediate point"
629                   << " at s=" << ApproxIntersecPointV.GetCurveLength()
630                   << " on way to full s="
631                   << CurveEndPointVelocity.GetCurveLength() << G4endl;
632          }
633#endif
634        }
635        else  // not Intersects_AF
636        { 
637          // In this case:
638          // There is NO intersection of AF with a volume boundary.
639          // We must continue the search in the segment FB!
640          //
641          fNavigator->LocateGlobalPointWithinVolume( CurrentF_Point );
642
643          G4double stepLengthFB;
644          G4ThreeVector PointH;
645
646          // Check whether any volumes are encountered by the chord FB
647          // ---------------------------------------------------------
648
649          G4bool Intersects_FB = IntersectChord( CurrentF_Point, Point_B, 
650                                                 NewSafety, stepLengthFB,
651                                                 PointH );
652          if( Intersects_FB )
653          { 
654            // There is an intersection of FB with a volume boundary
655            // H <- First Intersection of Chord FB
656
657            // H is our new Candidate for the intersection point.
658            // It replaces  "E" and we will repeat the test to see if
659            // it is a good enough approximate point for us.
660
661            // Note that F must be in volume volA  (the same as A)
662            // (otherwise AF would meet a volume boundary!)
663            //   A    <- F
664            //   E    <- H
665
666            CurrentA_PointVelocity = ApproxIntersecPointV;
667            CurrentE_Point = PointH;
668          }
669          else  // not Intersects_FB
670          {
671            // There is NO intersection of FB with a volume boundary
672
673            if( final_section  )
674            {
675              // If B is the original endpoint, this means that whatever
676              // volume(s) intersected the original chord, none touch the
677              // smaller chords we have used.
678              // The value of 'IntersectedOrRecalculatedFT' returned is
679              // likely not valid
680
681              // Check on real final_section or SubEndSection
682              //
683              if( ((Second_half)&&(depth==0)) || (first_section) )
684              {
685                there_is_no_intersection = true;   // real final_section
686              }
687              else
688              {
689                // end of subsection, not real final section
690                // exit from the and go to the depth-1 level
691
692                substep_no_p = param_substeps+2;  // exit from the loop
693
694                // but 'Second_half' is still true because we need to find
695                // the 'CurrentE_point' for the next loop
696                //
697                Second_half = true; 
698                sub_final_section = true;
699           
700              }
701            }
702            else
703            {
704              // We must restore the original endpoint
705
706              CurrentA_PointVelocity = CurrentB_PointVelocity;  // Got to B
707              CurrentB_PointVelocity = CurveEndPointVelocity;
708              restoredFullEndpoint = true;
709            }
710          } // Endif (Intersects_FB)
711        } // Endif (Intersects_AF)
712
713        // Ensure that the new endpoints are not further apart in space
714        // than on the curve due to different errors in the integration
715        //
716        G4double linDistSq, curveDist; 
717        linDistSq = ( CurrentB_PointVelocity.GetPosition() 
718                    - CurrentA_PointVelocity.GetPosition() ).mag2(); 
719        curveDist = CurrentB_PointVelocity.GetCurveLength()
720                    - CurrentA_PointVelocity.GetCurveLength();
721
722        // Change this condition for very strict parameters of propagation
723        //
724        if( curveDist*curveDist*(1+2* fEpsilonStep ) < linDistSq )
725        {
726          // Re-integrate to obtain a new B
727          //
728          G4FieldTrack newEndPointFT=
729                  ReEstimateEndpoint( CurrentA_PointVelocity,
730                                      CurrentB_PointVelocity,
731                                      linDistSq,    // to avoid recalculation
732                                      curveDist );
733          G4FieldTrack oldPointVelB = CurrentB_PointVelocity; 
734          CurrentB_PointVelocity = newEndPointFT;
735
736          if( (final_section)&&(Second_half)&&(depth==0) ) // real final section
737          {
738            recalculatedEndPoint = true;
739            IntersectedOrRecalculatedFT = newEndPointFT;
740              // So that we can return it, if it is the endpoint!
741          }
742        }
743        if( curveDist < 0.0 )
744        {
745          G4cerr << "ERROR - G4PropagatorInField::LocateIntersectionPoint()"
746                 << G4endl
747                 << "        Error in advancing propagation." << G4endl;
748          fVerboseLevel = 5; // Print out a maximum of information
749          printStatus( CurrentA_PointVelocity,  CurrentB_PointVelocity,
750                       -1.0, NewSafety,  substep_no, 0 );
751          G4cerr << "        Point A (start) is " << CurrentA_PointVelocity
752                 << G4endl;
753          G4cerr << "        Point B (end)   is " << CurrentB_PointVelocity
754                 << G4endl;
755          G4cerr << "        Curve distance is " << curveDist << G4endl;
756          G4cerr << G4endl
757                 << "The final curve point is not further along"
758                 << " than the original!" << G4endl;
759
760          if( recalculatedEndPoint )
761          {
762            G4cerr << "Recalculation of EndPoint was called with fEpsStep= "
763                   << fEpsilonStep << G4endl;
764          }
765          G4cerr.precision(20);
766          G4cerr << " Point A (Curve start)   is " << CurveStartPointVelocity
767                 << G4endl;
768          G4cerr << " Point B (Curve   end)   is " << CurveEndPointVelocity
769                 << G4endl;
770          G4cerr << " Point A (Current start) is " << CurrentA_PointVelocity
771                 << G4endl;
772          G4cerr << " Point B (Current end)   is " << CurrentB_PointVelocity
773                 << G4endl;
774          G4cerr << " Point S (Sub start)     is " << SubStart_PointVelocity
775                 << G4endl;
776          G4cerr << " Point E (Trial Point)   is " << CurrentE_Point
777                 << G4endl;
778          G4cerr << " Point F (Intersection)  is " << ApproxIntersecPointV
779                 << G4endl;
780          G4cerr << "        LocateIntersection parameters are : Substep no= "
781                 << substep_no << G4endl;
782          G4cerr << "        Substep depth no= "<< substep_no_p  << " Depth= "
783                 << depth << G4endl;
784
785          G4Exception("G4PropagatorInField::LocateIntersectionPoint()",
786                      "FatalError", FatalException,
787                      "Error in advancing propagation.");
788        }
789
790        if(restoredFullEndpoint)
791        {
792          final_section = restoredFullEndpoint;
793          restoredFullEndpoint = false;
794        }
795      } // EndIf ( E is close enough to the curve, ie point F. )
796        // tests ChordAF_Vector.mag() <= maximum_lateral_displacement
797
798#ifdef G4DEBUG_LOCATE_INTERSECTION 
799      if( substep_no >= trigger_substepno_print )
800      {
801        G4cout << "Difficulty in converging in "
802               << "G4PropagatorInField::LocateIntersectionPoint():"
803               << G4endl
804               << "    Substep no = " << substep_no << G4endl;
805        if( substep_no == trigger_substepno_print )
806        {
807          printStatus( CurveStartPointVelocity, CurveEndPointVelocity,
808                       -1.0, NewSafety, 0, 0);
809        }
810        G4cout << " State of point A: "; 
811        printStatus( CurrentA_PointVelocity, CurrentA_PointVelocity,
812                     -1.0, NewSafety, substep_no-1, 0);
813        G4cout << " State of point B: "; 
814        printStatus( CurrentA_PointVelocity, CurrentB_PointVelocity,
815                     -1.0, NewSafety, substep_no, 0);
816      }
817#endif
818
819      substep_no++; 
820      substep_no_p++;
821
822    } while (  ( ! found_approximate_intersection )
823            && ( ! there_is_no_intersection )     
824            && ( substep_no_p <= param_substeps) );  // UNTIL found or
825                                                     // failed param substep
826    first_section = false;
827
828    if( (!found_approximate_intersection) && (!there_is_no_intersection) )
829    {
830      G4double did_len = std::abs( CurrentA_PointVelocity.GetCurveLength()
831                       - SubStart_PointVelocity.GetCurveLength()); 
832      G4double all_len = std::abs( CurrentB_PointVelocity.GetCurveLength()
833                       - SubStart_PointVelocity.GetCurveLength());
834   
835      G4double stepLengthAB;
836      G4ThreeVector PointGe;
837
838      // Check if progress is too slow and if it possible to go deeper,
839      // then halve the step if so
840      //
841      if( ( ( did_len )<fraction_done*all_len)
842         && (depth<max_depth) && (!sub_final_section) )
843      {
844
845        Second_half=false;
846        depth++;
847
848        G4double Sub_len = (all_len-did_len)/(2.);
849        G4FieldTrack start = CurrentA_PointVelocity;
850        G4MagInt_Driver* integrDriver=GetChordFinder()->GetIntegrationDriver();
851        integrDriver->AccurateAdvance(start, Sub_len, fEpsilonStep);
852        *ptrInterMedFT[depth] = start;
853        CurrentB_PointVelocity = *ptrInterMedFT[depth];
854 
855        // Adjust 'SubStartPoint' to calculate the 'did_length' in next loop
856        //
857        SubStart_PointVelocity = CurrentA_PointVelocity;
858
859        // Find new trial intersection point needed at start of the loop
860        //
861        G4ThreeVector Point_A = CurrentA_PointVelocity.GetPosition();
862        G4ThreeVector SubE_point = CurrentB_PointVelocity.GetPosition();   
863     
864        fNavigator->LocateGlobalPointWithinVolume(Point_A);
865        G4bool Intersects_AB = IntersectChord(Point_A, SubE_point,
866                                              NewSafety, stepLengthAB, PointGe);
867        if(Intersects_AB)
868        {
869          CurrentE_Point = PointGe;
870        }
871        else
872        {
873          // No intersection found for first part of curve
874          // (CurrentA,InterMedPoint[depth]). Go to the second part
875          //
876          Second_half = true;
877        }
878      } // if did_len
879
880      if( (Second_half)&&(depth!=0) )
881      {
882        // Second part of curve (InterMed[depth],Intermed[depth-1])                       )
883        // On the depth-1 level normally we are on the 'second_half'
884
885        Second_half = true;
886
887        //  Find new trial intersection point needed at start of the loop
888        //
889        SubStart_PointVelocity = *ptrInterMedFT[depth];
890        CurrentA_PointVelocity = *ptrInterMedFT[depth];
891        CurrentB_PointVelocity = *ptrInterMedFT[depth-1];
892        G4ThreeVector Point_A    = CurrentA_PointVelocity.GetPosition();
893        G4ThreeVector SubE_point = CurrentB_PointVelocity.GetPosition();   
894        fNavigator->LocateGlobalPointWithinVolume(Point_A);
895        G4bool Intersects_AB = IntersectChord(Point_A, SubE_point, NewSafety,
896                                              stepLengthAB, PointGe);
897        if(Intersects_AB)
898        {
899          CurrentE_Point = PointGe;
900        }
901        else
902        {
903          final_section = true;
904        }
905        depth--;
906      }
907    }  // if(!found_aproximate_intersection)
908
909  } while ( ( ! found_approximate_intersection )
910            && ( ! there_is_no_intersection )     
911            && ( substep_no <= max_substeps) ); // UNTIL found or failed
912
913  if( substep_no > max_no_seen )
914  {
915    max_no_seen = substep_no; 
916    if( max_no_seen > warn_substeps )
917    {
918      trigger_substepno_print = max_no_seen-20; // Want to see last 20 steps
919    } 
920  }
921
922  if(  ( substep_no >= max_substeps)
923      && !there_is_no_intersection
924      && !found_approximate_intersection )
925  {
926    G4cerr << "WARNING - G4PropagatorInField::LocateIntersectionPoint()"
927           << G4endl
928           << "          Convergence is requiring too many substeps: "
929           << substep_no << G4endl;
930    G4cerr << "          Abandoning effort to intersect. " << G4endl;
931    G4cerr << "          Information on start & current step follows in cout."
932           << G4endl;
933    G4cout << "WARNING - G4PropagatorInField::LocateIntersectionPoint()"
934           << G4endl
935           << "          Convergence is requiring too many substeps: "
936           << substep_no << G4endl;
937    G4cout << "          Found intersection = "
938           << found_approximate_intersection << G4endl
939           << "          Intersection exists = "
940           << !there_is_no_intersection << G4endl;
941    G4cout << "          Start and Endpoint of Requested Step:" << G4endl;
942    printStatus( CurveStartPointVelocity, CurveEndPointVelocity,
943                 -1.0, NewSafety, 0, 0);
944    G4cout << G4endl;
945    G4cout << "          'Bracketing' starting and endpoint of current Sub-Step"
946           << G4endl;
947    printStatus( CurrentA_PointVelocity, CurrentA_PointVelocity,
948                 -1.0, NewSafety, substep_no-1, 0);
949    printStatus( CurrentA_PointVelocity, CurrentB_PointVelocity,
950                 -1.0, NewSafety, substep_no, 0);
951    G4cout << G4endl;
952 
953#ifdef FUTURE_CORRECTION
954    // Attempt to correct the results of the method // FIX - TODO
955
956    if ( ! found_approximate_intersection )
957    { 
958      recalculatedEndPoint = true;
959      // Return the further valid intersection point -- potentially A ??
960      // JA/19 Jan 2006
961      IntersectedOrRecalculatedFT = CurrentA_PointVelocity;
962
963      G4cout << "WARNING - G4PropagatorInField::LocateIntersectionPoint()"
964             << G4endl
965             << "          Did not convergence after " << substep_no
966             << " substeps." << G4endl;
967      G4cout << "          The endpoint was adjused to pointA resulting"
968             << G4endl
969             << "          from the last substep: " << CurrentA_PointVelocity
970             << G4endl;
971    }
972#endif
973
974    G4cout.precision( 10 ); 
975    G4double done_len = CurrentA_PointVelocity.GetCurveLength(); 
976    G4double full_len = CurveEndPointVelocity.GetCurveLength();
977    G4cout << "ERROR - G4PropagatorInField::LocateIntersectionPoint()"
978           << G4endl
979           << "        Undertaken only length: " << done_len
980           << " out of " << full_len << " required." << G4endl;
981    G4cout << "        Remaining length = " << full_len - done_len << G4endl; 
982
983    G4Exception("G4PropagatorInField::LocateIntersectionPoint()",
984                "UnableToLocateIntersection", FatalException,
985                "Too many substeps while trying to locate intersection.");
986  }
987  else if( substep_no >= warn_substeps )
988  { 
989    int oldprc= G4cout.precision( 10 ); 
990    G4cout << "WARNING - G4PropagatorInField::LocateIntersectionPoint()"
991           << G4endl
992           << "          Undertaken length: " 
993           << CurrentB_PointVelocity.GetCurveLength(); 
994    G4cout << " - Needed: "  << substep_no << " substeps." << G4endl
995           << "          Warning level = " << warn_substeps
996           << " and maximum substeps = " << max_substeps << G4endl;
997    G4Exception("G4PropagatorInField::LocateIntersectionPoint()",
998                "DifficultyToLocateIntersection", JustWarning,
999                "Many substeps while trying to locate intersection.");
1000    G4cout.precision( oldprc ); 
1001  }
1002 
1003  return  !there_is_no_intersection; //  Success or failure
1004}
1005
1006///////////////////////////////////////////////////////////////////////////
1007//
1008// Dumps status of propagator.
1009
1010void
1011G4PropagatorInField::printStatus( const G4FieldTrack&        StartFT,
1012                                  const G4FieldTrack&        CurrentFT, 
1013                                        G4double             requestStep, 
1014                                        G4double             safety,
1015                                        G4int                stepNo, 
1016                                        G4VPhysicalVolume*   startVolume)
1017{
1018  const G4int verboseLevel= fVerboseLevel;
1019  const G4ThreeVector StartPosition       = StartFT.GetPosition();
1020  const G4ThreeVector StartUnitVelocity   = StartFT.GetMomentumDir();
1021  const G4ThreeVector CurrentPosition     = CurrentFT.GetPosition();
1022  const G4ThreeVector CurrentUnitVelocity = CurrentFT.GetMomentumDir();
1023
1024  G4double step_len = CurrentFT.GetCurveLength() - StartFT.GetCurveLength();
1025     
1026  if( ((stepNo == 0) && (verboseLevel <3))
1027      || (verboseLevel >= 3) )
1028  {
1029    static G4int noPrecision= 4;
1030    G4cout.precision(noPrecision);
1031    // G4cout.setf(ios_base::fixed,ios_base::floatfield);
1032    G4cout << std::setw( 6)  << " " 
1033           << std::setw( 25) << " Current Position  and  Direction" << " "
1034           << G4endl; 
1035    G4cout << std::setw( 5) << "Step#" 
1036           << std::setw(10) << "  s  " << " "
1037           << std::setw(10) << "X(mm)" << " "
1038           << std::setw(10) << "Y(mm)" << " " 
1039           << std::setw(10) << "Z(mm)" << " "
1040           << std::setw( 7) << " N_x " << " "
1041           << std::setw( 7) << " N_y " << " "
1042           << std::setw( 7) << " N_z " << " " ;
1043    //            << G4endl;
1044    G4cout     // << " >>> "
1045           << std::setw( 7) << " Delta|N|" << " "
1046      //   << std::setw( 7) << " Delta(N_z) " << " "
1047           << std::setw( 9) << "StepLen" << " " 
1048           << std::setw(12) << "StartSafety" << " " 
1049           << std::setw( 9) << "PhsStep" << " "; 
1050    if( startVolume ) {
1051      G4cout << std::setw(18) << "NextVolume" << " "; 
1052    }
1053    G4cout << G4endl;
1054  }
1055  if((stepNo == 0) && (verboseLevel <=3)){
1056     // Recurse to print the start values
1057     //
1058     printStatus( StartFT, StartFT, -1.0, safety, -1, startVolume);
1059   }
1060   if( verboseLevel <= 3 )
1061   {
1062     if( stepNo >= 0)
1063       G4cout << std::setw( 4) << stepNo << " ";
1064     else
1065       G4cout << std::setw( 5) << "Start" ;
1066     G4cout.precision(8);
1067     G4cout << std::setw(10) << CurrentFT.GetCurveLength() << " "; 
1068     G4cout.precision(8);
1069     G4cout << std::setw(10) << CurrentPosition.x() << " "
1070            << std::setw(10) << CurrentPosition.y() << " "
1071            << std::setw(10) << CurrentPosition.z() << " ";
1072     G4cout.precision(4);
1073     G4cout << std::setw( 7) << CurrentUnitVelocity.x() << " "
1074            << std::setw( 7) << CurrentUnitVelocity.y() << " "
1075            << std::setw( 7) << CurrentUnitVelocity.z() << " ";
1076     //  G4cout << G4endl;
1077     //     G4cout << " >>> " ;
1078     G4cout.precision(3); 
1079     G4cout << std::setw( 7) << CurrentFT.GetMomentum().mag()- StartFT.GetMomentum().mag() << " "; 
1080     //   << std::setw( 7) << CurrentUnitVelocity.z() - InitialUnitVelocity.z() << " ";
1081     G4cout << std::setw( 9) << step_len << " "; 
1082     G4cout << std::setw(12) << safety << " ";
1083     if( requestStep != -1.0 ) 
1084       G4cout << std::setw( 9) << requestStep << " ";
1085     else
1086       G4cout << std::setw( 9) << "Init/NotKnown" << " "; 
1087
1088     if( startVolume != 0)
1089     {
1090       G4cout << std::setw(12) << startVolume->GetName() << " ";
1091     }
1092#if 0
1093     else
1094     {
1095       if( step_len != -1 )
1096         G4cout << std::setw(12) << "OutOfWorld" << " ";
1097       else
1098         G4cout << std::setw(12) << "NotGiven" << " ";
1099     }
1100#endif
1101
1102     G4cout << G4endl;
1103   }
1104   else // if( verboseLevel > 3 )
1105   {
1106     //  Multi-line output
1107       
1108     G4cout << "Step taken was " << step_len 
1109            << " out of PhysicalStep= " <<  requestStep << G4endl;
1110     G4cout << "Final safety is: " << safety << G4endl;
1111
1112     G4cout << "Chord length = " << (CurrentPosition-StartPosition).mag()
1113            << G4endl;
1114     G4cout << G4endl; 
1115   }
1116}
1117
1118///////////////////////////////////////////////////////////////////////////
1119//
1120// Prints Step diagnostics
1121
1122void 
1123G4PropagatorInField::PrintStepLengthDiagnostic(
1124                          G4double CurrentProposedStepLength,
1125                          G4double decreaseFactor,
1126                          G4double stepTrial,
1127                    const G4FieldTrack& )
1128{
1129  G4cout << " PiF: NoZeroStep= " << fNoZeroStep
1130         << " CurrentProposedStepLength= " << CurrentProposedStepLength
1131         << " Full_curvelen_last=" << fFull_CurveLen_of_LastAttempt
1132         << " last proposed step-length= " << fLast_ProposedStepLength
1133         << " decreate factor = " << decreaseFactor
1134         << " step trial = " << stepTrial
1135         << G4endl;
1136}
1137
1138G4bool
1139G4PropagatorInField::IntersectChord( G4ThreeVector  StartPointA, 
1140                                     G4ThreeVector  EndPointB,
1141                                     G4double      &NewSafety,
1142                                     G4double      &LinearStepLength,
1143                                     G4ThreeVector &IntersectionPoint
1144                                   )
1145{
1146    // Calculate the direction and length of the chord AB
1147    G4ThreeVector  ChordAB_Vector = EndPointB - StartPointA;
1148    G4double       ChordAB_Length = ChordAB_Vector.mag();  // Magnitude (norm)
1149    G4ThreeVector  ChordAB_Dir =    ChordAB_Vector.unit();
1150    G4bool intersects;
1151
1152    G4ThreeVector OriginShift = StartPointA - fPreviousSftOrigin ;
1153    G4double      MagSqShift  = OriginShift.mag2() ;
1154    G4double      currentSafety;
1155    G4bool        doCallNav= false;
1156
1157    if( MagSqShift >= sqr(fPreviousSafety) )
1158    {
1159        currentSafety = 0.0 ;
1160    }else{
1161        currentSafety = fPreviousSafety - std::sqrt(MagSqShift) ;
1162    }
1163
1164    if( fUseSafetyForOptimisation && (ChordAB_Length <= currentSafety) )
1165    {
1166       // The Step is guaranteed to be taken
1167
1168       LinearStepLength = ChordAB_Length;
1169       intersects = false;
1170
1171       NewSafety= currentSafety;
1172
1173#if 0 
1174       G4cout << " G4PropagatorInField does not call Navigator::ComputeStep " << G4endl ;
1175       G4cout << "    step= " << LinearStepLength << " safety= " << NewSafety << G4endl;
1176       G4cout << "    safety: Origin = " << fPreviousSftOrigin << " val= " << fPreviousSafety << G4endl;
1177#endif
1178    }
1179    else
1180    {
1181       doCallNav= true; 
1182       // Check whether any volumes are encountered by the chord AB
1183
1184       // G4cout << " G4PropagatorInField calling Navigator::ComputeStep " << G4endl ;
1185
1186       LinearStepLength = 
1187        fNavigator->ComputeStep( StartPointA, ChordAB_Dir,
1188                                 ChordAB_Length, NewSafety );
1189       intersects = (LinearStepLength <= ChordAB_Length); 
1190       // G4Navigator contracts to return k_infinity if len==asked
1191       // and it did not find a surface boundary at that length
1192       LinearStepLength = std::min( LinearStepLength, ChordAB_Length);
1193
1194       // G4cout << " G4PiF got step= " << LinearStepLength << " safety= " << NewSafety << G4endl;
1195
1196       // Save the last calculated safety!
1197       fPreviousSftOrigin = StartPointA;
1198       fPreviousSafety= NewSafety;
1199
1200       if( intersects ){
1201          // Intersection Point of chord AB and either volume A's surface
1202          //                                or a daughter volume's surface ..
1203          IntersectionPoint = StartPointA + LinearStepLength * ChordAB_Dir;
1204       }
1205    }
1206
1207#ifdef DEBUG_INTERSECTS_CHORD
1208    // printIntersection(
1209    // StartPointA, EndPointB, LinearStepLength, IntersectionPoint, NewSafety
1210
1211    G4cout << " G4PropagatorInField::IntersectChord reports " << G4endl;
1212    G4cout << " PiF-IC> "
1213           << "Start="  << std::setw(12) << StartPointA       << " "
1214           << "End= "   << std::setw(8) << EndPointB         << " "
1215           << "StepIn=" << std::setw(8) << LinearStepLength  << " "
1216           << "NewSft=" << std::setw(8) << NewSafety << " " 
1217           << "CallNav=" << doCallNav      << "  "
1218           << "Intersects " << intersects     << "  "; 
1219    if( intersects ) 
1220      G4cout << "IntrPt=" << std::setw(8) << IntersectionPoint << " " ; 
1221    G4cout << G4endl;
1222#endif
1223
1224    return intersects;
1225}
1226
1227// --------------------- oooo000000000000oooo ----------------------------
1228
1229G4FieldTrack G4PropagatorInField::
1230ReEstimateEndpoint( const G4FieldTrack &CurrentStateA, 
1231                    const G4FieldTrack &EstimatedEndStateB,
1232                          G4double      linearDistSq,
1233                          G4double      curveDist
1234                  )
1235{
1236  // G4double checkCurveDist= EstimatedEndStateB.GetCurveLength()
1237  //   - CurrentStateA.GetCurveLength();
1238  // G4double checkLinDistSq= (EstimatedEndStateB.GetPosition()
1239  //                    - CurrentStateA.GetPosition() ).mag2();
1240
1241  G4FieldTrack newEndPoint( CurrentStateA );
1242  G4MagInt_Driver* integrDriver= GetChordFinder()->GetIntegrationDriver(); 
1243
1244  G4FieldTrack retEndPoint( CurrentStateA );
1245  G4bool goodAdvance;
1246  G4int  itrial=0;
1247  const G4int no_trials= 20;
1248
1249  G4double endCurveLen= EstimatedEndStateB.GetCurveLength();
1250  do
1251  {
1252     G4double currentCurveLen= newEndPoint.GetCurveLength();
1253     G4double advanceLength= endCurveLen - currentCurveLen ; 
1254     if (std::abs(advanceLength)<kCarTolerance)
1255     {
1256       advanceLength=(EstimatedEndStateB.GetPosition()
1257                     -newEndPoint.GetPosition()).mag();
1258     }
1259     goodAdvance= 
1260       integrDriver->AccurateAdvance(newEndPoint, advanceLength, fEpsilonStep);
1261     //              ***************
1262  }
1263  while( !goodAdvance && (++itrial < no_trials) );
1264
1265  if( goodAdvance )
1266  {
1267    retEndPoint= newEndPoint; 
1268  }
1269  else
1270  {
1271    retEndPoint= EstimatedEndStateB; // Could not improve without major work !!
1272  }
1273
1274  //  All the work is done
1275  //   below are some diagnostics only -- before the return!
1276  //
1277  static const G4String MethodName("G4PropagatorInField::ReEstimateEndpoint");
1278
1279#ifdef G4VERBOSE
1280  G4int  latest_good_trials=0;
1281  if( itrial > 1)
1282  {
1283    if( fVerboseLevel > 0 )
1284    {
1285      G4cout << MethodName << " called - goodAdv= " << goodAdvance
1286             << " trials = " << itrial
1287             << " previous good= " << latest_good_trials
1288             << G4endl;
1289    }
1290    latest_good_trials=0; 
1291  }
1292  else
1293  {   
1294    latest_good_trials++; 
1295  }
1296#endif
1297
1298#ifdef G4DEBUG_FIELD
1299  G4double lengthDone = newEndPoint.GetCurveLength() 
1300                      - CurrentStateA.GetCurveLength(); 
1301  if( !goodAdvance )
1302  {
1303    if( fVerboseLevel >= 3 )
1304    {
1305      G4cout << MethodName << "> AccurateAdvance failed " ;
1306      G4cout << " in " << itrial << " integration trials/steps. " << G4endl;
1307      G4cout << " It went only " << lengthDone << " instead of " << curveDist
1308             << " -- a difference of " << curveDist - lengthDone  << G4endl;
1309      G4cout << " ReEstimateEndpoint> Reset endPoint to original value!"
1310             << G4endl;
1311    }
1312  }
1313
1314  static G4int noInaccuracyWarnings = 0; 
1315  G4int maxNoWarnings = 10;
1316  if (  (noInaccuracyWarnings < maxNoWarnings ) 
1317       || (fVerboseLevel > 1) )
1318    {
1319      G4cerr << "G4PropagatorInField::LocateIntersectionPoint():"
1320             << G4endl
1321             << " Warning: Integration inaccuracy requires" 
1322             <<   " an adjustment in the step's endpoint."  << G4endl
1323             << "   Two mid-points are further apart than their"
1324             <<   " curve length difference"                << G4endl
1325             << "   Dist = "       << std::sqrt(linearDistSq)
1326             << " curve length = " << curveDist             << G4endl; 
1327      G4cerr << " Correction applied is " 
1328             << (newEndPoint.GetPosition()-EstimatedEndStateB.GetPosition()).mag()
1329             << G4endl;
1330    }
1331#else
1332  // Statistics on the RMS value of the corrections
1333
1334  static G4int    noCorrections=0;
1335  static G4double sumCorrectionsSq = 0;
1336  noCorrections++; 
1337  if( goodAdvance )
1338  {
1339    sumCorrectionsSq += (EstimatedEndStateB.GetPosition() - 
1340                         newEndPoint.GetPosition()).mag2();
1341  }
1342  linearDistSq -= curveDist; // To use linearDistSq ... !
1343#endif
1344
1345  return retEndPoint;
1346}
1347
1348// Access the points which have passed through the filter. The
1349// points are stored as ThreeVectors for the initial impelmentation
1350// only (jacek 30/10/2002)
1351// Responsibility for deleting the points lies with
1352// SmoothTrajectoryPoint, which is the points' final
1353// destination. The points pointer is set to NULL, to ensure that
1354// the points are not re-used in subsequent steps, therefore THIS
1355// METHOD MUST BE CALLED EXACTLY ONCE PER STEP. (jacek 08/11/2002)
1356
1357std::vector<G4ThreeVector>*
1358G4PropagatorInField::GimmeTrajectoryVectorAndForgetIt() const
1359{
1360  // NB, GimmeThePointsAndForgetThem really forgets them, so it can
1361  // only be called (exactly) once for each step.
1362
1363  if (fpTrajectoryFilter)
1364  {
1365    return fpTrajectoryFilter->GimmeThePointsAndForgetThem();
1366  }
1367  else
1368  {
1369    return 0;
1370  }
1371}
1372
1373void 
1374G4PropagatorInField::SetTrajectoryFilter(G4VCurvedTrajectoryFilter* filter)
1375{
1376  fpTrajectoryFilter = filter;
1377}
1378
1379void G4PropagatorInField::ClearPropagatorState()
1380{
1381  // Goal: Clear all memory of previous steps,  cached information
1382
1383  fParticleIsLooping= false;
1384  fNoZeroStep= 0;
1385
1386  End_PointAndTangent= G4FieldTrack( G4ThreeVector(0.,0.,0.),
1387                                     G4ThreeVector(0.,0.,0.),
1388                                     0.0,0.0,0.0,0.0,0.0); 
1389  fFull_CurveLen_of_LastAttempt = -1; 
1390  fLast_ProposedStepLength = -1;
1391
1392  fPreviousSftOrigin= G4ThreeVector(0.,0.,0.);
1393  fPreviousSafety= 0.0;
1394}
1395
1396G4FieldManager* G4PropagatorInField::
1397FindAndSetFieldManager( G4VPhysicalVolume* pCurrentPhysicalVolume)
1398{
1399  G4FieldManager* currentFieldMgr;
1400
1401  currentFieldMgr = fDetectorFieldMgr;
1402  if( pCurrentPhysicalVolume)
1403  {
1404     G4FieldManager *newFieldMgr = 0;
1405     newFieldMgr= pCurrentPhysicalVolume->GetLogicalVolume()->GetFieldManager();
1406     if ( newFieldMgr ) 
1407        currentFieldMgr = newFieldMgr;
1408  }
1409  fCurrentFieldMgr= currentFieldMgr;
1410
1411  // Flag that field manager has been set.
1412  fSetFieldMgr= true;
1413
1414  return currentFieldMgr;
1415}
1416
1417G4int G4PropagatorInField::SetVerboseLevel( G4int level )
1418{
1419  G4int oldval= fVerboseLevel;
1420  fVerboseLevel= level;
1421
1422  // Forward the verbose level 'reduced' to ChordFinder,
1423  // MagIntegratorDriver ... ?
1424  //
1425  G4MagInt_Driver* integrDriver= GetChordFinder()->GetIntegrationDriver(); 
1426  integrDriver->SetVerboseLevel( fVerboseLevel - 2 ); 
1427  G4cout << "Set Driver verbosity to " << fVerboseLevel - 2 << G4endl;
1428
1429  return oldval;
1430}
Note: See TracBrowser for help on using the repository browser.