Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: draw measurements in e.g. .obj, refactor and update unittests #2229

Merged
merged 12 commits into from
Jun 28, 2023
41 changes: 32 additions & 9 deletions Core/include/Acts/Visualization/EventDataView3D.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file is part of the Acts project.
//
// Copyright (C) 2020 CERN for the benefit of the Acts project
// Copyright (C) 2020-2023 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
Expand Down Expand Up @@ -39,7 +39,7 @@ static ViewConfig s_viewFiltered = ViewConfig({255, 255, 0});
static ViewConfig s_viewSmoothed = ViewConfig({0, 102, 255});

struct EventDataView3D {
/// Helper to find the egen values and corr angle
/// Helper to find the eigen values and corr angle
///
/// @param covariance The covariance matrix
static inline std::array<double, 3> decomposeCovariance(
Expand Down Expand Up @@ -112,7 +112,7 @@ struct EventDataView3D {
/// @param position Where the cone originates from
/// @param direction The direction parameters
/// @param covariance The 2x2 covariance matrix for phi/theta
/// @param directionScale The direction arror length
/// @param directionScale The direction arrow length
/// @param angularErrorScale The local Error scale
/// @param viewConfig The visualization parameters
static void drawCovarianceAngular(
Expand Down Expand Up @@ -178,6 +178,30 @@ struct EventDataView3D {
}
}

/// Helper method to draw a single measurement
///
/// @param helper [in, out] The visualization helper
/// @param lposition calibrated measurement
/// @param covariance calibrated covariance
/// @param transform reference surface transformed with the geometry context
/// @param locErrorScale The scale of the local error
/// @param measurementConfig The visualization options for the measurement
///
/// TODO: Expand to 1D measurements
static void drawMeasurement(
IVisualization3D& helper, const Vector2& lposition,
const SymMatrix2& covariance, const Transform3& transform,
const double locErrorScale = 1.,
const ViewConfig& measurementConfig = s_viewMeasurement) {
if (locErrorScale <= 0) {
throw std::invalid_argument("locErrorScale must be > 0");
}
if (measurementConfig.visible) {
drawCovarianceCartesian(helper, lposition, covariance, transform,
locErrorScale, measurementConfig);
}
}

/// Helper method to draw one trajectory stored in a MultiTrajectory object
///
/// @param helper [in, out] The visualization helper
Expand All @@ -186,7 +210,7 @@ struct EventDataView3D {
/// @param gctx The geometry context for which it is drawn
/// @param momentumScale The scale of the momentum
/// @param locErrorScale The scale of the local error
/// @param angularErrorScale The sclae of the angular error
/// @param angularErrorScale The scale of the angular error
/// @param surfaceConfig The visualization options for the surface
/// @param measurementConfig The visualization options for the measurement
/// @param predictedConfig The visualization options for the predicted
Expand Down Expand Up @@ -231,13 +255,12 @@ struct EventDataView3D {
// Second, if necessary and present, draw the calibrated measurement (only
// draw 2D measurement here)
// @Todo: how to draw 1D measurement?
if (measurementConfig.visible and state.hasCalibrated() and
state.calibratedSize() == 2) {
if (state.hasCalibrated() and state.calibratedSize() == 2) {
const Vector2& lposition = state.template calibrated<2>();
const SymMatrix2 covariance = state.template calibratedCovariance<2>();
drawCovarianceCartesian(helper, lposition, covariance,
state.referenceSurface().transform(gctx),
locErrorScale, measurementConfig);
drawMeasurement(helper, lposition, covariance,
state.referenceSurface().transform(gctx), locErrorScale,
measurementConfig);
}

// Last, if necessary and present, draw the track parameters
Expand Down
217 changes: 150 additions & 67 deletions Tests/UnitTests/Core/Visualization/EventDataView3DBase.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This file is part of the Acts project.
//
// Copyright (C) 2020-2021 CERN for the benefit of the Acts project
// Copyright (C) 2020-2023 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
Expand Down Expand Up @@ -51,69 +51,28 @@ namespace Acts {
namespace EventDataView3DTest {

using Covariance = BoundSymMatrix;
template <BoundIndices... params>
using MeasurementType = Measurement<BoundIndices, params...>;

std::normal_distribution<double> gauss(0., 1.);
std::default_random_engine generator(42);

/// Helper method to visualize all types of surfaces
/// A function that creates a simple telescope detector with surfaces for the
/// EventDataView3D tests
///
/// @param helper The visualization helper
/// @param surfaces Reference to the surfaces, because we need them outside
/// @param detector The tracking geometry that will be filled
/// @param nSurfaces Number of surfaces to generate
///
/// @return an overall string including all written output
static inline std::string testBoundTrackParameters(IVisualization3D& helper) {
std::stringstream ss;

ViewConfig pcolor({20, 120, 20});
ViewConfig scolor({235, 198, 52});

auto gctx = GeometryContext();
auto identity = Transform3::Identity();

// rectangle and plane
auto rectangle = std::make_shared<RectangleBounds>(15., 15.);
auto plane = Surface::makeShared<PlaneSurface>(identity, rectangle);

double momentumScale = 0.005;
double localErrorScale = 10.;
double directionErrorScale = 1000.;

// now create parameters on this surface
// l_x, l_y, phi, theta, q/p (1/p), t
std::array<double, 6> pars_array = {
{-0.1234, 4.8765, 0.45, 0.128, 0.001, 21.}};

BoundTrackParameters::ParametersVector pars =
BoundTrackParameters::ParametersVector::Zero();
pars << pars_array[0], pars_array[1], pars_array[2], pars_array[3],
pars_array[4], pars_array[5];

BoundSymMatrix cov = BoundSymMatrix::Zero();
cov << 0.25, 0.0042, -0.00076, 6.156e-06, -2.11e-07, 0, 0.0042, 0.859,
-0.000173, 0.000916, -4.017e-08, 0, -0.00076, -0.000173, 2.36e-04,
-2.76e-07, 1.12e-08, 0, 6.15e-06, 0.000916, -2.76e-07, 8.84e-04,
-2.85e-11, 0, -2.11 - 07, -4.017e-08, 1.123e-08, -2.85 - 11, 1.26e-10, 0,
0, 0, 0, 0, 0, 1;

EventDataView3D::drawBoundTrackParameters(
helper, BoundTrackParameters(plane, pars, std::move(cov)), gctx,
momentumScale, localErrorScale, directionErrorScale, pcolor, scolor);

helper.write("EventData_BoundAtPlaneParameters");
helper.write(ss);

return ss.str();
}

static inline std::string testMultiTrajectory(IVisualization3D& helper) {
void createDetector(GeometryContext& tgContext,
std::vector<const Surface*>& surfaces,
std::shared_ptr<const TrackingGeometry>& detector,
const size_t nSurfaces = 7) {
using namespace UnitLiterals;
std::stringstream ss;

// Create a test context
GeometryContext tgContext = GeometryContext();
MagneticFieldContext mfContext = MagneticFieldContext();
CalibrationContext calContext = CalibrationContext();
if (nSurfaces < 1) {
throw std::invalid_argument("At least 1 surfaces needs to be created.");
}

// Construct the rotation
RotationMatrix3 rotation = RotationMatrix3::Identity();
Expand All @@ -136,17 +95,14 @@ static inline std::string testMultiTrajectory(IVisualization3D& helper) {

// Set translation vectors
std::vector<Vector3> translations;
translations.reserve(6);
translations.push_back({-300_mm, 0., 0.});
translations.push_back({-200_mm, 0., 0.});
translations.push_back({-100_mm, 0., 0.});
translations.push_back({100_mm, 0., 0.});
translations.push_back({200_mm, 0., 0.});
translations.push_back({300_mm, 0., 0.});
translations.reserve(nSurfaces);
for (unsigned int i = 0; i < nSurfaces; i++) {
translations.push_back({i * 100_mm - 300_mm, 0., 0.});
}

// Construct layer configs
std::vector<CuboidVolumeBuilder::LayerConfig> lConfs;
lConfs.reserve(6);
lConfs.reserve(nSurfaces);
for (unsigned int i = 0; i < translations.size(); i++) {
CuboidVolumeBuilder::SurfaceConfig sConf;
sConf.position = translations[i];
Expand Down Expand Up @@ -189,12 +145,10 @@ static inline std::string testMultiTrajectory(IVisualization3D& helper) {
return cvb.trackingVolume(context, inner, vb);
});
TrackingGeometryBuilder tgb(tgbCfg);
std::shared_ptr<const TrackingGeometry> detector =
tgb.trackingGeometry(tgContext);
detector = tgb.trackingGeometry(tgContext);

// Get the surfaces;
std::vector<const Surface*> surfaces;
surfaces.reserve(6);
surfaces.reserve(nSurfaces);
detector->visitSurfaces([&](const Surface* surface) {
if (surface != nullptr && surface->associatedDetectorElement() != nullptr) {
std::cout << "surface " << surface->geometryId() << " placed at: ("
Expand All @@ -203,12 +157,141 @@ static inline std::string testMultiTrajectory(IVisualization3D& helper) {
}
});
std::cout << "There are " << surfaces.size() << " surfaces" << std::endl;
}

/// Helper method to visualize all types of surfaces
///
/// @param helper The visualization helper
///
/// @return an overall string including all written output
static inline std::string testBoundTrackParameters(IVisualization3D& helper) {
std::stringstream ss;

ViewConfig pcolor({20, 120, 20});
ViewConfig scolor({235, 198, 52});

auto gctx = GeometryContext();
auto identity = Transform3::Identity();

// rectangle and plane
auto rectangle = std::make_shared<RectangleBounds>(15., 15.);
auto plane = Surface::makeShared<PlaneSurface>(identity, rectangle);

double momentumScale = 0.005;
double localErrorScale = 10.;
double directionErrorScale = 1000.;

// now create parameters on this surface
// l_x, l_y, phi, theta, q/p (1/p), t
std::array<double, 6> pars_array = {
{-0.1234, 4.8765, 0.45, 0.128, 0.001, 21.}};

BoundTrackParameters::ParametersVector pars =
BoundTrackParameters::ParametersVector::Zero();
pars << pars_array[0], pars_array[1], pars_array[2], pars_array[3],
pars_array[4], pars_array[5];

Covariance cov = Covariance::Zero();
cov << 0.25, 0.0042, -0.00076, 6.156e-06, -2.11e-07, 0, 0.0042, 0.859,
-0.000173, 0.000916, -4.017e-08, 0, -0.00076, -0.000173, 2.36e-04,
-2.76e-07, 1.12e-08, 0, 6.15e-06, 0.000916, -2.76e-07, 8.84e-04,
-2.85e-11, 0, -2.11 - 07, -4.017e-08, 1.123e-08, -2.85 - 11, 1.26e-10, 0,
0, 0, 0, 0, 0, 1;

EventDataView3D::drawBoundTrackParameters(
helper, BoundTrackParameters(plane, pars, std::move(cov)), gctx,
momentumScale, localErrorScale, directionErrorScale, pcolor, scolor);

helper.write("EventData_BoundAtPlaneParameters");
helper.write(ss);

return ss.str();
}

/// Helper method to visualize measurements
///
/// @param helper The visualization helper
///
/// @return an overall string including all written output
static inline std::string testMeasurement(IVisualization3D& helper) {
using namespace UnitLiterals;
std::stringstream ss;

// Create a test context
GeometryContext tgContext = GeometryContext();

// Create a detector
const size_t nSurfaces = 7;
std::vector<const Surface*> surfaces;
std::shared_ptr<const TrackingGeometry> detector;
createDetector(tgContext, surfaces, detector, nSurfaces);

// Create measurements (assuming they are for a linear track parallel to
// global x-axis)
std::cout << "Creating measurements:" << std::endl;
std::vector<Test::TestSourceLink> sourcelinks;
sourcelinks.reserve(nSurfaces);
Vector2 lPosCenter{5_mm, 5_mm};
Vector2 resolution{200_um, 150_um};
SymMatrix2 cov2D = resolution.cwiseProduct(resolution).asDiagonal();
for (const auto& surface : surfaces) {
// 2D measurements
Vector2 loc = lPosCenter;
loc[0] += resolution[0] * gauss(generator);
loc[1] += resolution[1] * gauss(generator);
sourcelinks.emplace_back(Test::TestSourceLink{
eBoundLoc0, eBoundLoc1, loc, cov2D, surface->geometryId()});
}

double localErrorScale = 100.;
ViewConfig mcolor({255, 145, 48});
mcolor.offset = 0.01;

// Draw the measurements
std::cout << "Draw the measurements" << std::endl;
// auto singleMeasurement = sourcelinks[0];
for (auto& singleMeasurement : sourcelinks) {
auto cov = singleMeasurement.covariance;
auto lposition = singleMeasurement.parameters;

auto surf = detector->findSurface(singleMeasurement.m_geometryId);
auto transf = surf->transform(tgContext);

EventDataView3D::drawMeasurement(helper, lposition, cov, transf,
localErrorScale, mcolor);
}

helper.write("EventData_Measurement");
helper.write(ss);

return ss.str();
}

/// Helper method to visualize a MultiTrajectory
///
/// @param helper The visualization helper
///
/// @return an overall string including all written output
static inline std::string testMultiTrajectory(IVisualization3D& helper) {
using namespace UnitLiterals;
std::stringstream ss;

// Create a test context
GeometryContext tgContext = GeometryContext();
MagneticFieldContext mfContext = MagneticFieldContext();
CalibrationContext calContext = CalibrationContext();

// Create a detector
const size_t nSurfaces = 7;
std::vector<const Surface*> surfaces;
std::shared_ptr<const TrackingGeometry> detector;
createDetector(tgContext, surfaces, detector, nSurfaces);

// Create measurements (assuming they are for a linear track parallel to
// global x-axis)
std::cout << "Creating measurements:" << std::endl;
std::vector<Acts::SourceLink> sourcelinks;
sourcelinks.reserve(6);
sourcelinks.reserve(nSurfaces);
Vector2 lPosCenter{5_mm, 5_mm};
Vector2 resolution{200_um, 150_um};
SymMatrix2 cov2D = resolution.cwiseProduct(resolution).asDiagonal();
Expand Down