// // ******************************************************************** // * 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: G4ChordFinder.cc,v 1.49 2008/07/15 14:02:06 japost Exp $ // GEANT4 tag $Name: HEAD $ // // // 25.02.97 John Apostolakis, design and implimentation // 05.03.97 V. Grichine , style modification // ------------------------------------------------------------------- #include "G4ChordFinder.hh" #include "G4MagneticField.hh" #include "G4Mag_UsualEqRhs.hh" #include "G4ClassicalRK4.hh" #include // .......................................................................... G4ChordFinder::G4ChordFinder(G4MagInt_Driver* pIntegrationDriver) : fDefaultDeltaChord( 0.25 * mm ), fDeltaChord( fDefaultDeltaChord ), fAllocatedStepper(false), fEquation(0), fDriversStepper(0), fFirstFraction(0.999), fFractionLast(1.00), fFractionNextEstimate(0.98), fMultipleRadius(15.0), fTotalNoTrials_FNC(0), fNoCalls_FNC(0), fmaxTrials_FNC(0), fStatsVerbose(0) { // Simple constructor which does not create equation, .. // fDeltaChord= fDefaultDeltaChord; fIntgrDriver= pIntegrationDriver; fAllocatedStepper= false; fLastStepEstimate_Unconstrained = DBL_MAX; // Should move q, p to SetFractions_Last_Next( fFractionLast, fFractionNextEstimate); // check the values and set the other parameters } // .......................................................................... G4ChordFinder::G4ChordFinder( G4MagneticField* theMagField, G4double stepMinimum, G4MagIntegratorStepper* pItsStepper ) : fDefaultDeltaChord( 0.25 * mm ), fDeltaChord( fDefaultDeltaChord ), fAllocatedStepper(false), fEquation(0), fDriversStepper(0), fFirstFraction(0.999), fFractionLast(1.00), fFractionNextEstimate(0.98), fMultipleRadius(15.0), fTotalNoTrials_FNC(0), fNoCalls_FNC(0), fmaxTrials_FNC(0), fStatsVerbose(0) { // Construct the Chord Finder // by creating in inverse order the Driver, the Stepper and EqRhs ... G4Mag_EqRhs *pEquation = new G4Mag_UsualEqRhs(theMagField); fEquation = pEquation; fLastStepEstimate_Unconstrained = DBL_MAX; // Should move q, p to // G4FieldTrack ?? SetFractions_Last_Next( fFractionLast, fFractionNextEstimate); // check the values and set the other parameters // --->> Charge Q = 0 // --->> Momentum P = 1 NOMINAL VALUES !!!!!!!!!!!!!!!!!! if( pItsStepper == 0 ) { pItsStepper = fDriversStepper = new G4ClassicalRK4(pEquation); fAllocatedStepper= true; } else { fAllocatedStepper= false; } fIntgrDriver = new G4MagInt_Driver(stepMinimum, pItsStepper, pItsStepper->GetNumberOfVariables() ); } // ...................................................................... void G4ChordFinder::SetFractions_Last_Next( G4double fractLast, G4double fractNext ) { // Use -1.0 as request for Default. if( fractLast == -1.0 ) fractLast = 1.0; // 0.9; if( fractNext == -1.0 ) fractNext = 0.98; // 0.9; // fFirstFraction = 0.999; // Orig 0.999 A safe value, range: ~ 0.95 - 0.999 // fMultipleRadius = 15.0; // For later use, range: ~ 2 - 20 if( fStatsVerbose ) { G4cout << " ChordFnd> Trying to set fractions: " << " first " << fFirstFraction << " last " << fractLast << " next " << fractNext << " and multiple " << fMultipleRadius << G4endl; } if( (fractLast > 0.0) && (fractLast <=1.0) ) { fFractionLast= fractLast; } else G4cerr << "G4ChordFinder:: SetFractions_Last_Next: Invalid " << " fraction Last = " << fractLast << " must be 0 < fractionLast <= 1 " << G4endl; if( (fractNext > 0.0) && (fractNext <1.0) ) { fFractionNextEstimate = fractNext; } else G4cerr << "G4ChordFinder:: SetFractions_Last_Next: Invalid " << " fraction Next = " << fractNext << " must be 0 < fractionNext < 1 " << G4endl; } // ...................................................................... G4ChordFinder::~G4ChordFinder() { delete fEquation; // fIntgrDriver->pIntStepper->theEquation_Rhs; if( fAllocatedStepper) { delete fDriversStepper; } // fIntgrDriver->pIntStepper;} delete fIntgrDriver; if( fStatsVerbose ) { PrintStatistics(); } } void G4ChordFinder::PrintStatistics() { // Print Statistics G4cout << "G4ChordFinder statistics report: " << G4endl; G4cout << " No trials: " << fTotalNoTrials_FNC << " No Calls: " << fNoCalls_FNC << " Max-trial: " << fmaxTrials_FNC << G4endl; G4cout << " Parameters: " << " fFirstFraction " << fFirstFraction << " fFractionLast " << fFractionLast << " fFractionNextEstimate " << fFractionNextEstimate << G4endl; } // ...................................................................... G4double G4ChordFinder::AdvanceChordLimited( G4FieldTrack& yCurrent, G4double stepMax, G4double epsStep, const G4ThreeVector latestSafetyOrigin, G4double latestSafetyRadius ) { G4double stepPossible; G4double dyErr; G4FieldTrack yEnd( yCurrent); G4double startCurveLen= yCurrent.GetCurveLength(); G4double nextStep; // ************* stepPossible= FindNextChord(yCurrent, stepMax, yEnd, dyErr, epsStep, &nextStep , latestSafetyOrigin, latestSafetyRadius ); // ************* // G4cout<<"Exit Find Next Chord Err= "<AccurateAdvance(yCurrent, stepPossible, epsStep, nextStep); // *************** if ( ! good_advance ){ // In this case the driver could not do the full distance stepPossible= yCurrent.GetCurveLength()-startCurveLen; } } #ifdef G4DEBUG_FIELD //G4cout << "Exiting FindNextChord Limited with:" << G4endl // << " yCurrent: " << yCurrent<< G4endl; #endif return stepPossible; } // #define TEST_CHORD_PRINT 1 // ............................................................................ G4double G4ChordFinder::FindNextChord( const G4FieldTrack& yStart, G4double stepMax, G4FieldTrack& yEnd, // Endpoint G4double& dyErrPos, // Error of endpoint G4double epsStep, G4double* pStepForAccuracy, const G4ThreeVector, // latestSafetyOrigin, G4double // latestSafetyRadius ) // Returns Length of Step taken { //G4cout<<"Inter Find Next Chord with step="< GetDerivatives( yCurrent, dydx ) ; //for (G4int i=0;iQuickAdvance( yCurrent, dydx, stepTrial, dChordStep, dyErrPos); // ************ // G4cout<<"AfterQuickAdv step="< adjust the maximum curve length. // NOTE: this case only happens for relatively straight paths. curve_length = ABdist; } G4double new_st_length; if ( ABdist > 0.0 ){ AE_fraction = ChordAE_Vector.mag() / ABdist; }else{ AE_fraction = 0.5; // Guess .. ?; #ifdef G4DEBUG_FIELD G4cout << "Warning in G4ChordFinder::ApproxCurvePoint:" << " A and B are the same point!" << G4endl << " Chord AB length = " << ChordAE_Vector.mag() << G4endl << G4endl; #endif } if( (AE_fraction> 1.0 + perMillion) || (AE_fraction< 0.) ){ #ifdef G4DEBUG_FIELD G4cerr << " G4ChordFinder::ApproxCurvePointV - Warning:" << " Anomalous condition:AE > AB or AE/AB <= 0 " << G4endl << " AE_fraction = " << AE_fraction << G4endl << " Chord AE length = " << ChordAE_Vector.mag() << G4endl << " Chord AB length = " << ABdist << G4endl << G4endl; G4cerr << " OK if this condition occurs after a recalculation of 'B'" << G4endl << " Otherwise it is an error. " << G4endl ; #endif // This course can now result if B has been re-evaluated, // without E being recomputed (1 July 99) // In this case this is not a "real error" - but it undesired // and we cope with it by a default corrective action ... AE_fraction = 0.5; // Default value } new_st_length= AE_fraction * curve_length; G4bool good_advance; if ( AE_fraction > 0.0 ) { good_advance = fIntgrDriver->AccurateAdvance(Current_PointVelocity, new_st_length, eps_step ); // Relative accuracy // In this case it does not matter if it cannot advance the full distance } // If there was a memory of the step_length actually require at the start // of the integration Step, this could be re-used ... G4cout.precision(14); // G4cout<<"G4ChordFinder::LinearApprox="<