File indexing completed on 2025-01-30 10:09:31
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010 #include <algorithm>
0011 #include <type_traits>
0012 #include <G4LogicalVolume.hh>
0013 #include <G4Navigator.hh>
0014 #include <G4TouchableHandle.hh>
0015 #include <G4TouchableHistory.hh>
0016
0017 #include "corecel/Macros.hh"
0018 #include "corecel/math/Algorithms.hh"
0019 #include "corecel/math/ArrayUtils.hh"
0020 #include "corecel/math/SoftEqual.hh"
0021 #include "geocel/Types.hh"
0022
0023 #include "Convert.geant.hh"
0024 #include "GeantGeoData.hh"
0025
0026 namespace celeritas
0027 {
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 class GeantGeoTrackView
0043 {
0044 public:
0045
0046
0047 using Initializer_t = GeoTrackInitializer;
0048 using ParamsRef = NativeCRef<GeantGeoParamsData>;
0049 using StateRef = NativeRef<GeantGeoStateData>;
0050 using real_type = double;
0051 using Real3 = Array<real_type, 3>;
0052
0053
0054
0055 struct DetailedInitializer
0056 {
0057 GeantGeoTrackView const& other;
0058 Real3 dir;
0059 };
0060
0061 public:
0062
0063 inline GeantGeoTrackView(ParamsRef const& params,
0064 StateRef const& state,
0065 TrackSlotId tid);
0066
0067
0068 inline GeantGeoTrackView& operator=(Initializer_t const& init);
0069
0070 inline GeantGeoTrackView& operator=(DetailedInitializer const& init);
0071
0072
0073
0074
0075 static constexpr real_type extra_push()
0076 {
0077 return 1e-12 * lengthunits::millimeter;
0078 }
0079
0080
0081
0082
0083
0084 CELER_FORCEINLINE Real3 const& pos() const { return pos_; }
0085 CELER_FORCEINLINE Real3 const& dir() const { return dir_; }
0086
0087
0088
0089 CELER_FORCEINLINE VolumeId volume_id() const;
0090 CELER_FORCEINLINE int volume_physid() const;
0091
0092
0093
0094 SurfaceId surface_id() const { return {}; }
0095 SurfaceId next_surface_id() const { return {}; }
0096
0097
0098
0099 CELER_FORCEINLINE bool is_outside() const;
0100
0101 CELER_FORCEINLINE bool is_on_boundary() const;
0102
0103 CELER_FORCEINLINE bool failed() const { return false; }
0104
0105
0106
0107
0108 inline Propagation find_next_step();
0109
0110
0111 inline Propagation find_next_step(real_type max_step);
0112
0113
0114 inline real_type find_safety();
0115
0116
0117 inline CELER_FUNCTION real_type find_safety(real_type max_step);
0118
0119
0120 inline void move_to_boundary();
0121
0122
0123 inline void move_internal(real_type step);
0124
0125
0126 inline void move_internal(Real3 const& pos);
0127
0128
0129 inline void cross_boundary();
0130
0131
0132 inline void set_dir(Real3 const& newdir);
0133
0134 private:
0135
0136
0137
0138
0139 Real3& pos_;
0140 Real3& dir_;
0141 real_type& next_step_;
0142 real_type& safety_radius_;
0143 G4TouchableHandle& touch_handle_;
0144 G4Navigator& navi_;
0145
0146
0147
0148 G4ThreeVector g4pos_;
0149 G4ThreeVector g4dir_;
0150 real_type g4safety_;
0151
0152
0153
0154
0155 inline bool has_next_step() const;
0156
0157
0158 inline G4LogicalVolume const* volume() const;
0159 };
0160
0161
0162
0163
0164
0165
0166
0167 GeantGeoTrackView::GeantGeoTrackView(ParamsRef const&,
0168 StateRef const& states,
0169 TrackSlotId tid)
0170 : pos_(states.pos[tid])
0171 , dir_(states.dir[tid])
0172 , next_step_(states.next_step[tid])
0173 , safety_radius_(states.safety_radius[tid])
0174 , touch_handle_(states.nav_state.touch_handle(tid))
0175 , navi_(states.nav_state.navigator(tid))
0176 {
0177 g4pos_ = convert_to_geant(pos_, clhep_length);
0178 g4dir_ = convert_to_geant(dir_, 1);
0179 g4safety_ = convert_to_geant(safety_radius_, clhep_length);
0180 }
0181
0182
0183
0184
0185
0186 GeantGeoTrackView& GeantGeoTrackView::operator=(Initializer_t const& init)
0187 {
0188 CELER_EXPECT(is_soft_unit_vector(init.dir));
0189
0190
0191 std::copy(init.pos.begin(), init.pos.end(), pos_.begin());
0192 std::copy(init.dir.begin(), init.dir.end(), dir_.begin());
0193 next_step_ = 0;
0194 safety_radius_ = -1;
0195
0196 g4pos_ = convert_to_geant(pos_, clhep_length);
0197 g4dir_ = convert_to_geant(dir_, 1);
0198 g4safety_ = -1;
0199
0200 navi_.LocateGlobalPointAndUpdateTouchable(g4pos_,
0201 g4dir_,
0202 touch_handle_(),
0203 false);
0204
0205 CELER_ENSURE(!this->has_next_step());
0206 return *this;
0207 }
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217 GeantGeoTrackView& GeantGeoTrackView::operator=(DetailedInitializer const& init)
0218 {
0219 CELER_EXPECT(is_soft_unit_vector(init.dir));
0220
0221 if (this != &init.other)
0222 {
0223
0224 pos_ = init.other.pos_;
0225 safety_radius_ = init.other.safety_radius_;
0226 g4pos_ = init.other.g4pos_;
0227 g4dir_ = init.other.g4dir_;
0228 g4safety_ = init.other.g4safety_;
0229
0230
0231 touch_handle_ = init.other.touch_handle_;
0232 navi_.ResetHierarchyAndLocate(
0233 g4pos_, g4dir_, dynamic_cast<G4TouchableHistory&>(*touch_handle_()));
0234 }
0235
0236
0237 dir_ = init.dir;
0238 next_step_ = 0;
0239
0240 CELER_ENSURE(!this->has_next_step());
0241 return *this;
0242 }
0243
0244
0245
0246
0247
0248 VolumeId GeantGeoTrackView::volume_id() const
0249 {
0250 CELER_EXPECT(!this->is_outside());
0251 auto inst_id = this->volume()->GetInstanceID();
0252 CELER_ENSURE(inst_id >= 0);
0253 return VolumeId{static_cast<VolumeId::size_type>(inst_id)};
0254 }
0255
0256
0257
0258
0259
0260 int GeantGeoTrackView::volume_physid() const
0261 {
0262 CELER_EXPECT(!this->is_outside());
0263 G4VPhysicalVolume* pv = touch_handle_()->GetVolume(0);
0264 if (!pv)
0265 return -1;
0266 return pv->GetInstanceID();
0267 }
0268
0269
0270
0271
0272
0273 bool GeantGeoTrackView::is_outside() const
0274 {
0275 return this->volume() == nullptr;
0276 }
0277
0278
0279
0280
0281
0282 bool GeantGeoTrackView::is_on_boundary() const
0283 {
0284 return safety_radius_ == 0.0;
0285 }
0286
0287
0288
0289
0290
0291 Propagation GeantGeoTrackView::find_next_step()
0292 {
0293 return this->find_next_step(numeric_limits<real_type>::infinity());
0294 }
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304 Propagation GeantGeoTrackView::find_next_step(real_type max_step)
0305 {
0306 CELER_EXPECT(!this->is_outside());
0307 CELER_EXPECT(max_step > 0);
0308
0309
0310 real_type g4step = convert_to_geant(max_step, clhep_length);
0311 g4step = navi_.ComputeStep(g4pos_, g4dir_, g4step, g4safety_);
0312
0313 if (g4safety_ != 0 && !this->is_on_boundary())
0314 {
0315
0316
0317 safety_radius_ = convert_from_geant(g4safety_, clhep_length);
0318 CELER_ASSERT(!this->is_on_boundary());
0319 }
0320
0321
0322 Propagation result;
0323 result.distance = convert_from_geant(g4step, clhep_length);
0324 if (result.distance <= max_step)
0325 {
0326 result.boundary = true;
0327 result.distance
0328 = celeritas::max<real_type>(result.distance, this->extra_push());
0329 CELER_ENSURE(result.distance > 0);
0330 }
0331 else
0332 {
0333
0334 result.distance = max_step;
0335 CELER_ENSURE(result.distance > 0);
0336 }
0337
0338
0339 next_step_ = result.distance;
0340
0341 CELER_ENSURE(result.distance > 0);
0342 CELER_ENSURE(result.distance <= max(max_step, this->extra_push()));
0343 CELER_ENSURE(result.boundary || result.distance == max_step
0344 || max_step < this->extra_push());
0345 CELER_ENSURE(this->has_next_step());
0346 return result;
0347 }
0348
0349
0350
0351
0352
0353 auto GeantGeoTrackView::find_safety() -> real_type
0354 {
0355 return this->find_safety(numeric_limits<real_type>::infinity());
0356 }
0357
0358
0359
0360
0361
0362
0363
0364
0365 auto GeantGeoTrackView::find_safety(real_type max_step) -> real_type
0366 {
0367 CELER_EXPECT(max_step > 0);
0368 if (!this->is_on_boundary() && (safety_radius_ < max_step))
0369 {
0370 real_type g4step = convert_to_geant(max_step, clhep_length);
0371 g4safety_ = navi_.ComputeSafety(g4pos_, g4step);
0372 safety_radius_ = max(convert_from_geant(g4safety_, clhep_length), 0.0);
0373 }
0374
0375 return safety_radius_;
0376 }
0377
0378
0379
0380
0381
0382 void GeantGeoTrackView::move_to_boundary()
0383 {
0384 CELER_EXPECT(this->has_next_step());
0385
0386
0387 axpy(next_step_, dir_, &pos_);
0388 axpy(convert_to_geant(next_step_, clhep_length), g4dir_, &g4pos_);
0389 next_step_ = 0;
0390 safety_radius_ = 0;
0391 g4safety_ = 0;
0392 navi_.SetGeometricallyLimitedStep();
0393
0394 CELER_ENSURE(this->is_on_boundary());
0395 }
0396
0397
0398
0399
0400
0401
0402
0403 void GeantGeoTrackView::cross_boundary()
0404 {
0405 CELER_EXPECT(this->is_on_boundary());
0406
0407 navi_.LocateGlobalPointAndUpdateTouchableHandle(
0408 g4pos_,
0409 g4dir_,
0410 touch_handle_,
0411 true);
0412
0413 CELER_ENSURE(this->is_on_boundary());
0414 }
0415
0416
0417
0418
0419
0420
0421
0422
0423 void GeantGeoTrackView::move_internal(real_type dist)
0424 {
0425 CELER_EXPECT(this->has_next_step());
0426 CELER_EXPECT(dist > 0 && dist <= next_step_);
0427
0428
0429 axpy(dist, dir_, &pos_);
0430 axpy(convert_to_geant(dist, clhep_length), g4dir_, &g4pos_);
0431 next_step_ -= dist;
0432 navi_.LocateGlobalPointWithinVolume(g4pos_);
0433
0434 safety_radius_ = -1;
0435 g4safety_ = 0;
0436 }
0437
0438
0439
0440
0441
0442
0443
0444
0445 void GeantGeoTrackView::move_internal(Real3 const& pos)
0446 {
0447 pos_ = pos;
0448 g4pos_ = convert_to_geant(pos_, clhep_length);
0449 next_step_ = 0;
0450 navi_.LocateGlobalPointWithinVolume(g4pos_);
0451
0452 safety_radius_ = -1;
0453 g4safety_ = 0;
0454 }
0455
0456
0457
0458
0459
0460
0461
0462
0463 void GeantGeoTrackView::set_dir(Real3 const& newdir)
0464 {
0465 CELER_EXPECT(is_soft_unit_vector(newdir));
0466 dir_ = newdir;
0467 g4dir_ = convert_to_geant(newdir, 1);
0468 next_step_ = 0;
0469 }
0470
0471
0472
0473
0474
0475
0476
0477 bool GeantGeoTrackView::has_next_step() const
0478 {
0479 return next_step_ != 0;
0480 }
0481
0482
0483
0484
0485
0486 auto GeantGeoTrackView::volume() const -> G4LogicalVolume const*
0487 {
0488 CELER_EXPECT(touch_handle_());
0489 G4VPhysicalVolume* pv = touch_handle_()->GetVolume(0);
0490 if (!pv)
0491 return nullptr;
0492
0493 return pv->GetLogicalVolume();
0494 }
0495
0496
0497 }