18#include <spdlog/spdlog.h>
21template <
typename Scalar>
25template <
typename Scalar>
27 this->hamiltonian_requires_construction =
true;
29 constexpr real_t numerical_precision = 100 * std::numeric_limits<real_t>::epsilon();
31 throw std::invalid_argument(
32 "The field must not have a y-component if the scalar type is real.");
35 electric_field = field;
40template <
typename Scalar>
42 this->hamiltonian_requires_construction =
true;
44 constexpr real_t numerical_precision = 100 * std::numeric_limits<real_t>::epsilon();
46 throw std::invalid_argument(
47 "The field must not have a y-component if the scalar type is real.");
50 magnetic_field = field;
55template <
typename Scalar>
57 this->hamiltonian_requires_construction =
true;
58 diamagnetism_enabled = enable;
62template <
typename Scalar>
65 this->hamiltonian_requires_construction =
true;
67 constexpr real_t numerical_precision = 100 * std::numeric_limits<real_t>::epsilon();
69 throw std::invalid_argument(
70 "The distance vector must not have a y-component if the scalar type is real.");
73 ion_distance_vector = vector;
78template <
typename Scalar>
80 this->hamiltonian_requires_construction =
true;
85template <
typename Scalar>
87 this->hamiltonian_requires_construction =
true;
88 if (value < 2 || value > 3) {
89 throw std::invalid_argument(
"The order of the Rydberg-ion interaction must be 2 or 3");
91 ion_interaction_order = value;
95template <
typename Scalar>
97 auto basis = this->hamiltonian->
get_basis();
99 constexpr real_t numerical_precision = 100 * std::numeric_limits<real_t>::epsilon();
103 this->hamiltonian_is_diagonal =
true;
104 bool sort_by_quantum_number_f =
true;
105 bool sort_by_quantum_number_m =
true;
106 bool sort_by_parity =
true;
111 Eigen::Map<const Eigen::Vector3<real_t>> vector_map(ion_distance_vector.data(),
112 ion_distance_vector.size());
113 real_t distance = vector_map.norm();
114 SPDLOG_DEBUG(
"Distance to the ion: {}", distance);
117 if (distance != std::numeric_limits<real_t>::infinity() && ion_interaction_order >= 2) {
121 spherical::get_transformator<Scalar>(1) * vector_map / distance;
122 vector_dipole_order = vector_dipole_order.conjugate() / std::pow(distance, 2);
124 for (
int q = -1; q <= 1; ++q) {
125 if (std::abs(vector_dipole_order[q + 1]) > numerical_precision) {
126 *this->hamiltonian -= ion_charge * vector_dipole_order[q + 1] *
128 this->hamiltonian_is_diagonal =
false;
129 sort_by_quantum_number_f =
false;
130 sort_by_parity =
false;
131 sort_by_quantum_number_m &= (q == 0);
138 if (distance != std::numeric_limits<real_t>::infinity() && ion_interaction_order >= 3) {
143 Eigen::KroneckerProduct(vector_map / distance, vector_map / distance);
144 vector_quadrupole_order = 3 * vector_quadrupole_order.conjugate() / std::pow(distance, 3);
146 for (
int q = -2; q <= 2; ++q) {
147 if (std::abs(vector_quadrupole_order[q + 2]) > numerical_precision) {
148 *this->hamiltonian -= ion_charge * vector_quadrupole_order[q + 2] *
150 this->hamiltonian_is_diagonal =
false;
151 sort_by_quantum_number_f =
false;
152 sort_by_quantum_number_m &= (q == 0);
161 Eigen::Map<const Eigen::Vector3<real_t>>(electric_field.data(), electric_field.size());
162 electric_field_spherical = electric_field_spherical.conjugate();
166 Eigen::Map<const Eigen::Vector3<real_t>>(magnetic_field.data(), magnetic_field.size());
167 magnetic_field_spherical = magnetic_field_spherical.conjugate();
173 for (
int q = -1; q <= 1; ++q) {
174 if (std::abs(electric_field_spherical[q + 1]) > numerical_precision) {
175 *this->hamiltonian -= electric_field_spherical[q + 1] *
177 this->hamiltonian_is_diagonal =
false;
178 sort_by_quantum_number_f =
false;
179 sort_by_parity =
false;
180 sort_by_quantum_number_m &= (q == 0);
188 for (
int q = -1; q <= 1; ++q) {
189 if (std::abs(magnetic_field_spherical[q + 1]) > numerical_precision) {
190 *this->hamiltonian -= magnetic_field_spherical[q + 1] *
192 this->hamiltonian_is_diagonal =
false;
193 sort_by_quantum_number_f =
false;
194 sort_by_quantum_number_m &= (q == 0);
205 if (diamagnetism_enabled) {
206 if (std::abs(magnetic_field_spherical[1]) > numerical_precision) {
207 *this->hamiltonian +=
static_cast<real_t>(1 / 12.) *
208 static_cast<Scalar
>(std::pow(magnetic_field_spherical[1], 2)) *
210 *this->hamiltonian -=
static_cast<real_t>(1 / 12.) *
211 static_cast<Scalar
>(std::pow(magnetic_field_spherical[1], 2)) *
213 this->hamiltonian_is_diagonal =
false;
214 sort_by_quantum_number_f =
false;
216 if (std::abs(magnetic_field_spherical[0]) > numerical_precision &&
217 std::abs(magnetic_field_spherical[2]) > numerical_precision) {
218 *this->hamiltonian -=
static_cast<real_t>(2 / 12.) * magnetic_field_spherical[0] *
219 magnetic_field_spherical[2] *
221 *this->hamiltonian -=
static_cast<real_t>(1 / 12.) * magnetic_field_spherical[0] *
222 magnetic_field_spherical[2] *
224 this->hamiltonian_is_diagonal =
false;
225 sort_by_quantum_number_f =
false;
227 if (std::abs(magnetic_field_spherical[1]) > numerical_precision &&
228 std::abs(magnetic_field_spherical[2]) > numerical_precision) {
229 *this->hamiltonian -=
static_cast<real_t>(std::sqrt(3.0) / 12.) *
230 magnetic_field_spherical[1] * magnetic_field_spherical[2] *
232 this->hamiltonian_is_diagonal =
false;
233 sort_by_quantum_number_f =
false;
234 sort_by_quantum_number_m =
false;
236 if (std::abs(magnetic_field_spherical[1]) > numerical_precision &&
237 std::abs(magnetic_field_spherical[0]) > numerical_precision) {
238 *this->hamiltonian -=
static_cast<real_t>(std::sqrt(3.0) / 12.) *
239 magnetic_field_spherical[1] * magnetic_field_spherical[0] *
241 this->hamiltonian_is_diagonal =
false;
242 sort_by_quantum_number_f =
false;
243 sort_by_quantum_number_m =
false;
245 if (std::abs(magnetic_field_spherical[2]) > numerical_precision) {
246 *this->hamiltonian -=
static_cast<real_t>(std::sqrt(1.5) / 12.) *
247 static_cast<Scalar
>(std::pow(magnetic_field_spherical[2], 2)) *
249 this->hamiltonian_is_diagonal =
false;
250 sort_by_quantum_number_f =
false;
251 sort_by_quantum_number_m =
false;
253 if (std::abs(magnetic_field_spherical[0]) > numerical_precision) {
254 *this->hamiltonian -=
static_cast<real_t>(std::sqrt(1.5) / 12.) *
255 static_cast<Scalar
>(std::pow(magnetic_field_spherical[0], 2)) *
257 this->hamiltonian_is_diagonal =
false;
258 sort_by_quantum_number_f =
false;
259 sort_by_quantum_number_m =
false;
264 this->blockdiagonalizing_labels.clear();
265 if (sort_by_quantum_number_f) {
268 if (sort_by_quantum_number_m) {
271 if (sort_by_parity) {
277template class SystemAtom<double>;
278template class SystemAtom<std::complex<double>>;
Type & set_ion_charge(real_t charge)
typename traits::CrtpTraits< Type >::real_t real_t
Type & set_diamagnetism_enabled(bool enable)
SystemAtom(std::shared_ptr< const basis_t > basis)
Type & set_electric_field(const std::array< real_t, 3 > &field)
Type & set_magnetic_field(const std::array< real_t, 3 > &field)
Type & set_ion_distance_vector(const std::array< real_t, 3 > &vector)
Type & set_ion_interaction_order(int value)
std::shared_ptr< const basis_t > get_basis() const
Matrix< Type, Size, 1 > Vector
Matrix< Type, 3, 1 > Vector3
@ ELECTRIC_QUADRUPOLE_ZERO
@ SORT_BY_QUANTUM_NUMBER_M
@ SORT_BY_QUANTUM_NUMBER_F
Helper struct to extract types from a numerical type.