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 // >> 27 // $Id$ >> 28 // >> 29 // 26 // class G4VoxelNavigation Implementation 30 // class G4VoxelNavigation Implementation 27 // 31 // 28 // Author: P.Kent, 1996 32 // Author: P.Kent, 1996 29 // 33 // 30 // ------------------------------------------- 34 // -------------------------------------------------------------------- >> 35 31 #include "G4VoxelNavigation.hh" 36 #include "G4VoxelNavigation.hh" 32 #include "G4GeometryTolerance.hh" 37 #include "G4GeometryTolerance.hh" 33 #include "G4VoxelSafety.hh" 38 #include "G4VoxelSafety.hh" 34 39 35 #include "G4AuxiliaryNavServices.hh" << 36 << 37 #include <cassert> << 38 #include <ostream> << 39 << 40 // ******************************************* 40 // ******************************************************************** 41 // Constructor 41 // Constructor 42 // ******************************************* 42 // ******************************************************************** 43 // 43 // 44 G4VoxelNavigation::G4VoxelNavigation() 44 G4VoxelNavigation::G4VoxelNavigation() 45 : fVoxelAxisStack(kNavigatorVoxelStackMax,kX << 45 : fBList(), fVoxelDepth(-1), >> 46 fVoxelAxisStack(kNavigatorVoxelStackMax,kXAxis), 46 fVoxelNoSlicesStack(kNavigatorVoxelStackMa 47 fVoxelNoSlicesStack(kNavigatorVoxelStackMax,0), 47 fVoxelSliceWidthStack(kNavigatorVoxelStack 48 fVoxelSliceWidthStack(kNavigatorVoxelStackMax,0.), 48 fVoxelNodeNoStack(kNavigatorVoxelStackMax, 49 fVoxelNodeNoStack(kNavigatorVoxelStackMax,0), 49 fVoxelHeaderStack(kNavigatorVoxelStackMax, << 50 fVoxelHeaderStack(kNavigatorVoxelStackMax,(G4SmartVoxelHeader*)0), >> 51 fVoxelNode(0), fpVoxelSafety(0), fCheck(false), fBestSafety(false) 50 { 52 { 51 fLogger= new G4NavigationLogger("G4VoxelNavi << 53 fLogger = new G4NavigationLogger("G4VoxelNavigation"); 52 fpVoxelSafety= new G4VoxelSafety(); << 54 fpVoxelSafety = new G4VoxelSafety (); 53 fHalfTolerance= 0.5*G4GeometryTolerance::Get << 54 << 55 #ifdef G4DEBUG_NAVIGATION << 56 SetVerboseLevel(5); // Reports most about << 57 #endif << 58 } 55 } 59 56 60 // ******************************************* 57 // ******************************************************************** 61 // Destructor 58 // Destructor 62 // ******************************************* 59 // ******************************************************************** 63 // 60 // 64 G4VoxelNavigation::~G4VoxelNavigation() 61 G4VoxelNavigation::~G4VoxelNavigation() 65 { 62 { 66 delete fpVoxelSafety; 63 delete fpVoxelSafety; 67 delete fLogger; 64 delete fLogger; 68 } 65 } 69 66 70 // ------------------------------------------- << 71 // Input: << 72 // exiting: : last step exited << 73 // blockedPhysical : phys volume last exit << 74 // blockedReplicaNo : copy/replica number o << 75 // Output: << 76 // entering : if true, found candid << 77 // blockedPhysical : candidate phys volume << 78 // blockedReplicaNo : copy/replica number << 79 // exiting: : will exit current (mo << 80 // In/Out << 81 // ------------------------------------------- << 82 << 83 // ******************************************* 67 // ******************************************************************** 84 // ComputeStep 68 // ComputeStep 85 // ******************************************* 69 // ******************************************************************** 86 // 70 // 87 G4double 71 G4double 88 G4VoxelNavigation::ComputeStep( const G4ThreeV 72 G4VoxelNavigation::ComputeStep( const G4ThreeVector& localPoint, 89 const G4ThreeV 73 const G4ThreeVector& localDirection, 90 const G4double 74 const G4double currentProposedStepLength, 91 G4double 75 G4double& newSafety, 92 /* const */ G4Naviga << 76 G4NavigationHistory& history, 93 G4bool& 77 G4bool& validExitNormal, 94 G4ThreeV 78 G4ThreeVector& exitNormal, 95 G4bool& 79 G4bool& exiting, 96 G4bool& 80 G4bool& entering, 97 G4VPhysi << 81 G4VPhysicalVolume *(*pBlockedPhysical), 98 G4int& b 82 G4int& blockedReplicaNo ) 99 { 83 { 100 G4VPhysicalVolume *motherPhysical, *samplePh << 84 G4VPhysicalVolume *motherPhysical, *samplePhysical, *blockedExitedVol=0; 101 G4LogicalVolume *motherLogical; 85 G4LogicalVolume *motherLogical; 102 G4VSolid *motherSolid; 86 G4VSolid *motherSolid; 103 G4ThreeVector sampleDirection; 87 G4ThreeVector sampleDirection; 104 G4double ourStep=currentProposedStepLength, << 88 G4double ourStep=currentProposedStepLength, motherSafety, ourSafety; 105 G4double motherSafety, motherStep = DBL_MAX; << 106 G4int localNoDaughters, sampleNo; 89 G4int localNoDaughters, sampleNo; 107 90 108 G4bool initialNode, noStep; 91 G4bool initialNode, noStep; 109 G4SmartVoxelNode *curVoxelNode; 92 G4SmartVoxelNode *curVoxelNode; 110 G4long curNoVolumes, contentNo; << 93 G4int curNoVolumes, contentNo; 111 G4double voxelSafety; 94 G4double voxelSafety; 112 95 113 motherPhysical = history.GetTopVolume(); 96 motherPhysical = history.GetTopVolume(); 114 motherLogical = motherPhysical->GetLogicalVo 97 motherLogical = motherPhysical->GetLogicalVolume(); 115 motherSolid = motherLogical->GetSolid(); 98 motherSolid = motherLogical->GetSolid(); 116 99 117 // 100 // 118 // Compute mother safety 101 // Compute mother safety 119 // 102 // 120 103 121 motherSafety = motherSolid->DistanceToOut(lo 104 motherSafety = motherSolid->DistanceToOut(localPoint); 122 ourSafety = motherSafety; // 105 ourSafety = motherSafety; // Working isotropic safety 123 106 124 #ifdef G4VERBOSE 107 #ifdef G4VERBOSE 125 if ( fCheck ) 108 if ( fCheck ) 126 { 109 { 127 fLogger->PreComputeStepLog (motherPhysical 110 fLogger->PreComputeStepLog (motherPhysical, motherSafety, localPoint); 128 } 111 } 129 #endif 112 #endif 130 113 131 // 114 // 132 // Compute daughter safeties & intersections 115 // Compute daughter safeties & intersections 133 // 116 // 134 117 135 // Exiting normal optimisation 118 // Exiting normal optimisation 136 // 119 // 137 if ( exiting && validExitNormal ) 120 if ( exiting && validExitNormal ) 138 { 121 { 139 if ( localDirection.dot(exitNormal)>=kMinE 122 if ( localDirection.dot(exitNormal)>=kMinExitingNormalCosine ) 140 { 123 { 141 // Block exited daughter volume 124 // Block exited daughter volume 142 // 125 // 143 blockedExitedVol = *pBlockedPhysical; 126 blockedExitedVol = *pBlockedPhysical; 144 ourSafety = 0; 127 ourSafety = 0; 145 } 128 } 146 } 129 } 147 exiting = false; 130 exiting = false; 148 entering = false; 131 entering = false; 149 132 150 // For extra checking, get the distance to << 133 localNoDaughters = motherLogical->GetNoDaughters(); 151 G4bool motherValidExitNormal = false; << 152 G4ThreeVector motherExitNormal(0.0, 0.0, 0.0 << 153 << 154 #ifdef G4VERBOSE << 155 if ( fCheck ) << 156 { << 157 // Compute early -- a) for validity << 158 // b) to check against an << 159 motherStep = motherSolid->DistanceToOut(lo << 160 lo << 161 tr << 162 &mo << 163 &mo << 164 } << 165 #endif << 166 << 167 localNoDaughters = (G4int)motherLogical->Get << 168 134 169 fBList.Enlarge(localNoDaughters); 135 fBList.Enlarge(localNoDaughters); 170 fBList.Reset(); 136 fBList.Reset(); 171 137 172 initialNode = true; 138 initialNode = true; 173 noStep = true; 139 noStep = true; 174 140 175 while (noStep) 141 while (noStep) 176 { 142 { 177 curVoxelNode = fVoxelNode; 143 curVoxelNode = fVoxelNode; 178 curNoVolumes = curVoxelNode->GetNoContaine 144 curNoVolumes = curVoxelNode->GetNoContained(); 179 for (contentNo=curNoVolumes-1; contentNo>= 145 for (contentNo=curNoVolumes-1; contentNo>=0; contentNo--) 180 { 146 { 181 sampleNo = curVoxelNode->GetVolume((G4in << 147 sampleNo = curVoxelNode->GetVolume(contentNo); 182 if ( !fBList.IsBlocked(sampleNo) ) 148 if ( !fBList.IsBlocked(sampleNo) ) 183 { 149 { 184 fBList.BlockVolume(sampleNo); 150 fBList.BlockVolume(sampleNo); 185 samplePhysical = motherLogical->GetDau 151 samplePhysical = motherLogical->GetDaughter(sampleNo); 186 if ( samplePhysical!=blockedExitedVol 152 if ( samplePhysical!=blockedExitedVol ) 187 { 153 { 188 G4AffineTransform sampleTf(samplePhy 154 G4AffineTransform sampleTf(samplePhysical->GetRotation(), 189 samplePhy 155 samplePhysical->GetTranslation()); 190 sampleTf.Invert(); 156 sampleTf.Invert(); 191 const G4ThreeVector samplePoint = 157 const G4ThreeVector samplePoint = 192 sampleTf.TransformPoint(l 158 sampleTf.TransformPoint(localPoint); 193 const G4VSolid *sampleSolid = 159 const G4VSolid *sampleSolid = 194 samplePhysical->GetLogica 160 samplePhysical->GetLogicalVolume()->GetSolid(); 195 const G4double sampleSafety = 161 const G4double sampleSafety = 196 sampleSolid->DistanceToIn 162 sampleSolid->DistanceToIn(samplePoint); 197 << 163 #ifdef G4VERBOSE >> 164 if( fCheck ) >> 165 { >> 166 fLogger->PrintDaughterLog(sampleSolid,samplePoint,sampleSafety,0); >> 167 } >> 168 #endif 198 if ( sampleSafety<ourSafety ) 169 if ( sampleSafety<ourSafety ) 199 { 170 { 200 ourSafety = sampleSafety; 171 ourSafety = sampleSafety; 201 } 172 } 202 if ( sampleSafety<=ourStep ) 173 if ( sampleSafety<=ourStep ) 203 { 174 { 204 sampleDirection = sampleTf.Transfo 175 sampleDirection = sampleTf.TransformAxis(localDirection); 205 G4double sampleStep = 176 G4double sampleStep = 206 sampleSolid->DistanceToIn 177 sampleSolid->DistanceToIn(samplePoint, sampleDirection); 207 #ifdef G4VERBOSE 178 #ifdef G4VERBOSE 208 if( fCheck ) 179 if( fCheck ) 209 { 180 { 210 fLogger->PrintDaughterLog(sample 181 fLogger->PrintDaughterLog(sampleSolid, samplePoint, 211 sample << 182 sampleSafety, sampleStep); 212 sample << 213 } 183 } 214 #endif 184 #endif 215 if ( sampleStep<=ourStep ) 185 if ( sampleStep<=ourStep ) 216 { 186 { 217 ourStep = sampleStep; 187 ourStep = sampleStep; 218 entering = true; 188 entering = true; 219 exiting = false; 189 exiting = false; 220 *pBlockedPhysical = samplePhysic 190 *pBlockedPhysical = samplePhysical; 221 blockedReplicaNo = -1; 191 blockedReplicaNo = -1; 222 #ifdef G4VERBOSE 192 #ifdef G4VERBOSE 223 // Check to see that the resulti 193 // Check to see that the resulting point is indeed in/on volume. 224 // This could be done only for s << 194 // This check could eventually be made only for successful >> 195 // candidate. >> 196 225 if ( fCheck ) 197 if ( fCheck ) 226 { 198 { 227 fLogger->AlongComputeStepLog ( 199 fLogger->AlongComputeStepLog (sampleSolid, samplePoint, 228 sampleDirection, localDirect 200 sampleDirection, localDirection, sampleSafety, sampleStep); 229 } 201 } 230 #endif 202 #endif 231 } 203 } 232 #ifdef G4VERBOSE << 233 if ( fCheck && ( sampleStep < kInf << 234 && ( sampleStep >= mot << 235 { << 236 // The intersection point with << 237 // point from the mother volume << 238 fLogger->CheckDaughterEntryPoin << 239 << 240 << 241 << 242 << 243 } << 244 #endif << 245 } << 246 #ifdef G4VERBOSE << 247 else // ie if sampleSafety > outStep << 248 { << 249 if( fCheck ) << 250 { << 251 fLogger->PrintDaughterLog(sample << 252 sample << 253 G4Thre << 254 } << 255 } 204 } 256 #endif << 257 } 205 } 258 } 206 } 259 } 207 } 260 if (initialNode) 208 if (initialNode) 261 { 209 { 262 initialNode = false; 210 initialNode = false; 263 voxelSafety = ComputeVoxelSafety(localPo 211 voxelSafety = ComputeVoxelSafety(localPoint); 264 if ( voxelSafety<ourSafety ) 212 if ( voxelSafety<ourSafety ) 265 { 213 { 266 ourSafety = voxelSafety; 214 ourSafety = voxelSafety; 267 } 215 } 268 if ( currentProposedStepLength<ourSafety 216 if ( currentProposedStepLength<ourSafety ) 269 { 217 { 270 // Guaranteed physics limited 218 // Guaranteed physics limited 271 // 219 // 272 noStep = false; 220 noStep = false; 273 entering = false; 221 entering = false; 274 exiting = false; 222 exiting = false; 275 *pBlockedPhysical = nullptr; << 223 *pBlockedPhysical = 0; 276 ourStep = kInfinity; 224 ourStep = kInfinity; 277 } 225 } 278 else 226 else 279 { 227 { 280 // 228 // 281 // Compute mother intersection if requ 229 // Compute mother intersection if required 282 // 230 // 283 if ( motherSafety<=ourStep ) 231 if ( motherSafety<=ourStep ) 284 { 232 { 285 // In case of check mode this is a d << 233 G4double motherStep = 286 motherStep = motherSolid->DistanceTo << 234 motherSolid->DistanceToOut(localPoint, 287 true, &motherVal << 235 localDirection, >> 236 true, &validExitNormal, &exitNormal); 288 #ifdef G4VERBOSE 237 #ifdef G4VERBOSE 289 if ( fCheck ) 238 if ( fCheck ) 290 { 239 { 291 fLogger->PostComputeStepLog(mother 240 fLogger->PostComputeStepLog(motherSolid, localPoint, localDirection, 292 mother 241 motherStep, motherSafety); 293 if( motherValidExitNormal ) << 294 { << 295 fLogger->CheckAndReportBadNormal << 296 << 297 << 298 "From << 299 } << 300 } 242 } 301 #endif 243 #endif 302 if( (motherStep >= kInfinity) || (mo << 303 { << 304 #ifdef G4VERBOSE << 305 if( fCheck ) // Error - indication << 306 { << 307 fLogger->ReportOutsideMother(loc << 308 mot << 309 } << 310 #endif << 311 motherStep = 0.0; << 312 ourStep = 0.0; << 313 exiting = true; << 314 entering = false; << 315 << 316 // validExitNormal= motherValidExi << 317 // exitNormal= motherExitNormal; << 318 // Useful only if the point is ver << 319 // => but it would need to be rota << 320 validExitNormal= false; << 321 << 322 *pBlockedPhysical = nullptr; // or << 323 blockedReplicaNo = 0; // or mothe << 324 << 325 newSafety = 0.0; << 326 return ourStep; << 327 } << 328 << 329 if ( motherStep<=ourStep ) 244 if ( motherStep<=ourStep ) 330 { 245 { 331 ourStep = motherStep; 246 ourStep = motherStep; 332 exiting = true; 247 exiting = true; 333 entering = false; 248 entering = false; 334 << 335 // Exit normal: Natural location t << 336 // << 337 validExitNormal = motherValidExitN << 338 exitNormal = motherExitNormal; << 339 << 340 if ( validExitNormal ) 249 if ( validExitNormal ) 341 { 250 { 342 const G4RotationMatrix *rot = mo 251 const G4RotationMatrix *rot = motherPhysical->GetRotation(); 343 if (rot != nullptr) << 252 if (rot) 344 { 253 { 345 exitNormal *= rot->inverse(); 254 exitNormal *= rot->inverse(); 346 #ifdef G4VERBOSE << 347 if( fCheck ) << 348 { << 349 fLogger->CheckAndReportBadNo << 350 << 351 << 352 << 353 } << 354 #endif << 355 } 255 } 356 } << 256 } 357 } 257 } 358 else 258 else 359 { 259 { 360 validExitNormal = false; 260 validExitNormal = false; 361 } 261 } 362 } 262 } 363 } 263 } 364 newSafety = ourSafety; 264 newSafety = ourSafety; 365 } 265 } 366 if (noStep) 266 if (noStep) 367 { 267 { 368 noStep = LocateNextVoxel(localPoint, loc 268 noStep = LocateNextVoxel(localPoint, localDirection, ourStep); 369 } 269 } 370 } // end -while (noStep)- loop 270 } // end -while (noStep)- loop 371 271 372 return ourStep; 272 return ourStep; 373 } 273 } 374 274 375 // ******************************************* 275 // ******************************************************************** 376 // ComputeVoxelSafety 276 // ComputeVoxelSafety 377 // 277 // 378 // Computes safety from specified point to vox 278 // Computes safety from specified point to voxel boundaries 379 // using already located point 279 // using already located point 380 // o collected boundaries for most derived lev 280 // o collected boundaries for most derived level 381 // o adjacent boundaries for previous levels 281 // o adjacent boundaries for previous levels 382 // ******************************************* 282 // ******************************************************************** 383 // 283 // 384 G4double 284 G4double 385 G4VoxelNavigation::ComputeVoxelSafety(const G4 285 G4VoxelNavigation::ComputeVoxelSafety(const G4ThreeVector& localPoint) const 386 { 286 { 387 G4SmartVoxelHeader *curHeader; 287 G4SmartVoxelHeader *curHeader; 388 G4double voxelSafety, curNodeWidth; 288 G4double voxelSafety, curNodeWidth; 389 G4double curNodeOffset, minCurCommonDelta, m 289 G4double curNodeOffset, minCurCommonDelta, maxCurCommonDelta; 390 G4int minCurNodeNoDelta, maxCurNodeNoDelta; 290 G4int minCurNodeNoDelta, maxCurNodeNoDelta; 391 G4int localVoxelDepth, curNodeNo; 291 G4int localVoxelDepth, curNodeNo; 392 EAxis curHeaderAxis; 292 EAxis curHeaderAxis; 393 293 394 localVoxelDepth = fVoxelDepth; 294 localVoxelDepth = fVoxelDepth; 395 295 396 curHeader = fVoxelHeaderStack[localVoxelDept 296 curHeader = fVoxelHeaderStack[localVoxelDepth]; 397 curHeaderAxis = fVoxelAxisStack[localVoxelDe 297 curHeaderAxis = fVoxelAxisStack[localVoxelDepth]; 398 curNodeNo = fVoxelNodeNoStack[localVoxelDept 298 curNodeNo = fVoxelNodeNoStack[localVoxelDepth]; 399 curNodeWidth = fVoxelSliceWidthStack[localVo 299 curNodeWidth = fVoxelSliceWidthStack[localVoxelDepth]; 400 300 401 // Compute linear intersection distance to b 301 // Compute linear intersection distance to boundaries of max/min 402 // to collected nodes at current level 302 // to collected nodes at current level 403 // 303 // 404 curNodeOffset = curNodeNo*curNodeWidth; 304 curNodeOffset = curNodeNo*curNodeWidth; 405 maxCurNodeNoDelta = fVoxelNode->GetMaxEquiva 305 maxCurNodeNoDelta = fVoxelNode->GetMaxEquivalentSliceNo()-curNodeNo; 406 minCurNodeNoDelta = curNodeNo-fVoxelNode->Ge 306 minCurNodeNoDelta = curNodeNo-fVoxelNode->GetMinEquivalentSliceNo(); 407 minCurCommonDelta = localPoint(curHeaderAxis 307 minCurCommonDelta = localPoint(curHeaderAxis) 408 - curHeader->GetMinExten 308 - curHeader->GetMinExtent() - curNodeOffset; 409 maxCurCommonDelta = curNodeWidth-minCurCommo 309 maxCurCommonDelta = curNodeWidth-minCurCommonDelta; 410 310 411 if ( minCurNodeNoDelta<maxCurNodeNoDelta ) 311 if ( minCurNodeNoDelta<maxCurNodeNoDelta ) 412 { 312 { 413 voxelSafety = minCurNodeNoDelta*curNodeWid 313 voxelSafety = minCurNodeNoDelta*curNodeWidth; 414 voxelSafety += minCurCommonDelta; 314 voxelSafety += minCurCommonDelta; 415 } 315 } 416 else if (maxCurNodeNoDelta < minCurNodeNoDel 316 else if (maxCurNodeNoDelta < minCurNodeNoDelta) 417 { 317 { 418 voxelSafety = maxCurNodeNoDelta*curNodeWid 318 voxelSafety = maxCurNodeNoDelta*curNodeWidth; 419 voxelSafety += maxCurCommonDelta; 319 voxelSafety += maxCurCommonDelta; 420 } 320 } 421 else // (maxCurNodeNoDelta == minCurNodeN 321 else // (maxCurNodeNoDelta == minCurNodeNoDelta) 422 { 322 { 423 voxelSafety = minCurNodeNoDelta*curNodeWid 323 voxelSafety = minCurNodeNoDelta*curNodeWidth; 424 voxelSafety += std::min(minCurCommonDelta, 324 voxelSafety += std::min(minCurCommonDelta,maxCurCommonDelta); 425 } 325 } 426 326 427 // Compute isotropic safety to boundaries of 327 // Compute isotropic safety to boundaries of previous levels 428 // [NOT to collected boundaries] 328 // [NOT to collected boundaries] 429 << 329 // 430 // Loop checking, 07.10.2016, JA << 431 while ( (localVoxelDepth>0) && (voxelSafety> 330 while ( (localVoxelDepth>0) && (voxelSafety>0) ) 432 { 331 { 433 localVoxelDepth--; 332 localVoxelDepth--; 434 curHeader = fVoxelHeaderStack[localVoxelDe 333 curHeader = fVoxelHeaderStack[localVoxelDepth]; 435 curHeaderAxis = fVoxelAxisStack[localVoxel 334 curHeaderAxis = fVoxelAxisStack[localVoxelDepth]; 436 curNodeNo = fVoxelNodeNoStack[localVoxelDe 335 curNodeNo = fVoxelNodeNoStack[localVoxelDepth]; 437 curNodeWidth = fVoxelSliceWidthStack[local 336 curNodeWidth = fVoxelSliceWidthStack[localVoxelDepth]; 438 curNodeOffset = curNodeNo*curNodeWidth; 337 curNodeOffset = curNodeNo*curNodeWidth; 439 minCurCommonDelta = localPoint(curHeaderAx 338 minCurCommonDelta = localPoint(curHeaderAxis) 440 - curHeader->GetMinExt 339 - curHeader->GetMinExtent() - curNodeOffset; 441 maxCurCommonDelta = curNodeWidth-minCurCom 340 maxCurCommonDelta = curNodeWidth-minCurCommonDelta; 442 341 443 if ( minCurCommonDelta<voxelSafety ) 342 if ( minCurCommonDelta<voxelSafety ) 444 { 343 { 445 voxelSafety = minCurCommonDelta; 344 voxelSafety = minCurCommonDelta; 446 } 345 } 447 if ( maxCurCommonDelta<voxelSafety ) 346 if ( maxCurCommonDelta<voxelSafety ) 448 { 347 { 449 voxelSafety = maxCurCommonDelta; 348 voxelSafety = maxCurCommonDelta; 450 } 349 } 451 } 350 } 452 if ( voxelSafety<0 ) 351 if ( voxelSafety<0 ) 453 { 352 { 454 voxelSafety = 0; 353 voxelSafety = 0; 455 } 354 } 456 355 457 return voxelSafety; 356 return voxelSafety; 458 } 357 } 459 358 460 // ******************************************* 359 // ******************************************************************** 461 // LocateNextVoxel 360 // LocateNextVoxel 462 // 361 // 463 // Finds the next voxel from the current voxel 362 // Finds the next voxel from the current voxel and point 464 // in the specified direction 363 // in the specified direction 465 // 364 // 466 // Returns false if all voxels considered 365 // Returns false if all voxels considered 467 // [current Step ends inside same 366 // [current Step ends inside same voxel or leaves all voxels] 468 // true otherwise 367 // true otherwise 469 // [the information on the next v 368 // [the information on the next voxel is put into the set of 470 // fVoxel* variables & "stacks"] 369 // fVoxel* variables & "stacks"] 471 // ******************************************* 370 // ******************************************************************** 472 // 371 // 473 G4bool 372 G4bool 474 G4VoxelNavigation::LocateNextVoxel(const G4Thr 373 G4VoxelNavigation::LocateNextVoxel(const G4ThreeVector& localPoint, 475 const G4Thr 374 const G4ThreeVector& localDirection, 476 const G4dou 375 const G4double currentStep) 477 { 376 { 478 G4SmartVoxelHeader *workHeader=nullptr, *new << 377 G4SmartVoxelHeader *workHeader=0, *newHeader=0; 479 G4SmartVoxelProxy *newProxy=nullptr; << 378 G4SmartVoxelProxy *newProxy=0; 480 G4SmartVoxelNode *newVoxelNode=nullptr; << 379 G4SmartVoxelNode *newVoxelNode=0; 481 G4ThreeVector targetPoint, voxelPoint; 380 G4ThreeVector targetPoint, voxelPoint; 482 G4double workNodeWidth, workMinExtent, workC 381 G4double workNodeWidth, workMinExtent, workCoord; 483 G4double minVal, maxVal, newDistance=0.; 382 G4double minVal, maxVal, newDistance=0.; 484 G4double newHeaderMin, newHeaderNodeWidth; 383 G4double newHeaderMin, newHeaderNodeWidth; 485 G4int depth=0, newDepth=0, workNodeNo=0, new 384 G4int depth=0, newDepth=0, workNodeNo=0, newNodeNo=0, newHeaderNoSlices=0; 486 EAxis workHeaderAxis, newHeaderAxis; 385 EAxis workHeaderAxis, newHeaderAxis; 487 G4bool isNewVoxel = false; << 386 G4bool isNewVoxel=false; 488 387 489 G4double currentDistance = currentStep; 388 G4double currentDistance = currentStep; >> 389 static const G4double sigma = 0.5*G4GeometryTolerance::GetInstance() >> 390 ->GetSurfaceTolerance(); 490 391 491 // Determine if end of Step within current v 392 // Determine if end of Step within current voxel 492 // 393 // 493 for (depth=0; depth<fVoxelDepth; ++depth) << 394 for (depth=0; depth<fVoxelDepth; depth++) 494 { 395 { 495 targetPoint = localPoint+localDirection*cu 396 targetPoint = localPoint+localDirection*currentDistance; 496 newDistance = currentDistance; 397 newDistance = currentDistance; 497 workHeader = fVoxelHeaderStack[depth]; 398 workHeader = fVoxelHeaderStack[depth]; 498 workHeaderAxis = fVoxelAxisStack[depth]; 399 workHeaderAxis = fVoxelAxisStack[depth]; 499 workNodeNo = fVoxelNodeNoStack[depth]; 400 workNodeNo = fVoxelNodeNoStack[depth]; 500 workNodeWidth = fVoxelSliceWidthStack[dept 401 workNodeWidth = fVoxelSliceWidthStack[depth]; 501 workMinExtent = workHeader->GetMinExtent() 402 workMinExtent = workHeader->GetMinExtent(); 502 workCoord = targetPoint(workHeaderAxis); 403 workCoord = targetPoint(workHeaderAxis); 503 minVal = workMinExtent+workNodeNo*workNode 404 minVal = workMinExtent+workNodeNo*workNodeWidth; 504 405 505 if ( minVal<=workCoord+fHalfTolerance ) << 406 if ( minVal<=workCoord+sigma ) 506 { 407 { 507 maxVal = minVal+workNodeWidth; 408 maxVal = minVal+workNodeWidth; 508 if ( maxVal<=workCoord-fHalfTolerance ) << 409 if ( maxVal<=workCoord-sigma ) 509 { 410 { 510 // Must consider next voxel 411 // Must consider next voxel 511 // 412 // 512 newNodeNo = workNodeNo+1; 413 newNodeNo = workNodeNo+1; 513 newHeader = workHeader; 414 newHeader = workHeader; 514 newDistance = (maxVal-localPoint(workH 415 newDistance = (maxVal-localPoint(workHeaderAxis)) 515 / localDirection(workHeade 416 / localDirection(workHeaderAxis); 516 isNewVoxel = true; 417 isNewVoxel = true; 517 newDepth = depth; 418 newDepth = depth; 518 } 419 } 519 } 420 } 520 else 421 else 521 { 422 { 522 newNodeNo = workNodeNo-1; 423 newNodeNo = workNodeNo-1; 523 newHeader = workHeader; 424 newHeader = workHeader; 524 newDistance = (minVal-localPoint(workHea 425 newDistance = (minVal-localPoint(workHeaderAxis)) 525 / localDirection(workHeaderA 426 / localDirection(workHeaderAxis); 526 isNewVoxel = true; 427 isNewVoxel = true; 527 newDepth = depth; 428 newDepth = depth; 528 } 429 } 529 currentDistance = newDistance; 430 currentDistance = newDistance; 530 } 431 } 531 targetPoint = localPoint+localDirection*curr 432 targetPoint = localPoint+localDirection*currentDistance; 532 433 533 // Check if end of Step within collected bou 434 // Check if end of Step within collected boundaries of current voxel 534 // 435 // 535 depth = fVoxelDepth; 436 depth = fVoxelDepth; 536 { 437 { 537 workHeader = fVoxelHeaderStack[depth]; 438 workHeader = fVoxelHeaderStack[depth]; 538 workHeaderAxis = fVoxelAxisStack[depth]; 439 workHeaderAxis = fVoxelAxisStack[depth]; 539 workNodeNo = fVoxelNodeNoStack[depth]; 440 workNodeNo = fVoxelNodeNoStack[depth]; 540 workNodeWidth = fVoxelSliceWidthStack[dept 441 workNodeWidth = fVoxelSliceWidthStack[depth]; 541 workMinExtent = workHeader->GetMinExtent() 442 workMinExtent = workHeader->GetMinExtent(); 542 workCoord = targetPoint(workHeaderAxis); 443 workCoord = targetPoint(workHeaderAxis); 543 minVal = workMinExtent+fVoxelNode->GetMinE 444 minVal = workMinExtent+fVoxelNode->GetMinEquivalentSliceNo()*workNodeWidth; 544 445 545 if ( minVal<=workCoord+fHalfTolerance ) << 446 if ( minVal<=workCoord+sigma ) 546 { 447 { 547 maxVal = workMinExtent+(fVoxelNode->GetM 448 maxVal = workMinExtent+(fVoxelNode->GetMaxEquivalentSliceNo()+1) 548 *workNodeWidth; 449 *workNodeWidth; 549 if ( maxVal<=workCoord-fHalfTolerance ) << 450 if ( maxVal<=workCoord-sigma ) 550 { 451 { 551 newNodeNo = fVoxelNode->GetMaxEquivale 452 newNodeNo = fVoxelNode->GetMaxEquivalentSliceNo()+1; 552 newHeader = workHeader; 453 newHeader = workHeader; 553 newDistance = (maxVal-localPoint(workH 454 newDistance = (maxVal-localPoint(workHeaderAxis)) 554 / localDirection(workHeade 455 / localDirection(workHeaderAxis); 555 isNewVoxel = true; 456 isNewVoxel = true; 556 newDepth = depth; 457 newDepth = depth; 557 } 458 } 558 } 459 } 559 else 460 else 560 { 461 { 561 newNodeNo = fVoxelNode->GetMinEquivalent 462 newNodeNo = fVoxelNode->GetMinEquivalentSliceNo()-1; 562 newHeader = workHeader; 463 newHeader = workHeader; 563 newDistance = (minVal-localPoint(workHea 464 newDistance = (minVal-localPoint(workHeaderAxis)) 564 / localDirection(workHeaderA 465 / localDirection(workHeaderAxis); 565 isNewVoxel = true; 466 isNewVoxel = true; 566 newDepth = depth; 467 newDepth = depth; 567 } 468 } 568 currentDistance = newDistance; 469 currentDistance = newDistance; 569 } 470 } 570 if (isNewVoxel) 471 if (isNewVoxel) 571 { 472 { 572 // Compute new voxel & adjust voxel stack 473 // Compute new voxel & adjust voxel stack 573 // 474 // 574 // newNodeNo=Candidate node no at 475 // newNodeNo=Candidate node no at 575 // newDepth =refinement depth of crossed v 476 // newDepth =refinement depth of crossed voxel boundary 576 // newHeader=Header for crossed voxel 477 // newHeader=Header for crossed voxel 577 // newDistance=distance to crossed voxel b 478 // newDistance=distance to crossed voxel boundary (along the track) 578 // 479 // 579 if ( (newNodeNo<0) || (newNodeNo>=G4int(ne << 480 if ( (newNodeNo<0) || (newNodeNo>=newHeader->GetNoSlices())) 580 { 481 { 581 // Leaving mother volume 482 // Leaving mother volume 582 // 483 // 583 isNewVoxel = false; 484 isNewVoxel = false; 584 } 485 } 585 else 486 else 586 { 487 { 587 // Compute intersection point on the lea 488 // Compute intersection point on the least refined 588 // voxel boundary that is hit 489 // voxel boundary that is hit 589 // 490 // 590 voxelPoint = localPoint+localDirection*n 491 voxelPoint = localPoint+localDirection*newDistance; 591 fVoxelNodeNoStack[newDepth] = newNodeNo; 492 fVoxelNodeNoStack[newDepth] = newNodeNo; 592 fVoxelDepth = newDepth; 493 fVoxelDepth = newDepth; 593 newVoxelNode = nullptr; << 494 newVoxelNode = 0; 594 while ( newVoxelNode == nullptr ) << 495 while ( !newVoxelNode ) 595 { 496 { 596 newProxy = newHeader->GetSlice(newNode 497 newProxy = newHeader->GetSlice(newNodeNo); 597 if (newProxy->IsNode()) 498 if (newProxy->IsNode()) 598 { 499 { 599 newVoxelNode = newProxy->GetNode(); 500 newVoxelNode = newProxy->GetNode(); 600 } 501 } 601 else 502 else 602 { 503 { 603 ++fVoxelDepth; << 504 fVoxelDepth++; 604 newHeader = newProxy->GetHeader(); 505 newHeader = newProxy->GetHeader(); 605 newHeaderAxis = newHeader->GetAxis() 506 newHeaderAxis = newHeader->GetAxis(); 606 newHeaderNoSlices = (G4int)newHeader << 507 newHeaderNoSlices = newHeader->GetNoSlices(); 607 newHeaderMin = newHeader->GetMinExte 508 newHeaderMin = newHeader->GetMinExtent(); 608 newHeaderNodeWidth = (newHeader->Get 509 newHeaderNodeWidth = (newHeader->GetMaxExtent()-newHeaderMin) 609 / newHeaderNoSlic 510 / newHeaderNoSlices; 610 newNodeNo = G4int( (voxelPoint(newHe 511 newNodeNo = G4int( (voxelPoint(newHeaderAxis)-newHeaderMin) 611 / newHeaderNodeWi 512 / newHeaderNodeWidth ); 612 // Rounding protection 513 // Rounding protection 613 // 514 // 614 if ( newNodeNo<0 ) 515 if ( newNodeNo<0 ) 615 { 516 { 616 newNodeNo=0; 517 newNodeNo=0; 617 } 518 } 618 else if ( newNodeNo>=newHeaderNoSlic 519 else if ( newNodeNo>=newHeaderNoSlices ) 619 { << 520 { 620 newNodeNo = newHeaderNoSlices-1; << 521 newNodeNo = newHeaderNoSlices-1; 621 } << 522 } 622 // Stack info for stepping 523 // Stack info for stepping 623 // 524 // 624 fVoxelAxisStack[fVoxelDepth] = newHe 525 fVoxelAxisStack[fVoxelDepth] = newHeaderAxis; 625 fVoxelNoSlicesStack[fVoxelDepth] = n 526 fVoxelNoSlicesStack[fVoxelDepth] = newHeaderNoSlices; 626 fVoxelSliceWidthStack[fVoxelDepth] = 527 fVoxelSliceWidthStack[fVoxelDepth] = newHeaderNodeWidth; 627 fVoxelNodeNoStack[fVoxelDepth] = new 528 fVoxelNodeNoStack[fVoxelDepth] = newNodeNo; 628 fVoxelHeaderStack[fVoxelDepth] = new 529 fVoxelHeaderStack[fVoxelDepth] = newHeader; 629 } 530 } 630 } 531 } 631 fVoxelNode = newVoxelNode; 532 fVoxelNode = newVoxelNode; 632 } 533 } 633 } 534 } 634 return isNewVoxel; 535 return isNewVoxel; 635 } 536 } 636 537 637 // ******************************************* 538 // ******************************************************************** 638 // ComputeSafety 539 // ComputeSafety 639 // 540 // 640 // Calculates the isotropic distance to the ne 541 // Calculates the isotropic distance to the nearest boundary from the 641 // specified point in the local coordinate sys 542 // specified point in the local coordinate system. 642 // The localpoint utilised must be within the 543 // The localpoint utilised must be within the current volume. 643 // ******************************************* 544 // ******************************************************************** 644 // 545 // 645 G4double 546 G4double 646 G4VoxelNavigation::ComputeSafety(const G4Three 547 G4VoxelNavigation::ComputeSafety(const G4ThreeVector& localPoint, 647 const G4Navig 548 const G4NavigationHistory& history, 648 const G4doubl << 549 const G4double maxLength) 649 { 550 { 650 G4VPhysicalVolume *motherPhysical, *samplePh 551 G4VPhysicalVolume *motherPhysical, *samplePhysical; 651 G4LogicalVolume *motherLogical; 552 G4LogicalVolume *motherLogical; 652 G4VSolid *motherSolid; 553 G4VSolid *motherSolid; 653 G4double motherSafety, ourSafety; 554 G4double motherSafety, ourSafety; 654 G4int sampleNo; 555 G4int sampleNo; 655 G4SmartVoxelNode *curVoxelNode; 556 G4SmartVoxelNode *curVoxelNode; 656 G4long curNoVolumes, contentNo; << 557 G4int curNoVolumes, contentNo; 657 G4double voxelSafety; 558 G4double voxelSafety; 658 559 659 motherPhysical = history.GetTopVolume(); 560 motherPhysical = history.GetTopVolume(); 660 motherLogical = motherPhysical->GetLogicalVo 561 motherLogical = motherPhysical->GetLogicalVolume(); 661 motherSolid = motherLogical->GetSolid(); 562 motherSolid = motherLogical->GetSolid(); 662 563 663 if( fBestSafety ) 564 if( fBestSafety ) 664 { 565 { 665 return fpVoxelSafety->ComputeSafety( local 566 return fpVoxelSafety->ComputeSafety( localPoint,*motherPhysical,maxLength ); 666 } 567 } 667 568 668 // 569 // 669 // Compute mother safety 570 // Compute mother safety 670 // 571 // 671 572 672 motherSafety = motherSolid->DistanceToOut(lo 573 motherSafety = motherSolid->DistanceToOut(localPoint); 673 ourSafety = motherSafety; // 574 ourSafety = motherSafety; // Working isotropic safety 674 575 675 if( motherSafety == 0.0 ) 576 if( motherSafety == 0.0 ) 676 { 577 { 677 #ifdef G4DEBUG_NAVIGATION 578 #ifdef G4DEBUG_NAVIGATION 678 // Check that point is inside mother volum 579 // Check that point is inside mother volume 679 EInside insideMother = motherSolid->Insid << 580 EInside insideMother= motherSolid->Inside(localPoint); 680 581 681 if( insideMother == kOutside ) 582 if( insideMother == kOutside ) 682 { 583 { 683 G4ExceptionDescription message; 584 G4ExceptionDescription message; 684 message << "Safety method called for loc 585 message << "Safety method called for location outside current Volume." << G4endl 685 << "Location for safety is Outside th 586 << "Location for safety is Outside this volume. " << G4endl 686 << "The approximate distance to the s 587 << "The approximate distance to the solid " 687 << "(safety from outside) is: " 588 << "(safety from outside) is: " 688 << motherSolid->DistanceToIn( localPo 589 << motherSolid->DistanceToIn( localPoint ) << G4endl; 689 message << " Problem occurred with phys 590 message << " Problem occurred with physical volume: " 690 << " Name: " << motherPhysical->GetNa 591 << " Name: " << motherPhysical->GetName() 691 << " Copy No: " << motherPhysical->Ge 592 << " Copy No: " << motherPhysical->GetCopyNo() << G4endl 692 << " Local Point = " << localPoint 593 << " Local Point = " << localPoint << G4endl; 693 message << " Description of solid: " << 594 message << " Description of solid: " << G4endl 694 << *motherSolid << G4endl; 595 << *motherSolid << G4endl; 695 G4Exception("G4VoxelNavigation::ComputeS 596 G4Exception("G4VoxelNavigation::ComputeSafety()", "GeomNav0003", 696 JustWarning, message); << 597 JustWarning, // FatalException, >> 598 message); 697 } 599 } 698 600 699 // Following check is NOT for an issue - i 601 // Following check is NOT for an issue - it is only for information 700 // It is allowed that a solid gives appro 602 // It is allowed that a solid gives approximate safety - even zero. 701 // 603 // 702 if( insideMother == kInside ) // && fVerbo 604 if( insideMother == kInside ) // && fVerbose ) 703 { 605 { 704 G4ExceptionDescription messageIn; 606 G4ExceptionDescription messageIn; 705 607 706 messageIn << " Point is Inside, but safe 608 messageIn << " Point is Inside, but safety is Zero ." << G4endl; 707 messageIn << " Inexact safety for volume 609 messageIn << " Inexact safety for volume " << motherPhysical->GetName() << G4endl 708 << " Solid: Name= " << motherSol 610 << " Solid: Name= " << motherSolid->GetName() 709 << " Type= " << motherSolid->Ge 611 << " Type= " << motherSolid->GetEntityType() << G4endl; 710 messageIn << " Local point= " << localP 612 messageIn << " Local point= " << localPoint << G4endl; 711 messageIn << " Solid parameters: " << G 613 messageIn << " Solid parameters: " << G4endl << *motherSolid << G4endl; 712 G4Exception("G4VoxelNavigation::ComputeS 614 G4Exception("G4VoxelNavigation::ComputeSafety()", "GeomNav0003", 713 JustWarning, messageIn); 615 JustWarning, messageIn); 714 } 616 } 715 #endif 617 #endif 716 // if( insideMother != kInside ) 618 // if( insideMother != kInside ) 717 return 0.0; 619 return 0.0; 718 } 620 } 719 621 720 #ifdef G4VERBOSE 622 #ifdef G4VERBOSE 721 if( fCheck ) 623 if( fCheck ) 722 { 624 { 723 fLogger->ComputeSafetyLog (motherSolid,loc << 625 fLogger->ComputeSafetyLog (motherSolid, localPoint, motherSafety, true); 724 } 626 } 725 #endif 627 #endif 726 // 628 // 727 // Compute daughter safeties 629 // Compute daughter safeties 728 // 630 // 729 // Look only inside the current Voxel only ( 631 // Look only inside the current Voxel only (in the first version). 730 // 632 // 731 curVoxelNode = fVoxelNode; 633 curVoxelNode = fVoxelNode; 732 curNoVolumes = curVoxelNode->GetNoContained( 634 curNoVolumes = curVoxelNode->GetNoContained(); 733 635 734 for ( contentNo=curNoVolumes-1; contentNo>=0 636 for ( contentNo=curNoVolumes-1; contentNo>=0; contentNo-- ) 735 { 637 { 736 sampleNo = curVoxelNode->GetVolume((G4int) << 638 sampleNo = curVoxelNode->GetVolume(contentNo); 737 samplePhysical = motherLogical->GetDaughte 639 samplePhysical = motherLogical->GetDaughter(sampleNo); 738 640 739 G4AffineTransform sampleTf(samplePhysical- 641 G4AffineTransform sampleTf(samplePhysical->GetRotation(), 740 samplePhysical- 642 samplePhysical->GetTranslation()); 741 sampleTf.Invert(); 643 sampleTf.Invert(); 742 const G4ThreeVector samplePoint = sampleTf << 644 const G4ThreeVector samplePoint = 743 const G4VSolid* sampleSolid= samplePhysica << 645 sampleTf.TransformPoint(localPoint); >> 646 const G4VSolid *sampleSolid = >> 647 samplePhysical->GetLogicalVolume()->GetSolid(); 744 G4double sampleSafety = sampleSolid->Dista 648 G4double sampleSafety = sampleSolid->DistanceToIn(samplePoint); 745 if ( sampleSafety<ourSafety ) 649 if ( sampleSafety<ourSafety ) 746 { 650 { 747 ourSafety = sampleSafety; 651 ourSafety = sampleSafety; 748 } 652 } 749 #ifdef G4VERBOSE 653 #ifdef G4VERBOSE 750 if( fCheck ) 654 if( fCheck ) 751 { 655 { 752 fLogger->ComputeSafetyLog(sampleSolid, s << 656 fLogger->ComputeSafetyLog (sampleSolid,samplePoint,sampleSafety,false); 753 sampleSafety, << 754 } 657 } 755 #endif 658 #endif 756 } 659 } 757 voxelSafety = ComputeVoxelSafety(localPoint) 660 voxelSafety = ComputeVoxelSafety(localPoint); 758 if ( voxelSafety<ourSafety ) 661 if ( voxelSafety<ourSafety ) 759 { 662 { 760 ourSafety = voxelSafety; 663 ourSafety = voxelSafety; 761 } 664 } 762 return ourSafety; 665 return ourSafety; 763 } 666 } 764 667 765 void G4VoxelNavigation::RelocateWithinVolume( << 766 << 767 { << 768 auto motherLogical = motherPhysical->GetLogi << 769 << 770 assert(motherLogical != nullptr); << 771 << 772 if ( auto pVoxelHeader = motherLogical->GetV << 773 VoxelLocate( pVoxelHeader, localPoint ); << 774 } << 775 << 776 // ******************************************* 668 // ******************************************************************** 777 // SetVerboseLevel 669 // SetVerboseLevel 778 // ******************************************* 670 // ******************************************************************** 779 // 671 // 780 void G4VoxelNavigation::SetVerboseLevel(G4int 672 void G4VoxelNavigation::SetVerboseLevel(G4int level) 781 { 673 { 782 if( fLogger != nullptr ) { fLogger->SetVerbo << 674 if( fLogger ) fLogger->SetVerboseLevel(level); 783 if( fpVoxelSafety != nullptr) { fpVoxelSafet << 675 if( fpVoxelSafety) fpVoxelSafety->SetVerboseLevel( level ); 784 } 676 } 785 677