17#include <Eigen/Eigenvalues>
18#include <doctest/doctest.h>
19#include <fmt/ranges.h>
46 system.set_electric_field({0, 0, 0.0001});
48 Eigen::MatrixXd tmp = Eigen::MatrixXd(1e5 * system.get_matrix()).array().round() / 1e5;
49 std::vector<double> matrix_vector(tmp.data(), tmp.data() + tmp.size());
50 DOCTEST_MESSAGE(fmt::format(
"Constructed: {}", fmt::join(matrix_vector,
", ")));
52 system.diagonalize(diagonalizer);
53 tmp = Eigen::MatrixXd(1e5 * system.get_matrix()).array().round() / 1e5;
54 matrix_vector = std::vector<double>(tmp.data(), tmp.data() + tmp.size());
55 DOCTEST_MESSAGE(fmt::format(
"Diagonalized: {}", fmt::join(matrix_vector,
", ")));
57 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eigensolver;
58 eigensolver.compute(system.get_matrix());
59 auto eigenenergies_eigen = eigensolver.eigenvalues();
60 auto eigenenergies_pairinteraction = system.get_eigenenergies();
61 for (
int i = 0; i < eigenenergies_eigen.size(); ++i) {
62 DOCTEST_CHECK(std::abs(eigenenergies_eigen(i) - eigenenergies_pairinteraction(i)) < 1e-10);
73 .restrict_quantum_number_l(0, 1)
82 diagonalize<SystemAtom<std::complex<double>>>({system1, system2}, diagonalizer);
85 auto matrix2 = system2.get_matrix();
86 for (
int i = 0; i < matrix1.rows(); ++i) {
87 for (
int j = 0; j < matrix1.cols(); ++j) {
89 DOCTEST_CHECK(std::abs(matrix1.coeff(i, j)) < 1e-10);
90 DOCTEST_CHECK(std::abs(matrix2.coeff(i, j)) < 1e-10);
97 doctest::skip(
true)) {
108 .set_species(
"Sr87_mqdt")
110 .restrict_quantum_number_l(0, 1)
113 std::vector<SystemAtom<std::complex<double>>> systems;
115 for (
int i = 0; i < n; ++i) {
118 systems.push_back(std::move(system));
121 DOCTEST_MESSAGE(
"Basis size: ", basis->get_number_of_states());
123 diagonalize<SystemAtom<std::complex<double>>>(systems, diagonalizer);
132 .restrict_quantum_number_l(0, 1)
140 Eigen::MatrixXcd matrix = system.
get_matrix();
141 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXcd> eigensolver;
142 eigensolver.compute(matrix);
143 auto eigenenergies_eigen = eigensolver.eigenvalues();
146 std::vector<std::unique_ptr<DiagonalizerInterface<std::complex<double>>>> diagonalizers;
147 std::vector<double> rtols;
149 DOCTEST_SUBCASE(
"Double precision") {
150 diagonalizers.push_back(std::make_unique<
DiagonalizerEigen<std::complex<double>>>());
156 diagonalizers.push_back(std::make_unique<
DiagonalizerFeast<std::complex<double>>>(300));
158 rtols = {1e-1, 1e-6, 1e-14};
159 eps = std::numeric_limits<double>::epsilon();
162 DOCTEST_SUBCASE(
"Single precision") {
163 diagonalizers.push_back(
166 diagonalizers.push_back(
168 diagonalizers.push_back(
172 diagonalizers.push_back(
175 rtols = {1e-1, 1e-6};
176 eps = std::numeric_limits<float>::epsilon();
180 for (
double rtol_eigenenergies : rtols) {
181 double atol_eigenvectors =
182 std::max(0.5 * rtol_eigenenergies / std::sqrt(basis->get_number_of_states()), 4 * eps);
183 DOCTEST_MESSAGE(
"Precision: " << rtol_eigenenergies <<
" (rtol eigenenergies), "
184 << atol_eigenvectors <<
" (atol eigenvectors)");
186 for (
const auto &diagonalizer : diagonalizers) {
195 system.
diagonalize(*diagonalizer, std::numeric_limits<float>::lowest() / 2,
196 std::numeric_limits<float>::max() / 2, rtol_eigenenergies);
198 auto eigenvectors_pairinteraction = system.get_eigenbasis()->get_coefficients();
201 (eigenenergies_eigen - eigenenergies_pairinteraction).array().abs().maxCoeff() <
202 rtol_eigenenergies * matrix.norm());
204 for (
int i = 0; i < eigenvectors_pairinteraction.cols(); ++i) {
205 DOCTEST_CHECK(abs(1 - eigenvectors_pairinteraction.col(i).norm()) <
206 atol_eigenvectors * eigenvectors_pairinteraction.rows());
213 double min_energy = 0.153355;
214 double max_energy = 0.153360;
220 .restrict_quantum_number_n(58, 62)
221 .restrict_quantum_number_l(0, 1)
226 system.set_electric_field(
229 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eigensolver;
230 eigensolver.compute(system.get_matrix());
231 auto eigenenergies_all = eigensolver.eigenvalues();
232 std::vector<double> eigenenergies_eigen;
233 for (
int i = 0; i < eigenenergies_all.size(); ++i) {
234 if (eigenenergies_all[i] > min_energy && eigenenergies_all[i] < max_energy) {
235 eigenenergies_eigen.push_back(eigenenergies_all[i]);
240 std::vector<std::unique_ptr<DiagonalizerInterface<double>>> diagonalizers;
251 for (
const auto &diagonalizer : diagonalizers) {
253 system.set_electric_field(
256 system.diagonalize(*diagonalizer, min_energy, max_energy, 1e-6);
257 auto eigenenergies_pairinteraction = system.get_eigenenergies();
259 Eigen::MatrixXd tmp = (1e5 * eigenenergies_pairinteraction).array().round() / 1e5;
260 std::vector<double> eigenenergies_vector(tmp.data(), tmp.data() + tmp.size());
261 DOCTEST_MESSAGE(fmt::format(
"Eigenenergies: {}", fmt::join(eigenenergies_vector,
", ")));
263 DOCTEST_CHECK(eigenenergies_eigen.size() == 8);
264 DOCTEST_CHECK(eigenenergies_pairinteraction.size() == 8);
265 for (
size_t i = 0; i < eigenenergies_eigen.size(); ++i) {
266 DOCTEST_CHECK(std::abs(eigenenergies_eigen[i] - eigenenergies_pairinteraction[i]) <
273#include <Eigen/Dense>
277 for (
size_t i = 0; i < 10; ++i) {
280 Eigen::MatrixXd matrix = Eigen::MatrixXd::Random(n, n);
281 matrix = (matrix + matrix.transpose()).eval();
282 Eigen::VectorXd eigenenergies(n);
286 LAPACKE_dsyev(LAPACK_COL_MAJOR,
'V',
'U', n, matrix.data(), n, eigenenergies.data());
287 DOCTEST_CHECK(info == 0);
293 double min_energy = -1;
294 double max_energy = -1;
300 .restrict_quantum_number_n(58, 62)
301 .restrict_quantum_number_l(0, 1)
304 std::vector<std::unique_ptr<DiagonalizerInterface<double>>> diagonalizers;
310 for (
const auto &diagonalizer : diagonalizers) {
312 system.set_electric_field(
315 system.diagonalize(*diagonalizer, min_energy, max_energy, 1e-6);
316 auto eigenenergies_pairinteraction = system.get_eigenenergies();
318 DOCTEST_CHECK(eigenenergies_pairinteraction.size() == 0);
Builder class for creating BasisAtom objects.
BasisAtomCreator< Scalar > & append_ket(const std::shared_ptr< const ket_t > &ket)
BasisAtomCreator< Scalar > & set_species(const std::string &value)
BasisAtomCreator< Scalar > & restrict_quantum_number_n(int min, int max)
BasisAtomCreator< Scalar > & restrict_quantum_number_nu(real_t min, real_t max)
static Database & get_global_instance()
Builder class for creating KetAtom objects.
KetAtomCreator & set_quantum_number_n(int value)
std::shared_ptr< const KetAtom > create(Database &database) const
KetAtomCreator & set_quantum_number_j(double value)
KetAtomCreator & set_quantum_number_l(double value)
KetAtomCreator & set_species(const std::string &value)
KetAtomCreator & set_quantum_number_m(double value)
Type & set_electric_field(const std::array< real_t, 3 > &field)
const Eigen::SparseMatrix< scalar_t, Eigen::RowMajor > & get_matrix() const
System< Derived > & diagonalize(const DiagonalizerInterface< scalar_t > &diagonalizer, std::optional< real_t > min_eigenenergy={}, std::optional< real_t > max_eigenenergy={}, double rtol=1e-6)
Eigen::VectorX< real_t > get_eigenenergies() const
DOCTEST_TEST_CASE("create a basis for strontium 88")
constexpr double VOLT_PER_CM_IN_ATOMIC_UNITS