File indexing completed on 2025-02-23 09:22:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 #include "PeriodicBoundaryProcess.hh"
0049
0050 #include "LogicalVolumePeriodic.hh"
0051 #include "ParticleChangeForPeriodic.hh"
0052
0053 #include "G4EventManager.hh"
0054 #include "G4GeometryTolerance.hh"
0055 #include "G4Navigator.hh"
0056 #include "G4PathFinder.hh"
0057 #include "G4TransportationManager.hh"
0058 #include "G4UnitsTable.hh"
0059 #include "G4VTrajectory.hh"
0060 #include "G4ios.hh"
0061
0062
0063
0064 PeriodicBoundaryProcess::PeriodicBoundaryProcess(const G4String& processName, G4ProcessType type,
0065 G4bool per_x, G4bool per_y, G4bool per_z)
0066 : G4VDiscreteProcess(processName, type), fPeriodicX(per_x), fPeriodicY(per_y), fPeriodicZ(per_z)
0067 {
0068 fkCarTolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
0069 pParticleChange = &fParticleChange;
0070 G4PathFinder::GetInstance()->SetVerboseLevel(0);
0071 }
0072
0073
0074
0075 G4VParticleChange* PeriodicBoundaryProcess::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep)
0076 {
0077 fTheStatus = Undefined;
0078
0079 fParticleChange.InitializeForPostStep(aTrack);
0080
0081 const G4Step* pStep = &aStep;
0082
0083 G4bool isOnBoundary = (pStep->GetPostStepPoint()->GetStepStatus() == fGeomBoundary);
0084
0085 if (!isOnBoundary) {
0086 fTheStatus = NotAtBoundary;
0087 if (verboseLevel > 0) {
0088 BoundaryProcessVerbose();
0089 }
0090 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
0091 }
0092
0093 if (aTrack.GetParentID() == 0)
0094 {
0095 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
0096 }
0097
0098 auto thePrePV = pStep->GetPreStepPoint()->GetPhysicalVolume();
0099 auto thePostPV = pStep->GetPostStepPoint()->GetPhysicalVolume();
0100
0101 if (verboseLevel > 0) {
0102 G4cout << " Particle at Boundary! " << G4endl;
0103 if (thePrePV) {
0104 G4cout << " thePrePV: " << thePrePV->GetName() << G4endl;
0105 }
0106 if (thePostPV) {
0107 G4cout << " thePostPV: " << thePostPV->GetName() << G4endl;
0108 }
0109 G4cout << "step length " << aTrack.GetStepLength() << G4endl;
0110 G4cout << "ParentID : " << aTrack.GetParentID() << " TrackID : " << aTrack.GetTrackID()
0111 << " Position : " << aTrack.GetPosition()
0112 << " aTrack Energy : " << G4BestUnit(aTrack.GetKineticEnergy(), "Energy") << G4endl;
0113 }
0114
0115
0116 if (aTrack.GetStepLength() <= fkCarTolerance / 2) {
0117 fTheStatus = StepTooSmall;
0118 if (verboseLevel > 0) {
0119 BoundaryProcessVerbose();
0120 }
0121 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
0122 }
0123
0124 const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
0125
0126
0127 fOldMomentum = aParticle->GetMomentumDirection();
0128 fOldPolarization = aParticle->GetPolarization();
0129 fOldPosition = pStep->GetPostStepPoint()->GetPosition();
0130 fNewPosition = fOldPosition;
0131
0132 if (verboseLevel > 0) {
0133 G4cout << " Old Momentum Direction: " << fOldMomentum << G4endl;
0134 G4cout << " Old Position: " << fNewPosition << G4endl;
0135 G4cout << "Get aTrack.GetParentID() : " << aTrack.GetParentID() << G4endl;
0136 }
0137
0138 auto theGlobalPoint = pStep->GetPostStepPoint()->GetPosition();
0139
0140 G4bool valid = false;
0141
0142
0143
0144 fTheGlobalNormal = G4TransportationManager::GetTransportationManager()
0145 ->GetNavigatorForTracking()
0146 ->GetGlobalExitNormal(theGlobalPoint, &valid);
0147
0148 if (valid) {
0149 fTheGlobalNormal = -fTheGlobalNormal;
0150 }
0151 else {
0152 G4cout << "global normal " << fTheGlobalNormal << G4endl;
0153 G4ExceptionDescription ed;
0154 ed << " PeriodicBoundaryProcess::PostStepDoIt(): "
0155 << " The Navigator reports that it returned an invalid normal" << G4endl;
0156 G4Exception("G4PeriodicBoundaryProcess::PostStepDoIt", "PerBoun01", FatalException, ed,
0157 "Invalid Surface Normal - Geometry must return valid surface normal");
0158 }
0159
0160 G4bool isWrongDirection = fOldMomentum * fTheGlobalNormal > 0.0;
0161 if (isWrongDirection) {
0162 if (verboseLevel > 0) {
0163 G4cout << "ftheGlobalNormal points in a wrong direction." << G4endl;
0164 G4cout << "Invalid Surface Normal - Geometry must return valid surface \
0165 normal pointing in the right direction"
0166 << G4endl;
0167 }
0168
0169 fTheGlobalNormal = -fTheGlobalNormal;
0170 }
0171
0172 if (thePostPV == nullptr) {
0173 G4ExceptionDescription ed;
0174 ed << " PeriodicBoundaryProcess::PostStepDoIt(): "
0175 << " thePostPV == nullptr" << G4endl;
0176 G4Exception("G4PeriodicBoundaryProcess::PostStepDoIt", "PB14", FatalException, ed,
0177 "Invalid thePostPV");
0178 }
0179 auto lvol = thePostPV->GetLogicalVolume();
0180
0181 if (lvol == nullptr) {
0182 G4ExceptionDescription ed;
0183 ed << " PeriodicBoundaryProcess::PostStepDoIt(): "
0184 << " lvol == nullptr" << G4endl;
0185 G4Exception("G4PeriodicBoundaryProcess::PostStepDoIt", "PB12", FatalException, ed,
0186 "Invalid lvol");
0187 }
0188
0189 if (verboseLevel > 0) {
0190 G4cout << "Post step logical " << lvol->GetName() << G4endl;
0191 }
0192
0193 G4LogicalVolume* dlvol = nullptr;
0194
0195 if (lvol->GetNoDaughters() > 0) {
0196 if (verboseLevel > 0) {
0197 G4cout << "eldest daughter " << lvol->GetDaughter(0)->GetName() << G4endl;
0198 }
0199
0200 dlvol = lvol->GetDaughter(0)->GetLogicalVolume();
0201 }
0202
0203 if (dlvol && dlvol->IsExtended()) {
0204 if (verboseLevel > 0) {
0205 G4cout << " Logical surface, periodic " << G4endl;
0206 }
0207
0208 G4bool on_x = fTheGlobalNormal.isParallel(G4ThreeVector(1, 0, 0));
0209 G4bool on_y = fTheGlobalNormal.isParallel(G4ThreeVector(0, 1, 0));
0210 G4bool on_z = fTheGlobalNormal.isParallel(G4ThreeVector(0, 0, 1));
0211
0212
0213 G4bool on_plane = (on_x || on_y || on_z);
0214
0215 if (!on_plane) {
0216 G4ExceptionDescription ed;
0217 ed << " G4PeriodicBoundaryProcess::ostStepDoIt(): "
0218 << " The particle is not on a surface of the cyclic world" << G4endl;
0219 G4Exception(
0220 "G4PeriodicBoundaryProcess::PostStepDoIt", "Periodic01", FatalException, ed,
0221 "Periodic boundary process must only occur for particle on periodic world surface");
0222 }
0223 else {
0224 G4bool on_x_and_periodic = (on_x && fPeriodicX);
0225 G4bool on_y_and_periodic = (on_y && fPeriodicY);
0226 G4bool on_z_and_periodic = (on_z && fPeriodicZ);
0227
0228 G4bool on_a_periodic_plane = (on_x_and_periodic || on_y_and_periodic || on_z_and_periodic);
0229
0230 if (on_a_periodic_plane) {
0231 if (verboseLevel > 0) {
0232 G4cout << " on periodic plane " << G4endl;
0233 }
0234
0235 fTheStatus = Cycling;
0236
0237 if (verboseLevel > 0) {
0238 G4cout << " periodic " << G4endl;
0239 }
0240
0241 if (verboseLevel > 0) {
0242 G4cout << "Global normal " << fTheGlobalNormal << G4endl;
0243 }
0244
0245
0246 if (on_x_and_periodic) {
0247 fNewPosition.setX(-fNewPosition.x());
0248 }
0249 else if (on_y_and_periodic) {
0250 fNewPosition.setY(-fNewPosition.y());
0251 }
0252 else if (on_z_and_periodic) {
0253 fNewPosition.setZ(-fNewPosition.z());
0254 }
0255 else {
0256 G4cout << "global normal does not belong to periodic plane!!" << G4endl;
0257 }
0258
0259 fNewMomentum = fOldMomentum.unit();
0260 fNewPolarization = fOldPolarization.unit();
0261
0262 if (verboseLevel > 0) {
0263 G4cout << " New Position: " << fNewPosition << G4endl;
0264 G4cout << " New Momentum Direction: " << fNewMomentum << G4endl;
0265 G4cout << " New Polarization: " << fNewPolarization << G4endl;
0266 BoundaryProcessVerbose();
0267 }
0268
0269 fParticleChange.ProposeMomentumDirection(fNewMomentum);
0270 fParticleChange.ProposePolarization(fNewPolarization);
0271 fParticleChange.ProposePosition(fNewPosition);
0272
0273 G4PathFinder::GetInstance()->ReLocate(fNewPosition);
0274 G4PathFinder::GetInstance()->ComputeSafety(fNewPosition);
0275
0276
0277 G4Navigator* gNavigator =
0278 G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking();
0279
0280
0281
0282 gNavigator->SetGeometricallyLimitedStep();
0283
0284
0285
0286 gNavigator->LocateGlobalPointAndSetup(fNewPosition, &fNewMomentum, false,
0287 false);
0288
0289
0290
0291 gNavigator->ComputeSafety(fNewPosition);
0292
0293
0294
0295 auto evtm = G4EventManager::GetEventManager();
0296 auto tckm = evtm->GetTrackingManager();
0297 auto pTrajectory = tckm->GimmeTrajectory();
0298 if (pTrajectory) {
0299 pTrajectory->AppendStep(pStep);
0300 }
0301 }
0302 }
0303 }
0304 return &fParticleChange;
0305 }
0306
0307
0308
0309 G4double PeriodicBoundaryProcess::GetMeanFreePath(const G4Track&, G4double,
0310 G4ForceCondition* condition)
0311 {
0312 *condition = Forced;
0313 return DBL_MAX;
0314 }
0315
0316
0317
0318 void PeriodicBoundaryProcess::BoundaryProcessVerbose()
0319 {
0320 if (fStatusMessages.count(fTheStatus) > 0) {
0321 G4cout << PeriodicBoundaryProcess::fStatusMessages[fTheStatus] << G4endl;
0322 }
0323 }
0324
0325