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