diff --git a/compact/tracking/tof_barrel.xml b/compact/tracking/tof_barrel.xml
index d916f0265..7a1b6949a 100644
--- a/compact/tracking/tof_barrel.xml
+++ b/compact/tracking/tof_barrel.xml
@@ -68,6 +68,15 @@
+
+
+
+
+
+
+
+
+
@@ -89,8 +98,8 @@
Tracker Barrel Modules
-
-
+
+
@@ -140,8 +149,8 @@
-
- system:8,layer:4,module:12,sensor:2,x:32:-16,y:-16
+
+ system:8,layer:4,module:12,sensor:10,x:40:-8,y:-16
diff --git a/src/BarrelTOFTracker_geo.cpp b/src/BarrelTOFTracker_geo.cpp
new file mode 100644
index 000000000..6a9cf6c75
--- /dev/null
+++ b/src/BarrelTOFTracker_geo.cpp
@@ -0,0 +1,399 @@
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// Copyright (C) 2022 - 2024, Whitney Armstrong, Chun Yuen Tsang
+
+/** \addtogroup Trackers Trackers
+ * \brief Type: **TOFBarrel**.
+ * \author W. Armstrong
+ * \modified by C.Y Tsang 3rd Aug, 2024
+ *
+ * \ingroup trackers
+ *
+ * @{
+ */
+#include "DD4hep/DetFactoryHelper.h"
+#include "DD4hep/Printout.h"
+#include "DD4hep/Shapes.h"
+#include "DDRec/DetectorData.h"
+#include "DDRec/Surface.h"
+#include "XML/Layering.h"
+#include "XML/Utilities.h"
+#include
+#include
+#include "DD4hepDetectorHelper.h"
+
+using namespace std;
+using namespace dd4hep;
+using namespace dd4hep::rec;
+using namespace dd4hep::detail;
+
+/** Barrel Tracker with space frame.
+ *
+ * - Optional "support" tag within the detector element.
+ *
+ * The shapes are created using createShape which can be one of many basic geomtries.
+ * See the examples Check_shape_*.xml in
+ * [dd4hep's examples/ClientTests/compact](https://github.com/AIDASoft/DD4hep/tree/master/examples/ClientTests/compact)
+ * directory.
+ *
+ *
+ * - Optional "frame" tag within the module element.
+ *
+ * \ingroup trackers
+ *
+ * \code
+ * \endcode
+ *
+ *
+ * @author Whitney Armstrong
+ */
+static Ref_t create_TOFBarrel(Detector& description, xml_h e, SensitiveDetector sens) {
+ typedef vector Placements;
+ xml_det_t x_det = e;
+ Material air = description.air();
+ int det_id = x_det.id();
+ string det_name = x_det.nameStr();
+ DetElement sdet(det_name, det_id);
+
+ map volumes;
+ map sensitives;
+ map> volplane_surfaces;
+ map> module_thicknesses;
+
+ PlacedVolume pv;
+
+ // Set detector type flag
+ dd4hep::xml::setDetectorTypeFlag(x_det, sdet);
+ auto& params = DD4hepDetectorHelper::ensureExtension(sdet);
+
+ // Add the volume boundary material if configured
+ for (xml_coll_t bmat(x_det, _Unicode(boundary_material)); bmat; ++bmat) {
+ xml_comp_t x_boundary_material = bmat;
+ DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_boundary_material, params,
+ "boundary_material");
+ }
+
+ // dd4hep::xml::Dimension dimensions(x_det.dimensions());
+ // Tube topVolumeShape(dimensions.rmin(), dimensions.rmax(), dimensions.length() * 0.5);
+ // Volume assembly(det_name,topVolumeShape,air);
+ Assembly assembly(det_name);
+
+ sens.setType("tracker");
+
+ // Loop over the suports
+ for (xml_coll_t su(x_det, _U(support)); su; ++su) {
+ xml_comp_t x_support = su;
+ double support_thickness = getAttrOrDefault(x_support, _U(thickness), 2.0 * mm);
+ double support_length = getAttrOrDefault(x_support, _U(length), 2.0 * mm);
+ double support_rmin = getAttrOrDefault(x_support, _U(rmin), 2.0 * mm);
+ double support_zstart = getAttrOrDefault(x_support, _U(zstart), 2.0 * mm);
+ std::string support_name =
+ getAttrOrDefault(x_support, _Unicode(name), "support_tube");
+ std::string support_vis = getAttrOrDefault(x_support, _Unicode(vis), "AnlRed");
+ xml_dim_t pos(x_support.child(_U(position), false));
+ xml_dim_t rot(x_support.child(_U(rotation), false));
+ Solid support_solid;
+ if (x_support.hasChild(_U(shape))) {
+ xml_comp_t shape(x_support.child(_U(shape)));
+ string shape_type = shape.typeStr();
+ support_solid = xml::createShape(description, shape_type, shape);
+ } else {
+ support_solid = Tube(support_rmin, support_rmin + support_thickness, support_length / 2);
+ }
+ Transform3D tr =
+ Transform3D(Rotation3D(), Position(0, 0, (support_zstart + support_length / 2)));
+ if (pos.ptr() && rot.ptr()) {
+ Rotation3D rot3D(RotationZYX(rot.z(0), rot.y(0), rot.x(0)));
+ Position pos3D(pos.x(0), pos.y(0), pos.z(0));
+ tr = Transform3D(rot3D, pos3D);
+ } else if (pos.ptr()) {
+ tr = Transform3D(Rotation3D(), Position(pos.x(0), pos.y(0), pos.z(0)));
+ } else if (rot.ptr()) {
+ Rotation3D rot3D(RotationZYX(rot.z(0), rot.y(0), rot.x(0)));
+ tr = Transform3D(rot3D, Position());
+ }
+ Material support_mat = description.material(x_support.materialStr());
+ Volume support_vol(support_name, support_solid, support_mat);
+ support_vol.setVisAttributes(description.visAttributes(support_vis));
+ pv = assembly.placeVolume(support_vol, tr);
+ // pv = assembly.placeVolume(support_vol, Position(0, 0, support_zstart + support_length / 2));
+ }
+
+ // loop over the modules
+ for (xml_coll_t mi(x_det, _U(module)); mi; ++mi) {
+ xml_comp_t x_mod = mi;
+ string m_nam = x_mod.nameStr();
+
+ if (volumes.find(m_nam) != volumes.end()) {
+ printout(ERROR, "TOFBarrel",
+ string((string("Module with named ") + m_nam + string(" already exists."))).c_str());
+ throw runtime_error("Logics error in building modules.");
+ }
+
+ int ncomponents = 0;
+ int sensor_number = 1;
+ double total_thickness = 0;
+
+ // Compute module total thickness from components
+ xml_coll_t ci(x_mod, _U(module_component));
+ for (ci.reset(), total_thickness = 0.0; ci; ++ci) {
+ total_thickness += xml_comp_t(ci).thickness();
+ }
+ // the module assembly volume
+ Assembly m_vol(m_nam);
+ volumes[m_nam] = m_vol;
+ m_vol.setVisAttributes(description.visAttributes(x_mod.visStr()));
+
+ // Optional module frame.
+ if (x_mod.hasChild(_U(frame))) {
+ xml_comp_t m_frame = x_mod.child(_U(frame));
+ // xmleles[m_nam] = x_mod;
+ double frame_thickness = m_frame.thickness();
+ double frame_width = m_frame.width();
+ double frame_height = getAttrOrDefault(m_frame, _U(height), 5.0 * mm);
+ double tanth = frame_height / (frame_width / 2.0);
+ double costh = 1. / sqrt(1 + tanth * tanth);
+ double frame_height2 = frame_height - frame_thickness - frame_thickness / costh;
+ double frame_width2 = 2.0 * frame_height2 / tanth;
+
+ Trd1 moduleframe_part1(frame_width / 2, 0.001 * mm, m_frame.length() / 2, frame_height / 2);
+ Trd1 moduleframe_part2(frame_width2 / 2, 0.001 * mm, m_frame.length() / 2 + 0.01 * mm,
+ frame_height2 / 2);
+
+ SubtractionSolid moduleframe(moduleframe_part1, moduleframe_part2,
+ Position(0.0, frame_thickness, 0.0));
+ Volume v_moduleframe(m_nam + "_vol", moduleframe,
+ description.material(m_frame.materialStr()));
+ v_moduleframe.setVisAttributes(description, m_frame.visStr());
+ m_vol.placeVolume(v_moduleframe,
+ Position(0.0, 0.0, frame_height / 2 + total_thickness / 2.0));
+ }
+
+ double thickness_so_far = 0.0;
+ double thickness_sum = -total_thickness / 2.0;
+ for (xml_coll_t mci(x_mod, _U(module_component)); mci; ++mci) {
+ xml_comp_t x_comp = mci;
+ xml_comp_t x_pos = x_comp.position(false);
+ xml_comp_t x_rot = x_comp.rotation(false);
+ auto make_box = [&](double pos_x = 0, double pos_y = 0, double pos_z = 0, double rot_x = 0,
+ double rot_y = 0, double rot_z = 0, bool z_stacking = true) {
+ const string c_nam = _toString(ncomponents, "component%d");
+ ++ncomponents;
+ Box c_box(x_comp.width() / 2, x_comp.length() / 2, x_comp.thickness() / 2);
+ Volume c_vol(c_nam, c_box, description.material(x_comp.materialStr()));
+
+ // Utility variable for the relative z-offset based off the previous components
+ const double zoff = thickness_sum + x_comp.thickness() / 2.0;
+ Position c_pos(pos_x, pos_y, pos_z + zoff);
+ RotationZYX c_rot(rot_z, rot_y, rot_x);
+ pv = m_vol.placeVolume(c_vol, Transform3D(c_rot, c_pos));
+ c_vol.setRegion(description, x_comp.regionStr());
+ c_vol.setLimitSet(description, x_comp.limitsStr());
+ c_vol.setVisAttributes(description, x_comp.visStr());
+ if (x_comp.isSensitive()) {
+ pv.addPhysVolID("sensor", sensor_number++);
+ c_vol.setSensitiveDetector(sens);
+ sensitives[m_nam].push_back(pv);
+ module_thicknesses[m_nam] = {thickness_so_far + x_comp.thickness() / 2.0,
+ total_thickness - thickness_so_far -
+ x_comp.thickness() / 2.0};
+
+ // -------- create a measurement plane for the tracking surface attched to the sensitive volume -----
+ Vector3D u(-1., 0., 0.);
+ Vector3D v(0., -1., 0.);
+ Vector3D n(0., 0., 1.);
+ // Vector3D o( 0. , 0. , 0. ) ;
+
+ // compute the inner and outer thicknesses that need to be assigned to the tracking surface
+ // depending on wether the support is above or below the sensor
+ double inner_thickness = module_thicknesses[m_nam][0];
+ double outer_thickness = module_thicknesses[m_nam][1];
+
+ SurfaceType type(SurfaceType::Sensitive);
+
+ // if( isStripDetector )
+ // type.setProperty( SurfaceType::Measurement1D , true ) ;
+
+ VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); //,o ) ;
+ volplane_surfaces[m_nam].push_back(surf);
+
+ //--------------------------------------------
+ }
+ if (z_stacking) {
+ thickness_sum += x_comp.thickness();
+ thickness_so_far += x_comp.thickness();
+ // apply relative offsets in z-position used to stack components side-by-side
+ thickness_sum += pos_z;
+ thickness_so_far += pos_z;
+ }
+ };
+
+ double pos_x = 0, pos_y = 0, pos_z = 0;
+ double rot_x = 0, rot_y = 0, rot_z = 0;
+ if (x_rot) {
+ rot_x = x_rot.x(0);
+ rot_y = x_rot.y(0);
+ rot_z = x_rot.z(0);
+ }
+ if (x_pos) {
+ pos_x = x_pos.x(0);
+ pos_y = x_pos.y(0);
+ pos_z = x_pos.z(0);
+ }
+ if (x_comp.hasChild(_Unicode(GridSensors))) {
+ auto x_comp_t = x_comp.child(_Unicode(GridSensors));
+ // x-distance between centers of neighboring sensors
+ double sensors_xdist = getAttrOrDefault(x_comp_t, _Unicode(xdist), x_comp.width());
+ // y-distance between centers of neighboring sensors
+ double sensors_ydist = getAttrOrDefault(x_comp_t, _Unicode(ydist), x_comp.length());
+ // number of rows of sensors in a stave
+ int nsensors_x = getAttrOrDefault(x_comp_t, _Unicode(nx), 1);
+ // number of column of sensors in a stave
+ int nsensors_y = getAttrOrDefault(x_comp_t, _Unicode(ny), 1);
+ // x-location of the center of the leftmost sensor
+ double start_x = getAttrOrDefault(x_comp_t, _Unicode(start_x), 0);
+ // y-location of the center of the uppermost sensor
+ double start_y = getAttrOrDefault(x_comp_t, _Unicode(start_y), 0);
+ // z-locatino of the center of all sensors (All sensors appears at the same z-layer
+ double start_z = getAttrOrDefault(x_comp_t, _Unicode(start_z), 0);
+ // central ring is located to the right of the ny_before_ring th sensor
+ int ny_before_ring = getAttrOrDefault(x_comp_t, _Unicode(ny_before_ring), 0);
+ // Extra width caused by the ring
+ // |<--sensors_ydist-->|<--sensors_ydist-->|<-----ring_extra_width------->|<--sensors_ydist-->|
+ // || || ||
+ // ring_extra_width is the extra width between boundaries of the sensor boundaries (including dead space)
+ double ring_extra_width = getAttrOrDefault(x_comp_t, _Unicode(ring_extra_width), 0);
+
+ double current_x = start_x;
+ for (int nx = 0; nx < nsensors_x; ++nx) {
+ double current_y = start_y;
+ for (int ny = 0; ny < nsensors_y; ++ny) {
+ make_box(current_x, current_y, start_z, rot_x, rot_y, rot_z,
+ ((nx == nsensors_x - 1) &&
+ (ny == nsensors_y - 1))); // all sensors are located at the same z-layer
+ // increment z-layers only at the end, after the last sensor is added
+ current_y += sensors_ydist;
+ if (ny + 1 == ny_before_ring)
+ current_y += ring_extra_width;
+ }
+ current_x += sensors_xdist;
+ }
+ } else
+ make_box(pos_x, pos_y, pos_z, rot_x, rot_y, rot_z);
+ }
+ }
+
+ // now build the layers
+ for (xml_coll_t li(x_det, _U(layer)); li; ++li) {
+ xml_comp_t x_layer = li;
+ xml_comp_t x_barrel = x_layer.child(_U(barrel_envelope));
+ xml_comp_t x_layout = x_layer.child(_U(rphi_layout));
+ xml_comp_t z_layout = x_layer.child(_U(z_layout)); // Get the element.
+ int lay_id = x_layer.id();
+ string m_nam = x_layer.moduleStr();
+ string lay_nam = det_name + _toString(x_layer.id(), "_layer%d");
+ Tube lay_tub(x_barrel.inner_r(), x_barrel.outer_r(), x_barrel.z_length() / 2.0);
+ Volume lay_vol(lay_nam, lay_tub, air); // Create the layer envelope volume.
+ Position lay_pos(0, 0, getAttrOrDefault(x_barrel, _U(z0), 0.));
+ lay_vol.setVisAttributes(description.visAttributes(x_layer.visStr()));
+
+ double phi0 = x_layout.phi0(); // Starting phi of first module.
+ double phi_tilt = x_layout.phi_tilt(); // Phi tilt of a module.
+ double rc = x_layout.rc(); // Radius of the module center.
+ int nphi = x_layout.nphi(); // Number of modules in phi.
+ double rphi_dr = x_layout.dr(); // The delta radius of every other module.
+ double phi_incr = (M_PI * 2) / nphi; // Phi increment for one module.
+ double phic = phi0; // Phi of the module center.
+ double z0 = z_layout.z0(); // Z position of first module in phi.
+ double nz = z_layout.nz(); // Number of modules to place in z.
+ double z_dr = z_layout.dr(); // Radial displacement parameter, of every other module.
+
+ Volume module_env = volumes[m_nam];
+ DetElement lay_elt(sdet, lay_nam, lay_id);
+ Placements& sensVols = sensitives[m_nam];
+
+ // the local coordinate systems of modules in dd4hep and acts differ
+ // see http://acts.web.cern.ch/ACTS/latest/doc/group__DD4hepPlugins.html
+ auto& layerParams =
+ DD4hepDetectorHelper::ensureExtension(lay_elt);
+
+ for (xml_coll_t lmat(x_layer, _Unicode(layer_material)); lmat; ++lmat) {
+ xml_comp_t x_layer_material = lmat;
+ DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_layer_material, layerParams,
+ "layer_material");
+ }
+
+ // Z increment for module placement along Z axis.
+ // Adjust for z0 at center of module rather than
+ // the end of cylindrical envelope.
+ double z_incr = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0;
+ // Starting z for module placement along Z axis.
+ double module_z = -z0;
+ int module = 1;
+
+ // Loop over the number of modules in phi.
+ for (int ii = 0; ii < nphi; ii++) {
+ double dx = z_dr * std::cos(phic + phi_tilt); // Delta x of module position.
+ double dy = z_dr * std::sin(phic + phi_tilt); // Delta y of module position.
+ double x = rc * std::cos(phic); // Basic x module position.
+ double y = rc * std::sin(phic); // Basic y module position.
+
+ // Loop over the number of modules in z.
+ for (int j = 0; j < nz; j++) {
+ string module_name = _toString(module, "module%d");
+ DetElement mod_elt(lay_elt, module_name, module);
+
+ Transform3D tr(RotationZYX(0, ((M_PI / 2) - phic - phi_tilt), -M_PI / 2),
+ Position(x, y, module_z));
+
+ pv = lay_vol.placeVolume(module_env, tr);
+ pv.addPhysVolID("module", module);
+ mod_elt.setPlacement(pv);
+ for (size_t ic = 0; ic < sensVols.size(); ++ic) {
+ PlacedVolume sens_pv = sensVols[ic];
+ DetElement comp_de(mod_elt, std::string("de_") + sens_pv.volume().name(), module);
+ comp_de.setPlacement(sens_pv);
+
+ auto& comp_de_params =
+ DD4hepDetectorHelper::ensureExtension(comp_de);
+ comp_de_params.set("axis_definitions", "XYZ");
+ // comp_de.setAttributes(description, sens_pv.volume(), x_layer.regionStr(), x_layer.limitsStr(),
+ // xml_det_t(xmleles[m_nam]).visStr());
+ //
+
+ volSurfaceList(comp_de)->push_back(volplane_surfaces[m_nam][ic]);
+ }
+
+ /// Increase counters etc.
+ module++;
+ // Adjust the x and y coordinates of the module.
+ x += dx;
+ y += dy;
+ // Flip sign of x and y adjustments.
+ dx *= -1;
+ dy *= -1;
+ // Add z increment to get next z placement pos.
+ module_z += z_incr;
+ }
+ phic += phi_incr; // Increment the phi placement of module.
+ rc += rphi_dr; // Increment the center radius according to dr parameter.
+ rphi_dr *= -1; // Flip sign of dr parameter.
+ module_z = -z0; // Reset the Z placement parameter for module.
+ }
+ // Create the PhysicalVolume for the layer.
+ pv = assembly.placeVolume(lay_vol, lay_pos); // Place layer in mother
+ pv.addPhysVolID("layer", lay_id); // Set the layer ID.
+ lay_elt.setAttributes(description, lay_vol, x_layer.regionStr(), x_layer.limitsStr(),
+ x_layer.visStr());
+ lay_elt.setPlacement(pv);
+ }
+ sdet.setAttributes(description, assembly, x_det.regionStr(), x_det.limitsStr(), x_det.visStr());
+ assembly.setVisAttributes(description.invisible());
+ pv = description.pickMotherVolume(sdet).placeVolume(assembly);
+ pv.addPhysVolID("system", det_id); // Set the subdetector system ID.
+ sdet.setPlacement(pv);
+ return sdet;
+}
+
+//@}
+// clang-format off
+DECLARE_DETELEMENT(epic_TOFBarrel, create_TOFBarrel)
diff --git a/src/BarrelTrackerWithFrame_geo.cpp b/src/BarrelTrackerWithFrame_geo.cpp
index e8fa910c0..0d0665279 100644
--- a/src/BarrelTrackerWithFrame_geo.cpp
+++ b/src/BarrelTrackerWithFrame_geo.cpp
@@ -349,5 +349,4 @@ static Ref_t create_BarrelTrackerWithFrame(Detector& description, xml_h e, Sensi
DECLARE_DETELEMENT(epic_BarrelTrackerWithFrame, create_BarrelTrackerWithFrame)
DECLARE_DETELEMENT(epic_TrackerBarrel, create_BarrelTrackerWithFrame)
DECLARE_DETELEMENT(epic_VertexBarrel, create_BarrelTrackerWithFrame)
-DECLARE_DETELEMENT(epic_TOFBarrel, create_BarrelTrackerWithFrame)
DECLARE_DETELEMENT(epic_InnerMPGDBarrel, create_BarrelTrackerWithFrame)