//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sim/Computation/SpecularComputation.cpp
//! @brief     Implements class SpecularComputation.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "Sim/Computation/SpecularComputation.h"
#include "Base/Spin/SpinMatrix.h"

double Compute::magneticR(const SpinMatrix& R, const SpinMatrix& polMatrix,
                          const SpinMatrix& anaMatrix)
{
    // For pure input |i> and output |f> states the measured refl = |<f|R|i>|^2
    // If polarizer and analyzer are imperfect (pass different polarizations with some probability)
    // we should calculate the following summation: refl = sum{ p_i * p_f * |<f|R|i>|^2 } over
    // possible states where 'p_i' and 'p_f' are probabilities of such states |i> and |f>.
    // Introducing
    // polMatrix = sum{ p_i * |i><i| }
    // and
    // anaMatrix = sum{ p_f * |f><f| }
    // and using identity
    // <j|A|j> = tr( |j><j|A )
    // we get
    // refl = tr( polMatrix * R.adjoint * anaMatrix * R )
    const complex_t trace = (polMatrix * R.adjoint() * anaMatrix * R).trace();

    // The result represents physically observable value so it has to be real.
    // For conversion from complex to real we can take absolute value or real part.
    return std::abs(trace);
}

double Compute::scalarR(complex_t R) // Let's keep this function for analogy with magneticR
{
    return std::norm(R); // absolute value squared
}
