File indexing completed on 2025-07-01 07:53:14
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/Io/Csv/CsvTrackingGeometryWriter.hpp"
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Units.hpp"
0013 #include "Acts/Geometry/BoundarySurfaceT.hpp"
0014 #include "Acts/Geometry/GeometryContext.hpp"
0015 #include "Acts/Geometry/GeometryIdentifier.hpp"
0016 #include "Acts/Geometry/Layer.hpp"
0017 #include "Acts/Geometry/TrackingGeometry.hpp"
0018 #include "Acts/Geometry/TrackingVolume.hpp"
0019 #include "Acts/Geometry/Volume.hpp"
0020 #include "Acts/Geometry/VolumeBounds.hpp"
0021 #include "Acts/Surfaces/Surface.hpp"
0022 #include "Acts/Surfaces/SurfaceArray.hpp"
0023 #include "Acts/Surfaces/SurfaceBounds.hpp"
0024 #include "Acts/Utilities/BinnedArray.hpp"
0025 #include "Acts/Utilities/IAxis.hpp"
0026 #include "Acts/Utilities/Logger.hpp"
0027 #include "ActsExamples/Framework/AlgorithmContext.hpp"
0028 #include "ActsExamples/Io/Csv/CsvInputOutput.hpp"
0029 #include "ActsExamples/Utilities/Paths.hpp"
0030
0031 #include <array>
0032 #include <cstddef>
0033 #include <stdexcept>
0034 #include <utility>
0035 #include <vector>
0036
0037 #include "CsvOutputData.hpp"
0038
0039 using namespace ActsExamples;
0040
0041 CsvTrackingGeometryWriter::CsvTrackingGeometryWriter(
0042 const CsvTrackingGeometryWriter::Config& config, Acts::Logging::Level level)
0043 : m_cfg(config),
0044 m_logger(Acts::getDefaultLogger("CsvTrackingGeometryWriter", level))
0045
0046 {
0047 if (!m_cfg.trackingGeometry) {
0048 throw std::invalid_argument("Missing tracking geometry");
0049 }
0050 m_world = m_cfg.trackingGeometry->highestTrackingVolume();
0051 if (m_world == nullptr) {
0052 throw std::invalid_argument("Could not identify the world volume");
0053 }
0054 }
0055
0056 std::string CsvTrackingGeometryWriter::name() const {
0057 return "CsvTrackingGeometryWriter";
0058 }
0059
0060 namespace {
0061
0062 using SurfaceWriter = ActsExamples::NamedTupleCsvWriter<SurfaceData>;
0063 using SurfaceGridWriter = ActsExamples::NamedTupleCsvWriter<SurfaceGridData>;
0064 using LayerVolumeWriter = ActsExamples::NamedTupleCsvWriter<LayerVolumeData>;
0065 using BoundarySurface = Acts::BoundarySurfaceT<Acts::TrackingVolume>;
0066
0067
0068 void fillSurfaceData(SurfaceData& data, const Acts::Surface& surface,
0069 const Acts::GeometryContext& geoCtx) noexcept(false) {
0070
0071 data.geometry_id = surface.geometryId().value();
0072 data.volume_id = surface.geometryId().volume();
0073 data.boundary_id = surface.geometryId().boundary();
0074 data.layer_id = surface.geometryId().layer();
0075 data.module_id = surface.geometryId().sensitive();
0076 data.extra_id = surface.geometryId().extra();
0077
0078 auto center = surface.center(geoCtx);
0079 data.cx = center.x() / Acts::UnitConstants::mm;
0080 data.cy = center.y() / Acts::UnitConstants::mm;
0081 data.cz = center.z() / Acts::UnitConstants::mm;
0082
0083 auto transform = surface.transform(geoCtx);
0084 data.rot_xu = transform(0, 0);
0085 data.rot_xv = transform(0, 1);
0086 data.rot_xw = transform(0, 2);
0087 data.rot_yu = transform(1, 0);
0088 data.rot_yv = transform(1, 1);
0089 data.rot_yw = transform(1, 2);
0090 data.rot_zu = transform(2, 0);
0091 data.rot_zv = transform(2, 1);
0092 data.rot_zw = transform(2, 2);
0093
0094 std::array<float*, 7> dataBoundParameters = {
0095 &data.bound_param0, &data.bound_param1, &data.bound_param2,
0096 &data.bound_param3, &data.bound_param4, &data.bound_param5,
0097 &data.bound_param6};
0098
0099 const auto& bounds = surface.bounds();
0100 data.bounds_type = static_cast<int>(bounds.type());
0101 auto boundValues = bounds.values();
0102
0103 if (boundValues.size() > dataBoundParameters.size()) {
0104 throw std::invalid_argument(
0105 "Bound types with too many parameters. Should never happen.");
0106 }
0107
0108 for (std::size_t ipar = 0; ipar < boundValues.size(); ++ipar) {
0109 (*dataBoundParameters[ipar]) = boundValues[ipar];
0110 }
0111
0112 if (surface.associatedDetectorElement() != nullptr) {
0113 data.module_t = surface.associatedDetectorElement()->thickness() /
0114 Acts::UnitConstants::mm;
0115 }
0116 }
0117
0118
0119 void writeSurface(SurfaceWriter& sfWriter, const Acts::Surface& surface,
0120 const Acts::GeometryContext& geoCtx) {
0121 SurfaceData data;
0122 fillSurfaceData(data, surface, geoCtx);
0123 sfWriter.append(data);
0124 }
0125
0126
0127
0128
0129
0130
0131
0132 void writeCylinderLayerVolume(LayerVolumeWriter& lvWriter,
0133 const Acts::Layer& lv,
0134 const Acts::Transform3& transform,
0135 std::vector<double>& representingBoundValues,
0136 std::vector<double>& volumeBoundValues,
0137 std::vector<double>& lastBoundValues, bool last) {
0138
0139 LayerVolumeData lvDims;
0140 lvDims.geometry_id = lv.geometryId().value();
0141 lvDims.volume_id = lv.geometryId().volume();
0142 lvDims.layer_id = lv.geometryId().layer();
0143 bool isCylinderLayer = (lv.surfaceRepresentation().bounds().type() ==
0144 Acts::SurfaceBounds::eCylinder);
0145
0146 auto lTranslation = transform.translation();
0147
0148
0149 representingBoundValues = {
0150 representingBoundValues[0],
0151 representingBoundValues[1],
0152 lTranslation.z() - representingBoundValues[2],
0153 lTranslation.z() + representingBoundValues[2],
0154 representingBoundValues[4] - representingBoundValues[3],
0155 representingBoundValues[4] + representingBoundValues[3]};
0156
0157
0158 lvDims.min_v0 =
0159 isCylinderLayer ? representingBoundValues[0] : volumeBoundValues[0];
0160 lvDims.max_v0 =
0161 isCylinderLayer ? representingBoundValues[1] : volumeBoundValues[1];
0162 lvDims.min_v1 =
0163 isCylinderLayer ? volumeBoundValues[2] : representingBoundValues[2];
0164 lvDims.max_v1 =
0165 isCylinderLayer ? volumeBoundValues[3] : representingBoundValues[3];
0166 lvDims.min_v2 = representingBoundValues[4];
0167 lvDims.max_v2 = representingBoundValues[5];
0168
0169
0170 LayerVolumeData nlvDims;
0171 nlvDims.geometry_id = lv.geometryId().value();
0172 nlvDims.volume_id = lv.geometryId().volume();
0173 nlvDims.layer_id = lv.geometryId().layer() - 1;
0174 if (isCylinderLayer) {
0175 nlvDims.min_v0 = lastBoundValues[0];
0176 nlvDims.max_v0 = representingBoundValues[0];
0177 nlvDims.min_v1 = lastBoundValues[2];
0178 nlvDims.max_v1 = lastBoundValues[3];
0179
0180 lastBoundValues[0] = representingBoundValues[1];
0181 } else {
0182 nlvDims.min_v0 = lastBoundValues[0];
0183 nlvDims.max_v0 = lastBoundValues[1];
0184 nlvDims.min_v1 = lastBoundValues[2];
0185 nlvDims.max_v1 = representingBoundValues[2];
0186
0187 lastBoundValues[2] = representingBoundValues[3];
0188 }
0189 nlvDims.min_v2 = representingBoundValues[4];
0190 nlvDims.max_v2 = representingBoundValues[5];
0191 lvWriter.append(nlvDims);
0192
0193 lvWriter.append(lvDims);
0194
0195
0196 if (last) {
0197
0198 LayerVolumeData llvDims;
0199 llvDims.geometry_id = lv.geometryId().value();
0200 llvDims.volume_id = lv.geometryId().volume();
0201 llvDims.layer_id = lv.geometryId().layer() + 1;
0202 llvDims.min_v0 = lastBoundValues[0];
0203 llvDims.max_v0 = lastBoundValues[1];
0204 llvDims.min_v1 = lastBoundValues[2];
0205 llvDims.max_v1 = lastBoundValues[3];
0206 llvDims.min_v2 = representingBoundValues[4];
0207 llvDims.max_v2 = representingBoundValues[5];
0208
0209 lvWriter.append(llvDims);
0210 }
0211 }
0212
0213
0214 void writeBoundarySurface(SurfaceWriter& writer,
0215 const BoundarySurface& bsurface,
0216 const Acts::GeometryContext& geoCtx) {
0217 SurfaceData data;
0218 fillSurfaceData(data, bsurface.surfaceRepresentation(), geoCtx);
0219 writer.append(data);
0220 }
0221
0222
0223 void writeVolume(SurfaceWriter& sfWriter, SurfaceGridWriter& sfGridWriter,
0224 LayerVolumeWriter& lvWriter,
0225 const Acts::TrackingVolume& volume, bool writeSensitive,
0226 bool writeBoundary, bool writeSurfaceGrid,
0227 bool writeLayerVolume, const Acts::GeometryContext& geoCtx) {
0228
0229 if (volume.confinedLayers() != nullptr) {
0230 const auto& vTransform = volume.transform();
0231
0232
0233 std::vector<double> volumeBoundValues = volume.volumeBounds().values();
0234 std::vector<double> lastBoundValues;
0235
0236 if (volume.volumeBounds().type() == Acts::VolumeBounds::eCylinder) {
0237 auto vTranslation = vTransform.translation();
0238
0239 volumeBoundValues = {
0240 volumeBoundValues[0],
0241 volumeBoundValues[1],
0242 vTranslation.z() - volumeBoundValues[2],
0243 vTranslation.z() + volumeBoundValues[2],
0244 volumeBoundValues[4] - volumeBoundValues[3],
0245 volumeBoundValues[4] + volumeBoundValues[3],
0246 };
0247 lastBoundValues = volumeBoundValues;
0248 }
0249
0250 unsigned int layerIdx = 0;
0251 const auto& layers = volume.confinedLayers()->arrayObjects();
0252
0253
0254
0255 if (layers.size() == 3 && writeLayerVolume) {
0256 auto slayer = layers[1];
0257 LayerVolumeData plvDims;
0258 plvDims.geometry_id = slayer->geometryId().value();
0259 plvDims.volume_id = slayer->geometryId().volume();
0260 plvDims.layer_id = slayer->geometryId().layer();
0261 plvDims.min_v0 = volumeBoundValues[0];
0262 plvDims.max_v0 = volumeBoundValues[1];
0263 plvDims.min_v1 = volumeBoundValues[2];
0264 plvDims.max_v1 = volumeBoundValues[3];
0265 lvWriter.append(plvDims);
0266 }
0267
0268
0269 for (const auto& layer : layers) {
0270
0271
0272
0273 if (layer->layerType() == Acts::navigation) {
0274 ++layerIdx;
0275
0276 if (writeLayerVolume) {
0277 writeSurface(sfWriter, layer->surfaceRepresentation(), geoCtx);
0278 }
0279 continue;
0280
0281 } else {
0282
0283 const auto* rVolume = layer->representingVolume();
0284
0285
0286 if (rVolume != nullptr && writeLayerVolume && layers.size() > 3) {
0287
0288 std::vector<double> representingBoundValues =
0289 rVolume->volumeBounds().values();
0290 if (rVolume->volumeBounds().type() == Acts::VolumeBounds::eCylinder) {
0291 bool last = (layerIdx + 2 ==
0292 volume.confinedLayers()->arrayObjects().size());
0293 writeCylinderLayerVolume(lvWriter, *layer, rVolume->transform(),
0294 representingBoundValues, volumeBoundValues,
0295 lastBoundValues, last);
0296 }
0297 }
0298
0299
0300 if (layer->surfaceArray() != nullptr) {
0301 auto sfArray = layer->surfaceArray();
0302
0303
0304 if (writeSurfaceGrid) {
0305 SurfaceGridData sfGrid;
0306 sfGrid.geometry_id = layer->geometryId().value();
0307 sfGrid.volume_id = layer->geometryId().volume();
0308 sfGrid.layer_id = layer->geometryId().layer();
0309
0310
0311 auto binning = sfArray->binningValues();
0312 auto axes = sfArray->getAxes();
0313 if (!binning.empty() && binning.size() == 2 && axes.size() == 2) {
0314 auto loc0Values = axes[0]->getBinEdges();
0315 sfGrid.nbins_loc0 = loc0Values.size() - 1;
0316 sfGrid.type_loc0 = static_cast<int>(binning[0]);
0317 sfGrid.min_loc0 = loc0Values[0];
0318 sfGrid.max_loc0 = loc0Values[loc0Values.size() - 1];
0319
0320 auto loc1Values = axes[1]->getBinEdges();
0321 sfGrid.nbins_loc1 = loc1Values.size() - 1;
0322 sfGrid.type_loc1 = static_cast<int>(binning[1]);
0323 sfGrid.min_loc1 = loc1Values[0];
0324 sfGrid.max_loc1 = loc1Values[loc1Values.size() - 1];
0325 }
0326 sfGridWriter.append(sfGrid);
0327 }
0328
0329
0330 if (writeSensitive) {
0331 for (auto surface : sfArray->surfaces()) {
0332 if (surface != nullptr) {
0333 writeSurface(sfWriter, *surface, geoCtx);
0334 }
0335 }
0336 }
0337 } else {
0338
0339 writeSurface(sfWriter, layer->surfaceRepresentation(), geoCtx);
0340 }
0341 }
0342 ++layerIdx;
0343 }
0344
0345
0346 if (writeBoundary) {
0347 for (const auto& bsurface : volume.boundarySurfaces()) {
0348 writeBoundarySurface(sfWriter, *bsurface, geoCtx);
0349 }
0350 }
0351 }
0352
0353 if (volume.confinedVolumes()) {
0354 for (const auto& confined : volume.confinedVolumes()->arrayObjects()) {
0355 writeVolume(sfWriter, sfGridWriter, lvWriter, *confined, writeSensitive,
0356 writeBoundary, writeSurfaceGrid, writeLayerVolume, geoCtx);
0357 }
0358 }
0359 }
0360 }
0361
0362 ProcessCode CsvTrackingGeometryWriter::write(const AlgorithmContext& ctx) {
0363 if (!m_cfg.writePerEvent) {
0364 return ProcessCode::SUCCESS;
0365 }
0366
0367 SurfaceWriter sfWriter(
0368 perEventFilepath(m_cfg.outputDir, "detectors.csv", ctx.eventNumber),
0369 m_cfg.outputPrecision);
0370
0371 SurfaceGridWriter sfGridWriter(
0372 perEventFilepath(m_cfg.outputDir, "surface-grids.csv", ctx.eventNumber),
0373 m_cfg.outputPrecision);
0374
0375 LayerVolumeWriter lvWriter(
0376 perEventFilepath(m_cfg.outputDir, "layer-volumes.csv", ctx.eventNumber),
0377 m_cfg.outputPrecision);
0378
0379 writeVolume(sfWriter, sfGridWriter, lvWriter, *m_world, m_cfg.writeSensitive,
0380 m_cfg.writeBoundary, m_cfg.writeSurfaceGrid,
0381 m_cfg.writeLayerVolume, ctx.geoContext);
0382 return ProcessCode::SUCCESS;
0383 }
0384
0385 ProcessCode CsvTrackingGeometryWriter::finalize() {
0386 SurfaceWriter sfWriter(joinPaths(m_cfg.outputDir, "detectors.csv"),
0387 m_cfg.outputPrecision);
0388 SurfaceGridWriter sfGridWriter(
0389 joinPaths(m_cfg.outputDir, "surface-grids.csv"), m_cfg.outputPrecision);
0390
0391 LayerVolumeWriter lvWriter(joinPaths(m_cfg.outputDir, "layer-volumes.csv"),
0392 m_cfg.outputPrecision);
0393
0394 writeVolume(sfWriter, sfGridWriter, lvWriter, *m_world, m_cfg.writeSensitive,
0395 m_cfg.writeBoundary, m_cfg.writeSurfaceGrid,
0396 m_cfg.writeLayerVolume, Acts::GeometryContext());
0397 return ProcessCode::SUCCESS;
0398 }