File indexing completed on 2026-04-10 07:50:32
0001 #pragma once
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
0049
0050
0051
0052
0053
0054
0055
0056
0057 #include <vector>
0058 #include <set>
0059 #include <algorithm>
0060
0061 #include "G4Polycone.hh"
0062
0063 #include "sn.h"
0064 #include "ssys.h"
0065
0066 struct RZ
0067 {
0068 double rmin ;
0069 double rmax ;
0070 double z ;
0071
0072 std::string desc() const ;
0073 };
0074
0075 inline std::string RZ::desc() const
0076 {
0077 std::stringstream ss ;
0078 ss << "RRZ"
0079 << " " << std::setw(10) << std::fixed << std::setprecision(3) << rmin
0080 << " " << std::setw(10) << std::fixed << std::setprecision(3) << rmax
0081 << " " << std::setw(10) << std::fixed << std::setprecision(3) << z
0082 ;
0083 std::string str = ss.str();
0084 return str ;
0085 }
0086
0087
0088 struct U4Polycone
0089 {
0090 static sn* Convert( const G4Polycone* polycone, int lvid, int depth, int level );
0091 private:
0092
0093 std::string desc() const ;
0094 static void GetMinMax( double& mn, double& mx, const std::set<double>& vv );
0095
0096
0097 U4Polycone(const G4Polycone* poly, int lvid, int depth, int level );
0098 bool checkZOrder( bool z_ascending );
0099 void init();
0100 void init_RZ();
0101 void init_phicut();
0102 void init_outer();
0103 void init_inner();
0104
0105 void collectPrims(std::vector<sn*>& prims, bool outside );
0106
0107
0108
0109
0110 int lvid ;
0111 int depth ;
0112 int level ;
0113
0114 bool enable_nudge ;
0115 const G4Polycone* polycone ;
0116 const G4PolyconeHistorical* ph ;
0117
0118 int num ;
0119 std::vector<RZ> rz ;
0120
0121
0122 static constexpr const char* U4Polycone__ENABLE_PHICUT = "U4Polycone__ENABLE_PHICUT" ;
0123 bool ENABLE_PHICUT ;
0124 double phi_start ;
0125 double phi_end ;
0126 sn* phicut ;
0127
0128 std::set<double> R_inner ;
0129 std::set<double> R_outer ;
0130 std::set<double> Z ;
0131
0132 int num_R_inner ;
0133 double R_inner_min ;
0134 double R_inner_max ;
0135
0136 int num_R_outer ;
0137 double R_outer_min ;
0138 double R_outer_max ;
0139
0140 int num_Z ;
0141 double Z_min ;
0142 double Z_max ;
0143
0144 bool has_inner ;
0145
0146 std::vector<sn*> outer_prims ;
0147 std::vector<sn*> inner_prims ;
0148 sn* inner ;
0149 sn* outer ;
0150 sn* root ;
0151
0152 const char* label ;
0153
0154 };
0155
0156
0157 inline sn* U4Polycone::Convert( const G4Polycone* polycone, int lvid, int depth, int level )
0158 {
0159 U4Polycone upoly(polycone, lvid, depth, level ) ;
0160
0161 if(level > 0)
0162 {
0163 std::cerr << "U4Polycone::Convert" << std::endl ;
0164 std::cerr << upoly.root->render(5) ;
0165 }
0166 return upoly.root ;
0167 }
0168
0169
0170
0171
0172 inline std::string U4Polycone::desc() const
0173 {
0174 std::stringstream ss ;
0175 ss << "U4Polycone::desc"
0176 << " lvid " << lvid
0177 << " depth " << depth
0178 << " level " << level
0179 << " enable_nudge " << ( enable_nudge ? "YES" : "NO " )
0180 << " num " << num
0181 << " ENABLE_PHICUT " << std::setw(10) << ( ENABLE_PHICUT ? "YES" : "NO " )
0182 << " phi_start " << std::setw(10) << phi_start
0183 << " phi_end " << std::setw(10) << phi_end
0184 << " phicut " << std::setw(10) << ( phicut ? "YES" : "NO " )
0185 << " rz " << rz.size()
0186 << std::endl
0187 << " num_R_inner " << std::setw(3) << num_R_inner
0188 << " R_inner_min " << std::setw(10) << R_inner_min
0189 << " R_inner_max " << std::setw(10) << R_inner_max
0190 << std::endl
0191 << " num_R_outer " << std::setw(3) << num_R_outer
0192 << " R_outer_min " << std::setw(10) << R_outer_min
0193 << " R_outer_max " << std::setw(10) << R_outer_max
0194 << std::endl
0195 << " num_Z " << std::setw(3) << num_Z
0196 << " Z_min " << std::setw(10) << Z_min
0197 << " Z_max " << std::setw(10) << Z_max
0198 << std::endl
0199 << " has_inner " << ( has_inner ? "YES" : "NO" )
0200 << " root " << std::setw(3) << ( root ? root->index() : -1 )
0201 << " label " << ( label ? label : "-" )
0202 << std::endl
0203 ;
0204
0205 for(int i=0 ; i < num ; i++) ss << std::setw(3) << i << " " << rz[i].desc() << std::endl ;
0206 std::string str = ss.str();
0207 return str ;
0208 }
0209
0210
0211
0212
0213 inline void U4Polycone::GetMinMax( double& mn, double& mx, const std::set<double>& vv )
0214 {
0215 mn = *vv.begin() ;
0216 mx = *vv.begin() ;
0217 for(std::set<double>::const_iterator it = vv.begin() ; it != vv.end() ; it++ )
0218 {
0219 mn = std::min( mn, *it );
0220 mx = std::max( mx, *it );
0221 }
0222 }
0223
0224 inline U4Polycone::U4Polycone(const G4Polycone* polycone_, int lvid_, int depth_, int level_ )
0225 :
0226 lvid(lvid_),
0227 depth(depth_),
0228 level(level_),
0229 enable_nudge(!ssys::getenvbool("U4Polycone__DISABLE_NUDGE")),
0230 polycone(polycone_),
0231 ph(polycone->GetOriginalParameters()),
0232 num(ph->Num_z_planes),
0233 ENABLE_PHICUT(ssys::getenvbool(U4Polycone__ENABLE_PHICUT)),
0234 phi_start(0.),
0235 phi_end(2.*M_PI),
0236 phicut(nullptr),
0237 num_R_inner(0),
0238 R_inner_min(0),
0239 R_inner_max(0),
0240 num_R_outer(0),
0241 R_outer_min(0),
0242 R_outer_max(0),
0243 num_Z(0),
0244 Z_min(0),
0245 Z_max(0),
0246 has_inner(false),
0247 inner(nullptr),
0248 outer(nullptr),
0249 root(nullptr),
0250 label("NOT-WITH-SND")
0251 {
0252 init();
0253 if(level > 0 ) std::cerr
0254 << "U4Polycone::U4Polycone "
0255 << ( label ? label : "-" )
0256 << std::endl
0257 << desc()
0258 << std::endl
0259 ;
0260
0261 }
0262
0263 inline bool U4Polycone::checkZOrder( bool z_ascending )
0264 {
0265 int count_z_order = 0 ;
0266 for( int i=1 ; i < num ; i++)
0267 {
0268 bool z_order = z_ascending ? rz[i-1].z <= rz[i].z : rz[i].z <= rz[i-1].z ;
0269 if(z_order) count_z_order += 1 ;
0270 }
0271 bool all_z_order = count_z_order == num - 1 ;
0272 return all_z_order ;
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 inline void U4Polycone::init()
0305 {
0306 init_RZ();
0307 init_phicut();
0308 init_outer();
0309
0310 sn* _root = nullptr ;
0311 {
0312 if(has_inner == false)
0313 {
0314 _root = outer ;
0315 }
0316 else
0317 {
0318 init_inner();
0319 assert( inner );
0320 _root = sn::Boolean(CSG_DIFFERENCE, outer, inner );
0321 }
0322 }
0323
0324
0325 if(phicut == nullptr)
0326 {
0327 root = _root ;
0328 }
0329 else
0330 {
0331 if(ENABLE_PHICUT)
0332 {
0333 root = sn::Boolean(CSG_INTERSECTION, phicut, _root );
0334 }
0335 else
0336 {
0337 std::cerr
0338 << "U4Polycone::init FATAL geometry with unsupported phicut : "
0339 << " enable experimental support with envvar "
0340 << " [" << U4Polycone__ENABLE_PHICUT << "]"
0341 << "\n"
0342 ;
0343
0344 assert(0);
0345 std::raise(SIGINT);
0346 }
0347 }
0348
0349 }
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366 inline void U4Polycone::init_RZ()
0367 {
0368 rz.resize(num);
0369
0370 for (int i=0; i < num ; i++)
0371 {
0372 RZ& rzi = rz[i] ;
0373 rzi.rmin = ph->Rmin[i] ;
0374 rzi.rmax = ph->Rmax[i] ;
0375 rzi.z = ph->Z_values[i] ;
0376
0377 R_inner.insert(rzi.rmin);
0378 R_outer.insert(rzi.rmax);
0379 Z.insert(rzi.z);
0380 }
0381
0382 num_R_inner = R_inner.size();
0383 num_R_outer = R_outer.size();
0384 num_Z = Z.size();
0385
0386
0387 bool all_z_descending = checkZOrder(false);
0388 if(all_z_descending)
0389 {
0390 if(level > 0) std::cerr
0391 << "U4Polycone::init_RZ"
0392 << label
0393 << " all_z_descending detected, reversing "
0394 << std::endl
0395 ;
0396 std::reverse( std::begin(rz), std::end(rz) ) ;
0397 }
0398 bool all_z_ascending = checkZOrder(true );
0399 assert( all_z_ascending );
0400 if(!all_z_ascending) std::raise(SIGINT);
0401
0402 GetMinMax(R_inner_min, R_inner_max, R_inner);
0403 GetMinMax(R_outer_min, R_outer_max, R_outer);
0404 GetMinMax(Z_min, Z_max, Z);
0405
0406 assert( Z_max > Z_min );
0407 bool no_inner = R_inner_min == 0. && R_inner_max == 0. ;
0408 has_inner = !no_inner ;
0409 }
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450 inline void U4Polycone::init_phicut()
0451 {
0452 double eps = 1e-6 ;
0453 double phi_delta = ph->Opening_angle/CLHEP::radian ;
0454 phi_start = ph->Start_angle/CLHEP::radian ;
0455 phi_end = phi_start + phi_delta ;
0456
0457 bool has_phicut = phi_start > 0. || phi_end < 2.0*CLHEP::pi ;
0458 bool has_half = std::abs( phi_start - 0.f ) < eps && std::abs(phi_end-CLHEP::pi) < eps ;
0459
0460 if( has_phicut )
0461 {
0462 if( has_half )
0463 {
0464 phicut = sn::HalfSpace( 0., -1., 0., 0. );
0465 }
0466 else
0467 {
0468 phicut = sn::PhiCut( phi_start, phi_end );
0469 }
0470 }
0471
0472 if(has_phicut) std::cerr
0473 << "U4Polycone::init_phicut"
0474 << " phi_start " << std::setw(10) << std::fixed << std::setprecision(4) << phi_start
0475 << " phi_end " << std::setw(10) << std::fixed << std::setprecision(4) << phi_end
0476 << " phi_delta " << std::setw(10) << std::fixed << std::setprecision(4) << phi_delta
0477 << " has_phicut " << ( has_phicut ? "YES" : "NO " )
0478 << " has_half " << ( has_half ? "YES" : "NO " )
0479 << " ENABLE_PHICUT " << ( ENABLE_PHICUT ? "YES" : "NO " )
0480 << "\n"
0481 ;
0482
0483 }
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497 inline void U4Polycone::init_outer()
0498 {
0499 if( num_R_outer == 1 )
0500 {
0501 assert( R_outer_min == R_outer_max );
0502 outer = sn::Cylinder( R_outer_max, Z_min, Z_max );
0503 }
0504 else
0505 {
0506 collectPrims( outer_prims, true );
0507 int num_outer_prim = outer_prims.size() ;
0508
0509 if(level > 0) std::cerr
0510 << "U4Polycone::init_outer."
0511 << " num_outer_prim " << num_outer_prim
0512 << std::endl
0513 ;
0514
0515 if(num_outer_prim > 1) sn::ZNudgeOverlapJoints(lvid, outer_prims, enable_nudge);
0516 outer = sn::Collection(outer_prims) ;
0517 }
0518
0519 }
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532 inline void U4Polycone::init_inner()
0533 {
0534 assert( has_inner ) ;
0535
0536 if(level > 0) std::cerr
0537 << "U4Polycone::init_inner "
0538 << std::endl
0539 ;
0540
0541 if( num_R_inner == 1 )
0542 {
0543 assert( R_inner_min == R_inner_max );
0544 inner = sn::Cylinder(R_inner_min, Z_min, Z_max);
0545 }
0546 else
0547 {
0548 collectPrims( inner_prims, false );
0549 int num_inner_prim = inner_prims.size() ;
0550
0551 if(level > 0) std::cerr
0552 << "U4Polycone::init."
0553 << label
0554 << " num_inner_prim " << num_inner_prim
0555 << std::endl
0556 ;
0557
0558 sn::ZNudgeExpandEnds(lvid, inner_prims, enable_nudge);
0559 if(num_inner_prim > 1) sn::ZNudgeOverlapJoints(lvid, inner_prims, enable_nudge);
0560 inner = sn::Collection( inner_prims );
0561 }
0562 }
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576 void U4Polycone::collectPrims(std::vector<sn*>& prims, bool outside )
0577 {
0578 bool inner = !outside ;
0579
0580 int num_rz = rz.size();
0581
0582 for( int i=1 ; i < num_rz ; i++ )
0583 {
0584 const RZ& rz1 = rz[i-1] ;
0585 const RZ& rz2 = rz[i] ;
0586 double r1 = outside ? rz1.rmax : rz1.rmin ;
0587 double r2 = outside ? rz2.rmax : rz2.rmin ;
0588 double z1 = rz1.z ;
0589 double z2 = rz2.z ;
0590
0591 if( z1 == z2 )
0592 {
0593 if(level > 0) std::cerr << "U4Polycone::collectPrims skipping prim as z2 == z1 " << std::endl ;
0594 continue ;
0595 }
0596
0597
0598 bool z_ascending = z2 > z1 ;
0599 assert(z_ascending);
0600 if(!z_ascending) std::raise(SIGINT);
0601
0602 bool is_cylinder = r1 == r2 ;
0603 int idx = -1 ;
0604
0605 if( inner && r1 == 0. && r2 == 0. )
0606 {
0607 if(level > 0) std::cerr << "U4Polycone::collectPrims skipping inner as r1 == r2 == 0. " << std::endl ;
0608 continue ;
0609 }
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630 sn* pr = is_cylinder ? sn::Cylinder(r2, z1, z2 ) : sn::Cone( r1, z1, r2, z2 ) ;
0631 pr->lvid = lvid ;
0632 prims.push_back(pr);
0633 idx = pr->index() ;
0634
0635 if( level > 0 ) std::cerr
0636 << "U4Polycone::collectPrims"
0637 << " outside " << ( outside ? "YES" : "NO " )
0638 << " idx " << idx
0639 << " is_cylinder " << ( is_cylinder ? "YES" : "NO " )
0640 << std::endl
0641 ;
0642 }
0643 }
0644
0645