Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer 3 // * License and Disclaimer * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/ 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. 9 // * include a list of copyright holders. * 10 // * 10 // * * 11 // * Neither the authors of this software syst 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitatio 16 // * for the full disclaimer and the limitation of liability. * 17 // * 17 // * * 18 // * This code implementation is the result 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboratio 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distri 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you ag 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publicati 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Sof 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************* 24 // ******************************************************************** 25 // 25 // 26 // G4ChordFinder implementation << 27 // 26 // 28 // Author: J.Apostolakis - Design and implemen << 27 // $Id: G4ChordFinder.cc,v 1.47 2006/06/29 18:23:32 gunter Exp $ >> 28 // GEANT4 tag $Name: geant4-09-01-patch-01 $ >> 29 // >> 30 // >> 31 // 25.02.97 John Apostolakis, design and implimentation >> 32 // 05.03.97 V. Grichine , style modification 29 // ------------------------------------------- 33 // ------------------------------------------------------------------- 30 34 31 #include <iomanip> << 32 << 33 #include "G4ChordFinder.hh" 35 #include "G4ChordFinder.hh" 34 #include "G4SystemOfUnits.hh" << 35 #include "G4MagneticField.hh" 36 #include "G4MagneticField.hh" 36 #include "G4Mag_UsualEqRhs.hh" 37 #include "G4Mag_UsualEqRhs.hh" 37 #include "G4MagIntegratorDriver.hh" << 38 #include "G4ClassicalRK4.hh" 38 // #include "G4ClassicalRK4.hh" << 39 // #include "G4CashKarpRKF45.hh" << 40 // #include "G4NystromRK4.hh" << 41 // #include "G4BogackiShampine23.hh" << 42 // #include "G4BogackiShampine45.hh" << 43 << 44 #include "G4DormandPrince745.hh" << 45 << 46 // New templated stepper(s) -- avoid virtual c << 47 #include "G4TDormandPrince45.hh" << 48 << 49 // FSAL type driver / steppers ----- << 50 #include "G4FSALIntegrationDriver.hh" << 51 #include "G4VFSALIntegrationStepper.hh" << 52 #include "G4RK547FEq1.hh" << 53 // #include "G4RK547FEq2.hh" << 54 // #include "G4RK547FEq3.hh" << 55 // #include "G4FSALBogackiShampine45.hh" << 56 // #include "G4FSALDormandPrince745.hh" << 57 << 58 // Templated type drivers ----- << 59 #include "G4IntegrationDriver.hh" << 60 #include "G4InterpolationDriver.hh" << 61 << 62 #include "G4HelixHeum.hh" << 63 #include "G4BFieldIntegrationDriver.hh" << 64 << 65 #include "G4QSSDriverCreator.hh" << 66 39 67 #include "G4CachedMagneticField.hh" << 40 #include <iomanip> 68 << 69 #include <cassert> << 70 #include <memory> << 71 41 72 G4bool G4ChordFinder::gVerboseCtor = false; << 73 // ........................................... 42 // .......................................................................... 74 43 75 G4ChordFinder::G4ChordFinder(G4VIntegrationDri << 44 G4ChordFinder::G4ChordFinder(G4MagInt_Driver* pIntegrationDriver) 76 : fDefaultDeltaChord(0.25 * mm), fIntgrDrive << 45 : fDefaultDeltaChord( 0.25 * mm ), >> 46 fDeltaChord( fDefaultDeltaChord ), >> 47 fAllocatedStepper(false), >> 48 fEquation(0), >> 49 fDriversStepper(0), >> 50 fFirstFraction(0.999), fFractionLast(1.00), fFractionNextEstimate(0.98), >> 51 fMultipleRadius(15.0), >> 52 fTotalNoTrials_FNC(0), fNoCalls_FNC(0), fmaxTrials_FNC(0), >> 53 fStatsVerbose(0) 77 { 54 { 78 // Simple constructor -- it does not create << 55 // Simple constructor which does not create equation, .. 79 if( gVerboseCtor ) << 56 // fDeltaChord= fDefaultDeltaChord; 80 { << 57 fIntgrDriver= pIntegrationDriver; 81 G4cout << "G4ChordFinder: Simple construct << 58 fAllocatedStepper= false; 82 } << 59 fLastStepEstimate_Unconstrained = DBL_MAX; // Should move q, p to 83 << 60 84 fDeltaChord = fDefaultDeltaChord; // P << 61 SetFractions_Last_Next( fFractionLast, fFractionNextEstimate); >> 62 // check the values and set the other parameters 85 } 63 } 86 64 87 // ........................................... 65 // .......................................................................... 88 66 89 G4ChordFinder::G4ChordFinder( G4MagneticField* 67 G4ChordFinder::G4ChordFinder( G4MagneticField* theMagField, 90 G4double << 68 G4double stepMinimum, 91 G4MagIntegratorS << 69 G4MagIntegratorStepper* pItsStepper ) 92 G4int << 70 : fDefaultDeltaChord( 0.25 * mm ), 93 : fDefaultDeltaChord(0.25 * mm) << 71 fDeltaChord( fDefaultDeltaChord ), >> 72 fAllocatedStepper(false), >> 73 fEquation(0), >> 74 fDriversStepper(0), >> 75 fFirstFraction(0.999), fFractionLast(1.00), fFractionNextEstimate(0.98), >> 76 fMultipleRadius(15.0), >> 77 fTotalNoTrials_FNC(0), fNoCalls_FNC(0), fmaxTrials_FNC(0), >> 78 fStatsVerbose(0) 94 { 79 { 95 // Construct the Chord Finder << 80 // Construct the Chord Finder 96 // by creating in inverse order the Driver, << 81 // by creating in inverse order the Driver, the Stepper and EqRhs ... 97 constexpr G4int nVar6 = 6; // Components i << 82 G4Mag_EqRhs *pEquation = new G4Mag_UsualEqRhs(theMagField); 98 << 83 fEquation = pEquation; 99 fDeltaChord = fDefaultDeltaChord; // P << 84 fLastStepEstimate_Unconstrained = DBL_MAX; // Should move q, p to >> 85 // G4FieldTrack ?? 100 86 101 G4cout << " G4ChordFinder: stepperDriverId: << 87 SetFractions_Last_Next( fFractionLast, fFractionNextEstimate); >> 88 // check the values and set the other parameters 102 89 103 G4bool useFSALstepper = (stepperDriverId << 90 // --->> Charge Q = 0 104 G4bool useTemplatedStepper= (stepperDriverId << 91 // --->> Momentum P = 1 NOMINAL VALUES !!!!!!!!!!!!!!!!!! 105 G4bool useRegularStepper = (stepperDriverId << 106 G4bool useBfieldDriver = (stepperDriverId << 107 G4bool useG4QSSDriver = (stepperDriverId << 108 << 109 if( stepperDriverId == kQss3DriverType) << 110 { << 111 stepperDriverId = kQss2DriverType; << 112 G4cout << " G4ChordFinder: QSS 3 is curren << 113 } << 114 92 115 using EquationType = G4Mag_UsualEqRhs; << 93 if( pItsStepper == 0 ) 116 << 94 { 117 using TemplatedStepperType = << 95 pItsStepper = fDriversStepper = new G4ClassicalRK4(pEquation); 118 G4TDormandPrince45<EquationType,nVar6 << 96 fAllocatedStepper= true; 119 const char* TemplatedStepperName = << 97 } 120 "G4TDormandPrince745 (templated Dormand- << 98 else 121 << 122 using RegularStepperType = << 123 G4DormandPrince745; // 5th order embe << 124 // G4ClassicalRK4; // The old << 125 // G4CashKarpRKF45; // First em << 126 // G4BogackiShampine45; // High eff << 127 // G4NystromRK4; // Nystrom << 128 // G4RK547FEq1; // or 2 or 3 << 129 const char* RegularStepperName = << 130 "G4DormandPrince745 (aka DOPRI5): 5th/4t << 131 // "BogackiShampine 45 (Embedded 5th/4th << 132 // "Nystrom stepper 4th order"; << 133 << 134 using NewFsalStepperType = G4DormandPrince74 << 135 << 136 const char* NewFSALStepperName = << 137 "G4RK574FEq1> FSAL 4th/5th order 7-stage << 138 << 139 #ifdef G4DEBUG_FIELD << 140 static G4bool verboseDebug = true; << 141 if( verboseDebug ) << 142 { 99 { 143 G4cout << "G4ChordFinder 2nd Constructor << 100 fAllocatedStepper= false; 144 G4cout << " Arguments: " << G4endl << 145 << " - min step = " << stepMinimum << 146 << " - stepper ptr provided : " << 147 << ( pItsStepper==nullptr ? " no << 148 if( pItsStepper==nullptr ) << 149 G4cout << " - stepper/driver Id = " << << 150 << " useFSAL = " << useFSALste << 151 << " , useTemplated = " << use << 152 << " , useRegular = " << useRe << 153 << " , useFSAL = " << useFSALs << 154 << G4endl; << 155 } 101 } 156 #endif << 102 fIntgrDriver = new G4MagInt_Driver(stepMinimum, pItsStepper, >> 103 pItsStepper->GetNumberOfVariables() ); >> 104 } 157 105 158 // useHigherStepper = forceHigherEffiencySte << 106 // ...................................................................... 159 107 160 auto pEquation = new G4Mag_UsualEqRhs(theMa << 108 void 161 fEquation = pEquation; << 109 G4ChordFinder::SetFractions_Last_Next( G4double fractLast, G4double fractNext ) >> 110 { >> 111 // Use -1.0 as request for Default. >> 112 if( fractLast == -1.0 ) fractLast = 1.0; // 0.9; >> 113 if( fractNext == -1.0 ) fractNext = 0.98; // 0.9; >> 114 >> 115 // fFirstFraction = 0.999; // Orig 0.999 A safe value, range: ~ 0.95 - 0.999 >> 116 // fMultipleRadius = 15.0; // For later use, range: ~ 2 - 20 >> 117 >> 118 if( fStatsVerbose ) { >> 119 G4cout << " ChordFnd> Trying to set fractions: " >> 120 << " first " << fFirstFraction >> 121 << " last " << fractLast >> 122 << " next " << fractNext >> 123 << " and multiple " << fMultipleRadius >> 124 << G4endl; >> 125 } 162 126 163 // G4MagIntegratorStepper* regularStepper = << 127 if( (fractLast > 0.0) && (fractLast <=1.0) ) 164 // G4VFSALIntegrationStepper* fsalStepper = << 128 { fFractionLast= fractLast; } 165 // G4MagIntegratorStepper* oldFSALStepper = << 129 else >> 130 G4cerr << "G4ChordFinder:: SetFractions_Last_Next: Invalid " >> 131 << " fraction Last = " << fractLast >> 132 << " must be 0 < fractionLast <= 1 " << G4endl; >> 133 if( (fractNext > 0.0) && (fractNext <1.0) ) >> 134 { fFractionNextEstimate = fractNext; } >> 135 else >> 136 G4cerr << "G4ChordFinder:: SetFractions_Last_Next: Invalid " >> 137 << " fraction Next = " << fractNext >> 138 << " must be 0 < fractionNext < 1 " << G4endl; >> 139 } 166 140 167 G4bool errorInStepperCreation = false; << 141 // ...................................................................... 168 142 169 std::ostringstream message; // In case of f << 143 G4ChordFinder::~G4ChordFinder() >> 144 { >> 145 delete fEquation; // fIntgrDriver->pIntStepper->theEquation_Rhs; >> 146 if( fAllocatedStepper) >> 147 { >> 148 delete fDriversStepper; >> 149 } // fIntgrDriver->pIntStepper;} >> 150 delete fIntgrDriver; 170 151 171 if( pItsStepper != nullptr ) << 152 if( fStatsVerbose ) { PrintStatistics(); } 172 { << 153 } 173 if( gVerboseCtor ) << 174 { << 175 G4cout << " G4ChordFinder: Creating G4I << 176 << " stepMinimum = " << stepMini << 177 << " numVar= " << pItsStepper->G << 178 } << 179 154 180 // Stepper type is not known - so must us << 155 void 181 if(pItsStepper->isQSS()) << 156 G4ChordFinder::PrintStatistics() 182 { << 157 { 183 // fIntgrDriver = pItsStepper->build_ << 158 // Print Statistics 184 G4Exception("G4ChordFinder::G4ChordFi << 159 G4cout << "G4ChordFinder statistics report: " << G4endl; 185 "GeomField1001", FatalEx << 160 G4cout 186 "Cannot provide QSS ste << 161 << " No trials: " << fTotalNoTrials_FNC 187 } << 162 << " No Calls: " << fNoCalls_FNC 188 else << 163 << " Max-trial: " << fmaxTrials_FNC 189 { << 164 << G4endl; 190 fIntgrDriver = new G4IntegrationDrive << 165 G4cout 191 pItsStepper, << 166 << " Parameters: " 192 // Stepper type is not known - so mus << 167 << " fFirstFraction " << fFirstFraction 193 // Non-interpolating driver used by d << 168 << " fFractionLast " << fFractionLast 194 // WAS: fIntgrDriver = pItsStepper-> << 169 << " fFractionNextEstimate " << fFractionNextEstimate 195 } << 170 << G4endl; 196 // -- Older: << 171 } 197 // G4cout << " G4ChordFinder: Creating G4 << 172 198 // Type is not known - so must use old cl << 173 // ...................................................................... 199 // fIntgrDriver = new G4MagInt_Driver( st << 174 200 // pItsSt << 175 G4double >> 176 G4ChordFinder::AdvanceChordLimited( G4FieldTrack& yCurrent, >> 177 G4double stepMax, >> 178 G4double epsStep, >> 179 const G4ThreeVector latestSafetyOrigin, >> 180 G4double latestSafetyRadius >> 181 ) >> 182 { >> 183 G4double stepPossible; >> 184 G4double dyErr; >> 185 G4FieldTrack yEnd( yCurrent); >> 186 G4double startCurveLen= yCurrent.GetCurveLength(); >> 187 >> 188 G4double nextStep; >> 189 // ************* >> 190 stepPossible= FindNextChord(yCurrent, stepMax, yEnd, dyErr, epsStep, &nextStep >> 191 , latestSafetyOrigin, latestSafetyRadius >> 192 ); >> 193 // ************* >> 194 G4bool good_advance; >> 195 if ( dyErr < epsStep * stepPossible ) >> 196 { >> 197 // Accept this accuracy. >> 198 yCurrent = yEnd; >> 199 good_advance = true; 201 } 200 } 202 else if ( useTemplatedStepper ) << 201 else 203 { 202 { 204 if( gVerboseCtor ) << 203 // Advance more accurately to "end of chord" 205 { << 204 // *************** 206 G4cout << " G4ChordFinder: Creating Te << 205 good_advance = fIntgrDriver->AccurateAdvance(yCurrent, stepPossible, epsStep, nextStep); 207 << TemplatedStepperName << G4en << 206 // *************** >> 207 if ( ! good_advance ){ >> 208 // In this case the driver could not do the full distance >> 209 stepPossible= yCurrent.GetCurveLength()-startCurveLen; 208 } 210 } 209 // RegularStepperType* regularStepper = n << 210 auto templatedStepper = new TemplatedStep << 211 // *** *************** << 212 // << 213 // Alternative - for G4NystromRK4: << 214 // = new G4NystromRK4(pEquation, 0.1*mm ) << 215 fRegularStepperOwned = templatedStepper; << 216 if( templatedStepper == nullptr ) << 217 { << 218 message << "Templated Stepper instanti << 219 message << "G4ChordFinder: Attempted t << 220 << TemplatedStepperName << " t << 221 errorInStepperCreation = true; << 222 } << 223 else << 224 { << 225 fIntgrDriver = new G4IntegrationDriver << 226 stepMinimum, templatedStepper, nVar << 227 if( gVerboseCtor ) << 228 { << 229 G4cout << " G4ChordFinder: Using G4 << 230 } << 231 } << 232 << 233 } 211 } 234 else if ( useRegularStepper ) // Plain st << 212 235 { << 213 #ifdef G4DEBUG_FIELD 236 auto regularStepper = new RegularStepperT << 214 G4cout << "Exiting FindNextChord Limited with:" << G4endl 237 // *** *************** << 215 << " yCurrent: " << yCurrent<< G4endl; 238 fRegularStepperOwned = regularStepper; << 216 #endif 239 << 217 240 if( gVerboseCtor ) << 218 return stepPossible; 241 { << 219 } 242 G4cout << " G4ChordFinder: Creating Dr << 220 243 } << 221 // #define TEST_CHORD_PRINT 1 244 << 222 245 if( regularStepper == nullptr ) << 223 // ............................................................................ 246 { << 224 247 message << "Regular Stepper instantiat << 225 G4double 248 message << "G4ChordFinder: Attempted t << 226 G4ChordFinder::FindNextChord( const G4FieldTrack yStart, 249 << RegularStepperName << " typ << 227 G4double stepMax, 250 errorInStepperCreation = true; << 228 G4FieldTrack& yEnd, // Endpoint 251 } << 229 G4double& dyErrPos, // Error of endpoint 252 else << 230 G4double epsStep, 253 { << 231 G4double* pStepForAccuracy, 254 auto dp5= dynamic_cast<G4DormandPrince << 232 const G4ThreeVector, // latestSafetyOrigin, 255 if( dp5 != nullptr ) << 233 G4double // latestSafetyRadius 256 { << 234 ) 257 fIntgrDriver = new G4InterpolationD << 235 // Returns Length of Step taken 258 stepMinimum, << 236 { 259 if( gVerboseCtor ) << 237 // G4int stepRKnumber=0; 260 { << 238 G4FieldTrack yCurrent= yStart; 261 G4cout << " Using InterpolationD << 239 G4double stepTrial, stepForAccuracy; 262 } << 240 G4double dydx[G4FieldTrack::ncompSVEC]; 263 } << 241 >> 242 // 1.) Try to "leap" to end of interval >> 243 // 2.) Evaluate if resulting chord gives d_chord that is good enough. >> 244 // 2a.) If d_chord is not good enough, find one that is. >> 245 >> 246 G4bool validEndPoint= false; >> 247 G4double dChordStep, lastStepLength; // stepOfLastGoodChord; >> 248 >> 249 fIntgrDriver-> GetDerivatives( yCurrent, dydx ) ; >> 250 >> 251 G4int noTrials=0; >> 252 const G4double safetyFactor= fFirstFraction; // 0.975 or 0.99 ? was 0.999 >> 253 >> 254 stepTrial = std::min( stepMax, >> 255 safetyFactor * fLastStepEstimate_Unconstrained ); >> 256 >> 257 G4double newStepEst_Uncons= 0.0; >> 258 do >> 259 { >> 260 G4double stepForChord; >> 261 yCurrent = yStart; // Always start from initial point >> 262 >> 263 // ************ >> 264 fIntgrDriver->QuickAdvance( yCurrent, dydx, stepTrial, >> 265 dChordStep, dyErrPos); >> 266 // ************ >> 267 >> 268 // We check whether the criterion is met here. >> 269 validEndPoint = AcceptableMissDist(dChordStep); >> 270 // && (dyErrPos < eps) ; >> 271 >> 272 lastStepLength = stepTrial; >> 273 >> 274 // This method estimates to step size for a good chord. >> 275 stepForChord = NewStep(stepTrial, dChordStep, newStepEst_Uncons ); >> 276 >> 277 if( ! validEndPoint ) { >> 278 if( stepTrial<=0.0 ) >> 279 stepTrial = stepForChord; >> 280 else if (stepForChord <= stepTrial) >> 281 // Reduce by a fraction, possibly up to 20% >> 282 stepTrial = std::min( stepForChord, >> 283 fFractionLast * stepTrial); 264 else 284 else 265 { << 285 stepTrial *= 0.1; 266 fIntgrDriver = new G4IntegrationDri << 286 267 stepMinimum, << 287 // if(dbg) G4cerr<<"Dchord too big. Try new hstep="<<stepTrial<<G4endl; 268 if( gVerboseCtor ) << 269 { << 270 G4cout << " Using IntegrationDri << 271 } << 272 } << 273 } << 274 } << 275 else if ( useBfieldDriver ) << 276 { << 277 auto regularStepper = new G4DormandPrince << 278 // *** *************** << 279 // << 280 fRegularStepperOwned = regularStepper; << 281 << 282 { << 283 using SmallStepDriver = G4Interpolatio << 284 using LargeStepDriver = G4IntegrationD << 285 << 286 fLongStepper = std::make_unique<G4Heli << 287 << 288 fIntgrDriver = new G4BFieldIntegration << 289 std::make_unique<SmallStepDriver>(st << 290 regularStepper, regularStepper-> << 291 std::make_unique<LargeStepDriver>(st << 292 fLongStepper.get(), regularStepp << 293 << 294 if( fIntgrDriver == nullptr) << 295 { << 296 message << "Using G4BFieldIntegrati << 297 << RegularStepperName << " << 298 message << "Driver instantiation FA << 299 G4Exception("G4ChordFinder::G4Chord << 300 "GeomField1001", JustWa << 301 } << 302 } << 303 } << 304 else if( useG4QSSDriver ) << 305 { << 306 if( stepperDriverId == kQss2DriverType ) << 307 { << 308 auto qssStepper2 = G4QSSDriverCreator:: << 309 if( gVerboseCtor ) << 310 { << 311 G4cout << "-- Created QSS-2 stepper" << 312 } << 313 fIntgrDriver = G4QSSDriverCreator::Crea << 314 } << 315 else << 316 { << 317 auto qssStepper3 = G4QSSDriverCreator:: << 318 if( gVerboseCtor ) << 319 { << 320 G4cout << "-- Created QSS-3 stepper" << 321 } << 322 fIntgrDriver = G4QSSDriverCreator::Crea << 323 } << 324 if( gVerboseCtor ) << 325 { << 326 G4cout << "-- G4ChordFinder: Using QSS << 327 } 288 } >> 289 // #ifdef TEST_CHORD_PRINT >> 290 // TestChordPrint( noTrials, lastStepLength, dChordStep, stepTrial ); >> 291 // #endif >> 292 >> 293 noTrials++; 328 } 294 } 329 else << 295 while( ! validEndPoint ); // End of do-while RKD 330 { << 296 331 auto fsalStepper= new NewFsalStepperType << 297 if( newStepEst_Uncons > 0.0 ){ 332 // *** ****************** << 298 fLastStepEstimate_Unconstrained= newStepEst_Uncons; 333 fNewFSALStepperOwned = fsalStepper; << 334 << 335 if( fsalStepper == nullptr ) << 336 { << 337 message << "Stepper instantiation FAIL << 338 message << "Attempted to instantiate " << 339 << NewFSALStepperName << " typ << 340 G4Exception("G4ChordFinder::G4ChordFin << 341 "GeomField1001", JustWarni << 342 errorInStepperCreation = true; << 343 } << 344 else << 345 { << 346 fIntgrDriver = new << 347 G4FSALIntegrationDriver<NewFsalStep << 348 fsal << 349 // ==== Create the driver which k << 350 << 351 if( fIntgrDriver == nullptr ) << 352 { << 353 message << "Using G4FSALIntegration << 354 << NewFSALStepperName << G4 << 355 message << "Integration Driver inst << 356 G4Exception("G4ChordFinder::G4Chord << 357 "GeomField1001", JustWa << 358 } << 359 } << 360 } 299 } 361 300 362 // -- Main work is now done << 301 AccumulateStatistics( noTrials ); 363 << 302 364 // Now check that no error occured, and r << 303 // stepOfLastGoodChord = stepTrial; 365 << 304 366 // To test failure to create driver << 305 if( pStepForAccuracy ){ 367 // delete fIntgrDriver; << 306 // Calculate the step size required for accuracy, if it is needed 368 // fIntgrDriver = nullptr; << 307 G4double dyErr_relative = dyErrPos/(epsStep*lastStepLength); 369 << 308 if( dyErr_relative > 1.0 ) { 370 // Detect and report Error conditions << 309 stepForAccuracy = 371 // << 310 fIntgrDriver->ComputeNewStepSize( dyErr_relative, 372 if( errorInStepperCreation || (fIntgrDriver << 311 lastStepLength ); 373 { << 312 }else{ 374 std::ostringstream errmsg; << 313 stepForAccuracy = 0.0; // Convention to show step was ok 375 << 376 if( errorInStepperCreation ) << 377 { << 378 errmsg << "ERROR> Failure to create S << 379 << " ------------------- << 380 } << 381 if (fIntgrDriver == nullptr ) << 382 { << 383 errmsg << "ERROR> Failure to create I << 384 << G4endl << 385 << " ------------------- << 386 << G4endl; << 387 } 314 } 388 const std::string BoolName[2]= { "False", << 315 *pStepForAccuracy = stepForAccuracy; 389 errmsg << " Configuration: (constructor << 390 << " provided Stepper = " << pI << 391 << " stepper/driver Id = " << step << 392 << " useTemplated = " << BoolNam << 393 << " useRegular = " << BoolName[ << 394 << " useFSAL = " << BoolName[use << 395 << " using combo BField Driver = << 396 BoolName[ ! (useFSALstepper << 397 || useRegularSt << 398 << G4endl; << 399 errmsg << message.str(); << 400 errmsg << "Aborting."; << 401 G4Exception("G4ChordFinder::G4ChordFinder << 402 "GeomField0003", FatalExcepti << 403 } 316 } 404 317 405 assert( ( pItsStepper != nullptr ) << 318 #ifdef TEST_CHORD_PRINT 406 || ( fRegularStepperOwned != nullptr << 319 static int dbg=0; 407 || ( fNewFSALStepperOwned != nullptr << 320 if( dbg ) 408 || useG4QSSDriver << 321 G4cout << "ChordF/FindNextChord: NoTrials= " << noTrials 409 ); << 322 << " StepForGoodChord=" << std::setw(10) << stepTrial << G4endl; 410 assert( fIntgrDriver != nullptr ); << 323 #endif 411 } << 412 324 413 // ........................................... << 325 yEnd= yCurrent; >> 326 return stepTrial; >> 327 } 414 328 415 G4ChordFinder::~G4ChordFinder() << 329 // ---------------------------------------------------------------------------- 416 { << 330 #if 0 417 delete fEquation; << 331 // #ifdef G4VERBOSE 418 delete fRegularStepperOwned; << 332 if( dbg ) { 419 delete fNewFSALStepperOwned; << 333 G4cerr << "Returned from QuickAdvance with: yCur=" << yCurrent <<G4endl; 420 delete fCachedField; << 334 G4cerr << " dChordStep= "<< dChordStep <<" dyErr=" << dyErr << G4endl; 421 delete fIntgrDriver; << 422 } 335 } >> 336 #endif >> 337 // ---------------------------------------------------------------------------- 423 338 424 // ........................................... 339 // ........................................................................... 425 340 426 G4FieldTrack << 341 G4double G4ChordFinder::NewStep(G4double stepTrialOld, 427 G4ChordFinder::ApproxCurvePointS( const G4Fiel << 342 G4double dChordStep, // Curr. dchord achieved 428 const G4Fiel << 343 G4double& stepEstimate_Unconstrained ) 429 const G4Fiel << 344 // 430 const G4Thre << 345 // Is called to estimate the next step size, even for successful steps, 431 const G4Thre << 346 // in order to predict an accurate 'chord-sensitive' first step 432 const G4Thre << 347 // which is likely to assist in more performant 'stepping'. 433 G4bool << 348 // >> 349 434 { 350 { 435 // ApproxCurvePointS is 2nd implementation o << 351 G4double stepTrial; 436 // Use Brent Algorithm (or InvParabolic) whe << 352 static G4double lastStepTrial = 1., lastDchordStep= 1.; 437 // Given a starting curve point A (CurveA_Po << 438 // (CurveB_PointVelocity), a point E which i << 439 // and a point F which is on the curve (fir << 440 // point S on the curve closer to point E. << 441 // While advancing towards S utilise 'eps_st << 442 // relative accuracy of each Step. << 443 << 444 G4FieldTrack EndPoint(CurveA_PointVelocity); << 445 if(!first) { EndPoint = ApproxCurveV; } << 446 << 447 G4ThreeVector Point_A,Point_B; << 448 Point_A=CurveA_PointVelocity.GetPosition(); << 449 Point_B=CurveB_PointVelocity.GetPosition(); << 450 << 451 G4double xa,xb,xc,ya,yb,yc; << 452 << 453 // InverseParabolic. AF Intersects (First Pa << 454 353 455 if(first) << 354 #if 1 456 { << 355 // const G4double threshold = 1.21, multiplier = 0.9; 457 xa=0.; << 356 // 0.9 < 1 / std::sqrt(1.21) 458 ya=(PointG-Point_A).mag(); << 357 459 xb=(Point_A-CurrentF_Point).mag(); << 358 if (dChordStep > 0.0) 460 yb=-(PointG-CurrentF_Point).mag(); << 359 { 461 xc=(Point_A-Point_B).mag(); << 360 stepEstimate_Unconstrained = stepTrialOld*std::sqrt( fDeltaChord / dChordStep ); 462 yc=-(CurrentE_Point-Point_B).mag(); << 361 // stepTrial = 0.98 * stepEstimate_Unconstrained; 463 } << 362 stepTrial = fFractionNextEstimate * stepEstimate_Unconstrained; >> 363 } 464 else 364 else 465 { 365 { 466 xa=0.; << 366 // Should not update the Unconstrained Step estimate: incorrect! 467 ya=(Point_A-CurrentE_Point).mag(); << 367 stepTrial = stepTrialOld * 2.; 468 xb=(Point_A-CurrentF_Point).mag(); << 469 yb=(PointG-CurrentF_Point).mag(); << 470 xc=(Point_A-Point_B).mag(); << 471 yc=-(Point_B-PointG).mag(); << 472 if(xb==0.) << 473 { << 474 EndPoint = ApproxCurvePointV(CurveA_Poin << 475 CurrentE_Po << 476 return EndPoint; << 477 } << 478 } 368 } 479 369 480 const G4double tolerance = 1.e-12; << 370 // if ( dChordStep < threshold * fDeltaChord ){ 481 if(std::abs(ya)<=tolerance||std::abs(yc)<=to << 371 // stepTrial= stepTrialOld * multiplier; >> 372 // } >> 373 if( stepTrial <= 0.001 * stepTrialOld) >> 374 { >> 375 if ( dChordStep > 1000.0 * fDeltaChord ){ >> 376 stepTrial= stepTrialOld * 0.03; >> 377 }else{ >> 378 if ( dChordStep > 100. * fDeltaChord ){ >> 379 stepTrial= stepTrialOld * 0.1; >> 380 }else{ >> 381 // Try halving the length until dChordStep OK >> 382 stepTrial= stepTrialOld * 0.5; >> 383 } >> 384 } >> 385 }else if (stepTrial > 1000.0 * stepTrialOld) 482 { 386 { 483 ; // What to do for the moment: return the << 387 stepTrial= 1000.0 * stepTrialOld; 484 // then PropagatorInField will take care << 485 } 388 } 486 else << 487 { << 488 G4double test_step = InvParabolic(xa,ya,xb << 489 G4double curve; << 490 if(first) << 491 { << 492 curve=std::abs(EndPoint.GetCurveLength() << 493 -ApproxCurveV.GetCurveLeng << 494 } << 495 else << 496 { << 497 test_step = test_step - xb; << 498 curve=std::abs(EndPoint.GetCurveLength() << 499 -CurveB_PointVelocity.GetC << 500 xb = (CurrentF_Point-Point_B).mag(); << 501 } << 502 << 503 if(test_step<=0) { test_step=0.1*xb; } << 504 if(test_step>=xb) { test_step=0.5*xb; } << 505 if(test_step>=curve){ test_step=0.5*curve; << 506 << 507 if(curve*(1.+eps_step)<xb) // Similar to R << 508 { // G4VIntersect << 509 test_step=0.5*curve; << 510 } << 511 389 512 fIntgrDriver->AccurateAdvance(EndPoint,tes << 390 if( stepTrial == 0.0 ){ 513 << 391 stepTrial= 0.000001; 514 #ifdef G4DEBUG_FIELD << 515 // Printing Brent and Linear Approximation << 516 // << 517 G4cout << "G4ChordFinder::ApproxCurvePoint << 518 << test_step << " EndPoint = " << << 519 << 520 // Test Track << 521 // << 522 G4FieldTrack TestTrack( CurveA_PointVeloci << 523 TestTrack = ApproxCurvePointV( CurveA_Poin << 524 CurveB_Poin << 525 CurrentE_Po << 526 G4cout.precision(14); << 527 G4cout << "G4ChordFinder::BrentApprox = " << 528 G4cout << "G4ChordFinder::LinearApprox= " << 529 #endif << 530 } 392 } 531 return EndPoint; << 532 } << 533 393 >> 394 lastStepTrial = stepTrialOld; >> 395 lastDchordStep= dChordStep; >> 396 #else >> 397 if ( dChordStep > 1000. * fDeltaChord ){ >> 398 stepTrial= stepTrialOld * 0.03; >> 399 }else{ >> 400 if ( dChordStep > 100. * fDeltaChord ){ >> 401 stepTrial= stepTrialOld * 0.1; >> 402 }else{ >> 403 // Keep halving the length until dChordStep OK >> 404 stepTrial= stepTrialOld * 0.5; >> 405 } >> 406 } >> 407 #endif >> 408 >> 409 // A more sophisticated chord-finder could figure out a better >> 410 // stepTrial, from dChordStep and the required d_geometry >> 411 // eg >> 412 // Calculate R, r_helix (eg at orig point) >> 413 // if( stepTrial < 2 pi R ) >> 414 // stepTrial = R arc_cos( 1 - fDeltaChord / r_helix ) >> 415 // else >> 416 // ?? 534 417 535 // ........................................... << 418 return stepTrial; >> 419 } 536 420 537 G4FieldTrack G4ChordFinder:: << 421 // 538 ApproxCurvePointV( const G4FieldTrack& CurveA_ << 422 // Given a starting curve point A (CurveA_PointVelocity), a later 539 const G4FieldTrack& CurveB_ << 423 // curve point B (CurveB_PointVelocity) and a point E which is (generally) 540 const G4ThreeVector& Curren << 424 // not on the curve, find and return a point F which is on the curve and 541 G4double eps_step) << 425 // which is close to E. While advancing towards F utilise eps_step >> 426 // as a measure of the relative accuracy of each Step. >> 427 >> 428 G4FieldTrack >> 429 G4ChordFinder::ApproxCurvePointV( const G4FieldTrack& CurveA_PointVelocity, >> 430 const G4FieldTrack& CurveB_PointVelocity, >> 431 const G4ThreeVector& CurrentE_Point, >> 432 G4double eps_step) 542 { 433 { 543 // If r=|AE|/|AB|, and s=true path lenght (A << 434 // 1st implementation: 544 // return the point that is r*s along the cu << 435 // if r=|AE|/|AB|, and s=true path lenght (AB) 545 << 436 // return the point that is r*s along the curve! 546 G4FieldTrack Current_PointVelocity = Curve << 437 >> 438 G4FieldTrack Current_PointVelocity= CurveA_PointVelocity; 547 439 548 G4ThreeVector CurveA_Point= CurveA_PointVel 440 G4ThreeVector CurveA_Point= CurveA_PointVelocity.GetPosition(); 549 G4ThreeVector CurveB_Point= CurveB_PointVel 441 G4ThreeVector CurveB_Point= CurveB_PointVelocity.GetPosition(); 550 442 551 G4ThreeVector ChordAB_Vector= CurveB_Point 443 G4ThreeVector ChordAB_Vector= CurveB_Point - CurveA_Point; 552 G4ThreeVector ChordAE_Vector= CurrentE_Poin 444 G4ThreeVector ChordAE_Vector= CurrentE_Point - CurveA_Point; 553 445 554 G4double ABdist= ChordAB_Vector.mag(); 446 G4double ABdist= ChordAB_Vector.mag(); 555 G4double curve_length; // A curve length 447 G4double curve_length; // A curve length of AB 556 G4double AE_fraction; 448 G4double AE_fraction; 557 449 558 curve_length= CurveB_PointVelocity.GetCurveL 450 curve_length= CurveB_PointVelocity.GetCurveLength() 559 - CurveA_PointVelocity.GetCurveL 451 - CurveA_PointVelocity.GetCurveLength(); 560 << 452 561 G4double integrationInaccuracyLimit= std::ma << 453 // const 562 if( curve_length < ABdist * (1. - integratio << 454 G4double integrationInaccuracyLimit= std::max( perMillion, 0.5*eps_step ); 563 { << 455 if( curve_length < ABdist * (1. - integrationInaccuracyLimit) ){ 564 #ifdef G4DEBUG_FIELD 456 #ifdef G4DEBUG_FIELD 565 G4cerr << " Warning in G4ChordFinder::Appr 457 G4cerr << " Warning in G4ChordFinder::ApproxCurvePoint: " 566 << G4endl 458 << G4endl 567 << " The two points are further apa 459 << " The two points are further apart than the curve length " 568 << G4endl 460 << G4endl 569 << " Dist = " << ABdist 461 << " Dist = " << ABdist 570 << " curve length = " << curve_leng 462 << " curve length = " << curve_length 571 << " relativeDiff = " << (curve_len 463 << " relativeDiff = " << (curve_length-ABdist)/ABdist 572 << G4endl; 464 << G4endl; 573 if( curve_length < ABdist * (1. - 10*eps_s << 465 if( curve_length < ABdist * (1. - 10*eps_step) ) { 574 { << 466 G4cerr << " ERROR: the size of the above difference" 575 std::ostringstream message; << 467 << " exceeds allowed limits. Aborting." << G4endl; 576 message << "Unphysical curve length." << << 468 G4Exception("G4ChordFinder::ApproxCurvePointV()", "PrecisionError", 577 << "The size of the above differ << 469 FatalException, "Unphysical curve length."); 578 << G4endl << 579 << "Aborting."; << 580 G4Exception("G4ChordFinder::ApproxCurveP << 581 FatalException, message); << 582 } 470 } 583 #endif 471 #endif 584 // Take default corrective action: adjust << 472 // Take default corrective action: 585 // NOTE: this case only happens for relati << 473 // --> adjust the maximum curve length. 586 // curve_length = ABdist; << 474 // NOTE: this case only happens for relatively straight paths. >> 475 curve_length = ABdist; 587 } 476 } 588 477 589 G4double new_st_length; << 478 G4double new_st_length; 590 479 591 if ( ABdist > 0.0 ) << 480 if ( ABdist > 0.0 ){ 592 { << 593 AE_fraction = ChordAE_Vector.mag() / ABdi 481 AE_fraction = ChordAE_Vector.mag() / ABdist; 594 } << 482 }else{ 595 else << 596 { << 597 AE_fraction = 0.5; 483 AE_fraction = 0.5; // Guess .. ?; 598 #ifdef G4DEBUG_FIELD 484 #ifdef G4DEBUG_FIELD 599 G4cout << "Warning in G4ChordFinder::Appr << 485 G4cout << "Warning in G4ChordFinder::ApproxCurvePoint:" 600 << " A and B are the same point!" 486 << " A and B are the same point!" << G4endl 601 << " Chord AB length = " << ChordA 487 << " Chord AB length = " << ChordAE_Vector.mag() << G4endl 602 << G4endl; 488 << G4endl; 603 #endif 489 #endif 604 } 490 } 605 491 606 if( (AE_fraction> 1.0 + perMillion) || (AE_f << 492 if( (AE_fraction> 1.0 + perMillion) || (AE_fraction< 0.) ){ 607 { << 608 #ifdef G4DEBUG_FIELD 493 #ifdef G4DEBUG_FIELD 609 G4cerr << " G4ChordFinder::ApproxCurvePoin << 494 G4cerr << " G4ChordFinder::ApproxCurvePointV - Warning:" 610 << " Anomalous condition:AE > AB or 495 << " Anomalous condition:AE > AB or AE/AB <= 0 " << G4endl 611 << " AE_fraction = " << AE_fract 496 << " AE_fraction = " << AE_fraction << G4endl 612 << " Chord AE length = " << Chord 497 << " Chord AE length = " << ChordAE_Vector.mag() << G4endl 613 << " Chord AB length = " << ABdis 498 << " Chord AB length = " << ABdist << G4endl << G4endl; 614 G4cerr << " OK if this condition occurs af 499 G4cerr << " OK if this condition occurs after a recalculation of 'B'" 615 << G4endl << " Otherwise it is an e 500 << G4endl << " Otherwise it is an error. " << G4endl ; 616 #endif 501 #endif 617 // This course can now result if B has be 502 // This course can now result if B has been re-evaluated, 618 // without E being recomputed (1 July 99) << 503 // without E being recomputed (1 July 99) 619 // In this case this is not a "real error << 504 // In this case this is not a "real error" - but it undesired 620 // and we cope with it by a default corre << 505 // and we cope with it by a default corrective action ... 621 // << 622 AE_fraction = 0.5; 506 AE_fraction = 0.5; // Default value 623 } 507 } 624 508 625 new_st_length = AE_fraction * curve_length; << 509 new_st_length= AE_fraction * curve_length; 626 510 627 if ( AE_fraction > 0.0 ) << 511 G4bool good_advance; 628 { << 512 if ( AE_fraction > 0.0 ) { 629 fIntgrDriver->AccurateAdvance(Current_Poi << 513 good_advance = 630 new_st_leng << 514 fIntgrDriver->AccurateAdvance(Current_PointVelocity, 631 // << 515 new_st_length, >> 516 eps_step ); // Relative accuracy 632 // In this case it does not matter if it 517 // In this case it does not matter if it cannot advance the full distance 633 } 518 } 634 519 635 // If there was a memory of the step_length << 520 // If there was a memory of the step_length actually require at the start 636 // of the integration Step, this could be re 521 // of the integration Step, this could be re-used ... 637 522 638 G4cout.precision(14); << 639 << 640 return Current_PointVelocity; 523 return Current_PointVelocity; 641 } 524 } 642 525 643 // ........................................... << 526 void 644 << 527 G4ChordFinder::TestChordPrint( G4int noTrials, 645 std::ostream& operator<<( std::ostream& os, co << 528 G4int lastStepTrial, >> 529 G4double dChordStep, >> 530 G4double nextStepTrial ) 646 { 531 { 647 // Dumping the state of G4ChordFinder << 532 G4int oldprec= G4cout.precision(5); 648 os << "State of G4ChordFinder : " << std::e << 533 G4cout << " ChF/fnc: notrial " << std::setw( 3) << noTrials 649 os << " delta_chord = " << cf.fDeltaCh << 534 << " this_step= " << std::setw(10) << lastStepTrial; 650 os << " Default d_c = " << cf.fDefault << 535 if( std::fabs( (dChordStep / fDeltaChord) - 1.0 ) < 0.001 ){ 651 << 536 G4cout.precision(8); 652 os << " stats-verbose = " << cf.fStatsVe << 537 }else{ G4cout.precision(6); } 653 << 538 G4cout << " dChordStep= " << std::setw(12) << dChordStep; 654 return os; << 539 if( dChordStep > fDeltaChord ) { G4cout << " d+"; } >> 540 else { G4cout << " d-"; } >> 541 G4cout.precision(5); >> 542 G4cout << " new_step= " << std::setw(10) >> 543 << fLastStepEstimate_Unconstrained >> 544 << " new_step_constr= " << std::setw(10) >> 545 << lastStepTrial << G4endl; >> 546 G4cout << " nextStepTrial = " << std::setw(10) << nextStepTrial << G4endl; >> 547 G4cout.precision(oldprec); 655 } 548 } 656 549