Mantid
Loading...
Searching...
No Matches
PeakStatisticsTools.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 +
8
11
13
14#include <memory>
15#include <numeric>
16#include <utility>
17
19
20using namespace Mantid::DataObjects;
21using namespace Mantid::Geometry;
22using namespace Mantid::Kernel;
23
26std::vector<double> UniqueReflection::getWavelengths() const {
27 std::vector<double> wavelengths;
28 wavelengths.reserve(m_peaks.size());
29
30 std::transform(m_peaks.begin(), m_peaks.end(), std::back_inserter(wavelengths),
31 [](const DataObjects::Peak &peak) { return peak.getWavelength(); });
32
33 return wavelengths;
34}
35
38std::vector<double> UniqueReflection::getIntensities() const {
39 std::vector<double> intensities;
40 intensities.reserve(m_peaks.size());
41
42 std::transform(m_peaks.begin(), m_peaks.end(), std::back_inserter(intensities),
43 [](const DataObjects::Peak &peak) { return peak.getIntensity(); });
44
45 return intensities;
46}
47
50std::vector<double> UniqueReflection::getSigmas() const {
51 std::vector<double> sigmas;
52 sigmas.reserve(m_peaks.size());
53
54 std::transform(m_peaks.begin(), m_peaks.end(), std::back_inserter(sigmas),
55 [](const DataObjects::Peak &peak) { return peak.getSigmaIntensity(); });
56
57 return sigmas;
58}
59
62UniqueReflection UniqueReflection::removeOutliers(double sigmaCritical, bool weightedZ) const {
63 if (sigmaCritical <= 0.0) {
64 throw std::invalid_argument("Critical sigma value has to be greater than 0.");
65 }
66
67 UniqueReflection newReflection(m_hkl);
68
69 if (m_peaks.size() > 2) {
70 auto intensities = getIntensities();
71 std::vector<double> zScores;
72 if (!weightedZ) {
73 zScores = Kernel::getZscore(intensities);
74 } else {
75 auto sigmas = getSigmas();
76 zScores = Kernel::getWeightedZscore(intensities, sigmas);
77 }
78
79 for (size_t i = 0; i < zScores.size(); ++i) {
80 if (zScores[i] <= sigmaCritical) {
81 newReflection.addPeak(m_peaks[i]);
82 }
83 }
84 } else {
85 for (const auto &peak : m_peaks) {
86 newReflection.addPeak(peak);
87 }
88 }
89
90 return newReflection;
91}
92
94void UniqueReflection::setPeaksIntensityAndSigma(double intensity, double sigma) {
95 for (auto &peak : m_peaks) {
96 peak.setIntensity(intensity);
97 peak.setSigmaIntensity(sigma);
98 }
99}
100
113UniqueReflectionCollection::UniqueReflectionCollection(const UnitCell &cell, const std::pair<double, double> &dLimits,
114 PointGroup_sptr pointGroup,
115 const ReflectionCondition_sptr &centering)
116 : m_reflections(), m_pointgroup(std::move(pointGroup)) {
117 HKLGenerator generator(cell, dLimits.first);
118 auto dFilter = std::make_shared<const HKLFilterDRange>(cell, dLimits.first, dLimits.second);
119 auto centeringFilter = std::make_shared<const HKLFilterCentering>(centering);
120 auto filter = dFilter & centeringFilter;
121
122 // Generate map of UniqueReflection-objects with reflection family as key.
123 for (const auto &hkl : generator) {
124 if (filter->isAllowed(hkl)) {
125 V3D hklFamily = m_pointgroup->getReflectionFamily(hkl);
126 m_reflections.emplace(hklFamily, UniqueReflection(hklFamily));
127 }
128 }
129}
130
133void UniqueReflectionCollection::addObservations(const std::vector<Peak> &peaks) {
134 for (auto const &peak : peaks) {
135 V3D hkl = peak.getIntHKL();
136 V3D mnp = peak.getIntMNP();
137
138 if (mnp.norm2() == 0.0) {
139 auto reflection = m_reflections.find(m_pointgroup->getReflectionFamily(hkl));
140
141 if (reflection != m_reflections.end()) {
142 (*reflection).second.addPeak(peak);
143 }
144 }
145 }
146}
147
151 return m_reflections.at(m_pointgroup->getReflectionFamily(hkl));
152}
153
156
160 return std::count_if(
161 m_reflections.cbegin(), m_reflections.cend(),
162 [=](const std::pair<Kernel::V3D, UniqueReflection> &item) { return item.second.count() > moreThan; });
163}
164
167 std::vector<V3D> reflections;
168 reflections.reserve(m_reflections.size());
169
170 for (const auto &reflection : m_reflections) {
171 if (reflection.second.count() == 0) {
172 reflections.emplace_back(reflection.first);
173 }
174 }
175
176 return reflections;
177}
178
181 return std::accumulate(m_reflections.cbegin(), m_reflections.cend(), size_t(0),
182 [](size_t totalReflections, const std::pair<Kernel::V3D, UniqueReflection> &item) {
183 return totalReflections + item.second.count();
184 });
185}
186
189const std::map<V3D, UniqueReflection> &UniqueReflectionCollection::getReflections() const { return m_reflections; }
190
208void PeaksStatistics::calculatePeaksStatistics(const std::map<V3D, UniqueReflection> &uniqueReflections,
209 std::string const &equivalentIntensities, double &sigmaCritical,
210 bool &weightedZ) {
211 double rMergeNumerator = 0.0;
212 double rPimNumerator = 0.0;
213 double intensitySumRValues = 0.0;
214 double iOverSigmaSum = 0.0;
215
216 for (const auto &unique : uniqueReflections) {
217 /* Since all possible unique reflections are explored
218 * there may be 0 observations for some of them.
219 * In that case, nothing can be done.*/
220 if (unique.second.count() > 0) {
222
223 // Possibly remove outliers.
224 auto outliersRemoved = unique.second.removeOutliers(sigmaCritical, weightedZ);
225
226 // I/sigma is calculated for all reflections, even if there is only one
227 // observation.
228 auto intensities = outliersRemoved.getIntensities();
229 auto sigmas = outliersRemoved.getSigmas();
230
231 // Accumulate the I/sigma's for current reflection into sum
232 iOverSigmaSum += getIOverSigmaSum(sigmas, intensities);
233
234 if (outliersRemoved.count() > 1) {
235 // Get mean, standard deviation for intensities
236 auto intensityStatistics = Kernel::getStatistics(
238
239 double meanIntensity = intensityStatistics.mean;
240 if (equivalentIntensities == "Median")
241 meanIntensity = intensityStatistics.median;
242
243 /* This was in the original algorithm, not entirely sure where it is
244 * used. It's basically the sum of all relative standard deviations.
245 * In a perfect data set with all equivalent reflections exactly
246 * equivalent that would be 0. */
247 m_chiSquared += intensityStatistics.standard_deviation / meanIntensity;
248
249 // For both RMerge and RPim sum(|I - <I>|) is required
250 double sumOfDeviationsFromMean =
251 std::accumulate(intensities.begin(), intensities.end(), 0.0, [meanIntensity](double sum, double intensity) {
252 return sum + fabs(intensity - meanIntensity);
253 });
254
255 // Accumulate into total sum for numerator of RMerge
256 rMergeNumerator += sumOfDeviationsFromMean;
257
258 // For Rpim, the sum is weighted by a factor depending on N
259 double rPimFactor = sqrt(1.0 / (static_cast<double>(outliersRemoved.count()) - 1.0));
260 rPimNumerator += (rPimFactor * sumOfDeviationsFromMean);
261
262 // Collect sum of intensities for R-value calculation
263 intensitySumRValues += std::accumulate(intensities.begin(), intensities.end(), 0.0);
264 }
265
266 const std::vector<Peak> &reflectionPeaks = outliersRemoved.getPeaks();
267 m_peaks.insert(m_peaks.end(), reflectionPeaks.begin(), reflectionPeaks.end());
268 }
269 }
270
271 m_measuredReflections = static_cast<int>(m_peaks.size());
272
273 if (m_uniqueReflections > 0) {
274 m_redundancy = static_cast<double>(m_measuredReflections) / static_cast<double>(m_uniqueReflections);
275 }
276
277 m_completeness = static_cast<double>(m_uniqueReflections) / static_cast<double>(uniqueReflections.size());
278
279 if (intensitySumRValues > 0.0) {
280 m_rMerge = rMergeNumerator / intensitySumRValues;
281 m_rPim = rPimNumerator / intensitySumRValues;
282 }
283
284 if (m_measuredReflections > 0) {
285 m_meanIOverSigma = iOverSigmaSum / static_cast<double>(m_measuredReflections);
286
287 auto dspacingLimits = getDSpacingLimits(m_peaks);
288 m_dspacingMin = dspacingLimits.first;
289 m_dspacingMax = dspacingLimits.second;
290 }
291}
292
295double PeaksStatistics::getIOverSigmaSum(const std::vector<double> &sigmas,
296 const std::vector<double> &intensities) const {
297 return std::inner_product(intensities.begin(), intensities.end(), sigmas.begin(), 0.0, std::plus<double>(),
298 std::divides<double>());
299}
300
302double PeaksStatistics::getRMS(const std::vector<double> &data) const {
303 double sumOfSquares = std::inner_product(data.begin(), data.end(), data.begin(), 0.0);
304
305 return sqrt(sumOfSquares / static_cast<double>(data.size()));
306}
307
309std::pair<double, double> PeaksStatistics::getDSpacingLimits(const std::vector<Peak> &peaks) const {
310 if (peaks.empty()) {
311 return std::make_pair(0.0, 0.0);
312 }
313
314 auto dspacingLimitIterators = std::minmax_element(peaks.begin(), peaks.end(), [](const Peak &lhs, const Peak &rhs) {
315 return lhs.getDSpacing() < rhs.getDSpacing();
316 });
317
318 return std::make_pair((*(dspacingLimitIterators.first)).getDSpacing(),
319 (*(dspacingLimitIterators.second)).getDSpacing());
320}
321
322} // namespace Mantid::Crystal::PeakStatisticsTools
const std::vector< double > & rhs
double sigma
Definition GetAllEi.cpp:156
int m_measuredReflections
Total number of observed reflections - no symmetry is taken into account for this.
double m_meanIOverSigma
Average signal to noise ratio in the reflections.
double m_redundancy
Average number of observations for a unique reflection.
double m_dspacingMin
Lower d-spacing limit in the data set, sometimes referred to as upper resolution limit.
double getIOverSigmaSum(const std::vector< double > &sigmas, const std::vector< double > &intensities) const
Returns the sum of all I/sigma-ratios defined by the two vectors using std::inner_product.
double m_rPim
Precision indicating R-factor (R_{p.i.m}).
double m_completeness
Fraction of observed unique reflections in the resolution range defined by d_min and d_max.
double m_dspacingMax
Upper d-spacing limit in the data set.
double getRMS(const std::vector< double > &data) const
Returns the Root mean square of the supplied vector.
void calculatePeaksStatistics(const std::map< Kernel::V3D, UniqueReflection > &uniqueReflections, std::string const &equivalentIntensities, double &sigmaCritical, bool &weightedZ)
PeaksStatistics::calculatePeaksStatistics.
std::pair< double, double > getDSpacingLimits(const std::vector< DataObjects::Peak > &peaks) const
Returns the lowest and hights wavelength in the peak list.
double m_rMerge
Merging R-factor, R_merge, sometimes also called R_sym.
UniqueReflectionCollection(const Geometry::UnitCell &cell, const std::pair< double, double > &dLimits, Geometry::PointGroup_sptr pointGroup, const Geometry::ReflectionCondition_sptr &centering)
UniqueReflectionCollection::UniqueReflectionCollection.
UniqueReflection getReflection(const Kernel::V3D &hkl) const
Returns a copy of the UniqueReflection with the supplied HKL.
std::vector< Kernel::V3D > getUnobservedUniqueReflections() const
List of unobserved unique reflections in resolution range.
size_t getObservedReflectionCount() const
Number of observed reflections.
const std::map< Kernel::V3D, UniqueReflection > & getReflections() const
Returns the internally stored reflection map.
void addObservations(const std::vector< DataObjects::Peak > &peaks)
Assigns the supplied peaks to the proper UniqueReflection.
size_t getUniqueReflectionCount() const
Total number of unique reflections (theoretically possible).
size_t getObservedUniqueReflectionCount(size_t moreThan=0) const
Number of unique reflections that have more observations than the supplied number (default is 0 - giv...
This class is a small helper for SortHKL to hold Peak-objects that belong to the same family of refle...
UniqueReflection removeOutliers(double sigmaCritical=3.0, bool weightedZ=false) const
Removes peaks whose intensity deviates more than sigmaCritical from the intensities' mean.
std::vector< double > getIntensities() const
Returns a vector with the intensities of the Peaks stored in this reflection.
std::vector< double > getWavelengths() const
Returns a vector with the wavelengths of the Peaks stored in this reflection.
void setPeaksIntensityAndSigma(double intensity, double sigma)
Sets the intensities and sigmas of all stored peaks to the supplied values.
std::vector< double > getSigmas() const
Returns a vector with the intensity sigmas of the Peaks stored in this reflection.
Structure describing a single-crystal peak.
Definition Peak.h:34
Class to implement unit cell of crystals.
Definition UnitCell.h:44
Class for 3D vectors.
Definition V3D.h:34
constexpr double norm2() const noexcept
Vector length squared.
Definition V3D.h:271
std::shared_ptr< ReflectionCondition > ReflectionCondition_sptr
Shared pointer to a ReflectionCondition.
std::shared_ptr< PointGroup > PointGroup_sptr
Shared pointer to a PointGroup.
Definition PointGroup.h:69
Statistics getStatistics(const std::vector< TYPE > &data, const unsigned int flags=StatOptions::AllStats)
Return a statistics object for the given data set.
std::vector< double > getZscore(const std::vector< TYPE > &data)
Return the Z score values for a dataset.
std::vector< double > getWeightedZscore(const std::vector< TYPE > &data, const std::vector< TYPE > &weights)
There are enough special cases in determining the Z score where it useful to put it in a single funct...
STL namespace.