/*! * \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 ::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::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 ::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 ::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 ::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 (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 ::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