diff --git a/macro/geometry/CMakeLists.txt b/macro/geometry/CMakeLists.txt index c9ac2f44e92bb86af308ae7afcadd541a75f39df..5a8c146dfb305fca0aee66c339b0e5b40616466e 100644 --- a/macro/geometry/CMakeLists.txt +++ b/macro/geometry/CMakeLists.txt @@ -62,6 +62,22 @@ foreach(setup IN LISTS setup_files) endforeach(setup IN LISTS setup_files) # ============================================================================ +# Example of usage to check overlaps in aligned setup +if(${CBM_TEST_MODEL} MATCHES Nightly OR ${CBM_TEST_MODEL} MATCHES Weekly) + set(setup mcbm_beam_2022_05_23_nickel) + set(align_file ${CBMROOT_SOURCE_DIR}/parameters/mcbm/AlignmentMatrices_mcbm_beam_2022_05_23_nickel.root) + set(testname geo_setup_overlaps_align_${setup}) + add_test(${testname} ${MACRO_DIR}/check_overlaps.sh \"data/examine_${setup}\" \"${align_file}\") + set_tests_properties(${testname} PROPERTIES + TIMEOUT 600 + FAIL_REGULAR_EXPRESSION "segmentation violation" + PASS_REGULAR_EXPRESSION "Test Passed;All ok" + FIXTURES_REQUIRED fixt_check_overlaps_${setup} + FIXTURES_SETUP fixt_check_overlaps_align_${setup} + ) +endIf() +# ============================================================================ + Install(FILES .rootrc examine_materials.C check_overlaps.C DESTINATION share/cbmroot/macro/geometry ) diff --git a/macro/geometry/README.md b/macro/geometry/README.md index dc4f35f75c140ebc3de23bb3d055e537bc45e1e0..4b639e4ed44624728d28f63f0e21ca13bea20a0a 100644 --- a/macro/geometry/README.md +++ b/macro/geometry/README.md @@ -219,5 +219,26 @@ root -q 'examine_materials.C("sis100_muon_jpsi_DEC21")' for file in `ls ../../geometry/setup/setup_mcbm_beam_2022_*`; do tag=`echo $file | awk -F'/' '{print $5}' | sed 's|setup_|"|' | sed 's_.C$_"_'`; echo $tag; root -q './examine_material.C('$tag')'; done > MCBM_2022_EXAMINE +--- +## check_overlaps.C + +Allow to check overlaps in existing full geometry file (setup, e.g. output of `examine_materials.C`) and detect +expected/unexpected ones. + +The lists of expected (known and ignored) overlaps are defined in 4 vectors at the begining of the macro for: +- overlaps between a BMon detector defined in the TOF geometry and the target/pipe vacuum in mCBM (always expected) +- overlaps in mCBM (should be expanded/reduced depending on simulation/analysis progresses) +- overlaps between a BMon detector defined in the TOF geometry and the target/pipe vacuum in CBM (always expected) +- overlaps in CBM (should be expanded/reduced depending on simulation/analysis progresses) + +**Usage of the script (see also examples in `CMakeLists.txt`:** +1. With a standard geometry (as defined in setup file, no alignment): + ``` + root -l -b -q 'check_overlaps.C("<full filename with path>.geo.root")' + ``` +1. With an aligned geometry (some shifts relative to setup file): + ``` + root -l -b -q 'check_overlaps.C("<full filename with path>.geo.root", "<full filename with path for alignment matrices>.root")' + ``` diff --git a/macro/geometry/check_overlaps.C b/macro/geometry/check_overlaps.C index 92754e5f4db4b226965a6541273efd5bdc244fff..f822d74d8f4fa13899f13001431307eb8e720dde 100644 --- a/macro/geometry/check_overlaps.C +++ b/macro/geometry/check_overlaps.C @@ -2,7 +2,154 @@ SPDX-License-Identifier: GPL-3.0-only Authors: Volker Friese, P.-A. Loizeau, Florian Uhlig [committer] */ +/**********************************************************************************************************************/ +#include "FairLogger.h" +namespace geo_ci +{ + /** + ** Temporary solution to bring capability of checking geometries after alignment. + ** Basically a copy of the FairAlignmentHandler of FairRoot v18.6.9 and v18.8.1 + ** FIXME: remove once a solution is found to make the FairRoot alignment functionalities available in ROOT CLI. + **/ + class FairAlignmentHandler { + public: + std::map<std::string, TGeoHMatrix> fAlignmentMatrices; + + void AlignGeometry() const; + void AlignGeometryByFullPath() const; + void AlignGeometryBySymlink() const; + + void AddAlignmentMatrices(const std::map<std::string, TGeoHMatrix>& alignmentMatrices, bool invertMatrices); + + void RecomputePhysicalAssmbBbox() const; + + FairAlignmentHandler(); + virtual ~FairAlignmentHandler(); + }; + /**********************************************************************************************************************/ + /**********************************************************************************************************************/ + FairAlignmentHandler::FairAlignmentHandler() {} + + FairAlignmentHandler::~FairAlignmentHandler() {} + + void FairAlignmentHandler::AlignGeometry() const + { + if (fAlignmentMatrices.size() > 0) { + LOG(info) << "aligning the geometry..."; + + LOG(info) << "aligning in total " << fAlignmentMatrices.size() << " volumes."; + if (gGeoManager->GetNAlignable() > 0) { // + AlignGeometryBySymlink(); + } + else { + AlignGeometryByFullPath(); + } + + // --- Force BoundingBox recomputation for AssemblyVolumes as they may have been corrupted by alignment + // FIXME: will hopefully be fixed in Root in near future, temp fix in meantime + RecomputePhysicalAssmbBbox(); + + LOG(info) << "Refreshing geometry..."; + gGeoManager->RefreshPhysicalNodes(kFALSE); + + LOG(info) << "alignment finished!"; + } + } + + void FairAlignmentHandler::AlignGeometryByFullPath() const + { + TString volume_path; + + LOG(info) << "aligning using full path."; + for (auto const& alignment_entry : fAlignmentMatrices) { + volume_path = alignment_entry.first; + + gGeoManager->cd(volume_path); + + TGeoNode* volume_node = gGeoManager->GetCurrentNode(); + TGeoMatrix* volume_matrix = volume_node->GetMatrix(); + // Need to do this as since ROOT 6.14 TGeoMatrix has no multiplication operator anymore + // it is implimnted now in TGeoHMatrix + + TGeoHMatrix local_volume_matrix = TGeoHMatrix(*volume_matrix); + + TGeoHMatrix* new_volume_matrix = new TGeoHMatrix(local_volume_matrix * alignment_entry.second); + // new matrix, representing real position (from new local mis RS to the global one) + + TGeoPhysicalNode* pn = gGeoManager->MakePhysicalNode(volume_path); + + pn->Align(new_volume_matrix); + } + LOG(info) << "alignments applied!"; + } + + void FairAlignmentHandler::AlignGeometryBySymlink() const + { + TString volume_path; + + LOG(info) << "aligning using symlinks"; + for (auto const& alignment_entry : fAlignmentMatrices) { + volume_path = alignment_entry.first; + + TGeoPhysicalNode* node = NULL; + TGeoPNEntry* entry = gGeoManager->GetAlignableEntry(volume_path); + if (entry) { // + node = gGeoManager->MakeAlignablePN(entry); + } + + TGeoMatrix* volume_matrix = NULL; + if (node) { // + volume_matrix = node->GetMatrix(); + } + else { + continue; + } + // Need to do this as since ROOT 6.14 TGeoMatrix has no multiplication operator anymore + // it is implimnted now in TGeoHMatrix + TGeoHMatrix local_volume_matrix = TGeoHMatrix(*volume_matrix); + + TGeoHMatrix* new_volume_matrix = new TGeoHMatrix(local_volume_matrix * alignment_entry.second); + // new matrix, representing real position (from new local mis RS to the global one) + node->Align(new_volume_matrix); + } + } + + void FairAlignmentHandler::AddAlignmentMatrices(const std::map<std::string, TGeoHMatrix>& alignmentMatrices, + bool invertMatrices) + { + LOG(info) << "adding inverting matrices..."; + for (auto const& m : alignmentMatrices) { + if (invertMatrices) // + fAlignmentMatrices[m.first] *= m.second.Inverse(); + else + fAlignmentMatrices[m.first] *= m.second; + } + } + + void FairAlignmentHandler::RecomputePhysicalAssmbBbox() const + { + TObjArray* pPhysNodesArr = gGeoManager->GetListOfPhysicalNodes(); + + TGeoPhysicalNode* pPhysNode = nullptr; + TGeoShapeAssembly* pShapeAsb = nullptr; + + Int_t iNbNodes = pPhysNodesArr->GetEntriesFast(); + for (Int_t iInd = 0; iInd < iNbNodes; ++iInd) { + pPhysNode = dynamic_cast<TGeoPhysicalNode*>(pPhysNodesArr->At(iInd)); + if (pPhysNode) { + pShapeAsb = dynamic_cast<TGeoShapeAssembly*>(pPhysNode->GetShape()); + if (pShapeAsb) { + // Should reach here only if the original node was a TGeoShapeAssembly + pShapeAsb->ComputeBBox(); + } + } + } + } +} // namespace geo_ci +/**********************************************************************************************************************/ + std::vector<std::string> mcbm_pipevac_bmon_overlaps = { + "cave/pipe_v19b_0/vacu20_1 overlapping cave/tof_v19d_mcbm_0/tof_v19d_mcbmStand_1/module_5_0", "cave/pipe_v19b_0/vacu20_1 overlapping cave/tof_v19e_mcbm_0/tof_v19e_mcbmStand_1/module_5_0", "cave/pipe_v19b_0/vacu20_1 overlapping cave/tof_v20f_mcbm_0/tof_v20f_mcbmStand_1/module_5_0", "cave/pipe_v19f_0/vacu20_1 overlapping cave/tof_v20c_mcbm_0/tof_v20c_mcbmStand_1/module_5_0", @@ -20,6 +167,7 @@ std::vector<std::pair<std::string, std::string>> mcbm_dets_overlaps = { "between modules 2 and 9 (internal to mTOF v21j)"}}; std::vector<std::pair<std::string, std::string>> mcbm_dets_overlaps_sampling = { + {"tof_v19d_mcbmStand: node module_8_0 overlapping module_8_0", "between module 8 and itself (internal to mTOF v19d)"}, {"tof_v19e_mcbmStand: node module_8_0 overlapping module_8_0", "between module 8 and itself (internal to mTOF v19e)"}, {"gas_box: node counter_0 overlapping counter_1", "between counters 0 and 1 (internal to mTOF v19e)"}, {"gas_box: node counter_1 overlapping counter_2", "between counters 1 and 2 (internal to mTOF v19e)"}, @@ -116,14 +264,15 @@ bool expected_cbm_sampling(TGeoOverlap* ov) return false; } -void check_overlaps(TString dataset = "test") +void check_overlaps(TString dataset = "test", TString alignment_matrices = "") { - // 2014-07-04 - DE - test CBM setups for collisions in nightly tests - // 2014-07-04 - DE - currently there are 2 overlaps between the PIPE and STS layer 8 - // 2014-07-04 - DE - set the default to 0 overlaps, anyway - // 2017-29-11 - FU - define some expected overlaps between magnet and rich or much - // these overlas are accepted for the time being until - // there is a new magnet geometry + // 2014-07-04 - DE - test CBM setups for collisions in nightly tests + // 2014-07-04 - DE - currently there are 2 overlaps between the PIPE and STS layer 8 + // 2014-07-04 - DE - set the default to 0 overlaps, anyway + // 2017-29-11 - FU - define some expected overlaps between magnet and rich or much + // these overlaps are accepted for the time being until there is a new magnet geometry + // 2023-07-xx - PAL - Test all setups in nightly tests, make the list of expected overlaps less ad-hoc, + // add all mCBM ones as expected, add a few CBM ones, create redmine issues for the rest UInt_t unexpectedOverlaps {0}; @@ -136,6 +285,37 @@ void check_overlaps(TString dataset = "test") gGeoManager = (TGeoManager*) f->Get("FAIRGeom"); + if ("" != alignment_matrices) { + + std::cout << " Applying alignment matrices from file " << alignment_matrices << std::endl; + // Define the basic structure which needs to be filled with information + // This structure is stored in the output file and later passed to the + // FairRoot framework to do the (miss)alignment + std::map<std::string, TGeoHMatrix>* matrices {nullptr}; + + // read matrices from disk + TFile* misalignmentMatrixRootfile = new TFile(alignment_matrices, "READ"); + if (misalignmentMatrixRootfile->IsOpen()) { + gDirectory->GetObject("MisalignMatrices", matrices); + misalignmentMatrixRootfile->Close(); + } + else { + std::cout << "Could not open file " << alignment_matrices << "\n Exiting"; + return; + } + + if (matrices) { + geo_ci::FairAlignmentHandler* handler = new geo_ci::FairAlignmentHandler(); + handler->AddAlignmentMatrices(*matrices, false); + handler->AlignGeometry(); + delete handler; + } + else { + std::cout << "Alignment required but no matrices found. \n Exiting"; + return; + } + } + gGeoManager->CheckOverlaps(0.0001); TIter next(gGeoManager->GetListOfOverlaps()); TGeoOverlap* ov;