Section

ddcms_det_element_DDCMS_track_DDCutTubsFromPoints

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
#include "DD4hep/DetFactoryHelper.h"
#include "DetectorDescription/DDCMS/interface/DDPlugins.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"

#include "DataFormats/Math/interface/CMSUnits.h"

using namespace cms_units::operators;  // _deg and convertRadToDeg

static long algorithm(dd4hep::Detector& /* description */, cms::DDParsingContext& ctxt, xml_h e) {
  cms::DDNamespace ns(ctxt, e, true);
  cms::DDAlgoArguments args(ctxt, e);

  dd4hep::Volume mother = ns.volume(args.parentName());

  struct Section {
    float phi;  // phi position of this edge
    float z_l;  // -Z end (cuttubs l plane)
    float z_t;  // +Z end (cuttubs t plane)
    // radius is implicitly r_min
  };

  std::vector<Section> sections;

  float r_min = args.value<float>("rMin");
  float r_max = args.value<float>("rMax");
  float z_pos = args.value<float>("zPos");

  std::string solidOutput = args.value<std::string>("SolidName");
  const std::string material = args.value<std::string>("Material");

  auto phis = ns.vecFloat(args.str("Phi"));
  auto z_ls = ns.vecFloat(args.str("z_l"));
  auto z_ts = ns.vecFloat(args.str("z_t"));

  assert(phis.size() == z_ls.size());
  assert(phis.size() == z_ts.size());

  for (unsigned i = 0; i < phis.size(); i++) {
    Section s = {phis[i], z_ls[i], z_ts[i]};

    edm::LogVerbatim("TrackerGeom") << "DDCutTubsFromPoints: Sections :" << phis[i] << " , " << z_ls[i] << " , "
                                    << z_ts[i];
    sections.emplace_back(s);
  }

  assert(!sections.empty());

  // a segment is produced between each two consecutive sections that have a
  // non-zero phi distance. Sections with zero phi distance can be used to
  // create sharp jumps.

  solidOutput = ns.prepend(solidOutput);
  edm::LogVerbatim("TrackerGeom") << "DDCutTubsFromPoints debug: Parent " << args.parentName() << "\tSolid "
                                  << solidOutput << " NameSpace " << ns.name() << "\tnumber of sections "
                                  << sections.size();

  // radius for plane calculations
  // We use r_max here, since P3 later has a Z that is always more inside
  // than the extreme points. This means the cutting planes have outwards
  // slopes in r-Z, and the corner at r_max could stick out of the bounding
  // volume otherwise.
  float r = r_max;

  // min and max z for the placement in the end
  float min_z = 1e9;
  float max_z = -1e9;

  // counter of actually produced segments (excluding skipped ones)
  int segment = 0;

  // the segments and their corresponding offset (absolute, as in the input)
  std::vector<dd4hep::Solid> segments;
  std::vector<float> offsets;

  Section s1 = sections[0];

  for (Section s2 : sections) {
    if (s1.phi != s2.phi) {
      segment++;
      // produce segment s1-s2.
      float phi1 = s1.phi;
      float phi2 = s2.phi;

      // track the min/max to properly place&align later
      if (s2.z_l < min_z)
        min_z = s2.z_l;
      if (s2.z_t > max_z)
        max_z = s2.z_t;

      float P1_z_l = s1.z_l;
      float P1_z_t = s1.z_t;
      float P2_z_l = s2.z_l;
      float P2_z_t = s2.z_t;

      float P1_x_t = cos(phi1) * r;
      float P1_x_l = cos(phi1) * r;
      float P1_y_t = sin(phi1) * r;
      float P1_y_l = sin(phi1) * r;

      float P2_x_t = cos(phi2) * r;
      float P2_x_l = cos(phi2) * r;
      float P2_y_t = sin(phi2) * r;
      float P2_y_l = sin(phi2) * r;

      // each cutting plane is defined by P1-3. P1-2 are corners of the
      // segment, P3 is at r=0 with the "average" z to get a nice cut.
      float P3_z_l = (P1_z_l + P2_z_l) / 2;
      float P3_z_t = (P1_z_t + P2_z_t) / 2;

      std::string segname(solidOutput + "_seg_" + std::to_string(segment));
      edm::LogVerbatim("TrackerGeom").log([&](auto& log) {
        log << "DDCutTubsFromPoints: P1 l: " << segname << P1_x_l << " , " << P1_y_l << " , " << P1_z_l;
        log << "DDCutTubsFromPoints: P1 t: " << segname << P1_x_t << " , " << P1_y_t << " , " << P1_z_t;
        log << "DDCutTubsFromPoints: P2 l: " << segname << P2_x_l << " , " << P2_y_l << " , " << P2_z_l;
        log << "DDCutTubsFromPoints: P2 t: " << segname << P2_x_t << " , " << P2_y_t << " , " << P2_z_t;
      });

      // we only have one dz to position both planes. The anchor is implicitly
      // between the P3's, we have to use an offset later to make the segments
      // line up correctly.
      float dz = 0.5 * (P3_z_t - P3_z_l);
      float offset = 0.5 * (P3_z_t + P3_z_l);

      // the plane is defined by P1-P3 and P2-P3; since P3 is at r=0 we
      // only need the z.
      float D1_z_l = P1_z_l - P3_z_l;
      float D2_z_l = P2_z_l - P3_z_l;

      // the normal is then the cross product...
      float n_x_l = (P1_y_l * D2_z_l) - (D1_z_l * P2_y_l);
      float n_y_l = (D1_z_l * P2_x_l) - (P1_x_l * D2_z_l);
      float n_z_l = (P1_x_l * P2_y_l) - (P1_y_l * P2_x_l);

      edm::LogVerbatim("TrackerGeom") << "DDCutTubsFromPoints: l_Pos (" << n_x_l << "," << n_y_l << "," << n_z_l << ")";

      // ... normalized.
      // flip the sign here (but not for t) since root wants it like that.
      float norm = -sqrt(n_x_l * n_x_l + n_y_l * n_y_l + n_z_l * n_z_l);
      n_x_l /= norm;
      n_y_l /= norm;
      n_z_l /= norm;

      edm::LogVerbatim("TrackerGeom") << "DDCutTubsFromPoints: l_norm " << norm;

      // same game for the t side.
      float D1_z_t = P1_z_t - P3_z_t;
      float D2_z_t = P2_z_t - P3_z_t;

      float n_x_t = (P1_y_t * D2_z_t) - (D1_z_t * P2_y_t);
      float n_y_t = (D1_z_t * P2_x_t) - (P1_x_t * D2_z_t);
      float n_z_t = (P1_x_t * P2_y_t) - (P1_y_t * P2_x_t);

      edm::LogVerbatim("TrackerGeom") << "DDCutTubsFromPoints: t_Pos (" << n_x_t << "," << n_y_t << "," << n_z_t << ")";

      norm = sqrt(n_x_t * n_x_t + n_y_t * n_y_t + n_z_t * n_z_t);

      edm::LogVerbatim("TrackerGeom") << "DDCutTubsFromPoints: t_norm " << norm;

      n_x_t /= norm;
      n_y_t /= norm;
      n_z_t /= norm;

      auto seg = dd4hep::CutTube(segname, r_min, r_max, dz, phi1, phi2, n_x_l, n_y_l, n_z_l, n_x_t, n_y_t, n_z_t);

      edm::LogVerbatim("TrackerGeom") << "DDCutTubsFromPoints: CutTube(" << r_min << "," << r_max << "," << dz << ","
                                      << phi1 << "," << phi2 << "," << n_x_l << "," << n_y_l << "," << n_z_l << ","
                                      << n_x_t << "," << n_y_t << "," << n_z_t << ")";

      segments.emplace_back(seg);
      offsets.emplace_back(offset);
    }

    s1 = s2;
  }

  assert(segments.size() >= 2);  // less would be special cases

  dd4hep::Solid solid = segments[0];

  // placement happens relative to the first member of the union
  float shift = offsets[0];

  for (unsigned i = 1; i < segments.size() - 1; i++) {
    solid = dd4hep::UnionSolid(solidOutput + "_uni_" + std::to_string(i + 1),
                               solid,
                               segments[i],
                               dd4hep::Position(0., 0., offsets[i] - shift));
  }

  solid = dd4hep::UnionSolid(solidOutput,
                             solid,
                             segments[segments.size() - 1],
                             dd4hep::Position(0., 0., offsets[segments.size() - 1] - shift));

  edm::LogVerbatim("TrackerGeom") << "DDCutTubsFromPoints: " << solid.name() << " Union solid with " << segments.size()
                                  << " segments";

  // remove the common offset from the input, to get sth. aligned at z=0.
  float offset = -shift + (min_z + 0.5 * (max_z - min_z));

  auto logical = dd4hep::Volume(solidOutput, solid, ns.material(material));

  int nCopy = 1;
  auto pos = dd4hep::Position(0., 0., z_pos - offset);
  mother.placeVolume(logical, nCopy, dd4hep::Transform3D(dd4hep::Rotation3D(), pos));

  mother.placeVolume(logical, nCopy + 1, dd4hep::Transform3D(ns.rotation("pixfwdCommon:Z180"), pos));

  return cms::s_executed;
}

// first argument is the type from the xml file
DECLARE_DDCMS_DETELEMENT(DDCMS_track_DDCutTubsFromPoints, algorithm)