Skip to content

Commit e05587d

Browse files
committed
Fix bugs in the Kalman fitter
1 parent 9166d9f commit e05587d

File tree

11 files changed

+218
-70
lines changed

11 files changed

+218
-70
lines changed

core/include/traccc/edm/track_parameters.hpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "traccc/definitions/qualifiers.hpp"
1515
#include "traccc/definitions/track_parametrization.hpp"
1616
#include "traccc/edm/container.hpp"
17+
#include "traccc/utils/trigonometric_helpers.hpp"
1718

1819
// detray include(s).
1920
#include <detray/tracks/tracks.hpp>
@@ -48,19 +49,15 @@ using bound_track_parameters_collection_types =
4849

4950
// Wrap the phi of track parameters to [-pi,pi]
5051
template <detray::concepts::algebra algebra_t>
51-
TRACCC_HOST_DEVICE inline void wrap_phi(
52+
TRACCC_HOST_DEVICE constexpr void normalize_angles(
5253
bound_track_parameters<algebra_t>& param) {
54+
traccc::scalar phi;
55+
traccc::scalar theta;
56+
57+
std::tie(phi, theta) = detail::wrap_phi_theta(param.phi(), param.theta());
5358

54-
traccc::scalar phi = param.phi();
55-
static constexpr traccc::scalar TWOPI =
56-
2.f * traccc::constant<traccc::scalar>::pi;
57-
phi = math::fmod(phi, TWOPI);
58-
if (phi > traccc::constant<traccc::scalar>::pi) {
59-
phi -= TWOPI;
60-
} else if (phi < -traccc::constant<traccc::scalar>::pi) {
61-
phi += TWOPI;
62-
}
6359
param.set_phi(phi);
60+
param.set_theta(theta);
6461
}
6562

6663
/// Covariance inflation used for track fitting

core/include/traccc/finding/details/combinatorial_kalman_filter.hpp

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -536,11 +536,30 @@ combinatorial_kalman_filter(
536536
assert(propagation._navigation.is_on_sensitive());
537537
assert(!propagation._stepping.bound_params().is_invalid());
538538

539-
out_params.push_back(propagation._stepping.bound_params());
540-
out_prop_data.emplace_back(
541-
s5.prev_surface_index,
542-
propagation._navigation.is_edge_candidate());
543-
param_to_link[step].push_back(link_id);
539+
const auto& out_param = propagation._stepping.bound_params();
540+
541+
bool valid_track{true};
542+
const scalar theta = out_param.theta();
543+
if (theta <= 0.f ||
544+
theta >= 2.f * constant<traccc::scalar>::pi) {
545+
valid_track = false;
546+
}
547+
548+
if (!std::isfinite(out_param.phi())) {
549+
valid_track = false;
550+
}
551+
552+
if (std::abs(out_param.qop()) == 0.f) {
553+
valid_track = false;
554+
}
555+
556+
if (valid_track) {
557+
out_params.push_back(out_param);
558+
out_prop_data.emplace_back(
559+
s5.prev_surface_index,
560+
propagation._navigation.is_edge_candidate());
561+
param_to_link[step].push_back(link_id);
562+
}
544563
}
545564
// Unless the track found a surface, it is considered a
546565
// tip

core/include/traccc/finding/propagation_data.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ struct propagation_data {
2323
bool is_edge{false};
2424
};
2525

26-
} // namespace traccc
26+
} // namespace traccc

core/include/traccc/fitting/fitting_config.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct fitting_config {
3434
std::size_t barcode_sequence_size_factor = 5;
3535
std::size_t min_barcode_sequence_capacity = 100;
3636
traccc::scalar backward_filter_mask_tolerance =
37-
5.f * traccc::unit<scalar>::mm;
37+
10.f * traccc::unit<scalar>::m;
3838
};
3939

4040
} // namespace traccc

core/include/traccc/fitting/kalman_filter/gain_matrix_updater.hpp

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,19 @@ struct gain_matrix_updater {
123123
predicted_vec + K * (meas_local - H * predicted_vec);
124124
const matrix_type<6, 6> filtered_cov = (I66 - K * H) * predicted_cov;
125125

126+
// Return false if track is parallel to z-axis or phi is not finite
127+
if (!std::isfinite(getter::element(filtered_vec, e_bound_theta, 0))) {
128+
return kalman_fitter_status::ERROR_INVERSION;
129+
}
130+
131+
if (!std::isfinite(getter::element(filtered_vec, e_bound_phi, 0))) {
132+
return kalman_fitter_status::ERROR_INVERSION;
133+
}
134+
135+
if (std::abs(getter::element(filtered_vec, e_bound_qoverp, 0)) == 0.f) {
136+
return kalman_fitter_status::ERROR_QOP_ZERO;
137+
}
138+
126139
// Residual between measurement and (projected) filtered vector
127140
const matrix_type<D, 1> residual = meas_local - H * filtered_vec;
128141

@@ -133,36 +146,28 @@ struct gain_matrix_updater {
133146
residual, matrix::inverse(R)) *
134147
residual;
135148

136-
// Return false if track is parallel to z-axis or phi is not finite
137-
const scalar theta = bound_params.theta();
149+
const scalar chi2_val{getter::element(chi2, 0, 0)};
138150

139-
if (theta <= 0.f || theta >= constant<traccc::scalar>::pi) {
140-
return kalman_fitter_status::ERROR_THETA_ZERO;
141-
}
142-
143-
if (!std::isfinite(bound_params.phi())) {
144-
return kalman_fitter_status::ERROR_INVERSION;
145-
}
146-
147-
if (std::abs(bound_params.qop()) == 0.f) {
148-
return kalman_fitter_status::ERROR_QOP_ZERO;
149-
}
150-
151-
if (getter::element(chi2, 0, 0) < 0.f) {
151+
if (chi2_val < 0.f) {
152152
return kalman_fitter_status::ERROR_UPDATER_CHI2_NEGATIVE;
153153
}
154154

155-
if (!std::isfinite(getter::element(chi2, 0, 0))) {
155+
if (!std::isfinite(chi2_val)) {
156156
return kalman_fitter_status::ERROR_UPDATER_CHI2_NOT_FINITE;
157157
}
158158

159-
// Set the track state parameters
159+
// Set the chi2 for this track and measurement
160160
trk_state.filtered_params().set_vector(filtered_vec);
161161
trk_state.filtered_params().set_covariance(filtered_cov);
162-
trk_state.filtered_chi2() = getter::element(chi2, 0, 0);
162+
trk_state.filtered_chi2() = chi2_val;
163163

164-
// Wrap the phi in the range of [-pi, pi]
165-
wrap_phi(trk_state.filtered_params());
164+
// Wrap the phi and theta angles in their valid ranges
165+
normalize_angles(trk_state.filtered_params());
166+
167+
const scalar theta = trk_state.filtered_params().theta();
168+
if (theta <= 0.f || theta >= 2.f * constant<traccc::scalar>::pi) {
169+
return kalman_fitter_status::ERROR_THETA_POLE;
170+
}
166171

167172
assert(!trk_state.filtered_params().is_invalid());
168173

core/include/traccc/fitting/kalman_filter/kalman_actor.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ struct kalman_actor : detray::actor {
170170
kalman_actor_direction::FORWARD_ONLY ||
171171
direction_e ==
172172
kalman_actor_direction::BIDIRECTIONAL) {
173+
// Wrap the phi and theta angles in their valid ranges
174+
normalize_angles(propagation._stepping.bound_params());
173175
// Forward filter
174176
res = gain_matrix_updater<algebra_t>{}(
175177
trk_state, actor_state.m_measurements,

core/include/traccc/fitting/kalman_filter/kalman_fitter.hpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,16 +280,20 @@ class kalman_fitter {
280280
}
281281

282282
auto last = fitter_state.m_fit_actor_state();
283-
284283
const scalar theta = last.filtered_params().theta();
285-
if (theta <= 0.f || theta >= constant<traccc::scalar>::pi) {
286-
return kalman_fitter_status::ERROR_THETA_ZERO;
284+
285+
if (!std::isfinite(last.filtered_params().theta())) {
286+
return kalman_fitter_status::ERROR_INVERSION;
287287
}
288288

289289
if (!std::isfinite(last.filtered_params().phi())) {
290290
return kalman_fitter_status::ERROR_INVERSION;
291291
}
292292

293+
if (theta <= 0.f || theta >= 2.f * constant<traccc::scalar>::pi) {
294+
return kalman_fitter_status::ERROR_THETA_POLE;
295+
}
296+
293297
last.smoothed_params().set_parameter_vector(last.filtered_params());
294298
last.smoothed_params().set_covariance(
295299
last.filtered_params().covariance());
@@ -327,6 +331,8 @@ class kalman_fitter {
327331

328332
propagation._navigation.set_direction(
329333
detray::navigation::direction::e_backward);
334+
propagation._navigation.safe_step_size =
335+
10.f * traccc::unit<scalar>::um;
330336

331337
// Synchronize the current barcode with the input track parameter
332338
while (propagation._navigation.get_target_barcode() !=

core/include/traccc/fitting/kalman_filter/two_filters_smoother.hpp

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,25 @@ struct two_filters_smoother {
107107
predicted_cov_inv * predicted_vec);
108108

109109
trk_state.smoothed_params().set_vector(smoothed_vec);
110+
111+
// Return false if track is parallel to z-axis or phi is not finite
112+
if (!std::isfinite(trk_state.smoothed_params().theta())) {
113+
return kalman_fitter_status::ERROR_INVERSION;
114+
}
115+
116+
if (!std::isfinite(trk_state.smoothed_params().phi())) {
117+
return kalman_fitter_status::ERROR_INVERSION;
118+
}
119+
120+
if (std::abs(trk_state.smoothed_params().qop()) == 0.f) {
121+
return kalman_fitter_status::ERROR_QOP_ZERO;
122+
}
123+
110124
trk_state.smoothed_params().set_covariance(smoothed_cov);
111125

126+
// Wrap the phi and theta angles in their valid ranges
127+
normalize_angles(trk_state.smoothed_params());
128+
112129
matrix_type<D, e_bound_size> H =
113130
measurements.at(trk_state.measurement_index())
114131
.subs.template projector<D>();
@@ -141,11 +158,13 @@ struct two_filters_smoother {
141158
residual_smt, matrix::inverse(R_smt)) *
142159
residual_smt;
143160

144-
if (getter::element(chi2_smt, 0, 0) < 0.f) {
161+
const scalar chi2_smt_value{getter::element(chi2_smt, 0, 0)};
162+
163+
if (chi2_smt_value < 0.f) {
145164
return kalman_fitter_status::ERROR_SMOOTHER_CHI2_NEGATIVE;
146165
}
147166

148-
if (!std::isfinite(getter::element(chi2_smt, 0, 0))) {
167+
if (!std::isfinite(chi2_smt_value)) {
149168
return kalman_fitter_status::ERROR_SMOOTHER_CHI2_NOT_FINITE;
150169
}
151170

@@ -180,26 +199,12 @@ struct two_filters_smoother {
180199
predicted_vec + K * (meas_local - H * predicted_vec);
181200
const matrix_type<6, 6> filtered_cov = (I66 - K * H) * predicted_cov;
182201

183-
// Residual between measurement and (projected) filtered vector
184-
const matrix_type<D, 1> residual = meas_local - H * filtered_vec;
185-
186-
// Calculate backward chi2
187-
const matrix_type<D, D> R = (I_m - H * K) * V;
188-
// assert(matrix::determinant(R) != 0.f);
189-
assert(std::isfinite(matrix::determinant(R)));
190-
const matrix_type<1, 1> chi2 =
191-
algebra::matrix::transposed_product<true, false>(
192-
residual, matrix::inverse(R)) *
193-
residual;
194-
195202
// Update the bound track parameters
196203
bound_params.set_vector(filtered_vec);
197-
bound_params.set_covariance(filtered_cov);
198204

199205
// Return false if track is parallel to z-axis or phi is not finite
200-
const scalar theta = bound_params.theta();
201-
if (theta <= 0.f || theta >= constant<traccc::scalar>::pi) {
202-
return kalman_fitter_status::ERROR_THETA_ZERO;
206+
if (!std::isfinite(bound_params.theta())) {
207+
return kalman_fitter_status::ERROR_INVERSION;
203208
}
204209

205210
if (!std::isfinite(bound_params.phi())) {
@@ -210,19 +215,40 @@ struct two_filters_smoother {
210215
return kalman_fitter_status::ERROR_QOP_ZERO;
211216
}
212217

213-
if (getter::element(chi2, 0, 0) < 0.f) {
214-
return kalman_fitter_status::ERROR_UPDATER_CHI2_NEGATIVE;
218+
bound_params.set_covariance(filtered_cov);
219+
220+
// Residual between measurement and (projected) filtered vector
221+
const matrix_type<D, 1> residual = meas_local - H * filtered_vec;
222+
223+
// Calculate backward chi2
224+
const matrix_type<D, D> R = (I_m - H * K) * V;
225+
assert(matrix::determinant(R) != 0.f);
226+
assert(std::isfinite(matrix::determinant(R)));
227+
const matrix_type<1, 1> chi2 =
228+
algebra::matrix::transposed_product<true, false>(
229+
residual, matrix::inverse(R)) *
230+
residual;
231+
232+
const scalar chi2_val{getter::element(chi2, 0, 0)};
233+
234+
if (chi2_val < 0.f) {
235+
return kalman_fitter_status::ERROR_SMOOTHER_CHI2_NEGATIVE;
215236
}
216237

217-
if (!std::isfinite(getter::element(chi2, 0, 0))) {
218-
return kalman_fitter_status::ERROR_UPDATER_CHI2_NOT_FINITE;
238+
if (!std::isfinite(chi2_val)) {
239+
return kalman_fitter_status::ERROR_SMOOTHER_CHI2_NOT_FINITE;
219240
}
220241

221242
// Set backward chi2
222-
trk_state.backward_chi2() = getter::element(chi2, 0, 0);
243+
trk_state.backward_chi2() = chi2_val;
244+
245+
// Wrap the phi and theta angles in their valid ranges
246+
normalize_angles(bound_params);
223247

224-
// Wrap the phi in the range of [-pi, pi]
225-
wrap_phi(bound_params);
248+
const scalar theta = bound_params.theta();
249+
if (theta <= 0.f || theta >= 2.f * constant<traccc::scalar>::pi) {
250+
return kalman_fitter_status::ERROR_THETA_POLE;
251+
}
226252

227253
trk_state.set_smoothed();
228254

core/include/traccc/fitting/status_codes.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace traccc {
1414
enum class kalman_fitter_status : uint32_t {
1515
SUCCESS,
1616
ERROR_QOP_ZERO,
17-
ERROR_THETA_ZERO,
17+
ERROR_THETA_POLE,
1818
ERROR_INVERSION,
1919
ERROR_SMOOTHER_CHI2_NEGATIVE,
2020
ERROR_SMOOTHER_CHI2_NOT_FINITE,
@@ -36,8 +36,8 @@ struct fitter_debug_msg {
3636
case ERROR_QOP_ZERO: {
3737
return msg + "Track qop is zero";
3838
}
39-
case ERROR_THETA_ZERO: {
40-
return msg + "Track theta is zero";
39+
case ERROR_THETA_POLE: {
40+
return msg + "Track theta hit pole";
4141
}
4242
case ERROR_INVERSION: {
4343
return msg + "Failed matrix inversion";
@@ -49,10 +49,10 @@ struct fitter_debug_msg {
4949
return msg + "Invalid chi2 in smoother";
5050
}
5151
case ERROR_UPDATER_CHI2_NEGATIVE: {
52-
return msg + "Negative chi2 in gain matrix update";
52+
return msg + "Negative chi2 in gain matrix updater";
5353
}
5454
case ERROR_UPDATER_CHI2_NOT_FINITE: {
55-
return msg + "Invalid chi2 in gain matrix update";
55+
return msg + "Invalid chi2 in gain matrix updater";
5656
}
5757
case ERROR_BARCODE_SEQUENCE_OVERFLOW: {
5858
return msg + "Barcode sequence overflow in direct navigator";

0 commit comments

Comments
 (0)