/* 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 << " ";
for (unsigned int i = 0; i < state.GetDimension(); ++i) {
converter << "(" << vec(i, 0) << " +/- " << sqrt(cov(i, i)) << "), ";
}
converter << "\n";
return converter.str();
}
std::string print_trackpoint(const TrackPoint& tp, const char* detail) {
std::ostringstream converter("");
if (detail) {
converter << detail << " @ ";
} else {
converter << "TrackPoint @ ";
}
converter << tp.GetPosition() << ", " << tp.GetId() << '\n';
if (tp.HasData()) {
converter << print_state(tp.GetData(), "DATA");
} else {
converter << "NO DATA\n";
}
converter << print_state(tp.GetPredicted(), "Predicted");
converter << print_state(tp.GetFiltered(), "Filtered ");
converter << print_state(tp.GetSmoothed(), "Smoothed ") << '\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) {
TrackPoint tp = track[i];
converter << print_trackpoint(tp);
}
converter << "\n";
return converter.str();
}
State CalculateResidual(const State& st1, const State& st2) {
if (st1._dimension != st2._dimension) {
throw Exceptions::Exception(Exceptions::recoverable,
"States have different dimensions",
"Kalman::CalculateResidual()");
}
TMatrixD vector = st1._vector - st2._vector;
TMatrixD covariance = st1._covariance + st2._covariance;
State residual(vector, covariance);
return residual;
}
State CalculateFilteredResidual(const State& data, const State& measured) {
if (data._dimension != measured._dimension) {
throw Exceptions::Exception(Exceptions::recoverable,
"States have different dimensions",
"Kalman::CalculateFilteredResidual()");
}
TMatrixD vector = data._vector - measured._vector;
TMatrixD covariance = data._covariance - measured._covariance;
State residual(vector, covariance);
return residual;
}
State CalculateChiSquaredResidual(const State& data, const State& measured) {
if (data._dimension != measured._dimension) {
throw Exceptions::Exception(Exceptions::recoverable,
"States have different dimensions",
"Kalman::CalculateFilteredResidual()");
}
TMatrixD vector = data._vector - measured._vector;
State residual(vector, data._covariance);
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) :
_dimension(prop->GetDimension()),
_propagator(prop),
_measurements(),
_seed(_dimension),
_track(_dimension),
_identity_matrix(_dimension, _dimension) {
_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;
}
for (std::map::iterator it = _measurements.begin();
it != _measurements.end(); ++it ) {
if (it->second) {
delete it->second;
}
}
_measurements.clear();
}
void TrackFit::AppendFilter(TrackPoint tp) {
_track.Append(tp);
int length = _track.GetLength();
if (length == 1) {
_track[0].SetPredicted(_seed);
} else {
this->_propagate(_track[length-2], _track[length-1]);
}
this->_filter(_track[length-1]);
}
void TrackFit::Filter(bool forward) {
int increment = (forward ? 1 : -1);
int track_start = (forward ? 1 : _track.GetLength() - 2);
int track_end = (forward ? _track.GetLength() : -1);
_track[track_start-increment].SetPredicted(_seed);
this->_filter(_track[track_start-increment]);
for (int i = track_start; i != track_end; i += increment) {
this->_propagate(_track[i-increment], _track[i]);
this->_filter(_track[i]);
}
}
void TrackFit::Smooth(bool forward) {
int increment = (forward ? -1 : 1);
int track_start = (forward ? (_track.GetLength() - 2) : 1);
int track_end = (forward ? -1 : (_track.GetLength()));
_track[track_start-increment].SetSmoothed(_track[track_start-increment].GetFiltered());
for (int i = track_start; i != track_end; i += increment) {
TMatrixD inv_cov(TMatrixD::kInverted, _track[i - increment].GetPredicted().GetCovariance());
TMatrixD prop = _propagator->CalculatePropagator(_track[i], _track[i - increment]);
TMatrixD propT(TMatrixD::kTransposed, prop);
TMatrixD A = _track[i].GetFiltered().GetCovariance() * propT * inv_cov;
TMatrixD AT(TMatrixD::kTransposed, A);
TMatrixD vec = _track[i].GetFiltered().GetVector() + A *
(_track[i-increment].GetSmoothed().GetVector() -
_track[i-increment].GetPredicted().GetVector());
TMatrixD temp = A * (_track[i-increment].GetSmoothed().GetCovariance() -
_track[i-increment].GetPredicted().GetCovariance()) * AT;
TMatrixD cov = _track[i].GetFiltered().GetCovariance() + temp;
_track[i].SetSmoothed(State(vec, cov));
}
}
void TrackFit::SetSeed(State seed) {
if (seed.GetDimension() != _dimension) {
throw Exceptions::Exception(Exceptions::recoverable,
"Seed dimension does not match the track fitter",
"Kalman::TrackFit::SetSeed()");
}
_seed = seed;
}
void TrackFit::SetTrack(Track track) {
if (track.GetDimension() != _dimension) {
throw Exceptions::Exception(Exceptions::recoverable,
"Track dimension does not match the track fitter",
"Kalman::TrackFit::SetTrack()");
}
_track = track;
}
// void TrackFit::_propagate(State& first, State& second) const {
void TrackFit::_propagate(const TrackPoint& first, TrackPoint& second) const {
_propagator->Propagate(first, second);
}
// void TrackFit::_filter(const State& data, const State& predicted, State& filtered) const {
void TrackFit::_filter(TrackPoint& tp) const {
if (tp.HasData()) {
const State& data = tp.GetData();
const State& predicted = tp.GetPredicted();
State measured = _measurements.at(tp.GetId())->Measure(predicted);
State pull = CalculateResidual(data, measured);
TMatrixD V = data.GetCovariance();
TMatrixD H = _measurements.at(tp.GetId())->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;
tp.SetFiltered(State(temp_vec, temp_cov));
} else {
tp.SetFiltered(tp.GetPredicted());
}
}
void TrackFit::_smooth(TrackPoint& first, TrackPoint& second) const {
}
State TrackFit::_inverse_filter(const TrackPoint& tp) const {
State data = tp.GetData();
const State& smoothed = tp.GetSmoothed();
State cleaned = State(_dimension);
// THIS IS THE INVERSE FILTER LINE!
data.SetCovariance(-1.0*data.GetCovariance());
State measured = _measurements.at(tp.GetId())->Measure(smoothed);
State pull = CalculateResidual(data, measured);
TMatrixD V = data.GetCovariance();
TMatrixD H = _measurements.at(tp.GetId())->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;
return State(temp_vec, temp_cov);
}
double TrackFit::CalculateSmoothedChiSquared() const {
double chi_squared = 0.0;
for (unsigned int i = 0; i < _track.GetLength(); ++i) {
if (_track[i].HasData()) {
State measured = _measurements.at(_track[i].GetId())->Measure(_track[i].GetSmoothed());
State chisq = Kalman::CalculateFilteredResidual(_track[i].GetData(), measured);
double update = CalculateChiSquaredUpdate(chisq);
chi_squared += update;
}
}
return chi_squared;
}
double TrackFit::CalculateChiSquared() const {
double chi_squared = 0.0;
for (unsigned int i = 0; i < _track.GetLength(); ++i) {
if (_track[i].HasData()) {
State measured = _measurements.at(_track[i].GetId())->Measure(_track[i].GetSmoothed());
State chisq = Kalman::CalculateChiSquaredResidual(_track[i].GetData(), measured);
double update = CalculateChiSquaredUpdate(chisq);
chi_squared += update;
}
}
return chi_squared;
}
double TrackFit::CalculatePullChiSquared() const {
double chi_squared = 0.0;
for (unsigned int i = 0; i < _track.GetLength(); ++i) {
if (_track[i].HasData()) {
State chisq = this->CalculatePull(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 < _track.GetLength(); ++i) {
if (_track[i].HasData()) {
no_measurements += _measurements.at(_track[i].GetId())->GetMeasurementDimension();
}
}
return (no_measurements - no_parameters);
}
int TrackFit::GetNumberMeasurements() const {
int no_measurements = 0;
for (unsigned int i = 0; i < _track.GetLength(); ++i) {
if (_track[i].HasData()) {
no_measurements += _measurements.at(_track[i].GetId())->GetMeasurementDimension();
}
}
return no_measurements;
}
State TrackFit::CalculateCleanedState(unsigned int i) const {
return this->_inverse_filter(_track[i]);
}
State TrackFit::CalculatePull(unsigned int i) const {
State cleaned = this->CalculateCleanedState(i);
State measured = _measurements.at(_track[i].GetId())->Measure(cleaned);
return Kalman::CalculateResidual(_track[i].GetData(), measured);
// return Kalman::CalculateChiSquaredResidual(_track[i].GetData(), measured);
}
State TrackFit::CalculatePredictedResidual(unsigned int i) const {
State measured = _measurements.at(_track[i].GetId())->Measure(_track[i].GetPredicted());
return CalculateResidual(measured, _track[i].GetData());
}
State TrackFit::CalculateFilteredResidual(unsigned int i) const {
State measured = _measurements.at(_track[i].GetId())->Measure(_track[i].GetFiltered());
return Kalman::CalculateFilteredResidual(_track[i].GetData(), measured);
}
State TrackFit::CalculateSmoothedResidual(unsigned int i) const {
State measured = _measurements.at(_track[i].GetId())->Measure(_track[i].GetSmoothed());
return Kalman::CalculateFilteredResidual(_track[i].GetData(), measured);
}
TrackFit::TrackFit(const TrackFit& tf) :
_dimension(tf.GetDimension()),
_propagator(0),
_measurements(),
_seed(_dimension),
_track(_dimension),
_identity_matrix(_measurement_dimension, _measurement_dimension) {
}
} // namespace Kalman
} // namespace MAUS