https://github.com/ElsevierSoftwareX/SOFTX_2019_219
Raw File
Tip revision: 99932db9e71d31a76425d68eef7d5859523ca0e4 authored by Konrad Werys on 04 November 2019, 09:33:32 UTC
doc: changes in the documentation
Tip revision: 99932db
OxFunctionsT1Shmolli.hxx
/*!
 * \file OxFunctionsT1Shmolli.hxx
 * \author Konrad Werys
 * \date 2018/08/22
 */

#ifndef Tomato_OXFunctionsT1Shmolli_HXX
#define Tomato_OXFunctionsT1Shmolli_HXX

namespace Ox {


    template< typename MeasureType >
    MeasureType
    FunctionsT1Shmolli<MeasureType>
    ::calcModelValue(const MeasureType* parameters, MeasureType time){
        MeasureType A = parameters[0];
        MeasureType B = parameters[1];
        MeasureType T1star = parameters[2];

        MeasureType calculated = 0;

        if (_preventUnderOverFlow){
            if (fabs(T1star) <= (time*0.005 ))
                calculated = A; //prevent underflow when (-mTI/A[2]) < (-500) -- div/0, e^-500 is 0.0000
            else if (fabs(T1star) >= (time*500 ))
                calculated = (A - B*exp((MeasureType)-500)); //prevent overflow
        }

        // if the previous block has calculated someting
        if (calculated != 0){
            return calculated;
        }

        // if the numbers are unreasonable
        if (fabs(T1star) < std::numeric_limits<MeasureType>::min()){
            return calculated;
        }

        if (_expAbsCost) {
            calculated = A - B * exp((MeasureType) -fabs( time / T1star ) );
        } else {
            calculated = A - B * exp((MeasureType) -time / T1star );
        }

        return calculated;
    }

    template< typename MeasureType >
    void
    FunctionsT1Shmolli<MeasureType>
    ::calcLSResiduals(const MeasureType* parameters, MeasureType* residuals){

        //std::cout << "calcLSResiduals" << std::endl;
        unsigned int nSamples = this->_nSamples;

        MeasureType A = parameters[0];
        MeasureType B = parameters[1];
        MeasureType T1star = parameters[2];

        for (unsigned int i = 0; i < nSamples; i++) {
            MeasureType invTime = this->_InvTimes[i];
            MeasureType measured = this->_Signal[i];
            MeasureType calculated = 0;

            calculated = calcModelValue(parameters, invTime);

            residuals[i] = calculated - measured;
        }
    }

    template< typename MeasureType >
    void
    FunctionsT1Shmolli<MeasureType>
    ::calcLSJacobian(const MeasureType* parameters, MeasureType* jacobian){
        int nSamples = this->_nSamples;

        //MeasureType A = parameters[0];
        MeasureType B = parameters[1];
        MeasureType T1star = parameters[2];
        MeasureType invTime, myexp;

        for (int i = 0; i < nSamples; i++) {
            invTime = this->_InvTimes[i];
            myexp = exp(-invTime/T1star);

            // calculated in matlab (syms A B T1 t), f=A-B*exp(-t./T1); diff(f,A), diff(f,B), diff(calcCostValue,T1)
            jacobian[i*3+0] = 1.0;
            jacobian[i*3+1] = -myexp;
            jacobian[i*3+2] = -B*invTime*myexp/(T1star*T1star);
        }
    }

    template< typename MeasureType >
    MeasureType
    FunctionsT1Shmolli<MeasureType>
    ::calcCostValue(const MeasureType* parameters){

        //std::cout << "calcCostValue" << std::endl;
        int nSamples = this->_nSamples;

        calcLSResiduals(parameters, this->_Residuals);
        MeasureType result = 0;

        if (_rootMedianSquareCost){
            // residuals are nor residuals squared!!!
            for (int i = 0; i < nSamples; ++i) {
                this->_Residuals[i] = this->_Residuals[i] * this->_Residuals[i];
            }
            // residuals are nor residuals squared!!!
            result = KWUtil::calcMedianArray(nSamples, this->_Residuals);
            // residuals are nor residuals squared!!!

        } else {

            for (int i = 0; i < nSamples; ++i) {
                result = result + this->_Residuals[i] * this->_Residuals[i];
            }

        }

        //// SKP magic
        if (_costHeuristic){
            if(parameters[0] < 0.  )
                result -= parameters[0]; // A<0 negative Mz0 estimate
            if(parameters[0] > parameters[1])
                result += (parameters[0] - parameters[1]); // less than saturation: B<A, should be B=2*A ideally
            if(parameters[1] > (4. * parameters[0]))
                result += (parameters[1]-4. * parameters[0]); // inversion ratio very high, likely error or SFFP
            if(parameters[2] < 0.)
                result -= parameters[2]; // negative time constant
        }

        return result;


    }

    template< typename MeasureType >
    void
    FunctionsT1Shmolli<MeasureType>
    ::calcCostDerivative(const MeasureType* parameters, MeasureType* derivative){
        //std::cout << "calcCostDerivative" << std::endl;

        int nSamples = this->_nSamples;

        derivative[0] = 0;
        derivative[1] = 0;
        derivative[2] = 0;

        MeasureType measured, invTime, myexp;

        MeasureType A = parameters[0];
        MeasureType B = parameters[1];
        MeasureType T1star = parameters[2];

        // calculated in matlab (syms A B T1 t y), f=(A-B*exp(-t./T1)-y).^2; diff(f,A), diff(f,B), diff(calcCostValue,T1)
        for (int i = 0; i < nSamples; ++i){
            measured = this->getSignal()[i];
            invTime = this->getInvTimes()[i];
            myexp = exp(-invTime/T1star);

            derivative[0] = derivative[0] + A*2 - measured*2 - myexp*B*2;;
            derivative[1] = derivative[1] + myexp*2*(measured - A + myexp*B);
            derivative[2] = derivative[2] + (invTime*myexp*B*2*(measured - A + myexp*B))/(T1star*T1star);
        }
    }

} //namespace Ox


#endif //Tomato_OXFunctionsT1Shmolli_HXX
back to top