Line data Source code
1 : // SPDX-FileCopyrightText: 2024 PairInteraction Developers 2 : // SPDX-License-Identifier: LGPL-3.0-or-later 3 : 4 : #include "pairinteraction/system/SystemPair.hpp" 5 : 6 : #include "pairinteraction/basis/BasisAtom.hpp" 7 : #include "pairinteraction/basis/BasisAtomCreator.hpp" 8 : #include "pairinteraction/basis/BasisPair.hpp" 9 : #include "pairinteraction/basis/BasisPairCreator.hpp" 10 : #include "pairinteraction/database/Database.hpp" 11 : #include "pairinteraction/diagonalize/DiagonalizerEigen.hpp" 12 : #include "pairinteraction/diagonalize/DiagonalizerFeast.hpp" 13 : #include "pairinteraction/diagonalize/DiagonalizerLapackeEvr.hpp" 14 : #include "pairinteraction/diagonalize/diagonalize.hpp" 15 : #include "pairinteraction/ket/KetAtom.hpp" 16 : #include "pairinteraction/ket/KetAtomCreator.hpp" 17 : #include "pairinteraction/system/SystemAtom.hpp" 18 : #include "pairinteraction/utils/Range.hpp" 19 : 20 : #include <cmath> 21 : #include <doctest/doctest.h> 22 : #include <fmt/ranges.h> 23 : 24 : namespace pairinteraction { 25 : 26 : constexpr double VOLT_PER_CM_IN_ATOMIC_UNITS = 1 / 5.14220675112e9; 27 : constexpr double UM_IN_ATOMIC_UNITS = 1 / 5.29177210544e-5; 28 : constexpr double HARTREE_IN_GHZ = 6579683.920501762; 29 : 30 1 : DOCTEST_TEST_CASE("construct a pair Hamiltonian") { 31 1 : auto &database = Database::get_global_instance(); 32 1 : auto diagonalizer = DiagonalizerEigen<double>(); 33 : 34 : // Construct and diagonalize the constituent systems 35 0 : auto basis = BasisAtomCreator<double>() 36 2 : .set_species("Rb") 37 1 : .restrict_quantum_number_n(60, 61) 38 1 : .restrict_quantum_number_l(0, 1) 39 1 : .restrict_quantum_number_m(-0.5, 0.5) 40 1 : .create(database); 41 : 42 1 : SystemAtom<double> system1(basis); 43 1 : SystemAtom<double> system2(basis); 44 1 : system1.set_electric_field({0, 0, 1 * VOLT_PER_CM_IN_ATOMIC_UNITS}); 45 1 : system2.set_electric_field({0, 0, 2 * VOLT_PER_CM_IN_ATOMIC_UNITS}); 46 1 : diagonalize<SystemAtom<double>>({system1, system2}, diagonalizer); 47 : 48 : // Construct and diagonalize the system_pair 49 1 : auto basis_pair = BasisPairCreator<double>().add(system1).add(system2).create(); 50 1 : DOCTEST_MESSAGE("Number of states in pair basis: ", basis_pair->get_number_of_states()); 51 : 52 1 : auto system_pair = SystemPair<double>(basis_pair); 53 1 : system_pair.set_distance_vector({0, 0, 3 * UM_IN_ATOMIC_UNITS}); 54 1 : system_pair.diagonalize(diagonalizer); 55 : 56 : // Print the largest and smallest eigenenergies 57 1 : auto eigenenergies = system_pair.get_eigenenergies(); 58 1 : DOCTEST_MESSAGE("Lowest energy: ", eigenenergies.minCoeff()); 59 1 : DOCTEST_MESSAGE("Highest energy: ", eigenenergies.maxCoeff()); 60 1 : } 61 : 62 1 : DOCTEST_TEST_CASE("construct a pair Hamiltonian in a non-canonical pair basis") { 63 1 : auto &database = Database::get_global_instance(); 64 : 65 0 : auto basis = BasisAtomCreator<double>() 66 2 : .set_species("Rb") 67 1 : .restrict_quantum_number_n(60, 61) 68 1 : .restrict_quantum_number_l(0, 1) 69 1 : .restrict_quantum_number_m(-0.5, 0.5) 70 1 : .create(database); 71 : 72 1 : auto diagonalizer = DiagonalizerEigen<double>(); 73 1 : SystemAtom<double> system1(basis); 74 1 : SystemAtom<double> system2(basis); 75 1 : system1.set_electric_field({0, 0, 1 * VOLT_PER_CM_IN_ATOMIC_UNITS}); 76 1 : system2.set_electric_field({0, 0, 2 * VOLT_PER_CM_IN_ATOMIC_UNITS}); 77 1 : diagonalize<SystemAtom<double>>({system1, system2}, diagonalizer); 78 : 79 1 : auto pair_basis = BasisPairCreator<double>().add(system1).add(system2).create(); 80 1 : DOCTEST_REQUIRE(pair_basis->get_number_of_states() >= 2); 81 : 82 1 : SystemPair<double> reference_system(pair_basis); 83 1 : reference_system.set_distance_vector({0, 0, 3 * UM_IN_ATOMIC_UNITS}); 84 1 : const auto &reference_matrix = reference_system.get_matrix(); 85 : 86 : Eigen::SparseMatrix<double, Eigen::RowMajor> transformation( 87 1 : static_cast<Eigen::Index>(pair_basis->get_number_of_states()), 88 2 : static_cast<Eigen::Index>(pair_basis->get_number_of_states())); 89 1 : transformation.setIdentity(); 90 : 91 1 : double inverse_sqrt_two = 1 / std::sqrt(2.0); 92 1 : transformation.coeffRef(0, 0) = inverse_sqrt_two; 93 1 : transformation.coeffRef(1, 0) = inverse_sqrt_two; 94 1 : transformation.coeffRef(0, 1) = inverse_sqrt_two; 95 1 : transformation.coeffRef(1, 1) = -inverse_sqrt_two; 96 1 : transformation.makeCompressed(); 97 : 98 1 : auto transformed_pair_basis = pair_basis->transformed(transformation); 99 1 : SystemPair<double> transformed_system(transformed_pair_basis); 100 1 : transformed_system.set_distance_vector({0, 0, 3 * UM_IN_ATOMIC_UNITS}); 101 : 102 : Eigen::SparseMatrix<double, Eigen::RowMajor> expected_matrix = 103 1 : transformation.adjoint() * reference_matrix * transformation; 104 : 105 1 : DOCTEST_CHECK(transformed_system.get_matrix().isApprox(expected_matrix, 1e-11)); 106 1 : } 107 : 108 : #ifdef WITH_LAPACKE 109 1 : DOCTEST_TEST_CASE("diagonalize with lapacke_evr") { 110 1 : auto &database = Database::get_global_instance(); 111 1 : auto diagonalizer = DiagonalizerLapackeEvr<double>(); 112 : 113 : // Construct the state of interest 114 0 : auto ket = KetAtomCreator() 115 2 : .set_species("Rb") 116 1 : .set_quantum_number_n(60) 117 1 : .set_quantum_number_l(0) 118 1 : .set_quantum_number_j(0.5) 119 1 : .set_quantum_number_m(0.5) 120 1 : .create(database); 121 : 122 : // Construct and diagonalize the constituent systems 123 0 : auto basis = BasisAtomCreator<double>() 124 2 : .set_species("Rb") 125 1 : .restrict_quantum_number_n(ket->get_quantum_number_n() - 3, 126 1 : ket->get_quantum_number_n() + 3) 127 1 : .restrict_quantum_number_l(ket->get_quantum_number_l() - 1, 128 1 : ket->get_quantum_number_l() + 1) 129 1 : .create(database); 130 1 : SystemAtom<double> system(basis); 131 : 132 : // Construct and diagonalize the system_pair 133 2 : auto basis_pair = BasisPairCreator<double>() 134 1 : .add(system) 135 1 : .add(system) 136 1 : .restrict_energy(2 * ket->get_energy() - 2 / HARTREE_IN_GHZ, 137 1 : 2 * ket->get_energy() + 2 / HARTREE_IN_GHZ) 138 1 : .create(); 139 1 : DOCTEST_MESSAGE("Number of states in pair basis: ", basis_pair->get_number_of_states()); 140 : 141 1 : auto system_pair = SystemPair<double>(basis_pair); 142 1 : system_pair.set_distance_vector({0, 0, 3 * UM_IN_ATOMIC_UNITS}); 143 1 : system_pair.diagonalize(diagonalizer, 2 * ket->get_energy() - 0.5 / HARTREE_IN_GHZ, 144 1 : 2 * ket->get_energy() + 0.5 / HARTREE_IN_GHZ); 145 : 146 : // Print the largest and smallest eigenenergies 147 1 : auto eigenenergies = system_pair.get_eigenenergies(); 148 1 : DOCTEST_MESSAGE("Lowest energy: ", eigenenergies.minCoeff()); 149 1 : DOCTEST_MESSAGE("Highest energy: ", eigenenergies.maxCoeff()); 150 1 : } 151 : #endif 152 : } // namespace pairinteraction