Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/examples/extended/medical/dna/UHDR/src/PeriodicBoundaryProcess.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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 /*
 28  * Based on 'g4pbc'.
 29  * Copyright (c) 2020 Amentum Pty Ltd
 30  * team@amentum.space
 31  * The original open-source version of this code
 32  * may be found at https://github.com/amentumspace/g4pbc
 33  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 34  * associated documentation files (the "Software"), to deal in the Software without restriction,
 35  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 36  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
 37  * is furnished to do so, subject to the following conditions:
 38  * The above copyright notice and this permission notice shall be included in all copies
 39  * or substantial portions of the Software.
 40  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 41  * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 42  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 43  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 44  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 45  *
 46  *
 47  */
 48 #include "PeriodicBoundaryProcess.hh"
 49 
 50 #include "LogicalVolumePeriodic.hh"
 51 #include "ParticleChangeForPeriodic.hh"
 52 
 53 #include "G4EventManager.hh"
 54 #include "G4GeometryTolerance.hh"
 55 #include "G4Navigator.hh"
 56 #include "G4PathFinder.hh"
 57 #include "G4TransportationManager.hh"
 58 #include "G4UnitsTable.hh"
 59 #include "G4VTrajectory.hh"
 60 #include "G4ios.hh"
 61 
 62 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 63 
 64 PeriodicBoundaryProcess::PeriodicBoundaryProcess(const G4String& processName, G4ProcessType type,
 65                                                  G4bool per_x, G4bool per_y, G4bool per_z)
 66   : G4VDiscreteProcess(processName, type), fPeriodicX(per_x), fPeriodicY(per_y), fPeriodicZ(per_z)
 67 {
 68   fkCarTolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
 69   pParticleChange = &fParticleChange;
 70   G4PathFinder::GetInstance()->SetVerboseLevel(0);
 71 }
 72 
 73 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
 74 
 75 G4VParticleChange* PeriodicBoundaryProcess::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep)
 76 {
 77   fTheStatus = Undefined;
 78 
 79   fParticleChange.InitializeForPostStep(aTrack);
 80 
 81   const G4Step* pStep = &aStep;
 82 
 83   G4bool isOnBoundary = (pStep->GetPostStepPoint()->GetStepStatus() == fGeomBoundary);
 84 
 85   if (!isOnBoundary) {
 86     fTheStatus = NotAtBoundary;
 87     if (verboseLevel > 0) {
 88       BoundaryProcessVerbose();
 89     }
 90     return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
 91   }
 92 
 93   if (aTrack.GetParentID() == 0)  // not primary particle (electron ?)
 94   {
 95     return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
 96   }
 97 
 98   auto thePrePV = pStep->GetPreStepPoint()->GetPhysicalVolume();
 99   auto thePostPV = pStep->GetPostStepPoint()->GetPhysicalVolume();
100 
101   if (verboseLevel > 0) {
102     G4cout << " Particle at Boundary! " << G4endl;
103     if (thePrePV) {
104       G4cout << " thePrePV:  " << thePrePV->GetName() << G4endl;
105     }
106     if (thePostPV) {
107       G4cout << " thePostPV: " << thePostPV->GetName() << G4endl;
108     }
109     G4cout << "step length " << aTrack.GetStepLength() << G4endl;
110     G4cout << "ParentID : " << aTrack.GetParentID() << "  TrackID : " << aTrack.GetTrackID()
111            << " Position : " << aTrack.GetPosition()
112            << "  aTrack Energy : " << G4BestUnit(aTrack.GetKineticEnergy(), "Energy") << G4endl;
113   }
114 
115   // avoid trapped particles at boundaries by testing for minimum step length
116   if (aTrack.GetStepLength() <= fkCarTolerance / 2) {
117     fTheStatus = StepTooSmall;
118     if (verboseLevel > 0) {
119       BoundaryProcessVerbose();
120     }
121     return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
122   }
123 
124   const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
125 
126   // store the current values
127   fOldMomentum = aParticle->GetMomentumDirection();
128   fOldPolarization = aParticle->GetPolarization();
129   fOldPosition = pStep->GetPostStepPoint()->GetPosition();
130   fNewPosition = fOldPosition;
131 
132   if (verboseLevel > 0) {
133     G4cout << " Old Momentum Direction: " << fOldMomentum << G4endl;
134     G4cout << " Old Position: " << fNewPosition << G4endl;
135     G4cout << "Get aTrack.GetParentID() : " << aTrack.GetParentID() << G4endl;
136   }
137 
138   auto theGlobalPoint = pStep->GetPostStepPoint()->GetPosition();
139 
140   G4bool valid = false;
141   //  Use the new method for Exit Normal in global coordinates,
142   //    which provides the normal more reliably.
143   // get from the real-world navigator (process not applied to parallel worlds)
144   fTheGlobalNormal = G4TransportationManager::GetTransportationManager()
145                        ->GetNavigatorForTracking()
146                        ->GetGlobalExitNormal(theGlobalPoint, &valid);
147 
148   if (valid) {
149     fTheGlobalNormal = -fTheGlobalNormal;
150   }
151   else {
152     G4cout << "global normal " << fTheGlobalNormal << G4endl;
153     G4ExceptionDescription ed;
154     ed << " PeriodicBoundaryProcess::PostStepDoIt(): "
155        << " The Navigator reports that it returned an invalid normal" << G4endl;
156     G4Exception("G4PeriodicBoundaryProcess::PostStepDoIt", "PerBoun01", FatalException, ed,
157                 "Invalid Surface Normal - Geometry must return valid surface normal");
158   }
159 
160   G4bool isWrongDirection = fOldMomentum * fTheGlobalNormal > 0.0;
161   if (isWrongDirection) {
162     if (verboseLevel > 0) {
163       G4cout << "ftheGlobalNormal points in a wrong direction." << G4endl;
164       G4cout << "Invalid Surface Normal - Geometry must return valid surface \
165         normal pointing in the right direction"
166              << G4endl;
167     }
168 
169     fTheGlobalNormal = -fTheGlobalNormal;
170   }
171 
172   if (thePostPV == nullptr) {
173     G4ExceptionDescription ed;
174     ed << " PeriodicBoundaryProcess::PostStepDoIt(): "
175        << " thePostPV == nullptr" << G4endl;
176     G4Exception("G4PeriodicBoundaryProcess::PostStepDoIt", "PB14", FatalException, ed,
177                 "Invalid thePostPV");
178   }
179   auto lvol = thePostPV->GetLogicalVolume();
180 
181   if (lvol == nullptr) {
182     G4ExceptionDescription ed;
183     ed << " PeriodicBoundaryProcess::PostStepDoIt(): "
184        << " lvol == nullptr" << G4endl;
185     G4Exception("G4PeriodicBoundaryProcess::PostStepDoIt", "PB12", FatalException, ed,
186                 "Invalid lvol");
187   }
188 
189   if (verboseLevel > 0) {
190     G4cout << "Post step logical " << lvol->GetName() << G4endl;
191   }
192 
193   G4LogicalVolume* dlvol = nullptr;
194 
195   if (lvol->GetNoDaughters() > 0) {
196     if (verboseLevel > 0) {
197       G4cout << "eldest daughter " << lvol->GetDaughter(0)->GetName() << G4endl;
198     }
199 
200     dlvol = lvol->GetDaughter(0)->GetLogicalVolume();
201   }
202 
203   if (dlvol && dlvol->IsExtended()) {
204     if (verboseLevel > 0) {
205       G4cout << " Logical surface, periodic " << G4endl;
206     }
207 
208     G4bool on_x = fTheGlobalNormal.isParallel(G4ThreeVector(1, 0, 0));
209     G4bool on_y = fTheGlobalNormal.isParallel(G4ThreeVector(0, 1, 0));
210     G4bool on_z = fTheGlobalNormal.isParallel(G4ThreeVector(0, 0, 1));
211 
212     // make sure that we are at a plane
213     G4bool on_plane = (on_x || on_y || on_z);
214 
215     if (!on_plane) {
216       G4ExceptionDescription ed;
217       ed << " G4PeriodicBoundaryProcess::ostStepDoIt(): "
218          << " The particle is not on a surface of the cyclic world" << G4endl;
219       G4Exception(
220         "G4PeriodicBoundaryProcess::PostStepDoIt", "Periodic01", FatalException, ed,
221         "Periodic boundary process must only occur for particle on periodic world surface");
222     }
223     else {
224       G4bool on_x_and_periodic = (on_x && fPeriodicX);
225       G4bool on_y_and_periodic = (on_y && fPeriodicY);
226       G4bool on_z_and_periodic = (on_z && fPeriodicZ);
227 
228       G4bool on_a_periodic_plane = (on_x_and_periodic || on_y_and_periodic || on_z_and_periodic);
229 
230       if (on_a_periodic_plane) {
231         if (verboseLevel > 0) {
232           G4cout << " on periodic plane " << G4endl;
233         }
234 
235         fTheStatus = Cycling;
236 
237         if (verboseLevel > 0) {
238           G4cout << " periodic " << G4endl;
239         }
240 
241         if (verboseLevel > 0) {
242           G4cout << "Global normal " << fTheGlobalNormal << G4endl;
243         }
244 
245         // translate a component of the position vector according to which plane we are on
246         if (on_x_and_periodic) {
247           fNewPosition.setX(-fNewPosition.x());
248         }
249         else if (on_y_and_periodic) {
250           fNewPosition.setY(-fNewPosition.y());
251         }
252         else if (on_z_and_periodic) {
253           fNewPosition.setZ(-fNewPosition.z());
254         }
255         else {
256           G4cout << "global normal does not belong to periodic plane!!" << G4endl;
257         }
258 
259         fNewMomentum = fOldMomentum.unit();
260         fNewPolarization = fOldPolarization.unit();
261 
262         if (verboseLevel > 0) {
263           G4cout << " New Position: " << fNewPosition << G4endl;
264           G4cout << " New Momentum Direction: " << fNewMomentum << G4endl;
265           G4cout << " New Polarization:       " << fNewPolarization << G4endl;
266           BoundaryProcessVerbose();
267         }
268 
269         fParticleChange.ProposeMomentumDirection(fNewMomentum);
270         fParticleChange.ProposePolarization(fNewPolarization);
271         fParticleChange.ProposePosition(fNewPosition);
272 
273         G4PathFinder::GetInstance()->ReLocate(fNewPosition);
274         G4PathFinder::GetInstance()->ComputeSafety(fNewPosition);
275 
276         // we must notify the navigator that we have moved the particle artificially
277         G4Navigator* gNavigator =
278           G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking();
279 
280         // Inform the navigator that the previous Step calculated
281         // by the geometry was taken in its entirety.
282         gNavigator->SetGeometricallyLimitedStep();
283 
284         // Search the geometrical hierarchy for the volumes deepest in the hierarchy
285         // containing the point in the global coordinate space.
286         gNavigator->LocateGlobalPointAndSetup(fNewPosition, &fNewMomentum, false,
287                                               false);  // do not ignore direction
288 
289         // Calculate the isotropic distance to the nearest boundary from the
290         // specified point in the global coordinate system.
291         gNavigator->ComputeSafety(fNewPosition);
292 
293         // Locates the volume containing the specified global point.
294         // force drawing of the step prior to periodic the particle
295         auto evtm = G4EventManager::GetEventManager();
296         auto tckm = evtm->GetTrackingManager();
297         auto pTrajectory = tckm->GimmeTrajectory();
298         if (pTrajectory) {
299           pTrajectory->AppendStep(pStep);
300         }
301       }
302     }
303   }
304   return &fParticleChange;
305 }
306 
307 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
308 
309 G4double PeriodicBoundaryProcess::GetMeanFreePath(const G4Track&, G4double,
310                                                   G4ForceCondition* condition)
311 {
312   *condition = Forced;
313   return DBL_MAX;
314 }
315 
316 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
317 
318 void PeriodicBoundaryProcess::BoundaryProcessVerbose()
319 {
320   if (fStatusMessages.count(fTheStatus) > 0) {
321     G4cout << PeriodicBoundaryProcess::fStatusMessages[fTheStatus] << G4endl;
322   }
323 }
324 
325 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
326