Skip to content

Commit

Permalink
add misalignment decoration
Browse files Browse the repository at this point in the history
  • Loading branch information
Zequn-SUN committed Nov 21, 2024
1 parent 11746d1 commit cbf14dd
Show file tree
Hide file tree
Showing 10 changed files with 303 additions and 0 deletions.
1 change: 1 addition & 0 deletions Examples/Detectors/DD4hepDetector/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ add_library(
SHARED
src/DD4hepDetector.cpp
src/DD4hepGeometryService.cpp
src/DD4hepAlignmentDecorator.cpp
)

target_include_directories(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#pragma once

#include "Acts/Definitions/Algebra.hpp"
#include "Acts/Plugins/DD4hep/DD4hepDetectorElement.hpp"
#include "Acts/Utilities/Logger.hpp"
#include "ActsExamples/Framework/AlgorithmContext.hpp"
#include "ActsExamples/Framework/IContextDecorator.hpp"
#include "ActsExamples/Framework/ProcessCode.hpp"
#include "ActsExamples/Framework/RandomNumbers.hpp"
#include <Acts/Geometry/TrackingGeometry.hpp>

#include <cstddef>
#include <iostream>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>

namespace ActsExamples {
struct AlgorithmContext;

namespace DD4hep {
class DD4hepAlignmentDecorator : public IContextDecorator {
public:
using LayerStore = std::vector<std::shared_ptr<Acts::DD4hepDetectorElement>>;
using DetectorStore = std::vector<LayerStore>;
struct Config {
// whether use the nominal geometry
bool nominal = true;
// path of Json file which is used to store the misalignment matrix of each
// detector element
// @todo use `JsonMisalignmentConfig`
std::string misAlignedGeoJsonPath = "odd-misalignment-matrix.json";
// tracking geometry
std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry = nullptr;
};

DD4hepAlignmentDecorator(const Config& cfg,
std::unique_ptr<const Acts::Logger> logger =
Acts::getDefaultLogger("AlignmentDecorator",
Acts::Logging::INFO));
~DD4hepAlignmentDecorator() override = default;
ProcessCode decorate(AlgorithmContext& context) override;
const std::string& name() const override { return m_name; }

private:
Config m_cfg; ///< the configuration class
std::unique_ptr<const Acts::Logger> m_logger; ///!< the logging instance
const Acts::Logger& logger() const { return *m_logger; }
std::string m_name = "Aligned Detector";
std::unordered_map<std::string, Acts::Transform3>
m_misalignmentAtConstruction;
std::unordered_map<std::string, Acts::Transform3> m_nominalStore;
std::unordered_map<std::string, Acts::Transform3> m_mistransform;
void parseGeometry(const Acts::TrackingGeometry& tGeometry);
void initializeMisFromJson(const std::string& misAlignedGeoJsonFile);
};

inline void DD4hepAlignmentDecorator::initializeMisFromJson(
const std::string& misJson) {
std::ifstream file(misJson);
if (!file.is_open())
throw std::runtime_error("Unable to open file");
nlohmann::json jsonData;
file >> jsonData;
for (auto& [key, value] : jsonData.items()) {
if (value.is_array() && value.size() == 6) {
double x = value[0].get<double>();
double y = value[1].get<double>();
double z = value[2].get<double>();
double alpha = value[3].get<double>() / 180 * M_PI;
double beta = value[4].get<double>() / 180 * M_PI;
double gamma = value[5].get<double>() / 180 * M_PI;
Acts::Transform3 translation =
Eigen::Affine3d(Eigen::Translation3d(x, y, z));
Acts::Transform3 delta_rotationx =
Eigen::Affine3d(Eigen::AngleAxisd(alpha, Eigen::Vector3d::UnitX()));
Acts::Transform3 delta_rotationy =
Eigen::Affine3d(Eigen::AngleAxisd(beta, Eigen::Vector3d::UnitY()));
Acts::Transform3 delta_rotationz =
Eigen::Affine3d(Eigen::AngleAxisd(gamma, Eigen::Vector3d::UnitZ()));
m_misalignmentAtConstruction[key] =
translation * delta_rotationx * delta_rotationy * delta_rotationz;
}
}
std::cout << "Successfully initialize the JSON file" << std::endl;
}
} // namespace DD4hep
} // namespace ActsExamples
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ struct DD4hepDetector {
/// @brief Access to the DD4hep field
/// @return a shared pointer to the DD4hep field
std::shared_ptr<Acts::DD4hepFieldAdapter> field() const;

// whether use the nominal geometry
bool m_nominal = false;
};

} // namespace ActsExamples::DD4hep
82 changes: 82 additions & 0 deletions Examples/Detectors/DD4hepDetector/src/DD4hepAlignmentDecorator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// This file is part of the ACTS project.
//
// Copyright (C) 2016 CERN for the benefit of the ACTS project
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

#include "ActsExamples/DD4hepDetector/DD4hepAlignmentDecorator.hpp"

#include "Acts/Definitions/Algebra.hpp"
#include "Acts/Geometry/GeometryContext.hpp"
#include "Acts/Plugins/DD4hep/DD4hepDetectorElement.hpp"
#include "Acts/Plugins/DD4hep/DD4hepGeometryContext.hpp"
#include "ActsExamples/Framework/AlgorithmContext.hpp"
#include "ActsExamples/Framework/RandomNumbers.hpp"
#include <Acts/Geometry/TrackingGeometry.hpp>

#include <ostream>
#include <thread>
#include <utility>

ActsExamples::DD4hep::DD4hepAlignmentDecorator::DD4hepAlignmentDecorator(
const Config& cfg, std::unique_ptr<const Acts::Logger> logger)
: m_cfg(cfg), m_logger(std::move(logger)) {
if (m_cfg.trackingGeometry != nullptr) {
parseGeometry(*m_cfg.trackingGeometry.get());
}
}

ActsExamples::ProcessCode
ActsExamples::DD4hep::DD4hepAlignmentDecorator::decorate(
AlgorithmContext& context) {
Acts::DD4hepGeometryContext dd4hepGeoCtx =
Acts::DD4hepGeometryContext(m_cfg.nominal);
if (!m_cfg.nominal) {
initializeMisFromJson(m_cfg.misAlignedGeoJsonPath);
for (const auto& entry : m_misalignmentAtConstruction) {
const std::string& identifier = entry.first;
const Acts::Transform3& misalignmentTransform = entry.second;
auto nominalIt = m_nominalStore.find(identifier);
if (nominalIt != m_nominalStore.end()) {
const Acts::Transform3& nominalTransform = nominalIt->second;
Eigen::Matrix3d R1 = nominalTransform.rotation();
Eigen::Vector3d T1 = nominalTransform.translation();
Eigen::Matrix3d R2 = misalignmentTransform.rotation();
Eigen::Vector3d T2 = misalignmentTransform.translation();
Eigen::Matrix3d R3 = R1 * R2;
Eigen::Vector3d T3 = T1 + T2;
m_mistransform[identifier] =
Eigen::Affine3d(Eigen::Translation3d(T3)) * Eigen::Affine3d(R3);
}
}
dd4hepGeoCtx.setAlignmentStore(m_mistransform);
}
context.geoContext = dd4hepGeoCtx;
return ProcessCode::SUCCESS;
}

void ActsExamples::DD4hep::DD4hepAlignmentDecorator::parseGeometry(
const Acts::TrackingGeometry& tGeometry) {
// Double-visit - first count
std::size_t nTransforms = 0;
tGeometry.visitSurfaces([&nTransforms](const auto*) { ++nTransforms; });
std::unordered_map<std::string, Acts::Transform3> aStore;
Acts::GeometryContext nominalCtx = {};
// Collect the surfacas into the nominal store
auto fillTransforms = [&aStore, &nominalCtx](const auto* surface) -> void {
if (surface == nullptr) {
throw std::invalid_argument("Surface is nullptr.");
}
auto alignableElement = dynamic_cast<const Acts::DD4hepDetectorElement*>(
surface->associatedDetectorElement());
if (alignableElement == nullptr) {
throw std::invalid_argument("Surface is not alignable");
}
unsigned long long id = alignableElement->identifier();
aStore[Form("%lld", id)] = surface->transform(nominalCtx);
};
tGeometry.visitSurfaces(fillTransforms);
m_nominalStore = std::move(aStore);
}
9 changes: 9 additions & 0 deletions Examples/Detectors/DD4hepDetector/src/DD4hepDetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Acts/Geometry/GeometryContext.hpp"
#include "Acts/MagneticField/MagneticFieldProvider.hpp"
#include "Acts/Plugins/DD4hep/DD4hepFieldAdapter.hpp"
#include "ActsExamples/DD4hepDetector/DD4hepAlignmentDecorator.hpp"
#include "ActsExamples/DD4hepDetector/DD4hepGeometryService.hpp"

#include <cstddef>
Expand Down Expand Up @@ -43,7 +44,15 @@ auto DD4hepDetector::finalize(
throw std::runtime_error{
"Did not receive tracking geometry from DD4hep geometry service"};
}

DD4hepAlignmentDecorator::Config dd4hepAcfg;
dd4hepAcfg.nominal = m_nominal;
dd4hepAcfg.trackingGeometry = dd4tGeometry;
ContextDecorators dd4ContextDecorators = {};
dd4ContextDecorators.push_back(std::make_shared<DD4hepAlignmentDecorator>(
std::move(dd4hepAcfg),
Acts::getDefaultLogger("AlignmentDecorator", Acts::Logging::INFO)));
std::cout << "After dd4ContextDecorators push back" << std::endl;
// return the pair of geometry and empty decorators
return std::make_pair<TrackingGeometryPtr, ContextDecorators>(
std::move(dd4tGeometry), std::move(dd4ContextDecorators));
Expand Down
1 change: 1 addition & 0 deletions Plugins/DD4hep/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_library(
src/DD4hepDetectorStructure.cpp
src/DD4hepMaterialHelpers.cpp
src/DD4hepDetectorElement.cpp
src/DD4hepGeometryContext.cpp
src/DD4hepDetectorSurfaceFactory.cpp
src/DD4hepLayerBuilder.cpp
src/DD4hepLayerStructure.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#pragma once

#include "Acts/Geometry/GeometryContext.hpp"
#include "Acts/Plugins/DD4hep/DD4hepGeometryContext.hpp"
#include "Acts/Plugins/TGeo/TGeoDetectorElement.hpp"
#include "Acts/Utilities/ThrowAssert.hpp"

Expand Down Expand Up @@ -87,6 +88,11 @@ class DD4hepDetectorElement : public TGeoDetectorElement {
// Give access to the DD4hep detector element
const dd4hep::DetElement& sourceElement() const { return m_detElement; }

const Transform3& transform(const GeometryContext& gctx) const override;
Transform3 nominalTransform(const GeometryContext& gctx) const {
return TGeoDetectorElement::transform(gctx);
}

private:
/// DD4hep detector element
dd4hep::DetElement m_detElement;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// This file is part of the ACTS project.
//
// Copyright (C) 2016-2024 CERN for the benefit of the ACTS project
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

#pragma once

#include "Acts/Definitions/Algebra.hpp"
#include "Acts/Geometry/GeometryContext.hpp"

#include <nlohmann/json.hpp>

namespace Acts {

class DD4hepDetectorElement;

/// @class GeometryContext
///
/// @brief DD4hep specific geometry context for alignment handling
///
/// Extends the base GeometryContext to provide DD4hep-specific alignment
/// capabilities. The context can be active or inactive, controlling whether
/// alignment corrections should be applied.
///
/// @note This context is specifically designed to work with DD4hepDetectorElement
/// and provides contextual transformations for alignment purposes.
///
class DD4hepGeometryContext : public GeometryContext {
public:
using AlignmentStore = std::unordered_map<std::string, Transform3>;

/// Default constructor
DD4hepGeometryContext() = default;

/// Constructor
explicit DD4hepGeometryContext(bool isGeometryNominal)
: m_nominal(isGeometryNominal) {}

/// The transform of this detector element within the given context
///
/// @param dElement The detector element
///
/// @return The transform of the detector element
const Transform3& contextualTransform(
const DD4hepDetectorElement& dElement) const;

void setAlignmentStore(
std::unordered_map<std::string, Transform3> alignmentStore);

/// @brief Return the active status of the context
/// @return boolean that indicates if the context is active
bool isNominal() const { return m_nominal; }

private:
bool m_nominal = true;
AlignmentStore m_alignmentStore = {};
};

} // namespace Acts
13 changes: 13 additions & 0 deletions Plugins/DD4hep/src/DD4hepDetectorElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#include "Acts/Plugins/DD4hep/DD4hepDetectorElement.hpp"

#include "Acts/Plugins/DD4hep/DD4hepGeometryContext.hpp"

#include <iostream>
#include <utility>

#include <DD4hep/Alignments.h>
Expand All @@ -23,3 +26,13 @@ Acts::DD4hepDetectorElement::DD4hepDetectorElement(
detElement.nominal().worldTransformation(), axes, scalor,
std::move(material)),
m_detElement(detElement) {}

const Acts::Transform3& Acts::DD4hepDetectorElement::transform(
const GeometryContext& gctx) const {
const Acts::DD4hepGeometryContext* dd4hepGtx =
gctx.maybeGet<DD4hepGeometryContext>();
if (dd4hepGtx != nullptr && !dd4hepGtx->isNominal()) {
return dd4hepGtx->contextualTransform(*this);
}
return TGeoDetectorElement::transform(gctx);
}
36 changes: 36 additions & 0 deletions Plugins/DD4hep/src/DD4hepGeometryContext.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// This file is part of the ACTS project.
//
// Copyright (C) 2016 CERN for the benefit of the ACTS project
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

#pragma once

#include "Acts/Plugins/DD4hep/DD4hepGeometryContext.hpp"

#include "Acts/Plugins/DD4hep/DD4hepDetectorElement.hpp"

#include <iostream>

#include <nlohmann/json.hpp>

const Acts::Transform3& Acts::DD4hepGeometryContext::contextualTransform(
const DD4hepDetectorElement& dElement) const {
if (!this->isNominal()) {
auto it = m_alignmentStore.find(Form("%lld", dElement.identifier()));
if (it != m_alignmentStore.end()) {
return it->second;
} else {
return dElement.nominalTransform(DD4hepGeometryContext());
}
} else {
return dElement.nominalTransform(DD4hepGeometryContext());
}
}

void Acts::DD4hepGeometryContext::setAlignmentStore(
std::unordered_map<std::string, Transform3> alignmentStore) {
m_alignmentStore = alignmentStore;
}

0 comments on commit cbf14dd

Please sign in to comment.