1 /*-------------------------------------------------------------------
2 Copyright 2011 Ravishankar Sundararaman
3
4 This file is part of JDFTx.
5
6 JDFTx is free software: you can redistribute it and/or modify
7 it under the terms of the GNU 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 JDFTx 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 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with JDFTx. If not, see <http://www.gnu.org/licenses/>.
18 -------------------------------------------------------------------*/
19
20 #include <fluid/Fex_LJ.h>
21 #include <fluid/FluidMixture.h>
22 #include <core/Operators.h>
23 #include <gsl/gsl_sf.h>
24
setLJatt_calc(double G,double eps,double sigma)25 double setLJatt_calc(double G, double eps, double sigma)
26 { //Scale so that well minimum is located at r=1, with depth 1:
27 double kScale = sigma*pow(2.0,1.0/6);
28 double k = G*kScale;
29 double kSq = k*k;
30 double result;
31 if(k<35.0)
32 { result =
33 (M_PI/1814400)*(
34 - 2*cos(k)*(-564480 + kSq*(301680 + kSq*(24 + kSq*(-2 + kSq))))
35 - 2*k*sin(k)*(297360 + kSq*(120 + kSq*(-6 + kSq)))
36 + pow(k,3)*(302400 + pow(k,6))*(M_PI - 2*gsl_sf_Si(k)) )
37 + (4*M_PI/3)*((2.2*gsl_sf_bessel_jl(0,k)) + gsl_sf_bessel_jl(2,k));
38 }
39 else //Use asymptotic form for large k
40 { result = (288*M_PI)*pow(k,-10) * (
41 cos(k)*(-23950080 + kSq*(75880 +kSq*(-287 + kSq)))
42 + k*sin(k)*(1315160 + kSq*(-4585 + kSq*18)) );
43 }
44 //Scale back to actual values:
45 return -eps*pow(kScale,3) * result;
46 }
setLJatt(RadialFunctionG & kernel,const GridInfo & gInfo,double eps,double sigma)47 void setLJatt(RadialFunctionG& kernel, const GridInfo& gInfo, double eps, double sigma)
48 { kernel.init(0, gInfo.dGradial, gInfo.GmaxGrid, setLJatt_calc, eps, sigma);
49 }
50
51
Fex_LJ(const FluidMixture * fluidMixture,const FluidComponent * comp,double eps,double sigmaOverride)52 Fex_LJ::Fex_LJ(const FluidMixture* fluidMixture, const FluidComponent* comp, double eps, double sigmaOverride)
53 : Fex(fluidMixture, comp), sigma(2.*molecule.sites[0]->Rhs)
54 {
55 if(sigmaOverride) sigma = sigmaOverride;
56 logPrintf(" Initializing LJ excess functional with eps=%lf Eh and sigma=%lf bohrs\n", eps, sigma);
57 setLJatt(ljatt, gInfo, eps, sigma);
58 }
~Fex_LJ()59 Fex_LJ::~Fex_LJ()
60 { ljatt.free();
61 }
62
compute(const ScalarFieldTilde * Ntilde,ScalarFieldTilde * Phi_Ntilde) const63 double Fex_LJ::compute(const ScalarFieldTilde* Ntilde, ScalarFieldTilde* Phi_Ntilde) const
64 { ScalarFieldTilde V = gInfo.nr * (ljatt * Ntilde[0]);
65 Phi_Ntilde[0] += V;
66 return 0.5*gInfo.dV*dot(V,Ntilde[0]);
67 }
computeUniform(const double * N,double * Phi_N) const68 double Fex_LJ::computeUniform(const double* N, double* Phi_N) const
69 { Phi_N[0] += ljatt(0)*N[0];
70 return 0.5*N[0]*ljatt(0)*N[0];
71 }
72
73
Fmix_LJ(FluidMixture * fluidMixture,std::shared_ptr<FluidComponent> fluid1,std::shared_ptr<FluidComponent> fluid2,double eps,double sigma)74 Fmix_LJ::Fmix_LJ(FluidMixture* fluidMixture, std::shared_ptr<FluidComponent> fluid1, std::shared_ptr<FluidComponent> fluid2, double eps, double sigma)
75 : Fmix(fluidMixture), fluid1(fluid1), fluid2(fluid2)
76 {
77 string name1 = fluid1->molecule.name;
78 string name2 = fluid2->molecule.name;
79 logPrintf("\n Initializing attractive LJ mixing functional between %s and %s\n sigma: %lg Bohr and eps: %lg H.\n",
80 name1.c_str(),name2.c_str(),sigma,eps);
81 setLJatt(ljatt, gInfo, eps, sigma);
82 }
83
~Fmix_LJ()84 Fmix_LJ::~Fmix_LJ()
85 { ljatt.free();
86 }
87
getName() const88 string Fmix_LJ::getName() const
89 { return fluid1->molecule.name + "<->" + fluid2->molecule.name;
90 }
91
compute(const ScalarFieldTildeArray & Ntilde,ScalarFieldTildeArray & Phi_Ntilde) const92 double Fmix_LJ::compute(const ScalarFieldTildeArray& Ntilde, ScalarFieldTildeArray& Phi_Ntilde) const
93 { unsigned i1 = fluid1->offsetDensity;
94 unsigned i2 = fluid2->offsetDensity;
95 ScalarFieldTilde V1 = gInfo.nr * (ljatt * Ntilde[i1]);
96 ScalarFieldTilde V2 = gInfo.nr * (ljatt * Ntilde[i2]);
97 Phi_Ntilde[i1] += V2;
98 Phi_Ntilde[i2] += V1;
99 return gInfo.dV*dot(V1,Ntilde[i2]);
100 }
computeUniform(const std::vector<double> & N,std::vector<double> & Phi_N) const101 double Fmix_LJ::computeUniform(const std::vector<double>& N, std::vector<double>& Phi_N) const
102 { unsigned i1 = fluid1->offsetDensity;
103 unsigned i2 = fluid2->offsetDensity;
104 Phi_N[i1] += ljatt(0)*N[i2];
105 Phi_N[i2] += ljatt(0)*N[i1];
106 return N[i1]*ljatt(0)*N[i2];
107 }
108
109
Fmix_GaussianKernel(FluidMixture * fluidMixture,std::shared_ptr<FluidComponent> fluid1,std::shared_ptr<FluidComponent> fluid2,double Esolv,double Rsolv)110 Fmix_GaussianKernel::Fmix_GaussianKernel(FluidMixture* fluidMixture, std::shared_ptr<FluidComponent> fluid1, std::shared_ptr<FluidComponent> fluid2, double Esolv, double Rsolv)
111 : Fmix(fluidMixture), fluid1(fluid1), fluid2(fluid2)
112 {
113 string name1 = fluid1->molecule.name;
114 string name2 = fluid2->molecule.name;
115 logPrintf(" Initializing gaussian kernel mixing functional between %s and %s\n Rsolv: %lg and Esolv: %lg.\n",name1.c_str(),name2.c_str(),Rsolv,Esolv);
116 Kmul = -Esolv*(4*M_PI*pow(Rsolv,3))/3;
117 Ksolv.init(0, gInfo.dGradial, gInfo.GmaxGrid, RadialFunctionG::gaussTilde, 1.0, Rsolv/sqrt(2));
118
119 }
120
~Fmix_GaussianKernel()121 Fmix_GaussianKernel::~Fmix_GaussianKernel()
122 {
123
124 }
125
getName() const126 string Fmix_GaussianKernel::getName() const
127 {
128 return fluid1->molecule.name + "<->" + fluid2->molecule.name;
129 }
130
computeUniform(const std::vector<double> & N,std::vector<double> & Phi_N) const131 double Fmix_GaussianKernel::computeUniform(const std::vector< double >& N, std::vector< double >& Phi_N) const
132 {
133 unsigned i1 = fluid1->offsetDensity;
134 unsigned i2 = fluid2->offsetDensity;
135 Phi_N[i1] += Kmul*Ksolv(0)*N[i2];
136 Phi_N[i2] += Kmul*Ksolv(0)*N[i1];
137 return N[i1]*Kmul*Ksolv(0)*N[i2];
138 }
139
compute(const ScalarFieldTildeArray & Ntilde,ScalarFieldTildeArray & Phi_Ntilde) const140 double Fmix_GaussianKernel::compute(const ScalarFieldTildeArray& Ntilde, ScalarFieldTildeArray& Phi_Ntilde) const
141 {
142 unsigned i1 = fluid1->offsetDensity;
143 unsigned i2 = fluid2->offsetDensity;
144 ScalarFieldTilde V1 = gInfo.nr * Kmul*(Ksolv * Ntilde[i1]);
145 ScalarFieldTilde V2 = gInfo.nr * Kmul*(Ksolv * Ntilde[i2]);
146 Phi_Ntilde[i1] += V2;
147 Phi_Ntilde[i2] += V1;
148 return gInfo.dV*dot(V1,Ntilde[i2]);
149 }
150