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)
|