Skip to content

Commit

Permalink
Convert Geant4 logical and physical volumes (#1170)
Browse files Browse the repository at this point in the history
* Add logical volume converter

* Add physical volume converter

* Add test for physical volume converter

* Add backdoor option to ignore fatal exceptions in logic converter

* Add additional tests

* Create a NoTransformation in the simple case

* Check for identity and remove now-unneeded function

* Remove gendered hierarchy names

* Add scale factor to volume converter

* Add helper for genericizing pointers

* IWYU

* Use material instead of physics-based material

* Incorporate review feedback
  • Loading branch information
sethrj committed Apr 11, 2024
1 parent b8b0c47 commit 11bc45b
Show file tree
Hide file tree
Showing 21 changed files with 1,286 additions and 50 deletions.
5 changes: 5 additions & 0 deletions src/geocel/detail/LengthUnits.hh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
//---------------------------------------------------------------------------//
#pragma once

#include "celeritas_config.h"
#include "corecel/Types.hh"

#define CELER_ICRT inline constexpr real_type

namespace celeritas
Expand All @@ -27,6 +30,8 @@ CELER_ICRT millimeter = 0.001;
CELER_ICRT meter = 1000;
CELER_ICRT centimeter = 10;
CELER_ICRT millimeter = 1;
#else
# error "CELERITAS_UNITS is undefined"
#endif

//---------------------------------------------------------------------------//
Expand Down
2 changes: 2 additions & 0 deletions src/orange/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ endif()

if(CELERITAS_USE_Geant4 AND CELERITAS_REAL_TYPE STREQUAL "double")
set( _cg4org_sources
g4org/LogicalVolumeConverter.cc
g4org/PhysicalVolumeConverter.cc
g4org/SolidConverter.cc
)
celeritas_get_g4libs(_cg4org_libs geometry)
Expand Down
126 changes: 126 additions & 0 deletions src/orange/g4org/LogicalVolumeConverter.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//----------------------------------*-C++-*----------------------------------//
// Copyright 2023-2024 UT-Battelle, LLC, and other Celeritas developers.
// See the top-level COPYRIGHT file for details.
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
//---------------------------------------------------------------------------//
//! \file orange/g4org/LogicalVolumeConverter.cc
//---------------------------------------------------------------------------//
#include "LogicalVolumeConverter.hh"

#include <G4LogicalVolume.hh>
#include <G4Material.hh>
#include <G4MaterialCutsCouple.hh>
#include <G4VSolid.hh>

#include "corecel/Assert.hh"
#include "corecel/io/Logger.hh"
#include "corecel/sys/Environment.hh"
#include "geocel/GeantGeoUtils.hh"

#include "SolidConverter.hh"
#include "Volume.hh"

namespace celeritas
{
namespace g4org
{
//---------------------------------------------------------------------------//
/*!
* Construct with solid conversion helper.
*/
LogicalVolumeConverter::LogicalVolumeConverter(SolidConverter& convert_solid)
: convert_solid_(convert_solid)
{
}

//---------------------------------------------------------------------------//
/*!
* Convert a Geant4 logical volume to an ORANGE LogicalVolume.
*
* This uses a cache to look up any previously converted volume.
*/
auto LogicalVolumeConverter::operator()(arg_type lv) -> result_type
{
SPLV result;
auto [cache_iter, inserted] = cache_.insert({&lv, {}});
if (inserted || cache_iter->second.expired())
{
// First time converting the volume, or it has expired
result = this->construct_impl(lv);
cache_iter->second = result;
}
else
{
result = cache_iter->second.lock();
}

CELER_ENSURE(result);
return {result, inserted};
}

//---------------------------------------------------------------------------//
/*!
* Convert the raw logical volume without processing any daughters.
*/
auto LogicalVolumeConverter::construct_impl(arg_type g4lv) -> SPLV
{
auto result = std::make_shared<LogicalVolume>();

// Save Geant4 volume pointer for later mappings
result->g4lv = &g4lv;

// Save name
result->name = g4lv.GetName();
if (result->name.find("0x") == std::string::npos)
{
// No pointer address: add one
result->name = make_gdml_name(g4lv);
}

// Save material ID
// NOTE: this is *not* the physics material ("cut couple")
if (auto* mat = g4lv.GetMaterial())
{
result->material_id
= MaterialId{static_cast<size_type>(mat->GetIndex())};
}

// Convert solid
try
{
result->solid = convert_solid_(*g4lv.GetSolid());
}
catch (celeritas::RuntimeError const& e)
{
CELER_LOG(error) << "Failed to convert solid type '"
<< g4lv.GetSolid()->GetEntityType() << "' named '"
<< g4lv.GetSolid()->GetName()
<< "': " << e.details().what;
result->solid = this->convert_solid_.to_sphere(*g4lv.GetSolid());
CELER_LOG(warning) << "Replaced unknown solid with sphere ("
<< to_string(*result->solid) << ")";
CELER_LOG(info) << "Unsupported solid belongs to logical volume "
<< PrintableLV{&g4lv};
}
catch (celeritas::DebugError const& e)
{
CELER_LOG(error) << "Failed to convert solid type '"
<< g4lv.GetSolid()->GetEntityType() << "' named '"
<< g4lv.GetSolid()->GetName();
CELER_LOG(info) << "Unsupported solid belongs to logical volume "
<< PrintableLV{&g4lv};

static bool const allow_errors
= !celeritas::getenv("G4ORG_ALLOW_ERRORS").empty();
if (!allow_errors)
{
throw;
}
}

return result;
}

//---------------------------------------------------------------------------//
} // namespace g4org
} // namespace celeritas
68 changes: 68 additions & 0 deletions src/orange/g4org/LogicalVolumeConverter.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//----------------------------------*-C++-*----------------------------------//
// Copyright 2023-2024 UT-Battelle, LLC, and other Celeritas developers.
// See the top-level COPYRIGHT file for details.
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
//---------------------------------------------------------------------------//
//! \file orange/g4org/LogicalVolumeConverter.hh
//---------------------------------------------------------------------------//
#pragma once

#include <unordered_map>

#include "geocel/Types.hh"
#include "orange/orangeinp/ObjectInterface.hh"

//---------------------------------------------------------------------------//
// Forward declarations
//---------------------------------------------------------------------------//

class G4LogicalVolume;

namespace celeritas
{
namespace g4org
{
//---------------------------------------------------------------------------//
struct LogicalVolume;
class SolidConverter;

//---------------------------------------------------------------------------//
/*!
* Convert a Geant4 base LV to an ORANGE temporary LV.
*
* This does not convert or add any of the daughters, which must be placed as
* physical volumes.
*/
class LogicalVolumeConverter
{
public:
//!@{
//! \name Type aliases
using arg_type = G4LogicalVolume const&;
using SPLV = std::shared_ptr<LogicalVolume>;
using result_type = std::pair<SPLV, bool>;
//!@}

public:
explicit LogicalVolumeConverter(SolidConverter& convert_solid);

// Convert a volume, return result plus insertion
result_type operator()(arg_type);

private:
using WPLV = std::weak_ptr<LogicalVolume>;

//// DATA ////

SolidConverter& convert_solid_;
std::unordered_map<G4LogicalVolume const*, WPLV> cache_;

//// HELPER FUNCTIONS ////

// Convert an LV that's not in the cache
SPLV construct_impl(arg_type);
};

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

0 comments on commit 11bc45b

Please sign in to comment.