From 56e3202ed3b936d0970bc456381ad87edd634cbc Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Wed, 18 Jun 2025 16:56:29 -0700 Subject: [PATCH 01/14] add MakeCartMapFieldInput --- src/accel/CMakeLists.txt | 1 + src/accel/CartMapMagneticField.cc | 117 ++++++++++++++++++++++++++++++ src/accel/CartMapMagneticField.hh | 101 ++++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 src/accel/CartMapMagneticField.cc create mode 100644 src/accel/CartMapMagneticField.hh diff --git a/src/accel/CMakeLists.txt b/src/accel/CMakeLists.txt index 3c65522c40..8564cbbf98 100644 --- a/src/accel/CMakeLists.txt +++ b/src/accel/CMakeLists.txt @@ -29,6 +29,7 @@ list(APPEND SOURCES IntegrationBase.cc Logger.cc LocalTransporter.cc + CartMapMagneticField.cc CylMapMagneticField.cc SetupOptions.cc SetupOptionsMessenger.cc diff --git a/src/accel/CartMapMagneticField.cc b/src/accel/CartMapMagneticField.cc new file mode 100644 index 0000000000..c964130b91 --- /dev/null +++ b/src/accel/CartMapMagneticField.cc @@ -0,0 +1,117 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file accel/CartMapMagneticField.cc +//---------------------------------------------------------------------------// + +#include "CartMapMagneticField.hh" + +#include +#include +#include +#include + +#include "corecel/Types.hh" +#include "corecel/cont/Array.hh" +#include "corecel/data/HyperslabIndexer.hh" +#include "corecel/math/Quantity.hh" +#include "geocel/GeantGeoUtils.hh" +#include "geocel/g4/Convert.hh" +#include "celeritas/Quantities.hh" +#include "celeritas/Types.hh" +#include "celeritas/ext/GeantUnits.hh" +#include "celeritas/field/CartMapFieldInput.hh" +#include "celeritas/field/CartMapFieldParams.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// +/*! + * Generates input for CartMapField params with configurable uniform grid + * dimensions in native Geant4 units. This must be called after + * G4RunManager::Initialize as it will retrieve the G4FieldManager's field + * to sample it. + */ +CartMapFieldParams::Input +MakeCartMapFieldInput(CartMapFieldGridParams const& params) +{ + CELER_VALIDATE(params.max_x > params.min_x, + << "maximum X must be greater than minimum X"); + CELER_VALIDATE(params.max_y > params.min_y, + << "maximum Y must be greater than minimum Y"); + CELER_VALIDATE(params.max_z > params.min_z, + << "maximum Z must be greater than minimum Z"); + CELER_VALIDATE(params.num_x >= 2, + << "number of X grid points must be at least 2"); + CELER_VALIDATE(params.num_y >= 2, + << "number of Y grid points must be at least 2"); + CELER_VALIDATE(params.num_z >= 2, + << "number of Z grid points must be at least 2"); + + CartMapFieldParams::Input field_input; + + // Convert from Geant4 units to native units + field_input.min_x = convert_from_geant(params.min_x, clhep_length); + field_input.max_x = convert_from_geant(params.max_x, clhep_length); + field_input.num_x = params.num_x; + + field_input.min_y = convert_from_geant(params.min_y, clhep_length); + field_input.max_y = convert_from_geant(params.max_y, clhep_length); + field_input.num_y = params.num_y; + + field_input.min_z = convert_from_geant(params.min_z, clhep_length); + field_input.max_z = convert_from_geant(params.max_z, clhep_length); + field_input.num_z = params.num_z; + + size_type const total_points = params.num_x * params.num_y * params.num_z; + field_input.field.resize(static_cast(Axis::size_) + * total_points); + + Array const dims{params.num_x, + params.num_y, + params.num_z, + static_cast(Axis::size_)}; + HyperslabIndexer const flat_index{dims}; + + G4Field const* g4field = celeritas::geant_field(); + CELER_VALIDATE(g4field, + << "no Geant4 global field has been set: cannot build " + "CartMapMagneticField"); + + // Calculate grid spacing + G4double const dx = (params.max_x - params.min_x) / (params.num_x - 1); + G4double const dy = (params.max_y - params.min_y) / (params.num_y - 1); + G4double const dz = (params.max_z - params.min_z) / (params.num_z - 1); + + Array bfield; + for (size_type ix = 0; ix < params.num_x; ++ix) + { + G4double x = params.min_x + ix * dx; + for (size_type iy = 0; iy < params.num_y; ++iy) + { + G4double y = params.min_y + iy * dy; + for (size_type iz = 0; iz < params.num_z; ++iz) + { + G4double z = params.min_z + iz * dz; + + auto* cur_bfield = field_input.field.data() + + flat_index(ix, iy, iz, 0); + + Array pos = {x, y, z, 0}; + g4field->GetFieldValue(pos.data(), bfield.data()); + + // Convert field values from Geant4 units to native units + auto bfield_native + = convert_from_geant(bfield.data(), clhep_field); + std::copy( + bfield_native.cbegin(), bfield_native.cend(), cur_bfield); + } + } + } + CELER_ENSURE(field_input); + return field_input; +} + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/accel/CartMapMagneticField.hh b/src/accel/CartMapMagneticField.hh new file mode 100644 index 0000000000..98fd66c862 --- /dev/null +++ b/src/accel/CartMapMagneticField.hh @@ -0,0 +1,101 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file accel/CartMapMagneticField.hh +//---------------------------------------------------------------------------// +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "corecel/Types.hh" +#include "corecel/math/Quantity.hh" +#include "geocel/g4/Convert.hh" +#include "celeritas/Quantities.hh" +#include "celeritas/field/CartMapField.hh" +#include "celeritas/field/CartMapFieldParams.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// +//! POD struct for CartMap field grid parameters +struct CartMapFieldGridParams +{ + G4double min_x; //!< Minimum X coordinate + G4double max_x; //!< Maximum X coordinate + size_type num_x; //!< Number of grid points in X direction + + G4double min_y; //!< Minimum Y coordinate + G4double max_y; //!< Maximum Y coordinate + size_type num_y; //!< Number of grid points in Y direction + + G4double min_z; //!< Minimum Z coordinate + G4double max_z; //!< Maximum Z coordinate + size_type num_z; //!< Number of grid points in Z direction +}; + +//---------------------------------------------------------------------------// +// Generate field input with user-defined uniform grid +CartMapFieldParams::Input +MakeCartMapFieldInput(CartMapFieldGridParams const& params); + +//---------------------------------------------------------------------------// +/*! + * A user magnetic field equivalent to celeritas::CartMapField. + */ +class CartMapMagneticField : public G4MagneticField +{ + public: + //!@{ + //! \name Type aliases + using SPConstFieldParams = std::shared_ptr; + //!@} + + public: + // Construct with CartMapFieldParams + inline explicit CartMapMagneticField(SPConstFieldParams field_params); + + // Calculate values of the magnetic field vector + inline void + GetFieldValue(G4double const point[3], G4double* field) const override; + + private: + SPConstFieldParams params_; + CartMapField calc_field_; +}; + +//---------------------------------------------------------------------------// +/*! + * Construct with the Celeritas shared CartMapFieldParams. + */ +CartMapMagneticField::CartMapMagneticField(SPConstFieldParams params) + : params_(std::move(params)) + , calc_field_(CartMapField{params_->ref()}) +{ + CELER_EXPECT(params_); +} + +//---------------------------------------------------------------------------// +/*! + * Calculate the magnetic field vector at the given position. + */ +void CartMapMagneticField::GetFieldValue(G4double const pos[3], + G4double* field) const +{ + // Calculate the magnetic field value in the native Celeritas unit system + Real3 result = calc_field_(convert_from_geant(pos, clhep_length)); + for (auto i = 0; i < 3; ++i) + { + // Return values of the field vector in CLHEP::tesla for Geant4 + auto ft = native_value_to(result[i]); + field[i] = convert_to_geant(ft.value(), CLHEP::tesla); + } +} + +//---------------------------------------------------------------------------// +} // namespace celeritas From ae2e39c83346ae6da6f81337b27fa783c34d3398 Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Wed, 18 Jun 2025 17:23:20 -0700 Subject: [PATCH 02/14] extract common behavior --- src/accel/CartMapMagneticField.cc | 95 ++++++++++++++------------ src/accel/CylMapMagneticField.cc | 59 ++++++++-------- src/accel/detail/MagneticFieldUtils.hh | 77 +++++++++++++++++++++ 3 files changed, 159 insertions(+), 72 deletions(-) create mode 100644 src/accel/detail/MagneticFieldUtils.hh diff --git a/src/accel/CartMapMagneticField.cc b/src/accel/CartMapMagneticField.cc index c964130b91..18442e4dd9 100644 --- a/src/accel/CartMapMagneticField.cc +++ b/src/accel/CartMapMagneticField.cc @@ -24,8 +24,38 @@ #include "celeritas/field/CartMapFieldInput.hh" #include "celeritas/field/CartMapFieldParams.hh" +#include "detail/MagneticFieldUtils.hh" + namespace celeritas { +namespace +{ +//---------------------------------------------------------------------------// + +/*! + * Validate grid dimension parameters. + * + * \param min_val Minimum coordinate value + * \param max_val Maximum coordinate value + * \param num_points Number of grid points + * \param dim_name Name of dimension for error messages + */ +void validate_grid_dimension(G4double min_val, + G4double max_val, + size_type num_points, + char const* dim_name) +{ + CELER_VALIDATE(max_val > min_val, + << "maximum " << dim_name + << " must be greater than minimum " << dim_name); + CELER_VALIDATE(num_points >= 2, + << "number of " << dim_name + << " grid points must be at least 2"); +} + +//---------------------------------------------------------------------------// +} // namespace + //---------------------------------------------------------------------------// /*! * Generates input for CartMapField params with configurable uniform grid @@ -36,18 +66,10 @@ namespace celeritas CartMapFieldParams::Input MakeCartMapFieldInput(CartMapFieldGridParams const& params) { - CELER_VALIDATE(params.max_x > params.min_x, - << "maximum X must be greater than minimum X"); - CELER_VALIDATE(params.max_y > params.min_y, - << "maximum Y must be greater than minimum Y"); - CELER_VALIDATE(params.max_z > params.min_z, - << "maximum Z must be greater than minimum Z"); - CELER_VALIDATE(params.num_x >= 2, - << "number of X grid points must be at least 2"); - CELER_VALIDATE(params.num_y >= 2, - << "number of Y grid points must be at least 2"); - CELER_VALIDATE(params.num_z >= 2, - << "number of Z grid points must be at least 2"); + // Validate input parameters + validate_grid_dimension(params.min_x, params.max_x, params.num_x, "X"); + validate_grid_dimension(params.min_y, params.max_y, params.num_y, "Y"); + validate_grid_dimension(params.min_z, params.max_z, params.num_z, "Z"); CartMapFieldParams::Input field_input; @@ -64,6 +86,7 @@ MakeCartMapFieldInput(CartMapFieldGridParams const& params) field_input.max_z = convert_from_geant(params.max_z, clhep_length); field_input.num_z = params.num_z; + // Prepare field data storage size_type const total_points = params.num_x * params.num_y * params.num_z; field_input.field.resize(static_cast(Axis::size_) * total_points); @@ -72,43 +95,31 @@ MakeCartMapFieldInput(CartMapFieldGridParams const& params) params.num_y, params.num_z, static_cast(Axis::size_)}; - HyperslabIndexer const flat_index{dims}; - - G4Field const* g4field = celeritas::geant_field(); - CELER_VALIDATE(g4field, - << "no Geant4 global field has been set: cannot build " - "CartMapMagneticField"); // Calculate grid spacing G4double const dx = (params.max_x - params.min_x) / (params.num_x - 1); G4double const dy = (params.max_y - params.min_y) / (params.num_y - 1); G4double const dz = (params.max_z - params.min_z) / (params.num_z - 1); - Array bfield; - for (size_type ix = 0; ix < params.num_x; ++ix) - { + // Position calculator for Cartesian grid + auto position_calculator = [&](size_type ix, size_type iy, size_type iz) { G4double x = params.min_x + ix * dx; - for (size_type iy = 0; iy < params.num_y; ++iy) - { - G4double y = params.min_y + iy * dy; - for (size_type iz = 0; iz < params.num_z; ++iz) - { - G4double z = params.min_z + iz * dz; - - auto* cur_bfield = field_input.field.data() - + flat_index(ix, iy, iz, 0); - - Array pos = {x, y, z, 0}; - g4field->GetFieldValue(pos.data(), bfield.data()); - - // Convert field values from Geant4 units to native units - auto bfield_native - = convert_from_geant(bfield.data(), clhep_field); - std::copy( - bfield_native.cbegin(), bfield_native.cend(), cur_bfield); - } - } - } + G4double y = params.min_y + iy * dy; + G4double z = params.min_z + iz * dz; + return Array{x, y, z, 0}; + }; + + // Field converter for Cartesian coordinates (no transformation needed) + auto field_converter = [](Array const& bfield, + real_type* cur_bfield) { + auto bfield_native = convert_from_geant(bfield.data(), clhep_field); + std::copy(bfield_native.cbegin(), bfield_native.cend(), cur_bfield); + }; + + // Sample field using common utility + setup_and_sample_field( + field_input.field.data(), dims, position_calculator, field_converter); + CELER_ENSURE(field_input); return field_input; } diff --git a/src/accel/CylMapMagneticField.cc b/src/accel/CylMapMagneticField.cc index 770433ec2e..1b15b2bd3c 100644 --- a/src/accel/CylMapMagneticField.cc +++ b/src/accel/CylMapMagneticField.cc @@ -16,6 +16,7 @@ #include "corecel/Types.hh" #include "corecel/cont/Array.hh" #include "corecel/cont/EnumArray.hh" +#include "corecel/data/HyperslabIndexer.hh" #include "corecel/math/Quantity.hh" #include "corecel/math/Turn.hh" #include "geocel/GeantGeoUtils.hh" @@ -26,6 +27,8 @@ #include "celeritas/field/CylMapFieldInput.hh" #include "celeritas/field/CylMapFieldParams.hh" +#include "detail/MagneticFieldUtils.hh" + namespace celeritas { //---------------------------------------------------------------------------// @@ -63,7 +66,7 @@ MakeCylMapFieldInput(std::vector const& r_grid, field_input.grid_phi.reserve(phi_values.size()); field_input.grid_z.reserve(z_grid.size()); - // Convert from geant + // Convert from geant units to native units std::transform(r_grid.cbegin(), r_grid.cend(), std::back_inserter(field_input.grid_r), @@ -83,41 +86,37 @@ MakeCylMapFieldInput(std::vector const& r_grid, size_type const nz = field_input.grid_z.size(); size_type const total_points = nr * nphi * nz; + // Prepare field data storage field_input.field.resize(static_cast(CylAxis::size_) * total_points); Array const dims{ nr, nphi, nz, static_cast(CylAxis::size_)}; - HyperslabIndexer const flat_index{dims}; - - G4Field const* g4field = celeritas::geant_field(); - CELER_VALIDATE(g4field, - << "no Geant4 global field has been set: cannot build " - "CylMapMagneticField"); - Array bfield; - for (size_type ir = 0; ir < nr; ++ir) - { + + // Position calculator for cylindrical grid + auto position_calculator = [&](size_type ir, size_type iphi, size_type iz) { auto r = r_grid[ir]; - for (size_type iphi = 0; iphi < nphi; ++iphi) - { - auto phi = phi_values[iphi]; - for (size_type iz = 0; iz < nz; ++iz) - { - auto* cur_bfield = field_input.field.data() - + flat_index(ir, iphi, iz, 0); - Array pos - = {r * std::cos(phi), r * std::sin(phi), z_grid[iz], 0}; - g4field->GetFieldValue(pos.data(), bfield.data()); - EnumArray bfield_cyl; - cartesian_to_cylindrical(bfield, bfield_cyl); - auto bfield_cyl_native - = convert_from_geant(bfield_cyl.data(), clhep_field); - std::copy(bfield_cyl_native.cbegin(), - bfield_cyl_native.cend(), - cur_bfield); - } - } - } + auto phi = phi_values[iphi]; + auto z = z_grid[iz]; + return Array{r * std::cos(phi), r * std::sin(phi), z, 0}; + }; + + // Field converter for cylindrical coordinates (requires coordinate + // transformation) + auto field_converter = [](Array const& bfield, + real_type* cur_bfield) { + EnumArray bfield_cyl; + cartesian_to_cylindrical(bfield, bfield_cyl); + auto bfield_cyl_native + = convert_from_geant(bfield_cyl.data(), clhep_field); + std::copy( + bfield_cyl_native.cbegin(), bfield_cyl_native.cend(), cur_bfield); + }; + + // Sample field using common utility + setup_and_sample_field( + field_input.field.data(), dims, position_calculator, field_converter); + CELER_ENSURE(field_input); return field_input; } diff --git a/src/accel/detail/MagneticFieldUtils.hh b/src/accel/detail/MagneticFieldUtils.hh new file mode 100644 index 0000000000..7feaf043b3 --- /dev/null +++ b/src/accel/detail/MagneticFieldUtils.hh @@ -0,0 +1,77 @@ +//------------------------------- -*- C++ -*- -------------------------------// +// Copyright Celeritas contributors: see top-level COPYRIGHT file for details +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file accel/detail/MagneticFieldUtils.hh +//! \brief Utilities for magnetic field map creation +//---------------------------------------------------------------------------// +#pragma once + +#include +#include + +#include "corecel/Types.hh" +#include "corecel/cont/Array.hh" +#include "corecel/data/HyperslabIndexer.hh" +#include "geocel/GeantGeoUtils.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// +/*! + * Common field sampling setup and execution. + * + * This function encapsulates the shared pattern of: + * 1. Getting the G4 field + * 2. Setting up the HyperslabIndexer + * 3. Sampling the field on a grid + * + * \param field_data Output parameter array to store field values (must be + * pre-allocated with size equal to the product of all dims) + * \param dims Grid dimensions + * \param position_calculator Callable that computes position given + * grid indices. Must have signature: + * Array(size_type, size_type, + * size_type) returning [x, y, z, 0] coordinates + * \param field_converter Callable that converts field from G4 to + * native units in the correct coodinate space. Must + * have signature: void(Array const&, + * real_type*) taking G4 field [Bx, By, Bz] and writing + * converted values to output pointer + */ +template +inline void setup_and_sample_field(real_type* field_data, + Array const& dims, + PositionCalc const& position_calculator, + FieldConverter const& field_converter) +{ + HyperslabIndexer const flat_index{dims}; + G4Field const* g4field = celeritas::geant_field(); + CELER_VALIDATE(g4field, + << "no Geant4 global field has been set: cannot build " + "magnetic field map"); + + Array bfield; + + for (size_type i = 0; i < dims[0]; ++i) + { + for (size_type j = 0; j < dims[1]; ++j) + { + for (size_type k = 0; k < dims[2]; ++k) + { + // Calculate position for this grid point + Array pos = position_calculator(i, j, k); + + // Sample field at this position + g4field->GetFieldValue(pos.data(), bfield.data()); + + // Convert and store field values + auto* cur_bfield = field_data + flat_index(i, j, k, 0); + field_converter(bfield, cur_bfield); + } + } + } +} + +//---------------------------------------------------------------------------// +} // namespace celeritas From 82df7bbdfb014dd92ea75bc26ab321913186b7f5 Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Wed, 18 Jun 2025 17:57:15 -0700 Subject: [PATCH 03/14] namespace --- src/accel/CartMapMagneticField.cc | 2 +- src/accel/CylMapMagneticField.cc | 3 +-- src/accel/detail/MagneticFieldUtils.hh | 3 +++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/accel/CartMapMagneticField.cc b/src/accel/CartMapMagneticField.cc index 18442e4dd9..48fac5f0e1 100644 --- a/src/accel/CartMapMagneticField.cc +++ b/src/accel/CartMapMagneticField.cc @@ -117,7 +117,7 @@ MakeCartMapFieldInput(CartMapFieldGridParams const& params) }; // Sample field using common utility - setup_and_sample_field( + detail::setup_and_sample_field( field_input.field.data(), dims, position_calculator, field_converter); CELER_ENSURE(field_input); diff --git a/src/accel/CylMapMagneticField.cc b/src/accel/CylMapMagneticField.cc index 1b15b2bd3c..4ea827f805 100644 --- a/src/accel/CylMapMagneticField.cc +++ b/src/accel/CylMapMagneticField.cc @@ -31,7 +31,6 @@ namespace celeritas { -//---------------------------------------------------------------------------// namespace { //---------------------------------------------------------------------------// @@ -114,7 +113,7 @@ MakeCylMapFieldInput(std::vector const& r_grid, }; // Sample field using common utility - setup_and_sample_field( + detail::setup_and_sample_field( field_input.field.data(), dims, position_calculator, field_converter); CELER_ENSURE(field_input); diff --git a/src/accel/detail/MagneticFieldUtils.hh b/src/accel/detail/MagneticFieldUtils.hh index 7feaf043b3..eb4f42f0e4 100644 --- a/src/accel/detail/MagneticFieldUtils.hh +++ b/src/accel/detail/MagneticFieldUtils.hh @@ -17,6 +17,8 @@ namespace celeritas { +namespace detail +{ //---------------------------------------------------------------------------// /*! * Common field sampling setup and execution. @@ -74,4 +76,5 @@ inline void setup_and_sample_field(real_type* field_data, } //---------------------------------------------------------------------------// +} // namespace detail } // namespace celeritas From 45e894287b964f09124650fea8ce2af84e4fb72c Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Wed, 18 Jun 2025 18:40:54 -0700 Subject: [PATCH 04/14] headers, and link to covfie --- src/accel/CMakeLists.txt | 1 + src/accel/CartMapMagneticField.cc | 4 ---- src/accel/CylMapMagneticField.cc | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/accel/CMakeLists.txt b/src/accel/CMakeLists.txt index 8564cbbf98..3facbb754b 100644 --- a/src/accel/CMakeLists.txt +++ b/src/accel/CMakeLists.txt @@ -6,6 +6,7 @@ set(SOURCES) set(PRIVATE_DEPS nlohmann_json::nlohmann_json + Celeritas::Extcovfie Celeritas::ExtThrust # TODO: add thrust exception conversion to corecel? Celeritas::ExtOpenMP # TODO: provide thread utils in corecel ) diff --git a/src/accel/CartMapMagneticField.cc b/src/accel/CartMapMagneticField.cc index 48fac5f0e1..777a195d49 100644 --- a/src/accel/CartMapMagneticField.cc +++ b/src/accel/CartMapMagneticField.cc @@ -14,11 +14,7 @@ #include "corecel/Types.hh" #include "corecel/cont/Array.hh" -#include "corecel/data/HyperslabIndexer.hh" -#include "corecel/math/Quantity.hh" -#include "geocel/GeantGeoUtils.hh" #include "geocel/g4/Convert.hh" -#include "celeritas/Quantities.hh" #include "celeritas/Types.hh" #include "celeritas/ext/GeantUnits.hh" #include "celeritas/field/CartMapFieldInput.hh" diff --git a/src/accel/CylMapMagneticField.cc b/src/accel/CylMapMagneticField.cc index 4ea827f805..1b03c58046 100644 --- a/src/accel/CylMapMagneticField.cc +++ b/src/accel/CylMapMagneticField.cc @@ -16,10 +16,8 @@ #include "corecel/Types.hh" #include "corecel/cont/Array.hh" #include "corecel/cont/EnumArray.hh" -#include "corecel/data/HyperslabIndexer.hh" #include "corecel/math/Quantity.hh" #include "corecel/math/Turn.hh" -#include "geocel/GeantGeoUtils.hh" #include "geocel/g4/Convert.hh" #include "celeritas/Quantities.hh" #include "celeritas/Types.hh" From 8c3bf21c7a5a8d58acda0262f11197a5c3d9613c Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Wed, 18 Jun 2025 18:49:02 -0700 Subject: [PATCH 05/14] hide c++20 dependency --- src/accel/CartMapMagneticField.cc | 60 +++++++++++++++++++++++++++++++ src/accel/CartMapMagneticField.hh | 43 +++++----------------- 2 files changed, 68 insertions(+), 35 deletions(-) diff --git a/src/accel/CartMapMagneticField.cc b/src/accel/CartMapMagneticField.cc index 777a195d49..b9d8a0c04e 100644 --- a/src/accel/CartMapMagneticField.cc +++ b/src/accel/CartMapMagneticField.cc @@ -17,6 +17,7 @@ #include "geocel/g4/Convert.hh" #include "celeritas/Types.hh" #include "celeritas/ext/GeantUnits.hh" +#include "celeritas/field/CartMapField.hh" #include "celeritas/field/CartMapFieldInput.hh" #include "celeritas/field/CartMapFieldParams.hh" @@ -24,6 +25,30 @@ namespace celeritas { +//---------------------------------------------------------------------------// +// PIMPL IMPLEMENTATION +//---------------------------------------------------------------------------// + +/*! + * Implementation struct for CartMapMagneticField. + * + * This hides the C++20 dependency (CartMapField) from the header file. + */ +struct CartMapMagneticField::Impl +{ + CartMapMagneticField::SPConstFieldParams params; + CartMapField calc_field; + + explicit Impl(CartMapMagneticField::SPConstFieldParams field_params) + : params(std::move(field_params)) + , calc_field(CartMapField{params->ref()}) + { + CELER_EXPECT(params); + } +}; + +//---------------------------------------------------------------------------// + namespace { //---------------------------------------------------------------------------// @@ -120,5 +145,40 @@ MakeCartMapFieldInput(CartMapFieldGridParams const& params) return field_input; } +//---------------------------------------------------------------------------// +// CARTMAPMAGNETIC FIELD IMPLEMENTATION +//---------------------------------------------------------------------------// + +/*! + * Construct with the Celeritas shared CartMapFieldParams. + */ +CartMapMagneticField::CartMapMagneticField(SPConstFieldParams field_params) + : pimpl_(std::make_unique(std::move(field_params))) +{ +} + +//---------------------------------------------------------------------------// +/*! + * Destructor. + */ +CartMapMagneticField::~CartMapMagneticField() = default; + +//---------------------------------------------------------------------------// +/*! + * Calculate the magnetic field vector at the given position. + */ +void CartMapMagneticField::GetFieldValue(G4double const pos[3], + G4double* field) const +{ + // Calculate the magnetic field value in the native Celeritas unit system + Real3 result = pimpl_->calc_field(convert_from_geant(pos, clhep_length)); + for (auto i = 0; i < 3; ++i) + { + // Return values of the field vector in CLHEP::tesla for Geant4 + auto ft = native_value_to(result[i]); + field[i] = convert_to_geant(ft.value(), CLHEP::tesla); + } +} + //---------------------------------------------------------------------------// } // namespace celeritas diff --git a/src/accel/CartMapMagneticField.hh b/src/accel/CartMapMagneticField.hh index 98fd66c862..c475db4dc2 100644 --- a/src/accel/CartMapMagneticField.hh +++ b/src/accel/CartMapMagneticField.hh @@ -14,10 +14,6 @@ #include #include "corecel/Types.hh" -#include "corecel/math/Quantity.hh" -#include "geocel/g4/Convert.hh" -#include "celeritas/Quantities.hh" -#include "celeritas/field/CartMapField.hh" #include "celeritas/field/CartMapFieldParams.hh" namespace celeritas @@ -58,44 +54,21 @@ class CartMapMagneticField : public G4MagneticField public: // Construct with CartMapFieldParams - inline explicit CartMapMagneticField(SPConstFieldParams field_params); + explicit CartMapMagneticField(SPConstFieldParams field_params); + + // Destructor + ~CartMapMagneticField() override; // Calculate values of the magnetic field vector - inline void - GetFieldValue(G4double const point[3], G4double* field) const override; + void GetFieldValue(G4double const point[3], G4double* field) const override; private: - SPConstFieldParams params_; - CartMapField calc_field_; + // Forward declaration for PIMPL + struct Impl; + std::unique_ptr pimpl_; }; //---------------------------------------------------------------------------// -/*! - * Construct with the Celeritas shared CartMapFieldParams. - */ -CartMapMagneticField::CartMapMagneticField(SPConstFieldParams params) - : params_(std::move(params)) - , calc_field_(CartMapField{params_->ref()}) -{ - CELER_EXPECT(params_); -} - -//---------------------------------------------------------------------------// -/*! - * Calculate the magnetic field vector at the given position. - */ -void CartMapMagneticField::GetFieldValue(G4double const pos[3], - G4double* field) const -{ - // Calculate the magnetic field value in the native Celeritas unit system - Real3 result = calc_field_(convert_from_geant(pos, clhep_length)); - for (auto i = 0; i < 3; ++i) - { - // Return values of the field vector in CLHEP::tesla for Geant4 - auto ft = native_value_to(result[i]); - field[i] = convert_to_geant(ft.value(), CLHEP::tesla); - } -} //---------------------------------------------------------------------------// } // namespace celeritas From fc00fb4845ce4a80ba621fbca3c408310e2b77c4 Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Wed, 18 Jun 2025 22:07:35 -0700 Subject: [PATCH 06/14] reword input validation --- src/accel/CartMapMagneticField.cc | 34 +------------------------- src/accel/CartMapMagneticField.hh | 25 ++++++++++++------- src/accel/detail/MagneticFieldUtils.hh | 2 +- 3 files changed, 18 insertions(+), 43 deletions(-) diff --git a/src/accel/CartMapMagneticField.cc b/src/accel/CartMapMagneticField.cc index b9d8a0c04e..d60970cf01 100644 --- a/src/accel/CartMapMagneticField.cc +++ b/src/accel/CartMapMagneticField.cc @@ -47,36 +47,6 @@ struct CartMapMagneticField::Impl } }; -//---------------------------------------------------------------------------// - -namespace -{ -//---------------------------------------------------------------------------// - -/*! - * Validate grid dimension parameters. - * - * \param min_val Minimum coordinate value - * \param max_val Maximum coordinate value - * \param num_points Number of grid points - * \param dim_name Name of dimension for error messages - */ -void validate_grid_dimension(G4double min_val, - G4double max_val, - size_type num_points, - char const* dim_name) -{ - CELER_VALIDATE(max_val > min_val, - << "maximum " << dim_name - << " must be greater than minimum " << dim_name); - CELER_VALIDATE(num_points >= 2, - << "number of " << dim_name - << " grid points must be at least 2"); -} - -//---------------------------------------------------------------------------// -} // namespace - //---------------------------------------------------------------------------// /*! * Generates input for CartMapField params with configurable uniform grid @@ -88,9 +58,7 @@ CartMapFieldParams::Input MakeCartMapFieldInput(CartMapFieldGridParams const& params) { // Validate input parameters - validate_grid_dimension(params.min_x, params.max_x, params.num_x, "X"); - validate_grid_dimension(params.min_y, params.max_y, params.num_y, "Y"); - validate_grid_dimension(params.min_z, params.max_z, params.num_z, "Z"); + CELER_VALIDATE(params, << "invalid CartMapFieldGridParams provided"); CartMapFieldParams::Input field_input; diff --git a/src/accel/CartMapMagneticField.hh b/src/accel/CartMapMagneticField.hh index c475db4dc2..75dc428720 100644 --- a/src/accel/CartMapMagneticField.hh +++ b/src/accel/CartMapMagneticField.hh @@ -22,17 +22,24 @@ namespace celeritas //! POD struct for CartMap field grid parameters struct CartMapFieldGridParams { - G4double min_x; //!< Minimum X coordinate - G4double max_x; //!< Maximum X coordinate - size_type num_x; //!< Number of grid points in X direction + G4double min_x{}; //!< Minimum X coordinate + G4double max_x{}; //!< Maximum X coordinate + size_type num_x{}; //!< Number of grid points in X direction - G4double min_y; //!< Minimum Y coordinate - G4double max_y; //!< Maximum Y coordinate - size_type num_y; //!< Number of grid points in Y direction + G4double min_y{}; //!< Minimum Y coordinate + G4double max_y{}; //!< Maximum Y coordinate + size_type num_y{}; //!< Number of grid points in Y direction - G4double min_z; //!< Minimum Z coordinate - G4double max_z; //!< Maximum Z coordinate - size_type num_z; //!< Number of grid points in Z direction + G4double min_z{}; //!< Minimum Z coordinate + G4double max_z{}; //!< Maximum Z coordinate + size_type num_z{}; //!< Number of grid points in Z direction + + //! Check if parameters are valid for field generation + explicit operator bool() const + { + return (max_x > min_x && num_x > 1) && (max_y > min_y && num_y > 1) + && (max_z > min_z && num_z > 1); + } }; //---------------------------------------------------------------------------// diff --git a/src/accel/detail/MagneticFieldUtils.hh b/src/accel/detail/MagneticFieldUtils.hh index eb4f42f0e4..dcbb05bef1 100644 --- a/src/accel/detail/MagneticFieldUtils.hh +++ b/src/accel/detail/MagneticFieldUtils.hh @@ -36,7 +36,7 @@ namespace detail * Array(size_type, size_type, * size_type) returning [x, y, z, 0] coordinates * \param field_converter Callable that converts field from G4 to - * native units in the correct coodinate space. Must + * native units in the correct coordinate space. Must * have signature: void(Array const&, * real_type*) taking G4 field [Bx, By, Bz] and writing * converted values to output pointer From 88f0263dfea28991b49226f2f99df15b893cbb6d Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Fri, 20 Jun 2025 10:05:43 -0700 Subject: [PATCH 07/14] custom deleter, naming --- src/accel/CartMapMagneticField.cc | 14 +++++++++----- src/accel/CartMapMagneticField.hh | 24 ++++++++++++++++-------- src/accel/detail/MagneticFieldUtils.hh | 8 ++++---- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/accel/CartMapMagneticField.cc b/src/accel/CartMapMagneticField.cc index d60970cf01..0ee803bba8 100644 --- a/src/accel/CartMapMagneticField.cc +++ b/src/accel/CartMapMagneticField.cc @@ -14,6 +14,7 @@ #include "corecel/Types.hh" #include "corecel/cont/Array.hh" +#include "corecel/math/ArrayUtils.hh" #include "geocel/g4/Convert.hh" #include "celeritas/Types.hh" #include "celeritas/ext/GeantUnits.hh" @@ -118,18 +119,21 @@ MakeCartMapFieldInput(CartMapFieldGridParams const& params) //---------------------------------------------------------------------------// /*! - * Construct with the Celeritas shared CartMapFieldParams. + * Custom deleter implementation for PIMPL idiom. */ -CartMapMagneticField::CartMapMagneticField(SPConstFieldParams field_params) - : pimpl_(std::make_unique(std::move(field_params))) +void CartMapMagneticField::ImplDeleter::operator()(Impl* ptr) const { + delete ptr; } //---------------------------------------------------------------------------// /*! - * Destructor. + * Construct with the Celeritas shared CartMapFieldParams. */ -CartMapMagneticField::~CartMapMagneticField() = default; +CartMapMagneticField::CartMapMagneticField(SPConstFieldParams field_params) + : pimpl_(new Impl(std::move(field_params))) +{ +} //---------------------------------------------------------------------------// /*! diff --git a/src/accel/CartMapMagneticField.hh b/src/accel/CartMapMagneticField.hh index 75dc428720..a004fa45f0 100644 --- a/src/accel/CartMapMagneticField.hh +++ b/src/accel/CartMapMagneticField.hh @@ -7,12 +7,9 @@ #pragma once #include -#include -#include #include -#include -#include +#include "corecel/Macros.hh" #include "corecel/Types.hh" #include "celeritas/field/CartMapFieldParams.hh" @@ -59,20 +56,31 @@ class CartMapMagneticField : public G4MagneticField using SPConstFieldParams = std::shared_ptr; //!@} + private: + // Forward declaration for pImpl + struct Impl; + + // Custom deleter for pImpl + struct ImplDeleter + { + void operator()(Impl* ptr) const; + }; + public: // Construct with CartMapFieldParams explicit CartMapMagneticField(SPConstFieldParams field_params); + // Default move semantics work with custom deleter + CELER_DEFAULT_MOVE_DELETE_COPY(CartMapMagneticField); + // Destructor - ~CartMapMagneticField() override; + ~CartMapMagneticField() override = default; // Calculate values of the magnetic field vector void GetFieldValue(G4double const point[3], G4double* field) const override; private: - // Forward declaration for PIMPL - struct Impl; - std::unique_ptr pimpl_; + std::unique_ptr pimpl_; }; //---------------------------------------------------------------------------// diff --git a/src/accel/detail/MagneticFieldUtils.hh b/src/accel/detail/MagneticFieldUtils.hh index dcbb05bef1..aac18438a3 100644 --- a/src/accel/detail/MagneticFieldUtils.hh +++ b/src/accel/detail/MagneticFieldUtils.hh @@ -44,8 +44,8 @@ namespace detail template inline void setup_and_sample_field(real_type* field_data, Array const& dims, - PositionCalc const& position_calculator, - FieldConverter const& field_converter) + PositionCalc const& calc_position, + FieldConverter const& convert_field) { HyperslabIndexer const flat_index{dims}; G4Field const* g4field = celeritas::geant_field(); @@ -62,14 +62,14 @@ inline void setup_and_sample_field(real_type* field_data, for (size_type k = 0; k < dims[2]; ++k) { // Calculate position for this grid point - Array pos = position_calculator(i, j, k); + Array pos = calc_position(i, j, k); // Sample field at this position g4field->GetFieldValue(pos.data(), bfield.data()); // Convert and store field values auto* cur_bfield = field_data + flat_index(i, j, k, 0); - field_converter(bfield, cur_bfield); + convert_field(bfield, cur_bfield); } } } From 687332ff3fad18cf4bf442223ea5f1ca731c1989 Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Fri, 20 Jun 2025 10:10:20 -0700 Subject: [PATCH 08/14] define uniform struct --- src/accel/CartMapMagneticField.cc | 38 +++++++++++++++---------------- src/accel/CartMapMagneticField.hh | 32 +++++++++++++------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/accel/CartMapMagneticField.cc b/src/accel/CartMapMagneticField.cc index 0ee803bba8..bf1320fb91 100644 --- a/src/accel/CartMapMagneticField.cc +++ b/src/accel/CartMapMagneticField.cc @@ -64,38 +64,38 @@ MakeCartMapFieldInput(CartMapFieldGridParams const& params) CartMapFieldParams::Input field_input; // Convert from Geant4 units to native units - field_input.min_x = convert_from_geant(params.min_x, clhep_length); - field_input.max_x = convert_from_geant(params.max_x, clhep_length); - field_input.num_x = params.num_x; + field_input.min_x = convert_from_geant(params.x.min, clhep_length); + field_input.max_x = convert_from_geant(params.x.max, clhep_length); + field_input.num_x = params.x.num; - field_input.min_y = convert_from_geant(params.min_y, clhep_length); - field_input.max_y = convert_from_geant(params.max_y, clhep_length); - field_input.num_y = params.num_y; + field_input.min_y = convert_from_geant(params.y.min, clhep_length); + field_input.max_y = convert_from_geant(params.y.max, clhep_length); + field_input.num_y = params.y.num; - field_input.min_z = convert_from_geant(params.min_z, clhep_length); - field_input.max_z = convert_from_geant(params.max_z, clhep_length); - field_input.num_z = params.num_z; + field_input.min_z = convert_from_geant(params.z.min, clhep_length); + field_input.max_z = convert_from_geant(params.z.max, clhep_length); + field_input.num_z = params.z.num; // Prepare field data storage - size_type const total_points = params.num_x * params.num_y * params.num_z; + size_type const total_points = params.x.num * params.y.num * params.z.num; field_input.field.resize(static_cast(Axis::size_) * total_points); - Array const dims{params.num_x, - params.num_y, - params.num_z, + Array const dims{params.x.num, + params.y.num, + params.z.num, static_cast(Axis::size_)}; // Calculate grid spacing - G4double const dx = (params.max_x - params.min_x) / (params.num_x - 1); - G4double const dy = (params.max_y - params.min_y) / (params.num_y - 1); - G4double const dz = (params.max_z - params.min_z) / (params.num_z - 1); + G4double const dx = (params.x.max - params.x.min) / (params.x.num - 1); + G4double const dy = (params.y.max - params.y.min) / (params.y.num - 1); + G4double const dz = (params.z.max - params.z.min) / (params.z.num - 1); // Position calculator for Cartesian grid auto position_calculator = [&](size_type ix, size_type iy, size_type iz) { - G4double x = params.min_x + ix * dx; - G4double y = params.min_y + iy * dy; - G4double z = params.min_z + iz * dz; + G4double x = params.x.min + ix * dx; + G4double y = params.y.min + iy * dy; + G4double z = params.z.min + iz * dz; return Array{x, y, z, 0}; }; diff --git a/src/accel/CartMapMagneticField.hh b/src/accel/CartMapMagneticField.hh index a004fa45f0..338493e1d3 100644 --- a/src/accel/CartMapMagneticField.hh +++ b/src/accel/CartMapMagneticField.hh @@ -16,27 +16,27 @@ namespace celeritas { //---------------------------------------------------------------------------// -//! POD struct for CartMap field grid parameters -struct CartMapFieldGridParams +//! Uniform grid specification for a single axis +struct Uniform { - G4double min_x{}; //!< Minimum X coordinate - G4double max_x{}; //!< Maximum X coordinate - size_type num_x{}; //!< Number of grid points in X direction + G4double min{}; //!< Minimum coordinate value + G4double max{}; //!< Maximum coordinate value + size_type num{}; //!< Number of grid points - G4double min_y{}; //!< Minimum Y coordinate - G4double max_y{}; //!< Maximum Y coordinate - size_type num_y{}; //!< Number of grid points in Y direction + //! Check if parameters are valid + explicit operator bool() const { return max > min && num > 1; } +}; - G4double min_z{}; //!< Minimum Z coordinate - G4double max_z{}; //!< Maximum Z coordinate - size_type num_z{}; //!< Number of grid points in Z direction +//---------------------------------------------------------------------------// +//! POD struct for CartMap field grid parameters +struct CartMapFieldGridParams +{ + Uniform x{}; //!< X-axis grid specification + Uniform y{}; //!< Y-axis grid specification + Uniform z{}; //!< Z-axis grid specification //! Check if parameters are valid for field generation - explicit operator bool() const - { - return (max_x > min_x && num_x > 1) && (max_y > min_y && num_y > 1) - && (max_z > min_z && num_z > 1); - } + explicit operator bool() const { return x && y && z; } }; //---------------------------------------------------------------------------// From ca79e6ba0af959e2b542e27dc8c6d5bd5cf9b1ef Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Fri, 20 Jun 2025 10:26:23 -0700 Subject: [PATCH 09/14] use uniform for field input --- src/accel/CartMapMagneticField.cc | 18 ++++---- src/accel/CartMapMagneticField.hh | 20 ++------ src/celeritas/field/CartMapFieldInput.hh | 41 ++++++++--------- .../field/CartMapFieldParams.covfie.cc | 32 ++++++------- test/celeritas/field/Fields.test.cc | 46 +++++++++---------- 5 files changed, 72 insertions(+), 85 deletions(-) diff --git a/src/accel/CartMapMagneticField.cc b/src/accel/CartMapMagneticField.cc index bf1320fb91..08669711cc 100644 --- a/src/accel/CartMapMagneticField.cc +++ b/src/accel/CartMapMagneticField.cc @@ -64,17 +64,17 @@ MakeCartMapFieldInput(CartMapFieldGridParams const& params) CartMapFieldParams::Input field_input; // Convert from Geant4 units to native units - field_input.min_x = convert_from_geant(params.x.min, clhep_length); - field_input.max_x = convert_from_geant(params.x.max, clhep_length); - field_input.num_x = params.x.num; + field_input.x.min = convert_from_geant(params.x.min, clhep_length); + field_input.x.max = convert_from_geant(params.x.max, clhep_length); + field_input.x.num = params.x.num; - field_input.min_y = convert_from_geant(params.y.min, clhep_length); - field_input.max_y = convert_from_geant(params.y.max, clhep_length); - field_input.num_y = params.y.num; + field_input.y.min = convert_from_geant(params.y.min, clhep_length); + field_input.y.max = convert_from_geant(params.y.max, clhep_length); + field_input.y.num = params.y.num; - field_input.min_z = convert_from_geant(params.z.min, clhep_length); - field_input.max_z = convert_from_geant(params.z.max, clhep_length); - field_input.num_z = params.z.num; + field_input.z.min = convert_from_geant(params.z.min, clhep_length); + field_input.z.max = convert_from_geant(params.z.max, clhep_length); + field_input.z.num = params.z.num; // Prepare field data storage size_type const total_points = params.x.num * params.y.num * params.z.num; diff --git a/src/accel/CartMapMagneticField.hh b/src/accel/CartMapMagneticField.hh index 338493e1d3..94e8c63607 100644 --- a/src/accel/CartMapMagneticField.hh +++ b/src/accel/CartMapMagneticField.hh @@ -10,30 +10,18 @@ #include #include "corecel/Macros.hh" -#include "corecel/Types.hh" +#include "celeritas/field/CartMapFieldInput.hh" #include "celeritas/field/CartMapFieldParams.hh" namespace celeritas { -//---------------------------------------------------------------------------// -//! Uniform grid specification for a single axis -struct Uniform -{ - G4double min{}; //!< Minimum coordinate value - G4double max{}; //!< Maximum coordinate value - size_type num{}; //!< Number of grid points - - //! Check if parameters are valid - explicit operator bool() const { return max > min && num > 1; } -}; - //---------------------------------------------------------------------------// //! POD struct for CartMap field grid parameters struct CartMapFieldGridParams { - Uniform x{}; //!< X-axis grid specification - Uniform y{}; //!< Y-axis grid specification - Uniform z{}; //!< Z-axis grid specification + AxisGrid x{}; //!< X-axis grid specification + AxisGrid y{}; //!< Y-axis grid specification + AxisGrid z{}; //!< Z-axis grid specification //! Check if parameters are valid for field generation explicit operator bool() const { return x && y && z; } diff --git a/src/celeritas/field/CartMapFieldInput.hh b/src/celeritas/field/CartMapFieldInput.hh index dedcd3598f..2044c5e2ca 100644 --- a/src/celeritas/field/CartMapFieldInput.hh +++ b/src/celeritas/field/CartMapFieldInput.hh @@ -16,6 +16,19 @@ namespace celeritas { +//---------------------------------------------------------------------------// +//! Grid specification for a single axis +template +struct AxisGrid +{ + T min{}; //!< Minimum coordinate value + T max{}; //!< Maximum coordinate value + size_type num{}; //!< Number of grid points + + //! Check if parameters are valid + explicit operator bool() const { return max > min && num > 1; } +}; + //---------------------------------------------------------------------------// /*! * Input data for a magnetic X-Y-Z vector field stored on an X-Y-Z grid. @@ -30,17 +43,9 @@ namespace celeritas */ struct CartMapFieldInput { - real_type min_x; //!< Minimum X grid point [len] - real_type max_x; //!< Maximum X grid point [len] - size_type num_x; //!< Number of X grid points - - real_type min_y; //!< Minimum Y grid point [len] - real_type max_y; //!< Maximum Y grid point [len] - size_type num_y; //!< Number of Y grid points - - real_type min_z; //!< Minimum Z grid point [len] - real_type max_z; //!< Maximum Z grid point [len] - size_type num_z; //!< Number of Z grid points + AxisGrid x; //!< X-axis grid specification [len] + AxisGrid y; //!< Y-axis grid specification [len] + AxisGrid z; //!< Z-axis grid specification [len] std::vector field; //!< Flattened X-Y-Z field component //!< [bfield] @@ -51,16 +56,10 @@ struct CartMapFieldInput //! Whether all data are assigned and valid explicit operator bool() const { - // clang-format off - return - (max_x >= min_x) - && (num_x >= 2) - && (max_y >= min_y) - && (num_y >= 2) - && (max_z >= min_z) - && (num_z >= 2) - && (field.size() == static_cast(Axis::size_) * num_x * num_y * num_z); - // clang-format on + return x && y && z + && (field.size() + == static_cast(Axis::size_) * x.num * y.num + * z.num); } }; diff --git a/src/celeritas/field/CartMapFieldParams.covfie.cc b/src/celeritas/field/CartMapFieldParams.covfie.cc index 9420d3695f..78ad1b2bf9 100644 --- a/src/celeritas/field/CartMapFieldParams.covfie.cc +++ b/src/celeritas/field/CartMapFieldParams.covfie.cc @@ -34,9 +34,9 @@ struct CartMapFieldParams::Impl : host_{[&inp] { HostVal host; - Array const dims{inp.num_x, - inp.num_y, - inp.num_z, + Array const dims{inp.x.num, + inp.y.num, + inp.z.num, static_cast(Axis::size_)}; HyperslabIndexer const flat_index{dims}; @@ -45,14 +45,14 @@ struct CartMapFieldParams::Impl builder_t builder{covfie::make_parameter_pack( builder_t::backend_t::configuration_t{ - inp.num_x, inp.num_y, inp.num_z})}; + inp.x.num, inp.y.num, inp.z.num})}; builder_t::view_t builder_view{builder}; // fill the covfie field data - for (auto ix : range(inp.num_x)) + for (auto ix : range(inp.x.num)) { - for (auto iy : range(inp.num_y)) + for (auto iy : range(inp.y.num)) { - for (auto iz : range(inp.num_z)) + for (auto iz : range(inp.z.num)) { auto* fv = builder_view.at(ix, iy, iz).begin(); auto* finp = inp.field.data() @@ -66,17 +66,17 @@ struct CartMapFieldParams::Impl using field_real_type = CartMapField::real_type; auto affine_translate = covfie::algebra::affine<3>::translation( - static_cast(-inp.min_x), - static_cast(-inp.min_y), - static_cast(-inp.min_z)); + static_cast(-inp.x.min), + static_cast(-inp.y.min), + static_cast(-inp.z.min)); auto affine_scale = covfie::algebra::affine<3>::scaling( - static_cast((inp.num_x - 1) - / (inp.max_x - inp.min_x)), - static_cast((inp.num_y - 1) - / (inp.max_y - inp.min_y)), - static_cast((inp.num_z - 1) - / (inp.max_z - inp.min_z))); + static_cast((inp.x.num - 1) + / (inp.x.max - inp.x.min)), + static_cast((inp.y.num - 1) + / (inp.y.max - inp.y.min)), + static_cast((inp.z.num - 1) + / (inp.z.max - inp.z.min))); using field_t = detail::CovfieFieldTraits::field_t; host.field = std::make_unique(covfie::make_parameter_pack( diff --git a/test/celeritas/field/Fields.test.cc b/test/celeritas/field/Fields.test.cc index 9ddbe425fa..0cad868c11 100644 --- a/test/celeritas/field/Fields.test.cc +++ b/test/celeritas/field/Fields.test.cc @@ -289,29 +289,29 @@ using CartMapFieldTest = ::celeritas::test::Test; TEST_F(CartMapFieldTest, all) { CartMapFieldInput inp; - inp.min_x = -2750; - inp.max_x = 2750; - inp.num_x = static_cast(inp.max_x * 2 / 100); - inp.min_y = -2750; - inp.max_y = 2750; - inp.num_y = static_cast(inp.max_y * 2 / 100); - inp.min_z = -6350; - inp.max_z = 6350; - inp.num_z = static_cast(inp.max_z * 2 / 100); + inp.x.min = -2750; + inp.x.max = 2750; + inp.x.num = static_cast(inp.x.max * 2 / 100); + inp.y.min = -2750; + inp.y.max = 2750; + inp.y.num = static_cast(inp.y.max * 2 / 100); + inp.z.min = -6350; + inp.z.max = 6350; + inp.z.num = static_cast(inp.z.max * 2 / 100); Array const dims{ - inp.num_x, inp.num_y, inp.num_z, static_cast(Axis::size_)}; - size_type const total_points = inp.num_x * inp.num_y * inp.num_z; + inp.x.num, inp.y.num, inp.z.num, static_cast(Axis::size_)}; + size_type const total_points = inp.x.num * inp.y.num * inp.z.num; // Resize each component of the field inp.field.resize(static_cast(Axis::size_) * total_points); // Fill with a simple field pattern HyperslabIndexer const flat_index{dims}; - for (size_type x = 0; x < inp.num_x; ++x) + for (size_type x = 0; x < inp.x.num; ++x) { - for (size_type y = 0; y < inp.num_y; ++y) + for (size_type y = 0; y < inp.y.num; ++y) { - for (size_type z = 0; z < inp.num_z; ++z) + for (size_type z = 0; z < inp.z.num; ++z) { auto arr = inp.field.begin() + flat_index(x, y, z, 0); arr[static_cast(Axis::x)] = std::cos(x); @@ -335,19 +335,19 @@ TEST_F(CartMapFieldTest, all) for (size_type ix = 0; ix < nx_samples; ++ix) { - real_type x = inp.min_x - + ix * (inp.max_x - inp.min_x) / (nx_samples - 1); - x = std::min(x, inp.max_x - 1); + real_type x = inp.x.min + + ix * (inp.x.max - inp.x.min) / (nx_samples - 1); + x = std::min(x, inp.x.max - 1); for (size_type iy = 0; iy < ny_samples; ++iy) { - real_type y = inp.min_y - + iy * (inp.max_y - inp.min_y) / (ny_samples - 1); - y = std::min(y, inp.max_y - 1); + real_type y = inp.y.min + + iy * (inp.y.max - inp.y.min) / (ny_samples - 1); + y = std::min(y, inp.y.max - 1); for (size_type iz = 0; iz < nz_samples; ++iz) { - real_type z = inp.min_z - + iz * (inp.max_z - inp.min_z) / (nz_samples - 1); - z = std::min(z, inp.max_z - 1); + real_type z = inp.z.min + + iz * (inp.z.max - inp.z.min) / (nz_samples - 1); + z = std::min(z, inp.z.max - 1); Real3 field = calc_field({x, y, z}); for (real_type f : field) From db8583abcf914168c77112eed9ce5050d644a445 Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Fri, 20 Jun 2025 10:32:14 -0700 Subject: [PATCH 10/14] rename params --- src/accel/detail/MagneticFieldUtils.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/accel/detail/MagneticFieldUtils.hh b/src/accel/detail/MagneticFieldUtils.hh index aac18438a3..cab749b537 100644 --- a/src/accel/detail/MagneticFieldUtils.hh +++ b/src/accel/detail/MagneticFieldUtils.hh @@ -31,11 +31,11 @@ namespace detail * \param field_data Output parameter array to store field values (must be * pre-allocated with size equal to the product of all dims) * \param dims Grid dimensions - * \param position_calculator Callable that computes position given + * \param calc_position Callable that computes position given * grid indices. Must have signature: * Array(size_type, size_type, * size_type) returning [x, y, z, 0] coordinates - * \param field_converter Callable that converts field from G4 to + * \param convert_field Callable that converts field from G4 to * native units in the correct coordinate space. Must * have signature: void(Array const&, * real_type*) taking G4 field [Bx, By, Bz] and writing From 325e116b4d1f48d885de2f0b066314029dbd9355 Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Fri, 20 Jun 2025 10:33:05 -0700 Subject: [PATCH 11/14] use real_type --- src/accel/CartMapMagneticField.hh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/accel/CartMapMagneticField.hh b/src/accel/CartMapMagneticField.hh index 94e8c63607..ad246d14cc 100644 --- a/src/accel/CartMapMagneticField.hh +++ b/src/accel/CartMapMagneticField.hh @@ -10,6 +10,7 @@ #include #include "corecel/Macros.hh" +#include "corecel/Types.hh" #include "celeritas/field/CartMapFieldInput.hh" #include "celeritas/field/CartMapFieldParams.hh" @@ -19,9 +20,9 @@ namespace celeritas //! POD struct for CartMap field grid parameters struct CartMapFieldGridParams { - AxisGrid x{}; //!< X-axis grid specification - AxisGrid y{}; //!< Y-axis grid specification - AxisGrid z{}; //!< Z-axis grid specification + AxisGrid x{}; //!< X-axis grid specification + AxisGrid y{}; //!< Y-axis grid specification + AxisGrid z{}; //!< Z-axis grid specification //! Check if parameters are valid for field generation explicit operator bool() const { return x && y && z; } From 3e4e11abdc9ca0ae4c6ecfa8056b223df49c0062 Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Fri, 20 Jun 2025 13:47:19 -0700 Subject: [PATCH 12/14] implement feedback --- src/accel/CartMapMagneticField.hh | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/accel/CartMapMagneticField.hh b/src/accel/CartMapMagneticField.hh index ad246d14cc..99dadcac14 100644 --- a/src/accel/CartMapMagneticField.hh +++ b/src/accel/CartMapMagneticField.hh @@ -45,6 +45,13 @@ class CartMapMagneticField : public G4MagneticField using SPConstFieldParams = std::shared_ptr; //!@} + public: + // Construct with CartMapFieldParams + explicit CartMapMagneticField(SPConstFieldParams field_params); + + // Calculate values of the magnetic field vector + void GetFieldValue(G4double const point[3], G4double* field) const override; + private: // Forward declaration for pImpl struct Impl; @@ -54,21 +61,6 @@ class CartMapMagneticField : public G4MagneticField { void operator()(Impl* ptr) const; }; - - public: - // Construct with CartMapFieldParams - explicit CartMapMagneticField(SPConstFieldParams field_params); - - // Default move semantics work with custom deleter - CELER_DEFAULT_MOVE_DELETE_COPY(CartMapMagneticField); - - // Destructor - ~CartMapMagneticField() override = default; - - // Calculate values of the magnetic field vector - void GetFieldValue(G4double const point[3], G4double* field) const override; - - private: std::unique_ptr pimpl_; }; From 10149636a248971c97601779aeeece243011c69a Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Fri, 20 Jun 2025 13:47:51 -0700 Subject: [PATCH 13/14] header --- src/accel/CartMapMagneticField.hh | 1 - 1 file changed, 1 deletion(-) diff --git a/src/accel/CartMapMagneticField.hh b/src/accel/CartMapMagneticField.hh index 99dadcac14..46689a798b 100644 --- a/src/accel/CartMapMagneticField.hh +++ b/src/accel/CartMapMagneticField.hh @@ -9,7 +9,6 @@ #include #include -#include "corecel/Macros.hh" #include "corecel/Types.hh" #include "celeritas/field/CartMapFieldInput.hh" #include "celeritas/field/CartMapFieldParams.hh" From 53017599a60ce8093e91d0f8f2dc7eacb1430b02 Mon Sep 17 00:00:00 2001 From: Julien Esseiva Date: Fri, 20 Jun 2025 16:01:02 -0700 Subject: [PATCH 14/14] cleanup --- src/accel/CartMapMagneticField.hh | 1 - 1 file changed, 1 deletion(-) diff --git a/src/accel/CartMapMagneticField.hh b/src/accel/CartMapMagneticField.hh index 46689a798b..3eaaa04516 100644 --- a/src/accel/CartMapMagneticField.hh +++ b/src/accel/CartMapMagneticField.hh @@ -44,7 +44,6 @@ class CartMapMagneticField : public G4MagneticField using SPConstFieldParams = std::shared_ptr; //!@} - public: // Construct with CartMapFieldParams explicit CartMapMagneticField(SPConstFieldParams field_params);