File: fun-pw86x.c

package info (click to toggle)
ergo 3.8.2-1.1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 17,568 kB
  • sloc: cpp: 94,763; ansic: 17,785; sh: 10,701; makefile: 1,403; yacc: 127; lex: 116; awk: 23
file content (120 lines) | stat: -rw-r--r-- 3,826 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* Ergo, version 3.8.2, a program for linear scaling electronic structure
 * calculations.
 * Copyright (C) 2023 Elias Rudberg, Emanuel H. Rubensson, Pawel Salek,
 * and Anastasia Kruchinina.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Primary academic reference:
 * Ergo: An open-source program for linear-scaling electronic structure
 * calculations,
 * Elias Rudberg, Emanuel H. Rubensson, Pawel Salek, and Anastasia
 * Kruchinina,
 * SoftwareX 7, 107 (2018),
 * <http://dx.doi.org/10.1016/j.softx.2018.03.005>
 * 
 * For further information about Ergo, see <http://www.ergoscf.org>.
 */

/** @file fun-pw86x.c
   The PW86 exchange functional and its derivative.
   Contributed by Olav Fossgaard, olav@chem.uit.no, May 2002
 
   Reference: Phys. Rev. B 33. 8800 (1986)
*/

#include <math.h>
#include <stdio.h>

#define __CVERSION__

#include "functionals.h"

/* INTERFACE PART */
static int pw86x_isgga(void) { return 1; }
static int pw86x_read(const char* conf_line);
static real pw86x_energy(const FunDensProp* dp);
static void pw86x_first (FunFirstFuncDrv *ds,  real factor, const FunDensProp*dp);

Functional PW86xFunctional = {
  "PW86x",       /* name */
  pw86x_isgga,   /* gga-corrected */
  pw86x_read, 
  NULL,
  pw86x_energy, 
  pw86x_first,
  NULL,
  NULL
};

/* IMPLEMENTATION PART */
static int
pw86x_read(const char* conf_line)
{
  fun_set_hf_weight(0);
  return 1;
}

static real
pw86x_energy(const FunDensProp* dp)
{
/* Use density functional form. In case of spin polarization,
   this function will have to be called twice with arguments
   rho=2rhoa and rho=2rhob, respectively. The total energy is then
   half the sum of the returned values.
*/
  const real a = 1.0;
  const real b = 1.296;
  const real c = 14.0;
  const real d = 0.20;
/* Closed shell (See eq. (25) in reference) */
  real rho = dp->rhoa+dp->rhob, grad = dp->grada+dp->gradb;

  const real Ax = -POW(3.0/M_PI,1.0/3.0)*3.0/4.0;
  const real kf = POW(3.0*POW(M_PI,2.0)*rho,1.0/3.0);
  real s = grad/(2.0*kf*rho);
  real F = POW(a+b*POW(s,2.0)+c*POW(s,4.0)+d*POW(s,6.0),1.0/15.0); 
  return Ax*POW(rho,4.0/3.0)*F;
}

static void
pw86x_first(FunFirstFuncDrv *ds, real factor, const FunDensProp* dp)
{
/* The energy expression is the integral int(Ax*rho**(4/3)*F). We first 
   calculate d(F)/d(rho) and d(F)/d(grad_rho) and differentiate the
   product in the last step.
*/
  const real a = 1.0;
  const real b = 1.296;
  const real c = 14.0;
  const real d = 0.20;
/* Closed shell (See eq. (25) in reference) */
  real rho = dp->rhoa+dp->rhob, grad = dp->grada+dp->gradb;

  const real Ax= -POW(3.0/M_PI,1.0/3.0)*3.0/4.0;
  const real kf= POW(3.0*M_PI*M_PI*rho,1.0/3.0);
  real  s = grad/(2.0*kf*rho);
  real  F = POW(a+b*POW(s,2.0)+c*POW(s,4.0)+d*POW(s,6.0),1.0/15.0);

  real F1 = 1.0/15.0*POW(a+b*POW(s,2.0)+c*POW(s,4.0)+d*POW(s,6.0),-14.0/15.0)
            *(2.0*b*s+4.0*c*POW(s,3.0)+6.0*d*POW(s,5.0)); /* dF/ds */

  real s1 = -4.0*s/(3.0*rho); /* ds/d(rho) */
  real s2 = 1.0/(2.0*kf*rho); /* d(s)/d(grad) */
  real G1 = F1*s1; /* dF/d(rho) */ 
  real G2 = F1*s2; /* dF/d(grad) */
   
  ds->df1000 += Ax*((4.0/3.0)*POW(rho,1.0/3.0)*F + POW(rho,4.0/3.0)*G1 )*factor;
  ds->df0010 += Ax*POW(rho,4.0/3.0)*G2*factor;
}