Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-10 07:50:35

0001 #pragma once
0002 /**
0003 U4TreeBorder.h : Implicit surface handling : TODO : pick a better name 
0004 =========================================================================
0005 
0006 * see ~/opticks/notes/issues/stree_bd_names_and_Implicit_RINDEX_NoRINDEX.rst
0007 * causes difference between SSim/bnd_names.txt and SSim/stree/bd_names.txt
0008 
0009 All transparent materials like Scintillator, Acrylic, Water should have RINDEX property. 
0010 Some absorbing materials like Tyvek might not have RINDEX property as 
0011 lazy Physicists sometimes rely on sloppy Geant4 implicit behavior 
0012 which causes fStopAndKill at the RINDEX->NoRINDEX boundary
0013 as if there was a perfect absorbing surface there.  
0014 
0015 To mimic the implicit surface Geant4 behaviour with Opticks on GPU 
0016 it is necessary to add explicit perfect absorber surfaces. 
0017 
0018 First try at implicit handling
0019 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0020 
0021 HMM: want to mint only the minimum number of implicits
0022 so need to define a name that captures the desired identity 
0023 and only collect more implicits when they have different names. 
0024 
0025 Implicit border surface "directionality" is always 
0026 from the material with RINDEX to the material without RINDEX 
0027 
0028 U4SurfaceArray is assuming the implicits all appear together
0029 after standard surfaces and before perfects. 
0030 All standard surfaces are collected in initSurfaces so 
0031 have a constant base of surfaces ontop of which to 
0032 add implicits. 
0033 
0034 When an implicit is detected the osur or isur is 
0035 changed accordingly.   
0036 
0037 Confusing and pointless osur from absorbers
0038 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0039 
0040 see ~/opticks/notes/issues/optical_ems_4_getting_too_many_from_non_sensor_Vacuum_Steel_borders.rst
0041 
0042 
0043 **/
0044 
0045 #include "ssys.h"
0046 #include "U4Mat.h"
0047 
0048 
0049 struct U4TreeBorder 
0050 {
0051     stree* st ; 
0052 
0053     const G4LogicalVolume* const lv ; 
0054     const G4LogicalVolume* const lv_p ;  
0055     const G4Material* const imat_ ; 
0056     const G4Material* const omat_ ; 
0057     const char* imat ; 
0058     const char* omat ; 
0059     const G4VSolid* isolid_ ; 
0060     const G4VSolid* osolid_ ;
0061     G4String isolid ; // unavoidable, because G4VSolid::GetName returns by value 
0062     G4String osolid ; 
0063     const char* _isolid ;  
0064     const char* _osolid ; 
0065     const std::string& inam ; 
0066     const std::string& onam ; 
0067 
0068     const G4MaterialPropertyVector* i_rindex ; 
0069     const G4MaterialPropertyVector* o_rindex ; 
0070 
0071     const G4LogicalSurface* const osur_ ; 
0072     const G4LogicalSurface* const isur_ ;  
0073 
0074     int  implicit_idx ; 
0075     bool implicit_isur ; 
0076     bool implicit_osur ; 
0077 
0078     const char* flagged_isolid ; 
0079 
0080     U4TreeBorder(
0081         stree* st_, 
0082         const G4VPhysicalVolume* const pv, 
0083         const G4VPhysicalVolume* const pv_p 
0084         ); 
0085 
0086     std::string desc() const ; 
0087     bool is_flagged() const ; 
0088 
0089     int  get_surface_idx_of_implicit(bool flip); 
0090 
0091     bool has_osur_override( const int4& bd ) const ; 
0092     bool has_isur_override( const int4& bd ) const ; 
0093     void do_osur_override( int4& bd ) ; 
0094     void do_isur_override( int4& bd ) ; 
0095 
0096     void check( const int4& bd )  ; 
0097 }; 
0098 
0099 /**
0100 U4TreeBorder::U4TreeBorder
0101 -----------------------------
0102 
0103 Boundary spec::
0104 
0105    omat/osur/isur/imat 
0106     
0107    +-----------------------------+
0108    |                             |
0109    | pv_p    omat    osolid      |
0110    |              ||             |     implicit_osur : o_rindex != nullptr && i_rindex = nullptr
0111    |              ||             | 
0112    |         osur \/             |     osur : relevant for photons going from pv_p -> pv ( outer to inner, ingoing )
0113    +-----------------------------+ 
0114    |         isur /\             |     isur : relevant for photons goes from pv -> pv_p  ( inner to outer, outgoing ) 
0115    |              ||             | 
0116    |              ||             |     implicit_isur : i_rindex != nullptr && o_rindex == nullptr
0117    | pv      imat    isolid      |
0118    |                             |
0119    +-----------------------------+
0120 
0121 **/
0122 
0123 
0124 inline U4TreeBorder::U4TreeBorder(
0125     stree* st_, 
0126     const G4VPhysicalVolume* const pv, 
0127     const G4VPhysicalVolume* const pv_p )
0128     :
0129     st(st_),
0130     lv(pv->GetLogicalVolume()),
0131     lv_p(pv_p ? pv_p->GetLogicalVolume() : lv),
0132     imat_(lv->GetMaterial()),
0133     omat_(lv_p ? lv_p->GetMaterial() : imat_), // top omat -> imat 
0134     imat(imat_->GetName().c_str()),
0135     omat(omat_->GetName().c_str()),
0136     isolid_(lv->GetSolid()),
0137     osolid_(lv_p->GetSolid()),
0138     isolid(isolid_->GetName()),
0139     osolid(osolid_->GetName()),
0140     _isolid(isolid.c_str()),
0141     _osolid(osolid.c_str()),
0142     inam(pv->GetName()), 
0143     onam(pv_p ? pv_p->GetName() : inam), 
0144     i_rindex(U4Mat::GetRINDEX( imat_ )), 
0145     o_rindex(U4Mat::GetRINDEX( omat_ )),
0146     osur_(U4Surface::Find( pv_p, pv )),    // look for border or skin surface, HMM: maybe disable for o_rindex == nullptr ?
0147     isur_( i_rindex == nullptr ? nullptr : U4Surface::Find( pv, pv_p )), // disable isur from absorbers without RINDEX
0148     implicit_idx(-1),
0149     implicit_isur(i_rindex != nullptr && o_rindex == nullptr),  
0150     implicit_osur(o_rindex != nullptr && i_rindex == nullptr),
0151     flagged_isolid(ssys::getenvvar("U4TreeBorder__FLAGGED_ISOLID", "PLACEHOLDER_FOR_SOLIDNAME_LIKE_sStrutBallhead"))
0152 {
0153 }
0154 
0155 
0156 inline std::string U4TreeBorder::desc() const 
0157 {
0158     std::stringstream ss ; 
0159     ss << "U4TreeBorder::desc" << std::endl 
0160        << " omat " << omat << std::endl 
0161        << " imat " << imat << std::endl 
0162        << " osolid " << osolid << std::endl 
0163        << " isolid " << isolid << std::endl 
0164        << " is_flagged " << ( is_flagged() ? "YES" : "NO " ) 
0165        ;
0166     std::string str = ss.str(); 
0167     return str ; 
0168 }
0169 
0170 inline bool U4TreeBorder::is_flagged() const 
0171 {
0172     return _isolid && flagged_isolid && strcmp(_isolid, flagged_isolid ) == 0 ;  
0173 }
0174 
0175 
0176 
0177 
0178 /**
0179 U4TreeBorder::get_surface_idx_of_implicit
0180 -------------------------------------------
0181 
0182 +---------------------------------+-----------------+
0183 |  Callers                        |  flip           |
0184 +=================================+=================+ 
0185 |  U4TreeBorder::do_osur_override |  true           |
0186 +---------------------------------+-----------------+  
0187 |  U4TreeBorder::do_isur_override |  false          |
0188 +---------------------------------+-----------------+  
0189 
0190 
0191 1. uses inam and onam pv name to form a name for the implicit surface
0192 2. adds implicit name to the stree suname vector if not already present 
0193    and returns the standard surface index  
0194 
0195 
0196 **/
0197 
0198 inline int U4TreeBorder::get_surface_idx_of_implicit(bool flip)
0199 {
0200     std::string implicit_ = S4::ImplicitBorderSurfaceName(inam, onam, flip );   // based on pv pv_p names
0201     const char* implicit = implicit_.c_str(); 
0202     int surface_idx = st->add_surface_implicit(implicit) ;  // now returns standard surface idx 
0203     return surface_idx ; 
0204 }
0205 
0206 /**
0207 U4TreeBorder::has_osur_override
0208 --------------------------------
0209 
0210 Only returns true when:
0211 
0212 1. materials are RINDEX->NoRINDEX 
0213 2. AND no corresponding surface defined already 
0214 
0215 The old X4/GGeo workflow does similar to 
0216 this in X4PhysicalVolume::convertImplicitSurfaces_r
0217 but in addition that workflow skips osur, doing only isur
0218 for no valid reason that I can find/recall. 
0219 
0220 **/
0221 
0222 inline bool U4TreeBorder::has_osur_override( const int4& bd ) const 
0223 {
0224     const int& osur = bd.y ; 
0225     return osur == -1 && implicit_osur == true ;  
0226 }
0227 inline bool U4TreeBorder::has_isur_override( const int4& bd ) const 
0228 {
0229     const int& isur = bd.z ; 
0230     return isur == -1 && implicit_isur == true ;  
0231 }
0232 
0233 /**
0234 U4TreeBorder::do_osur_override U4TreeBorder::do_isur_override
0235 --------------------------------------------------------------
0236 
0237 Called from U4Tree::initNodes_r when osur/isur implicits are enabled
0238 and the above has override methods return true. 
0239 
0240 **/
0241 
0242 inline void U4TreeBorder::do_osur_override( int4& bd ) // from omat to imat : inwards
0243 {
0244     int& osur = bd.y ; 
0245     osur = get_surface_idx_of_implicit(true); 
0246 }
0247 inline void U4TreeBorder::do_isur_override( int4& bd ) // from imat to omat : outwards
0248 {
0249     int& isur = bd.z ; 
0250     isur = get_surface_idx_of_implicit(false); 
0251 }
0252 
0253 inline void U4TreeBorder::check( const int4& bd ) 
0254 {
0255     if(is_flagged()) std::cout 
0256         << "U4TreeBorder::check is_flagged " << std::endl 
0257         << " (omat,osur,isur,imat) " << bd << std::endl 
0258         << desc()
0259         << std::endl 
0260         ;
0261 }
0262 
0263