LCOV - code coverage report
Current view: top level - src/grpp - grpp_nuclear_attraction.c (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:b4bd748) Lines: 0 97 0.0 %
Date: 2025-03-09 07:56:22 Functions: 0 11 0.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             :  * Calculation of nuclear attraction integrals.
      17             :  *
      18             :  * For the point charge nuclear model the recursive Obara-Saika scheme is used
      19             :  * to calculate nuclear attraction integrals. For details, see
      20             :  * T. Helgaker, P. Jorgensen, J. Olsen, Molecular Electronic-Structure Theory,
      21             :  * John Wiley & Sons Ltd, 2000.
      22             :  * Chapter 9.10.1, "The Obara-Saika scheme for one-electron Coulomb integrals"
      23             :  *
      24             :  * For the other three models,
      25             :  * - uniformly charged ball
      26             :  * - Gaussian nucleus
      27             :  * - Fermi nucleus,
      28             :  * the scheme is actually the same as for the type 1 (radially-local) ECP
      29             :  * integrals. Electrostatic potential V(r) induced by the finite nuclear charge
      30             :  * distribution is integrated numerically on a radial grid.
      31             :  */
      32             : 
      33             : #include <assert.h>
      34             : #include <math.h>
      35             : #include <stdio.h>
      36             : #include <stdlib.h>
      37             : #include <string.h>
      38             : 
      39             : #include "grpp_norm_gaussian.h"
      40             : #include "grpp_nuclear_models.h"
      41             : #include "grpp_utils.h"
      42             : #include "libgrpp.h"
      43             : 
      44             : #ifndef M_PI
      45             : #define M_PI 3.14159265358979323846
      46             : #endif
      47             : 
      48             : void libgrpp_evaluate_radially_local_potential_integral_primitive_gaussians(
      49             :     double *A, int n_cart_A, int *cart_list_A, double alpha_A, double *B,
      50             :     int n_cart_B, int *cart_list_B, double alpha_B, double *C,
      51             :     double (*potential)(double r, void *params), void *potential_params,
      52             :     double *matrix);
      53             : 
      54             : void libgrpp_evaluate_rpp_type1_mmd_n1_primitive_shell_pair(
      55             :     libgrpp_shell_t *shell_A, double alpha_A, libgrpp_shell_t *shell_B,
      56             :     double alpha_B, double *rpp_origin, double rpp_alpha, double *rpp_matrix);
      57             : 
      58             : static double wrapper_coulomb_potential_point(double r, void *params);
      59             : 
      60             : static double wrapper_coulomb_potential_ball(double r, void *params);
      61             : 
      62             : static double wrapper_coulomb_potential_gaussian(double r, void *params);
      63             : 
      64             : static double wrapper_coulomb_potential_fermi(double r, void *params);
      65             : 
      66             : static double wrapper_coulomb_potential_fermi_bubble(double r, void *params);
      67             : 
      68             : /**
      69             :  * Calculates nuclear attraction integral between two shells
      70             :  * represented by contracted Gaussian functions.
      71             :  *
      72             :  * nuclear model should be one of:
      73             :  *   LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE
      74             :  *   LIBGRPP_NUCLEAR_MODEL_CHARGED_BALL
      75             :  *   LIBGRPP_NUCLEAR_MODEL_GAUSSIAN
      76             :  *   LIBGRPP_NUCLEAR_MODEL_FERMI
      77             :  *   LIBGRPP_NUCLEAR_MODEL_FERMI_BUBBLE
      78             :  *   LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE_NUMERICAL
      79             :  */
      80           0 : void libgrpp_nuclear_attraction_integrals(libgrpp_shell_t *shell_A,
      81             :                                           libgrpp_shell_t *shell_B,
      82             :                                           double *charge_origin, int charge,
      83             :                                           int nuclear_model,
      84             :                                           double *model_params,
      85             :                                           double *coulomb_matrix) {
      86           0 :   assert(libgrpp_is_initialized());
      87             : 
      88           0 :   int size_A = libgrpp_get_shell_size(shell_A);
      89           0 :   int size_B = libgrpp_get_shell_size(shell_B);
      90             : 
      91           0 :   double *buf = calloc(size_A * size_B, sizeof(double));
      92             : 
      93           0 :   memset(coulomb_matrix, 0, size_A * size_B * sizeof(double));
      94             : 
      95             :   // loop over primitives in contractions
      96           0 :   for (int i = 0; i < shell_A->num_primitives; i++) {
      97           0 :     double coef_A_i = shell_A->coeffs[i];
      98             : 
      99           0 :     for (int j = 0; j < shell_B->num_primitives; j++) {
     100           0 :       double coef_B_j = shell_B->coeffs[j];
     101             : 
     102           0 :       if (fabs(coef_A_i * coef_B_j) < 1e-13) {
     103           0 :         continue;
     104             :       }
     105             : 
     106           0 :       if (nuclear_model == LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE) {
     107             : 
     108             :         // use code for RPP type-1 integrals with RPP exponent = 0.0
     109           0 :         libgrpp_evaluate_rpp_type1_mmd_n1_primitive_shell_pair(
     110           0 :             shell_A, shell_A->alpha[i], shell_B, shell_B->alpha[j],
     111             :             charge_origin, 0.0, buf);
     112             : 
     113           0 :         for (int k = 0; k < size_A * size_B; k++) {
     114           0 :           buf[k] *= (-1) * charge;
     115             :         }
     116           0 :       } else if (nuclear_model == LIBGRPP_NUCLEAR_MODEL_CHARGED_BALL ||
     117             :                  nuclear_model == LIBGRPP_NUCLEAR_MODEL_GAUSSIAN ||
     118             :                  nuclear_model == LIBGRPP_NUCLEAR_MODEL_FERMI ||
     119           0 :                  nuclear_model == LIBGRPP_NUCLEAR_MODEL_FERMI_BUBBLE ||
     120             :                  nuclear_model ==
     121             :                      LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE_NUMERICAL) {
     122             : 
     123           0 :         double params[10];
     124           0 :         params[0] = charge;
     125             : 
     126             :         /*
     127             :          * choose nuclear model
     128             :          */
     129           0 :         double (*electrostatic_potential_fun)(double, void *) = NULL;
     130             : 
     131           0 :         if (nuclear_model == LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE_NUMERICAL) {
     132             :           // printf("charge distribution: point\n");
     133             :           electrostatic_potential_fun = wrapper_coulomb_potential_point;
     134           0 :         } else if (nuclear_model == LIBGRPP_NUCLEAR_MODEL_CHARGED_BALL) {
     135           0 :           params[1] = model_params[0]; // R_rms
     136           0 :           electrostatic_potential_fun = wrapper_coulomb_potential_ball;
     137           0 :         } else if (nuclear_model == LIBGRPP_NUCLEAR_MODEL_GAUSSIAN) {
     138           0 :           params[1] = model_params[0]; // R_rms
     139           0 :           electrostatic_potential_fun = wrapper_coulomb_potential_gaussian;
     140           0 :         } else if (nuclear_model == LIBGRPP_NUCLEAR_MODEL_FERMI) {
     141           0 :           params[1] = model_params[0]; // c
     142           0 :           params[2] = model_params[1]; // a
     143           0 :           electrostatic_potential_fun = wrapper_coulomb_potential_fermi;
     144             :         } else {
     145           0 :           params[1] = model_params[0]; // c
     146           0 :           params[2] = model_params[1]; // a
     147           0 :           params[3] = model_params[2]; // k
     148           0 :           electrostatic_potential_fun = wrapper_coulomb_potential_fermi_bubble;
     149             :         }
     150             : 
     151             :         /*
     152             :          * calculate integrals for the shell pair
     153             :          */
     154           0 :         libgrpp_evaluate_radially_local_potential_integral_primitive_gaussians(
     155           0 :             shell_A->origin, size_A, shell_A->cart_list, shell_A->alpha[i],
     156           0 :             shell_B->origin, size_B, shell_B->cart_list, shell_B->alpha[j],
     157             :             charge_origin, electrostatic_potential_fun, params, buf);
     158             :       } else {
     159           0 :         printf("LIBGRPP: unknown finite nuclear charge distribution model!\n");
     160           0 :         exit(0);
     161             :       }
     162             : 
     163           0 :       libgrpp_daxpy(size_A * size_B, coef_A_i * coef_B_j, buf, coulomb_matrix);
     164             :     }
     165             :   }
     166             : 
     167           0 :   free(buf);
     168           0 : }
     169             : 
     170             : /**
     171             :  * Calculates nuclear attraction integral between two shells
     172             :  * represented by contracted Gaussian functions for the electrostatic potential
     173             :  * generated by the point charge.
     174             :  */
     175           0 : void libgrpp_nuclear_attraction_integrals_point_charge(libgrpp_shell_t *shell_A,
     176             :                                                        libgrpp_shell_t *shell_B,
     177             :                                                        double *charge_origin,
     178             :                                                        int charge,
     179             :                                                        double *coulomb_matrix) {
     180           0 :   libgrpp_nuclear_attraction_integrals(shell_A, shell_B, charge_origin, charge,
     181             :                                        LIBGRPP_NUCLEAR_MODEL_POINT_CHARGE, NULL,
     182             :                                        coulomb_matrix);
     183           0 : }
     184             : 
     185             : /**
     186             :  * Calculates nuclear attraction integral between two shells
     187             :  * represented by contracted Gaussian functions for the electrostatic potential
     188             :  * generated by the charged ball.
     189             :  *
     190             :  * r_rms stands for the root mean square radius (in bohrs)
     191             :  */
     192           0 : void libgrpp_nuclear_attraction_integrals_charged_ball(libgrpp_shell_t *shell_A,
     193             :                                                        libgrpp_shell_t *shell_B,
     194             :                                                        double *charge_origin,
     195             :                                                        int charge, double r_rms,
     196             :                                                        double *coulomb_matrix) {
     197           0 :   double params[10];
     198           0 :   params[0] = charge;
     199           0 :   params[1] = r_rms;
     200             : 
     201           0 :   libgrpp_nuclear_attraction_integrals(shell_A, shell_B, charge_origin, charge,
     202             :                                        LIBGRPP_NUCLEAR_MODEL_CHARGED_BALL,
     203             :                                        params, coulomb_matrix);
     204           0 : }
     205             : 
     206             : /**
     207             :  * Calculates nuclear attraction integral between two shells
     208             :  * represented by contracted Gaussian functions for the electrostatic potential
     209             :  * generated by the Gaussian distribution.
     210             :  *
     211             :  * r_rms stands for the root mean square radius (in bohrs)
     212             :  */
     213           0 : void libgrpp_nuclear_attraction_integrals_gaussian_model(
     214             :     libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *charge_origin,
     215             :     int charge, double r_rms, double *coulomb_matrix) {
     216           0 :   double params[10];
     217           0 :   params[0] = charge;
     218           0 :   params[1] = r_rms;
     219             : 
     220           0 :   libgrpp_nuclear_attraction_integrals(shell_A, shell_B, charge_origin, charge,
     221             :                                        LIBGRPP_NUCLEAR_MODEL_GAUSSIAN, params,
     222             :                                        coulomb_matrix);
     223           0 : }
     224             : 
     225             : /**
     226             :  * Calculates nuclear attraction integral between two shells
     227             :  * represented by contracted Gaussian functions for the electrostatic potential
     228             :  * generated by the Fermi distribution.
     229             :  *
     230             :  * Model parameters 'c' and 'a' must be given in bohrs.
     231             :  */
     232           0 : void libgrpp_nuclear_attraction_integrals_fermi_model(
     233             :     libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *charge_origin,
     234             :     int charge, double fermi_param_c, double fermi_param_a,
     235             :     double *coulomb_matrix) {
     236           0 :   double params[10];
     237           0 :   params[0] = charge;
     238           0 :   params[1] = fermi_param_c;
     239           0 :   params[2] = fermi_param_a;
     240             : 
     241           0 :   libgrpp_nuclear_attraction_integrals(shell_A, shell_B, charge_origin, charge,
     242             :                                        LIBGRPP_NUCLEAR_MODEL_FERMI, params,
     243             :                                        coulomb_matrix);
     244           0 : }
     245             : 
     246             : /**
     247             :  * Calculates nuclear attraction integral between two shells
     248             :  * represented by contracted Gaussian functions for the electrostatic potential
     249             :  * generated by the "Fermi + bubble" distribution.
     250             :  *
     251             :  * Model parameters 'c' and 'a' must be given in bohrs.
     252             :  * The 'k' constant is dimensionless.
     253             :  */
     254           0 : void libgrpp_nuclear_attraction_integrals_fermi_bubble_model(
     255             :     libgrpp_shell_t *shell_A, libgrpp_shell_t *shell_B, double *charge_origin,
     256             :     int charge, double param_c, double param_a, double param_k,
     257             :     double *coulomb_matrix) {
     258           0 :   double params[10];
     259           0 :   params[0] = charge;
     260           0 :   params[1] = param_c;
     261           0 :   params[2] = param_a;
     262           0 :   params[3] = param_k;
     263             : 
     264           0 :   libgrpp_nuclear_attraction_integrals(shell_A, shell_B, charge_origin, charge,
     265             :                                        LIBGRPP_NUCLEAR_MODEL_FERMI_BUBBLE,
     266             :                                        params, coulomb_matrix);
     267           0 : }
     268             : 
     269             : /**
     270             :  * wrappers for charge distribution functions.
     271             :  * are used to provide a unified interface to radially-local potentials.
     272             :  * the 'params' argument is unpacked, then the specific routines are invoked.
     273             :  */
     274             : 
     275           0 : static double wrapper_coulomb_potential_point(double r, void *params) {
     276           0 :   double Z = ((double *)params)[0];
     277             : 
     278           0 :   return libgrpp_coulomb_potential_point(r, Z);
     279             : }
     280             : 
     281           0 : static double wrapper_coulomb_potential_ball(double r, void *params) {
     282           0 :   double Z = ((double *)params)[0];
     283           0 :   double R_rms = ((double *)params)[1];
     284             : 
     285           0 :   return libgrpp_coulomb_potential_ball(r, Z, R_rms);
     286             : }
     287             : 
     288           0 : static double wrapper_coulomb_potential_gaussian(double r, void *params) {
     289           0 :   double Z = ((double *)params)[0];
     290           0 :   double R_rms = ((double *)params)[1];
     291             : 
     292           0 :   return libgrpp_coulomb_potential_gaussian(r, Z, R_rms);
     293             : }
     294             : 
     295           0 : static double wrapper_coulomb_potential_fermi(double r, void *params) {
     296           0 :   double Z = ((double *)params)[0];
     297           0 :   double c = ((double *)params)[1];
     298           0 :   double a = ((double *)params)[2];
     299             : 
     300           0 :   return libgrpp_coulomb_potential_fermi(r, Z, c, a);
     301             : }
     302             : 
     303           0 : static double wrapper_coulomb_potential_fermi_bubble(double r, void *params) {
     304           0 :   double Z = ((double *)params)[0];
     305           0 :   double c = ((double *)params)[1];
     306           0 :   double a = ((double *)params)[2];
     307           0 :   double k = ((double *)params)[3];
     308             : 
     309           0 :   return libgrpp_coulomb_potential_fermi_bubble(r, Z, c, a, k);
     310             : }

Generated by: LCOV version 1.15