/* 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 .
*/
/* Author: Peter Lane
*/
#include "src/common_cpp/Optics/CovarianceMatrix.hh"
#include
#include
#include
#include
#include
#include "CLHEP/Matrix/SymMatrix.h"
#include "CLHEP/Units/PhysicalConstants.h"
#include "TMatrixDSym.h"
#include "Utils/Exception.hh"
#include "Maths/Matrix.hh"
#include "Maths/SymmetricMatrix.hh"
namespace MAUS {
using MAUS::Matrix;
using ::CLHEP::c_light;
// ############################
// Free Functions
// ############################
// ****************************
// Conversion Functions
// ****************************
CovarianceMatrix rotate(const CovarianceMatrix& covariances,
const double angle) {
double fcos = ::cos(angle);
double fsin = ::sin(angle);
double rotation_array[36] = {
1., 0., 0., 0., 0., 0.,
0., 1., 0., 0., 0., 0.,
0., 0., fcos, 0., fsin, 0.,
0., 0., 0., fcos, 0., fsin,
0., 0., -fsin, 0., fcos, 0.,
0., 0., 0., -fsin, 0., fcos
};
const Matrix rotation(6, 6, rotation_array);
const Matrix rotation_transpose = transpose(rotation);
// the orthogonal similarity transform of a symmetric matrix is also symmetric
CovarianceMatrix rotated_covariances(
rotation * covariances * rotation_transpose);
return rotated_covariances;
}
// ############################
// CovarianceMatrix
// ############################
// ****************************
// Constructors
// ****************************
CovarianceMatrix::CovarianceMatrix() : SymmetricMatrix(6)
{ }
CovarianceMatrix::CovarianceMatrix(const CovarianceMatrix& original_instance)
: SymmetricMatrix((SymmetricMatrix) original_instance)
{ }
CovarianceMatrix::CovarianceMatrix(const Matrix& matrix)
: SymmetricMatrix() {
if ( (matrix.number_of_rows() < 6)
|| (matrix.number_of_columns() < 6)) {
throw(Exception(Exception::recoverable,
"Attempted to construct with a Matrix containing "
"fewer than six rows and/or columns",
"CovarianceMatrix::CovarianceMatrix(Matrix)"));
}
build_matrix(6);
for (size_t row = 1; row <= 6; ++row) {
for (size_t column = 1; column <= row; ++column) {
set(row, column, matrix(row, column));
}
}
}
CovarianceMatrix::CovarianceMatrix(const SymmetricMatrix& symmetric_matrix)
: SymmetricMatrix() {
if ( (symmetric_matrix.number_of_rows() < 6)
|| (symmetric_matrix.number_of_columns() < 6)) {
throw(Exception(Exception::recoverable,
"Attempted to construct with a SymmetricMatrix containing "
"fewer than six rows/columns",
"CovarianceMatrix::CovarianceMatrix(SymmetricMatrix)"));
}
build_matrix(6);
for (size_t row = 1; row <= 6; ++row) {
for (size_t column = 1; column <= row; ++column) {
set(row, column, symmetric_matrix(row, column));
}
}
}
CovarianceMatrix::CovarianceMatrix(const ::CLHEP::HepSymMatrix& hep_sym_matrix)
: SymmetricMatrix() {
if ( (hep_sym_matrix.num_row() < 6)
|| (hep_sym_matrix.num_col() < 6)) {
throw(Exception(Exception::recoverable,
"Attempted to construct with a HepSymMatrix containing fewer "
"than six rows/columns",
"CovarianceMatrix::CovarianceMatrix(CLHEP::HepSymMatrix)"));
}
build_matrix(6);
double element;
for (size_t row = 1; row <= 6; ++row) {
for (size_t column = 1; column <= row; ++column) {
element = hep_sym_matrix(row, column);
Matrix::operator()(row, column) = element;
Matrix::operator()(column, row) = element;
}
}
}
CovarianceMatrix::CovarianceMatrix(const TMatrixDSym& root_sym_matrix)
: SymmetricMatrix(root_sym_matrix) {
if ( (root_sym_matrix.GetNrows() < 6)
|| (root_sym_matrix.GetNcols() < 6)) {
throw(Exception(Exception::recoverable,
"Attempted to construct with a TMatrixDSym containing fewer "
"than six rows/columns",
"CovarianceMatrix::CovarianceMatrix(TMatrixDSym)"));
}
const double * data = root_sym_matrix.GetMatrixArray();
build_matrix(6, data);
}
CovarianceMatrix::CovarianceMatrix(double const * const array_matrix)
: SymmetricMatrix(6, array_matrix)
{ }
/* xboa uses an equation for calculating canonical angular momentum that is
* different from the standard. This in turn affects Ltwiddle_t. Furthermore,
* xboa uses a different definition of kappa and sigma_y_Px than G. Penn's
* paper (this might be an error). It also appears that xboa uses total
* momentum instead of longitudinal momentum in calculations of the covariances.
*/
const CovarianceMatrix CovarianceMatrix::CreateFromPennParameters(
double mass,
double momentum,
double charge,
double Bz,
double Ltwiddle_t,
double emittance_t,
double beta_t,
double alpha_t,
double emittance_l,
double beta_l,
double alpha_l,
double dispersion_x,
double dispersion_prime_x,
double dispersion_y,
double dispersion_prime_y) {
// *** calculate some intermediate values ***
double energy = ::sqrt(momentum * momentum + mass * mass);
// this differs from G. Penn's paper
double kappa = c_light * Bz / (2. * momentum);
double gamma_t = (1 + alpha_t*alpha_t
+ (beta_t*kappa - Ltwiddle_t)*(beta_t*kappa-Ltwiddle_t))
/ beta_t;
double gamma_l = (1+alpha_l*alpha_l+beta_l*beta_l*kappa*kappa)/beta_l;
// *** calculate the lower triangle covariances = sigma_A_B ***
double sigma_t_t = emittance_l * mass * beta_l / momentum;
double sigma_E_t = -emittance_l * mass * alpha_l;
double sigma_E_E = emittance_l * mass * gamma_l * momentum;
double sigma_x_t = 0.;
double sigma_x_E = dispersion_x * sigma_E_E / energy;
double sigma_x_x = emittance_t * beta_t * mass / momentum;
double sigma_Px_t = 0.;
double sigma_Px_E = dispersion_prime_x * sigma_E_E / energy;
double sigma_Px_x = -mass * emittance_t * alpha_t;
double sigma_Px_Px= mass * momentum * emittance_t * gamma_t;
double sigma_y_t = 0.;
double sigma_y_E = dispersion_y * sigma_E_E / energy;
double sigma_y_x = 0.;
// this differes from G. Penn's paper
double sigma_y_Px = mass * emittance_t
* (beta_t*kappa - Ltwiddle_t) * charge;
double sigma_y_y = emittance_t * beta_t * mass / momentum;
double sigma_Py_t = 0.;
double sigma_Py_E = dispersion_prime_y * sigma_E_E / energy;
double sigma_Py_x = -sigma_y_Px;
double sigma_Py_Px= 0.;
double sigma_Py_y = sigma_Px_x;
double sigma_Py_Py= sigma_Px_Px;
double covariances[36] = {
sigma_t_t, 0., 0., 0., 0., 0.,
sigma_E_t, sigma_E_E, 0., 0., 0., 0.,
sigma_x_t, sigma_x_E, sigma_x_x, 0., 0., 0.,
sigma_Px_t, sigma_Px_E, sigma_Px_x, sigma_Px_Px, 0., 0.,
sigma_y_t, sigma_y_E, sigma_y_x, sigma_y_Px, sigma_y_y, 0.,
sigma_Py_t, sigma_Py_E, sigma_Py_x, sigma_Py_Px, sigma_Py_y, sigma_Py_Py
};
return CovarianceMatrix(covariances);
}
const CovarianceMatrix CovarianceMatrix::CreateFromTwissParameters(
double mass,
double momentum,
double emittance_x,
double beta_x,
double alpha_x,
double emittance_y,
double beta_y,
double alpha_y,
double emittance_l,
double beta_l,
double alpha_l,
double dispersion_x,
double dispersion_prime_x,
double dispersion_y,
double dispersion_prime_y) {
// *** calculate some intermediate values ***
double energy = ::sqrt(momentum * momentum + mass * mass);
double gamma_x = (1+alpha_x*alpha_x)/beta_x;
double gamma_y = (1+alpha_y*alpha_y)/beta_y;
double gamma_l = (1+alpha_l*alpha_l)/beta_l;
// *** calculate the lower triangle covariances = sigma_A_B ***
double sigma_t_t = emittance_l * mass * beta_l / momentum;
double sigma_E_t = -emittance_l * mass * alpha_l;
double sigma_E_E = emittance_l * mass * gamma_l * momentum;
double sigma_x_t = 0.;
double sigma_x_E = dispersion_x * sigma_E_E / energy;
// FIXME(plane1@hawk.iit.edu) Shouldn't this be just beta_x emittance_x?
double sigma_x_x = emittance_x * mass * beta_x / momentum;
double sigma_Px_t = 0.;
double sigma_Px_E = dispersion_prime_x * sigma_E_E / energy;
// FIXME(plane1@hawk.iit.edu) Shouldn't this be just -alpha_x emittance_x ?
double sigma_Px_x = -emittance_x * mass * alpha_x;
// FIXME(plane1@hawk.iit.edu) Shouldn't this be just gamma_x emittance_x ?
double sigma_Px_Px= emittance_x * mass * momentum * gamma_x;
double sigma_y_t = 0.;
double sigma_y_E = dispersion_y * sigma_E_E / energy;
double sigma_y_x = 0.;
double sigma_y_Px = 0.;
// FIXME(plane1@hawk.iit.edu) Shouldn't this be just beta_y emittance_y?
double sigma_y_y = emittance_y * mass * beta_y / momentum;
double sigma_Py_t = 0.;
double sigma_Py_E = dispersion_prime_y * sigma_E_E / energy;
double sigma_Py_x = 0.;
double sigma_Py_Px= 0.;
// FIXME(plane1@hawk.iit.edu) Shouldn't this be just -alpha_y emittance_y ?
double sigma_Py_y = -emittance_y * mass * alpha_y;
// FIXME(plane1@hawk.iit.edu) Shouldn't this be just gamma_y emittance_y ?
double sigma_Py_Py= emittance_y * mass * momentum * gamma_y;
double covariances[36] = {
sigma_t_t, 0., 0., 0., 0., 0.,
sigma_E_t, sigma_E_E, 0., 0., 0., 0.,
sigma_x_t, sigma_x_E, sigma_x_x, 0., 0., 0.,
sigma_Px_t, sigma_Px_E, sigma_Px_x, sigma_Px_Px, 0., 0.,
sigma_y_t, sigma_y_E, sigma_y_x, sigma_y_Px, sigma_y_y, 0.,
sigma_Py_t, sigma_Py_E, sigma_Py_x, sigma_Py_Px, sigma_Py_y, sigma_Py_Py
};
return CovarianceMatrix(covariances);
}
bool CovarianceMatrix::IsPositiveDefinite() const {
size_t min_row = 1;
size_t min_column = 1;
size_t rows = size();
for (size_t length = 1; length <= rows; length++) {
// Sylvester Criterion - all the leading principle minors must be positive
if (determinant(submatrix(min_row, length, min_column, length)) <= 0) {
return false;
}
}
return true;
}
} // namespace MAUS