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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
|
// #include "Math/GenVector/Rotation3D.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include "FWCore/Utilities/interface/Parse.h"
#include "Alignment/CommonAlignment/interface/Utilities.h"
align::EulerAngles align::toAngles(const RotationType& rot) {
const Scalar one = 1; // to ensure same precison is used in comparison
EulerAngles angles(3);
if (std::abs(rot.zx()) > one) {
edm::LogWarning("Alignment") << "Rounding errors in\n" << rot;
}
if (std::abs(rot.zx()) < one) {
angles(1) = -std::atan2(rot.zy(), rot.zz());
angles(2) = std::asin(rot.zx());
angles(3) = -std::atan2(rot.yx(), rot.xx());
} else if (rot.zx() >= one) {
angles(1) = std::atan2(rot.xy() + rot.yz(), rot.yy() - rot.xz());
angles(2) = std::asin(one);
angles(3) = 0;
} else if (rot.zx() <= -one) {
angles(1) = std::atan2(rot.xy() - rot.yz(), rot.yy() + rot.xz());
angles(2) = std::asin(-one);
angles(3) = 0;
}
return angles;
}
align::RotationType align::toMatrix(const EulerAngles& angles) {
Scalar s1 = std::sin(angles[0]), c1 = std::cos(angles[0]);
Scalar s2 = std::sin(angles[1]), c2 = std::cos(angles[1]);
Scalar s3 = std::sin(angles[2]), c3 = std::cos(angles[2]);
return RotationType(c2 * c3,
c1 * s3 + s1 * s2 * c3,
s1 * s3 - c1 * s2 * c3,
-c2 * s3,
c1 * c3 - s1 * s2 * s3,
s1 * c3 + c1 * s2 * s3,
s2,
-s1 * c2,
c1 * c2);
}
align::PositionType align::motherPosition(const std::vector<const PositionType*>& dauPos) {
unsigned int nDau = dauPos.size();
Scalar posX(0.), posY(0.), posZ(0.); // position of mother
for (unsigned int i = 0; i < nDau; ++i) {
const PositionType* point = dauPos[i];
posX += point->x();
posY += point->y();
posZ += point->z();
}
Scalar inv = 1. / static_cast<Scalar>(nDau);
return PositionType(posX * inv, posY * inv, posZ * inv);
}
align::RotationType align::diffRot(const GlobalVectors& current, const GlobalVectors& nominal) {
// Find the matrix needed to rotate the nominal surface to the current one
// using small angle approximation through the equation:
//
// I * dOmega = dr * r (sum over points)
//
// where dOmega is a vector of small rotation angles about (x, y, z)-axes,
// and I is the inertia tensor defined as
//
// I_ij = delta_ij * r^2 - r_i * r_j (sum over points)
//
// delta_ij is the identity matrix. i, j are indices for (x, y, z).
//
// On the rhs of the first eq, r * dr is the cross product of r and dr.
// In this case, r is the nominal vector and dr is the displacement of the
// current point from its nominal point (current vector - nominal vector).
//
// Since the solution of dOmega (by inverting I) gives angles that are small,
// we rotate the current surface by -dOmega and repeat the process until the
// dOmega^2 is less than a certain tolerance value.
// (In other words, we move the current surface by small angular steps till
// it matches the nominal surface.)
// The full rotation is found by adding up the rotations (given by dOmega)
// in each step. (More precisely, the product of all the matrices.)
//
// Note that, in some cases, if the angular displacement between current and
// nominal is pi, the algorithm can return an identity (no rotation).
// This is because dr = -r and r * dr is all zero.
// This is not a problem since we are dealing with small angles in alignment.
static const double tolerance = 1e-12;
RotationType rot; // rotation from nominal to current; init to identity
// Initial values for dr and I; I is always the same in each step
AlgebraicSymMatrix I(3); // inertia tensor
GlobalVectors rotated = current; // rotated current vectors in each step
unsigned int nPoints = nominal.size();
for (unsigned int j = 0; j < nPoints; ++j) {
const GlobalVector& r = nominal[j];
// Inertial tensor: I_ij = delta_ij * r^2 - r_i * r_j (sum over points)
I.fast(1, 1) += r.y() * r.y() + r.z() * r.z();
I.fast(2, 2) += r.x() * r.x() + r.z() * r.z();
I.fast(3, 3) += r.y() * r.y() + r.x() * r.x();
I.fast(2, 1) -= r.x() * r.y(); // row index must be >= col index
I.fast(3, 1) -= r.x() * r.z();
I.fast(3, 2) -= r.y() * r.z();
}
int count = 0;
while (true) {
AlgebraicVector rhs(3); // sum of dr * r
for (unsigned int j = 0; j < nPoints; ++j) {
const GlobalVector& r = nominal[j];
const GlobalVector& c = rotated[j];
// Cross product of dr * r = c * r (sum over points)
rhs(1) += c.y() * r.z() - c.z() * r.y();
rhs(2) += c.z() * r.x() - c.x() * r.z();
rhs(3) += c.x() * r.y() - c.y() * r.x();
}
EulerAngles dOmega = CLHEP::solve(I, rhs);
rot *= toMatrix(dOmega); // add to rotation
if (dOmega.normsq() < tolerance)
break; // converges, so exit loop
count++;
if (count > 100000) {
std::cout << "diffRot infinite loop: dOmega is " << dOmega.normsq() << "\n";
break;
}
// Not yet converge; move current vectors to new positions and find dr
for (unsigned int j = 0; j < nPoints; ++j) {
rotated[j] = GlobalVector(rot.multiplyInverse(current[j].basicVector()));
}
}
return rot;
}
align::GlobalVector align::diffR(const GlobalVectors& current, const GlobalVectors& nominal) {
GlobalVector nCM(0, 0, 0);
GlobalVector cCM(0, 0, 0);
unsigned int nPoints = nominal.size();
for (unsigned int j = 0; j < nPoints; ++j) {
nCM += nominal[j];
cCM += current[j];
}
nCM -= cCM;
return nCM /= static_cast<Scalar>(nPoints);
}
align::GlobalVector align::centerOfMass(const GlobalVectors& theVs) {
unsigned int nPoints = theVs.size();
GlobalVector CM(0, 0, 0);
for (unsigned int j = 0; j < nPoints; ++j)
CM += theVs[j];
return CM /= static_cast<Scalar>(nPoints);
}
void align::rectify(RotationType& rot) {
// Use ROOT for better numerical precision but slower.
// ROOT::Math::Rotation3D temp( rot.xx(), rot.xy(), rot.xz(),
// rot.yx(), rot.yy(), rot.yz(),
// rot.zx(), rot.zy(), rot.zz() );
//
// temp.Rectify();
//
// Scalar elems[9];
//
// temp.GetComponents(elems);
// rot = RotationType(elems);
rot = toMatrix(toAngles(rot)); // fast rectification but less precise
}
align::RunRanges align::makeNonOverlappingRunRanges(const edm::VParameterSet& runRanges, const RunNumber& defaultRun) {
const auto beginValue = cond::timeTypeSpecs[cond::runnumber].beginValue;
const auto endValue = cond::timeTypeSpecs[cond::runnumber].endValue;
RunRanges uniqueRunRanges;
if (!runRanges.empty()) {
std::map<RunNumber, RunNumber> uniqueFirstRunNumbers;
for (const auto& ipset : runRanges) {
const auto RunRangeStrings = ipset.getParameter<std::vector<std::string> >("RunRanges");
for (const auto& irange : RunRangeStrings) {
if (irange.find(':') == std::string::npos) {
long int temp{strtol(irange.c_str(), nullptr, 0)};
auto first = (temp != -1) ? temp : beginValue;
uniqueFirstRunNumbers[first] = first;
} else {
edm::LogWarning("BadConfig") << "@SUB=align::makeNonOverlappingRunRanges"
<< "Config file contains old format for 'RunRangeSelection'. Only "
<< "the start run number is used internally. The number of the last"
<< " run is ignored and can besafely removed from the config file.";
auto tokens = edm::tokenize(irange, ":");
long int temp{strtol(tokens[0].c_str(), nullptr, 0)};
auto first = (temp != -1) ? temp : beginValue;
uniqueFirstRunNumbers[first] = first;
}
}
}
for (const auto& iFirst : uniqueFirstRunNumbers) {
uniqueRunRanges.push_back(std::make_pair(iFirst.first, endValue));
}
for (unsigned int i = 0; i < uniqueRunRanges.size() - 1; ++i) {
uniqueRunRanges[i].second = uniqueRunRanges[i + 1].first - 1;
}
} else {
uniqueRunRanges.push_back(std::make_pair(defaultRun, endValue));
}
return uniqueRunRanges;
}
align::RunRanges align::makeUniqueRunRanges(const edm::VParameterSet& runRanges, const RunNumber& defaultRun) {
auto uniqueRunRanges = align::makeNonOverlappingRunRanges(runRanges, defaultRun);
if (uniqueRunRanges.empty()) { // create dummy IOV
const RunRange runRange(defaultRun, cond::timeTypeSpecs[cond::runnumber].endValue);
uniqueRunRanges.push_back(runRange);
}
return uniqueRunRanges;
}
|