From ff72bd664e8ecbf37f79bbbc129357143cbbffba Mon Sep 17 00:00:00 2001 From: Arthur Hennequin Date: Wed, 2 Apr 2025 16:29:39 +0200 Subject: [PATCH 1/8] Load cached binary magnetic field if it exists --- Core/include/Core/MagneticFieldGridReader.h | 1 + Core/src/MagneticFieldGridReader.cpp | 80 +++++++++++++++------ 2 files changed, 60 insertions(+), 21 deletions(-) diff --git a/Core/include/Core/MagneticFieldGridReader.h b/Core/include/Core/MagneticFieldGridReader.h index deae5b221f..389ff9ea3b 100644 --- a/Core/include/Core/MagneticFieldGridReader.h +++ b/Core/include/Core/MagneticFieldGridReader.h @@ -43,6 +43,7 @@ namespace LHCb::Magnet { private: void fillGridFromQuadrants( GridQuadrants& quadrants, MagneticFieldGrid& grid ) const; bool readQuadrant( const std::string& filename, GridQuadrant& quad ) const; + bool readFromBinFile( const std::string& filename, MagneticFieldGrid& grid ) const; private: std::string m_mapFilePath = ""; diff --git a/Core/src/MagneticFieldGridReader.cpp b/Core/src/MagneticFieldGridReader.cpp index 30d5ed0748..7f60c7a87f 100644 --- a/Core/src/MagneticFieldGridReader.cpp +++ b/Core/src/MagneticFieldGridReader.cpp @@ -14,11 +14,14 @@ #include "DD4hep/DD4hepUnits.h" #include "DD4hep/Printout.h" #include "Math/Vector3D.h" +#include #include #include #include +#include #include #include +#include #include #include #include @@ -85,31 +88,66 @@ namespace { // Read the field map files and scale by scaleFactor //============================================================================= -bool LHCb::Magnet::MagneticFieldGridReader::readFiles( const std::vector& filenames, - LHCb::Magnet::MagneticFieldGrid& grid ) const { +bool LHCb::Magnet::MagneticFieldGridReader::readFromBinFile( const std::string& filename, + LHCb::Magnet::MagneticFieldGrid& grid ) const { + // Check if a cached binary file exists + std::filesystem::path path{ m_mapFilePath + "/" + filename }; + path.replace_extension( "bin" ); + + std::ifstream file; + file.open( path, std::ios::binary | std::ios::in ); + if ( !file ) return false; + dd4hep::printout( dd4hep::INFO, "MagneticFieldGridReader", "Opened magnetic field file: %s", path.c_str() ); + + file.read( (char*)grid.m_invDxyz.data(), sizeof( std::array ) ); + file.read( (char*)grid.m_Nxyz.data(), sizeof( std::array ) ); + file.read( (char*)grid.m_min.data(), sizeof( std::array ) ); + std::size_t N = grid.m_Nxyz[0] * grid.m_Nxyz[1] * grid.m_Nxyz[2]; + grid.m_B.resize( N, { 0, 0, 0, 0 } ); + file.read( (char*)grid.m_B.data(), sizeof( std::array ) * N ); + file.close(); - GridQuadrants quadrants; - assert( filenames.size() == quadrants.size() ); + dd4hep::printout( dd4hep::DEBUG, "MagneticFieldGridReader", "Field grid , nbins x,y,z : (%d, %d, %d)", + grid.m_Nxyz[0], grid.m_Nxyz[1], grid.m_Nxyz[2] ); + dd4hep::printout( dd4hep::DEBUG, "MagneticFieldGridReader", "dx, xmin, xmax: (%f, %f, %f)", 1.f / grid.m_invDxyz[0], + grid.m_min[0], grid.m_min[0] + ( grid.m_Nxyz[0] - 1 ) / grid.m_invDxyz[0] ); + dd4hep::printout( dd4hep::DEBUG, "MagneticFieldGridReader", "dy, ymin, ymax: (%f, %f, %f)", 1.f / grid.m_invDxyz[1], + grid.m_min[1], grid.m_min[1] + ( grid.m_Nxyz[1] - 1 ) / grid.m_invDxyz[1] ); + dd4hep::printout( dd4hep::DEBUG, "MagneticFieldGridReader", "dz, zmin, zmax: (%f, %f, %f)", 1.f / grid.m_invDxyz[2], + grid.m_min[2], grid.m_min[2] + ( grid.m_Nxyz[2] - 1 ) / grid.m_invDxyz[2] ); + return true; +} - bool sc = true; - for ( std::size_t iquad = 0; iquad < quadrants.size() && sc; ++iquad ) { - sc = readQuadrant( filenames[iquad], quadrants[iquad] ); - } +bool LHCb::Magnet::MagneticFieldGridReader::readFiles( const std::vector& filenames, + LHCb::Magnet::MagneticFieldGrid& grid ) const { + TTimeStamp start; + bool sc = readFromBinFile( filenames[0], grid ); + if ( !sc ) { + GridQuadrants quadrants; + assert( filenames.size() == quadrants.size() ); + + sc = true; + for ( std::size_t iquad = 0; iquad < quadrants.size() && sc; ++iquad ) { + sc = readQuadrant( filenames[iquad], quadrants[iquad] ); + } - if ( sc ) { - // check that the quadrants are consistent - for ( std::size_t iquad = 1; iquad < quadrants.size(); ++iquad ) { - assert( essentiallyEqual( quadrants[0].zOffset, quadrants[iquad].zOffset ) ); - for ( std::size_t icoord = 0; icoord < quadrants[0].Dxyz.size(); ++icoord ) { - assert( essentiallyEqual( quadrants[0].Dxyz[icoord], quadrants[iquad].Dxyz[icoord] ) ); - assert( quadrants[0].Nxyz[icoord] == quadrants[iquad].Nxyz[icoord] ); + if ( sc ) { + // check that the quadrants are consistent + for ( std::size_t iquad = 1; iquad < quadrants.size(); ++iquad ) { + assert( essentiallyEqual( quadrants[0].zOffset, quadrants[iquad].zOffset ) ); + for ( std::size_t icoord = 0; icoord < quadrants[0].Dxyz.size(); ++icoord ) { + assert( essentiallyEqual( quadrants[0].Dxyz[icoord], quadrants[iquad].Dxyz[icoord] ) ); + assert( quadrants[0].Nxyz[icoord] == quadrants[iquad].Nxyz[icoord] ); + } } - } - // now fill the grid - fillGridFromQuadrants( quadrants, grid ); + // now fill the grid + fillGridFromQuadrants( quadrants, grid ); + } } - + TTimeStamp stop; + dd4hep::printout( dd4hep::INFO, "MagneticFieldGridReader", "+ Loaded 4 quadrants in %7.5fs", + stop.AsDouble() - start.AsDouble() ); return sc; } @@ -201,9 +239,9 @@ void LHCb::Magnet::MagneticFieldGridReader::fillGridFromQuadrants( GridQuadrants grid.m_Nxyz[0], grid.m_Nxyz[1], grid.m_Nxyz[2] ); dd4hep::printout( dd4hep::DEBUG, "MagneticFieldGridReader", "dx, xmin, xmax: (%f, %f, %f)", Dxyz[0], grid.m_min[0], grid.m_min[0] + ( grid.m_Nxyz[0] - 1 ) * Dxyz[0] ); - dd4hep::printout( dd4hep::DEBUG, "MagneticFieldGridReader", "dy, ymin, ymax: (%f, %f, %f)", Dxyz[0], grid.m_min[1], + dd4hep::printout( dd4hep::DEBUG, "MagneticFieldGridReader", "dy, ymin, ymax: (%f, %f, %f)", Dxyz[1], grid.m_min[1], grid.m_min[1] + ( grid.m_Nxyz[1] - 1 ) * Dxyz[1] ); - dd4hep::printout( dd4hep::DEBUG, "MagneticFieldGridReader", "dz, zmin, zmax: (%f, %f, %f)", Dxyz[0], grid.m_min[2], + dd4hep::printout( dd4hep::DEBUG, "MagneticFieldGridReader", "dz, zmin, zmax: (%f, %f, %f)", Dxyz[2], grid.m_min[2], grid.m_min[2] + ( grid.m_Nxyz[2] - 1 ) * Dxyz[2] ); } -- GitLab From 905015a19384454271089a4df0ae3fe803d3c24f Mon Sep 17 00:00:00 2001 From: Arthur Hennequin Date: Thu, 3 Apr 2025 11:07:42 +0200 Subject: [PATCH 2/8] Add test to compare binary and cdf loading --- Core/include/Core/MagneticFieldGridReader.h | 2 +- Core/src/MagneticFieldGridReader.cpp | 4 +- Core/tests/CMakeLists.txt | 3 + Core/tests/src/test_magnet.cpp | 97 +++++++++++++++++++++ 4 files changed, 103 insertions(+), 3 deletions(-) diff --git a/Core/include/Core/MagneticFieldGridReader.h b/Core/include/Core/MagneticFieldGridReader.h index 389ff9ea3b..9dd375deef 100644 --- a/Core/include/Core/MagneticFieldGridReader.h +++ b/Core/include/Core/MagneticFieldGridReader.h @@ -24,7 +24,7 @@ namespace LHCb::Magnet { public: MagneticFieldGridReader( std::string field_map_path ) : m_mapFilePath{ std::move( field_map_path ) } {} - bool readFiles( const std::vector& filenames, MagneticFieldGrid& grid ) const; + bool readFiles( const std::vector& filenames, MagneticFieldGrid& grid, bool force_cdf = false ) const; bool readDC06File( const std::string& filename, MagneticFieldGrid& grid ) const; diff --git a/Core/src/MagneticFieldGridReader.cpp b/Core/src/MagneticFieldGridReader.cpp index 7f60c7a87f..7cfa424116 100644 --- a/Core/src/MagneticFieldGridReader.cpp +++ b/Core/src/MagneticFieldGridReader.cpp @@ -119,9 +119,9 @@ bool LHCb::Magnet::MagneticFieldGridReader::readFromBinFile( const std::string& } bool LHCb::Magnet::MagneticFieldGridReader::readFiles( const std::vector& filenames, - LHCb::Magnet::MagneticFieldGrid& grid ) const { + LHCb::Magnet::MagneticFieldGrid& grid, bool force_cdf ) const { TTimeStamp start; - bool sc = readFromBinFile( filenames[0], grid ); + bool sc = !force_cdf && readFromBinFile( filenames[0], grid ); if ( !sc ) { GridQuadrants quadrants; assert( filenames.size() == quadrants.size() ); diff --git a/Core/tests/CMakeLists.txt b/Core/tests/CMakeLists.txt index d7ad93831c..2ad0ac013e 100644 --- a/Core/tests/CMakeLists.txt +++ b/Core/tests/CMakeLists.txt @@ -126,6 +126,9 @@ add_test(NAME test_Magnet_load_condition add_test(NAME test_Magnet_load_field COMMAND ${TEST_SCRIPT} -input ${PROJECT_SOURCE_DIR}/compact/run3/trunk/LHCb.xml -plugin LHCb_TEST_Magnet_load_field -conditions -fieldmappath) +add_test(NAME test_Magnet_load_field_bin + COMMAND ${TEST_SCRIPT} -input ${PROJECT_SOURCE_DIR}/compact/run3/trunk/LHCb.xml -plugin LHCb_TEST_Magnet_load_field_bin -conditions -fieldmappath) + add_test(NAME test_Magnet_load_demagnet COMMAND ${TEST_SCRIPT} -input ${PROJECT_SOURCE_DIR}/compact/run3/trunk/LHCb.xml -plugin LHCb_TEST_Magnet_load_demagnet -conditions -fieldmappath) diff --git a/Core/tests/src/test_magnet.cpp b/Core/tests/src/test_magnet.cpp index 8428fc015d..ff51b93fed 100644 --- a/Core/tests/src/test_magnet.cpp +++ b/Core/tests/src/test_magnet.cpp @@ -165,6 +165,103 @@ static long test_magnet_load_field( dd4hep::Detector& description, int argc, cha } DECLARE_APPLY( LHCb_TEST_Magnet_load_field, test_magnet_load_field ) +static long test_magnet_load_field_bin( dd4hep::Detector& description, int argc, char** argv ) { + + // XXX Boiler plate for the plugin, to be improved/factorized + bool help = false; + std::string conditions; + std::string field_map_path = ""; + for ( int i = 0; i < argc && argv[i]; ++i ) { + if ( argv[i][0] == '-' || argv[i][0] == '/' ) { + if ( 0 == ::strncmp( "-help", argv[i], 4 ) ) + help = true; + else if ( 0 == ::strncmp( "-conditions", argv[i], 11 ) ) + conditions = argv[++i]; + else if ( 0 == ::strncmp( "-fieldmappath", argv[i], 13 ) ) { + field_map_path = argv[++i]; + } else + help = true; + } + } + if ( help || conditions.empty() ) { + /// Help printout describing the basic command line interface + std::cout << "Usage: -plugin -arg [-arg] \n" + " name: factory name LHCb_TEST_Magnet \n" + " -detector Name of the sub-detector to analyze. \n" + " -conditions Top-directory with conditions files. \n" + " -fieldmappath Directory containing the filed map files. \n" + " Fully qualified: :// \n" + " -help Show this help. \n" + "\tArguments given: " + << dd4hep::arguments( argc, argv ) << std::endl; + ::exit( EINVAL ); + } + + // Loading the detector and retrieving the condition with the file names for the Magnetic field service + LHCb::Magnet::setup_magnetic_field_extension( description, field_map_path ); + std::vector detector_list{ "/world", "Magnet" }; + LHCb::Detector::DetectorDataService dds( description, detector_list ); + dds.initialize( nlohmann::json{ { "repository", conditions } } ); + + int slice1_id = 100; + auto slice = dds.get_slice( slice1_id ); + dd4hep::DetElement magnetdet = description.detector( "Magnet" ); + // const LHCb::Detector::DeMagnet& magnet = slice->get( magnetdet, LHCb::Detector::Keys::deKey ); + + using nlohmann::json; + + // Loading the FieldMap file + const auto& cond = slice->get( magnetdet, LHCb::Detector::item_key( "FieldMapFilesDown" ) ).get(); + const auto& values = cond["Files"]; + for ( std::size_t i = 0; i < values.size(); i++ ) { + dd4hep::printout( dd4hep::INFO, "test_Magnet", "values[%d]: %s", i, values[i].get().c_str() ); + } + const auto filenames = values.get>(); + + // Loading the current value + const auto& online_cond = slice->get( magnetdet, LHCb::Detector::item_key( "Magnet" ) ).get(); + dd4hep::printout( dd4hep::INFO, "test_Magnet", "Current value: %f", online_cond["Current"].get() ); + + // Now that we have the filenames, load the field itself + LHCb::Magnet::MagneticFieldGridReader reader{ field_map_path }; + LHCb::Magnet::MagneticFieldGrid fieldgrid_cdf, fieldgrid_bin; + if ( filenames.size() == 1 ) { + dd4hep::printout( dd4hep::ERROR, "test_magnet", "Field should be in cdf format" ); + ::exit( EINVAL ); + } + const auto sc = reader.readFiles( filenames, fieldgrid_bin ) && reader.readFiles( filenames, fieldgrid_cdf, true ); + + if ( !sc ) { + dd4hep::printout( dd4hep::ERROR, "test_magnet", "Error loading magnetic field map" ); + ::exit( EINVAL ); + } + + double maxdiff = 1e-5; + auto check = [&maxdiff]( double val, double ref, std::string name ) { + if ( std::abs( ( val - ref ) / val ) > maxdiff ) { + dd4hep::printout( dd4hep::ERROR, "test_magnet", "Error with %s", name.c_str() ); + ::exit( EINVAL ); + } + }; + + for ( double z = -500.0; z <= 14000.0; z += 1000.0 ) { + for ( double y = -4000.0; y <= 4000.0; y += 1000.0 ) { + for ( double x = -4000.0; x <= 4000.0; x += 1000.0 ) { + const auto f1 = fieldgrid_bin.fieldVectorLinearInterpolation( ROOT::Math::XYZPoint{ x, y, z } ); + const auto f2 = fieldgrid_cdf.fieldVectorLinearInterpolation( ROOT::Math::XYZPoint{ x, y, z } ); + check( f1.X(), f2.X(), "field map X component" ); + check( f1.Y(), f2.Y(), "field map Y component" ); + check( f1.Z(), f2.Z(), "field map Z component" ); + } + } + } + + // Finalizing the service and returning + dds.finalize(); + return 1; // Plugins return 1 when they are successful +} +DECLARE_APPLY( LHCb_TEST_Magnet_load_field_bin, test_magnet_load_field_bin ) + static long test_magnet_load_demagnet( dd4hep::Detector& description, int argc, char** argv ) { // XXX Boiler plate for the plugin, to be improved/factorized -- GitLab From 0a73c3605787713ee22c98b0d49a071497685f53 Mon Sep 17 00:00:00 2001 From: Arthur Hennequin Date: Thu, 3 Apr 2025 13:09:41 +0200 Subject: [PATCH 3/8] Add accessors to magfield raw data --- Core/include/Core/MagneticFieldGrid.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Core/include/Core/MagneticFieldGrid.h b/Core/include/Core/MagneticFieldGrid.h index 0c7a2b4835..c20bc8e7c6 100644 --- a/Core/include/Core/MagneticFieldGrid.h +++ b/Core/include/Core/MagneticFieldGrid.h @@ -56,6 +56,14 @@ namespace LHCb::Magnet { /// Update the scale factor void setScaleFactor( const float s ) { m_scaleFactor = { s, s, s, 0 }; } + const float* rawField() const { return reinterpret_cast( m_B.data() ); } + + auto invDXYZ() const { return m_invDxyz; } + + auto minXYZ() const { return m_min; } + + auto sizeXYZ() const { return m_Nxyz; } + public: using IndexType = std::int32_t; -- GitLab From a656ce292eb6abd98396d4ebde1bb5de8ef63048 Mon Sep 17 00:00:00 2001 From: Arthur Hennequin Date: Tue, 20 May 2025 16:05:59 +0200 Subject: [PATCH 4/8] Fix cast issue --- Core/include/Core/MagneticFieldGrid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/include/Core/MagneticFieldGrid.h b/Core/include/Core/MagneticFieldGrid.h index c20bc8e7c6..8cab32eea7 100644 --- a/Core/include/Core/MagneticFieldGrid.h +++ b/Core/include/Core/MagneticFieldGrid.h @@ -56,7 +56,7 @@ namespace LHCb::Magnet { /// Update the scale factor void setScaleFactor( const float s ) { m_scaleFactor = { s, s, s, 0 }; } - const float* rawField() const { return reinterpret_cast( m_B.data() ); } + const float* rawField() const { return reinterpret_cast( m_B.data() ); } auto invDXYZ() const { return m_invDxyz; } -- GitLab From 16df955d7bededd5211af8a5ffce01720994edda Mon Sep 17 00:00:00 2001 From: Arthur Hennequin Date: Tue, 20 May 2025 16:09:23 +0200 Subject: [PATCH 5/8] Remove commented code --- Core/tests/src/test_magnet.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/tests/src/test_magnet.cpp b/Core/tests/src/test_magnet.cpp index ff51b93fed..db536e9248 100644 --- a/Core/tests/src/test_magnet.cpp +++ b/Core/tests/src/test_magnet.cpp @@ -206,7 +206,6 @@ static long test_magnet_load_field_bin( dd4hep::Detector& description, int argc, int slice1_id = 100; auto slice = dds.get_slice( slice1_id ); dd4hep::DetElement magnetdet = description.detector( "Magnet" ); - // const LHCb::Detector::DeMagnet& magnet = slice->get( magnetdet, LHCb::Detector::Keys::deKey ); using nlohmann::json; -- GitLab From 49b88eaeedc2d3fd82ce28578b0a6c607321f336 Mon Sep 17 00:00:00 2001 From: Christopher Rob Jones Date: Wed, 28 May 2025 09:46:03 +0000 Subject: [PATCH 6/8] Make message DEBUG --- Core/src/MagneticFieldGridReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/MagneticFieldGridReader.cpp b/Core/src/MagneticFieldGridReader.cpp index 7cfa424116..6798b05e02 100644 --- a/Core/src/MagneticFieldGridReader.cpp +++ b/Core/src/MagneticFieldGridReader.cpp @@ -146,7 +146,7 @@ bool LHCb::Magnet::MagneticFieldGridReader::readFiles( const std::vector Date: Mon, 2 Jun 2025 09:42:31 +0200 Subject: [PATCH 7/8] Apply suggestion --- Core/src/MagneticFieldGridReader.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Core/src/MagneticFieldGridReader.cpp b/Core/src/MagneticFieldGridReader.cpp index 6798b05e02..d50b8f3b0c 100644 --- a/Core/src/MagneticFieldGridReader.cpp +++ b/Core/src/MagneticFieldGridReader.cpp @@ -15,6 +15,7 @@ #include "DD4hep/Printout.h" #include "Math/Vector3D.h" #include +#include #include #include #include @@ -91,7 +92,9 @@ namespace { bool LHCb::Magnet::MagneticFieldGridReader::readFromBinFile( const std::string& filename, LHCb::Magnet::MagneticFieldGrid& grid ) const { // Check if a cached binary file exists - std::filesystem::path path{ m_mapFilePath + "/" + filename }; + auto tmppath = m_mapFilePath + "/" + filename; + boost::replace_all( tmppath, ".c1", "" ); + std::filesystem::path path{ tmppath }; path.replace_extension( "bin" ); std::ifstream file; -- GitLab From d40a79c7679d1855c56919de636ccb59b6be0252 Mon Sep 17 00:00:00 2001 From: Arthur Hennequin Date: Mon, 2 Jun 2025 17:25:24 +0200 Subject: [PATCH 8/8] Remove unused method --- Core/include/Core/MagneticFieldGrid.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/include/Core/MagneticFieldGrid.h b/Core/include/Core/MagneticFieldGrid.h index 8cab32eea7..42c953bbb9 100644 --- a/Core/include/Core/MagneticFieldGrid.h +++ b/Core/include/Core/MagneticFieldGrid.h @@ -56,8 +56,6 @@ namespace LHCb::Magnet { /// Update the scale factor void setScaleFactor( const float s ) { m_scaleFactor = { s, s, s, 0 }; } - const float* rawField() const { return reinterpret_cast( m_B.data() ); } - auto invDXYZ() const { return m_invDxyz; } auto minXYZ() const { return m_min; } -- GitLab