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<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);
1160 std::vector<V3D> b_dir_list;
1169 int max_indexed = 0;
1173 std::vector<V3D> selected_a_dirs;
1174 std::vector<V3D> selected_b_dirs;
1175 std::vector<V3D> selected_c_dirs;
1177 for (
auto &a_dir_num : a_dir_list) {
1178 a_dir_temp = a_dir_num;
1179 a_dir_temp =
V3D(a_dir_temp);
1182 b_dir_list =
MakeCircleDirections(boost::numeric_cast<int>(num_b_steps), a_dir_temp, gamma_degrees);
1184 for (
auto &b_dir_num : b_dir_list) {
1185 b_dir_temp = b_dir_num;
1186 b_dir_temp =
V3D(b_dir_temp);
1188 c_dir_temp =
makeCDir(a_dir_temp, b_dir_temp, c, cosAlpha, cosBeta, cosGamma, sinGamma);
1189 int num_indexed = 0;
1190 for (
const auto &q_vector : q_vectors) {
1191 bool indexes_peak =
true;
1192 q_vec = q_vector / (2.0 * M_PI);
1194 nearest_int = std::round(dot_prod);
1196 if (
error > required_tolerance)
1197 indexes_peak =
false;
1200 nearest_int = std::round(dot_prod);
1202 if (
error > required_tolerance)
1203 indexes_peak =
false;
1206 nearest_int = std::round(dot_prod);
1208 if (
error > required_tolerance)
1209 indexes_peak =
false;
1216 if (num_indexed > max_indexed)
1218 selected_a_dirs.clear();
1219 selected_b_dirs.clear();
1220 selected_c_dirs.clear();
1221 max_indexed = num_indexed;
1223 if (num_indexed == max_indexed) {
1224 selected_a_dirs.emplace_back(a_dir_temp);
1225 selected_b_dirs.emplace_back(b_dir_temp);
1226 selected_c_dirs.emplace_back(c_dir_temp);
1233 double min_error = 1.0e50;
1234 for (
size_t dir_num = 0; dir_num < selected_a_dirs.size(); dir_num++) {
1235 a_dir_temp = selected_a_dirs[dir_num];
1236 b_dir_temp = selected_b_dirs[dir_num];
1237 c_dir_temp = selected_c_dirs[dir_num];
1239 double sum_sq_error = 0.0;
1240 for (
const auto &q_vector : q_vectors) {
1241 q_vec = q_vector / (2.0 * M_PI);
1243 nearest_int = std::round(dot_prod);
1244 error = dot_prod - nearest_int;
1248 nearest_int = std::round(dot_prod);
1249 error = dot_prod - nearest_int;
1253 nearest_int = std::round(dot_prod);
1254 error = dot_prod - nearest_int;
1258 if (sum_sq_error < min_error) {
1259 min_error = sum_sq_error;
1267 throw std::runtime_error(
"UB could not be formed, invert matrix failed");
1298 double max_d,
double required_tolerance,
double degrees_per_step) {
1303 int max_indexed = 0;
1307 int num_steps = boost::math::iround(90.0 / degrees_per_step);
1314 double delta_d = 0.1f;
1315 int n_steps = boost::math::iround(1.0 + (max_d - min_d) / delta_d);
1317 std::vector<V3D> selected_dirs;
1320 for (
const auto ¤t_dir : full_list) {
1321 for (
int step = 0; step <= n_steps; step++) {
1322 dir_temp = current_dir;
1323 dir_temp *= (min_d + step * delta_d);
1325 int num_indexed = 0;
1326 for (
const auto &q_vector : q_vectors) {
1327 q_vec = q_vector / (2.0 * M_PI);
1329 nearest_int = std::round(dot_prod);
1331 if (
error <= required_tolerance)
1335 if (num_indexed > max_indexed)
1337 selected_dirs.clear();
1338 max_indexed = num_indexed;
1340 if (num_indexed >= max_indexed) {
1341 selected_dirs.emplace_back(dir_temp);
1348 std::vector<int> index_vals;
1349 std::vector<V3D> indexed_qs;
1350 index_vals.reserve(q_vectors.size());
1351 indexed_qs.reserve(q_vectors.size());
1356 for (
auto &selected_dir : selected_dirs) {
1357 current_dir = selected_dir;
1359 GetIndexedPeaks_1D(current_dir, q_vectors, required_tolerance, index_vals, indexed_qs, fit_error);
1363 double length = current_dir.
norm();
1364 if (length >= min_d && length <= max_d)
1366 bool duplicate =
false;
1367 for (
auto &direction : directions) {
1368 dir_temp = direction;
1369 diff = current_dir - dir_temp;
1371 if (diff.
norm() < 0.001) {
1374 diff = current_dir + dir_temp;
1376 if (diff.
norm() < 0.001) {
1382 directions.emplace_back(current_dir);
1416 double min_d,
double max_d,
double required_tolerance,
1417 double degrees_per_step) {
1418 constexpr size_t N_FFT_STEPS = 512;
1419 constexpr size_t HALF_FFT_STEPS = 256;
1422 int max_indexed = 0;
1426 int num_steps = boost::math::iround(90.0 / degrees_per_step);
1431 double max_mag_Q = 0;
1432 for (
size_t q_num = 1; q_num < q_vectors.size(); q_num++) {
1433 double mag_Q = q_vectors[q_num].norm() / (2.0 * M_PI);
1434 if (mag_Q > max_mag_Q)
1443 std::vector<double> max_fft_val;
1444 max_fft_val.resize(full_list.size());
1446 double projections[N_FFT_STEPS];
1447 double magnitude_fft[HALF_FFT_STEPS];
1449 double index_factor = N_FFT_STEPS / max_mag_Q;
1451 for (
size_t dir_num = 0; dir_num < full_list.size(); dir_num++) {
1452 V3D current_dir = full_list[dir_num];
1453 max_mag_fft =
GetMagFFT(q_vectors, current_dir, N_FFT_STEPS, projections, index_factor, magnitude_fft);
1455 max_fft_val[dir_num] = max_mag_fft;
1461 std::vector<double> max_fft_copy;
1462 max_fft_copy.resize(full_list.size());
1463 for (
size_t i = 0; i < max_fft_copy.size(); i++) {
1464 max_fft_copy[i] = max_fft_val[i];
1467 std::sort(max_fft_copy.begin(), max_fft_copy.end());
1469 size_t index = max_fft_copy.size() - 1;
1470 max_mag_fft = max_fft_copy[
index];
1472 double threshold = max_mag_fft;
1473 while ((
index > max_fft_copy.size() - N_TO_TRY) && threshold >= max_mag_fft / 2) {
1475 threshold = max_fft_copy[
index];
1478 std::vector<V3D> temp_dirs;
1479 for (
size_t i = 0; i < max_fft_val.size(); i++) {
1480 if (max_fft_val[i] >= threshold) {
1481 temp_dirs.emplace_back(full_list[i]);
1489 std::vector<V3D> temp_dirs_2;
1491 for (
auto &temp_dir : temp_dirs) {
1492 GetMagFFT(q_vectors, temp_dir, N_FFT_STEPS, projections, index_factor, magnitude_fft);
1496 double q_val = max_mag_Q /
position;
1497 double d_val = 1 / q_val;
1498 if (d_val >= 0.8 * min_d && d_val <= 1.2 * max_d) {
1499 temp = temp_dir * d_val;
1500 temp_dirs_2.emplace_back(temp);
1509 for (
auto &dir_num : temp_dirs_2) {
1510 current_dir = dir_num;
1511 num_indexed =
NumberIndexed_1D(current_dir, q_vectors, required_tolerance);
1512 if (num_indexed > max_indexed)
1513 max_indexed = num_indexed;
1519 for (
auto &dir_num : temp_dirs_2) {
1520 current_dir = dir_num;
1521 num_indexed =
NumberIndexed_1D(current_dir, q_vectors, required_tolerance);
1522 if (num_indexed >= 0.50 * max_indexed)
1523 temp_dirs.emplace_back(current_dir);
1529 std::vector<int> index_vals;
1530 std::vector<V3D> indexed_qs;
1531 for (
auto &temp_dir : temp_dirs) {
1532 num_indexed =
GetIndexedPeaks_1D(temp_dir, q_vectors, required_tolerance, index_vals, indexed_qs, fit_error);
1539 num_indexed =
GetIndexedPeaks_1D(temp_dir, q_vectors, required_tolerance, index_vals, indexed_qs, fit_error);
1540 if (num_indexed > max_indexed)
1541 max_indexed = num_indexed;
1550 temp_dirs_2.clear();
1551 for (
auto &temp_dir : temp_dirs) {
1552 current_dir = temp_dir;
1553 double length = current_dir.
norm();
1554 if (length >= 0.8 * min_d && length <= 1.2 * max_d)
1555 temp_dirs_2.emplace_back(current_dir);
1560 for (
auto &dir_num : temp_dirs_2) {
1561 current_dir = dir_num;
1562 num_indexed =
NumberIndexed_1D(current_dir, q_vectors, required_tolerance);
1563 if (num_indexed > max_indexed * 0.75)
1564 temp_dirs.emplace_back(current_dir);
1570 double len_tol = 0.1;
1571 double ang_tol = 5.0;
1572 DiscardDuplicates(directions, temp_dirs, q_vectors, required_tolerance, len_tol, ang_tol);
1601 double projections[],
double index_factor,
double magnitude_fft[]) {
1602 for (
size_t i = 0; i < N; i++) {
1603 projections[i] = 0.0;
1607 for (
const auto &q_vector : q_vectors) {
1608 q_vec = q_vector / (2.0 * M_PI);
1610 auto index =
static_cast<size_t>(
fabs(index_factor * dot_prod));
1612 projections[
index] += 1;
1614 projections[N - 1] += 1;
1618 gsl_fft_real_radix2_transform(projections, 1, N);
1619 for (
size_t i = 1; i < N / 2; i++) {
1620 magnitude_fft[i] = sqrt(projections[i] * projections[i] + projections[N - i] * projections[N - i]);
1623 magnitude_fft[0] =
fabs(projections[0]);
1626 double max_mag_fft = 0.0;
1627 for (
size_t i = dc_end; i < N / 2; i++)
1628 if (magnitude_fft[i] > max_mag_fft)
1629 max_mag_fft = magnitude_fft[i];
1649 bool found_min =
false;
1651 while (i < N - 1 && !found_min) {
1652 val = magnitude_fft[i];
1653 if (val < threshold && val <= magnitude_fft[i - 1] && val <= magnitude_fft[i + 1])
1661 bool found_max =
false;
1662 while (i < N - 1 && !found_max) {
1663 val = magnitude_fft[i];
1664 if (val >= threshold && val >= magnitude_fft[i - 1] && val >= magnitude_fft[i + 1])
1673 for (
size_t j = i - 2; j < std::min(N, i + 3); j++) {
1674 sum +=
static_cast<double>(j) * magnitude_fft[j];
1675 w_sum += magnitude_fft[j];
1710 double min_d,
double max_d) {
1712 throw std::invalid_argument(
"Find_UB(): UB matrix NULL or not 3X3");
1715 size_t index = a_index;
1721 double min_deg = (RAD_TO_DEG)*atan(2.0 * std::min(0.2, min_d / max_d));
1725 bool b_found =
false;
1726 while (!b_found &&
index < directions.size()) {
1728 double gamma = a_dir.
angle(vec) * RAD_TO_DEG;
1730 if (gamma >= min_deg && (180. - gamma) >= min_deg) {
1732 if (gamma > 90 + epsilon)
1744 bool c_found =
false;
1750 while (!c_found &&
index < directions.size()) {
1753 while (!c_found && factor >= -1)
1757 perp_ang = perp.
angle(c_dir) * RAD_TO_DEG;
1758 alpha = b_dir.
angle(c_dir) * RAD_TO_DEG;
1759 beta = a_dir.
angle(c_dir) * RAD_TO_DEG;
1762 if (perp_ang < 90. - epsilon && alpha >= min_deg && (180. - alpha) >= min_deg && beta >= min_deg &&
1763 (180. - beta) >= min_deg) {
1777 throw std::runtime_error(
"UB could not be formed, invert matrix failed");
1810 const std::vector<V3D> &q_vectors,
double req_tolerance,
double min_vol) {
1812 throw std::invalid_argument(
"Find_UB(): UB matrix NULL or not 3X3");
1815 int max_indexed = 0;
1825 for (
size_t i = 0; i < directions.size() - 2; i++) {
1826 a_temp = directions[i];
1827 for (
size_t j = i + 1; j < directions.size() - 1; j++) {
1828 b_temp = directions[j];
1830 for (
size_t k = j + 1; k < directions.size(); k++) {
1831 c_temp = directions[k];
1833 if (vol > min_vol) {
1834 const auto num_indexed =
NumberIndexed_3D(a_temp, b_temp, c_temp, q_vectors, req_tolerance);
1838 if (num_indexed > 1.20 * max_indexed) {
1839 max_indexed = num_indexed;
1849 if (max_indexed <= 0) {
1855 c_dir = c_dir * (-1.0);
1859 throw std::runtime_error(
"UB could not be formed, invert matrix failed");
1885 const double cosBeta,
const double cosGamma,
const double sinGamma) {
1887 double c1 = c * cosBeta;
1888 double c2 = c * (cosAlpha - cosGamma * cosBeta) / sinGamma;
1890 sqrt(1 - cosAlpha * cosAlpha - cosBeta * cosBeta - cosGamma * cosGamma + 2 * cosAlpha * cosBeta * cosGamma);
1891 double c3 = c * V / sinGamma;
1895 auto basis_2 = basis_3.cross(basis_1).normalized();
1926 const std::vector<V3D> &q_vectors,
double required_tolerance,
double len_tol,
1929 std::vector<V3D> temp;
1933 V3D zero_vec(0, 0, 0);
1942 while (dir_num < directions.size())
1944 current_dir = directions[dir_num];
1945 double current_length = current_dir.
norm();
1948 if (current_length > 0)
1951 temp.emplace_back(current_dir);
1952 check_index = dir_num;
1954 while (check_index < directions.size() && !new_dir) {
1955 next_dir = directions[check_index];
1956 next_length = next_dir.
norm();
1957 if (next_length > 0) {
1958 length_diff =
fabs(next_dir.
norm() - current_length);
1959 if ((length_diff / current_length) < len_tol)
1961 angle = current_dir.
angle(next_dir) * RAD_TO_DEG;
1962 if ((std::isnan)(angle))
1964 if ((angle < ang_tol) || (angle > (180.0 - ang_tol))) {
1965 temp.emplace_back(next_dir);
1966 directions[check_index] = zero_vec;
1980 int max_indexed = 0;
1983 for (
size_t i = 0; i < temp.size(); i++) {
1984 int num_indexed =
NumberIndexed_1D(temp[i], q_vectors, required_tolerance);
1985 if (num_indexed > max_indexed) {
1986 max_indexed = num_indexed;
1987 max_i =
static_cast<long>(i);
1991 if (max_indexed > 0)
1993 new_list.emplace_back(temp[max_i]);
2006 for (
size_t i = 0; i < 3; i++) {
2007 hkl[i] = std::round(hkl[i]);
2021 for (
auto &entry : hkl_list) {
2035 if (floor(myVal + 1.) - myVal <
tolerance)
2054 if ((hkl[0] == 0.) && (hkl[1] == 0.) && (hkl[2] == 0.))
2075 double total_error = 0;
2077 for (
const auto &hkl : hkls) {
2080 h_error =
fabs(round(hkl[0]) - hkl[0]);
2081 k_error =
fabs(round(hkl[1]) - hkl[1]);
2082 l_error =
fabs(round(hkl[2]) - hkl[2]);
2083 total_error += h_error + k_error + l_error;
2088 average_error = total_error / (3.0 *
static_cast<double>(
count));
2090 average_error = 0.0;
2097 const std::vector<V3D> &q_vectors) {
2102 throw std::runtime_error(
"The UB in IndexingError() is not valid");
2104 if (hkls.size() != q_vectors.size()) {
2105 throw std::runtime_error(
"Different size hkl and q_vectors in IndexingError()");
2108 double total_error = 0;
2110 for (
size_t i = 0; i < hkls.size(); i++) {
2111 hkl = UB_inverse * q_vectors[i] / (2.0 * M_PI);
2113 double h_error =
fabs(hkl[0] - round(hkl[0]));
2114 double k_error =
fabs(hkl[1] - round(hkl[1]));
2115 double l_error =
fabs(hkl[2] - round(hkl[2]));
2116 total_error += h_error + k_error + l_error;
2120 return total_error / (3.0 *
static_cast<double>(hkls.size()));
2140 for (
size_t row = 0; row < 3; row++)
2141 for (
size_t col = 0; col < 3; col++) {
2142 if (!std::isfinite(UB[row][col])) {
2149 double abs_det =
fabs(det);
2151 return !(abs_det > 10 || abs_det < 1e-12);
2182 throw std::runtime_error(
"The UB in NumberIndexed() is not valid");
2186 for (
const auto &q_vector : q_vectors) {
2187 hkl = UB_inverse * q_vector / (2.0 * M_PI);
2214 if (direction.
norm() == 0)
2219 for (
const auto &q_vector : q_vectors) {
2220 double proj_value = direction.
scalar_prod(q_vector) / (2.0 * M_PI);
2221 double error =
fabs(proj_value - std::round(proj_value));
2252 const std::vector<V3D> &q_vectors,
double tolerance) {
2253 if (a_dir.
norm() == 0 || b_dir.
norm() == 0 || c_dir.
norm() == 0)
2259 for (
const auto &q_vector : q_vectors) {
2260 hkl_vec[0] = a_dir.
scalar_prod(q_vector) / (2.0 * M_PI);
2261 hkl_vec[1] = b_dir.
scalar_prod(q_vector) / (2.0 * M_PI);
2262 hkl_vec[2] = c_dir.
scalar_prod(q_vector) / (2.0 * M_PI);
2295 std::vector<V3D> &miller_indices,
double &ave_error) {
2301 throw std::runtime_error(
"The UB in CalculateMillerIndices() is not valid");
2304 miller_indices.clear();
2305 miller_indices.reserve(q_vectors.size());
2309 for (
const auto &q_vector : q_vectors) {
2315 miller_indices.emplace_back(hkl);
2319 ave_error /= (3.0 *
count);
2345 V3D &miller_indices) {
2350 miller_indices =
V3D(0, 0, 0);
2367 return inverseUB * q_vector / (2.0 * M_PI);
2399 double required_tolerance, std::vector<int> &index_vals,
2400 std::vector<V3D> &indexed_qs,
double &fit_error) {
2401 int num_indexed = 0;
2404 index_vals.reserve(q_vectors.size());
2405 indexed_qs.reserve(q_vectors.size());
2409 if (direction.
norm() == 0)
2413 for (
const auto &q_vector : q_vectors) {
2414 double proj_value = direction.
scalar_prod(q_vector) / (2.0 * M_PI);
2415 double nearest_int = std::round(proj_value);
2416 double error =
fabs(proj_value - nearest_int);
2417 if (
error < required_tolerance) {
2419 indexed_qs.emplace_back(q_vector);
2420 index_vals.emplace_back(boost::numeric_cast<int>(nearest_int));
2465 const std::vector<V3D> &q_vectors,
double required_tolerance,
2466 std::vector<V3D> &miller_indices, std::vector<V3D> &indexed_qs,
2467 double &fit_error) {
2469 int num_indexed = 0;
2471 miller_indices.clear();
2472 miller_indices.reserve(q_vectors.size());
2475 indexed_qs.reserve(q_vectors.size());
2479 for (
const auto &q_vector : q_vectors) {
2480 double projected_h = direction_1.
scalar_prod(q_vector) / (2.0 * M_PI);
2481 double projected_k = direction_2.
scalar_prod(q_vector) / (2.0 * M_PI);
2482 double projected_l = direction_3.
scalar_prod(q_vector) / (2.0 * M_PI);
2484 hkl(projected_h, projected_k, projected_l);
2487 double h_int = std::round(projected_h);
2488 double k_int = std::round(projected_k);
2489 double l_int = std::round(projected_l);
2491 double h_error =
fabs(projected_h - h_int);
2492 double k_error =
fabs(projected_k - k_int);
2493 double l_error =
fabs(projected_l - l_int);
2495 fit_error += h_error * h_error + k_error * k_error + l_error * l_error;
2497 indexed_qs.emplace_back(q_vector);
2499 V3D miller_ind(h_int, k_int, l_int);
2500 miller_indices.emplace_back(miller_ind);
2535 std::vector<V3D> &miller_indices, std::vector<V3D> &indexed_qs,
double &fit_error) {
2537 int num_indexed = 0;
2540 miller_indices.clear();
2541 miller_indices.reserve(q_vectors.size());
2544 indexed_qs.reserve(q_vectors.size());
2552 throw std::runtime_error(
"The UB in GetIndexedPeaks() is not valid");
2555 for (
const auto &q_vector : q_vectors) {
2556 hkl = UB_inverse * q_vector / (2.0 * M_PI);
2559 for (
int i = 0; i < 3; i++) {
2560 error = hkl[i] - std::round(hkl[i]);
2564 indexed_qs.emplace_back(q_vector);
2566 V3D miller_ind(round(hkl[0]), round(hkl[1]), round(hkl[2]));
2567 miller_indices.emplace_back(miller_ind);
2596 throw std::invalid_argument(
"MakeHemisphereDirections(): n_steps must be greater than 0");
2599 std::vector<V3D> direction_list;
2601 double angle_step = M_PI / (2 * n_steps);
2603 for (
int iPhi = 0; iPhi < n_steps + 1; ++iPhi) {
2604 double phi =
static_cast<double>(iPhi) * angle_step;
2605 double r = sin(phi);
2607 int n_theta = boost::math::iround(2. * M_PI * r / angle_step);
2611 theta_step = 2. * M_PI + 1.;
2614 theta_step = 2. * M_PI /
static_cast<double>(n_theta);
2619 if (
fabs(phi - M_PI / 2.) < angle_step / 2.) {
2623 for (
int jTheta = 0; jTheta < n_theta; ++jTheta) {
2624 double theta =
static_cast<double>(jTheta) * theta_step;
2625 direction_list.emplace_back(r * cos(theta), cos(phi), r * sin(theta));
2628 return direction_list;
2646 double angle_degrees) {
2648 throw std::invalid_argument(
"MakeCircleDirections(): n_steps must be greater than 0");
2651 double max_component =
fabs(axis[0]);
2652 double min_component = max_component;
2653 size_t min_index = 0;
2654 for (
size_t i = 1; i < 3; i++) {
2655 if (
fabs(axis[i]) < min_component) {
2656 min_component =
fabs(axis[i]);
2659 if (
fabs(axis[i]) > max_component) {
2660 max_component =
fabs(axis[i]);
2664 if (max_component == 0) {
2665 throw std::invalid_argument(
"MakeCircleDirections(): Axis vector must be non-zero!");
2668 V3D second_vec(0, 0, 0);
2669 second_vec[min_index] = 1;
2675 Quat rotation_1(angle_degrees, perp_vec);
2676 V3D vector_at_angle(axis);
2677 rotation_1.
rotate(vector_at_angle);
2683 double angle_step = 360.0 / n_steps;
2684 Quat rotation_2(0, axis);
2685 std::vector<V3D> directions;
2686 for (
int i = 0; i < n_steps; i++) {
2687 V3D vec(vector_at_angle);
2690 directions.emplace_back(vec);
2727 const std::vector<V3D> &direction_list,
double plane_spacing,
2728 double required_tolerance) {
2729 if (q_vectors.empty()) {
2730 throw std::invalid_argument(
"SelectDirection(): No Q vectors specified");
2733 if (direction_list.empty()) {
2734 throw std::invalid_argument(
"SelectDirection(): List of possible directions has zero length");
2738 double min_sum_sq_error = 1.0e100;
2740 for (
auto direction : direction_list) {
2741 double sum_sq_error = 0;
2742 direction /= plane_spacing;
2743 for (
const auto &q_vector : q_vectors) {
2744 double dot_product = direction.scalar_prod(q_vector) / (2.0 * M_PI);
2745 error = std::abs(dot_product - std::round(dot_product));
2749 if (sum_sq_error < min_sum_sq_error + DBL_EPSILON) {
2750 min_sum_sq_error = sum_sq_error;
2751 best_direction = direction;
2755 int num_indexed = 0;
2756 for (
const auto &q_vector : q_vectors) {
2757 double proj_value = best_direction.
scalar_prod(q_vector) / (2.0 * M_PI);
2758 error = std::abs(proj_value - std::round(proj_value));
2759 if (
error < required_tolerance)
2782 o_lattice.
setUB(UB);
2784 lattice_par.clear();
2785 lattice_par.emplace_back(o_lattice.
a());
2786 lattice_par.emplace_back(o_lattice.
b());
2787 lattice_par.emplace_back(o_lattice.
c());
2789 lattice_par.emplace_back(o_lattice.
alpha());
2790 lattice_par.emplace_back(o_lattice.
beta());
2791 lattice_par.emplace_back(o_lattice.
gamma());
2793 lattice_par.emplace_back(o_lattice.
volume());
2801 o_lattice.
setUB(UB);
2809 if (o_lattice.
getdh(0) != 0.0 || o_lattice.
getdk(0) != 0.0 || o_lattice.
getdl(0) != 0.0)
2811 if (o_lattice.
getdh(1) != 0.0 || o_lattice.
getdk(1) != 0.0 || o_lattice.
getdl(1) != 0.0)
2813 if (o_lattice.
getdh(2) != 0.0 || o_lattice.
getdk(2) != 0.0 || o_lattice.
getdl(2) != 0.0)
2821 o_lattice.
setUB(UB);
2826 if (ModVec[0] != 0.0 || ModVec[1] != 0.0 || ModVec[2] != 0.0)
2839 std::vector<double> lat_par;
2844 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],
2845 lat_par[2], lat_par[3], lat_par[4], lat_par[5], lat_par[6]);
2847 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
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 matix 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.