LCOV - code coverage report
Current view: top level - pairinteraction - HamiltonianOne.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 276 282 97.9 %
Date: 2024-04-29 00:41:50 Functions: 8 12 66.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Sebastian Weber, Henri Menke. All rights reserved.
       3             :  *
       4             :  * This file is part of the pairinteraction library.
       5             :  *
       6             :  * The pairinteraction library is free software: you can redistribute it and/or modify
       7             :  * it under the terms of the GNU Lesser General Public License as published by
       8             :  * the Free Software Foundation, either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * The pairinteraction library is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public License
      17             :  * along with the pairinteraction library. If not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include "HamiltonianOne.hpp"
      21             : #include "filesystem.hpp"
      22             : 
      23             : #include <fmt/format.h>
      24             : 
      25             : #include <stdexcept>
      26             : #include <utility>
      27             : 
      28             : template <typename Scalar>
      29           3 : HamiltonianOne<Scalar>::HamiltonianOne(const Configuration &config, fs::path &path_cache,
      30             :                                        std::shared_ptr<BasisnamesOne> basis_one)
      31           3 :     : path_cache(path_cache) {
      32           3 :     this->basis = std::move(basis_one);
      33           3 :     configure(config);
      34           3 :     build();
      35           3 : }
      36             : 
      37             : template <typename Scalar>
      38           0 : const Configuration &HamiltonianOne<Scalar>::getConf()
      39             :     const { // TODO in Configurable Klasse auslagern, von der geerbt werrden soll
      40           0 :     return basicconf;
      41             : }
      42             : 
      43             : template <typename Scalar>
      44           8 : void HamiltonianOne<Scalar>::changeToSpherical(double val_x, double val_y, double val_z,
      45             :                                                double &val_p, double &val_m, double &val_0) {
      46           8 :     if (val_y != 0) {
      47           0 :         std::string msg("For fields with non-zero y-coordinates, a complex data type is needed.");
      48           0 :         std::cout << fmt::format(">>ERR{:s}", msg) << std::endl;
      49           0 :         throw std::runtime_error(msg);
      50             :     }
      51           8 :     val_p = -val_x / std::sqrt(2);
      52           8 :     val_m = val_x / std::sqrt(2);
      53           8 :     val_0 = val_z;
      54           8 : }
      55             : 
      56             : template <typename Scalar>
      57           4 : void HamiltonianOne<Scalar>::changeToSpherical(double val_x, double val_y, double val_z,
      58             :                                                std::complex<double> &val_p,
      59             :                                                std::complex<double> &val_m,
      60             :                                                std::complex<double> &val_0) {
      61           4 :     val_p = std::complex<double>(-val_x / std::sqrt(2), -val_y / std::sqrt(2));
      62           4 :     val_m = std::complex<double>(val_x / std::sqrt(2), -val_y / std::sqrt(2));
      63           4 :     val_0 = std::complex<double>(val_z, 0);
      64           4 : }
      65             : 
      66             : template <typename Scalar>
      67           3 : void HamiltonianOne<Scalar>::configure(const Configuration &config) {
      68           3 :     basicconf = this->basis->getConf();
      69           3 :     basicconf["deltaESingle"] << config["deltaESingle"];
      70           3 :     basicconf["diamagnetism"] << config["diamagnetism"];
      71             : 
      72           3 :     basicconf["deltaESingle"] >> deltaE;
      73           3 :     basicconf["species1"] >> species;
      74             : 
      75           3 :     diamagnetism = basicconf["diamagnetism"].str() == "true";
      76             : 
      77           3 :     config["minBx"] >> min_B_x;
      78           3 :     config["minBy"] >> min_B_y;
      79           3 :     config["minBz"] >> min_B_z;
      80           3 :     config["minEx"] >> min_E_x;
      81           3 :     config["minEy"] >> min_E_y;
      82           3 :     config["minEz"] >> min_E_z;
      83           3 :     config["maxBx"] >> max_B_x;
      84           3 :     config["maxBy"] >> max_B_y;
      85           3 :     config["maxBz"] >> max_B_z;
      86           3 :     config["maxEx"] >> max_E_x;
      87           3 :     config["maxEy"] >> max_E_y;
      88           3 :     config["maxEz"] >> max_E_z;
      89             : 
      90           3 :     if ((min_B_x == max_B_x) && (min_B_y == max_B_y) && (min_B_z == max_B_z) &&
      91           3 :         (min_E_x == max_E_x) && (min_E_y == max_E_y) && (min_E_z == max_E_z)) {
      92           3 :         nSteps = 1;
      93             :     } else {
      94           0 :         config["steps"] >> nSteps;
      95             :     }
      96           3 : }
      97             : 
      98             : template <typename Scalar>
      99           3 : void HamiltonianOne<Scalar>::build() {
     100           6 :     fs::path path_cache_mat;
     101             :     if (utils::is_complex<Scalar>::value) {
     102           1 :         path_cache_mat = path_cache / "cache_matrix_complex";
     103             :     } else {
     104           2 :         path_cache_mat = path_cache / "cache_matrix_real";
     105             :     }
     106           3 :     if (!fs::exists(path_cache_mat)) {
     107           3 :         fs::create_directory(path_cache_mat);
     108             :     }
     109             : 
     110           3 :     double tol = 1e-32;
     111             : 
     112             :     ////////////////////////////////////////////////////////
     113             :     ////// Build single atom basis and Hamiltonian /////////
     114             :     ////////////////////////////////////////////////////////
     115             : 
     116             :     // === Calculate one-atom Hamiltonian ===
     117             : 
     118             :     // --- Count entries of one-atom Hamiltonian ---
     119           3 :     size_t size_basis = this->basis->size();
     120           3 :     size_t size_energy = this->basis->size();
     121             : 
     122             :     // --- Construct one-atom  Hamiltonian and basis ---
     123           3 :     std::cout << "One-atom Hamiltonian, construct diagonal Hamiltonian" << std::endl;
     124             : 
     125           6 :     Hamiltonianmatrix<Scalar> hamiltonian_energy(size_basis, size_energy);
     126             : 
     127           3 :     double energy_initial = 0;
     128           9 :     for (const auto &state : this->basis->initial()) {
     129           6 :         energy_initial += energy_level(species, state.n, state.l, state.j);
     130             :     }
     131           3 :     energy_initial /= this->basis->initial().size(); // TODO save it to the json file
     132             : 
     133           6 :     std::vector<bool> is_necessary(this->basis->size(), false);
     134           3 :     idx_t idx = 0;
     135        1149 :     for (const auto &state : *this->basis) {
     136        1146 :         double val = energy_level(species, state.n, state.l, state.j) - energy_initial;
     137        1146 :         if (std::abs(val) < deltaE + 1e-11 || deltaE < 0) { // TODO
     138         374 :             is_necessary[state.idx] = true;
     139         374 :             hamiltonian_energy.addEntries(idx, idx, val);
     140         374 :             hamiltonian_energy.addBasis(idx, idx, 1);
     141         374 :             ++idx;
     142             :         }
     143             :     }
     144           3 :     std::cout << "One-atom Hamiltonian, basis size without restrictions: " << this->basis->size()
     145           3 :               << std::endl;
     146             : 
     147           3 :     this->basis->removeUnnecessaryStates(is_necessary);
     148             : 
     149           3 :     hamiltonian_energy.compress(this->basis->dim(), this->basis->dim());
     150             : 
     151           3 :     std::cout << "One-atom Hamiltonian, basis size with restrictions: " << this->basis->size()
     152           3 :               << std::endl;
     153           6 :     std::cout << fmt::format(">>BAS{:7d}", this->basis->size()) << std::endl;
     154             : 
     155             :     // === Save single atom basis ===
     156           3 :     std::cout << "One-atom Hamiltonian, save single atom basis" << std::endl;
     157             : 
     158             :     // initialize uuid generator
     159             :     boost::uuids::random_generator generator;
     160             : 
     161             :     // generate uuid
     162           6 :     std::string uuid;
     163           3 :     boost::uuids::uuid u = generator();
     164           3 :     boost::algorithm::hex(u.begin(), u.end(), std::back_inserter(uuid));
     165             : 
     166             :     // save basis
     167           6 :     fs::path path_basis = fs::temp_directory_path();
     168           3 :     path_basis /= "basis_one_" + uuid + ".csv";
     169           3 :     this->basis->save(path_basis.string());
     170             : 
     171           6 :     std::cout << fmt::format(">>STA {:s}", path_basis.string()) << std::endl;
     172             : 
     173             :     ////////////////////////////////////////////////////////
     174             :     ////// Construct atom-field interaction ////////////////
     175             :     ////////////////////////////////////////////////////////
     176             : 
     177             :     // --- Obtain existence of fields ---
     178           1 :     Scalar min_E_0, min_E_p, min_E_m, min_B_0, min_B_p, min_B_m, max_E_0, max_E_p, max_E_m, max_B_0,
     179           1 :         max_B_p, max_B_m;
     180           3 :     changeToSpherical(min_E_x, min_E_y, min_E_z, min_E_p, min_E_m, min_E_0);
     181           3 :     changeToSpherical(max_E_x, max_E_y, max_E_z, max_E_p, max_E_m, max_E_0);
     182           3 :     changeToSpherical(min_B_x, min_B_y, min_B_z, min_B_p, min_B_m, min_B_0);
     183           3 :     changeToSpherical(max_B_x, max_B_y, max_B_z, max_B_p, max_B_m, max_B_0);
     184             : 
     185           3 :     bool exist_E_0 = (std::abs(min_E_0) != 0 || std::abs(max_E_0) != 0);
     186           3 :     bool exist_E_1 = (std::abs(min_E_p) != 0 || std::abs(max_E_p) != 0);
     187           3 :     bool exist_B_0 = (std::abs(min_B_0) != 0 || std::abs(max_B_0) != 0);
     188           3 :     bool exist_B_1 = (std::abs(min_B_p) != 0 || std::abs(max_B_p) != 0);
     189             : 
     190             :     // --- Precalculate matrix elements --- // TODO parallelization
     191           3 :     std::cout << "One-atom Hamiltonian, precalculate matrix elements" << std::endl;
     192             : 
     193           9 :     MatrixElements matrix_elements(basicconf, species, (path_cache / "cache_elements.db").string());
     194             : 
     195           3 :     if (exist_E_0) {
     196           1 :         matrix_elements.precalculateElectricMomentum(this->basis, 0);
     197             :     }
     198           3 :     if (exist_E_1) {
     199           1 :         matrix_elements.precalculateElectricMomentum(this->basis, 1);
     200             :     }
     201           3 :     if (exist_E_1) {
     202           1 :         matrix_elements.precalculateElectricMomentum(this->basis, -1);
     203             :     }
     204             : 
     205           3 :     if (exist_B_0) {
     206           1 :         matrix_elements.precalculateMagneticMomentum(this->basis, 0);
     207             :     }
     208           3 :     if (exist_B_1) {
     209           1 :         matrix_elements.precalculateMagneticMomentum(this->basis, 1);
     210             :     }
     211           3 :     if (exist_B_1) {
     212           1 :         matrix_elements.precalculateMagneticMomentum(this->basis, -1);
     213             :     }
     214             : 
     215           3 :     if (diamagnetism && (exist_B_0 || exist_B_1)) {
     216           1 :         matrix_elements.precalculateDiamagnetism(this->basis, 0, 0);
     217             :     }
     218           3 :     if (diamagnetism && (exist_B_0 || exist_B_1)) {
     219           1 :         matrix_elements.precalculateDiamagnetism(this->basis, 2, 0);
     220             :     }
     221           3 :     if (diamagnetism && exist_B_0 && exist_B_1) {
     222           1 :         matrix_elements.precalculateDiamagnetism(this->basis, 2, 1);
     223             :     }
     224           3 :     if (diamagnetism && exist_B_0 && exist_B_1) {
     225           1 :         matrix_elements.precalculateDiamagnetism(this->basis, 2, -1);
     226             :     }
     227           3 :     if (diamagnetism && exist_B_1) {
     228           1 :         matrix_elements.precalculateDiamagnetism(this->basis, 2, 2);
     229             :     }
     230           3 :     if (diamagnetism && exist_B_1) {
     231           1 :         matrix_elements.precalculateDiamagnetism(this->basis, 2, -2);
     232             :     }
     233             : 
     234             :     // --- Count entries of atom-field Hamiltonian ---
     235           3 :     std::cout << "One-atom Hamiltonian, count number of entries within the field Hamiltonian"
     236           3 :               << std::endl;
     237             : 
     238           3 :     size_basis = this->basis->size();
     239           3 :     size_t size_electricMomentum_0 = 0;
     240           3 :     size_t size_electricMomentum_p = 0;
     241           3 :     size_t size_electricMomentum_m = 0;
     242             : 
     243           3 :     size_t size_magneticMomentum_0 = 0;
     244           3 :     size_t size_magneticMomentum_p = 0;
     245           3 :     size_t size_magneticMomentum_m = 0;
     246             : 
     247           3 :     size_t size_diamagnetism_00 = 0;
     248           3 :     size_t size_diamagnetism_20 = 0;
     249           3 :     size_t size_diamagnetism_2p = 0;
     250           3 :     size_t size_diamagnetism_2m = 0;
     251           3 :     size_t size_diamagnetism_2pp = 0;
     252           3 :     size_t size_diamagnetism_2mm = 0;
     253             : 
     254         377 :     for (const auto &state_col : *this->basis) { // TODO parallelization
     255       73050 :         for (const auto &state_row : *this->basis) {
     256       72676 :             if (state_row.idx < state_col.idx) { // lower triangle only
     257       36151 :                 continue;
     258             :             }
     259             : 
     260       36525 :             if (exist_E_0 && selectionRulesMultipole(state_row, state_col, 1, 0)) {
     261         468 :                 size_electricMomentum_0++;
     262       36057 :             } else if (exist_E_1 && selectionRulesMultipole(state_row, state_col, 1, 1)) {
     263         432 :                 size_electricMomentum_p++;
     264       35625 :             } else if (exist_E_1 && selectionRulesMultipole(state_row, state_col, 1, -1)) {
     265         432 :                 size_electricMomentum_m++;
     266             :             }
     267             : 
     268       36525 :             if (exist_B_0 && selectionRulesMomentum(state_row, state_col, 0)) {
     269         480 :                 size_magneticMomentum_0++;
     270       36045 :             } else if (exist_B_1 && selectionRulesMomentum(state_row, state_col, 1)) {
     271         426 :                 size_magneticMomentum_p++;
     272       35619 :             } else if (exist_B_1 && selectionRulesMomentum(state_row, state_col, -1)) {
     273         303 :                 size_magneticMomentum_m++;
     274             :             }
     275             : 
     276       47850 :             if (diamagnetism && (exist_B_0 || exist_B_1) &&
     277       11325 :                 selectionRulesMultipole(state_row, state_col, 0, 0)) {
     278         300 :                 size_diamagnetism_00++;
     279       47250 :             } else if (diamagnetism && (exist_B_0 || exist_B_1) &&
     280       11025 :                        selectionRulesMultipole(state_row, state_col, 2, 0)) {
     281         450 :                 size_diamagnetism_20++;
     282       46350 :             } else if (diamagnetism && (exist_B_0 && exist_B_1) &&
     283       10575 :                        selectionRulesMultipole(state_row, state_col, 2, 1)) {
     284         672 :                 size_diamagnetism_2p++;
     285       45006 :             } else if (diamagnetism && (exist_B_0 && exist_B_1) &&
     286        9903 :                        selectionRulesMultipole(state_row, state_col, 2, -1)) {
     287         561 :                 size_diamagnetism_2m++;
     288       43884 :             } else if (diamagnetism && (exist_B_1) &&
     289        9342 :                        selectionRulesMultipole(state_row, state_col, 2, 2)) {
     290         579 :                 size_diamagnetism_2pp++;
     291       42726 :             } else if (diamagnetism && (exist_B_1) &&
     292        8763 :                        selectionRulesMultipole(state_row, state_col, 2, -2)) {
     293         483 :                 size_diamagnetism_2mm++;
     294             :             }
     295             :         }
     296             :     }
     297             : 
     298             :     // --- Construct atom-field Hamiltonian ---
     299           3 :     std::cout << "One-atom Hamiltonian, construct field Hamiltonian" << std::endl;
     300             : 
     301           6 :     Hamiltonianmatrix<Scalar> hamiltonian_electricMomentum_0(size_basis, size_electricMomentum_0);
     302           6 :     Hamiltonianmatrix<Scalar> hamiltonian_electricMomentum_p(size_basis, size_electricMomentum_p);
     303           6 :     Hamiltonianmatrix<Scalar> hamiltonian_electricMomentum_m(size_basis, size_electricMomentum_m);
     304             : 
     305           6 :     Hamiltonianmatrix<Scalar> hamiltonian_magneticMomentum_0(size_basis, size_magneticMomentum_0);
     306           6 :     Hamiltonianmatrix<Scalar> hamiltonian_magneticMomentum_p(size_basis, size_magneticMomentum_p);
     307           6 :     Hamiltonianmatrix<Scalar> hamiltonian_magneticMomentum_m(size_basis, size_magneticMomentum_m);
     308             : 
     309           6 :     Hamiltonianmatrix<Scalar> hamiltonian_diamagnetism_00(size_basis, size_diamagnetism_00);
     310           6 :     Hamiltonianmatrix<Scalar> hamiltonian_diamagnetism_20(size_basis, size_diamagnetism_20);
     311           6 :     Hamiltonianmatrix<Scalar> hamiltonian_diamagnetism_2p(size_basis, size_diamagnetism_2p);
     312           6 :     Hamiltonianmatrix<Scalar> hamiltonian_diamagnetism_2m(size_basis, size_diamagnetism_2m);
     313           6 :     Hamiltonianmatrix<Scalar> hamiltonian_diamagnetism_2pp(size_basis, size_diamagnetism_2pp);
     314           6 :     Hamiltonianmatrix<Scalar> hamiltonian_diamagnetism_2mm(size_basis, size_diamagnetism_2mm);
     315             : 
     316         377 :     for (const auto &state_col : *this->basis) { // TODO parallelization
     317       73050 :         for (const auto &state_row : *this->basis) {
     318       72676 :             if (state_row.idx < state_col.idx) {
     319       36151 :                 continue;
     320             :             }
     321             : 
     322       36525 :             if (state_row.idx == state_col.idx) {
     323         374 :                 hamiltonian_electricMomentum_0.addBasis(state_row.idx, state_col.idx, 1);
     324         374 :                 hamiltonian_electricMomentum_p.addBasis(state_row.idx, state_col.idx, 1);
     325         374 :                 hamiltonian_electricMomentum_m.addBasis(state_row.idx, state_col.idx, 1);
     326             : 
     327         374 :                 hamiltonian_magneticMomentum_0.addBasis(state_row.idx, state_col.idx, 1);
     328         374 :                 hamiltonian_magneticMomentum_p.addBasis(state_row.idx, state_col.idx, 1);
     329         374 :                 hamiltonian_magneticMomentum_m.addBasis(state_row.idx, state_col.idx, 1);
     330             : 
     331         374 :                 hamiltonian_diamagnetism_00.addBasis(state_row.idx, state_col.idx, 1);
     332         374 :                 hamiltonian_diamagnetism_20.addBasis(state_row.idx, state_col.idx, 1);
     333         374 :                 hamiltonian_diamagnetism_2p.addBasis(state_row.idx, state_col.idx, 1);
     334         374 :                 hamiltonian_diamagnetism_2m.addBasis(state_row.idx, state_col.idx, 1);
     335         374 :                 hamiltonian_diamagnetism_2pp.addBasis(state_row.idx, state_col.idx, 1);
     336         374 :                 hamiltonian_diamagnetism_2mm.addBasis(state_row.idx, state_col.idx, 1);
     337             :             }
     338             : 
     339       36525 :             if (exist_E_0 && selectionRulesMultipole(state_row, state_col, 1, 0)) {
     340         468 :                 double val = matrix_elements.getElectricMomentum(state_row, state_col);
     341         468 :                 if (std::abs(val) > tol) {
     342         468 :                     hamiltonian_electricMomentum_0.addEntries(state_row.idx, state_col.idx, val);
     343             :                 }
     344       36057 :             } else if (exist_E_1 && selectionRulesMultipole(state_row, state_col, 1, 1)) {
     345         432 :                 double val = matrix_elements.getElectricMomentum(state_row, state_col);
     346         432 :                 if (std::abs(val) > tol) {
     347         432 :                     hamiltonian_electricMomentum_p.addEntries(state_row.idx, state_col.idx, val);
     348             :                 }
     349       35625 :             } else if (exist_E_1 && selectionRulesMultipole(state_row, state_col, 1, -1)) {
     350         432 :                 double val = matrix_elements.getElectricMomentum(state_row, state_col);
     351         432 :                 if (std::abs(val) > tol) {
     352         432 :                     hamiltonian_electricMomentum_m.addEntries(state_row.idx, state_col.idx, val);
     353             :                 }
     354             :             }
     355             : 
     356       36525 :             if (exist_B_0 && selectionRulesMomentum(state_row, state_col, 0)) {
     357         480 :                 double val = matrix_elements.getMagneticMomentum(state_row, state_col);
     358         480 :                 if (std::abs(val) > tol) {
     359         480 :                     hamiltonian_magneticMomentum_0.addEntries(state_row.idx, state_col.idx, val);
     360             :                 }
     361       36045 :             } else if (exist_B_1 && selectionRulesMomentum(state_row, state_col, 1)) {
     362         426 :                 double val = matrix_elements.getMagneticMomentum(state_row, state_col);
     363         426 :                 if (std::abs(val) > tol) {
     364         426 :                     hamiltonian_magneticMomentum_p.addEntries(state_row.idx, state_col.idx, val);
     365             :                 }
     366       35619 :             } else if (exist_B_1 && selectionRulesMomentum(state_row, state_col, -1)) {
     367         303 :                 double val = matrix_elements.getMagneticMomentum(state_row, state_col);
     368         303 :                 if (std::abs(val) > tol) {
     369         303 :                     hamiltonian_magneticMomentum_m.addEntries(state_row.idx, state_col.idx, val);
     370             :                 }
     371             :             }
     372             : 
     373       47850 :             if (diamagnetism && (exist_B_0 || exist_B_1) &&
     374       11325 :                 selectionRulesMultipole(state_row, state_col, 0, 0)) {
     375         300 :                 double val = matrix_elements.getDiamagnetism(state_row, state_col, 0);
     376         300 :                 if (std::abs(val) > tol) {
     377         300 :                     hamiltonian_diamagnetism_00.addEntries(state_row.idx, state_col.idx, val);
     378             :                 }
     379       47250 :             } else if (diamagnetism && (exist_B_0 || exist_B_1) &&
     380       11025 :                        selectionRulesMultipole(state_row, state_col, 2, 0)) {
     381         450 :                 double val = matrix_elements.getDiamagnetism(state_row, state_col, 2);
     382         450 :                 if (std::abs(val) > tol) {
     383         450 :                     hamiltonian_diamagnetism_20.addEntries(state_row.idx, state_col.idx, val);
     384             :                 }
     385       46350 :             } else if (diamagnetism && (exist_B_0 && exist_B_1) &&
     386       10575 :                        selectionRulesMultipole(state_row, state_col, 2, 1)) {
     387         672 :                 double val = matrix_elements.getDiamagnetism(state_row, state_col, 2);
     388         672 :                 if (std::abs(val) > tol) {
     389         660 :                     hamiltonian_diamagnetism_2p.addEntries(state_row.idx, state_col.idx, val);
     390             :                 }
     391       45006 :             } else if (diamagnetism && (exist_B_0 && exist_B_1) &&
     392        9903 :                        selectionRulesMultipole(state_row, state_col, 2, -1)) {
     393         561 :                 double val = matrix_elements.getDiamagnetism(state_row, state_col, 2);
     394         561 :                 if (std::abs(val) > tol) {
     395         555 :                     hamiltonian_diamagnetism_2m.addEntries(state_row.idx, state_col.idx, val);
     396             :                 }
     397       43884 :             } else if (diamagnetism && (exist_B_1) &&
     398        9342 :                        selectionRulesMultipole(state_row, state_col, 2, 2)) {
     399         579 :                 double val = matrix_elements.getDiamagnetism(state_row, state_col, 2);
     400         579 :                 if (std::abs(val) > tol) {
     401         579 :                     hamiltonian_diamagnetism_2pp.addEntries(state_row.idx, state_col.idx, val);
     402             :                 }
     403       42726 :             } else if (diamagnetism && (exist_B_1) &&
     404        8763 :                        selectionRulesMultipole(state_row, state_col, 2, -2)) {
     405         483 :                 double val = matrix_elements.getDiamagnetism(state_row, state_col, 2);
     406         483 :                 if (std::abs(val) > tol) {
     407         483 :                     hamiltonian_diamagnetism_2mm.addEntries(state_row.idx, state_col.idx, val);
     408             :                 }
     409             :             }
     410             :         }
     411             :     }
     412             : 
     413           3 :     std::cout << "One-atom Hamiltonian, compress field Hamiltonian" << std::endl;
     414             : 
     415           3 :     hamiltonian_electricMomentum_0.compress(this->basis->dim(), this->basis->dim());
     416           3 :     hamiltonian_electricMomentum_p.compress(this->basis->dim(), this->basis->dim());
     417           3 :     hamiltonian_electricMomentum_m.compress(this->basis->dim(), this->basis->dim());
     418             : 
     419           3 :     hamiltonian_magneticMomentum_0.compress(this->basis->dim(), this->basis->dim());
     420           3 :     hamiltonian_magneticMomentum_p.compress(this->basis->dim(), this->basis->dim());
     421           3 :     hamiltonian_magneticMomentum_m.compress(this->basis->dim(), this->basis->dim());
     422             : 
     423           3 :     hamiltonian_diamagnetism_00.compress(this->basis->dim(), this->basis->dim());
     424           3 :     hamiltonian_diamagnetism_20.compress(this->basis->dim(), this->basis->dim());
     425           3 :     hamiltonian_diamagnetism_2p.compress(this->basis->dim(), this->basis->dim());
     426           3 :     hamiltonian_diamagnetism_2m.compress(this->basis->dim(), this->basis->dim());
     427           3 :     hamiltonian_diamagnetism_2pp.compress(this->basis->dim(), this->basis->dim());
     428           3 :     hamiltonian_diamagnetism_2mm.compress(this->basis->dim(), this->basis->dim());
     429             : 
     430             :     ////////////////////////////////////////////////////////
     431             :     ////// Prepare processing of Hamiltonians //////////////
     432             :     ////////////////////////////////////////////////////////
     433             : 
     434             :     // TODO Put the logic in its own class
     435             : 
     436           3 :     std::cout << "One-atom Hamiltonian, processe Hamiltonians" << std::endl;
     437             : 
     438             :     // === Open database ===
     439           6 :     fs::path path_db;
     440             : 
     441             :     if (utils::is_complex<Scalar>::value) {
     442           1 :         path_db = path_cache / "cache_matrix_complex.db";
     443             :     } else {
     444           2 :         path_db = path_cache / "cache_matrix_real.db";
     445             :     }
     446           6 :     sqlite::handle db(path_db.string());
     447           6 :     sqlite::statement stmt(db);
     448             : 
     449             :     // === Initialize variables ===
     450           3 :     bool flag_perhapsmissingtable = true;
     451             : 
     452           3 :     this->matrix_path.resize(nSteps);
     453           3 :     this->matrix_diag.resize(nSteps); // TODO maybe remove
     454           3 :     this->params.resize(nSteps);      // TODO maybe remove
     455             : 
     456             :     ////////////////////////////////////////////////////////
     457             :     ////// Loop through steps //////////////////////////////
     458             :     ////////////////////////////////////////////////////////
     459             : 
     460           6 :     std::cout << fmt::format(">>TOT{:7d}", nSteps) << std::endl;
     461             : 
     462           3 :     auto nSteps_i = static_cast<int>(nSteps);
     463             : 
     464           3 : #pragma omp parallel for schedule(static, 1)
     465             : 
     466             :     // Loop through steps
     467             :     for (int step = 0; step < nSteps_i; ++step) {
     468             : 
     469             :         // === Get parameters for the current position inside the loop ===
     470             : 
     471             :         // Get fields
     472             :         double normalized_position = (nSteps > 1) ? step / (nSteps - 1.) : 0;
     473             : 
     474             :         double Ex = min_E_x + normalized_position * (max_E_x - min_E_x);
     475             :         double Ey = min_E_y + normalized_position * (max_E_y - min_E_y);
     476             :         double Ez = min_E_z + normalized_position * (max_E_z - min_E_z);
     477             :         double Bx = min_B_x + normalized_position * (max_B_x - min_B_x);
     478             :         double By = min_B_y + normalized_position * (max_B_y - min_B_y);
     479             :         double Bz = min_B_z + normalized_position * (max_B_z - min_B_z);
     480             : 
     481             :         Scalar E_0 = min_E_0 + normalized_position * (max_E_0 - min_E_0);
     482             :         Scalar E_p = min_E_p + normalized_position * (max_E_p - min_E_p);
     483             :         Scalar E_m = min_E_m + normalized_position * (max_E_m - min_E_m);
     484             :         Scalar B_0 = min_B_0 + normalized_position * (max_B_0 - min_B_0);
     485             :         Scalar B_p = min_B_p + normalized_position * (max_B_p - min_B_p);
     486             :         Scalar B_m = min_B_m + normalized_position * (max_B_m - min_B_m);
     487             : 
     488             :         // Get configuration and save fields
     489             :         Configuration conf = basicconf;
     490             :         conf["Ex"] << Ex;
     491             :         conf["Ey"] << Ey;
     492             :         conf["Ez"] << Ez;
     493             :         conf["Bx"] << Bx;
     494             :         conf["By"] << By;
     495             :         conf["Bz"] << Bz;
     496             : 
     497             :         // === Create table if necessary ===
     498             :         std::stringstream query;
     499             :         std::string spacer;
     500             : 
     501             :         if (flag_perhapsmissingtable) {
     502             :             query << "CREATE TABLE IF NOT EXISTS cache_one (uuid text NOT NULL PRIMARY KEY, "
     503             :                      "created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, "
     504             :                      "accessed TIMESTAMP DEFAULT CURRENT_TIMESTAMP";
     505             :             for (auto p : conf) {
     506             :                 query << ", " << p.first << " text";
     507             :             }
     508             :             query << ", UNIQUE (";
     509             :             for (auto p : conf) {
     510             :                 query << spacer << p.first;
     511             :                 spacer = ", ";
     512             :             }
     513             :             query << "));";
     514             : 
     515             :             flag_perhapsmissingtable = false;
     516             : 
     517             : #pragma omp critical(database)
     518             :             stmt.exec(query.str());
     519             :         }
     520             : 
     521             :         // === Get uuid as filename === // TODO put code in its own method
     522             :         std::string uuid;
     523             :         spacer = "";
     524             :         query.str(std::string());
     525             :         query << "SELECT uuid FROM cache_one WHERE ";
     526             :         for (auto p : conf) {
     527             :             query << spacer << p.first << "='" << p.second.str() << "'";
     528             :             spacer = " AND ";
     529             :         }
     530             :         query << ";";
     531             : 
     532             : #pragma omp critical(database)
     533             :         {
     534             :             sqlite::statement stmt(db, query.str());
     535             :             stmt.prepare();
     536             :             if (stmt.step()) {
     537             :                 uuid = stmt.get<std::string>(0);
     538             :             }
     539             :         }
     540             : 
     541             :         if (!uuid.empty()) {
     542             :             query.str(std::string());
     543             :             query << "UPDATE cache_one SET accessed = CURRENT_TIMESTAMP WHERE uuid = '" << uuid
     544             :                   << "';";
     545             : #pragma omp critical(database)
     546             :             stmt.exec(query.str()); // TODO check whether this slows down the program
     547             : 
     548             :         } else {
     549             :             boost::uuids::uuid u = generator();
     550             :             boost::algorithm::hex(u.begin(), u.end(), std::back_inserter(uuid));
     551             : 
     552             :             query.str(std::string());
     553             :             query << "INSERT INTO cache_one (uuid";
     554             :             for (auto p : conf) {
     555             :                 query << ", " << p.first;
     556             :             }
     557             :             query << ") values ( '" << uuid << "'";
     558             :             for (auto p : conf) {
     559             :                 query << ", "
     560             :                       << "'" << p.second.str() << "'";
     561             :             }
     562             :             query << ");";
     563             : #pragma omp critical(database)
     564             :             stmt.exec(query.str());
     565             :         }
     566             : 
     567             :         // === Check existence of files === // TODO put code in its own method
     568             : 
     569             :         // Check whether .mat and .json file exists and compare settings in program with settings in
     570             :         // .json file
     571             :         fs::path path, path_mat, path_json;
     572             : 
     573             :         path = path_cache_mat / ("one_" + uuid);
     574             :         path_mat = path;
     575             :         path_mat.replace_extension(".mat");
     576             :         path_json = path;
     577             :         path_json.replace_extension(".json");
     578             : 
     579             :         bool is_existing = false;
     580             :         if (fs::exists(path_mat)) {
     581             :             if (fs::exists(path_json)) {
     582             :                 Configuration params_loaded;
     583             :                 params_loaded.load_from_json(path_json.string());
     584             :                 if (conf == params_loaded) {
     585             :                     is_existing = true;
     586             :                 }
     587             :             }
     588             :         }
     589             : 
     590             :         // Create .json file if "is_existing" is false
     591             :         if (!is_existing) {
     592             :             conf.save_to_json(path_json.string());
     593             :         }
     594             : 
     595             :         // === Build and diagonalize total matrix if not existent ===
     596             :         Hamiltonianmatrix<Scalar> totalmatrix;
     597             : 
     598             :         // calculate Hamiltonian if "is_existing" is false
     599             :         std::shared_ptr<Hamiltonianmatrix<Scalar>> mat;
     600             :         if (!is_existing || !totalmatrix.load(path_mat.string())) {
     601             : 
     602             :             // --- Build matrix ---
     603             :             totalmatrix = hamiltonian_energy - hamiltonian_electricMomentum_0 * E_0 +
     604             :                 hamiltonian_electricMomentum_p * E_m + hamiltonian_electricMomentum_m * E_p +
     605             :                 hamiltonian_magneticMomentum_0 * B_0 - hamiltonian_magneticMomentum_p * B_m -
     606             :                 hamiltonian_magneticMomentum_m * B_p +
     607             :                 hamiltonian_diamagnetism_00 * (B_0 * B_0 - 2. * B_p * B_m) -
     608             :                 hamiltonian_diamagnetism_20 * (B_0 * B_0 + B_p * B_m) +
     609             :                 std::sqrt(3) * hamiltonian_diamagnetism_2p * B_0 * B_m +
     610             :                 std::sqrt(3) * hamiltonian_diamagnetism_2m * B_0 * B_p -
     611             :                 std::sqrt(1.5) * hamiltonian_diamagnetism_2pp * B_m * B_m -
     612             :                 std::sqrt(1.5) * hamiltonian_diamagnetism_2mm * B_p * B_p;
     613             : 
     614             :             // Stdout: Hamiltonian assembled
     615             : #pragma omp critical(textoutput)
     616             :             {
     617             :                 std::cout << fmt::format(">>DIM{:7d}", totalmatrix.num_basisvectors()) << std::endl;
     618             :                 std::cout << "One-atom Hamiltonian, " << step + 1 << ". Hamiltonian assembled"
     619             :                           << std::endl;
     620             :             }
     621             : 
     622             :             // --- Diagonalize matrix and save diagonalized matrix ---
     623             :             totalmatrix.diagonalize();
     624             :             totalmatrix.save(path_mat.string());
     625             : 
     626             :             // Stdout: Hamiltonian diagonalized
     627             : #pragma omp critical(textoutput)
     628             :             {
     629             :                 std::cout << fmt::format(">>OUT{:7d}{:7d}{:7d}{:7d} {:s}", (step + 1), step, 1, 0,
     630             :                                          path.string())
     631             :                           << std::endl;
     632             :                 std::cout << "One-atom Hamiltonian, " << step + 1 << ". Hamiltonian diagonalized"
     633             :                           << std::endl;
     634             :             }
     635             :         } else {
     636             :             // Stdout: Hamiltonian loaded
     637             : #pragma omp critical(textoutput)
     638             :             {
     639             :                 std::cout << fmt::format(">>DIM{:7d}", totalmatrix.num_basisvectors()) << std::endl;
     640             :                 std::cout << fmt::format(">>OUT{:7d}{:7d}{:7d}{:7d} {:s}", (step + 1), step, 1, 0,
     641             :                                          path.string())
     642             :                           << std::endl;
     643             :                 std::cout << "One-atom Hamiltonian, " << step + 1 << ". Hamiltonian loaded"
     644             :                           << std::endl;
     645             :             }
     646             :         }
     647             : 
     648             :         // === Store path to configuration and diagonalized matrix ===
     649             :         this->matrix_path[step] = path.string();
     650             :         this->matrix_diag[step] =
     651             :             std::make_shared<Hamiltonianmatrix<Scalar>>(totalmatrix); // TODO maybe remove
     652             :         this->params[step] = std::make_shared<Configuration>(conf);   // TODO maybe remove
     653             :     }
     654             : 
     655           3 :     std::cout << "One-atom Hamiltonian, all Hamiltonians processed" << std::endl;
     656           3 : }
     657             : 
     658             : template class HamiltonianOne<std::complex<double>>;
     659             : template class HamiltonianOne<double>;

Generated by: LCOV version 1.14