12#include <boost/math/special_functions/round.hpp>
13#include <boost/numeric/conversion/cast.hpp>
15#include <gsl/gsl_errno.h>
16#include <gsl/gsl_fft_real.h>
17#include <gsl/gsl_linalg.h>
18#include <gsl/gsl_matrix.h>
19#include <gsl/gsl_sys.h>
20#include <gsl/gsl_vector.h>
32const constexpr double DEG_TO_RAD = M_PI / 180.;
33const constexpr double RAD_TO_DEG = 180. / M_PI;
95 double required_tolerance,
int base_index,
size_t num_initial,
double degrees_per_step,
96 bool fixAll,
int iterations) {
98 throw std::invalid_argument(
"Find_UB(): UB matrix NULL or not 3X3");
101 if (q_vectors.size() < 2) {
102 throw std::invalid_argument(
"Find_UB(): Two or more indexed peaks needed to find UB");
105 if (required_tolerance <= 0) {
106 throw std::invalid_argument(
"Find_UB(): required_tolerance must be positive");
109 if (num_initial < 2) {
110 throw std::invalid_argument(
"Find_UB(): number of peaks for inital scan must be > 2");
113 if (degrees_per_step <= 0) {
114 throw std::invalid_argument(
"Find_UB(): degrees_per_step must be positive");
118 std::vector<V3D> sorted_qs;
119 sorted_qs.reserve(q_vectors.size());
121 if (q_vectors.size() > 5)
124 std::vector<V3D> shifted_qs(q_vectors);
125 size_t mid_ind = q_vectors.size() / 3;
129 if (base_index < 0 || base_index >=
static_cast<int>(q_vectors.size())) {
132 mid_ind = base_index;
134 V3D mid_vec(shifted_qs[mid_ind]);
136 for (
size_t i = 0; i < shifted_qs.size(); i++) {
138 V3D shifted_vec(shifted_qs[i]);
139 shifted_vec -= mid_vec;
140 sorted_qs.emplace_back(shifted_vec);
144 std::copy(q_vectors.cbegin(), q_vectors.cend(), std::back_inserter(sorted_qs));
149 if (num_initial > sorted_qs.size())
150 num_initial = sorted_qs.size();
152 std::vector<V3D> some_qs;
153 some_qs.reserve(q_vectors.size());
155 for (
size_t i = 0; i < num_initial; i++)
156 some_qs.emplace_back(sorted_qs[i]);
158 ScanFor_UB(UB, some_qs, lattice, degrees_per_step, required_tolerance);
160 double fit_error = 0;
161 std::vector<V3D> miller_ind;
162 std::vector<V3D> indexed_qs;
163 miller_ind.reserve(q_vectors.size());
164 indexed_qs.reserve(q_vectors.size());
169 while (!fixAll && num_initial < sorted_qs.size()) {
170 num_initial = std::lround(1.5 *
static_cast<double>(num_initial + 3));
173 if (num_initial >= sorted_qs.size())
174 num_initial = sorted_qs.size();
176 for (
size_t i = some_qs.size(); i < num_initial; i++)
177 some_qs.emplace_back(sorted_qs[i]);
178 for (
int counter = 0; counter < iterations; counter++) {
180 GetIndexedPeaks(UB, some_qs, required_tolerance, miller_ind, indexed_qs, fit_error);
182 fit_error =
Optimize_UB(temp_UB, miller_ind, indexed_qs);
190 std::vector<double> sigabc(7);
191 if (!fixAll && q_vectors.size() >= 3)
193 for (
int counter = 0; counter < iterations; counter++) {
195 GetIndexedPeaks(UB, q_vectors, required_tolerance, miller_ind, indexed_qs, fit_error);
197 fit_error =
Optimize_UB(temp_UB, miller_ind, indexed_qs, sigabc);
207 GetIndexedPeaks(UB, q_vectors, required_tolerance, miller_ind, indexed_qs, fit_error);
210 lattice.
setError(sigabc[0], sigabc[1], sigabc[2], sigabc[3], sigabc[4], sigabc[5]);
278 double required_tolerance,
int base_index,
size_t num_initial,
double degrees_per_step) {
280 throw std::invalid_argument(
"Find_UB(): UB matrix NULL or not 3X3");
283 if (q_vectors.size() < 3) {
284 throw std::invalid_argument(
"Find_UB(): Three or more indexed peaks needed to find UB");
287 if (min_d >= max_d || min_d <= 0) {
288 throw std::invalid_argument(
"Find_UB(): Need 0 < min_d < max_d");
291 if (required_tolerance <= 0) {
292 throw std::invalid_argument(
"Find_UB(): required_tolerance must be positive");
295 if (num_initial < 3) {
296 throw std::invalid_argument(
"Find_UB(): number of peaks for inital scan must be > 2");
299 if (degrees_per_step <= 0) {
300 throw std::invalid_argument(
"Find_UB(): degrees_per_step must be positive");
304 std::vector<V3D> sorted_qs;
305 sorted_qs.reserve(q_vectors.size());
307 if (q_vectors.size() > 5)
310 std::vector<V3D> shifted_qs(q_vectors);
311 size_t mid_ind = q_vectors.size() / 2;
315 if (base_index < 0 || base_index >=
static_cast<int>(q_vectors.size())) {
318 mid_ind = base_index;
320 V3D mid_vec(shifted_qs[mid_ind]);
322 for (
size_t i = 0; i < shifted_qs.size(); i++) {
324 V3D shifted_vec(shifted_qs[i]);
325 shifted_vec -= mid_vec;
326 sorted_qs.emplace_back(shifted_vec);
330 std::copy(q_vectors.cbegin(), q_vectors.cend(), std::back_inserter(sorted_qs));
335 if (num_initial > sorted_qs.size())
336 num_initial = sorted_qs.size();
338 std::vector<V3D> some_qs;
339 some_qs.reserve(q_vectors.size());
341 for (
size_t i = 0; i < num_initial; i++)
342 some_qs.emplace_back(sorted_qs[i]);
343 std::vector<V3D> directions;
344 ScanFor_Directions(directions, some_qs, min_d, max_d, required_tolerance, degrees_per_step);
346 if (directions.size() < 3) {
347 throw std::runtime_error(
"Find_UB(): Could not find at least three possible lattice directions");
353 throw std::runtime_error(
"Find_UB(): Could not find independent a, b, c directions");
358 std::vector<V3D> miller_ind;
359 std::vector<V3D> indexed_qs;
360 miller_ind.reserve(q_vectors.size());
361 indexed_qs.reserve(q_vectors.size());
364 double fit_error = 0;
365 while (num_initial < sorted_qs.size()) {
366 num_initial = std::lround(1.5 *
static_cast<double>(num_initial + 3));
369 if (num_initial >= sorted_qs.size())
370 num_initial = sorted_qs.size();
372 for (
size_t i = some_qs.size(); i < num_initial; i++)
373 some_qs.emplace_back(sorted_qs[i]);
375 GetIndexedPeaks(UB, some_qs, required_tolerance, miller_ind, indexed_qs, fit_error);
377 fit_error =
Optimize_UB(temp_UB, miller_ind, indexed_qs);
385 if (q_vectors.size() >= 5)
387 GetIndexedPeaks(UB, q_vectors, required_tolerance, miller_ind, indexed_qs, fit_error);
389 fit_error =
Optimize_UB(temp_UB, miller_ind, indexed_qs);
452 double required_tolerance,
double degrees_per_step,
int iterations) {
454 throw std::invalid_argument(
"Find_UB(): UB matrix NULL or not 3X3");
457 if (q_vectors.size() < 4) {
458 throw std::invalid_argument(
"Find_UB(): Four or more indexed peaks needed to find UB");
461 if (min_d >= max_d || min_d <= 0) {
462 throw std::invalid_argument(
"Find_UB(): Need 0 < min_d < max_d");
465 if (required_tolerance <= 0) {
466 throw std::invalid_argument(
"Find_UB(): required_tolerance must be positive");
469 if (degrees_per_step <= 0) {
470 throw std::invalid_argument(
"Find_UB(): degrees_per_step must be positive");
473 std::vector<V3D> directions;
480 FFTScanFor_Directions(directions, q_vectors, min_d, max_d, 0.75f * required_tolerance, degrees_per_step);
482 if (max_indexed == 0) {
483 throw std::invalid_argument(
"Find_UB(): Could not find any a,b,c vectors to index Qs");
486 if (directions.size() < 3) {
487 throw std::invalid_argument(
"Find_UB(): Could not find enough a,b,c vectors");
492 double min_vol = min_d * min_d * min_d / 4.0;
495 throw std::invalid_argument(
"Find_UB(): Could not form UB matrix from a,b,c vectors");
499 double fit_error = 0;
500 if (q_vectors.size() >= 5)
502 std::vector<V3D> miller_ind;
503 std::vector<V3D> indexed_qs;
504 miller_ind.reserve(q_vectors.size());
505 indexed_qs.reserve(q_vectors.size());
507 GetIndexedPeaks(UB, q_vectors, required_tolerance, miller_ind, indexed_qs, fit_error);
509 for (
int counter = 0; counter < iterations; counter++) {
511 fit_error =
Optimize_UB(temp_UB, miller_ind, indexed_qs);
513 GetIndexedPeaks(UB, q_vectors, required_tolerance, miller_ind, indexed_qs, fit_error);
514 }
catch (std::exception &) {
563 std::vector<double> &sigabc) {
567 if (sigabc.size() < 6) {
571 for (
int i = 0; i < 6; i++)
574 size_t nDOF = 3 * (hkl_vectors.size() - 3);
576 for (
int r = 0; r < 3; r++)
577 for (
int c = 0; c < 3; c++)
578 for (
const auto &hkl_vector : hkl_vectors) {
579 HKLTHKL[r][c] += hkl_vector[r] * hkl_vector[c];
584 double SMALL = 1.525878906E-5;
586 std::vector<double> latOrig, latNew;
589 for (
int r = 0; r < 3; r++) {
590 for (
int c = 0; c < 3; c++) {
596 for (
size_t l = 0; l < 7; l++)
597 derivs[c][l] = (latNew[l] - latOrig[l]) / SMALL;
600 for (
size_t l = 0; l < std::min<size_t>(
static_cast<size_t>(7), sigabc.size()); l++)
601 for (
int m = 0;
m < 3;
m++)
602 for (
int n = 0;
n < 3;
n++)
603 sigabc[l] += (derivs[
m][l] * HKLTHKL[
m][
n] * derivs[
n][l]);
606 double delta = result /
static_cast<double>(nDOF);
608 for (
size_t i = 0; i < std::min<size_t>(7, sigabc.size()); i++)
609 sigabc[i] = sqrt(
delta * sigabc[i]);
645 const std::vector<V3D> &q_vectors) {
647 throw std::invalid_argument(
"Optimize_UB(): UB matrix NULL or not 3X3");
650 if (hkl_vectors.size() < 3) {
651 throw std::invalid_argument(
"Optimize_UB(): Three or more indexed peaks needed to find UB");
654 if (hkl_vectors.size() != q_vectors.size()) {
655 throw std::invalid_argument(
"Optimize_UB(): Number of hkl_vectors != number of q_vectors");
658 gsl_matrix *H_transpose = gsl_matrix_alloc(hkl_vectors.size(), 3);
659 gsl_vector *tau = gsl_vector_alloc(3);
661 double sum_sq_error = 0;
664 for (
size_t row = 0; row < hkl_vectors.size(); row++) {
665 for (
size_t col = 0; col < 3; col++) {
666 gsl_matrix_set(H_transpose, row, col, (hkl_vectors[row])[col]);
670 int returned_flag = gsl_linalg_QR_decomp(H_transpose, tau);
672 if (returned_flag != 0) {
673 gsl_matrix_free(H_transpose);
674 gsl_vector_free(tau);
675 throw std::runtime_error(
"Optimize_UB(): gsl QR_decomp failed, invalid hkl values");
680 gsl_vector *UB_row = gsl_vector_alloc(3);
681 gsl_vector *q = gsl_vector_alloc(q_vectors.size());
682 gsl_vector *residual = gsl_vector_alloc(q_vectors.size());
684 bool found_UB =
true;
686 for (
size_t row = 0; row < 3; row++) {
687 for (
size_t i = 0; i < q_vectors.size(); i++) {
688 gsl_vector_set(q, i, (q_vectors[i])[row] / (2.0 * M_PI));
691 returned_flag = gsl_linalg_QR_lssolve(H_transpose, tau, q, UB_row, residual);
692 if (returned_flag != 0) {
696 for (
size_t i = 0; i < 3; i++) {
697 double value = gsl_vector_get(UB_row, i);
698 if (!std::isfinite(
value))
702 V3D row_values(gsl_vector_get(UB_row, 0), gsl_vector_get(UB_row, 1), gsl_vector_get(UB_row, 2));
703 UB.
setRow(row, row_values);
705 for (
size_t i = 0; i < q_vectors.size(); i++) {
706 sum_sq_error += gsl_vector_get(residual, i) * gsl_vector_get(residual, i);
710 gsl_matrix_free(H_transpose);
711 gsl_vector_free(tau);
712 gsl_vector_free(UB_row);
714 gsl_vector_free(residual);
717 throw std::runtime_error(
"Optimize_UB(): Failed to find UB, invalid hkl or Q values");
721 throw std::runtime_error(
"Optimize_UB(): The optimized UB is not valid");
771 const std::vector<V3D> &mnp_vectors,
const int &ModDim,
772 const std::vector<V3D> &q_vectors, std::vector<double> &sigabc,
773 std::vector<double> &sigq) {
775 if (ModDim != 0 && ModDim != 1 && ModDim != 2 && ModDim != 3)
776 throw std::invalid_argument(
"invalid Value for Modulation Dimension");
779 result =
Optimize_6dUB(UB, ModUB, hkl_vectors, mnp_vectors, ModDim, q_vectors);
781 if (sigabc.size() <
static_cast<size_t>(6)) {
785 for (
int i = 0; i < 6; i++)
788 size_t nDOF = 3 * (hkl_vectors.size() - 3);
790 for (
int r = 0; r < 3; r++)
791 for (
int c = 0; c < 3; c++)
792 for (
const auto &hkl_vector : hkl_vectors) {
793 HKLTHKL[r][c] += hkl_vector[r] * hkl_vector[c];
798 double SMALL = 1.525878906E-5;
800 std::vector<double> latOrig, latNew;
803 for (
int r = 0; r < 3; r++) {
804 for (
int c = 0; c < 3; c++) {
810 for (
size_t l = 0; l < 7; l++)
811 derivs[c][l] = (latNew[l] - latOrig[l]) / SMALL;
814 for (
size_t l = 0; l < std::min<size_t>(
static_cast<size_t>(7), sigabc.size()); l++)
815 for (
int m = 0;
m < 3;
m++)
816 for (
int n = 0;
n < 3;
n++)
817 sigabc[l] += (derivs[
m][l] * HKLTHKL[
m][
n] * derivs[
n][l]);
820 double delta = result /
static_cast<double>(nDOF);
822 for (
size_t i = 0; i < std::min<size_t>(7, sigabc.size()); i++)
823 sigabc[i] = sqrt(
delta * sigabc[i]);
828 if (sigq.size() <
static_cast<size_t>(3)) {
834 sigq[0] = sqrt(
delta) * latOrig[0];
835 sigq[1] = sqrt(
delta) * latOrig[1];
836 sigq[2] = sqrt(
delta) * latOrig[2];
887 const std::vector<V3D> &mnp_vectors,
const int &ModDim,
888 const std::vector<V3D> &q_vectors) {
891 throw std::invalid_argument(
"Optimize_6dUB(): UB matrix NULL or not 3X3");
895 throw std::invalid_argument(
"Optimize_6dUB(): ModUB matrix NULL or not 3X3");
898 if (hkl_vectors.size() < 3) {
899 throw std::invalid_argument(
"Optimize_6dUB(): Three or more indexed peaks needed to find UB");
902 if (hkl_vectors.size() != q_vectors.size() || hkl_vectors.size() != mnp_vectors.size()) {
903 throw std::invalid_argument(
"Optimize_6dUB(): Number of hkl_vectors "
904 "doesn't match number of mnp_vectors or number "
908 if (ModDim != 0 && ModDim != 1 && ModDim != 2 && ModDim != 3)
909 throw std::invalid_argument(
"invalid Value for Modulation Dimension");
911 gsl_matrix *H_transpose = gsl_matrix_alloc(hkl_vectors.size(), ModDim + 3);
912 gsl_vector *tau = gsl_vector_alloc(ModDim + 3);
914 double sum_sq_error = 0;
917 for (
size_t row = 0; row < hkl_vectors.size(); row++) {
918 for (
size_t col = 0; col < 3; col++)
919 gsl_matrix_set(H_transpose, row, col, (hkl_vectors[row])[col]);
920 for (
size_t col = 0; col < static_cast<size_t>(ModDim); col++)
921 gsl_matrix_set(H_transpose, row, col + 3, (mnp_vectors[row])[col]);
924 int returned_flag = gsl_linalg_QR_decomp(H_transpose, tau);
926 if (returned_flag != 0) {
927 gsl_matrix_free(H_transpose);
928 gsl_vector_free(tau);
929 throw std::runtime_error(
"Optimize_UB(): gsl QR_decomp failed, invalid hkl and mnp values");
934 gsl_vector *UB_row = gsl_vector_alloc(ModDim + 3);
935 gsl_vector *q = gsl_vector_alloc(q_vectors.size());
936 gsl_vector *residual = gsl_vector_alloc(q_vectors.size());
938 bool found_UB =
true;
940 for (
size_t row = 0; row < 3; row++) {
941 for (
size_t i = 0; i < q_vectors.size(); i++) {
942 gsl_vector_set(q, i, (q_vectors[i])[row] / (2.0 * M_PI));
945 returned_flag = gsl_linalg_QR_lssolve(H_transpose, tau, q, UB_row, residual);
947 if (returned_flag != 0) {
951 for (
size_t i = 0; i < static_cast<size_t>(ModDim + 3); i++) {
952 double value = gsl_vector_get(UB_row, i);
953 if (!std::isfinite(
value))
957 V3D hklrow_values(gsl_vector_get(UB_row, 0), gsl_vector_get(UB_row, 1), gsl_vector_get(UB_row, 2));
958 V3D mnprow_values(0, 0, 0);
961 mnprow_values(gsl_vector_get(UB_row, 3), 0, 0);
963 mnprow_values(gsl_vector_get(UB_row, 3), gsl_vector_get(UB_row, 4), 0);
965 mnprow_values(gsl_vector_get(UB_row, 3), gsl_vector_get(UB_row, 4), gsl_vector_get(UB_row, 5));
967 UB.
setRow(row, hklrow_values);
968 ModUB.
setRow(row, mnprow_values);
970 for (
size_t i = 0; i < q_vectors.size(); i++) {
971 sum_sq_error += gsl_vector_get(residual, i) * gsl_vector_get(residual, i);
975 gsl_matrix_free(H_transpose);
976 gsl_vector_free(tau);
977 gsl_vector_free(UB_row);
979 gsl_vector_free(residual);
982 throw std::runtime_error(
"Optimize_UB(): Failed to find UB, invalid hkl or Q values");
986 throw std::runtime_error(
"Optimize_UB(): The optimized UB is not valid");
1028 const std::vector<int> &index_values,
const std::vector<V3D> &q_vectors) {
1029 if (index_values.size() < 3) {
1030 throw std::invalid_argument(
"Optimize_Direction(): Three or more indexed values needed");
1033 if (index_values.size() != q_vectors.size()) {
1034 throw std::invalid_argument(
"Optimize_Direction(): Number of index_values != number of q_vectors");
1037 gsl_matrix *H_transpose = gsl_matrix_alloc(q_vectors.size(), 3);
1038 gsl_vector *tau = gsl_vector_alloc(3);
1040 double sum_sq_error = 0;
1044 for (
size_t row = 0; row < q_vectors.size(); row++) {
1045 for (
size_t col = 0; col < 3; col++) {
1046 gsl_matrix_set(H_transpose, row, col, (q_vectors[row])[col] / (2.0 * M_PI));
1049 int returned_flag = gsl_linalg_QR_decomp(H_transpose, tau);
1051 if (returned_flag != 0) {
1052 gsl_matrix_free(H_transpose);
1053 gsl_vector_free(tau);
1054 throw std::runtime_error(
"Optimize_Direction(): gsl QR_decomp failed, invalid hkl values");
1059 gsl_vector *
x = gsl_vector_alloc(3);
1060 gsl_vector *indices = gsl_vector_alloc(index_values.size());
1061 gsl_vector *residual = gsl_vector_alloc(index_values.size());
1063 bool found_best_vec =
true;
1065 for (
size_t i = 0; i < index_values.size(); i++) {
1066 gsl_vector_set(indices, i, index_values[i]);
1069 returned_flag = gsl_linalg_QR_lssolve(H_transpose, tau, indices,
x, residual);
1070 if (returned_flag != 0) {
1071 found_best_vec =
false;
1074 for (
size_t i = 0; i < 3; i++) {
1075 double value = gsl_vector_get(
x, i);
1076 if (!std::isfinite(
value))
1077 found_best_vec =
false;
1080 best_vec(gsl_vector_get(
x, 0), gsl_vector_get(
x, 1), gsl_vector_get(
x, 2));
1082 for (
size_t i = 0; i < index_values.size(); i++) {
1083 sum_sq_error += gsl_vector_get(residual, i) * gsl_vector_get(residual, i);
1086 gsl_matrix_free(H_transpose);
1087 gsl_vector_free(tau);
1089 gsl_vector_free(indices);
1090 gsl_vector_free(residual);
1092 if (!found_best_vec) {
1093 throw std::runtime_error(
"Optimize_Direction(): Failed to find best_vec, "
1094 "invalid indexes or Q values");
1097 return sum_sq_error;
1135 double degrees_per_step,
double required_tolerance) {
1137 throw std::invalid_argument(
"Find_UB(): UB matrix NULL or not 3X3");
1145 const auto cosAlpha = std::cos(cell.
alpha() * DEG_TO_RAD);
1146 const auto cosBeta = std::cos(cell.
beta() * DEG_TO_RAD);
1147 const auto cosGamma = std::cos(cell.
gamma() * DEG_TO_RAD);
1148 const auto sinGamma = std::sin(cell.
gamma() * DEG_TO_RAD);
1149 const auto gamma_degrees = cell.
gamma();
1155 double num_a_steps = std::round(90.0 / degrees_per_step);
1156 int num_b_steps = boost::math::iround(4.0 * sinGamma * num_a_steps);
1167 int max_indexed = 0;
1171 std::vector<V3D> selected_a_dirs;
1172 std::vector<V3D> selected_b_dirs;
1173 std::vector<V3D> selected_c_dirs;
1175 for (
const auto &a_dir_num : a_dir_list) {
1176 a_dir_temp = a_dir_num;
1177 a_dir_temp =
V3D(a_dir_temp);
1180 std::vector<V3D> b_dir_list =
1183 for (
const auto &b_dir_num : b_dir_list) {
1184 b_dir_temp = b_dir_num;
1185 b_dir_temp =
V3D(b_dir_temp);
1187 c_dir_temp =
makeCDir(a_dir_temp, b_dir_temp, c, cosAlpha, cosBeta, cosGamma, sinGamma);
1188 int num_indexed = 0;
1189 for (
const auto &q_vector : q_vectors) {
1190 bool indexes_peak =
true;
1191 q_vec = q_vector / (2.0 * M_PI);
1193 nearest_int = std::round(dot_prod);
1195 if (
error > required_tolerance)
1196 indexes_peak =
false;
1199 nearest_int = std::round(dot_prod);
1201 if (
error > required_tolerance)
1202 indexes_peak =
false;
1205 nearest_int = std::round(dot_prod);
1207 if (
error > required_tolerance)
1208 indexes_peak =
false;
1215 if (num_indexed > max_indexed)
1217 selected_a_dirs.clear();
1218 selected_b_dirs.clear();
1219 selected_c_dirs.clear();
1220 max_indexed = num_indexed;
1222 if (num_indexed == max_indexed) {
1223 selected_a_dirs.emplace_back(a_dir_temp);
1224 selected_b_dirs.emplace_back(b_dir_temp);
1225 selected_c_dirs.emplace_back(c_dir_temp);
1232 double min_error = 1.0e50;
1233 for (
size_t dir_num = 0; dir_num < selected_a_dirs.size(); dir_num++) {
1234 a_dir_temp = selected_a_dirs[dir_num];
1235 b_dir_temp = selected_b_dirs[dir_num];
1236 c_dir_temp = selected_c_dirs[dir_num];
1238 double sum_sq_error = 0.0;
1239 for (
const auto &q_vector : q_vectors) {
1240 q_vec = q_vector / (2.0 * M_PI);
1242 nearest_int = std::round(dot_prod);
1243 error = dot_prod - nearest_int;
1247 nearest_int = std::round(dot_prod);
1248 error = dot_prod - nearest_int;
1252 nearest_int = std::round(dot_prod);
1253 error = dot_prod - nearest_int;
1257 if (sum_sq_error < min_error) {
1258 min_error = sum_sq_error;
1266 throw std::runtime_error(
"UB could not be formed, invert matrix failed");
1297 double max_d,
double required_tolerance,
double degrees_per_step) {
1302 int max_indexed = 0;
1306 int num_steps = boost::math::iround(90.0 / degrees_per_step);
1313 double delta_d = 0.1f;
1314 int n_steps = boost::math::iround(1.0 + (max_d - min_d) / delta_d);
1316 std::vector<V3D> selected_dirs;
1318 for (
const auto ¤t_dir : full_list) {
1319 for (
int step = 0; step <= n_steps; step++) {
1320 V3D dir_temp = current_dir;
1321 dir_temp *= (min_d + step * delta_d);
1323 int num_indexed = 0;
1324 for (
const auto &q_vector : q_vectors) {
1325 q_vec = q_vector / (2.0 * M_PI);
1327 nearest_int = std::round(dot_prod);
1329 if (
error <= required_tolerance)
1333 if (num_indexed > max_indexed)
1335 selected_dirs.clear();
1336 max_indexed = num_indexed;
1338 if (num_indexed >= max_indexed) {
1339 selected_dirs.emplace_back(dir_temp);
1346 std::vector<int> index_vals;
1347 std::vector<V3D> indexed_qs;
1348 index_vals.reserve(q_vectors.size());
1349 indexed_qs.reserve(q_vectors.size());
1352 for (
const auto &selected_dir : selected_dirs) {
1353 V3D current_dir = selected_dir;
1355 GetIndexedPeaks_1D(current_dir, q_vectors, required_tolerance, index_vals, indexed_qs, fit_error);
1359 double length = current_dir.
norm();
1360 if (length >= min_d && length <= max_d)
1362 bool duplicate =
false;
1363 for (
const auto &direction : directions) {
1364 V3D diff = current_dir - direction;
1366 if (diff.
norm() < 0.001) {
1369 diff = current_dir + direction;
1371 if (diff.
norm() < 0.001) {
1377 directions.emplace_back(current_dir);
1411 double min_d,
double max_d,
double required_tolerance,
1412 double degrees_per_step) {
1413 constexpr size_t N_FFT_STEPS = 512;
1414 constexpr size_t HALF_FFT_STEPS = 256;
1417 int max_indexed = 0;
1421 int num_steps = boost::math::iround(90.0 / degrees_per_step);
1426 double max_mag_Q = 0;
1427 for (
size_t q_num = 1; q_num < q_vectors.size(); q_num++) {
1428 double mag_Q = q_vectors[q_num].norm() / (2.0 * M_PI);
1429 if (mag_Q > max_mag_Q)
1438 std::vector<double> max_fft_val;
1439 max_fft_val.resize(full_list.size());
1441 double projections[N_FFT_STEPS];
1442 double magnitude_fft[HALF_FFT_STEPS];
1444 double index_factor = N_FFT_STEPS / max_mag_Q;
1446 for (
size_t dir_num = 0; dir_num < full_list.size(); dir_num++) {
1447 V3D current_dir = full_list[dir_num];
1448 max_mag_fft =
GetMagFFT(q_vectors, current_dir, N_FFT_STEPS, projections, index_factor, magnitude_fft);
1450 max_fft_val[dir_num] = max_mag_fft;
1456 std::vector<double> max_fft_copy;
1457 max_fft_copy.resize(full_list.size());
1458 for (
size_t i = 0; i < max_fft_copy.size(); i++) {
1459 max_fft_copy[i] = max_fft_val[i];
1462 std::sort(max_fft_copy.begin(), max_fft_copy.end());
1464 size_t index = max_fft_copy.size() - 1;
1465 max_mag_fft = max_fft_copy[
index];
1467 double threshold = max_mag_fft;
1468 while ((
index > max_fft_copy.size() - N_TO_TRY) && threshold >= max_mag_fft / 2) {
1470 threshold = max_fft_copy[
index];
1473 std::vector<V3D> temp_dirs;
1474 for (
size_t i = 0; i < max_fft_val.size(); i++) {
1475 if (max_fft_val[i] >= threshold) {
1476 temp_dirs.emplace_back(full_list[i]);
1484 std::vector<V3D> temp_dirs_2;
1486 for (
const auto &temp_dir : temp_dirs) {
1487 GetMagFFT(q_vectors, temp_dir, N_FFT_STEPS, projections, index_factor, magnitude_fft);
1491 double q_val = max_mag_Q /
position;
1492 double d_val = 1 / q_val;
1493 if (d_val >= 0.8 * min_d && d_val <= 1.2 * max_d) {
1494 temp = temp_dir * d_val;
1495 temp_dirs_2.emplace_back(temp);
1504 for (
const auto &dir_num : temp_dirs_2) {
1506 if (num_indexed > max_indexed)
1507 max_indexed = num_indexed;
1513 for (
const auto &dir_num : temp_dirs_2) {
1514 current_dir = dir_num;
1515 num_indexed =
NumberIndexed_1D(current_dir, q_vectors, required_tolerance);
1516 if (num_indexed >= 0.50 * max_indexed)
1517 temp_dirs.emplace_back(current_dir);
1523 std::vector<int> index_vals;
1524 std::vector<V3D> indexed_qs;
1525 for (
auto &temp_dir : temp_dirs) {
1526 num_indexed =
GetIndexedPeaks_1D(temp_dir, q_vectors, required_tolerance, index_vals, indexed_qs, fit_error);
1533 num_indexed =
GetIndexedPeaks_1D(temp_dir, q_vectors, required_tolerance, index_vals, indexed_qs, fit_error);
1534 if (num_indexed > max_indexed)
1535 max_indexed = num_indexed;
1544 temp_dirs_2.clear();
1545 for (
const auto &temp_dir : temp_dirs) {
1546 current_dir = temp_dir;
1547 double length = current_dir.
norm();
1548 if (length >= 0.8 * min_d && length <= 1.2 * max_d)
1549 temp_dirs_2.emplace_back(current_dir);
1554 for (
const auto &dir_num : temp_dirs_2) {
1555 current_dir = dir_num;
1556 num_indexed =
NumberIndexed_1D(current_dir, q_vectors, required_tolerance);
1557 if (num_indexed > max_indexed * 0.75)
1558 temp_dirs.emplace_back(current_dir);
1564 double len_tol = 0.1;
1565 double ang_tol = 5.0;
1566 DiscardDuplicates(directions, temp_dirs, q_vectors, required_tolerance, len_tol, ang_tol);
1595 double projections[],
double index_factor,
double magnitude_fft[]) {
1596 for (
size_t i = 0; i < N; i++) {
1597 projections[i] = 0.0;
1601 for (
const auto &q_vector : q_vectors) {
1602 q_vec = q_vector / (2.0 * M_PI);
1604 auto index =
static_cast<size_t>(
fabs(index_factor * dot_prod));
1606 projections[
index] += 1;
1608 projections[N - 1] += 1;
1612 gsl_fft_real_radix2_transform(projections, 1, N);
1613 for (
size_t i = 1; i < N / 2; i++) {
1614 magnitude_fft[i] = sqrt(projections[i] * projections[i] + projections[N - i] * projections[N - i]);
1617 magnitude_fft[0] =
fabs(projections[0]);
1620 double max_mag_fft = 0.0;
1621 for (
size_t i = dc_end; i < N / 2; i++)
1622 if (magnitude_fft[i] > max_mag_fft)
1623 max_mag_fft = magnitude_fft[i];
1643 bool found_min =
false;
1645 while (i < N - 1 && !found_min) {
1646 val = magnitude_fft[i];
1647 if (val < threshold && val <= magnitude_fft[i - 1] && val <= magnitude_fft[i + 1])
1655 bool found_max =
false;
1656 while (i < N - 1 && !found_max) {
1657 val = magnitude_fft[i];
1658 if (val >= threshold && val >= magnitude_fft[i - 1] && val >= magnitude_fft[i + 1])
1667 for (
size_t j = i - 2; j < std::min(N, i + 3); j++) {
1668 sum +=
static_cast<double>(j) * magnitude_fft[j];
1669 w_sum += magnitude_fft[j];
1704 double min_d,
double max_d) {
1706 throw std::invalid_argument(
"Find_UB(): UB matrix NULL or not 3X3");
1709 size_t index = a_index;
1715 double min_deg = (RAD_TO_DEG)*atan(2.0 * std::min(0.2, min_d / max_d));
1719 bool b_found =
false;
1720 while (!b_found &&
index < directions.size()) {
1722 double gamma = a_dir.
angle(
vec) * RAD_TO_DEG;
1724 if (gamma >= min_deg && (180. - gamma) >= min_deg) {
1726 if (gamma > 90 + epsilon)
1738 bool c_found =
false;
1744 while (!c_found &&
index < directions.size()) {
1747 while (!c_found && factor >= -1)
1751 perp_ang = perp.
angle(c_dir) * RAD_TO_DEG;
1752 alpha = b_dir.
angle(c_dir) * RAD_TO_DEG;
1753 beta = a_dir.
angle(c_dir) * RAD_TO_DEG;
1756 if (perp_ang < 90. - epsilon && alpha >= min_deg && (180. - alpha) >= min_deg && beta >= min_deg &&
1757 (180. - beta) >= min_deg) {
1771 throw std::runtime_error(
"UB could not be formed, invert matrix failed");
1804 const std::vector<V3D> &q_vectors,
double req_tolerance,
double min_vol) {
1806 throw std::invalid_argument(
"Find_UB(): UB matrix NULL or not 3X3");
1809 int max_indexed = 0;
1819 for (
size_t i = 0; i < directions.size() - 2; i++) {
1820 a_temp = directions[i];
1821 for (
size_t j = i + 1; j < directions.size() - 1; j++) {
1822 b_temp = directions[j];
1824 for (
size_t k = j + 1; k < directions.size(); k++) {
1825 c_temp = directions[k];
1827 if (vol > min_vol) {
1828 const auto num_indexed =
NumberIndexed_3D(a_temp, b_temp, c_temp, q_vectors, req_tolerance);
1832 if (num_indexed > 1.20 * max_indexed) {
1833 max_indexed = num_indexed;
1843 if (max_indexed <= 0) {
1849 c_dir = c_dir * (-1.0);
1853 throw std::runtime_error(
"UB could not be formed, invert matrix failed");
1879 const double cosBeta,
const double cosGamma,
const double sinGamma) {
1881 double c1 = c * cosBeta;
1882 double c2 = c * (cosAlpha - cosGamma * cosBeta) / sinGamma;
1884 sqrt(1 - cosAlpha * cosAlpha - cosBeta * cosBeta - cosGamma * cosGamma + 2 * cosAlpha * cosBeta * cosGamma);
1885 double c3 = c * V / sinGamma;
1889 auto basis_2 = basis_3.cross(basis_1).normalized();
1920 const std::vector<V3D> &q_vectors,
double required_tolerance,
double len_tol,
1923 std::vector<V3D> temp;
1927 V3D zero_vec(0, 0, 0);
1936 while (dir_num < directions.size())
1938 current_dir = directions[dir_num];
1939 double current_length = current_dir.
norm();
1942 if (current_length > 0)
1945 temp.emplace_back(current_dir);
1946 check_index = dir_num;
1948 while (check_index < directions.size() && !new_dir) {
1949 next_dir = directions[check_index];
1950 next_length = next_dir.
norm();
1951 if (next_length > 0) {
1952 length_diff =
fabs(next_dir.
norm() - current_length);
1953 if ((length_diff / current_length) < len_tol)
1955 angle = current_dir.
angle(next_dir) * RAD_TO_DEG;
1956 if ((std::isnan)(angle))
1958 if ((angle < ang_tol) || (angle > (180.0 - ang_tol))) {
1959 temp.emplace_back(next_dir);
1960 directions[check_index] = zero_vec;
1974 int max_indexed = 0;
1977 for (
size_t i = 0; i < temp.size(); i++) {
1978 int num_indexed =
NumberIndexed_1D(temp[i], q_vectors, required_tolerance);
1979 if (num_indexed > max_indexed) {
1980 max_indexed = num_indexed;
1981 max_i =
static_cast<long>(i);
1985 if (max_indexed > 0)
1987 new_list.emplace_back(temp[max_i]);
2000 for (
size_t i = 0; i < 3; i++) {
2001 hkl[i] = std::round(hkl[i]);
2015 for (
auto &entry : hkl_list) {
2029 if (floor(myVal + 1.) - myVal <
tolerance)
2048 if ((hkl[0] == 0.) && (hkl[1] == 0.) && (hkl[2] == 0.))
2069 double total_error = 0;
2071 for (
const auto &hkl : hkls) {
2074 h_error =
fabs(round(hkl[0]) - hkl[0]);
2075 k_error =
fabs(round(hkl[1]) - hkl[1]);
2076 l_error =
fabs(round(hkl[2]) - hkl[2]);
2077 total_error += h_error + k_error + l_error;
2082 average_error = total_error / (3.0 *
static_cast<double>(
count));
2084 average_error = 0.0;
2091 const std::vector<V3D> &q_vectors) {
2096 throw std::runtime_error(
"The UB in IndexingError() is not valid");
2098 if (hkls.size() != q_vectors.size()) {
2099 throw std::runtime_error(
"Different size hkl and q_vectors in IndexingError()");
2102 double total_error = 0;
2104 for (
size_t i = 0; i < hkls.size(); i++) {
2105 hkl = UB_inverse * q_vectors[i] / (2.0 * M_PI);
2107 double h_error =
fabs(hkl[0] - round(hkl[0]));
2108 double k_error =
fabs(hkl[1] - round(hkl[1]));
2109 double l_error =
fabs(hkl[2] - round(hkl[2]));
2110 total_error += h_error + k_error + l_error;
2114 return total_error / (3.0 *
static_cast<double>(hkls.size()));
2134 for (
size_t row = 0; row < 3; row++)
2135 for (
size_t col = 0; col < 3; col++) {
2136 if (!std::isfinite(UB[row][col])) {
2143 double abs_det =
fabs(det);
2145 return !(abs_det > 10 || abs_det < 1e-12);
2176 throw std::runtime_error(
"The UB in NumberIndexed() is not valid");
2180 for (
const auto &q_vector : q_vectors) {
2181 hkl = UB_inverse * q_vector / (2.0 * M_PI);
2208 if (direction.
norm() == 0)
2213 for (
const auto &q_vector : q_vectors) {
2214 double proj_value = direction.
scalar_prod(q_vector) / (2.0 * M_PI);
2215 double error =
fabs(proj_value - std::round(proj_value));
2246 const std::vector<V3D> &q_vectors,
double tolerance) {
2247 if (a_dir.
norm() == 0 || b_dir.
norm() == 0 || c_dir.
norm() == 0)
2253 for (
const auto &q_vector : q_vectors) {
2254 hkl_vec[0] = a_dir.
scalar_prod(q_vector) / (2.0 * M_PI);
2255 hkl_vec[1] = b_dir.
scalar_prod(q_vector) / (2.0 * M_PI);
2256 hkl_vec[2] = c_dir.
scalar_prod(q_vector) / (2.0 * M_PI);
2289 std::vector<V3D> &miller_indices,
double &ave_error) {
2295 throw std::runtime_error(
"The UB in CalculateMillerIndices() is not valid");
2298 miller_indices.clear();
2299 miller_indices.reserve(q_vectors.size());
2303 for (
const auto &q_vector : q_vectors) {
2309 miller_indices.emplace_back(hkl);
2313 ave_error /= (3.0 *
count);
2339 V3D &miller_indices) {
2344 miller_indices =
V3D(0, 0, 0);
2361 return inverseUB * q_vector / (2.0 * M_PI);
2393 double required_tolerance, std::vector<int> &index_vals,
2394 std::vector<V3D> &indexed_qs,
double &fit_error) {
2395 int num_indexed = 0;
2398 index_vals.reserve(q_vectors.size());
2399 indexed_qs.reserve(q_vectors.size());
2403 if (direction.
norm() == 0)
2407 for (
const auto &q_vector : q_vectors) {
2408 double proj_value = direction.
scalar_prod(q_vector) / (2.0 * M_PI);
2409 double nearest_int = std::round(proj_value);
2410 double error =
fabs(proj_value - nearest_int);
2411 if (
error < required_tolerance) {
2413 indexed_qs.emplace_back(q_vector);
2414 index_vals.emplace_back(boost::numeric_cast<int>(nearest_int));
2459 const std::vector<V3D> &q_vectors,
double required_tolerance,
2460 std::vector<V3D> &miller_indices, std::vector<V3D> &indexed_qs,
2461 double &fit_error) {
2463 int num_indexed = 0;
2465 miller_indices.clear();
2466 miller_indices.reserve(q_vectors.size());
2469 indexed_qs.reserve(q_vectors.size());
2473 for (
const auto &q_vector : q_vectors) {
2474 double projected_h = direction_1.
scalar_prod(q_vector) / (2.0 * M_PI);
2475 double projected_k = direction_2.
scalar_prod(q_vector) / (2.0 * M_PI);
2476 double projected_l = direction_3.
scalar_prod(q_vector) / (2.0 * M_PI);
2478 hkl(projected_h, projected_k, projected_l);
2481 double h_int = std::round(projected_h);
2482 double k_int = std::round(projected_k);
2483 double l_int = std::round(projected_l);
2485 double h_error =
fabs(projected_h - h_int);
2486 double k_error =
fabs(projected_k - k_int);
2487 double l_error =
fabs(projected_l - l_int);
2489 fit_error += h_error * h_error + k_error * k_error + l_error * l_error;
2491 indexed_qs.emplace_back(q_vector);
2493 V3D miller_ind(h_int, k_int, l_int);
2494 miller_indices.emplace_back(miller_ind);
2529 std::vector<V3D> &miller_indices, std::vector<V3D> &indexed_qs,
double &fit_error) {
2531 int num_indexed = 0;
2534 miller_indices.clear();
2535 miller_indices.reserve(q_vectors.size());
2538 indexed_qs.reserve(q_vectors.size());
2546 throw std::runtime_error(
"The UB in GetIndexedPeaks() is not valid");
2549 for (
const auto &q_vector : q_vectors) {
2550 hkl = UB_inverse * q_vector / (2.0 * M_PI);
2553 for (
int i = 0; i < 3; i++) {
2554 error = hkl[i] - std::round(hkl[i]);
2558 indexed_qs.emplace_back(q_vector);
2560 V3D miller_ind(round(hkl[0]), round(hkl[1]), round(hkl[2]));
2561 miller_indices.emplace_back(miller_ind);
2590 throw std::invalid_argument(
"MakeHemisphereDirections(): n_steps must be greater than 0");
2593 std::vector<V3D> direction_list;
2595 double angle_step = M_PI / (2 * n_steps);
2597 for (
int iPhi = 0; iPhi < n_steps + 1; ++iPhi) {
2598 double phi =
static_cast<double>(iPhi) * angle_step;
2599 double r = sin(phi);
2601 int n_theta = boost::math::iround(2. * M_PI * r / angle_step);
2605 theta_step = 2. * M_PI + 1.;
2608 theta_step = 2. * M_PI /
static_cast<double>(n_theta);
2613 if (
fabs(phi - M_PI / 2.) < angle_step / 2.) {
2617 for (
int jTheta = 0; jTheta < n_theta; ++jTheta) {
2618 double theta =
static_cast<double>(jTheta) * theta_step;
2619 direction_list.emplace_back(r * cos(theta), cos(phi), r * sin(theta));
2622 return direction_list;
2640 double angle_degrees) {
2642 throw std::invalid_argument(
"MakeCircleDirections(): n_steps must be greater than 0");
2645 double max_component =
fabs(axis[0]);
2646 double min_component = max_component;
2647 size_t min_index = 0;
2648 for (
size_t i = 1; i < 3; i++) {
2649 if (
fabs(axis[i]) < min_component) {
2650 min_component =
fabs(axis[i]);
2653 if (
fabs(axis[i]) > max_component) {
2654 max_component =
fabs(axis[i]);
2658 if (max_component == 0) {
2659 throw std::invalid_argument(
"MakeCircleDirections(): Axis vector must be non-zero!");
2662 V3D second_vec(0, 0, 0);
2663 second_vec[min_index] = 1;
2669 Quat rotation_1(angle_degrees, perp_vec);
2670 V3D vector_at_angle(axis);
2671 rotation_1.
rotate(vector_at_angle);
2677 double angle_step = 360.0 / n_steps;
2678 Quat rotation_2(0, axis);
2679 std::vector<V3D> directions;
2680 for (
int i = 0; i < n_steps; i++) {
2681 V3D vec(vector_at_angle);
2684 directions.emplace_back(
vec);
2721 const std::vector<V3D> &direction_list,
double plane_spacing,
2722 double required_tolerance) {
2723 if (q_vectors.empty()) {
2724 throw std::invalid_argument(
"SelectDirection(): No Q vectors specified");
2727 if (direction_list.empty()) {
2728 throw std::invalid_argument(
"SelectDirection(): List of possible directions has zero length");
2732 double min_sum_sq_error = 1.0e100;
2734 for (
auto direction : direction_list) {
2735 double sum_sq_error = 0;
2736 direction /= plane_spacing;
2737 for (
const auto &q_vector : q_vectors) {
2738 double dot_product = direction.scalar_prod(q_vector) / (2.0 * M_PI);
2739 error = std::abs(dot_product - std::round(dot_product));
2743 if (sum_sq_error < min_sum_sq_error + DBL_EPSILON) {
2744 min_sum_sq_error = sum_sq_error;
2745 best_direction = direction;
2749 int num_indexed = 0;
2750 for (
const auto &q_vector : q_vectors) {
2751 double proj_value = best_direction.
scalar_prod(q_vector) / (2.0 * M_PI);
2752 error = std::abs(proj_value - std::round(proj_value));
2753 if (
error < required_tolerance)
2776 o_lattice.
setUB(UB);
2778 lattice_par.clear();
2779 lattice_par.emplace_back(o_lattice.
a());
2780 lattice_par.emplace_back(o_lattice.
b());
2781 lattice_par.emplace_back(o_lattice.
c());
2783 lattice_par.emplace_back(o_lattice.
alpha());
2784 lattice_par.emplace_back(o_lattice.
beta());
2785 lattice_par.emplace_back(o_lattice.
gamma());
2787 lattice_par.emplace_back(o_lattice.
volume());
2795 o_lattice.
setUB(UB);
2803 if (o_lattice.
getdh(0) != 0.0 || o_lattice.
getdk(0) != 0.0 || o_lattice.
getdl(0) != 0.0)
2805 if (o_lattice.
getdh(1) != 0.0 || o_lattice.
getdk(1) != 0.0 || o_lattice.
getdl(1) != 0.0)
2807 if (o_lattice.
getdh(2) != 0.0 || o_lattice.
getdk(2) != 0.0 || o_lattice.
getdl(2) != 0.0)
2815 o_lattice.
setUB(UB);
2820 if (ModVec[0] != 0.0 || ModVec[1] != 0.0 || ModVec[2] != 0.0)
2833 std::vector<double> lat_par;
2838 sprintf(buffer, std::string(
" %8.4f %8.4f %8.4f %8.3f %8.3f %8.3f %9.2f").c_str(), lat_par[0], lat_par[1],
2839 lat_par[2], lat_par[3], lat_par[4], lat_par[5], lat_par[6]);
2841 std::string result(buffer);
double value
The value of the point.
bool withinTol(const double value, const double tolerance)
std::map< DeltaEMode::Type, std::string > index
std::vector< T > const * vec
static double Optimize_6dUB(Kernel::DblMatrix &UB, Kernel::DblMatrix &ModUB, const std::vector< Kernel::V3D > &hkl_vectors, const std::vector< Kernel::V3D > &mnp_vectors, const int &ModDim, const std::vector< Kernel::V3D > &q_vectors, std::vector< double > &sigabc, std::vector< double > &sigq)
STATIC method Optimize_UB: Calculates the matrix that most nearly maps the specified hkl_vectors to t...
static int GetIndexedPeaks(const Kernel::DblMatrix &UB, const std::vector< Kernel::V3D > &q_vectors, double required_tolerance, std::vector< Kernel::V3D > &miller_indices, std::vector< Kernel::V3D > &indexed_qs, double &fit_error)
Get lists of indices and Qs for peaks indexed by the specified UB matrix.
static double IndexingError(const Kernel::DblMatrix &UB, const std::vector< Kernel::V3D > &hkls, const std::vector< Kernel::V3D > &q_vectors)
Find the average indexing error for UB with the specified q's and hkls.
static int GetModulationVectors(const Kernel::DblMatrix &UB, const Kernel::DblMatrix &ModUB, Kernel::V3D &ModVec1, Kernel::V3D &ModVec2, Kernel::V3D &ModVec3)
static void DiscardDuplicates(std::vector< Kernel::V3D > &new_list, std::vector< Kernel::V3D > &directions, const std::vector< Kernel::V3D > &q_vectors, double required_tolerance, double len_tol, double ang_tol)
Construct a sublist of the specified list of a,b,c directions, by removing all directions that seem t...
static std::string GetLatticeParameterString(const Kernel::DblMatrix &UB)
Get a formatted string listing the lattice parameters and cell volume.
static double Optimize_Direction(Kernel::V3D &best_vec, const std::vector< int > &index_values, const std::vector< Kernel::V3D > &q_vectors)
Find the vector that best corresponds to plane normal, given 1-D indices.
static void RoundHKL(Kernel::V3D &hkl)
Round all the components of a HKL objects to the nearest integer.
static std::vector< Kernel::V3D > MakeCircleDirections(int n_steps, const Kernel::V3D &axis, double angle_degrees)
Make list of the circle of direction vectors that form a fixed angle with the specified axis.
static double GetFirstMaxIndex(const double magnitude_fft[], size_t N, double threshold)
Get the location of the first maximum (beyond the DC term) in the |FFT| that exceeds the specified th...
static int GetIndexedPeaks_1D(const Kernel::V3D &direction, const std::vector< Kernel::V3D > &q_vectors, double required_tolerance, std::vector< int > &index_vals, std::vector< Kernel::V3D > &indexed_qs, double &fit_error)
Get lists of indices and Qs for peaks indexed in the specified direction.
static double Find_UB(Kernel::DblMatrix &UB, const std::vector< Kernel::V3D > &q_vectors, OrientedLattice &lattice, double required_tolerance, int base_index, size_t num_initial, double degrees_per_step, bool fixAll=false, int iterations=1)
Find the UB matrix that most nearly indexes the specified qxyz values given the lattice parameters.
static Kernel::V3D makeCDir(const Kernel::V3D &a_dir, const Kernel::V3D &b_dir, const double c, const double cosAlpha, const double cosBeta, const double cosGamma, const double sinGamma)
Get the vector in the direction of "c" given other unit cell information.
static int SelectDirection(Kernel::V3D &best_direction, const std::vector< Kernel::V3D > &q_vectors, const std::vector< Kernel::V3D > &direction_list, double plane_spacing, double required_tolerance)
Choose the direction in a list of directions, that is most nearly perpendicular to planes with the sp...
static int NumberOfValidIndexes(const std::vector< Kernel::V3D > &hkls, double tolerance, double &average_error)
Find number of valid HKLs and average error, in list of HKLs.
static int NumberIndexed_1D(const Kernel::V3D &direction, const std::vector< Kernel::V3D > &q_vectors, double tolerance)
Calculate the number of Q vectors that map to an integer index in one direction.
static bool CheckUB(const Kernel::DblMatrix &UB)
Check that the specified UB is reasonable for an orientation matrix.
static int NumberIndexed(const Kernel::DblMatrix &UB, const std::vector< Kernel::V3D > &q_vectors, double tolerance)
Calculate the number of Q vectors that are mapped to integer indices by UB.
static std::vector< Kernel::V3D > MakeHemisphereDirections(int n_steps)
Make list of direction vectors uniformly distributed over a hemisphere.
static size_t FFTScanFor_Directions(std::vector< Kernel::V3D > &directions, const std::vector< Kernel::V3D > &q_vectors, double min_d, double max_d, double required_tolerance, double degrees_per_step)
Use FFT to get list of possible directions and lengths for real space unit cell.
static int GetIndexedPeaks_3D(const Kernel::V3D &direction_1, const Kernel::V3D &direction_2, const Kernel::V3D &direction_3, const std::vector< Kernel::V3D > &q_vectors, double required_tolerance, std::vector< Kernel::V3D > &miller_indices, std::vector< Kernel::V3D > &indexed_qs, double &fit_error)
Get lists of indices and Qs for peaks indexed in three given directions.
static double GetMagFFT(const std::vector< Kernel::V3D > &q_vectors, const Kernel::V3D ¤t_dir, const size_t N, double projections[], double index_factor, double magnitude_fft[])
Get the magnitude of the FFT of the projections of the q_vectors on the current direction vector.
static void RoundHKLs(std::vector< Kernel::V3D > &hkl_list)
Round all the components of a list of V3D objects, to the nearest integer.
static bool GetModulationVector(const Kernel::DblMatrix &UB, const Kernel::DblMatrix &ModUB, Kernel::V3D &ModVec, const int j)
static size_t ScanFor_Directions(std::vector< Kernel::V3D > &directions, const std::vector< Kernel::V3D > &q_vectors, double min_d, double max_d, double required_tolerance, double degrees_per_step)
Get list of possible directions and lengths for real space unit cell.
static double Optimize_UB(Kernel::DblMatrix &UB, const std::vector< Kernel::V3D > &hkl_vectors, const std::vector< Kernel::V3D > &q_vectors, std::vector< double > &sigabc)
Find the UB matrix that most nearly maps hkl to qxyz for 3 or more peaks.
static bool FormUB_From_abc_Vectors(Kernel::DblMatrix &UB, const std::vector< Kernel::V3D > &directions, size_t a_index, double min_d, double max_d)
Try to form a UB matrix from three vectors chosen from list of possible a,b,c directions,...
static bool ValidIndex(const Kernel::V3D &hkl, double tolerance)
Check is hkl is within tolerance of integer (h,k,l) non-zero values.
static double ScanFor_UB(Kernel::DblMatrix &UB, const std::vector< Kernel::V3D > &q_vectors, const UnitCell &cell, double degrees_per_step, double required_tolerance)
Scan rotations to find UB that indexes peaks given lattice parameters.
static int NumberIndexed_3D(const Kernel::V3D &a_dir, const Kernel::V3D &b_dir, const Kernel::V3D &c_dir, const std::vector< Kernel::V3D > &q_vectors, double tolerance)
Calculate the number of Q vectors that map to integer indices simutlaneously in three directions.
static bool GetLatticeParameters(const Kernel::DblMatrix &UB, std::vector< double > &lattice_par)
Get the lattice parameters for the specified orientation matrix.
static int CalculateMillerIndices(const Kernel::DblMatrix &UB, const std::vector< Kernel::V3D > &q_vectors, double tolerance, std::vector< Kernel::V3D > &miller_indices, double &ave_error)
Given a UB, get list of Miller indices for specifed Qs and tolerance.
static bool MakeNiggliUB(const Kernel::DblMatrix &UB, Kernel::DblMatrix &newUB)
Construct a newUB corresponding to a Niggli cell from the given UB.
Class to implement UB matrix.
void setModUB(const Kernel::DblMatrix &newModUB)
Sets the Modulation UB matrix.
void setUB(const Kernel::DblMatrix &newUB)
Sets the UB matrix and recalculates lattice parameters.
static bool GetUB(Kernel::DblMatrix &UB, const Kernel::V3D &a_dir, const Kernel::V3D &b_dir, const Kernel::V3D &c_dir)
Get the UB matrix corresponding to the real space edge vectors a,b,c.
Class to implement unit cell of crystals.
double alpha() const
Get lattice parameter.
double a(int nd) const
Get lattice parameter a1-a3 as function of index (0-2)
double c() const
Get lattice parameter.
double getdh(int j) const
Get modulation vectors for satellites.
double getdk(int j) const
Get modulation vectors for satellites.
double volume() const
Volume of the direct unit-cell.
double getdl(int j) const
Get modulation vectors for satellites.
double beta() const
Get lattice parameter.
void setError(double _aerr, double _berr, double _cerr, double _alphaerr, double _betaerr, double _gammaerr, const int angleunit=angDegrees)
Set lattice parameter errors.
double b() const
Get lattice parameter.
const Kernel::V3D getModVec(int j) const
Get modulation vectors for satellites.
double gamma() const
Get lattice parameter.
T determinant() const
Calculate the determinant.
T Invert()
LU inversion routine.
void setRow(const size_t nRow, const std::vector< T > &newRow)
size_t numRows() const
Return the number of rows in the matrix.
size_t numCols() const
Return the number of columns in the matrix.
void rotate(V3D &) const
Rotate a vector.
void setAngleAxis(const double _deg, const V3D &_axis)
Constructor from an angle and axis.
static bool compareMagnitude(const Kernel::V3D &v1, const Kernel::V3D &v2)
Convenience method for sorting list of V3D objects based on magnitude.
constexpr double scalar_prod(const V3D &v) const noexcept
Calculates the cross product.
double normalize()
Make a normalized vector (return norm value)
constexpr V3D cross_prod(const V3D &v) const noexcept
Cross product (this * argument)
double angle(const V3D &) const
Angle between this and another vector.
double norm() const noexcept
double hklError() const
Calculates the error in hkl.
Eigen::Vector3d toVector3d(const Kernel::V3D &vec)
Converts Kernel::V3D to Eigen::Vector3d.
Kernel::V3D toV3D(const Eigen::Vector3d &vec)
This header provides conversion helpers between vector and rotation types in MantidKernel and equival...
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.