LCOV - code coverage report
Current view: top level - src/grpp - grpp_type1_mcmurchie_davidson.c (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 0.0 % 285 0
Test Date: 2025-12-04 06:27:48 Functions: 0.0 % 7 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              : /*
      16              :  * Implementation of the McMurchie-Davidson (MMD) recurrence relations
      17              :  * for radially local RPP integrals.
      18              :  *
      19              :  * Operators to be integrated are:
      20              :  * n = 2: e^{-ar^2}
      21              :  * n = 1: e^{-ar^2}/r^1
      22              :  * n = 0: e^{-ar^2}/r^2
      23              :  *
      24              :  * General description of the MMD scheme is given in:
      25              :  * (1) T. Helgaker, P. Jorgensen, J. Olsen, Molecular Electronic-Structure
      26              :  * Theory, John Wiley & Sons Ltd, 2000. (2) L. E. McMurchie, E. R. Davidson,
      27              :  *     One- and two-electron integrals over cartesian gaussian functions.
      28              :  *     J. Comput. Phys. 26(2), 218 (1978).
      29              :  *     doi: 10.1016/0021-9991(78)90092-X
      30              :  *
      31              :  * More on the evaluation of integrals over the 1/r^2 operator:
      32              :  * (1) J. 0. Jensen, A. H. Cameri, C. P. Vlahacos, D. Zeroka, H. F. Hameka, C.
      33              :  * N. Merrow, Evaluation of one-electron integrals for arbitrary operators V(r)
      34              :  * over cartesian Gaussians: Application to inverse-square distance and Yukawa
      35              :  * operators. J. Comput. Chem. 14(8), 986 (1993). doi: 10.1002/jcc.540140814 (2)
      36              :  * B. Gao, A. J. Thorvaldsen, K. Ruud, GEN1INT: A unified procedure for the
      37              :  * evaluation of one-electron integrals over Gaussian basis functions and their
      38              :  * geometric derivatives. Int. J. Quantum Chem. 111(4), 858 (2011).
      39              :  *     doi: 10.1002/qua.22886
      40              :  */
      41              : #include <assert.h>
      42              : #include <math.h>
      43              : #include <stdlib.h>
      44              : #include <string.h>
      45              : 
      46              : #include "grpp_type1_mcmurchie_davidson.h"
      47              : 
      48              : #ifndef M_PI
      49              : #define M_PI 3.14159265358979323846
      50              : #endif
      51              : 
      52              : #include "grpp_norm_gaussian.h"
      53              : #include "grpp_specfunc.h"
      54              : #include "grpp_utils.h"
      55              : #include "libgrpp.h"
      56              : 
      57              : #define LMAX LIBGRPP_MAX_BASIS_L
      58              : 
      59              : /*
      60              :  * temporary data for the McMurchie-Davidson algorithm
      61              :  */
      62              : struct mmd_data {
      63              :   double A[3];
      64              :   double B[3];
      65              :   double C[3];
      66              :   double Q[3];
      67              :   double q;
      68              :   double K_abc[3];
      69              :   double R_QC_2;
      70              :   double boys[100];
      71              :   double E[3][LMAX][LMAX][2 * LMAX];
      72              :   double R[2 * LMAX][2 * LMAX][2 * LMAX][2 * LMAX];
      73              : };
      74              : 
      75              : /*
      76              :  * functions used below in the file
      77              :  */
      78              : 
      79              : static void evaluate_rpp_type1_mmd_n2_primitive_shell_pair(
      80              :     libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
      81              :     double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix);
      82              : 
      83              : void libgrpp_evaluate_rpp_type1_mmd_n1_primitive_shell_pair(
      84              :     libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
      85              :     double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix);
      86              : 
      87              : static void evaluate_rpp_type1_mmd_n0_primitive_shell_pair(
      88              :     libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
      89              :     double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix);
      90              : 
      91              : static void setup_E_array(struct mmd_data *data, int L_A, int L_B);
      92              : 
      93              : static void setup_R_array(struct mmd_data *data, int L_A, int L_B);
      94              : 
      95              : static void setup_G_array(struct mmd_data *data, int L_A, int L_B);
      96              : 
      97              : /**
      98              :  * General interface for the McMurchie-Davidson algorithm for integrals
      99              :  * over the radially local RPP operator.
     100              :  */
     101            0 : void libgrpp_type1_integrals_mcmurchie_davidson_1978(
     102              :     libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *origin_C,
     103              :     double alpha_C, int ecp_power, double *rpp_matrix) {
     104            0 :   assert((ecp_power == 0) || (ecp_power == 1) || (ecp_power == 2));
     105              : 
     106            0 :   int size_A = libgrpp_get_shell_size(shell_A);
     107            0 :   int size_B = libgrpp_get_shell_size(shell_B);
     108              : 
     109            0 :   double *buf = calloc(size_A * size_B, sizeof(double));
     110              : 
     111            0 :   memset(rpp_matrix, 0, size_A * size_B * sizeof(double));
     112              : 
     113              :   /*
     114              :    * loop over primitives in contractions
     115              :    */
     116            0 :   for (int i = 0; i < shell_A->num_primitives; i++) {
     117            0 :     double coef_A_i = shell_A->coeffs[i];
     118            0 :     if (fabs(coef_A_i) < LIBGRPP_ZERO_THRESH) {
     119            0 :       continue;
     120              :     }
     121              : 
     122            0 :     for (int j = 0; j < shell_B->num_primitives; j++) {
     123            0 :       double coef_B_j = shell_B->coeffs[j];
     124            0 :       if (fabs(coef_B_j) < LIBGRPP_ZERO_THRESH) {
     125            0 :         continue;
     126              :       }
     127              : 
     128            0 :       if (ecp_power == 2) {
     129            0 :         evaluate_rpp_type1_mmd_n2_primitive_shell_pair(
     130            0 :             shell_A, shell_A->alpha[i], shell_B, shell_B->alpha[j], origin_C,
     131              :             alpha_C, buf);
     132            0 :       } else if (ecp_power == 1) {
     133            0 :         libgrpp_evaluate_rpp_type1_mmd_n1_primitive_shell_pair(
     134            0 :             shell_A, shell_A->alpha[i], shell_B, shell_B->alpha[j], origin_C,
     135              :             alpha_C, buf);
     136            0 :       } else if (ecp_power == 0) {
     137            0 :         evaluate_rpp_type1_mmd_n0_primitive_shell_pair(
     138            0 :             shell_A, shell_A->alpha[i], shell_B, shell_B->alpha[j], origin_C,
     139              :             alpha_C, buf);
     140              :       }
     141              : 
     142            0 :       libgrpp_daxpy(size_A * size_B, coef_A_i * coef_B_j, buf, rpp_matrix);
     143              :     }
     144              :   }
     145              : 
     146            0 :   free(buf);
     147            0 : }
     148              : 
     149              : /**
     150              :  * Integrals of the operator: e^{-ar^2}/r^2
     151              :  */
     152            0 : static void evaluate_rpp_type1_mmd_n0_primitive_shell_pair(
     153              :     libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
     154              :     double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix) {
     155            0 :   double a = alpha_A;
     156            0 :   double b = alpha_B;
     157            0 :   double c = rpp_alpha;
     158              : 
     159            0 :   double *A = shell_A->origin;
     160            0 :   double *B = shell_B->origin;
     161            0 :   double *C = rpp_origin;
     162              : 
     163            0 :   double q = a + b + c;
     164            0 :   double mu_AB = a * b / q;
     165            0 :   double mu_AC = a * c / q;
     166            0 :   double mu_BC = b * c / q;
     167              : 
     168            0 :   struct mmd_data data;
     169              : 
     170            0 :   for (int i = 0; i < 3; i++) {
     171            0 :     data.A[i] = A[i];
     172            0 :     data.B[i] = B[i];
     173            0 :     data.C[i] = C[i];
     174            0 :     data.Q[i] = (a * A[i] + b * B[i] + c * C[i]) / q;
     175              : 
     176            0 :     double X_AB = A[i] - B[i];
     177            0 :     double X_AC = A[i] - C[i];
     178            0 :     double X_BC = B[i] - C[i];
     179              : 
     180            0 :     double K_ab = exp(-mu_AB * X_AB * X_AB);
     181            0 :     double K_ac = exp(-mu_AC * X_AC * X_AC);
     182            0 :     double K_bc = exp(-mu_BC * X_BC * X_BC);
     183              : 
     184            0 :     data.K_abc[i] = K_ab * K_ac * K_bc;
     185              :   }
     186              : 
     187            0 :   data.q = q;
     188            0 :   data.R_QC_2 = distance_squared(data.Q, data.C);
     189            0 :   int L_A = shell_A->L;
     190            0 :   int L_B = shell_B->L;
     191            0 :   int Nmax = L_A + L_B;
     192            0 :   libgrpp_gfun_values(q * data.R_QC_2, Nmax, data.boys);
     193              : 
     194              :   /*
     195              :    * setup E array
     196              :    */
     197            0 :   setup_E_array(&data, L_A, L_B);
     198              : 
     199              :   /*
     200              :    * setup R array
     201              :    */
     202            0 :   setup_G_array(&data, L_A, L_B);
     203              : 
     204              :   /*
     205              :    * loop over cartesian functions inside the shells
     206              :    */
     207            0 :   int size_A = libgrpp_get_shell_size(shell_A);
     208            0 :   int size_B = libgrpp_get_shell_size(shell_B);
     209            0 :   double N_A = libgrpp_gaussian_norm_factor(L_A, 0, 0, alpha_A);
     210            0 :   double N_B = libgrpp_gaussian_norm_factor(L_B, 0, 0, alpha_B);
     211              : 
     212            0 :   for (int m = 0; m < size_A; m++) {
     213            0 :     for (int n = 0; n < size_B; n++) {
     214            0 :       int n_A = shell_A->cart_list[3 * m + 0];
     215            0 :       int l_A = shell_A->cart_list[3 * m + 1];
     216            0 :       int m_A = shell_A->cart_list[3 * m + 2];
     217            0 :       int n_B = shell_B->cart_list[3 * n + 0];
     218            0 :       int l_B = shell_B->cart_list[3 * n + 1];
     219            0 :       int m_B = shell_B->cart_list[3 * n + 2];
     220              : 
     221            0 :       double s = 0.0;
     222              : 
     223            0 :       for (int t = 0; t <= n_A + n_B; t++) {
     224            0 :         double Ex = data.E[0][n_A][n_B][t];
     225              : 
     226            0 :         for (int u = 0; u <= l_A + l_B; u++) {
     227            0 :           double Ey = data.E[1][l_A][l_B][u];
     228              : 
     229            0 :           for (int v = 0; v <= m_A + m_B; v++) {
     230            0 :             double Ez = data.E[2][m_A][m_B][v];
     231              : 
     232            0 :             double R_tuv = data.R[t][u][v][0];
     233              : 
     234            0 :             s += Ex * Ey * Ez * R_tuv;
     235              :           }
     236              :         }
     237              :       }
     238              : 
     239            0 :       s *= N_A * N_B * 2.0 * pow(M_PI, 1.5) / sqrt(q);
     240            0 :       rpp_matrix[m * size_B + n] = s;
     241              :     }
     242              :   }
     243            0 : }
     244              : 
     245              : /**
     246              :  * Integrals of the operator: e^{-ar^2}/r
     247              :  */
     248            0 : void libgrpp_evaluate_rpp_type1_mmd_n1_primitive_shell_pair(
     249              :     libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
     250              :     double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix) {
     251            0 :   double a = alpha_A;
     252            0 :   double b = alpha_B;
     253            0 :   double c = rpp_alpha;
     254              : 
     255            0 :   double *A = shell_A->origin;
     256            0 :   double *B = shell_B->origin;
     257            0 :   double *C = rpp_origin;
     258              : 
     259            0 :   double q = a + b + c;
     260            0 :   double mu_AB = a * b / q;
     261            0 :   double mu_AC = a * c / q;
     262            0 :   double mu_BC = b * c / q;
     263              : 
     264            0 :   struct mmd_data data;
     265              : 
     266            0 :   for (int i = 0; i < 3; i++) {
     267            0 :     data.A[i] = A[i];
     268            0 :     data.B[i] = B[i];
     269            0 :     data.C[i] = C[i];
     270            0 :     data.Q[i] = (a * A[i] + b * B[i] + c * C[i]) / q;
     271              : 
     272            0 :     double X_AB = A[i] - B[i];
     273            0 :     double X_AC = A[i] - C[i];
     274            0 :     double X_BC = B[i] - C[i];
     275              : 
     276            0 :     double K_ab = exp(-mu_AB * X_AB * X_AB);
     277            0 :     double K_ac = exp(-mu_AC * X_AC * X_AC);
     278            0 :     double K_bc = exp(-mu_BC * X_BC * X_BC);
     279              : 
     280            0 :     data.K_abc[i] = K_ab * K_ac * K_bc;
     281              :   }
     282              : 
     283            0 :   data.q = q;
     284            0 :   data.R_QC_2 = distance_squared(data.Q, data.C);
     285            0 :   int L_A = shell_A->L;
     286            0 :   int L_B = shell_B->L;
     287            0 :   int Nmax = L_A + L_B;
     288              : 
     289            0 :   libgrpp_boys_values(q * data.R_QC_2, Nmax, data.boys);
     290              : 
     291              :   /*
     292              :    * setup E array
     293              :    */
     294            0 :   setup_E_array(&data, L_A, L_B);
     295              : 
     296              :   /*
     297              :    * setup R array
     298              :    */
     299            0 :   setup_R_array(&data, L_A, L_B);
     300              : 
     301              :   /*
     302              :    * loop over cartesian functions inside the shells
     303              :    */
     304            0 :   int size_A = libgrpp_get_shell_size(shell_A);
     305            0 :   int size_B = libgrpp_get_shell_size(shell_B);
     306            0 :   double N_A = libgrpp_gaussian_norm_factor(L_A, 0, 0, alpha_A);
     307            0 :   double N_B = libgrpp_gaussian_norm_factor(L_B, 0, 0, alpha_B);
     308              : 
     309            0 :   for (int m = 0; m < size_A; m++) {
     310            0 :     for (int n = 0; n < size_B; n++) {
     311            0 :       int n_A = shell_A->cart_list[3 * m + 0];
     312            0 :       int l_A = shell_A->cart_list[3 * m + 1];
     313            0 :       int m_A = shell_A->cart_list[3 * m + 2];
     314            0 :       int n_B = shell_B->cart_list[3 * n + 0];
     315            0 :       int l_B = shell_B->cart_list[3 * n + 1];
     316            0 :       int m_B = shell_B->cart_list[3 * n + 2];
     317              : 
     318            0 :       double s = 0.0;
     319              : 
     320            0 :       for (int t = 0; t <= n_A + n_B; t++) {
     321            0 :         double Ex = data.E[0][n_A][n_B][t];
     322              : 
     323            0 :         for (int u = 0; u <= l_A + l_B; u++) {
     324            0 :           double Ey = data.E[1][l_A][l_B][u];
     325              : 
     326            0 :           for (int v = 0; v <= m_A + m_B; v++) {
     327            0 :             double Ez = data.E[2][m_A][m_B][v];
     328              : 
     329            0 :             double R_tuv = data.R[t][u][v][0];
     330              : 
     331            0 :             s += Ex * Ey * Ez * R_tuv;
     332              :           }
     333              :         }
     334              :       }
     335              : 
     336            0 :       s *= N_A * N_B * 2.0 * M_PI / q;
     337            0 :       rpp_matrix[m * size_B + n] = s;
     338              :     }
     339              :   }
     340            0 : }
     341              : 
     342              : /**
     343              :  * Integrals of the operator: e^{-ar^2}
     344              :  */
     345            0 : static void evaluate_rpp_type1_mmd_n2_primitive_shell_pair(
     346              :     libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
     347              :     double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix) {
     348            0 :   double a = alpha_A;
     349            0 :   double b = alpha_B;
     350            0 :   double c = rpp_alpha;
     351              : 
     352            0 :   double *A = shell_A->origin;
     353            0 :   double *B = shell_B->origin;
     354            0 :   double *C = rpp_origin;
     355              : 
     356            0 :   double q = a + b + c;
     357            0 :   double mu_AB = a * b / q;
     358            0 :   double mu_AC = a * c / q;
     359            0 :   double mu_BC = b * c / q;
     360              : 
     361            0 :   struct mmd_data data;
     362              : 
     363            0 :   for (int i = 0; i < 3; i++) {
     364            0 :     data.A[i] = A[i];
     365            0 :     data.B[i] = B[i];
     366            0 :     data.C[i] = C[i];
     367            0 :     data.Q[i] = (a * A[i] + b * B[i] + c * C[i]) / q;
     368              : 
     369            0 :     double X_AB = A[i] - B[i];
     370            0 :     double X_AC = A[i] - C[i];
     371            0 :     double X_BC = B[i] - C[i];
     372              : 
     373            0 :     double K_ab = exp(-mu_AB * X_AB * X_AB);
     374            0 :     double K_ac = exp(-mu_AC * X_AC * X_AC);
     375            0 :     double K_bc = exp(-mu_BC * X_BC * X_BC);
     376              : 
     377            0 :     data.K_abc[i] = K_ab * K_ac * K_bc;
     378              :   }
     379              : 
     380            0 :   data.q = q;
     381            0 :   data.R_QC_2 = distance_squared(data.Q, data.C);
     382              : 
     383            0 :   int L_A = shell_A->L;
     384            0 :   int L_B = shell_B->L;
     385              : 
     386              :   /*
     387              :    * setup E array
     388              :    */
     389            0 :   setup_E_array(&data, L_A, L_B);
     390              : 
     391              :   /*
     392              :    * loop over cartesian functions inside the shells
     393              :    */
     394            0 :   int size_A = libgrpp_get_shell_size(shell_A);
     395            0 :   int size_B = libgrpp_get_shell_size(shell_B);
     396            0 :   double N_A = libgrpp_gaussian_norm_factor(L_A, 0, 0, alpha_A);
     397            0 :   double N_B = libgrpp_gaussian_norm_factor(L_B, 0, 0, alpha_B);
     398              : 
     399            0 :   for (int m = 0; m < size_A; m++) {
     400            0 :     for (int n = 0; n < size_B; n++) {
     401            0 :       int n_A = shell_A->cart_list[3 * m + 0];
     402            0 :       int l_A = shell_A->cart_list[3 * m + 1];
     403            0 :       int m_A = shell_A->cart_list[3 * m + 2];
     404            0 :       int n_B = shell_B->cart_list[3 * n + 0];
     405            0 :       int l_B = shell_B->cart_list[3 * n + 1];
     406            0 :       int m_B = shell_B->cart_list[3 * n + 2];
     407              : 
     408            0 :       double E_ij_0 = data.E[0][n_A][n_B][0];
     409            0 :       double E_kl_0 = data.E[1][l_A][l_B][0];
     410            0 :       double E_mn_0 = data.E[2][m_A][m_B][0];
     411              : 
     412            0 :       double s = N_A * N_B * E_ij_0 * E_kl_0 * E_mn_0 * pow(M_PI / q, 1.5);
     413              : 
     414            0 :       rpp_matrix[m * size_B + n] = s;
     415              :     }
     416              :   }
     417            0 : }
     418              : 
     419              : /**
     420              :  * Calculation of the R_{tuv}^N auxiliary integrals for the 1/r operator
     421              :  */
     422            0 : static void setup_R_array(struct mmd_data *data, int L_A, int L_B) {
     423            0 :   double q = data->q;
     424            0 :   double X_QC = data->Q[0] - data->C[0];
     425            0 :   double Y_QC = data->Q[1] - data->C[1];
     426            0 :   double Z_QC = data->Q[2] - data->C[2];
     427              : 
     428            0 :   int nmax = L_A + L_B;
     429            0 :   int L_SUM = L_A + L_B;
     430              : 
     431            0 :   for (int t = 0; t <= L_SUM; t++) {
     432            0 :     for (int u = 0; u <= L_SUM; u++) {
     433            0 :       for (int v = 0; v <= L_SUM; v++) {
     434              : 
     435            0 :         if (t + u + v > L_SUM) {
     436            0 :           continue;
     437              :         }
     438              : 
     439            0 :         for (int n = 0; n <= nmax - (t + u + v); n++) {
     440              : 
     441            0 :           double val = 0.0;
     442              : 
     443            0 :           if (t + u + v == 0) {
     444            0 :             val = pow(-2.0 * q, n) * data->boys[n];
     445            0 :           } else if (t + u == 0) {
     446            0 :             if (v > 1) {
     447            0 :               val += (v - 1) * data->R[t][u][v - 2][n + 1];
     448              :             }
     449            0 :             val += Z_QC * data->R[t][u][v - 1][n + 1];
     450            0 :           } else if (t == 0) {
     451            0 :             if (u > 1) {
     452            0 :               val += (u - 1) * data->R[t][u - 2][v][n + 1];
     453              :             }
     454            0 :             val += Y_QC * data->R[t][u - 1][v][n + 1];
     455              :           } else {
     456            0 :             if (t > 1) {
     457            0 :               val += (t - 1) * data->R[t - 2][u][v][n + 1];
     458              :             }
     459            0 :             val += X_QC * data->R[t - 1][u][v][n + 1];
     460              :           }
     461              : 
     462            0 :           data->R[t][u][v][n] = val;
     463              :         }
     464              :       }
     465              :     }
     466              :   }
     467            0 : }
     468              : 
     469              : /**
     470              :  * Calculation of the R_{tuv}^N auxiliary integrals for the 1/r^2 operator
     471              :  */
     472            0 : static void setup_G_array(struct mmd_data *data, int L_A, int L_B) {
     473            0 :   double q = data->q;
     474            0 :   double X_QC = data->Q[0] - data->C[0];
     475            0 :   double Y_QC = data->Q[1] - data->C[1];
     476            0 :   double Z_QC = data->Q[2] - data->C[2];
     477              : 
     478            0 :   int nmax = L_A + L_B;
     479            0 :   int L_SUM = L_A + L_B;
     480              : 
     481            0 :   for (int t = 0; t <= L_SUM; t++) {
     482            0 :     for (int u = 0; u <= L_SUM; u++) {
     483            0 :       for (int v = 0; v <= L_SUM; v++) {
     484              : 
     485            0 :         if (t + u + v > L_SUM) {
     486            0 :           continue;
     487              :         }
     488              : 
     489            0 :         for (int n = 0; n <= nmax - (t + u + v); n++) {
     490              : 
     491            0 :           double val = 0.0;
     492              : 
     493            0 :           if (t + u + v == 0) {
     494            0 :             val = pow(2.0 * q, n) * data->boys[n];
     495            0 :           } else if (t + u == 0) {
     496            0 :             if (v > 1) {
     497            0 :               val += (v - 1) * (data->R[t][u][v - 2][n + 1] -
     498            0 :                                 2.0 * q * data->R[t][u][v - 2][n]);
     499              :             }
     500            0 :             val += Z_QC * (data->R[t][u][v - 1][n + 1] -
     501            0 :                            2.0 * q * data->R[t][u][v - 1][n]);
     502            0 :           } else if (t == 0) {
     503            0 :             if (u > 1) {
     504            0 :               val += (u - 1) * (data->R[t][u - 2][v][n + 1] -
     505            0 :                                 2.0 * q * data->R[t][u - 2][v][n]);
     506              :             }
     507            0 :             val += Y_QC * (data->R[t][u - 1][v][n + 1] -
     508            0 :                            2.0 * q * data->R[t][u - 1][v][n]);
     509              :           } else {
     510            0 :             if (t > 1) {
     511            0 :               val += (t - 1) * (data->R[t - 2][u][v][n + 1] -
     512            0 :                                 2.0 * q * data->R[t - 2][u][v][n]);
     513              :             }
     514            0 :             val += X_QC * (data->R[t - 1][u][v][n + 1] -
     515            0 :                            2.0 * q * data->R[t - 1][u][v][n]);
     516              :           }
     517              : 
     518            0 :           data->R[t][u][v][n] = val;
     519              :         }
     520              :       }
     521              :     }
     522              :   }
     523            0 : }
     524              : 
     525              : /**
     526              :  * Calculates E^{ij}_t coefficients in the MMD scheme.
     527              :  */
     528            0 : static void setup_E_array(struct mmd_data *data, int L_A, int L_B) {
     529            0 :   double q = data->q;
     530              : 
     531            0 :   for (int coord = 0; coord < 3; coord++) {
     532            0 :     for (int i = 0; i <= L_A; i++) {
     533            0 :       for (int j = 0; j <= L_B; j++) {
     534              : 
     535            0 :         for (int t = 0; t <= i + j; t++) {
     536              : 
     537            0 :           if (t == 0) {
     538            0 :             if (i == 0 && j == 0) {
     539            0 :               data->E[coord][0][0][0] = data->K_abc[coord];
     540            0 :               continue;
     541            0 :             } else if (i == 1 && j == 0) {
     542            0 :               double X_QA = data->Q[coord] - data->A[coord];
     543            0 :               data->E[coord][1][0][0] = X_QA * data->E[coord][0][0][0];
     544            0 :               continue;
     545            0 :             } else if (i == 0 && j == 1) {
     546            0 :               double X_QB = data->Q[coord] - data->B[coord];
     547            0 :               data->E[coord][0][1][0] = X_QB * data->E[coord][0][0][0];
     548            0 :               continue;
     549            0 :             } else if (i == 0) {
     550            0 :               double X_QB = data->Q[coord] - data->B[coord];
     551            0 :               data->E[coord][i][j][0] = X_QB * data->E[coord][i][j - 1][0] +
     552            0 :                                         data->E[coord][i][j - 1][1];
     553            0 :               continue;
     554            0 :             } else {
     555            0 :               double X_QA = data->Q[coord] - data->A[coord];
     556            0 :               data->E[coord][i][j][0] = X_QA * data->E[coord][i - 1][j][0] +
     557            0 :                                         data->E[coord][i - 1][j][1];
     558            0 :               continue;
     559              :             }
     560              :           } else {
     561            0 :             double E_ijt = 0.0;
     562            0 :             double factor = 1.0 / (2.0 * q * t);
     563              : 
     564            0 :             if (i > 0) {
     565            0 :               E_ijt += factor * i * data->E[coord][i - 1][j][t - 1];
     566              :             }
     567            0 :             if (j > 0) {
     568            0 :               E_ijt += factor * j * data->E[coord][i][j - 1][t - 1];
     569              :             }
     570              : 
     571            0 :             data->E[coord][i][j][t] = E_ijt;
     572              :           }
     573              :         }
     574              :       }
     575              :     }
     576              :   }
     577            0 : }
        

Generated by: LCOV version 2.0-1