diff --git a/CMakeLists.txt b/CMakeLists.txt index c97bd9a650d1e8a89da75f210eafc82cf3e30c38..0fd76aaa1064d7fe630c71c4fb42860c746689c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ ############################################################################### cmake_minimum_required(VERSION 3.14 FATAL_ERROR) -project(Detector VERSION 1.30) +project(Detector VERSION 1.31) set(CMAKE_EXPORT_COMPILE_COMMANDS "ON") add_definitions(${GCC_COVERAGE_COMPILE_FLAGS}) @@ -99,6 +99,7 @@ add_library(DetectorLib SHARED Detector/LHCb/src/DeLHCbHandles.cpp Detector/LHCb/src/InteractionRegion.cpp Detector/LHCb/src/Tell40Links.cpp + Detector/LHCb/src/LHCInfo.cpp Detector/Rich/src/DeRich.cpp Detector/Rich/src/DeRichRadiator.cpp Detector/Rich/src/DeRichMapmt.cpp diff --git a/Core/tests/CMakeLists.txt b/Core/tests/CMakeLists.txt index d116c353a1d970fdd5c858338c288d19ce0ba8dd..3b3a14f58704aa6ac3548430a22122c2b5bebba9 100644 --- a/Core/tests/CMakeLists.txt +++ b/Core/tests/CMakeLists.txt @@ -28,6 +28,7 @@ add_executable(test_DDS src/test_DDS_limit_IOV.cpp src/test_DDS_tell40links.cpp src/test_DDS_interactionregion.cpp + src/test_DDS_lhcinfo.cpp src/test_conddb_schema_handling.cpp src/test_condition_git_reader.cpp ) diff --git a/Core/tests/src/test_DDS_lhcinfo.cpp b/Core/tests/src/test_DDS_lhcinfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65d24768a6aeb68e44fa62b1d11e39745bf8e272 --- /dev/null +++ b/Core/tests/src/test_DDS_lhcinfo.cpp @@ -0,0 +1,70 @@ +/*****************************************************************************\ +* (c) Copyright 2024 CERN for the benefit of the LHCb Collaboration * +* * +* This software is distributed under the terms of the GNU General Public * +* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * +* * +* In applying this licence, CERN does not waive the privileges and immunities * +* granted to it by virtue of its status as an Intergovernmental Organization * +* or submit itself to any jurisdiction. * +\*****************************************************************************/ +#include <Core/DetectorDataService.h> +#include <Core/Keys.h> +#include <DD4hep/Detector.h> +#include <Detector/LHCb/DeLHCb.h> +#include <Detector/Test/Fixture.h> +#include <cstdio> + +#include <catch2/catch.hpp> + +TEST_CASE( "LHCCondition loading" ) { + namespace fs = std::filesystem; + using Catch::Matchers::Contains; + + Detector::Test::Fixture f; + + auto& description = f.description(); + + description.fromXML( "compact/run3/trunk/LHCb.xml" ); + + REQUIRE( description.state() == dd4hep::Detector::READY ); + + auto det = description.detector( "/world" ); + // the `!!` is needed because handles have `operator!` but not `operator bool` + REQUIRE( !!det ); + + LHCb::Detector::DetectorDataService dds( description, {"/world"} ); + dds.initialize( nlohmann::json( {{"repository", "file:tests/ConditionsIOV"}} ) ); + + { + // get a condition slice where the condition exists + // - we should get the values from the condition + + auto slice = dds.get_slice( 200 ); + REQUIRE( slice ); + + LHCb::Detector::DeLHCb lhcb = slice->get( det, LHCb::Detector::Keys::deKey ); + REQUIRE( !!lhcb ); + + auto lhcinfo = lhcb.lhcInfo(); + REQUIRE( lhcinfo.has_value() ); + + CHECK( lhcinfo.value().fillnumber == 7974 ); + CHECK( lhcinfo.value().lhcstate == "INJECTION" ); + CHECK( lhcinfo.value().lhcenergy == 450 ); + CHECK( abs( lhcinfo.value().lhcbclockphase - 0.46556840909089 ) < 1e-6 ); + } + + { + // get a condition slice where the condition doesn't exist + // - we should get the fallback values + auto slice = dds.get_slice( 0 ); + REQUIRE( slice ); + + LHCb::Detector::DeLHCb lhcb = slice->get( det, LHCb::Detector::Keys::deKey ); + REQUIRE( !!lhcb ); + + auto lhcinfo = lhcb.lhcInfo(); + REQUIRE( !lhcinfo.has_value() ); + } +} diff --git a/Detector/LHCb/include/Detector/LHCb/DeLHCb.h b/Detector/LHCb/include/Detector/LHCb/DeLHCb.h index e942f3ebff31a198d6521e29c635a261bfb1ca1e..0d99ece88d2fec5daf4c5607a064b5e2cb65e48c 100644 --- a/Detector/LHCb/include/Detector/LHCb/DeLHCb.h +++ b/Detector/LHCb/include/Detector/LHCb/DeLHCb.h @@ -14,6 +14,7 @@ #include <Core/DeIOV.h> #include <Core/Keys.h> #include <Detector/LHCb/InteractionRegion.h> +#include <Detector/LHCb/LHCInfo.h> #include <Detector/LHCb/Tell40Links.h> #include <fmt/core.h> @@ -31,6 +32,7 @@ namespace LHCb::Detector { std::vector<DeIOV> children; Tell40Links m_tell40links; std::optional<InteractionRegion> m_interactionRegion; + std::optional<LHCInfo> m_lhcinfo; }; // Utility method to lookup DeIOV object from the condition slice @@ -46,6 +48,7 @@ namespace LHCb::Detector { /// Provide the position, spread, and tilt of the interaction region std::optional<InteractionRegion> interactionRegion() const { return this->access()->m_interactionRegion; } + std::optional<LHCInfo> lhcInfo() const { return this->access()->m_lhcinfo; } }; // Utility method to setup DeLHCb diff --git a/Detector/LHCb/include/Detector/LHCb/LHCInfo.h b/Detector/LHCb/include/Detector/LHCb/LHCInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..d432bd810223eb416623fad41a91a0dd2e2f53ba --- /dev/null +++ b/Detector/LHCb/include/Detector/LHCb/LHCInfo.h @@ -0,0 +1,29 @@ +/*****************************************************************************\ +* (c) Copyright 2023 CERN for the benefit of the LHCb Collaboration * +* * +* This software is distributed under the terms of the GNU General Public * +* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * +* * +* In applying this licence, CERN does not waive the privileges and immunities * +* granted to it by virtue of its status as an Intergovernmental Organization * +* or submit itself to any jurisdiction. * +\*****************************************************************************/ +#pragma once + +#include <nlohmann/json_fwd.hpp> + +namespace LHCb::Detector { + struct LHCInfo { + + LHCInfo() = default; + LHCInfo( const nlohmann::json& obj ); + + unsigned int fillnumber{}; + std::string lhcstate{}; + int lhcenergy{}; + float lhcbclockphase{}; + float xangleh{}; + float xanglev{}; + std::string beamtype{}; + }; +} // namespace LHCb::Detector diff --git a/Detector/LHCb/src/DeLHCb.cpp b/Detector/LHCb/src/DeLHCb.cpp index a17b7fa8333e76d6dc21cd57e1b85506b1720860..a8531146aeb2ac67f44432dc36496933c5a4e5a7 100644 --- a/Detector/LHCb/src/DeLHCb.cpp +++ b/Detector/LHCb/src/DeLHCb.cpp @@ -21,7 +21,6 @@ LHCb::Detector::detail::DeLHCbObject::DeLHCbObject( const dd4hep::DetElement& de, dd4hep::cond::ConditionUpdateContext& ctxt ) : DeIOVObject( de, ctxt, 9000000, false ) { - { auto cond = ctxt.condition( hash_key( de, "Tell40Links" ), false ); if ( cond.isValid() ) { @@ -36,6 +35,13 @@ LHCb::Detector::detail::DeLHCbObject::DeLHCbObject( const dd4hep::DetElement& if ( !ir.is_null() ) { m_interactionRegion = ir; } } } + { + auto cond = ctxt.condition( hash_key( de, "LHC" ), false ); + if ( cond.isValid() ) { + auto lhcinfo = cond.get<nlohmann::json>(); + if ( !lhcinfo.is_null() ) { m_lhcinfo = lhcinfo; } + } + } } void LHCb::Detector::detail::DeLHCbObject::applyToAllChildren( @@ -124,5 +130,10 @@ void LHCb::Detector::setup_DeLHCb_callback( dd4hep::Detector& description ) { depbuilder.add( hash_key( de, "InteractionRegion" ) ); } + if ( !schema || schema->has( "Conditions/LHCb/Online/LHC.yml", "LHC" ) ) { + ( *requests )->addLocation( de, LHCb::Detector::item_key( "LHC" ), "Conditions/LHCb/Online/LHC.yml", "LHC" ); + depbuilder.add( hash_key( de, "LHC" ) ); + } + ( *requests )->addDependency( depbuilder.release() ); } diff --git a/Detector/LHCb/src/LHCInfo.cpp b/Detector/LHCb/src/LHCInfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78f4dbeacb0bac65da7ffda1767dbe5d887585af --- /dev/null +++ b/Detector/LHCb/src/LHCInfo.cpp @@ -0,0 +1,33 @@ +/*****************************************************************************\ +* (c) Copyright 2023 CERN for the benefit of the LHCb Collaboration * +* * +* This software is distributed under the terms of the GNU General Public * +* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * +* * +* In applying this licence, CERN does not waive the privileges and immunities * +* granted to it by virtue of its status as an Intergovernmental Organization * +* or submit itself to any jurisdiction. * +\*****************************************************************************/ +#include <Detector/LHCb/LHCInfo.h> + +#include <Core/Utils.h> + +#include <DD4hep/DD4hepUnits.h> +#include <DD4hep/Handle.h> + +#include <nlohmann/json.hpp> + +LHCb::Detector::LHCInfo::LHCInfo( const nlohmann::json& obj ) { + if ( !obj.contains( "FillNumber" ) || !obj.contains( "LHCState" ) || !obj.contains( "LHCEnergy" ) || + !obj.contains( "LHCbClockPhase" ) ) { + throw std::runtime_error{"LHC condition is empty"}; + } + + fillnumber = obj.at( "FillNumber" ); + lhcstate = obj.at( "LHCState" ); + lhcenergy = obj.at( "LHCEnergy" ); + lhcbclockphase = obj.at( "LHCbClockPhase" ); + if ( obj.contains( "XAngleH" ) ) xangleh = obj.at( "XAngleH" ); + if ( obj.contains( "XAngleV" ) ) xanglev = obj.at( "XAngleV" ); + if ( obj.contains( "BeamType" ) ) beamtype = obj.at( "BeamType" ); +} diff --git a/Detector/UT/include/Detector/UT/ChannelID.h b/Detector/UT/include/Detector/UT/ChannelID.h index cd18567a68cf292973cb3a2e263a1bf3bbb49321..5bf6af3dd9c9d07bb3488b456b8e2198e5bd15e4 100644 --- a/Detector/UT/include/Detector/UT/ChannelID.h +++ b/Detector/UT/include/Detector/UT/ChannelID.h @@ -24,19 +24,23 @@ namespace LHCb::Detector::UT { /// Bitmasks for UT bitfield that are different from TT/IT enum struct Mask : unsigned { - strip = 0x1ffL, - sector = 0x200L, - module = 0x1c00L, - face = 0x2000L, - stave = 0x3c000L, - layer = 0xc0000L, - side = 0x100000, - type = 0x600000, - uniquelayer = layer | side, - uniquestave = uniquelayer | stave, - uniqueface = uniquestave | face, - uniquemodule = uniqueface | module, - uniqueSector = uniquemodule | sector + strip = 0x1ffL, + asic = 0x180L, + subsector = 0x100L, + sector = 0x200L, + module = 0x1c00L, + face = 0x2000L, + stave = 0x3c000L, + layer = 0xc0000L, + side = 0x100000, + type = 0x600000, + uniquelayer = layer | side, + uniquestave = uniquelayer | stave, + uniqueface = uniquestave | face, + uniquemodule = uniqueface | module, + uniquesector = uniquemodule | sector, + uniquesubsector = uniquesector | subsector, + uniqueasic = uniquesector | asic }; template <Mask m> @@ -68,10 +72,10 @@ namespace LHCb::Detector::UT { /// constructor with side, halflayer, stave, face, module, sector, strip. New style ChannelID( const unsigned int iType, const unsigned int iSide, const unsigned int iHalflayer, const unsigned int iStave, const unsigned int iFace, const unsigned int iModule, - const unsigned int iSubsector, const unsigned int iStrip ) + const unsigned int iSector, const unsigned int iStrip ) : ChannelID{shift<Mask::type>( iType ) | shift<Mask::side>( iSide ) | shift<Mask::layer>( iHalflayer ) | shift<Mask::stave>( iStave ) | shift<Mask::face>( iFace ) | shift<Mask::module>( iModule ) | - shift<Mask::sector>( iSubsector ) | shift<Mask::strip>( iStrip )} {} + shift<Mask::sector>( iSector ) | shift<Mask::strip>( iStrip )} {} /// cast constexpr operator unsigned int() const { return m_channelID; } @@ -85,6 +89,9 @@ namespace LHCb::Detector::UT { /// Retrieve sector [[nodiscard]] constexpr unsigned int sector() const { return extract<Mask::sector>( m_channelID ); } + /// Retrieve subsector + [[nodiscard]] constexpr unsigned int subSector() const { return extract<Mask::subsector>( m_channelID ); } + /// Retrieve detRegion [[nodiscard]] constexpr unsigned int detRegion() const { return stave() < 2 ? 2 : side() == 0 ? 1 : 3; } @@ -94,6 +101,24 @@ namespace LHCb::Detector::UT { /// Retrieve unique layer [[nodiscard]] constexpr unsigned int uniqueLayer() const { return extract<Mask::uniquelayer>( m_channelID ); } + /// Trim to keep until sector part + [[nodiscard]] constexpr unsigned int getFullSector() const { + unsigned int m = (unsigned int)Mask::uniquesector | (unsigned int)Mask::type; + return channelID() & m; + } + + /// Trim to keep until subsector part + [[nodiscard]] constexpr unsigned int getFullSubSector() const { + unsigned int m = (unsigned int)Mask::uniquesubsector | (unsigned int)Mask::type; + return channelID() & m; + } + + /// Trim to keep until asic part + [[nodiscard]] constexpr unsigned int getFullAsic() const { + unsigned int m = (unsigned int)Mask::uniqueasic | (unsigned int)Mask::type; + return channelID() & m; + } + /// Print method for python NOT NEEDED + SLOW IN C++ use operator<< [[nodiscard]] std::string toString() const; @@ -109,11 +134,22 @@ namespace LHCb::Detector::UT { /// Retrieve strip [[nodiscard]] constexpr unsigned int strip() const { return extract<Mask::strip>( m_channelID ); } + /// Retrive asic + [[nodiscard]] constexpr unsigned int asic() const { return extract<Mask::asic>( m_channelID ); } + /// Retrieve station [[nodiscard]] constexpr unsigned int station() const { return ( this->layer() / 2 + 1u ); } /// Retrieve unique sector - [[nodiscard]] constexpr unsigned int uniqueSector() const { return extract<Mask::uniqueSector>( m_channelID ); } + [[nodiscard]] constexpr unsigned int uniqueSector() const { return extract<Mask::uniquesector>( m_channelID ); } + + /// Retrieve unique sub sector + [[nodiscard]] constexpr unsigned int uniqueSubSector() const { + return extract<Mask::uniquesubsector>( m_channelID ); + } + + /// Retrieve unique asic + [[nodiscard]] constexpr unsigned int uniqueAsic() const { return extract<Mask::uniqueasic>( m_channelID ); } /// Retrieve side [[nodiscard]] constexpr unsigned int side() const { return extract<Mask::side>( m_channelID ); } diff --git a/Detector/UT/src/DeUT.cpp b/Detector/UT/src/DeUT.cpp index a43c7ca1c6ec22b185103ad5a2c6bbb791e64cc4..9fecde2d28b1a581602850d0a82ae9409be05002 100644 --- a/Detector/UT/src/DeUT.cpp +++ b/Detector/UT/src/DeUT.cpp @@ -197,7 +197,7 @@ LHCb::Detector::UT::detail::DeUTModuleObject::DeUTModuleObject( const dd4hep::De 0, 0} { // type of stave - auto staveVolName = de.parent().parent().volume().name(); + auto staveVolName = de.parent().parent().volume().name(); // lvStaveA/B/C m_type = std::string( staveVolName + 8, staveVolName + std::strlen( staveVolName ) ); // flatten for ( auto& group : de.children() ) @@ -327,17 +327,11 @@ LHCb::Detector::UT::detail::DeUTSensorObject::DeUTSensorObject( const dd4hep::De // UTSensorObject actually for half sensors for TypeBCD // get pitch size - auto nameString = de.placement().volume().name(); - std::string m_type( nameString + 8, nameString + std::strlen( nameString ) ); - if ( m_type == "Norm" ) { - m_pitch = dd4hep::_toDouble( "UTSensorAPitch" ); - m_sensorType = 'A'; - } else { - m_pitch = dd4hep::_toDouble( "UTSensorBCDPitch" ); - if ( m_type == "Dual" ) m_sensorType = 'B'; - if ( m_type == "Quad" ) m_sensorType = 'C'; - if ( m_type == "Hole" ) m_sensorType = 'D'; - } + auto logVolName = de.placement().volume().name(); + auto moduleLogVolName = de.parent().parent().parent().placement().volume().name(); + std::string m_type( logVolName + 8, logVolName + std::strlen( logVolName ) ); // lvSensor(Norm|Dual|Quad|Hole) + m_sensorType = moduleLogVolName[std::strlen( moduleLogVolName ) - 1]; // lvModule(A|B|C|D) + m_pitch = m_type == "Norm" ? dd4hep::_toDouble( "UTSensorAPitch" ) : dd4hep::_toDouble( "UTSensorBCDPitch" ); m_uMaxLocal = 0.5f * ( m_pitch * m_nStrip ); m_uMinLocal = -m_uMaxLocal; diff --git a/ReleaseNotes/v1r31.md b/ReleaseNotes/v1r31.md new file mode 100644 index 0000000000000000000000000000000000000000..5a9f9bbf9f822622f8051cb3dcef0e4daf4d053a --- /dev/null +++ b/ReleaseNotes/v1r31.md @@ -0,0 +1,11 @@ +2024-04-19 Detector v1r31 +=== + +This version uses LCG [105a](http://lcginfo.cern.ch/release/105a/) with ROOT 6.30.04. + +This version is released on the `2024-patches` branch. +Built relative to Detector [v1r30](/../../tags/v1r30), with the following changes: + +- Cherry-pick the changes in checksum at master branch, !540 (@mexu) +- Merge branch 'protect-against-missing-0-cond' into 'master', !538 (@cagapopo) +- Access to LHC condition information, !418 (@tfulghes) diff --git a/tests/ConditionsIOV/.schema.json b/tests/ConditionsIOV/.schema.json index ccc777d2c6af994c3646cd981fcb52fb984b5714..610e08c52c11a47bc51c5d743333cf0903f6ea25 100644 --- a/tests/ConditionsIOV/.schema.json +++ b/tests/ConditionsIOV/.schema.json @@ -1391,6 +1391,9 @@ "Conditions/LHCb/Online/InteractionRegion.yml": [ "InteractionRegion" ], + "Conditions/LHCb/Online/LHC.yml": [ + "LHC" + ], "Conditions/LHCb/Online/Magnet.yml": [ "Magnet" ], diff --git a/tests/ConditionsIOV/Conditions/LHCb/Online/LHC.yml/.condition b/tests/ConditionsIOV/Conditions/LHCb/Online/LHC.yml/.condition new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/ConditionsIOV/Conditions/LHCb/Online/LHC.yml/0 b/tests/ConditionsIOV/Conditions/LHCb/Online/LHC.yml/0 new file mode 100644 index 0000000000000000000000000000000000000000..b7721432b12a66ddabaa9ce930225346ae9103a9 --- /dev/null +++ b/tests/ConditionsIOV/Conditions/LHCb/Online/LHC.yml/0 @@ -0,0 +1,3 @@ +# Special case of empty condition +--- +LHC: diff --git a/tests/ConditionsIOV/Conditions/LHCb/Online/LHC.yml/200 b/tests/ConditionsIOV/Conditions/LHCb/Online/LHC.yml/200 new file mode 100644 index 0000000000000000000000000000000000000000..ca461d4b2545dde5d85f10e31626d9504f7345f0 --- /dev/null +++ b/tests/ConditionsIOV/Conditions/LHCb/Online/LHC.yml/200 @@ -0,0 +1,14 @@ +# Example of LHC condition +# ``` +# LHCCondition: +# fillnumber: [int] +# lhcbstate: [string] +# lhcbenergy: [int] +# lhcbclockphase: [float] +# ``` +--- +LHC: + FillNumber: 7974 + LHCState: INJECTION + LHCEnergy: 450 + LHCbClockPhase: 0.46556840909089