/* This file is part of MAUS: http://micewww.pp.rl.ac.uk:8080/projects/maus * * MAUS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MAUS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MAUS. If not, see . * */ #include "src/common_cpp/Recon/Kalman/KalmanTrackFit.hh" #include #include #include "src/common_cpp/Utils/Exception.hh" #include "TDecompLU.h" namespace MAUS { namespace Kalman { std::string print_state(const State& state, const char* detail) { std::ostringstream converter(""); TMatrixD vec = state.GetVector(); TMatrixD cov = state.GetCovariance(); if (detail) converter << detail; converter << " @ " << state.GetPosition() << ", " << state.GetId() << " | "; if (state.HasValue()) { for (unsigned int i = 0; i < state.GetDimension(); ++i) { converter << "(" << vec(i, 0) << " +/- " << sqrt(cov(i, i)) << "), "; } converter << "\n"; } else { converter << "NO DATA\n"; } return converter.str(); } std::string print_track(const Track& track, const char* name) { unsigned int num = track.GetLength(); std::ostringstream converter(""); if (name) { converter << "Printing " << name << " (" << num << ")\n"; } else { converter << "Printing Track (" << num << ")\n"; } for (unsigned int i = 0; i < num; ++i) { State state = track[i]; converter << print_state(state); } converter << "\n"; return converter.str(); } State CalculateResidual(const State& st1, const State& st2) { if (st1._dimension != st2._dimension) { throw Exception(Exception::recoverable, "States have different dimensions", "Kalman::CalculateResidual()"); } TMatrixD vector = st1._vector - st2._vector; TMatrixD covariance = st1._covariance + st2._covariance; State residual(vector, covariance, st1._position); residual.SetId(st1._id); return residual; } double CalculateChiSquaredUpdate(const State& st) { TMatrixD rT(TMatrixD::kTransposed, st._vector);// rT.Transpose(r); TMatrixD RI(TMatrixD::kInverted, st._covariance); TMatrixD update = rT * RI * st._vector; return update(0, 0); } TrackFit::TrackFit(Propagator_base* prop, Measurement_base* meas) : _dimension(prop->GetDimension()), _measurement_dimension(meas->GetMeasurementDimension()), _propagator(prop), _measurement(meas), _seed(_dimension, _measurement_dimension), _data(_dimension), _predicted(_dimension), _filtered(_dimension), _smoothed(_dimension), _identity_matrix(_dimension, _dimension) { if (_measurement->GetDimension() != _propagator->GetDimension()) { throw Exception(Exception::recoverable, "Propagators and Measurements have conflicting dimension.", "Kalman::TrackFit::TrackFit()"); } _identity_matrix.Zero(); for (unsigned int i = 0; i < _dimension; ++i) _identity_matrix(i, i) = 1.0; } TrackFit::~TrackFit() { if (_propagator) { delete _propagator; _propagator = NULL; } if (_measurement) { delete _measurement; _measurement = NULL; } } void TrackFit::AppendFilter(State state) { throw Exception(Exception::nonRecoverable, "Functionality Not Implemented!", "Kalman::TrackFit::AppendFilter()"); if (state.GetDimension() != _measurement->GetMeasurementDimension()) { throw Exception(Exception::recoverable, "State dimension does not match the measurement dimension", "Kalman::TrackFit::AppendFilter()"); } // The good stuff goes here! } void TrackFit::Filter(bool forward) { _predicted.Reset(_data); _filtered.Reset(_data); int increment = (forward ? 1 : -1); int track_start = (forward ? 1 : _data.GetLength() - 2); int track_end = (forward ? _data.GetLength() : -1); _predicted[track_start-increment].copy(_seed); this->_filter(_data[track_start-increment], _predicted[track_start-increment], _filtered[track_start-increment]); for (int i = track_start; i != track_end; i += increment) { this->_propagate(_filtered[i-increment], _predicted[i]); if (_data[i].HasValue()) { this->_filter(_data[i], _predicted[i], _filtered[i]); } else { _filtered[i] = _predicted[i]; } } } void TrackFit::Smooth(bool forward) { _smoothed.Reset(_data); int increment = (forward ? -1 : 1); int track_start = (forward ? (_smoothed.GetLength() - 2) : 1); int track_end = (forward ? -1 : (_smoothed.GetLength())); _smoothed[track_start-increment] = _filtered[track_start-increment]; for (int i = track_start; i != track_end; i += increment) { TMatrixD inv_cov(TMatrixD::kInverted, _predicted[i - increment].GetCovariance()); TMatrixD prop = _propagator->CalculatePropagator(_filtered[i], _filtered[i - increment]); TMatrixD propT(TMatrixD::kTransposed, prop); TMatrixD A = _filtered[i].GetCovariance() * propT * inv_cov; TMatrixD AT(TMatrixD::kTransposed, A); TMatrixD vec = _filtered[i].GetVector() + A * (_smoothed[i-increment].GetVector() - _predicted[i-increment].GetVector()); TMatrixD temp = A * (_smoothed[i-increment].GetCovariance() - _predicted[i-increment].GetCovariance()) * AT; TMatrixD cov = _filtered[i].GetCovariance() + temp; _smoothed[i].SetVector(vec); _smoothed[i].SetCovariance(cov); } } void TrackFit::SetSeed(State seed) { if (seed.GetDimension() != _dimension) { throw Exception(Exception::recoverable, "Seed dimension does not match the track fitter", "Kalman::TrackFit::SetSeed()"); } _seed = seed; } void TrackFit::SetData(Track data_track) { if (data_track.GetDimension() != _measurement->GetMeasurementDimension()) { throw Exception(Exception::nonRecoverable, "Data track dimension does not match the measurement dimension", "Kalman::TrackFit::SetData()"); } _data = data_track; _predicted = Track(_dimension); _filtered = Track(_dimension); _smoothed = Track(_dimension); } void TrackFit::_propagate(State& first, State& second) const { _propagator->Propagate(first, second); } void TrackFit::_filter(const State& data, const State& predicted, State& filtered) const { State measured = _measurement->Measure(predicted); State pull = CalculateResidual(data, measured); TMatrixD V = _measurement->GetMeasurementNoise(); TMatrixD H = _measurement->GetMeasurementMatrix(); TMatrixD HT(TMatrixD::kTransposed, H); TMatrixD cov_inv(TMatrixD::kInverted, pull.GetCovariance()); TMatrixD K = predicted.GetCovariance() * HT * cov_inv; TMatrixD KT(TMatrixD::kTransposed, K); TMatrixD gain = _identity_matrix - K*H; TMatrixD gainT(TMatrixD::kTransposed, gain); TMatrixD gain_constant = K * V * KT; TMatrixD temp_vec = predicted.GetVector() + K * pull.GetVector(); TMatrixD temp_cov = gain * predicted.GetCovariance() * gainT + gain_constant; filtered.SetVector(temp_vec); filtered.SetCovariance(temp_cov); } void TrackFit::_smooth(State& first, State& second) const { } void TrackFit::_inverse_filter(const State& data, const State& smoothed, State& cleaned) const { State measured = _measurement->Measure(smoothed); State pull = CalculateResidual(data, measured); TMatrixD V = _measurement->GetMeasurementNoise(); TMatrixD H = _measurement->GetMeasurementMatrix(); TMatrixD HT(TMatrixD::kTransposed, H); TMatrixD cov_inv(TMatrixD::kInverted, pull.GetCovariance()); // THIS IS THE INVERSE FILTER LINE! V *= -1.0; TMatrixD K = smoothed.GetCovariance() * HT * cov_inv; TMatrixD KT(TMatrixD::kTransposed, K); TMatrixD gain = _identity_matrix - K*H; TMatrixD gainT(TMatrixD::kTransposed, gain); TMatrixD gain_constant = K * V * KT; TMatrixD temp_vec = smoothed.GetVector() + K * pull.GetVector(); TMatrixD temp_cov = gain * smoothed.GetCovariance() * gainT + gain_constant; cleaned.SetVector(temp_vec); cleaned.SetCovariance(temp_cov); } double TrackFit::CalculateChiSquared(const Track& track) const { if (track.GetLength() != _data.GetLength()) throw Exception(Exception::recoverable, "Supplied Track length is different to data track", "Kalman::TrackFit::CalculateChiSquared()"); double chi_squared = 0.0; for (unsigned int i = 0; i < track.GetLength(); ++i) { if (_data[i]) { State measured = _measurement->Measure(track[i]); State chisq = CalculateResidual(measured, _data[i]); double update = CalculateChiSquaredUpdate(chisq); chi_squared += update; } } return chi_squared; } int TrackFit::GetNDF() const { int no_parameters = GetDimension(); int no_measurements = 0; for (unsigned int i = 0; i < _data.GetLength(); ++i) { if (_data[i].HasValue()) { no_measurements += GetMeasurementDimension(); } } return (no_measurements - no_parameters); } State TrackFit::CalculateCleanedState(unsigned int i) const { State smoothed = _smoothed[i]; const State& data = _data[i]; State cleaned(GetDimension()); this->_inverse_filter(data, smoothed, cleaned); return cleaned; } State TrackFit::CalculatePull(unsigned int i) const { State cleaned = this->CalculateCleanedState(i); return CalculateResidual(cleaned, _smoothed[i]); } State TrackFit::CalculatePredictedResidual(unsigned int i) const { State measured = _measurement->Measure(_predicted[i]); return CalculateResidual(measured, _data[i]); } State TrackFit::CalculateFilteredResidual(unsigned int i) const { State measured = _measurement->Measure(_filtered[i]); return CalculateResidual(measured, _data[i]); } State TrackFit::CalculateSmoothedResidual(unsigned int i) const { State measured = _measurement->Measure(_smoothed[i]); return CalculateResidual(measured, _data[i]); } TrackFit::TrackFit(const TrackFit& tf) : _dimension(tf.GetDimension()), _propagator(0), _measurement(0), _seed(_dimension), _data(_dimension), _predicted(_dimension), _filtered(_dimension), _smoothed(_dimension), _identity_matrix(_measurement_dimension, _measurement_dimension) { } } // namespace Kalman } // namespace MAUS