Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /eic-opticks/tests/SimphonyApiTest.cc was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 #include <filesystem>
0002 #include <iostream>
0003 #include <stdexcept>
0004 #include <string>
0005 
0006 #include "G4GDMLParser.hh"
0007 
0008 #include "simphony.h"
0009 
0010 namespace
0011 {
0012 struct TranslationFailure : std::runtime_error
0013 {
0014     TranslationFailure() :
0015         std::runtime_error("injected sensor translation failure")
0016     {
0017     }
0018 };
0019 
0020 struct SensorIdentifier : simphony::SensorIdentifier
0021 {
0022     int  calls = 0;
0023     bool fail_translation = false;
0024 
0025     void setLevel(int) override
0026     {
0027     }
0028 
0029     int getGlobalIdentity(const G4VPhysicalVolume*, const G4VPhysicalVolume*) override
0030     {
0031         ++calls;
0032         if (fail_translation)
0033             throw TranslationFailure();
0034         return -1;
0035     }
0036 
0037     int getInstanceIdentity(const G4VPhysicalVolume*) const override
0038     {
0039         return -1;
0040     }
0041 };
0042 
0043 void require(bool condition, const std::string& message)
0044 {
0045     if (!condition)
0046         throw std::runtime_error(message);
0047 }
0048 
0049 template <typename Exception, typename Function>
0050 void require_throws(Function&& function, const std::string& message)
0051 {
0052     try
0053     {
0054         function();
0055     }
0056     catch (const Exception&)
0057     {
0058         return;
0059     }
0060     throw std::runtime_error(message);
0061 }
0062 
0063 void require_negative_event_ids_rejected()
0064 {
0065     require_throws<std::invalid_argument>(
0066         [] { simphony::simulate(-1); },
0067         "simulate(-1) did not throw std::invalid_argument");
0068     require_throws<std::invalid_argument>(
0069         [] { simphony::reset(-1); },
0070         "reset(-1) did not throw std::invalid_argument");
0071 }
0072 } // namespace
0073 
0074 int main(int argc, char** argv)
0075 {
0076     try
0077     {
0078         require(argc == 3 || (argc == 4 && std::string(argv[3]) == "--fail-translation"),
0079                 "usage: SimphonyApiTest GEOMETRY.gdml OUTPUT_DIRECTORY [--fail-translation]");
0080 
0081         require(!simphony::is_initialized(), "API unexpectedly initialized at process start");
0082         require(!simphony::has_gpu(), "API unexpectedly has a GPU backend at process start");
0083         require_throws<std::logic_error>(
0084             [] { simphony::simulate(0); },
0085             "simulate before initialize did not throw std::logic_error");
0086         require_throws<std::invalid_argument>(
0087             [] { simphony::initialize(nullptr); },
0088             "initialize(nullptr) did not throw std::invalid_argument");
0089         require(!simphony::is_initialized(), "failed initialization changed API state");
0090         require_negative_event_ids_rejected();
0091 
0092         G4GDMLParser parser;
0093         parser.Read(argv[1], false);
0094         const G4VPhysicalVolume* world = parser.GetWorldVolume();
0095         require(world != nullptr, "GDML parser returned a null world");
0096 
0097         SensorIdentifier                identifier;
0098         const simphony::GeometryOptions options{
0099             .sensor_identifier = &identifier,
0100             .gpu = simphony::GpuRequirement::Disabled,
0101         };
0102 
0103         if (argc == 4)
0104         {
0105             identifier.fail_translation = true;
0106             require_throws<TranslationFailure>(
0107                 [&] { simphony::initialize(world, options); },
0108                 "initialize did not propagate the translation failure");
0109             require(!simphony::is_initialized() && !simphony::has_gpu(),
0110                     "failed translation published an initialized runtime");
0111 
0112             identifier.fail_translation = false;
0113             require_throws<std::logic_error>(
0114                 [&] { simphony::initialize(world, options); },
0115                 "retry after partial geometry translation did not throw std::logic_error");
0116             auto changed_options = options;
0117             changed_options.sensor_identifier = nullptr;
0118             changed_options.gpu = simphony::GpuRequirement::Required;
0119             require_throws<std::logic_error>(
0120                 [&] { simphony::initialize(world, changed_options); },
0121                 "retry with different options after partial translation was not rejected");
0122             require(!simphony::is_initialized() && !simphony::has_gpu(),
0123                     "rejected retry changed the runtime state");
0124             return 0;
0125         }
0126 
0127         simphony::initialize(world, options);
0128 
0129         require(identifier.calls > 0, "custom sensor identifier was not used during translation");
0130         require(simphony::is_initialized(), "initialize did not update API state");
0131         require(!simphony::has_gpu(), "Disabled policy unexpectedly created a GPU backend");
0132         require_negative_event_ids_rejected();
0133 
0134         simphony::initialize(world, options);
0135         require_throws<std::logic_error>(
0136             [] { simphony::simulate(7, false); },
0137             "simulate without a GPU backend did not throw std::logic_error");
0138         require_throws<std::logic_error>(
0139             [] { simphony::reset(7); },
0140             "reset without a pending event did not throw std::logic_error");
0141 
0142         auto changed_identifier = options;
0143         changed_identifier.sensor_identifier = nullptr;
0144         require_throws<std::logic_error>(
0145             [world, changed_identifier] { simphony::initialize(world, changed_identifier); },
0146             "reinitialization with a different sensor identifier did not throw std::logic_error");
0147 
0148         auto changed_options = options;
0149         changed_options.gpu = simphony::GpuRequirement::Optional;
0150         require_throws<std::logic_error>(
0151             [world, changed_options] { simphony::initialize(world, changed_options); },
0152             "reinitialization with changed options did not throw std::logic_error");
0153 
0154         const std::filesystem::path output = argv[2];
0155         std::filesystem::remove_all(output);
0156         simphony::save_geometry(output);
0157 
0158         require(std::filesystem::is_regular_file(output / "origin.gdml"),
0159                 "save_geometry did not write origin.gdml");
0160         require(std::filesystem::is_regular_file(output / "CSGFoundry" / "solid.npy"),
0161                 "save_geometry did not write CSGFoundry/solid.npy");
0162     }
0163     catch (const std::exception& error)
0164     {
0165         std::cerr << "SimphonyApiTest: " << error.what() << '\n';
0166         return 1;
0167     }
0168 
0169     return 0;
0170 }