Skip to content

Commit

Permalink
Support using VecGeom without VGDML (#1046)
Browse files Browse the repository at this point in the history
* Update ReflFactory namespace for VecGeom v1.2.3
* Add CMake support for missing VGDML
* Fix vecgeom build when VGDML is unavailable
* Try configuring vecgeom to work with geant4 loader (nope)
* Add VecgeomParamsOutput with diagnostic information
* Make celer_debug_fail a public macro
* Improve error checking
* Remove G4GDMLParser call now that the scoped logger initailizes the UI manager
* Warn if already-loaded vecgeom is not new enough
* Fix vecgeom diagnostic messages
  • Loading branch information
sethrj committed Dec 7, 2023
1 parent 3fa7c6e commit 2b76eec
Show file tree
Hide file tree
Showing 13 changed files with 284 additions and 67 deletions.
26 changes: 20 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -318,33 +318,47 @@ if(CELERITAS_USE_SWIG)
endif()

if(CELERITAS_USE_VecGeom)
set(_min_vecgeom_version 1.2.4)
if(NOT VecGeom_FOUND)
find_package(VecGeom 1.2.4 REQUIRED)
find_package(VecGeom ${_min_vecgeom_version} REQUIRED)
elseif(VecGeom_VERSION VERSION_LESS _min_vecgeom_version)
# Another package, probably Geant4, is already using vecgeom
celeritas_error_incompatible_option(
"VecGeom version \"${VecGeom_VERSION}\" at \"${VecGeom_DIR}\" is too old for Celeritas to use: you must update to ${_min_vecgeom_version} or higher"
CELERITAS_USE_VecGeom
OFF
)
endif()

if(CELERITAS_USE_CUDA AND NOT VecGeom_CUDA_FOUND)
celeritas_error_incompatible_option(
"VecGeom installation at ${VECGEOM_INSTALL_DIR} is not CUDA-enabled"
"VecGeom installation at \"${VecGeom_DIR}\" is not CUDA-enabled"
CELERITAS_USE_CUDA
"${VecGeom_CUDA_FOUND}"
)
endif()
if(CELERITAS_REAL_TYPE STREQUAL "float" AND NOT VecGeom_single_precision_FOUND)
celeritas_error_incompatible_option(
"VecGeom installation at ${VECGEOM_INSTALL_DIR} uses double precision"
"VecGeom installation at \"${VecGeom_DIR}\" uses double precision"
CELERITAS_REAL_TYPE
"double"
)
endif()
if(CELERITAS_REAL_TYPE STREQUAL "double" AND VecGeom_single_precision_FOUND)
celeritas_error_incompatible_option(
"VecGeom installation at ${VECGEOM_INSTALL_DIR} uses single precision"
"VecGeom installation at \"${VecGeom_DIR}\" uses single precision"
CELERITAS_REAL_TYPE
"float"
)
endif()
if(NOT VecGeom_GDML_FOUND)
message(SEND_ERROR "VecGeom GDML capability is required for Celeritas")
if(CELERITAS_BUILD_TESTS AND NOT VecGeom_GDML_FOUND
AND CELERITAS_CORE_GEO STREQUAL "VecGeom")
celeritas_error_incompatible_option(
"VecGeom installation at \"${VecGeom_DIR}\" was not built with VGDML:
celer-sim and many tests will fail"
CELERITAS_BUILD_TESTS
OFF
)
endif()
endif()

Expand Down
3 changes: 2 additions & 1 deletion app/celer-sim/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ set(_env
)

if(CELERITAS_USE_Geant4 AND CELERITAS_USE_HepMC3 AND CELERITAS_USE_Python
AND (NOT CELERITAS_CORE_GEO STREQUAL "Geant4"))
AND (NOT CELERITAS_CORE_GEO STREQUAL "Geant4")
AND (VecGeom_GDML_FOUND OR NOT (CELERITAS_CORE_GEO STREQUAL "VecGeom")))
set(_needs_deps)
else()
set(_needs_deps DISABLED true)
Expand Down
5 changes: 4 additions & 1 deletion src/celeritas/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,12 @@ endif()
if(CELERITAS_USE_VecGeom)
list(APPEND SOURCES
ext/VecgeomParams.cc
ext/VecgeomParamsOutput.cc
ext/detail/VecgeomNavCollection.cc
)
list(APPEND PRIVATE_DEPS VecGeom::vgdml)
if(VecGeom_GDML_FOUND)
list(APPEND PRIVATE_DEPS VecGeom::vgdml)
endif()
if(VecGeom_CUDA_FOUND AND VecGeom_SURF_FOUND)
# Special routines needed for surface
list(APPEND SOURCES
Expand Down
14 changes: 9 additions & 5 deletions src/celeritas/ext/GeantGeoUtils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <G4LogicalVolumeStore.hh>
#include <G4PhysicalVolumeStore.hh>
#include <G4SolidStore.hh>
#include <G4Threading.hh>
#include <G4TouchableHistory.hh>
#include <G4VPhysicalVolume.hh>
#include <G4ios.hh>
Expand Down Expand Up @@ -48,15 +49,18 @@ G4VPhysicalVolume*
load_geant_geometry_impl(std::string const& filename, bool strip_pointer_ext)
{
CELER_LOG(info) << "Loading Geant4 geometry from GDML at " << filename;
ScopedMem record_mem("load_geant_geometry");
ScopedTimeLog scoped_time;

if (!G4Threading::IsMasterThread())
{
// I have no idea why, but creating the GDML parser resets the
// ScopedGeantLogger on its first instantiation (geant4@11.0)
G4GDMLParser temp_parser_init;
// Always-on debug assertion (not a "runtime" error but a
// subtle programming logic error that always causes a crash)
CELER_DEBUG_FAIL(
"Geant4 geometry cannot be loaded from a worker thread", internal);
}

ScopedMem record_mem("load_geant_geometry");
ScopedTimeLog scoped_time;

ScopedGeantLogger scoped_logger;
ScopedGeantExceptionHandler scoped_exceptions;

Expand Down
13 changes: 13 additions & 0 deletions src/celeritas/ext/ScopedGeantLogger.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
#include <memory>
#include <mutex>
#include <G4String.hh>
#include <G4Threading.hh>
#include <G4Types.hh>
#include <G4UImanager.hh>
#include <G4Version.hh>
#include <G4coutDestination.hh>
#if G4VERSION_NUMBER >= 1120
Expand All @@ -22,6 +24,7 @@
# define CELER_G4SSBUF 1
#endif

#include "corecel/Assert.hh"
#include "corecel/io/Logger.hh"
#include "corecel/io/StringUtils.hh"

Expand Down Expand Up @@ -70,6 +73,16 @@ class GeantLoggerAdapter : public G4coutDestination
*/
GeantLoggerAdapter::GeantLoggerAdapter()
{
if (!G4UImanager::GetUIpointer())
{
// Always-on debug assertion (not a "runtime" error but a
// subtle programming logic error that always causes a crash)
CELER_DEBUG_FAIL(
"Geant4 logging cannot be changed after G4UImanager has been "
"destroyed",
precondition);
}

#if CELER_G4SSBUF
saved_cout_ = G4coutbuf.GetDestination();
saved_cerr_ = G4cerrbuf.GetDestination();
Expand Down
111 changes: 79 additions & 32 deletions src/celeritas/ext/VecgeomParams.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,39 @@
#include <vector>
#include <VecGeom/base/Config.h>
#include <VecGeom/base/Cuda.h>
#include <VecGeom/gdml/Frontend.h>
#include <VecGeom/management/ABBoxManager.h>
#include <VecGeom/management/BVHManager.h>
#include <VecGeom/management/GeoManager.h>
#include <VecGeom/volumes/PlacedVolume.h>

#include "celeritas_config.h"
#include "corecel/device_runtime_api.h"
#include "corecel/Assert.hh"
#include "corecel/Macros.hh"
#include "corecel/sys/Environment.hh"
#include "corecel/sys/ScopedLimitSaver.hh"
#include "corecel/sys/ScopedProfiling.hh"
#include "celeritas/ext/detail/VecgeomCompatibility.hh"
#if CELERITAS_USE_CUDA
# include <VecGeom/management/CudaManager.h>
# include <cuda_runtime_api.h>
#endif
#ifdef VECGEOM_USE_SURF
# include <VecGeom/surfaces/BrepHelper.h>
#endif
#ifdef VECGEOM_GDML
# include <VecGeom/gdml/Frontend.h>
#endif

#include "corecel/device_runtime_api.h"
#include "corecel/Assert.hh"
#include "corecel/Macros.hh"
#include "corecel/cont/Range.hh"
#include "corecel/io/Join.hh"
#include "corecel/io/Logger.hh"
#include "corecel/io/ScopedTimeAndRedirect.hh"
#include "corecel/io/StringUtils.hh"
#include "corecel/sys/Device.hh"
#include "corecel/sys/Environment.hh"
#include "corecel/sys/ScopedLimitSaver.hh"
#include "corecel/sys/ScopedMem.hh"
#include "corecel/sys/ScopedProfiling.hh"
#include "celeritas/ext/detail/VecgeomCompatibility.hh"

#include "GeantGeoUtils.hh"
#include "VecgeomData.hh" // IWYU pragma: associated
#include "g4vg/Converter.hh"

Expand Down Expand Up @@ -117,6 +120,19 @@ bool VecgeomParams::use_surface_tracking()
#endif
}

//---------------------------------------------------------------------------//
/*!
* Whether VecGeom GDML is used to load the geometry.
*/
bool VecgeomParams::use_vgdml()
{
#ifdef VECGEOM_GDML
return true;
#else
return false;
#endif
}

//---------------------------------------------------------------------------//
/*!
* Construct from a GDML input.
Expand All @@ -130,11 +146,14 @@ VecgeomParams::VecgeomParams(std::string const& filename)
}

ScopedMem record_mem("VecgeomParams.construct");

if (VecgeomParams::use_vgdml())
{
ScopedProfiling profile_this{"load-vecgeom"};
ScopedMem record_mem("VecgeomParams.load_geant_geometry");
ScopedTimeAndRedirect time_and_output_("vgdml::Frontend");
vgdml::Frontend::Load(filename, /* validate_xml_schema = */ false);
this->build_volumes_vgdml(filename);
}
else
{
CELER_NOT_CONFIGURED("VGDML");
}

this->build_tracking();
Expand All @@ -154,25 +173,7 @@ VecgeomParams::VecgeomParams(G4VPhysicalVolume const* world)
CELER_EXPECT(world);
ScopedMem record_mem("VecgeomParams.construct");

{
// Convert the geometry to VecGeom
ScopedProfiling profile_this{"load-vecgeom"};
g4vg::Converter::Options opts;
opts.compare_volumes
= !celeritas::getenv("G4VG_COMPARE_VOLUMES").empty();
g4vg::Converter convert{opts};
auto result = convert(world);
CELER_ASSERT(result.world != nullptr);
g4log_volid_map_ = std::move(result.volumes);

// Set as world volume
auto& vg_manager = vecgeom::GeoManager::Instance();
vg_manager.RegisterPlacedVolume(result.world);
vg_manager.SetWorldAndClose(result.world);

// NOTE: setting and closing changes the world
CELER_ASSERT(vg_manager.GetWorld() != nullptr);
}
this->build_volumes_geant4(world);

this->build_tracking();
this->build_data();
Expand Down Expand Up @@ -210,6 +211,11 @@ VecgeomParams::~VecgeomParams()

CELER_LOG(debug) << "Clearing VecGeom CPU data";
vecgeom::GeoManager::Instance().Clear();

if (loaded_geant4_gdml_)
{
reset_geant_geometry();
}
}

//---------------------------------------------------------------------------//
Expand Down Expand Up @@ -278,7 +284,48 @@ auto VecgeomParams::find_volumes(std::string const& name) const

//---------------------------------------------------------------------------//
/*!
* After loading solids, set up VecGeom tracking data and copy to GPU.
* Construct VecGeom objects using the VGDML reader.
*/
void VecgeomParams::build_volumes_vgdml(std::string const& filename)
{
ScopedProfiling profile_this{"load-vecgeom"};
ScopedMem record_mem("VecgeomParams.load_geant_geometry");
ScopedTimeAndRedirect time_and_output_("vgdml::Frontend");
#ifdef VECGEOM_GDML
vgdml::Frontend::Load(filename, /* validate_xml_schema = */ false);
#else
CELER_DISCARD(filename);
CELER_NOT_CONFIGURED("VGDML");
#endif
}

//---------------------------------------------------------------------------//
/*!
* Construct VecGeom objects using Geant4 objects in memory.
*/
void VecgeomParams::build_volumes_geant4(G4VPhysicalVolume const* world)
{
// Convert the geometry to VecGeom
ScopedProfiling profile_this{"load-vecgeom"};
g4vg::Converter::Options opts;
opts.compare_volumes = !celeritas::getenv("G4VG_COMPARE_VOLUMES").empty();
g4vg::Converter convert{opts};
auto result = convert(world);
CELER_ASSERT(result.world != nullptr);
g4log_volid_map_ = std::move(result.volumes);

// Set as world volume
auto& vg_manager = vecgeom::GeoManager::Instance();
vg_manager.RegisterPlacedVolume(result.world);
vg_manager.SetWorldAndClose(result.world);

// NOTE: setting and closing changes the world
CELER_ASSERT(vg_manager.GetWorld() != nullptr);
}

//---------------------------------------------------------------------------//
/*!
* After loading solids+volumes, set up VecGeom tracking data and copy to GPU.
*/
void VecgeomParams::build_tracking()
{
Expand Down
8 changes: 8 additions & 0 deletions src/celeritas/ext/VecgeomParams.hh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class VecgeomParams final : public GeoParamsInterface,
// Whether surface tracking is being used
static bool use_surface_tracking();

// Whether VecGeom GDML is being used to load the geometry
static bool use_vgdml();

// Construct from a GDML filename
explicit VecgeomParams(std::string const& gdml_filename);

Expand Down Expand Up @@ -102,9 +105,14 @@ class VecgeomParams final : public GeoParamsInterface,
HostRef host_ref_;
DeviceRef device_ref_;

// If VGDML is unavailable and Geant4 is, we load and
bool loaded_geant4_gdml_{false};

//// HELPER FUNCTIONS ////

// Construct VecGeom tracking data and copy to GPU
void build_volumes_vgdml(std::string const& filename);
void build_volumes_geant4(G4VPhysicalVolume const* world);
void build_tracking();
void build_surface_tracking();
void build_volume_tracking();
Expand Down
52 changes: 52 additions & 0 deletions src/celeritas/ext/VecgeomParamsOutput.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//----------------------------------*-C++-*----------------------------------//
// Copyright 2023 UT-Battelle, LLC, and other Celeritas developers.
// See the top-level COPYRIGHT file for details.
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
//---------------------------------------------------------------------------//
//! \file celeritas/ext/VecgeomParamsOutput.cc
//---------------------------------------------------------------------------//
#include "VecgeomParamsOutput.hh"

#include "celeritas_config.h"
#include "corecel/cont/Range.hh"
#include "corecel/io/JsonPimpl.hh"

#include "VecgeomParams.hh" // IWYU pragma: keep
#if CELERITAS_USE_JSON
# include <nlohmann/json.hpp>
#endif

namespace celeritas
{
//---------------------------------------------------------------------------//
/*!
* Construct from shared vecgeom data.
*/
VecgeomParamsOutput::VecgeomParamsOutput(SPConstVecgeomParams vecgeom)
: vecgeom_(std::move(vecgeom))
{
CELER_EXPECT(vecgeom_);
}

//---------------------------------------------------------------------------//
/*!
* Write output to the given JSON object.
*/
void VecgeomParamsOutput::output(JsonPimpl* j) const
{
#if CELERITAS_USE_JSON
using json = nlohmann::json;

auto scalars = json::object({
{"max_depth", vecgeom_->max_depth()},
{"use_vgdml", vecgeom_->use_vgdml()},
{"use_surface_tracking", vecgeom_->use_surface_tracking()},
});
j->obj = json::object({{"scalars", std::move(scalars)}});
#else
(void)sizeof(j);
#endif
}

//---------------------------------------------------------------------------//
} // namespace celeritas

0 comments on commit 2b76eec

Please sign in to comment.