Mantid
Loading...
Searching...
No Matches
PeakIntegration.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
12#include "MantidAPI/Sample.h"
21
22#include <boost/math/special_functions/round.hpp>
23#include <cmath>
24
25namespace Mantid::Crystal {
26
27// Register the class into the algorithm factory
28DECLARE_ALGORITHM(PeakIntegration)
29
30using namespace Kernel;
31using namespace Geometry;
32using namespace API;
33using namespace DataObjects;
34
39
40 declareProperty(std::make_unique<WorkspaceProperty<PeaksWorkspace>>("InPeaksWorkspace", "", Direction::Input),
41 "Name of the peaks workspace.");
42 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input,
43 std::make_shared<InstrumentValidator>()),
44 "A 2D workspace with X values of time of flight");
45 declareProperty(std::make_unique<WorkspaceProperty<PeaksWorkspace>>("OutPeaksWorkspace", "", Direction::Output),
46 "Name of the output peaks workspace with integrated intensities.");
47 declareProperty("IkedaCarpenterTOF", false,
48 "Integrate TOF using IkedaCarpenter fit.\n"
49 "Default is false which is best for corrected data.");
50 declareProperty("MatchingRunNo", true,
51 "Integrate only peaks where run "
52 "number of peak matches run number of "
53 "sample.\n"
54 "Default is true.");
55 declareProperty("NBadEdgePixels", 0, "Number of bad Edge Pixels");
56}
57
65
67 PeaksWorkspace_sptr inPeaksW = getProperty("InPeaksWorkspace");
68
70 PeaksWorkspace_sptr peaksW = getProperty("OutPeaksWorkspace");
71 if (peaksW != inPeaksW)
72 peaksW = inPeaksW->clone();
73
74 double qspan = 0.12;
75 m_IC = getProperty("IkedaCarpenterTOF");
76 bool matchRun = getProperty("MatchingRunNo");
77 if (peaksW->mutableSample().hasOrientedLattice()) {
78 OrientedLattice latt = peaksW->mutableSample().getOrientedLattice();
79 qspan = 1. / std::max(latt.a(), std::max(latt.b(), latt.c())); // 1/6*2Pi about 1
80
81 } else {
82 qspan = 0.12;
83 }
84
85 // To get the workspace index from the detector ID
86 const auto pixel_to_wi = inputW->getDetectorIDToWorkspaceIndexMap();
87
88 // Sort events if EventWorkspace so it will run in parallel
89 EventWorkspace_const_sptr inWS = std::dynamic_pointer_cast<const EventWorkspace>(inputW);
90 if (inWS) {
91 inWS->sortAll(TOF_SORT, nullptr);
92 }
93
94 // Get some stuff from the input workspace
95 const auto YLength = static_cast<int>(inputW->blocksize());
96 outputW = API::WorkspaceFactory::Instance().create(inputW, peaksW->getNumberPeaks(), YLength + 1, YLength);
97 // Copy geometry over.
98 API::WorkspaceFactory::Instance().initializeFromParent(*inputW, *outputW, true);
99 size_t Numberwi = inputW->getNumberHistograms();
100 int NumberPeaks = peaksW->getNumberPeaks();
101 int MinPeaks = 0;
102
103 std::vector<int> badPeaks;
104 for (int i = NumberPeaks - 1; i >= 0; i--) {
105 Peak const &peak = peaksW->getPeaks()[i];
106 int pixelID = peak.getDetectorID();
107
108 // Find the workspace index for this detector ID
109 auto wiEntry = pixel_to_wi.find(pixelID);
110 if (wiEntry != pixel_to_wi.end()) {
111 size_t wi = wiEntry->second;
112 if ((matchRun && peak.getRunNumber() != inputW->getRunNumber()) || wi >= Numberwi)
113 badPeaks.emplace_back(i);
114 } else if (i + 1 > MinPeaks) {
115 // This is for appending peak workspaces when running
116 // SNSSingleCrystalReduction one bank at at time
117 MinPeaks = i + 1;
118 }
119 }
120 peaksW->removePeaks(std::move(badPeaks));
121 NumberPeaks = peaksW->getNumberPeaks();
122 if (NumberPeaks <= 0) {
123 g_log.error("RunNumbers of InPeaksWorkspace and InputWorkspace do not match");
124 return;
125 }
126
127 Progress prog(this, MinPeaks, 1.0, NumberPeaks);
129 for (int i = MinPeaks; i < NumberPeaks; i++) {
130
132
133 // Direct ref to that peak
134 Peak &peak = peaksW->getPeaks()[i];
135
136 double col = peak.getCol();
137 double row = peak.getRow();
138
139 // Average integer postion
140 int XPeak = boost::math::iround(col);
141 int YPeak = boost::math::iround(row);
142
143 double TOFPeakd = peak.getTOF();
144 std::string bankName = peak.getBankName();
145
146 std::shared_ptr<const IComponent> parent = inputW->getInstrument()->getComponentByName(bankName);
147
148 if (!parent)
149 continue;
150
151 int TOFPeak = 0, TOFmin = 0, TOFmax = 0;
152 TOFmax = fitneighbours(i, bankName, XPeak, YPeak, i, qspan, peaksW, pixel_to_wi);
153
154 double I = 0., sigI = 0.;
155 // Find point of peak centre
156 // Get references to the current spectrum
157 const auto &X = outputW->x(i);
158 const auto &Y = outputW->y(i);
159 const auto &E = outputW->e(i);
160 auto numbins = static_cast<int>(Y.size());
161 if (TOFmin > numbins)
162 TOFmin = numbins;
163 if (TOFmax > numbins)
164 TOFmax = numbins;
165
166 TOFPeak = VectorHelper::getBinIndex(X.rawData(), TOFPeakd);
167 const double peakLoc = X[TOFPeak];
168 int iTOF;
169 for (iTOF = TOFmin; iTOF < TOFmax; iTOF++) {
170 if (Y[iTOF] > 0.0 && Y[iTOF + 1] > 0.0)
171 break;
172 }
173 TOFmin = iTOF;
174 for (iTOF = TOFmax; iTOF > TOFmin; iTOF--) {
175 if (Y[iTOF] > 0.0 && Y[iTOF - 1] > 0.0)
176 break;
177 }
178 TOFmax = iTOF;
179 if (TOFmax <= TOFmin)
180 continue;
181 const int n = TOFmax - TOFmin + 1;
182 // double pktime = 0.0;
183
184 // for (iTOF = TOFmin; iTOF < TOFmax; iTOF++) pktime+= X[iTOF];
185 if (n >= 8 && m_IC) // Number of fitting parameters large enough if
186 // Ikeda-Carpenter fit
187 {
188 for (iTOF = TOFmin; iTOF <= TOFmax; iTOF++) {
189 if (((Y[iTOF] - Y[TOFPeak] / 2.) * (Y[iTOF + 1] - Y[TOFPeak] / 2.)) < 0.)
190 break;
191 }
192 double Gamma = fabs(X[TOFPeak] - X[iTOF]);
193 double SigmaSquared = Gamma * Gamma;
194 const double peakHeight = Y[TOFPeak] * Gamma; // Intensity*HWHM
195
196 IAlgorithm_sptr fit_alg;
197 try {
198 fit_alg = createChildAlgorithm("Fit", -1, -1, false);
199 } catch (Exception::NotFoundError &) {
200 g_log.error("Can't locate Fit algorithm");
201 throw;
202 }
203 // Initialize Ikeda-Carpender function variables
204 double Alpha0 = 1.6;
205 double Alpha1 = 1.5;
206 double Beta0 = 31.9;
207 double Kappa = 46.0;
208 std::ostringstream fun_str;
209 fun_str << "name=IkedaCarpenterPV,I=" << peakHeight << ",Alpha0=" << Alpha0 << ",Alpha1=" << Alpha1
210 << ",Beta0=" << Beta0 << ",Kappa=" << Kappa << ",SigmaSquared=" << SigmaSquared << ",Gamma=" << Gamma
211 << ",X0=" << peakLoc;
212 fit_alg->setPropertyValue("Function", fun_str.str());
213 if (Alpha0 != 1.6 || Alpha1 != 1.5 || Beta0 != 31.9 || Kappa != 46.0) {
214 std::ostringstream tie_str;
215 tie_str << "Alpha0=" << Alpha0 << ",Alpha1=" << Alpha1 << ",Beta0=" << Beta0 << ",Kappa=" << Kappa;
216 fit_alg->setProperty("Ties", tie_str.str());
217 }
218 fit_alg->setProperty("InputWorkspace", outputW);
219 fit_alg->setProperty("WorkspaceIndex", i);
220 fit_alg->setProperty("StartX", X[TOFmin]);
221 fit_alg->setProperty("EndX", X[TOFmax]);
222 fit_alg->setProperty("MaxIterations", 5000);
223 fit_alg->setProperty("CreateOutput", true);
224 fit_alg->setProperty("Output", "fit");
225 fit_alg->executeAsChildAlg();
226 MatrixWorkspace_sptr fitWS = fit_alg->getProperty("OutputWorkspace");
227
228 /*double chisq = fit_alg->getProperty("OutputChi2overDoF");
229 if(chisq > 0 && chisq < 400 && !haveFit && PeakIntensity < 30.0) // use
230 fit of strong peaks for weak peaks
231 {
232 std::vector<double> params = fit_alg->getProperty("Parameters");
233 Alpha0 = params[1];
234 Alpha1 = params[2];
235 Beta0 = params[3];
236 Kappa = params[4];
237 haveFit = true;
238 }
239 std::string funct = fit_alg->getPropertyValue("Function");
240 */
241
242 // Evaluate fit at points
243 const auto &y = fitWS->y(1);
244
245 // Calculate intensity
246 for (iTOF = 0; iTOF < n; iTOF++)
247 if (std::isfinite(y[iTOF]))
248 I += y[iTOF];
249 } else
250 for (iTOF = TOFmin; iTOF <= TOFmax; iTOF++)
251 I += Y[iTOF];
252
253 if (!m_IC) {
254 sigI = peak.getSigmaIntensity();
255 } else {
256 // Calculate errors correctly for nonPoisson distributions
257 for (iTOF = TOFmin; iTOF <= TOFmax; iTOF++)
258 sigI += E[iTOF] * E[iTOF];
259 sigI = sqrt(sigI);
260 }
261
262 peak.setIntensity(I);
263 peak.setSigmaIntensity(sigI);
264
265 prog.report();
267 }
268
270
271 // Save the output
272 setProperty("OutPeaksWorkspace", peaksW);
273}
274
276 inputW = getProperty("InputWorkspace");
277 if (inputW->y(0).size() <= 1)
278 throw std::runtime_error("Must Rebin data with more than 1 bin");
279 // Check if detectors are RectangularDetectors
280 Instrument_const_sptr inst = inputW->getInstrument();
281 std::shared_ptr<RectangularDetector> det;
282 for (int i = 0; i < inst->nelements(); i++) {
283 det = std::dynamic_pointer_cast<RectangularDetector>((*inst)[i]);
284 if (det)
285 break;
286 }
287}
288
289int PeakIntegration::fitneighbours(int ipeak, const std::string &det_name, int x0, int y0, int idet, double qspan,
290 PeaksWorkspace_sptr &Peaks, const detid2index_map &pixel_to_wi) {
291 UNUSED_ARG(det_name);
292 UNUSED_ARG(x0);
293 UNUSED_ARG(y0);
294 Peak &peak = Peaks->getPeak(ipeak);
295 // Number of slices
296 int TOFmax = 0;
297
298 auto slice_alg = createChildAlgorithm("IntegratePeakTimeSlices");
299 slice_alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", inputW);
300 std::ostringstream tab_str;
301 tab_str << "LogTable" << ipeak;
302
303 slice_alg->setPropertyValue("OutputWorkspace", tab_str.str());
304 slice_alg->setProperty<PeaksWorkspace_sptr>("Peaks", Peaks);
305 slice_alg->setProperty("PeakIndex", ipeak);
306 slice_alg->setProperty("PeakQspan", qspan);
307
308 int nPixels = std::max<int>(0, getProperty("NBadEdgePixels"));
309
310 slice_alg->setProperty("NBadEdgePixels", nPixels);
311 slice_alg->executeAsChildAlg();
312
313 auto &Xout = outputW->mutableX(idet);
314 auto &Yout = outputW->mutableY(idet);
315 auto &Eout = outputW->mutableE(idet);
316 TableWorkspace_sptr logtable = slice_alg->getProperty("OutputWorkspace");
317
318 peak.setIntensity(slice_alg->getProperty("Intensity"));
319 peak.setSigmaIntensity(slice_alg->getProperty("SigmaIntensity"));
320
321 TOFmax = static_cast<int>(logtable->rowCount());
322 for (int iTOF = 0; iTOF < TOFmax; iTOF++) {
323 Xout[iTOF] = logtable->getRef<double>(std::string("Time"), iTOF);
324 if (m_IC) // Ikeda-Carpenter fit
325 {
326 Yout[iTOF] = logtable->getRef<double>(std::string("TotIntensity"), iTOF);
327 Eout[iTOF] = logtable->getRef<double>(std::string("TotIntensityError"), iTOF);
328 } else {
329 Yout[iTOF] = logtable->getRef<double>(std::string("ISAWIntensity"), iTOF);
330 Eout[iTOF] = logtable->getRef<double>(std::string("ISAWIntensityError"), iTOF);
331 }
332 }
333
334 outputW->getSpectrum(idet).clearDetectorIDs();
335 // Find the pixel ID at that XY position on the rectangular detector
336 int pixelID = peak.getDetectorID(); // det->getAtXY(x0,y0)->getID();
337
338 // Find the corresponding workspace index, if any
339 auto wiEntry = pixel_to_wi.find(pixelID);
340 if (wiEntry != pixel_to_wi.end()) {
341 size_t wi = wiEntry->second;
342 // Set detectorIDs
343 outputW->getSpectrum(idet).addDetectorIDs(inputW->getSpectrum(wi).getDetectorIDs());
344 }
345
346 return TOFmax - 1;
347}
348
349} // namespace Mantid::Crystal
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
#define fabs(x)
Definition Matrix.cpp:22
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:48
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Kernel::Logger & g_log
Definition Algorithm.h:422
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
bool m_IC
Ikeida Carpenter fit of TOF.
void retrieveProperties()
Read in all the input parameters.
int fitneighbours(int ipeak, const std::string &det_name, int x0, int y0, int idet, double qspan, DataObjects::PeaksWorkspace_sptr &Peaks, const detid2index_map &pixel_to_wi)
API::MatrixWorkspace_sptr outputW
A pointer to the output workspace.
void exec() override
Executes the algorithm.
void init() override
Initialisation method.
API::MatrixWorkspace_sptr inputW
A pointer to the input workspace.
void setSigmaIntensity(double m_sigmaIntensity) override
Set the error on the integrated peak intensity.
Definition BasePeak.cpp:205
int getRunNumber() const override
Return the run number this peak was measured at.
Definition BasePeak.cpp:77
void setIntensity(double m_intensity) override
Set the integrated peak intensity.
Definition BasePeak.cpp:197
Structure describing a single-crystal peak.
Definition Peak.h:34
int getCol() const override
For RectangularDetectors only, returns the column (x) of the pixel of the detector or -1 if not found...
Definition Peak.cpp:335
int getDetectorID() const override
Get the ID of the detector at the center of the peak
Definition Peak.cpp:265
Class to implement UB matrix.
double a(int nd) const
Get lattice parameter a1-a3 as function of index (0-2)
Definition UnitCell.cpp:94
double c() const
Get lattice parameter.
Definition UnitCell.cpp:128
double b() const
Get lattice parameter.
Definition UnitCell.cpp:123
Exception for when an item is not found in a collection.
Definition Exception.h:145
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< const EventWorkspace > EventWorkspace_const_sptr
shared pointer to a const Workspace2D
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::shared_ptr< PeaksWorkspace > PeaksWorkspace_sptr
Typedef for a shared pointer to a peaks workspace.
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
MANTID_KERNEL_DLL int getBinIndex(const std::vector< double > &bins, const double value)
Return the index into a vector of bin boundaries for a particular X value.
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
std::unordered_map< detid_t, size_t > detid2index_map
Map with key = detector ID, value = workspace index.
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54