LCOV - code coverage report
Current view: top level - src/grpp - grpp_spin_orbit_integrals.c (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 0.0 % 145 0
Test Date: 2025-12-04 06:27:48 Functions: 0.0 % 2 0

            Line data    Source code
       1              : /*----------------------------------------------------------------------------*/
       2              : /*  CP2K: A general program to perform molecular dynamics simulations         */
       3              : /*  Copyright 2000-2025 CP2K developers group <https://cp2k.org>              */
       4              : /*                                                                            */
       5              : /*  SPDX-License-Identifier: MIT                                              */
       6              : /*----------------------------------------------------------------------------*/
       7              : 
       8              : /*
       9              :  *  libgrpp - a library for the evaluation of integrals over
      10              :  *            generalized relativistic pseudopotentials.
      11              :  *
      12              :  *  Copyright (C) 2021-2023 Alexander Oleynichenko
      13              :  */
      14              : 
      15              : #include <assert.h>
      16              : #include <math.h>
      17              : #include <stdlib.h>
      18              : #include <string.h>
      19              : 
      20              : #ifndef M_PI
      21              : #define M_PI 3.14159265358979323846
      22              : #endif
      23              : 
      24              : #include "grpp_angular_integrals.h"
      25              : #include "grpp_binomial.h"
      26              : #include "grpp_lmatrix.h"
      27              : #include "grpp_radial_type2_integral.h"
      28              : #include "grpp_spherical_harmonics.h"
      29              : #include "grpp_utils.h"
      30              : #include "libgrpp.h"
      31              : 
      32              : #define LMAX (2 * LIBGRPP_MAX_BASIS_L + LIBGRPP_MAX_RPP_L)
      33              : 
      34              : static void type3_angular_sum(int L, double *Lx_matrix, double *Ly_matrix,
      35              :                               double *Lz_matrix, int lambda_1, int a, int b,
      36              :                               int c, double *rsh_values_kA, int lambda_2, int d,
      37              :                               int e, int f, double *rsh_values_kB,
      38              :                               double *sum_angular_x, double *sum_angular_y,
      39              :                               double *sum_angular_z);
      40              : 
      41              : /**
      42              :  * Evaluation of spin-orbit ("type 3") RPP integrals.
      43              :  *
      44              :  * The theoretical outline is given in the paper:
      45              :  * R. M. Pitzer, N. W. Winter. Spin-orbit (core) and core potential integrals.
      46              :  * Int. J. Quantum Chem. 40(6), 773 (1991). doi: 10.1002/qua.560400606
      47              :  * However, the formula on page 776 of Pitzer & Winter is not reproduced in the
      48              :  * code exactly.
      49              :  */
      50            0 : void libgrpp_spin_orbit_integrals(libgrpp_shell_t *shell_A,
      51              :                                   libgrpp_shell_t *shell_B, double *rpp_origin,
      52              :                                   libgrpp_potential_t *potential,
      53              :                                   double *so_x_matrix, double *so_y_matrix,
      54              :                                   double *so_z_matrix) {
      55            0 :   assert(libgrpp_is_initialized());
      56              : 
      57            0 :   int size_A = libgrpp_get_shell_size(shell_A);
      58            0 :   int size_B = libgrpp_get_shell_size(shell_B);
      59              : 
      60            0 :   memset(so_x_matrix, 0, size_A * size_B * sizeof(double));
      61            0 :   memset(so_y_matrix, 0, size_A * size_B * sizeof(double));
      62            0 :   memset(so_z_matrix, 0, size_A * size_B * sizeof(double));
      63              : 
      64            0 :   int L = potential->L;
      65            0 :   int L_A =
      66            0 :       shell_A->cart_list[0] + shell_A->cart_list[1] + shell_A->cart_list[2];
      67            0 :   int L_B =
      68            0 :       shell_B->cart_list[0] + shell_B->cart_list[1] + shell_B->cart_list[2];
      69              : 
      70            0 :   double *A = shell_A->origin;
      71            0 :   double *B = shell_B->origin;
      72            0 :   double *C = rpp_origin;
      73              : 
      74            0 :   double CA_x = C[0] - A[0];
      75            0 :   double CA_y = C[1] - A[1];
      76            0 :   double CA_z = C[2] - A[2];
      77            0 :   double CB_x = C[0] - B[0];
      78            0 :   double CB_y = C[1] - B[1];
      79            0 :   double CB_z = C[2] - B[2];
      80            0 :   double CA_2 = CA_x * CA_x + CA_y * CA_y + CA_z * CA_z;
      81            0 :   double CB_2 = CB_x * CB_x + CB_y * CB_y + CB_z * CB_z;
      82              : 
      83            0 :   double alpha_A = shell_A->alpha[0];
      84            0 :   double alpha_B = shell_B->alpha[0];
      85            0 :   double kA_x = -2.0 * (alpha_A * CA_x);
      86            0 :   double kA_y = -2.0 * (alpha_A * CA_y);
      87            0 :   double kA_z = -2.0 * (alpha_A * CA_z);
      88            0 :   double kB_x = -2.0 * (alpha_B * CB_x);
      89            0 :   double kB_y = -2.0 * (alpha_B * CB_y);
      90            0 :   double kB_z = -2.0 * (alpha_B * CB_z);
      91            0 :   double kA_vec[3];
      92            0 :   kA_vec[0] = kA_x;
      93            0 :   kA_vec[1] = kA_y;
      94            0 :   kA_vec[2] = kA_z;
      95            0 :   double kB_vec[3];
      96            0 :   kB_vec[0] = kB_x;
      97            0 :   kB_vec[1] = kB_y;
      98            0 :   kB_vec[2] = kB_z;
      99              : 
     100            0 :   int lambda1_max = L + L_A;
     101            0 :   int lambda2_max = L + L_B;
     102            0 :   int N_max = L_A + L_B; // + n_RPP;
     103              : 
     104              :   /*
     105              :    * pre-compute matrices of the Lx, Ly, Lz operators
     106              :    */
     107            0 :   double *Lx_matrix = calloc((2 * L + 1) * (2 * L + 1), sizeof(double));
     108            0 :   double *Ly_matrix = calloc((2 * L + 1) * (2 * L + 1), sizeof(double));
     109            0 :   double *Lz_matrix = calloc((2 * L + 1) * (2 * L + 1), sizeof(double));
     110            0 :   libgrpp_construct_angular_momentum_matrices_rsh(L, Lx_matrix, Ly_matrix,
     111              :                                                   Lz_matrix);
     112              : 
     113              :   /*
     114              :    * for further evaluation of angular integrals
     115              :    */
     116            0 :   int lmax = int_max3(lambda1_max, lambda2_max, L);
     117              :   // create_real_spherical_harmonic_coeffs_tables(lmax);
     118              : 
     119              :   /*
     120              :    * pre-calculate values of real spherical harmonics for different L
     121              :    */
     122            0 :   double rsh_values_kA[LMAX][2 * LMAX + 1];
     123            0 :   double rsh_values_kB[LMAX][2 * LMAX + 1];
     124              : 
     125            0 :   for (int lambda = 0; lambda <= lmax; lambda++) {
     126            0 :     libgrpp_evaluate_real_spherical_harmonics_array(lambda, kA_vec,
     127            0 :                                                     rsh_values_kA[lambda]);
     128            0 :     libgrpp_evaluate_real_spherical_harmonics_array(lambda, kB_vec,
     129            0 :                                                     rsh_values_kB[lambda]);
     130              :   }
     131              : 
     132              :   /*
     133              :    * pre-compute radial integrals
     134              :    */
     135            0 :   radial_type2_table_t *radial_table = libgrpp_tabulate_radial_type2_integrals(
     136              :       lambda1_max, lambda2_max, N_max, CA_2, CB_2, potential, shell_A, shell_B);
     137              : 
     138              :   /*
     139              :    * loop over shell pairs
     140              :    */
     141            0 :   for (int icart = 0; icart < size_A; icart++) {
     142            0 :     for (int jcart = 0; jcart < size_B; jcart++) {
     143              : 
     144            0 :       double SO_x = 0.0;
     145            0 :       double SO_y = 0.0;
     146            0 :       double SO_z = 0.0;
     147              : 
     148            0 :       int n_A = shell_A->cart_list[3 * icart + 0];
     149            0 :       int l_A = shell_A->cart_list[3 * icart + 1];
     150            0 :       int m_A = shell_A->cart_list[3 * icart + 2];
     151            0 :       int n_B = shell_B->cart_list[3 * jcart + 0];
     152            0 :       int l_B = shell_B->cart_list[3 * jcart + 1];
     153            0 :       int m_B = shell_B->cart_list[3 * jcart + 2];
     154              : 
     155            0 :       for (int a = 0; a <= n_A; a++) {
     156              : 
     157            0 :         double C_nA_a = libgrpp_binomial(n_A, a);
     158            0 :         double pow_CA_x = pow(CA_x, n_A - a);
     159              : 
     160            0 :         for (int b = 0; b <= l_A; b++) {
     161              : 
     162            0 :           double C_lA_b = libgrpp_binomial(l_A, b);
     163            0 :           double pow_CA_y = pow(CA_y, l_A - b);
     164              : 
     165            0 :           for (int c = 0; c <= m_A; c++) {
     166              : 
     167            0 :             double C_mA_c = libgrpp_binomial(m_A, c);
     168            0 :             double pow_CA_z = pow(CA_z, m_A - c);
     169              : 
     170            0 :             for (int d = 0; d <= n_B; d++) {
     171              : 
     172            0 :               double C_nB_d = libgrpp_binomial(n_B, d);
     173            0 :               double pow_CB_x = pow(CB_x, n_B - d);
     174              : 
     175            0 :               for (int e = 0; e <= l_B; e++) {
     176              : 
     177            0 :                 double C_lB_e = libgrpp_binomial(l_B, e);
     178            0 :                 double pow_CB_y = pow(CB_y, l_B - e);
     179              : 
     180            0 :                 for (int f = 0; f <= m_B; f++) {
     181              : 
     182            0 :                   double C_mB_f = libgrpp_binomial(m_B, f);
     183            0 :                   double pow_CB_z = pow(CB_z, m_B - f);
     184              : 
     185            0 :                   int N = a + b + c + d + e + f;
     186            0 :                   double factor = C_nA_a * C_lA_b * C_mA_c * C_nB_d * C_lB_e *
     187            0 :                                   C_mB_f * pow_CA_x * pow_CA_y * pow_CA_z *
     188            0 :                                   pow_CB_x * pow_CB_y * pow_CB_z;
     189              : 
     190            0 :                   if (fabs(factor) < LIBGRPP_ZERO_THRESH) {
     191            0 :                     continue;
     192              :                   }
     193              : 
     194              :                   /*
     195              :                    * contraction of radial integrals with angular integrals
     196              :                    */
     197              : 
     198            0 :                   double sum_omega_Q_x = 0.0;
     199            0 :                   double sum_omega_Q_y = 0.0;
     200            0 :                   double sum_omega_Q_z = 0.0;
     201              : 
     202            0 :                   int lambda1_lower = int_max2(L - a - b - c, 0);
     203            0 :                   int lambda2_lower = int_max2(L - d - e - f, 0);
     204            0 :                   int lambda1_upper = L + a + b + c;
     205            0 :                   int lambda2_upper = L + d + e + f;
     206              : 
     207            0 :                   for (int lambda_1 = lambda1_lower; lambda_1 <= lambda1_upper;
     208            0 :                        lambda_1++) {
     209            0 :                     if ((L + a + b + c - lambda_1) % 2 != 0) {
     210            0 :                       continue;
     211              :                     }
     212              : 
     213              :                     for (int lambda_2 = lambda2_lower;
     214            0 :                          lambda_2 <= lambda2_upper; lambda_2++) {
     215            0 :                       if ((L + d + e + f - lambda_2) % 2 != 0) {
     216            0 :                         continue;
     217              :                       }
     218              : 
     219            0 :                       double QN = libgrpp_get_radial_type2_integral(
     220              :                           radial_table, lambda_1, lambda_2, N);
     221            0 :                       if (fabs(QN) < LIBGRPP_ZERO_THRESH) {
     222            0 :                         continue;
     223              :                       }
     224              : 
     225            0 :                       double sum_angular_x, sum_angular_y, sum_angular_z;
     226            0 :                       type3_angular_sum(
     227              :                           L, Lx_matrix, Ly_matrix, Lz_matrix, lambda_1, a, b, c,
     228            0 :                           rsh_values_kA[lambda_1], lambda_2, d, e, f,
     229            0 :                           rsh_values_kB[lambda_2], &sum_angular_x,
     230              :                           &sum_angular_y, &sum_angular_z);
     231              : 
     232            0 :                       sum_omega_Q_x += QN * sum_angular_x;
     233            0 :                       sum_omega_Q_y += QN * sum_angular_y;
     234            0 :                       sum_omega_Q_z += QN * sum_angular_z;
     235              :                     }
     236              :                   }
     237              : 
     238            0 :                   SO_x += factor * sum_omega_Q_x;
     239            0 :                   SO_y += factor * sum_omega_Q_y;
     240            0 :                   SO_z += factor * sum_omega_Q_z;
     241              :                 }
     242              :               }
     243              :             }
     244              :           }
     245              :         }
     246              :       }
     247              : 
     248            0 :       so_x_matrix[icart * size_B + jcart] = SO_x * (16.0 * M_PI * M_PI);
     249            0 :       so_y_matrix[icart * size_B + jcart] = SO_y * (16.0 * M_PI * M_PI);
     250            0 :       so_z_matrix[icart * size_B + jcart] = SO_z * (16.0 * M_PI * M_PI);
     251              :     }
     252              :   }
     253              : 
     254            0 :   libgrpp_delete_radial_type2_integrals(radial_table);
     255            0 :   free(Lx_matrix);
     256            0 :   free(Ly_matrix);
     257            0 :   free(Lz_matrix);
     258            0 : }
     259              : 
     260              : /*
     261              :  * Double sum of products of type 2 angular integrals
     262              :  * (Pitzer, Winter, 1991, formula on the top of the page 776)
     263              :  */
     264            0 : static void type3_angular_sum(int L, double *Lx_matrix, double *Ly_matrix,
     265              :                               double *Lz_matrix, int lambda_1, int a, int b,
     266              :                               int c, double *rsh_values_kA, int lambda_2, int d,
     267              :                               int e, int f, double *rsh_values_kB,
     268              :                               double *sum_angular_x, double *sum_angular_y,
     269              :                               double *sum_angular_z) {
     270            0 :   *sum_angular_x = 0.0;
     271            0 :   *sum_angular_y = 0.0;
     272            0 :   *sum_angular_z = 0.0;
     273              : 
     274              :   /*
     275              :    * contract tensors with angular integrals
     276              :    */
     277            0 :   for (int m1 = -L; m1 <= L; m1++) {
     278            0 :     for (int m2 = -L; m2 <= L; m2++) {
     279              : 
     280            0 :       double lx = Lx_matrix[(2 * L + 1) * (m1 + L) + (m2 + L)];
     281            0 :       double ly = Ly_matrix[(2 * L + 1) * (m1 + L) + (m2 + L)];
     282            0 :       double lz = Lz_matrix[(2 * L + 1) * (m1 + L) + (m2 + L)];
     283            0 :       if (fabs(lx) < LIBGRPP_ZERO_THRESH && fabs(ly) < LIBGRPP_ZERO_THRESH &&
     284            0 :           fabs(lz) < LIBGRPP_ZERO_THRESH) {
     285            0 :         continue;
     286              :       }
     287              : 
     288            0 :       double omega_1 = libgrpp_angular_type2_integral(lambda_1, L, m1, a, b, c,
     289              :                                                       rsh_values_kA);
     290            0 :       if (fabs(omega_1) < LIBGRPP_ZERO_THRESH) {
     291            0 :         continue;
     292              :       }
     293              : 
     294            0 :       double omega_2 = libgrpp_angular_type2_integral(lambda_2, L, m2, d, e, f,
     295              :                                                       rsh_values_kB);
     296              : 
     297            0 :       *sum_angular_x += omega_1 * omega_2 * lx;
     298            0 :       *sum_angular_y += omega_1 * omega_2 * ly;
     299            0 :       *sum_angular_z += omega_1 * omega_2 * lz;
     300              :     }
     301              :   }
     302            0 : }
        

Generated by: LCOV version 2.0-1