LCOV - code coverage report
Current view: top level - pairinteraction - Wavefunction.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 67 69 97.1 %
Date: 2024-04-29 00:41:50 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 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 "Wavefunction.hpp"
      21             : #include "Constants.hpp"
      22             : #include "QuantumDefect.hpp"
      23             : 
      24             : #include "EigenCompat.hpp"
      25             : #include <Eigen/Core>
      26             : 
      27             : #include <cctype>
      28             : #include <cmath>
      29             : #ifdef WITH_GSL
      30             : #include <gsl/gsl_sf_hyperg.h>
      31             : #endif
      32             : #include <string>
      33             : #include <vector>
      34             : 
      35             : // --- Numerov's method ---
      36             : 
      37             : namespace model_potential {
      38             : 
      39   174374866 : double V(QuantumDefect const &qd, double x) {
      40             :     double Z_l =
      41   174374866 :         1 + (qd.Z - 1) * std::exp(-qd.a1 * x) - x * (qd.a3 + qd.a4 * x) * std::exp(-qd.a2 * x);
      42   174374866 :     double V_c = -Z_l / x;
      43   174374866 :     double V_p = -qd.ac / (2. * x * x * x * x) * (1 - std::exp(-std::pow(x / qd.rc, 6)));
      44   174374866 :     double V_so = 0.0;
      45   174374866 :     if (qd.l < 4) {
      46   148245211 :         double s = 0.5;
      47   148245211 :         if (std::isdigit(qd.species.back()) != 0) {
      48           0 :             s = ((qd.species.back() - '0') - 1) / 2.; // TODO think of a better solution
      49             :         }
      50   148245211 :         double alpha = 7.2973525664e-3; // ~1/137 fine-structure constant CODATA 2014
      51   148245211 :         V_so =
      52   148245211 :             alpha * alpha / (4 * x * x * x) * (qd.j * (qd.j + 1) - qd.l * (qd.l + 1) - s * (s + 1));
      53             :     }
      54   174374866 :     return V_c + V_p + V_so;
      55             : }
      56             : 
      57   174374864 : double g(QuantumDefect const &qd, double x) {
      58   174374864 :     return (2. * qd.l + .5) * (2. * qd.l + 1.5) / x + 8 * x * (V(qd, x) - qd.energy / au2GHz);
      59             : }
      60             : 
      61             : } // namespace model_potential
      62             : 
      63        6136 : Numerov::Numerov(QuantumDefect const &qd) : qd(qd) {
      64             :     // augmented classical turning point
      65        6136 :     double xmin = qd.n * qd.n - qd.n * std::sqrt(qd.n * qd.n - (qd.l - 1) * (qd.l - 1));
      66        6136 :     if (xmin < 2.08) {
      67        4900 :         xmin = std::floor(std::sqrt(2.08));
      68             :     } else {
      69        1236 :         xmin = std::floor(std::sqrt(xmin));
      70             :     }
      71             : 
      72        6136 :     double const xmax = std::sqrt(2 * qd.n * (qd.n + 15));
      73        6136 :     double const nsteps = std::ceil((xmax - xmin) / dx);
      74             : 
      75        6136 :     xy = Eigen::MatrixX<double>::Zero(nsteps, 2);
      76             : 
      77    58143362 :     for (int i = 0; i < nsteps; ++i) {
      78    58137226 :         xy(i, 0) = (xmin + i * dx);
      79             :     }
      80        6136 : }
      81             : 
      82        6136 : Eigen::MatrixX<double> Numerov::integrate() {
      83             :     using model_potential::g;
      84             : 
      85        6136 :     int const nsteps = xy.rows();
      86             : 
      87             :     // Set the initial condition
      88        6136 :     if ((qd.n - qd.l) % 2 == 0) {
      89        2938 :         xy(nsteps - 2, 1) = -1e-10;
      90             :     } else {
      91        3198 :         xy(nsteps - 2, 1) = 1e-10;
      92             :     }
      93             : 
      94             :     // Perform the integration using Numerov's scheme
      95    58131090 :     for (int i = nsteps - 3; i >= 0; --i) {
      96    58124954 :         double A = (2. + 5. / 6. * dx * dx * g(qd, xy(i + 1, 0) * xy(i + 1, 0))) * xy(i + 1, 1);
      97    58124954 :         double B = (1. - 1. / 12. * dx * dx * g(qd, xy(i + 2, 0) * xy(i + 2, 0))) * xy(i + 2, 1);
      98    58124954 :         double C = 1. - 1. / 12. * dx * dx * g(qd, xy(i, 0) * xy(i, 0));
      99    58124954 :         xy(i, 1) = (A - B) / C;
     100             :     }
     101             : 
     102             :     // Normalization
     103        6136 :     double norm = 0;
     104    58143362 :     for (int i = 0; i < nsteps; ++i) {
     105    58137226 :         norm += xy(i, 1) * xy(i, 1) * xy(i, 0) * xy(i, 0) * dx;
     106             :     }
     107        6136 :     norm = std::sqrt(2 * norm);
     108             : 
     109        6136 :     if (norm > 0.0) {
     110    58143362 :         for (int i = 0; i < nsteps; ++i) {
     111    58137226 :             xy(i, 1) /= norm;
     112             :         }
     113             :     }
     114             : 
     115        6136 :     return xy;
     116             : }
     117             : 
     118             : // --- Whittaker method ---
     119             : 
     120             : namespace whittaker_functions {
     121             : 
     122      253288 : double HypergeometricU(double a, double b, double z) {
     123             : #ifdef WITH_GSL
     124      253288 :     if (z == 0) {
     125           0 :         return NAN;
     126             :     }
     127      253288 :     return gsl_sf_hyperg_U(a, b, z);
     128             : #else
     129             :     static_cast<void>(a);
     130             :     static_cast<void>(b);
     131             :     static_cast<void>(z);
     132             :     throw std::runtime_error("Whittaker functions require the GSL library!");
     133             : #endif
     134             : }
     135             : 
     136      253288 : double WhittakerW(double k, double m, double z) {
     137      253288 :     return std::exp(-.5 * z) * std::pow(z, m + .5) * HypergeometricU(m - k + .5, 1 + 2 * m, z);
     138             : }
     139             : 
     140      253288 : double RadialWFWhittaker(double r, double nu, int l) {
     141      253288 :     return 1 / std::sqrt(nu * nu * std::tgamma(nu + l + 1) * std::tgamma(nu - l)) *
     142      253288 :         WhittakerW(nu, l + .5, 2 * r / nu);
     143             : }
     144             : 
     145             : } // namespace whittaker_functions
     146             : 
     147          30 : Whittaker::Whittaker(QuantumDefect const &qd) : qd(qd) {
     148          30 :     double const xmin = 1;
     149          30 :     double const xmax = std::sqrt(2 * qd.n * (qd.n + 15));
     150          30 :     double const nsteps = std::ceil((xmax - xmin) / dx);
     151             : 
     152          30 :     xy.resize(nsteps, 2);
     153             : 
     154      253318 :     for (int i = 0; i < nsteps; ++i) {
     155      253288 :         xy(i, 0) = (xmin + i * dx);
     156             :     }
     157          30 : }
     158             : 
     159          30 : Eigen::MatrixX<double> Whittaker::integrate() {
     160             :     using whittaker_functions::RadialWFWhittaker;
     161             : 
     162             :     // Set the sign
     163             :     int sign;
     164          30 :     if ((qd.n - qd.l) % 2 == 0) {
     165          25 :         sign = -1;
     166             :     } else {
     167           5 :         sign = 1;
     168             :     }
     169             : 
     170          30 :     int const nsteps = xy.rows();
     171             : 
     172      253318 :     for (int i = 0; i < nsteps; ++i) {
     173      253288 :         xy(i, 1) = sign * RadialWFWhittaker(xy(i, 0) * xy(i, 0), qd.nstar, qd.l);
     174             :     }
     175             : 
     176          30 :     return xy;
     177             : }

Generated by: LCOV version 1.14