File indexing completed on 2026-04-10 07:50:34
0001 #pragma once
0002
0003 #include <csignal>
0004
0005 class G4Step ;
0006 class G4StepPoint ;
0007 class G4LogicalSurface ;
0008 class G4VPhysicalVolume ;
0009
0010 struct sphoton ;
0011 struct SCF ;
0012
0013
0014 enum {
0015 U4Step_UNSET,
0016 U4Step_NOT_AT_BOUNDARY,
0017 U4Step_MOTHER_TO_CHILD,
0018 U4Step_CHILD_TO_MOTHER,
0019 U4Step_CHILD_TO_CHILD,
0020 U4Step_UNEXPECTED
0021 };
0022
0023 struct U4Step
0024 {
0025 static const SCF* CF ;
0026
0027 static constexpr const char* UNSET = "UNSET" ;
0028 static constexpr const char* NOT_AT_BOUNDARY = "NOT_AT_BOUNDARY" ;
0029 static constexpr const char* MOTHER_TO_CHILD = "MOTHER_TO_CHILD" ;
0030 static constexpr const char* CHILD_TO_MOTHER = "CHILD_TO_MOTHER" ;
0031 static constexpr const char* CHILD_TO_CHILD = "CHILD_TO_CHILD" ;
0032 static constexpr const char* UNEXPECTED = "UNEXPECTED" ;
0033
0034 static const char* MockOpticksBoundaryIdentity_NOTE ;
0035 static void MockOpticksBoundaryIdentity(sphoton& current_photon, const G4Step* step, unsigned idx);
0036
0037 static unsigned PackIdentity(unsigned prim_idx, unsigned instance_id);
0038 static int KludgePrimIdx(const G4Step* step, unsigned type, unsigned idx);
0039
0040 static const char* Name(unsigned type);
0041 static bool IsProblem(unsigned type);
0042 static unsigned Classify(const G4Step* step);
0043 static bool IsOnBoundary( const G4Step* step );
0044 static std::string BoundarySpec( const G4Step* step );
0045 static std::string BoundarySpec_(const G4Step* step );
0046 static const G4VSolid* Solid(const G4StepPoint* point );
0047 static G4LogicalSurface* GetLogicalSurface(const G4VPhysicalVolume* thePrePV, const G4VPhysicalVolume* thePostPV);
0048 static std::string Spec(const G4Step* step);
0049
0050
0051 static bool IsSameMaterial(const G4Step* step, const char* q_matname );
0052 static bool IsPVBorder(const G4Step* step, const char* q_pvname1, const char* q_pvname2 );
0053 static bool IsSameMaterialPVBorder( const G4Step* step, const char* q_matname, const char* q_pvname1, const char* q_pvname2 );
0054
0055 };
0056
0057
0058 const SCF* U4Step::CF = SCF::Create() ;
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084 const char* U4Step::MockOpticksBoundaryIdentity_NOTE = R"(
0085 U4Step::MockOpticksBoundaryIdentity
0086 ====================================
0087
0088 Mocking Opticks requires CFBASE envvar which allows instanciation of SCF
0089 This means that when changing the U4VolumeMaker geometry it is necessary to
0090 run the Opticks gxs.sh GPU simulation first and grab the CSGFoundry geometry
0091 back to the machine running the Geant4 simulation.
0092
0093 eg::
0094
0095 gx
0096 ./gxs.sh run # workstation
0097 ./gxs.sh grab # laptop
0098
0099 u4
0100 ./u4s.sh run # CFBASE is set by the script to pick up the CF geometry
0101
0102 )";
0103
0104
0105 inline void U4Step::MockOpticksBoundaryIdentity(sphoton& current_photon, const G4Step* step, unsigned idx)
0106 {
0107 if(CF == nullptr) std::cerr << MockOpticksBoundaryIdentity_NOTE ;
0108 assert(CF);
0109
0110 std::string spec = BoundarySpec(step) ;
0111 unsigned boundary = spec.empty() ? 0 : CF->getBoundary(spec.c_str()) ;
0112 unsigned type = U4Step::Classify(step);
0113 int kludge_prim_idx = KludgePrimIdx(step, type, idx) ;
0114 unsigned kludge_prim_idx_ = kludge_prim_idx == -1 ? 0xffff : kludge_prim_idx ;
0115
0116 float cosThetaSign = 0.f ;
0117
0118 switch(type)
0119 {
0120 case U4Step_NOT_AT_BOUNDARY: cosThetaSign = 0.f ; break ;
0121 case U4Step_MOTHER_TO_CHILD: cosThetaSign = -1.f ; break ;
0122 case U4Step_CHILD_TO_MOTHER: cosThetaSign = 1.f ; break ;
0123 }
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149 current_photon.set_orient( cosThetaSign );
0150 current_photon.set_boundary( boundary);
0151 current_photon.identity = PackIdentity( kludge_prim_idx_, 0u) ;
0152 }
0153 inline unsigned U4Step::PackIdentity(unsigned prim_idx, unsigned instance_id)
0154 {
0155 unsigned identity = (( prim_idx & 0xffff ) << 16 ) | ( instance_id & 0xffff ) ;
0156 return identity ;
0157 }
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200 inline int U4Step::KludgePrimIdx(const G4Step* step, unsigned type, unsigned idx)
0201 {
0202
0203 const G4StepPoint* pre = step->GetPreStepPoint() ;
0204 const G4StepPoint* post = step->GetPostStepPoint() ;
0205
0206 const G4VSolid* pre_so = U4Step::Solid(pre) ;
0207 const G4VSolid* post_so = U4Step::Solid(post) ;
0208 G4String pre_so_name = pre_so ? pre_so->GetName() : "" ;
0209 G4String post_so_name = post_so ? post_so->GetName() : "" ;
0210
0211 if( pre_so_name.empty() || post_so_name.empty() )
0212 std::cerr
0213 << "U4Step::KludgePrimIdx EMPTY NAME "
0214 << " pre_so_name " << pre_so_name
0215 << " post_so_name " << post_so_name
0216 << std::endl
0217 ;
0218
0219
0220 int pre_prim_idx = CF->getPrimIdx(pre_so_name.c_str()) ;
0221 int post_prim_idx = CF->getPrimIdx(post_so_name.c_str()) ;
0222
0223 int kludge_prim_idx = 0 ;
0224 switch(type)
0225 {
0226 case U4Step_MOTHER_TO_CHILD: kludge_prim_idx = post_prim_idx ; break ;
0227 case U4Step_CHILD_TO_MOTHER: kludge_prim_idx = pre_prim_idx ; break ;
0228 default: kludge_prim_idx = 0 ; break ;
0229 }
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243 return kludge_prim_idx ;
0244 }
0245
0246
0247
0248
0249
0250
0251
0252 inline const char* U4Step::Name(unsigned type)
0253 {
0254 const char* s = nullptr ;
0255 switch(type)
0256 {
0257 case U4Step_UNSET: s = UNSET ; break ;
0258 case U4Step_NOT_AT_BOUNDARY: s = NOT_AT_BOUNDARY ; break ;
0259 case U4Step_MOTHER_TO_CHILD: s = MOTHER_TO_CHILD ; break ;
0260 case U4Step_CHILD_TO_MOTHER: s = CHILD_TO_MOTHER ; break ;
0261 case U4Step_CHILD_TO_CHILD: s = CHILD_TO_CHILD ; break ;
0262 case U4Step_UNEXPECTED: s = UNEXPECTED ; break ;
0263 }
0264 return s ;
0265 }
0266
0267 inline bool U4Step::IsProblem(unsigned type)
0268 {
0269 return type == U4Step_UNSET || type == U4Step_CHILD_TO_CHILD || type == U4Step_UNEXPECTED ;
0270 }
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328 inline unsigned U4Step::Classify(const G4Step* step)
0329 {
0330 const G4StepPoint* pre = step->GetPreStepPoint() ;
0331 const G4StepPoint* post = step->GetPostStepPoint() ;
0332 bool not_post_boundary = post->GetStepStatus() != fGeomBoundary ;
0333 if(not_post_boundary) return U4Step_NOT_AT_BOUNDARY ;
0334
0335 const G4VPhysicalVolume* thePrePV = pre->GetPhysicalVolume();
0336 const G4VPhysicalVolume* thePostPV = post->GetPhysicalVolume();
0337
0338 bool pre_is_post_mother = thePrePV->GetLogicalVolume() == thePostPV->GetMotherLogical() ;
0339 bool pre_mother_is_post = thePrePV->GetMotherLogical() == thePostPV->GetLogicalVolume() ;
0340 bool pre_mother_is_post_mother = thePrePV->GetMotherLogical() == thePostPV->GetMotherLogical() ;
0341
0342 bool expect_exclusive = int(pre_is_post_mother) + int(pre_mother_is_post) + int(pre_mother_is_post_mother) <= 1 ;
0343 assert( expect_exclusive ) ;
0344 if(!expect_exclusive) std::raise(SIGINT);
0345
0346 unsigned type = U4Step_UNSET ;
0347 if( pre_is_post_mother ) type = U4Step_MOTHER_TO_CHILD ;
0348 else if( pre_mother_is_post ) type = U4Step_CHILD_TO_MOTHER ;
0349 else if( pre_mother_is_post_mother ) type = U4Step_CHILD_TO_CHILD ;
0350 else type = U4Step_UNEXPECTED ;
0351
0352 return type ;
0353 }
0354
0355
0356 inline bool U4Step::IsOnBoundary( const G4Step* step )
0357 {
0358 const G4StepPoint* post = step->GetPostStepPoint() ;
0359 G4bool isOnBoundary = post->GetStepStatus() == fGeomBoundary ;
0360 return isOnBoundary ;
0361 }
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382 inline std::string U4Step::BoundarySpec(const G4Step* step )
0383 {
0384 return IsOnBoundary(step) ? BoundarySpec_(step) : "" ;
0385 }
0386 inline std::string U4Step::BoundarySpec_(const G4Step* step)
0387 {
0388 const G4StepPoint* pre = step->GetPreStepPoint() ;
0389 const G4StepPoint* post = step->GetPostStepPoint() ;
0390 const G4Material* m1 = pre->GetMaterial();
0391 const G4Material* m2 = post->GetMaterial();
0392 const char* n1 = m1->GetName().c_str() ;
0393 const char* n2 = m2->GetName().c_str() ;
0394
0395 const G4VPhysicalVolume* thePrePV = pre->GetPhysicalVolume();
0396 const G4VPhysicalVolume* thePostPV = post->GetPhysicalVolume();
0397 G4bool enteredDaughter = thePostPV->GetMotherLogical() == thePrePV ->GetLogicalVolume();
0398
0399 const char* omat = enteredDaughter ? n1 : n2 ;
0400 const char* imat = enteredDaughter ? n2 : n1 ;
0401
0402 const G4LogicalSurface* surf1 = GetLogicalSurface(thePrePV, thePostPV );
0403 const G4LogicalSurface* surf2 = GetLogicalSurface(thePostPV, thePrePV );
0404
0405 const char* osur = nullptr ;
0406 const char* isur = nullptr ;
0407
0408 if( enteredDaughter )
0409 {
0410 osur = surf1 ? surf1->GetName().c_str() : nullptr ;
0411 isur = surf2 ? surf2->GetName().c_str() : nullptr ;
0412 }
0413 else
0414 {
0415 osur = surf2 ? surf2->GetName().c_str() : nullptr ;
0416 isur = surf1 ? surf1->GetName().c_str() : nullptr ;
0417 }
0418
0419 std::stringstream ss ;
0420 ss
0421 << omat
0422 << "/"
0423 << ( osur ? osur : "" )
0424 << "/"
0425 << ( isur ? isur : "" )
0426 << "/"
0427 << imat
0428 ;
0429
0430 std::string s = ss.str();
0431 return s ;
0432 }
0433
0434
0435 inline G4LogicalSurface* U4Step::GetLogicalSurface(const G4VPhysicalVolume* thePrePV, const G4VPhysicalVolume* thePostPV)
0436 {
0437 G4LogicalSurface* Surface = G4LogicalBorderSurface::GetSurface(thePrePV, thePostPV);
0438 if (Surface == nullptr)
0439 {
0440 G4bool enteredDaughter = thePostPV->GetMotherLogical() == thePrePV ->GetLogicalVolume();
0441
0442 if(enteredDaughter)
0443 {
0444 Surface = G4LogicalSkinSurface::GetSurface(thePostPV->GetLogicalVolume());
0445 if(Surface == nullptr) Surface = G4LogicalSkinSurface::GetSurface(thePrePV->GetLogicalVolume());
0446 }
0447 else
0448 {
0449 Surface = G4LogicalSkinSurface::GetSurface(thePrePV->GetLogicalVolume());
0450 if(Surface == NULL) Surface = G4LogicalSkinSurface::GetSurface(thePostPV->GetLogicalVolume());
0451 }
0452 }
0453 return Surface ;
0454 }
0455
0456
0457
0458 inline const G4VSolid* U4Step::Solid(const G4StepPoint* point )
0459 {
0460 const G4VPhysicalVolume* pv = point->GetPhysicalVolume();
0461 const G4LogicalVolume* lv = pv ? pv->GetLogicalVolume() : nullptr ;
0462 const G4VSolid* so = lv ? lv->GetSolid() : nullptr ;
0463 return so ;
0464 }
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478 inline std::string U4Step::Spec(const G4Step* step)
0479 {
0480 const G4Track* track = step->GetTrack();
0481
0482 G4VPhysicalVolume* pv = track->GetVolume() ;
0483 G4VPhysicalVolume* next_pv = track->GetNextVolume() ;
0484
0485 const G4StepPoint* pre = step->GetPreStepPoint() ;
0486 const G4StepPoint* post = step->GetPostStepPoint() ;
0487
0488 const G4VPhysicalVolume* pre_pv = pre->GetPhysicalVolume();
0489 const G4VPhysicalVolume* post_pv = post->GetPhysicalVolume();
0490
0491
0492 bool pre_pv_expect = pv == pre_pv ;
0493 bool post_pv_expect = next_pv == post_pv ;
0494
0495 assert( pre_pv_expect );
0496 assert( post_pv_expect );
0497
0498 if(!pre_pv_expect) std::raise(SIGINT);
0499 if(!post_pv_expect) std::raise(SIGINT);
0500
0501
0502 const G4Material* pre_mat = pre->GetMaterial();
0503 const G4Material* post_mat = post->GetMaterial();
0504
0505 std::stringstream ss ;
0506 ss
0507 << ( pre_mat ? pre_mat->GetName() : "-" )
0508 << "/"
0509 << ( post_mat ? post_mat->GetName() : "-" )
0510 << ":"
0511 << ( pv ? pv->GetName() : "-" )
0512 << "/"
0513 << ( next_pv ? next_pv->GetName() : "-" )
0514 ;
0515
0516 std::string str = ss.str() ;
0517 return str ;
0518 }
0519
0520
0521 inline bool U4Step::IsSameMaterial(const G4Step* step, const char* q_matname )
0522 {
0523 const G4StepPoint* pre = step->GetPreStepPoint() ;
0524 const G4StepPoint* post = step->GetPostStepPoint() ;
0525
0526 const G4Material* pre_mat = pre->GetMaterial();
0527 const G4Material* post_mat = post->GetMaterial();
0528
0529 const char* matname = pre_mat->GetName().c_str();
0530 bool same_material = pre_mat == post_mat && strcmp(matname, q_matname) == 0 ;
0531
0532 return same_material ;
0533 }
0534
0535
0536 inline bool U4Step::IsPVBorder(const G4Step* step, const char* q_pvname1, const char* q_pvname2 )
0537 {
0538 const G4StepPoint* pre = step->GetPreStepPoint() ;
0539 const G4StepPoint* post = step->GetPostStepPoint() ;
0540
0541 const G4VPhysicalVolume* pre_pv = pre->GetPhysicalVolume();
0542 const G4VPhysicalVolume* post_pv = post->GetPhysicalVolume();
0543
0544 const char* pre_pvname = pre_pv->GetName().c_str();
0545 const char* post_pvname = post_pv->GetName().c_str();
0546
0547 bool pre_pvname1 = strstr( pre_pvname, q_pvname1 ) != nullptr ;
0548 bool pre_pvname2 = strstr( pre_pvname, q_pvname2 ) != nullptr ;
0549 bool post_pvname1 = strstr( post_pvname, q_pvname1 ) != nullptr ;
0550 bool post_pvname2 = strstr( post_pvname, q_pvname2 ) != nullptr ;
0551
0552 bool is_pvborder_12 = pre_pvname1 && post_pvname2 ;
0553 bool is_pvborder_21 = pre_pvname2 && post_pvname1 ;
0554 bool is_pvborder = is_pvborder_12 || is_pvborder_21 ;
0555
0556 return is_pvborder ;
0557 }
0558
0559 inline bool U4Step::IsSameMaterialPVBorder( const G4Step* step, const char* q_matname, const char* q_pvname1, const char* q_pvname2 )
0560 {
0561 return IsSameMaterial(step, q_matname) && IsPVBorder(step, q_pvname1, q_pvname2 );
0562 }
0563
0564