| @@ -0,0 +1,225 @@ | ||
| #include "MantidCurveFitting/ThermoNeutronBackToBackExpPV.h" | ||
| #include "MantidKernel/System.h" | ||
| #include "MantidAPI/FunctionFactory.h" | ||
|
|
||
| #define PI 3.14159265358979323846264338327950288419716939937510582 | ||
|
|
||
| using namespace Mantid::Kernel; | ||
| using namespace Mantid::API; | ||
|
|
||
| namespace Mantid | ||
| { | ||
| namespace CurveFitting | ||
| { | ||
|
|
||
| DECLARE_FUNCTION(ThermoNeutronBackToBackExpPV) | ||
|
|
||
| // Get a reference to the logger | ||
| Mantid::Kernel::Logger& ThermoNeutronBackToBackExpPV::g_log = Kernel::Logger::get("ThermoNeutronBackToBackExpPV"); | ||
|
|
||
| // ---------------------------- | ||
| /* | ||
| * Constructor and Desctructor | ||
| */ | ||
| ThermoNeutronBackToBackExpPV::ThermoNeutronBackToBackExpPV() | ||
| { | ||
|
|
||
| } | ||
|
|
||
| ThermoNeutronBackToBackExpPV::~ThermoNeutronBackToBackExpPV() | ||
| { | ||
|
|
||
| } | ||
|
|
||
| /* | ||
| * Initialize: declare paraemters | ||
| */ | ||
| void ThermoNeutronBackToBackExpPV::init() | ||
| { | ||
| declareParameter("I", 1.0); | ||
| declareParameter("TOF_h", 0.0); | ||
| declareParameter("height", 1.0); | ||
| declareParameter("Alpha",1.6); | ||
| declareParameter("Beta",1.6); | ||
| declareParameter("Sigma2", 1.0); | ||
| declareParameter("Gamma", 0.0); | ||
|
|
||
| /* Kept for wrapper function | ||
| declareParameter("I", 1.0); | ||
| declareParameter("Dtt1", 1.0); | ||
| declareParameter("Dtt1t", 1.0); | ||
| declareParameter("Dtt2t", 1.0); | ||
| declareParameter("d_peak", 1.0); | ||
| declareParameter("Zero_e", 0.0); | ||
| declareParameter("Zero_t", 0.0); | ||
| declareParameter("w_cross", 1.0); | ||
| declareParameter("T_cross", 1.0); | ||
| declareParameter("Alpha0",1.6); | ||
| declareParameter("Alpha1",1.5); | ||
| declareParameter("Beta0",1.6); | ||
| declareParameter("Beta1",1.5); | ||
| declareParameter("Alpha0t",1.6); | ||
| declareParameter("Alpha1t",1.5); | ||
| declareParameter("Beta0t",1.6); | ||
| declareParameter("Beta1t",1.5); | ||
| declareParameter("Sigma0", 1.0); | ||
| declareParameter("Sigma1", 1.0); | ||
| declareParameter("Sigma2", 1.0); | ||
| declareParameter("Gamma0", 0.0); | ||
| declareParameter("Gamma1", 0.0); | ||
| declareParameter("Gamma2", 0.0); | ||
| */ | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| double ThermoNeutronBackToBackExpPV::centre()const | ||
| { | ||
| return getParameter("TOF_h"); | ||
| } | ||
|
|
||
|
|
||
| void ThermoNeutronBackToBackExpPV::setHeight(const double h) | ||
| { | ||
| setParameter("height", h); | ||
|
|
||
| return; | ||
| }; | ||
|
|
||
| double ThermoNeutronBackToBackExpPV::height() const | ||
| { | ||
| double height = this->getParameter("height"); | ||
| return height; | ||
| }; | ||
|
|
||
| double ThermoNeutronBackToBackExpPV::fwhm() const | ||
| { | ||
| return mFWHM; | ||
| }; | ||
|
|
||
| void ThermoNeutronBackToBackExpPV::setFwhm(const double w) | ||
| { | ||
| UNUSED_ARG(w); | ||
| throw std::invalid_argument("Unable to set FWHM"); | ||
| }; | ||
|
|
||
| void ThermoNeutronBackToBackExpPV::setCentre(const double c) | ||
| { | ||
| setParameter("TOF_h",c); | ||
| }; | ||
|
|
||
| /* | ||
| * Implement the peak calculating formula | ||
| */ | ||
| void ThermoNeutronBackToBackExpPV::functionLocal(double* out, const double* xValues, const size_t nData) const | ||
| { | ||
| // 1. Prepare constants | ||
| const double alpha = this->getParameter("Alpha"); | ||
| const double beta = this->getParameter("Beta"); | ||
| const double sigma2 = this->getParameter("Sigma2"); | ||
| const double gamma = this->getParameter("Gamma"); | ||
| const double height = this->getParameter("height"); | ||
| const double tof_h = this->getParameter("TOF_h"); | ||
|
|
||
| double invert_sqrt2sigma = 1.0/sqrt(2.0*sigma2); | ||
| double N = alpha*beta*0.5/(alpha+beta); | ||
|
|
||
| double H, eta; | ||
| calHandEta(sigma2, gamma, H, eta); | ||
|
|
||
| // 2. Do calculation | ||
| for (size_t id = 0; id < nData; ++id) | ||
| { | ||
| double dT = xValues[id]-tof_h; | ||
| out[id] = height*calOmega(dT, eta, N, alpha, beta, H, sigma2, invert_sqrt2sigma); | ||
| } | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| void ThermoNeutronBackToBackExpPV::functionDerivLocal(API::Jacobian* , const double* , const size_t ) | ||
| { | ||
| throw Mantid::Kernel::Exception::NotImplementedError("functionDerivLocal is not implemented for IkedaCarpenterPV."); | ||
| } | ||
|
|
||
| void ThermoNeutronBackToBackExpPV::functionDeriv(const API::FunctionDomain& domain, API::Jacobian& jacobian) | ||
| { | ||
| calNumericalDeriv(domain, jacobian); | ||
| } | ||
|
|
||
| /* | ||
| * Calculate Omega(x) = ... ... | ||
| */ | ||
| double ThermoNeutronBackToBackExpPV::calOmega(double x, double eta, double N, double alpha, double beta, double H, | ||
| double sigma2, double invert_sqrt2sigma) const | ||
| { | ||
| // 1. Prepare | ||
| std::complex<double> p(alpha*x, alpha*H*0.5); | ||
| std::complex<double> q(-beta*x, beta*H*0.5); | ||
|
|
||
| double u = 0.5*alpha*(alpha*sigma2+2*x); | ||
| double y = (alpha*sigma2 + x)*invert_sqrt2sigma; | ||
|
|
||
| double v = 0.5*beta*(beta*sigma2 - 2*x); | ||
| double z = (beta*sigma2 - x)*invert_sqrt2sigma; | ||
|
|
||
| // 2. Calculate | ||
| double omega1 = (1-eta)*N*(exp(u)*erfc(y) + std::exp(v)*erfc(z)); | ||
| double omega2; | ||
| if (eta < 1.0E-8) | ||
| { | ||
| omega2 = 0.0; | ||
| } | ||
| else | ||
| { | ||
| omega2 = 2*N*eta/PI*(imag(exp(p)*E1(p)) + imag(exp(q)*E1(q))); | ||
| } | ||
| double omega = omega1+omega2; | ||
|
|
||
| return omega; | ||
| } | ||
|
|
||
| /* | ||
| * Implementation of complex integral E_1 | ||
| */ | ||
| std::complex<double> ThermoNeutronBackToBackExpPV::E1(std::complex<double> z) const | ||
| { | ||
| return z; | ||
| } | ||
|
|
||
| void ThermoNeutronBackToBackExpPV::geneatePeak(double* out, const double* xValues, const size_t nData) | ||
| { | ||
| this->functionLocal(out, xValues, nData); | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| void ThermoNeutronBackToBackExpPV::calHandEta(double sigma2, double gamma, double& H, double& eta) const | ||
| { | ||
| // 1. Calculate H | ||
| double H_G = sqrt(8.0 * sigma2 * log(2.0)); | ||
| double H_L = gamma; | ||
|
|
||
| double temp1 = std::pow(H_L, 5) + 0.07842*H_G*std::pow(H_L, 4) + 4.47163*std::pow(H_G, 2)*std::pow(H_L, 3) + | ||
| 2.42843*std::pow(H_G, 3)*std::pow(H_L, 2) + 2.69269*std::pow(H_G, 4)*H_L + std::pow(H_G, 5); | ||
|
|
||
| H = std::pow(temp1, 0.2); | ||
|
|
||
| mFWHM = H; | ||
|
|
||
| // 2. Calculate eta | ||
| double gam_pv = H_L/H; | ||
| eta = 1.36603 * gam_pv - 0.47719 * std::pow(gam_pv, 2) + 0.11116 * std::pow(gam_pv, 3); | ||
|
|
||
| if (eta > 1 || eta < 0) | ||
| { | ||
| g_log.error() << "Calculated eta = " << eta << " is out of range [0, 1]." << std::endl; | ||
| } | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| } // namespace Mantid | ||
| } // namespace CurveFitting |
| @@ -0,0 +1,188 @@ | ||
| #ifndef MANTID_CURVEFITTING_THERMONEUTRONBACKTOBACKEXPPVTEST_H_ | ||
| #define MANTID_CURVEFITTING_THERMONEUTRONBACKTOBACKEXPPVTEST_H_ | ||
|
|
||
| #include <cxxtest/TestSuite.h> | ||
| #include "MantidKernel/Timer.h" | ||
| #include "MantidKernel/System.h" | ||
| #include <iostream> | ||
| #include <iomanip> | ||
| #include <fstream> | ||
|
|
||
| #include "MantidCurveFitting/ThermoNeutronBackToBackExpPV.h" | ||
| #include "MantidCurveFitting/Fit.h" | ||
| #include "MantidAPI/WorkspaceFactory.h" | ||
| #include "MantidDataObjects/Workspace2D.h" | ||
|
|
||
| using namespace Mantid; | ||
| using namespace Mantid::CurveFitting; | ||
| using namespace Mantid::API; | ||
|
|
||
| class ThermoNeutronBackToBackExpPVTest : public CxxTest::TestSuite | ||
| { | ||
| public: | ||
| // This pair of boilerplate methods prevent the suite being created statically | ||
| // This means the constructor isn't called when running other tests | ||
| static ThermoNeutronBackToBackExpPVTest *createSuite() { return new ThermoNeutronBackToBackExpPVTest(); } | ||
| static void destroySuite( ThermoNeutronBackToBackExpPVTest *suite ) { delete suite; } | ||
|
|
||
| /* | ||
| * Experiment data for HKL = (2, 1, 0) | ||
| */ | ||
| void getMockData(std::vector<double>& xvalues, std::vector<double>& yvalues) | ||
| { | ||
| xvalues.clear(); | ||
| yvalues.clear(); | ||
|
|
||
| xvalues.push_back(54999.094); yvalues.push_back(2.6283364); | ||
| xvalues.push_back(55010.957); yvalues.push_back(4.0346470); | ||
| xvalues.push_back(55022.820); yvalues.push_back(6.1934152); | ||
| xvalues.push_back(55034.684); yvalues.push_back(9.5072470); | ||
| xvalues.push_back(55046.547); yvalues.push_back(14.594171); | ||
| xvalues.push_back(55058.410); yvalues.push_back(22.402889); | ||
| xvalues.push_back(55070.273); yvalues.push_back(34.389721); | ||
| xvalues.push_back(55082.137); yvalues.push_back(52.790192); | ||
| xvalues.push_back(55094.000); yvalues.push_back(81.035973); | ||
| xvalues.push_back(55105.863); yvalues.push_back(124.39484); | ||
| xvalues.push_back(55117.727); yvalues.push_back(190.95044); | ||
| xvalues.push_back(55129.590); yvalues.push_back(293.01022); | ||
| xvalues.push_back(55141.453); yvalues.push_back(447.60229); | ||
| xvalues.push_back(55153.320); yvalues.push_back(664.84778); | ||
| xvalues.push_back(55165.184); yvalues.push_back(900.43817); | ||
| xvalues.push_back(55177.047); yvalues.push_back(1028.0037); | ||
| xvalues.push_back(55188.910); yvalues.push_back(965.38873); | ||
| xvalues.push_back(55200.773); yvalues.push_back(787.02441); | ||
| xvalues.push_back(55212.637); yvalues.push_back(603.50177); | ||
| xvalues.push_back(55224.500); yvalues.push_back(456.12289); | ||
| xvalues.push_back(55236.363); yvalues.push_back(344.13235); | ||
| xvalues.push_back(55248.227); yvalues.push_back(259.61121); | ||
| xvalues.push_back(55260.090); yvalues.push_back(195.84842); | ||
| xvalues.push_back(55271.953); yvalues.push_back(147.74631); | ||
| xvalues.push_back(55283.816); yvalues.push_back(111.45851); | ||
| xvalues.push_back(55295.680); yvalues.push_back(84.083313); | ||
| xvalues.push_back(55307.543); yvalues.push_back(63.431709); | ||
| xvalues.push_back(55319.406); yvalues.push_back(47.852318); | ||
| xvalues.push_back(55331.270); yvalues.push_back(36.099365); | ||
| xvalues.push_back(55343.133); yvalues.push_back(27.233042); | ||
| xvalues.push_back(55354.996); yvalues.push_back(20.544367); | ||
| xvalues.push_back(55366.859); yvalues.push_back(15.498488); | ||
| xvalues.push_back(55378.727); yvalues.push_back(11.690837); | ||
| xvalues.push_back(55390.590); yvalues.push_back(8.8194647); | ||
| xvalues.push_back(55402.453); yvalues.push_back(6.6533256); | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| /* | ||
| * Test 1 | ||
| */ | ||
| void test_functionCalculator() | ||
| { | ||
| // 1. Set peak | ||
| ThermoNeutronBackToBackExpPV peak; | ||
| peak.initialize(); | ||
|
|
||
| /* | ||
| * 2 1 0 1.859018 55175.79 0.03613 0.02376 187.50514 0.00000 30.46799 3.4990 52.2059 91.3293 0.5385 | ||
| */ | ||
|
|
||
| peak.setParameter("height", 111.0); | ||
| peak.setParameter("TOF_h", 55175.79); | ||
|
|
||
| // peak.tie("TOF_h", "55175.79"); | ||
| peak.tie("Alpha", "0.03613"); | ||
| peak.tie("Beta", "0.02376"); | ||
| peak.tie("Sigma2", "187.50514"); | ||
| peak.tie("Gamma", "0.0"); | ||
| // peak.setParameter("height", 1.0*100*1000); | ||
|
|
||
| // 2. Set workspace | ||
| std::vector<double> Xs; | ||
| std::vector<double> Ys; | ||
| getMockData(Xs, Ys); | ||
|
|
||
| size_t histogramNumber = 1; | ||
| size_t timechannels = Xs.size(); | ||
| Workspace_sptr ws = WorkspaceFactory::Instance().create("Workspace2D", histogramNumber, timechannels, timechannels); | ||
| DataObjects::Workspace2D_sptr ws2D = boost::dynamic_pointer_cast<DataObjects::Workspace2D>(ws); | ||
|
|
||
| MantidVec& wsX = ws2D->dataX(0); | ||
| MantidVec& wsY = ws2D->dataY(0); | ||
| MantidVec& wsE = ws2D->dataE(0); | ||
| for (size_t i = 0; i < timechannels; ++i) | ||
| { | ||
| wsX[i] = Xs[i]; | ||
| wsY[i] = Ys[i]; | ||
| wsE[i] = std::sqrt(fabs(Ys[i])); | ||
| } | ||
|
|
||
| //put this workspace in the data service | ||
| std::string wsName("Peak210WS"); | ||
| TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().add(wsName, ws2D)); | ||
|
|
||
| std::cout << "Number of data points to fit = " << ws2D->readX(0).size() << std::endl; | ||
|
|
||
| // 3. Set fit | ||
| Fit fitalg; | ||
| fitalg.initialize(); | ||
| TS_ASSERT(fitalg.isInitialized()); | ||
|
|
||
| // Note: Function must be set before InputWorkspace for Fit | ||
| fitalg.setPropertyValue("Function", peak.asString()); | ||
| fitalg.setPropertyValue("InputWorkspace", wsName); | ||
| fitalg.setPropertyValue("WorkspaceIndex","0"); | ||
| fitalg.setProperty("StartX", wsX[0]); | ||
| fitalg.setProperty("EndX", wsX.back()); | ||
| // fitalg.setProperty("Minimizer", "Levenberg-MarquardtMD"); | ||
| fitalg.setProperty("Minimizer", "Simplex"); | ||
| fitalg.setProperty("CostFunction", "Least squares"); | ||
| fitalg.setProperty("MaxIterations", 100); | ||
|
|
||
| // 4. Execute fit | ||
| TS_ASSERT_THROWS_NOTHING(fitalg.execute()); | ||
| TS_ASSERT(fitalg.isExecuted()); | ||
|
|
||
| // test the output from fit is what you expect | ||
| double dummy = fitalg.getProperty("OutputChi2overDoF"); | ||
| std::cout << "Chi2 = " << dummy << std::endl; | ||
|
|
||
| std::string fitStatus = fitalg.getProperty("OutputStatus"); | ||
| std::cout << "Fit status = " << fitStatus << std::endl; | ||
|
|
||
| // 5. Check result | ||
| IFunction_sptr out = fitalg.getProperty("Function"); | ||
| std::vector<std::string> parnames = out->getParameterNames(); | ||
| std::cout << "Number of Parameters = " << parnames.size() << std::endl; | ||
| for (size_t ip = 0; ip < parnames.size(); ++ip) | ||
| { | ||
| std::string parname = parnames[ip]; | ||
| double parvalue = out->getParameter(parname); | ||
| std::cout << parname << " = " << parvalue << std::endl; | ||
| } | ||
|
|
||
| /* | ||
| std::cout << "InputWorkspace: " << std::endl; | ||
| API::MatrixWorkspace_sptr inpWS = | ||
| boost::dynamic_pointer_cast<API::MatrixWorkspace>(AnalysisDataService::Instance().retrieve(wsName)); | ||
| for (size_t i = 0; i < inpWS->readX(0).size(); ++i) | ||
| { | ||
| std::cout << i << " X = " << inpWS->readX(0)[i] << " Y = " << inpWS->readY(0)[i] << " E = " << inpWS->readE(0)[i] << std::endl; | ||
| } | ||
| */ | ||
|
|
||
| /* | ||
| peak.geneatePeak(out, xvalues, nData); | ||
| std::ofstream ofile; | ||
| ofile.open("prof10.dat", std::ios::out); | ||
| for (size_t i = 0; i < nData; ++i) | ||
| ofile << xvalues[i] << " " << out[i] << std::endl; | ||
| ofile.close(); | ||
| */ | ||
|
|
||
| } | ||
|
|
||
|
|
||
| }; | ||
|
|
||
|
|
||
| #endif /* MANTID_CURVEFITTING_THERMONEUTRONBACKTOBACKEXPPVTEST_H_ */ |