Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-26 07:50:31

0001 #include <cassert>
0002 #include <csignal>
0003 #include <cstdlib>
0004 #include <iostream>
0005 #include <set>
0006 #include <sys/types.h>
0007 #include <sys/wait.h>
0008 #include <unistd.h>
0009 
0010 #include <plog/Appenders/ConsoleAppender.h>
0011 #include <plog/Formatters/TxtFormatter.h>
0012 #include <plog/Init.h>
0013 #include <plog/Log.h>
0014 
0015 using plog::error;
0016 using plog::fatal;
0017 using plog::info;
0018 
0019 #include "G4BooleanSolid.hh"
0020 #include "G4IntersectionSolid.hh"
0021 #include "G4LogicalVolume.hh"
0022 #include "G4PhysicalConstants.hh"
0023 #include "G4Sphere.hh"
0024 #include "G4SubtractionSolid.hh"
0025 #include "G4SystemOfUnits.hh"
0026 #include "G4VPhysicalVolume.hh"
0027 #include "G4VSolid.hh"
0028 
0029 #include "config_path.h"
0030 
0031 #include "U4GDML.h"
0032 #include "U4Solid.h"
0033 #include "U4Volume.h"
0034 
0035 #include "s_csg.h"
0036 
0037 namespace
0038 {
0039 inline constexpr char testGeomFile[] = GPHOX_TEST_GEOM_DIR "/sphere_phicut_quarter_shell.gdml";
0040 
0041 enum ConvertOutcome
0042 {
0043     CONVERT_REJECTED,
0044     CONVERT_ACCEPTED,
0045     CONVERT_ERROR
0046 };
0047 
0048 bool IsExpectedRejectSignal(int signal)
0049 {
0050     return signal == SIGABRT || signal == SIGINT;
0051 }
0052 
0053 bool HasNonSpherePrimitive(const sn* nd)
0054 {
0055     if (nd == nullptr)
0056         return false;
0057 
0058     std::set<int> typecodes;
0059     nd->typecodes(typecodes);
0060 
0061     for (int typecode : typecodes)
0062     {
0063         if (CSG::IsPrimitive(typecode) == false)
0064             continue;
0065 
0066         if (typecode == CSG_SPHERE || typecode == CSG_ZSPHERE)
0067             continue;
0068 
0069         if (typecode == CSG_NOTSUPPORTED || typecode == CSG_UNDEFINED)
0070             continue;
0071 
0072         if (typecode == CSG_PHICUT || typecode == CSG_HALFSPACE)
0073             return true;
0074     }
0075 
0076     return false;
0077 }
0078 
0079 int CountPartialPhiSpheres(const G4VSolid* solid)
0080 {
0081     const G4Sphere* sphere = dynamic_cast<const G4Sphere*>(solid);
0082     if (sphere)
0083     {
0084         double start_phi = sphere->GetStartPhiAngle() / CLHEP::radian;
0085         double delta_phi = sphere->GetDeltaPhiAngle() / CLHEP::radian;
0086         bool   partial_phi = start_phi != 0. || delta_phi != 2. * CLHEP::pi;
0087         return partial_phi ? 1 : 0;
0088     }
0089 
0090     const G4BooleanSolid* boolean = dynamic_cast<const G4BooleanSolid*>(solid);
0091     if (boolean == nullptr)
0092         return 0;
0093 
0094     const G4VSolid* left = boolean->GetConstituentSolid(0);
0095     const G4VSolid* right = boolean->GetConstituentSolid(1);
0096     return CountPartialPhiSpheres(left) + CountPartialPhiSpheres(right);
0097 }
0098 
0099 ConvertOutcome ConvertInChildProcess(const G4VSolid* solid)
0100 {
0101     pid_t pid = fork();
0102     if (pid < 0)
0103     {
0104         perror("fork");
0105         return CONVERT_ERROR;
0106     }
0107 
0108     if (pid == 0)
0109     {
0110         s_csg* csg = new s_csg;
0111         assert(csg);
0112 
0113         int lvid = 0;
0114         int depth = 0;
0115         int level = 1;
0116         sn* nd = U4Solid::Convert(solid, lvid, depth, level);
0117         int exit_code = 4;
0118         if (nd != nullptr)
0119         {
0120             bool has_phi_cut_representation = HasNonSpherePrimitive(nd);
0121             exit_code = has_phi_cut_representation ? 0 : 5;
0122             if (has_phi_cut_representation == false)
0123             {
0124                 std::cerr
0125                     << "child conversion produced non-null tree without any non-sphere primitive; "
0126                     << "phi-cut geometry is not represented"
0127                     << std::endl;
0128             }
0129         }
0130         delete nd;
0131         _exit(exit_code);
0132     }
0133 
0134     int status = 0;
0135     int rc = waitpid(pid, &status, 0);
0136     if (rc != pid)
0137     {
0138         perror("waitpid");
0139         return CONVERT_ERROR;
0140     }
0141 
0142     if (WIFSIGNALED(status))
0143     {
0144         int signal = WTERMSIG(status);
0145         if (IsExpectedRejectSignal(signal))
0146         {
0147             std::cout << "child rejected conversion with expected signal " << signal << std::endl;
0148             return CONVERT_REJECTED;
0149         }
0150 
0151         std::cerr << "child crashed with unexpected signal " << signal << std::endl;
0152         return CONVERT_ERROR;
0153     }
0154 
0155     if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
0156     {
0157         std::cout
0158             << "child converted partial-phi sphere with non-sphere primitive(s) in the CSG tree"
0159             << std::endl;
0160         return CONVERT_ACCEPTED;
0161     }
0162 
0163     if (WIFEXITED(status))
0164     {
0165         std::cerr << "child exited unexpectedly with status " << WEXITSTATUS(status) << std::endl;
0166         return CONVERT_ERROR;
0167     }
0168 
0169     std::cerr << "child ended in unexpected state " << status << std::endl;
0170     return CONVERT_ERROR;
0171 }
0172 } // namespace
0173 
0174 int main(int argc, char** argv)
0175 {
0176     static plog::ConsoleAppender<plog::TxtFormatter> consoleAppender;
0177     plog::init(plog::info, &consoleAppender);
0178 
0179     const G4VPhysicalVolume* world = U4GDML::Read(testGeomFile);
0180     LOG_IF(plog::fatal, world == nullptr)
0181         << "failed to load GDML path " << (testGeomFile ? testGeomFile : "-");
0182     if (world == nullptr)
0183         return EXIT_FAILURE;
0184 
0185     const G4VPhysicalVolume* quarter_shell_pv = U4Volume::FindPV(world, "QuarterShell_pv");
0186     LOG_IF(plog::fatal, quarter_shell_pv == nullptr)
0187         << "failed to find QuarterShell_pv in GDML path " << testGeomFile;
0188     if (quarter_shell_pv == nullptr)
0189         return EXIT_FAILURE;
0190 
0191     const G4LogicalVolume* quarter_shell_lv = quarter_shell_pv->GetLogicalVolume();
0192     LOG_IF(plog::fatal, quarter_shell_lv == nullptr)
0193         << "QuarterShell_pv lacks a logical volume";
0194     if (quarter_shell_lv == nullptr)
0195         return EXIT_FAILURE;
0196 
0197     const G4VSolid* quarter_shell_solid = quarter_shell_lv->GetSolid();
0198     LOG_IF(plog::fatal, quarter_shell_solid == nullptr)
0199         << "QuarterShell_pv lacks a solid";
0200     if (quarter_shell_solid == nullptr)
0201         return EXIT_FAILURE;
0202 
0203     const G4IntersectionSolid* intersection = dynamic_cast<const G4IntersectionSolid*>(quarter_shell_solid);
0204     LOG_IF(plog::fatal, intersection != nullptr)
0205         << "test geometry unexpectedly uses a parent IntersectionSolid";
0206     if (intersection != nullptr)
0207         return EXIT_FAILURE;
0208 
0209     const G4SubtractionSolid* subtraction = dynamic_cast<const G4SubtractionSolid*>(quarter_shell_solid);
0210     LOG_IF(plog::fatal, subtraction == nullptr)
0211         << "test geometry expected a subtraction shell solid " << quarter_shell_solid->GetName();
0212     if (subtraction == nullptr)
0213         return EXIT_FAILURE;
0214 
0215     int partial_phi_spheres = CountPartialPhiSpheres(quarter_shell_solid);
0216     LOG_IF(plog::fatal, partial_phi_spheres == 0)
0217         << "test geometry expected partial-phi sphere primitives";
0218     if (partial_phi_spheres == 0)
0219         return EXIT_FAILURE;
0220 
0221     ConvertOutcome outcome = ConvertInChildProcess(quarter_shell_solid);
0222     switch (outcome)
0223     {
0224     case CONVERT_REJECTED:
0225         std::cout
0226             << "partial-phi sphere conversion is rejected, matching current fail-fast behavior"
0227             << std::endl;
0228         return EXIT_SUCCESS;
0229 
0230     case CONVERT_ACCEPTED:
0231         std::cout
0232             << "partial-phi sphere conversion succeeded with a non-null CSG tree"
0233             << std::endl;
0234         return EXIT_SUCCESS;
0235 
0236     case CONVERT_ERROR:
0237         break;
0238     }
0239 
0240     std::cerr
0241         << "SpherePhiCutQuarterShellTest could neither confirm fail-fast rejection nor "
0242         << "successful conversion of the partial-phi spherical shell."
0243         << std::endl;
0244 
0245     return EXIT_FAILURE;
0246 }