Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement a profile function to fit a mass peak in Y-space.
Used in neutron compton scattering to Fit a spectrum using only the proton peak. Refs #8598
- Loading branch information
1 parent
cc054f9
commit 6c9b13e
Showing
7 changed files
with
371 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/ComptonPeakProfile.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#ifndef MANTID_CURVEFITTING_COMPTONPEAKPROFILE_H_ | ||
#define MANTID_CURVEFITTING_COMPTONPEAKPROFILE_H_ | ||
|
||
#include "MantidCurveFitting/DllConfig.h" | ||
#include "MantidAPI/IPeakFunction.h" | ||
#include "MantidAPI/MatrixWorkspace.h" | ||
#include "MantidAPI/ParamFunction.h" | ||
|
||
namespace Mantid | ||
{ | ||
namespace CurveFitting | ||
{ | ||
/** | ||
This implements a resolution function for fitting a single mass in a compton scattering spectrum. The | ||
function has two domains defined by the VoigtEnergyCutOff attribute: | ||
- < VoigtEnergyCutOff: Voigt approximation to spectrum is used | ||
- >= VoigtEnergyCutOff: Gaussian approximation to spectrum is used. | ||
Both are normalized by the peak area. | ||
Copyright © 2013 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory | ||
This file is part of Mantid. | ||
Mantid 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. | ||
Mantid 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 this program. If not, see <http://www.gnu.org/licenses/>. | ||
File change history is stored at: <https://github.com/mantidproject/mantid> | ||
Code Documentation is available at: <http://doxygen.mantidproject.org> | ||
*/ | ||
class MANTID_CURVEFITTING_DLL ComptonPeakProfile : public virtual API::ParamFunction, | ||
public virtual API::IFunction1D | ||
{ | ||
public: | ||
/// Default constructor required for factory | ||
ComptonPeakProfile(); | ||
|
||
private: | ||
std::string name() const; | ||
|
||
/** @name Function evaluation */ | ||
///@{ | ||
/// Calculate the function | ||
void function1D(double* out, const double* xValues, const size_t nData) const; | ||
/// Ensure the object is ready to be fitted | ||
void setUpForFit(); | ||
/// Cache a copy of the workspace pointer and pull out the parameters | ||
void setWorkspace(boost::shared_ptr<const API::Workspace> ws); | ||
///@} | ||
|
||
void declareParameters(); | ||
void declareAttributes(); | ||
void setAttribute(const std::string& name,const Attribute& value); | ||
|
||
/// WorkspaceIndex attribute | ||
size_t m_wsIndex; | ||
/// Mass of peak | ||
double m_mass; | ||
/// Below this value a Voigt is used for profile approximation | ||
double m_voigtCutOff; | ||
|
||
/// Gaussian function for lower-energy peaks | ||
boost::shared_ptr<API::IPeakFunction> m_gauss; | ||
/// Voigt function for higher-energy peaks | ||
boost::shared_ptr<API::IPeakFunction> m_voigt; | ||
|
||
/// Final energy of analyser | ||
double m_efixed; | ||
/// Calculated value of lorentz width | ||
double m_hwhmLorentz; | ||
}; | ||
|
||
|
||
} // namespace CurveFitting | ||
} // namespace Mantid | ||
|
||
#endif /* MANTID_CURVEFITTING_COMPTONPEAKPROFILE_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
157 changes: 157 additions & 0 deletions
157
Code/Mantid/Framework/CurveFitting/src/ComptonPeakProfile.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
//----------------------------------------------------------------------------- | ||
// Includes | ||
//----------------------------------------------------------------------------- | ||
#include "MantidCurveFitting/ComptonPeakProfile.h" | ||
#include "MantidCurveFitting/ConvertToYSpace.h" | ||
#include "MantidAPI/FunctionFactory.h" | ||
|
||
namespace Mantid | ||
{ | ||
namespace CurveFitting | ||
{ | ||
|
||
DECLARE_FUNCTION(ComptonPeakProfile); | ||
|
||
namespace | ||
{ | ||
///@cond | ||
const char * WSINDEX_NAME = "WorkspaceIndex"; | ||
const char * MASS_NAME = "Mass"; | ||
const char * VOIGT_CUT_OFF = "VoigtEnergyCutOff"; | ||
|
||
const char * AMP_PARAM = "Intensity"; | ||
const char * POS_PARAM = "Position"; | ||
const char * WIDTH_PARAM = "SigmaGauss"; | ||
|
||
/// Conversion constant | ||
const double MASS_TO_MEV = 0.5*PhysicalConstants::NeutronMass/PhysicalConstants::meV; | ||
const double STDDEV_TO_FWHM = 0.5*std::sqrt(std::log(4.0)); | ||
///@endcond | ||
} | ||
|
||
/** | ||
*/ | ||
ComptonPeakProfile::ComptonPeakProfile() : API::ParamFunction(), API::IFunction1D(), | ||
m_wsIndex(0), m_mass(0.0), m_voigtCutOff(5000.), | ||
m_gauss(), m_voigt(), m_efixed(0.0), m_hwhmLorentz(0.0) | ||
{} | ||
|
||
//-------------------------------------- Private methods ----------------------------------------- | ||
|
||
/// A string identifier for this function | ||
std::string ComptonPeakProfile::name() const { return "ComptonPeakProfile"; } | ||
|
||
/** | ||
* Calculates the value of the function for each x value and stores in the given output array | ||
* @param out An array of size nData to store the results | ||
* @param xValues The input X data array of size nData. | ||
* @param nData The length of the out & xValues arrays | ||
*/ | ||
void ComptonPeakProfile::function1D(double* out, const double* xValues, const size_t nData) const | ||
{ | ||
double amp(getParameter(0)), pos(getParameter(1)), gaussSigma(getParameter(2)); | ||
|
||
if(m_efixed < m_voigtCutOff) | ||
{ | ||
double gaussFWHM(getParameter(2)*STDDEV_TO_FWHM), lorentzFWHM(2.0*m_hwhmLorentz); | ||
m_voigt->setParameter(0,amp); | ||
m_voigt->setParameter(1,pos); | ||
m_voigt->setParameter(2,lorentzFWHM); | ||
m_voigt->setParameter(3, gaussFWHM); | ||
m_voigt->functionLocal(out, xValues, nData); | ||
const double norm = 1.0/(0.5*M_PI*lorentzFWHM); | ||
std::transform(out, out + nData, out, std::bind2nd(std::multiplies<double>(), norm)); | ||
} | ||
else | ||
{ | ||
double sigmaTotalSq = m_hwhmLorentz*m_hwhmLorentz + gaussSigma*gaussSigma; | ||
// Our gaussian isn't normalised by the width. Here we set the height to | ||
// amp/(2*sigma^2) so that it will be normalised correctly | ||
m_gauss->setParameter(0, 0.5*amp/M_PI/sigmaTotalSq); | ||
m_gauss->setParameter(1, pos); | ||
m_gauss->setParameter(2, sqrt(sigmaTotalSq)); | ||
m_gauss->functionLocal(out, xValues, nData); | ||
} | ||
} | ||
|
||
/* | ||
* Creates the internal caches | ||
*/ | ||
void ComptonPeakProfile::setUpForFit() | ||
{ | ||
// Voigt & Gaussian | ||
using namespace Mantid::API; | ||
m_gauss = boost::dynamic_pointer_cast<IPeakFunction>(FunctionFactory::Instance().createFunction("Gaussian")); | ||
m_voigt = boost::dynamic_pointer_cast<IPeakFunction>(FunctionFactory::Instance().createFunction("Voigt")); | ||
} | ||
|
||
/** | ||
* Also caches parameters from the instrument | ||
* Throws if it is not a MatrixWorkspace | ||
* @param ws The workspace set as input | ||
*/ | ||
void ComptonPeakProfile::setWorkspace(boost::shared_ptr<const API::Workspace> ws) | ||
{ | ||
auto workspace = boost::dynamic_pointer_cast<const API::MatrixWorkspace>(ws); | ||
if(!workspace) | ||
{ | ||
throw std::invalid_argument("ComptonPeakProfile expected an object of type MatrixWorkspace, type=" + ws->id()); | ||
} | ||
|
||
DetectorParams detpar = ConvertToYSpace::getDetectorParameters(workspace, m_wsIndex); | ||
m_efixed = detpar.efixed; | ||
|
||
// Recoil time | ||
const double sth = sin(detpar.theta); | ||
const double distFact = (cos(detpar.theta) + sqrt(m_mass*m_mass - sth*sth))/(m_mass+1.0); | ||
const double ei = detpar.efixed/pow(distFact,2.0); | ||
const double v1 = std::sqrt(detpar.efixed/MASS_TO_MEV); | ||
const double k1 = std::sqrt(detpar.efixed/PhysicalConstants::E_mev_toNeutronWavenumberSq); | ||
const double v2 = std::sqrt(ei/MASS_TO_MEV); | ||
const double trec = detpar.l1/v1 + detpar.l2/v2; | ||
|
||
// Compute lorentz width due to in Y due to spread in energy hwhm_lorentz | ||
const double dELorentz = | ||
ConvertToYSpace::getComponentParameter(workspace->getDetector(m_wsIndex), workspace->constInstrumentParameters(), | ||
"hwhm_lorentz"); | ||
double yplus(0.0), yminus(0.0), dummy(0.0); | ||
detpar.efixed += dELorentz; | ||
ConvertToYSpace::calculateY(yplus,dummy,dummy,m_mass,trec*1e6,k1,v1,detpar); | ||
detpar.efixed -= 2.0*dELorentz; | ||
ConvertToYSpace::calculateY(yminus,dummy,dummy,m_mass,trec*1e6,k1,v1,detpar); | ||
// lorentzian width | ||
m_hwhmLorentz = 0.5*(yplus-yminus); | ||
} | ||
|
||
/** | ||
*/ | ||
void ComptonPeakProfile::declareParameters() | ||
{ | ||
declareParameter(AMP_PARAM, 1.0, "Intensity parameter"); | ||
declareParameter(POS_PARAM, 1.0, "Peak position parameter"); | ||
declareParameter(WIDTH_PARAM, 1.0, "Width parameter"); | ||
} | ||
|
||
/** | ||
*/ | ||
void ComptonPeakProfile::declareAttributes() | ||
{ | ||
declareAttribute(WSINDEX_NAME, IFunction::Attribute(static_cast<int>(m_wsIndex))); | ||
declareAttribute(MASS_NAME, IFunction::Attribute(m_mass)); | ||
declareAttribute(VOIGT_CUT_OFF, IFunction::Attribute(m_voigtCutOff)); | ||
} | ||
|
||
/** | ||
* @param name The name of the attribute | ||
* @param value The attribute's value | ||
*/ | ||
void ComptonPeakProfile::setAttribute(const std::string& name,const Attribute& value) | ||
{ | ||
IFunction::setAttribute(name,value); // Make sure the base-class stores it | ||
if(name == WSINDEX_NAME) m_wsIndex = static_cast<size_t>(value.asInt()); | ||
else if(name == MASS_NAME) m_mass = value.asDouble(); | ||
else if(name == VOIGT_CUT_OFF) m_voigtCutOff = value.asDouble(); | ||
} | ||
|
||
} // namespace CurveFitting | ||
} // namespace Mantid |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.