// This file is part of the ESPResSo distribution (http://www.espresso.mpg.de).
// It is therefore subject to the ESPResSo license agreement which you accepted upon receiving the distribution
// and by which you are legally bound while utilizing this file in any form or way.
// There is NO WARRANTY, not even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// You should have received a copy of that license along with this program;
// if not, refer to http://www.espresso.mpg.de/license.html where its current version can be found, or
// write to Max-Planck-Institute for Polymer Research, Theory Group, PO Box 3148, 55021 Mainz, Germany.
// Copyright (c) 2002-2006; all rights reserved unless otherwise stated.
#ifndef SUBT_GB_H
#define SUBT_GB_H
/** \file subt_gb.h
* Routines to calculate and subtract the Gay-Berne energy, torque and force
* for a pair of particles.
* \ref forces.c
*
* Responsible:
* Dmytro
*/
#ifdef ROTATION
/// set the parameters for the subtract GB potential
MDINLINE int subt_gb_set_params(int bond_type, double k, double r)
{
if(bond_type < 0)
return TCL_ERROR;
make_bond_type_exist(bond_type);
bonded_ia_params[bond_type].p.subt_gb.k = k;
bonded_ia_params[bond_type].p.subt_gb.r = r;
bonded_ia_params[bond_type].type = BONDED_IA_SUBT_GB;
bonded_ia_params[bond_type].p.subt_gb.r2 = SQR(bonded_ia_params[bond_type].p.subt_gb.r);
bonded_ia_params[bond_type].num = 1;
mpi_bcast_ia_params(bond_type, -1);
return TCL_OK;
}
/// parse parameters for the subt_lj potential
MDINLINE int inter_parse_subt_gb(Tcl_Interp *interp, int bond_type, int argc, char **argv)
{
double k, r;
if (argc != 3) {
Tcl_AppendResult(interp, "subt_gb needs 2 dummy parameters: "
" ", (char *) NULL);
return TCL_ERROR;
}
if ((! ARG_IS_D(1, k)) || (! ARG_IS_D(2, r))) {
Tcl_AppendResult(interp, "subt_gb needs 2 dummy DOUBLE parameters: "
" ", (char *) NULL);
return TCL_ERROR;
}
CHECK_VALUE(subt_gb_set_params(bond_type, k, r), "bond type must be nonnegative");
}
MDINLINE int calc_subt_gb_pair_force(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams,
double d[3], double force[3], double torque1[3], double torque2[3])
{
double Brack,BrackCut, Bra6,Bra6Cut, Bra12,Bra12Cut, Bra7,Bra7Cut, Bra13,Bra13Cut;
double u1x, u1y, u1z,u2x, u2y, u2z, a, b, c;
double chi2,chip2,X, Xcut;
double E1,E2,E1E2, Sigma,soft;
double apb,amb,apb2,amb2;
double dU_dr, dU_da, dU_db, dU_dc; /* all derivatives */
double denp,denm,denpp,denmp,den2,rep,repp,rem,remp,tmp,tmpp,den;
double FikX,FikY,FikZ,dU_dc1,dU_dc2,dU_dc3;
/* help for forces */
// double Gx,Gy,Gz;
/* help for torques */
IA_parameters *ia_params;
double dist2 = sqrlen(d);
double dist = sqrt(dist2);
ia_params = get_ia_param(p1->p.type,p2->p.type);
if(dist >= iaparams->p.subt_gb.r) return 1;
if (dist < ia_params->GB_cut && ia_params->GB_eps != 0) {
u1x=p1->r.quatu[0];u1y=p1->r.quatu[1];u1z=p1->r.quatu[2];
u2x=p2->r.quatu[0];u2y=p2->r.quatu[1];u2z=p2->r.quatu[2];
a = (d[0]*u1x+ d[1]*u1y+d[2]*u1z)/dist;
b = (d[0]*u2x+ d[1]*u2y+d[2]*u2z)/dist;
c = u1x*u2x + u1y*u2y + u1z*u2z;
chi2 = ia_params->GB_chi1*ia_params->GB_chi1;
chip2 = ia_params->GB_chi2*ia_params->GB_chi2;
tmp = ia_params->GB_chi1*c; denp = 1.0 + tmp ; denm = 1.0 - tmp ;
tmp = ia_params->GB_chi2*c; denpp = 1.0 + tmp ; denmp = 1.0 - tmp ;
den2 = 1.0 - chi2*c*c;
apb = a+b;
amb = a-b;
apb2=apb*apb;
amb2=amb*amb;
/******************************************************/
/* Gay-Berne epsilon function */
E1 = 1. / sqrt( den2 ) ;
/* Gay-Berne epsilon prime function */
E2 = 1.0 - 0.5 * ia_params->GB_chi2 * (apb2/denpp + amb2/denmp ) ;
/* Gay-Berne well */
if (ia_params->GB_mu == 2 && ia_params->GB_nu == 1) {
E1E2 = ia_params->GB_eps*E1*E2*E2;
} else {
E1E2 = ia_params->GB_eps*pow(E1,ia_params->GB_nu)*pow(E2,ia_params->GB_mu);
}
// well = POWNU(eps) * POWMU(epsp) ;
/* Gay-Berne sigma function */
den = sqrt(1.0- 0.5* ia_params->GB_chi1 *(apb2/denp+amb2/denm )) ;
Sigma = ia_params->GB_sig/den;
soft=ia_params->GB_sig*1.00;
X = soft/(dist - Sigma + soft);
Xcut = soft/(ia_params->GB_cut - Sigma + soft);
Bra6 = X*X*X;
Bra6 = Bra6*Bra6;
Bra7 = Bra6*X;
Bra12 = Bra6*Bra6;
Bra13 = Bra12*X;
Brack = Bra6*(Bra6-1);
if (ia_params->GB_cut > 0.0)
{Bra6Cut = Xcut*Xcut*Xcut;
Bra6Cut = Bra6Cut*Bra6Cut;
Bra7Cut = Bra6Cut*Xcut;
Bra12Cut = Bra6Cut*Bra6Cut;
Bra13Cut = Bra12Cut*Xcut;
BrackCut = Bra6Cut*(Bra6Cut-1);
Bra7 = Bra7-Bra7Cut;
Bra13 = Bra13-Bra13Cut;
Brack = Brack-BrackCut;}
if (X < 1.5) { /* 1.25 corresponds to the interparticle penetration of 0.2 units of length.
If they are not that close, the GB forces and torques are calculated */
/***************************************************/
/* forces and torques between pair of molecules */
rep = (apb)/denp ;
rem = (amb)/denm ;
repp = (apb)/denpp ;
remp = (amb)/denmp ;
/* derivative of potential energy with respect to molecular distance r(12) */
tmp = 3.0 * E1E2 * ( 2.0 * Bra13 - Bra7) ;
dU_dr = - 2.0 * tmp /ia_params->GB_sig;
tmp *= ia_params->GB_chi1 / (den*den*den );
/* derivative of potential energy
with respect to cos(theta1) */
tmpp = E1E2*ia_params->GB_mu*Brack*ia_params->GB_chi2/E2;
dU_da = -tmpp*(repp+remp) + tmp*(rep+rem) ;
/* derivative of potential energy with respect to cos(theta2) */
dU_db = -tmpp*(repp-remp) + tmp*(rep-rem) ;
/* derivative of potential energy with respect to cos(phi12) */
dU_dc = E1E2*Brack*(ia_params->GB_nu*chi2*c/den2
+ 0.5*ia_params->GB_mu*chip2*(remp*remp-repp*repp)/E2)
- 0.5*tmp*ia_params->GB_chi1*(rem*rem-rep*rep);
/* rescale */
dU_dr = 4*dU_dr/dist ;
dU_da = 4*dU_da/dist ;
dU_db = 4*dU_db/dist ;
dU_dc = 4*dU_dc*1.;
dU_dc1 = dU_dc*(u1y*u2z-u1z*u2y);
dU_dc2 = dU_dc*(u1z*u2x-u1x*u2z);
dU_dc3 = dU_dc*(u1x*u2y-u1y*u2x);
a /= dist ;
b /= dist ;
/* force on molecule 1 due to molecule 2 */
force[0] = (dU_dr*d[0]+dU_da*(u1x-a*d[0])+dU_db*(u2x-b*d[0]));
force[1] = (dU_dr*d[1]+dU_da*(u1y-a*d[1])+dU_db*(u2y-b*d[1]));
force[2] = (dU_dr*d[2]+dU_da*(u1z-a*d[2])+dU_db*(u2z-b*d[2]));
/* torque on molecule 1 due to molecule 2 */
torque1[0] = (dU_da*(u1y*d[2]-u1z*d[1])-dU_dc1);
torque1[1] = (dU_da*(u1z*d[0]-u1x*d[2])-dU_dc2);
torque1[2] = (dU_da*(u1x*d[1]-u1y*d[0])-dU_dc3);
/* torque on molecule 2 due to molecule 1 */
torque2[0] = (dU_db*(u2y*d[2]-u2z*d[1])+dU_dc1);
torque2[1] = (dU_db*(u2z*d[0]-u2x*d[2])+dU_dc2);
torque2[2] = (dU_db*(u2x*d[1]-u2y*d[0])+dU_dc3);
}
else { /* the particles are too close to each other */
/* derivative of potential energy with respect to molecular distance r(12) */
tmp = 3.0 * E1E2 * X * ( 2.0 * Bra12 - Bra6 ) ;
dU_dr = - 2.0 * tmp / ia_params->GB_sig;
if (dU_dr > 0.) {dU_dr = 10/dist;} else {dU_dr = -10/dist;}
FikX = dU_dr * d[0];
FikY = dU_dr * d[1];
FikZ = dU_dr * d[2];
force[0] = FikX;
force[1] = FikY;
force[2] = FikZ;
}
}
// if (p1->p.identity==0 && p2->p.identity == 1) {printf("sub %f %f %f \n",torque1[0],torque1[1],torque1[2]);}
// if (p1->p.identity==1 && p2->p.identity == 0) {printf("sub %f %f %f \n",torque1[0],torque1[1],torque1[2]);}
// if (p1->p.identity==1 && p2->p.identity == 2) {printf("sub12 %f %f %f \n",FikX,FikY,FikZ);}
// if (p1->p.identity==2 && p2->p.identity == 1) {printf("sub21 %f %f %f \n",FikX,FikY,FikZ);}
return 0;
}
MDINLINE double subt_gb_pair_energy(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams,
double d[3], double *_energy)
{double a,b,c, X, Xcut,
Brack,BrackCut,
u1x, u1y, u1z, u2x, u2y, u2z,
E,E1,E2,soft,
Sigma,tmp,chi2,denp,denpp,denm,denmp,apb2,amb2,apb,amb;
IA_parameters *ia_params;
double dist2 = sqrlen(d);
double dist = sqrt(dist2);
if(dist >= iaparams->p.subt_gb.r) return 1;
ia_params = get_ia_param(p1->p.type,p2->p.type);
u1x=p1->r.quatu[0];u1y=p1->r.quatu[1];u1z=p1->r.quatu[2];
u2x=p2->r.quatu[0];u2y=p2->r.quatu[1];u2z=p2->r.quatu[2];
a = (d[0]*u1x+ d[1]*u1y+d[2]*u1z)/dist;
b = (d[0]*u2x+ d[1]*u2y+d[2]*u2z)/dist;
c = u1x*u2x + u1y*u2y + u1z*u2z;
chi2 = ia_params->GB_chi1*ia_params->GB_chi1;
tmp = ia_params->GB_chi1*c; denp = 1.0 + tmp ; denm = 1.0 - tmp ;
tmp = ia_params->GB_chi2*c; denpp = 1.0 + tmp ; denmp = 1.0 - tmp ;
apb = a+b; amb = a-b;
apb2=apb*apb; amb2=amb*amb;
E1 = 1. / sqrt(1.0 - chi2*c*c) ;
E2 = 1.0 - 0.5 * ia_params->GB_chi2 * (apb2/denpp + amb2/denmp ) ;
E = 4*ia_params->GB_eps*pow(E1,ia_params->GB_nu)*pow(E2,ia_params->GB_mu);
Sigma = ia_params->GB_sig/sqrt(1.0-0.5*ia_params->GB_chi1*(apb2/denp+amb2/denm));
soft = ia_params->GB_sig*1.00;
X = soft/(dist - Sigma + soft);
Xcut = soft/(ia_params->GB_cut - Sigma + soft);
Brack = X*X*X;
Brack *= Brack;
Brack = Brack*Brack-Brack;
if (ia_params->GB_cut > 0.0)
{
BrackCut = Xcut*Xcut*Xcut;
BrackCut *= BrackCut;
BrackCut = BrackCut*BrackCut-BrackCut;
Brack = Brack-BrackCut;
}
*_energy = - E*Brack;
// if (p1->p.identity == 0 && p2->p.identity== 1){printf("subtracting: %f \n",(-E*(Brack-BrackCut)) );}
// if (p1->p.identity == 1 && p2->p.identity== 0){printf("subtracting: %f \n",(-E*(Brack-BrackCut)) );}
return 0;
}
#endif
#endif