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.getHKL();
136 hkl.round();
137
138 auto reflection = m_reflections.find(m_pointgroup->getReflectionFamily(hkl));
139
140 if (reflection != m_reflections.end()) {
141 (*reflection).second.addPeak(peak);
142 }
143 }
144}
145
149 return m_reflections.at(m_pointgroup->getReflectionFamily(hkl));
150}
151
154
158 return std::count_if(
159 m_reflections.cbegin(), m_reflections.cend(),
160 [=](const std::pair<Kernel::V3D, UniqueReflection> &item) { return item.second.count() > moreThan; });
161}
162
165 std::vector<V3D> reflections;
166 reflections.reserve(m_reflections.size());
167
168 for (const auto &reflection : m_reflections) {
169 if (reflection.second.count() == 0) {
170 reflections.emplace_back(reflection.first);
171 }
172 }
173
174 return reflections;
175}
176
179 return std::accumulate(m_reflections.cbegin(), m_reflections.cend(), size_t(0),
180 [](size_t totalReflections, const std::pair<Kernel::V3D, UniqueReflection> &item) {
181 return totalReflections + item.second.count();
182 });
183}
184
187const std::map<V3D, UniqueReflection> &UniqueReflectionCollection::getReflections() const { return m_reflections; }
188
206void PeaksStatistics::calculatePeaksStatistics(const std::map<V3D, UniqueReflection> &uniqueReflections,
207 std::string &equivalentIntensities, double &sigmaCritical,
208 bool &weightedZ) {
209 double rMergeNumerator = 0.0;
210 double rPimNumerator = 0.0;
211 double intensitySumRValues = 0.0;
212 double iOverSigmaSum = 0.0;
213
214 for (const auto &unique : uniqueReflections) {
215 /* Since all possible unique reflections are explored
216 * there may be 0 observations for some of them.
217 * In that case, nothing can be done.*/
218 if (unique.second.count() > 0) {
220
221 // Possibly remove outliers.
222 auto outliersRemoved = unique.second.removeOutliers(sigmaCritical, weightedZ);
223
224 // I/sigma is calculated for all reflections, even if there is only one
225 // observation.
226 auto intensities = outliersRemoved.getIntensities();
227 auto sigmas = outliersRemoved.getSigmas();
228
229 // Accumulate the I/sigma's for current reflection into sum
230 iOverSigmaSum += getIOverSigmaSum(sigmas, intensities);
231
232 if (outliersRemoved.count() > 1) {
233 // Get mean, standard deviation for intensities
234 auto intensityStatistics = Kernel::getStatistics(
236
237 double meanIntensity = intensityStatistics.mean;
238 if (equivalentIntensities == "Median")
239 meanIntensity = intensityStatistics.median;
240
241 /* This was in the original algorithm, not entirely sure where it is
242 * used. It's basically the sum of all relative standard deviations.
243 * In a perfect data set with all equivalent reflections exactly
244 * equivalent that would be 0. */
245 m_chiSquared += intensityStatistics.standard_deviation / meanIntensity;
246
247 // For both RMerge and RPim sum(|I - <I>|) is required
248 double sumOfDeviationsFromMean =
249 std::accumulate(intensities.begin(), intensities.end(), 0.0, [meanIntensity](double sum, double intensity) {
250 return sum + fabs(intensity - meanIntensity);
251 });
252
253 // Accumulate into total sum for numerator of RMerge
254 rMergeNumerator += sumOfDeviationsFromMean;
255
256 // For Rpim, the sum is weighted by a factor depending on N
257 double rPimFactor = sqrt(1.0 / (static_cast<double>(outliersRemoved.count()) - 1.0));
258 rPimNumerator += (rPimFactor * sumOfDeviationsFromMean);
259
260 // Collect sum of intensities for R-value calculation
261 intensitySumRValues += std::accumulate(intensities.begin(), intensities.end(), 0.0);
262 }
263
264 const std::vector<Peak> &reflectionPeaks = outliersRemoved.getPeaks();
265 m_peaks.insert(m_peaks.end(), reflectionPeaks.begin(), reflectionPeaks.end());
266 }
267 }
268
269 m_measuredReflections = static_cast<int>(m_peaks.size());
270
271 if (m_uniqueReflections > 0) {
272 m_redundancy = static_cast<double>(m_measuredReflections) / static_cast<double>(m_uniqueReflections);
273 }
274
275 m_completeness = static_cast<double>(m_uniqueReflections) / static_cast<double>(uniqueReflections.size());
276
277 if (intensitySumRValues > 0.0) {
278 m_rMerge = rMergeNumerator / intensitySumRValues;
279 m_rPim = rPimNumerator / intensitySumRValues;
280 }
281
282 if (m_measuredReflections > 0) {
283 m_meanIOverSigma = iOverSigmaSum / static_cast<double>(m_measuredReflections);
284
285 auto dspacingLimits = getDSpacingLimits(m_peaks);
286 m_dspacingMin = dspacingLimits.first;
287 m_dspacingMax = dspacingLimits.second;
288 }
289}
290
293double PeaksStatistics::getIOverSigmaSum(const std::vector<double> &sigmas,
294 const std::vector<double> &intensities) const {
295 return std::inner_product(intensities.begin(), intensities.end(), sigmas.begin(), 0.0, std::plus<double>(),
296 std::divides<double>());
297}
298
300double PeaksStatistics::getRMS(const std::vector<double> &data) const {
301 double sumOfSquares = std::inner_product(data.begin(), data.end(), data.begin(), 0.0);
302
303 return sqrt(sumOfSquares / static_cast<double>(data.size()));
304}
305
307std::pair<double, double> PeaksStatistics::getDSpacingLimits(const std::vector<Peak> &peaks) const {
308 if (peaks.empty()) {
309 return std::make_pair(0.0, 0.0);
310 }
311
312 auto dspacingLimitIterators = std::minmax_element(peaks.begin(), peaks.end(), [](const Peak &lhs, const Peak &rhs) {
313 return lhs.getDSpacing() < rhs.getDSpacing();
314 });
315
316 return std::make_pair((*(dspacingLimitIterators.first)).getDSpacing(),
317 (*(dspacingLimitIterators.second)).getDSpacing());
318}
319
320} // 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.
void calculatePeaksStatistics(const std::map< Kernel::V3D, UniqueReflection > &uniqueReflections, std::string &equivalentIntensities, double &sigmaCritical, bool &weightedZ)
PeaksStatistics::calculatePeaksStatistics.
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.
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
void round() noexcept
Round each component to the nearest integer.
Definition: V3D.cpp:140
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:67
Statistics getStatistics(const std::vector< TYPE > &data, const unsigned int flags=StatOptions::AllStats)
Return a statistics object for the given data set.
Definition: Statistics.cpp:167
std::vector< double > getZscore(const std::vector< TYPE > &data)
Return the Z score values for a dataset.
Definition: Statistics.cpp:81
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...
Definition: Statistics.cpp:102
STL namespace.