14#include <boost/math/special_functions/round.hpp>
25#include <gsl/gsl_eigen.h>
26#include <gsl/gsl_matrix.h>
27#include <gsl/gsl_vector.h>
34namespace MDAlgorithms {
46 const bool useOnePercentBackgroundCorrection)
47 : m_radius(
radius), m_useOnePercentBackgroundCorrection(useOnePercentBackgroundCorrection) {
49 for (
size_t peakIndex = 0; peakIndex != peak_q_list.size(); ++peakIndex) {
50 const V3D q = peak_q_list[peakIndex].second;
56 std::pair<size_t, OccupiedCell> newCell(abc.
getHash(), c);
69 int64_t a(
static_cast<int64_t
>(q[0] / cellSize));
70 int64_t b(
static_cast<int64_t
>(q[1] / cellSize));
71 int64_t c(
static_cast<int64_t
>(q[2] / cellSize));
72 return !(a || b || c);
76 for (
const auto &event_q : event_qs)
83 double peak_radius,
double back_inner_radius,
double back_outer_radius,
84 std::vector<double> &axes_radii,
double &inti,
double &sigi,
85 std::pair<double, double> &backi) {
88 backi = std::make_pair<double, double>(0.0, 0.0);
93 return std::make_shared<NoShape>();
96 if (some_events.size() < 3)
97 return std::make_shared<NoShape>();
102 std::vector<V3D> eigen_vectors;
103 std::vector<double> eigen_values;
106 std::vector<double> sigmas(3);
107 for (
int i = 0; i < 3; i++)
108 sigmas[i] = sqrt(eigen_values[i]);
111 std::any_of(sigmas.cbegin(), sigmas.cend(), [](
const double sigma) { return std::isnan(sigma) || sigma <= 0; });
115 return std::make_shared<NoShape>();
117 return ellipseIntegrateEvents(E1Vec, peak_q, some_events, eigen_vectors, sigmas, specify_size, peak_radius,
118 back_inner_radius, back_outer_radius, axes_radii, inti, sigi, backi);
122 std::vector<V3D>
const &directions,
123 std::vector<double>
const &sizes) {
124 std::pair<double, double>
count(0, 0);
125 for (
const auto &event : events) {
127 for (
size_t k = 0; k < 3; k++) {
128 double comp =
event.second.scalar_prod(directions[k]) / sizes[k];
132 count.first +=
event.first.first;
133 count.second +=
event.first.second;
140 std::vector<V3D>
const &directions,
141 std::vector<double>
const &sizes,
142 std::vector<double>
const &sizesIn,
143 const bool useOnePercentBackgroundCorrection) {
144 std::pair<double, double>
count(0, 0);
145 std::vector<std::pair<double, double>> eventVec;
146 for (
const auto &event : events) {
149 for (
size_t k = 0; k < 3; k++) {
150 double comp =
event.second.scalar_prod(directions[k]) / sizes[k];
152 comp =
event.second.scalar_prod(directions[k]) / sizesIn[k];
153 sumIn += comp * comp;
155 if (sum <= 1 && sumIn >= 1)
156 eventVec.emplace_back(event.first);
166 auto endIndex = eventVec.size();
167 if (useOnePercentBackgroundCorrection) {
169 std::sort(eventVec.begin(), eventVec.end(),
170 [](
const std::pair<double, double> &a,
const std::pair<double, double> &b) { return a.first < b.first; });
171 endIndex =
static_cast<size_t>(0.99 *
static_cast<double>(endIndex));
174 for (
size_t k = 0; k < endIndex; ++k) {
175 count.first += eventVec[k].first;
176 count.second += eventVec[k].second;
184 for (
int row = 0; row < 3; row++) {
185 for (
int col = 0; col < 3; col++) {
188 for (
const auto &event : events) {
189 if (event.second.norm() <=
radius) {
190 totalCounts +=
event.first.first;
191 sum +=
event.first.first *
event.second[row] *
event.second[col];
195 matrix[row][col] = sum / (totalCounts - 1);
197 matrix[row][col] = sum;
203 std::vector<double> &eigen_values) {
204 unsigned int size = 3;
206 gsl_matrix *matrix = gsl_matrix_alloc(size, size);
207 gsl_vector *eigen_val = gsl_vector_alloc(size);
208 gsl_matrix *eigen_vec = gsl_matrix_alloc(size, size);
209 gsl_eigen_symmv_workspace *wkspace = gsl_eigen_symmv_alloc(size);
212 for (
size_t row = 0; row < size; row++)
213 for (
size_t col = 0; col < size; col++) {
214 gsl_matrix_set(matrix, row, col, cov_matrix[row][col]);
217 gsl_eigen_symmv(matrix, eigen_val, eigen_vec, wkspace);
220 for (
size_t col = 0; col < size; col++) {
221 eigen_vectors.emplace_back(gsl_matrix_get(eigen_vec, 0, col), gsl_matrix_get(eigen_vec, 1, col),
222 gsl_matrix_get(eigen_vec, 2, col));
223 eigen_values.emplace_back(gsl_vector_get(eigen_val, col));
226 gsl_matrix_free(matrix);
227 gsl_vector_free(eigen_val);
228 gsl_matrix_free(eigen_vec);
229 gsl_eigen_symmv_free(wkspace);
241 std::pair<size_t, SlimEvents> newCell(hash, events);
244 cell_it->second.emplace_back(event);
249 std::vector<V3D>
const &directions, std::vector<double>
const &sigmas,
250 bool specify_size,
double peak_radius,
double back_inner_radius,
251 double back_outer_radius, std::vector<double> &axes_radii,
double &inti,
252 double &sigi, std::pair<double, double> &backi) {
261 double max_sigma = sigmas[0];
262 for (
int i = 1; i < 3; i++) {
263 if (sigmas[i] > max_sigma) {
264 max_sigma = sigmas[i];
272 r1 = peak_radius / max_sigma;
273 r2 = back_inner_radius / max_sigma;
274 r3 = back_outer_radius / max_sigma;
278 r3 = r2 * 1.25992105;
284 r1 = r3 * 0.79370053f;
290 std::vector<double> abcBackgroundOuterRadii;
291 std::vector<double> abcBackgroundInnerRadii;
292 std::vector<double> abcRadii;
293 for (
int i = 0; i < 3; i++) {
294 abcBackgroundOuterRadii.emplace_back(r3 * sigmas[i]);
295 abcBackgroundInnerRadii.emplace_back(r2 * sigmas[i]);
296 abcRadii.emplace_back(r1 * sigmas[i]);
297 axes_radii.emplace_back(r1 * sigmas[i]);
300 if (!E1Vec.empty()) {
301 double h3 = 1.0 -
detectorQ(E1Vec, peak_q, abcBackgroundOuterRadii);
303 double m3 = std::sqrt(1.0 - (std::acos(1.0 - h3) - (1.0 - h3) * std::sqrt(2.0 * h3 - h3 * h3)) / M_PI);
304 double h1 = 1.0 -
detectorQ(E1Vec, peak_q, axes_radii);
307 return std::make_shared<const PeakShapeEllipsoid>(directions, abcRadii, abcBackgroundInnerRadii,
309 "IntegrateEllipsoids");
312 double h2 = 1.0 -
detectorQ(E1Vec, peak_q, abcBackgroundInnerRadii);
314 double m2 = std::sqrt(1.0 - (std::acos(1.0 - h2) - (1.0 - h2) * std::sqrt(2.0 * h2 - h2 * h2)) / M_PI);
319 std::pair<double, double> backgrd =
numInEllipsoidBkg(ev_list, directions, abcBackgroundOuterRadii,
322 std::pair<double, double> peak_w_back =
numInEllipsoid(ev_list, directions, axes_radii);
324 double ratio = pow(r1, 3) / (pow(r3, 3) - pow(r2, 3));
329 backgrd.second = 0.0;
332 inti = peak_w_back.first - ratio * backgrd.first;
333 sigi = sqrt(peak_w_back.second + ratio * ratio * backgrd.second);
334 backi = std::make_pair<double, double>(backgrd.first * ratio, backgrd.second * ratio * ratio);
337 std::ostringstream msg;
338 msg <<
"Negative intensity found: " << inti <<
"\n"
339 <<
"Please use slice viewer to check the peak with negative intensity to decide:\n"
340 <<
"-- adjust peak and background raidus\n"
341 <<
"-- prune false positive indexation results\n";
344 std::ostringstream debugmsg;
345 debugmsg <<
"peak_radius = " << peak_radius <<
"\n"
346 <<
"back_inner_radius = " << back_inner_radius <<
"\n"
347 <<
"back_outer_radius = " << back_outer_radius <<
"\n"
348 <<
"sigmas = (" << sigmas[0] <<
"," << sigmas[1] <<
"," << sigmas[2] <<
")\n"
349 <<
"r1, r2, r3 = " << r1 <<
"," << r2 <<
"," << r3 <<
"\n"
350 <<
"peak_w_back.first = " << peak_w_back.first <<
"\n"
351 <<
"backgrd.first = " << backgrd.first <<
"\n"
352 <<
"ratio = " << ratio <<
"\n"
353 <<
"inti = peak_w_back.first - ratio * backgrd.first = " << inti <<
"\n";
358 return std::make_shared<const PeakShapeEllipsoid>(directions, abcRadii, abcBackgroundInnerRadii,
360 "IntegrateEllipsoids");
363 const std::vector<double> &r) {
365 for (
auto &
E1 : E1Vec) {
367 double quot0 = distv.
norm() / *(std::min_element(r.begin(), r.end()));
382 for (
const SlimEvent &event : cellE_it->second) {
384 neighborEvent.second =
event.second - cell.
peakQ;
385 cell.
events.emplace_back(neighborEvent);
Helper class for reporting progress from algorithms.
The Logger class is in charge of the publishing messages from the framework through various channels.
void debug(const std::string &msg)
Logs at debug level.
void notice(const std::string &msg)
Logs at notice level.
constexpr double scalar_prod(const V3D &v) const noexcept
Calculates the cross product.
double norm() const noexcept
std::unordered_map< size_t, SlimEvents > m_cellsWithEvents
list of cells occupied with events
double detectorQ(const std::vector< V3D > &E1Vec, const V3D &QLabFrame, const std::vector< double > &r)
Calculate if this Q is on a detector.
static bool isOrigin(const V3D &q, const double &cellSize)
Determine if an input Q-vector lies in the cell associated to the origin.
void addEvent(const SlimEvent event)
assign an event to one cell of the partitioned QLab space.
double m_cellSize
size of the square cell unit, holding at most one single peak
static std::pair< double, double > numInEllipsoidBkg(SlimEvents const &events, std::vector< V3D > const &directions, std::vector< double > const &sizes, std::vector< double > const &sizesIn, const bool useOnePercentBackgroundCorrection)
Number of events in an ellipsoid with background correction.
void setRadius(const double &radius)
Set peak integration radius.
const bool m_useOnePercentBackgroundCorrection
if one percent culling of the background should be performed.
static void getEigenVectors(Kernel::DblMatrix const &cov_matrix, std::vector< V3D > &eigen_vectors, std::vector< double > &eigen_values)
Eigen vectors of a 3x3 real symmetric matrix using the GSL.
static std::pair< double, double > numInEllipsoid(SlimEvents const &events, std::vector< V3D > const &directions, std::vector< double > const &sizes)
Number of events in an ellipsoid.
void populateCellsWithPeaks()
Assign events to each of the cells occupied by events.
std::unordered_map< size_t, OccupiedCell > m_cellsWithPeaks
list the occupied cells in an unordered map for fast searching
PeakShape_const_sptr ellipseIntegrateEvents(const std::vector< V3D > &E1Vec, V3D const &peak_q, bool specify_size, double peak_radius, double back_inner_radius, double back_outer_radius, std::vector< double > &axes_radii, double &inti, double &sigi, std::pair< double, double > &backi)
Integrate the events around the specified peak QLab vector.
static void makeCovarianceMatrix(SlimEvents const &events, Kernel::DblMatrix &matrix, double radius)
3x3 covariance matrix of a list of SlimEvent objects
IntegrateQLabEvents(const SlimEvents &peak_q_list, double radius, const bool useOnePercentBackgroundCorrection=true)
Store events within a certain radius of the specified peak centers, and sum these events to estimate ...
void addEvents(SlimEvents const &event_qs)
distribute the events among the cells of the partitioned QLab space.
std::complex< double > MANTID_API_DLL E1(std::complex< double > z)
Integral for Gamma.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< const PeakShapeEllipsoid > PeakShapeEllipsoid_const_sptr
std::shared_ptr< const PeakShape > PeakShape_const_sptr
std::vector< SlimEvent > SlimEvents
std::pair< std::pair< double, double >, V3D > SlimEvent
Helper class which provides the Collimation Length for SANS instruments.
Partition QLab space into a cubic lattice.
bool isOrigin()
Check if all cell coords are zero.
std::vector< int64_t > nearbyCellHashes()
Hashes for the 26 first neighbor coordinates plus the coordinates themselves.
int64_t getHash()
cast coordinates to scalar, to be used as key in an unordered map