#ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #ifdef USING_NAMESPACE_STD using namespace std; #endif using namespace sc; static inline double get_ki(int z) { // The ki values (used in the computation of the dispersion coefficients) // for H, C, and N were taken from Vigne-Maeder and Claverie, JACS 1987, v109, pp24-28 // and the value for O from Huron and Claverie, J. Phys. Chem. 1974, v78, p1862 double ki; if (z <= 0) { ExEnv::errn() << "Non-positive nuclear charge encountered in computation of" << " dispersion coefficient" << endl; abort(); } else if (z == 1) ki = 1.0; else if (z == 6) ki = 1.0; else if (z == 7) ki = 1.18; else if (z == 8) ki = 1.36; // from Huron & Claverie, J.Phys.Chem v78, 1974, p1862 else if (z > 1 && z < 6) { ki = 1.0; ExEnv::out0() << "Warning: No d6 dispersion coefficient available for atomic number " << z << "; using value for carbon instead" << endl; } else { ki = 1.18; ExEnv::out0() << "Warning: No d6 dispersion coefficient available for atomic number " << z << "; using value for nitrogen instead" << endl; } return ki; } static inline double get_d6ii(int z, double r_vdw) { // The dispersion coefficient d6 for a pair of atoms ij can be computed // from the dispersion coefficient d6ii for atom pair ii and d6jj for // atom pair jj by the formula: d6 = sqrt(d6ii*d6jj). // The dispersion coefficients d8 and d10 can be obtained from d6. // The d6ii values given below were taken from: Vigne-Maeder and Claverie // JACS 1987, v. 109, pp. 24-28. const double a6 = 0.143; // [kcal/mol] double d6ii; double ki; Ref unit = new Units("kcal/mol"); ki = get_ki(z); d6ii = ki*ki*a6*pow(4*r_vdw*r_vdw,3.0); // units of (kcal mol^-1)*bohr^6 d6ii *= unit->to_atomic_units(); // convert to atomic units return d6ii; } static inline double get_d8ii(double d6ii, double r_vdw) { // The value of c8 was taken from Vigne-Maeder and Claverie, JACS 1987, // v. 109, pp 24-28 and is here obtained in atomic units by using // atomic units for d6ii and r_vdw double d8ii; const double c8 = 0.26626; d8ii = d6ii*c8*4*pow(r_vdw,2.0); return d8ii; } static inline double get_d10ii(double d6ii, double r_vdw) { // The value of c10 was taken from Vigne-Maeder and Claverie, JACS 1987, // v. 109, pp 24-28 and is here obtained in atomic units by using // atomic units for d6ii and r_vdw double d10ii; const double c10 = 0.095467; d10ii = d6ii*c10*16*pow(r_vdw,4.0); return d10ii; } // For debugging compute 6, 8, and 10 contributions separately static inline double disp6_contrib(double rasnorm, double d6) { double edisp6_contrib; edisp6_contrib = d6/(3*pow(rasnorm,6.0)); // atomic units return edisp6_contrib; } static inline double disp8_contrib(double rasnorm, double d8) { double edisp8_contrib; edisp8_contrib = d8/(5*pow(rasnorm,8.0)); // atomic units return edisp8_contrib; } static inline double disp10_contrib(double rasnorm, double d10) { double edisp10_contrib; edisp10_contrib = d10/(7*pow(rasnorm,10.0)); // atomic units return edisp10_contrib; } static inline double disp_contrib(double rasnorm, double d6, double d8, double d10) { double edisp_contrib; edisp_contrib = d6/(3*pow(rasnorm,6.0)) + d8/(5*pow(rasnorm,8.0)) + d10/(7*pow(rasnorm,10.0)); return edisp_contrib; } static inline double rep_contrib(double rasnorm, double ri_vdw, double rj_vdw, double ki, double kj, double kcalpermol_to_hartree) { // The expression and the parameters used for the repulsion energy // were taken from Vigne-Maeder and Claverie, JACS 1987, v109, pp24-28 // NB: We have omitted the factor Gij const double c = 90000; // [kcal/mol] const double gamma = 12.35; double erep_contrib; double tmp; tmp = gamma*rasnorm/(2.0*sqrt(ri_vdw*rj_vdw)); erep_contrib = -ki*kj*c*(1.0/tmp + 2.0/(tmp*tmp) + 2.0/(tmp*tmp*tmp))*exp(-tmp); erep_contrib *= kcalpermol_to_hartree; // convert from kcal/mol to atomic units return erep_contrib; } double BEMSolvent::disprep() { double edisprep = 0.0; double edisprep_contrib; double edisp6_contrib, edisp8_contrib, edisp10_contrib; // for debugging double erep_contrib; double edisp6 = 0.0; // for debugging double edisp8 = 0.0; // for debugging double edisp10 = 0.0; // for debugging double erep = 0.0; double proberadius; double radius; double rasnorm; double weight; double d6, d8, d10; // dispersion coefficients double d6aa, d8aa, d10aa; // dispersion coefficients for atom pair aa double d6ss, d8ss, d10ss; // dispersion coefficients for atom pair ss int i, iloop, isolute; int natomtypes; int z_solvent_atom; Ref unit = new Units("kcal/mol"); double kcalpermol_to_hartree = unit->to_atomic_units(); Ref atominfo = solute_->atominfo(); Ref solventatominfo = solvent_->atominfo(); MolecularFormula formula(solvent_); // Compute number of different atom types in solvent molecule natomtypes = formula.natomtypes(); double *solute_d6ii = new double[solute_->natom()]; double *solute_d8ii = new double[solute_->natom()]; double *solute_d10ii = new double[solute_->natom()]; double *solute_ki = new double[solute_->natom()]; for (isolute=0; isolutenatom(); isolute++) { int Z_solute = solute_->Z(isolute); double radius = atominfo->vdw_radius(Z_solute); solute_d6ii[isolute] = get_d6ii(Z_solute,radius); solute_d8ii[isolute] = get_d8ii(solute_d6ii[isolute],radius); solute_d10ii[isolute] = get_d10ii(solute_d6ii[isolute],radius); solute_ki[isolute] = get_ki(Z_solute); } // Loop over atom types in solvent molecule for (iloop=0; iloop us = new UnionShape; z_solvent_atom = formula.Z(iloop); proberadius = solventatominfo->vdw_radius(z_solvent_atom); for (i=0; inatom(); i++) { us->add_shape(new SphereShape(solute_->r(i), atominfo->vdw_radius(solute_->Z(i))+proberadius)); } // triangulate the surface Ref keyval = new AssignedKeyVal; keyval->assign("volume", us.pointer()); keyval->assign("order", 2); keyval->assign("remove_short_edges", 1); keyval->assign("remove_small_triangles", 1); keyval->assign("remove_slender_triangles", 1); keyval->assign("short_edge_factor", 0.8); keyval->assign("small_triangle_factor", 0.8); keyval->assign("slender_triangle_factor", 0.8); Ref ts = new TriangulatedImplicitSurface(keyval.pointer()); ts->init(); // Debug print: check the triangulated surface // if (iloop == 0) { // ofstream geomviewfile("geomview.input"); // ts->print_geomview_format(geomviewfile); // } ExEnv::out0().setf(ios::scientific,ios::floatfield); // use scientific format ExEnv::out0() << "Area of disp-rep surface generated with atom number " << setw(3) << setfill(' ') << z_solvent_atom << " as probe: " << setprecision(4) << ts->area() << " bohr^2" << endl; edisprep_contrib = 0.0; edisp6_contrib = 0.0; // for debugging edisp8_contrib = 0.0; // for debugging edisp10_contrib = 0.0; // for debugging erep_contrib = 0.0; TriangulatedSurfaceIntegrator triint(ts.pointer()); double solvent_ki = get_ki(z_solvent_atom); d6ss = get_d6ii(z_solvent_atom,proberadius); d8ss = get_d8ii(d6ss, proberadius); d10ss = get_d10ii(d6ss, proberadius); // integrate the surface for (triint=0; triint.update(); triint++) { SCVector3 dA = triint.dA(); SCVector3 location = triint.current()->point(); weight = triint.weight(); //Loop over atoms in solute for (isolute=0; isolutenatom(); isolute++) { SCVector3 atom(solute_->r(isolute)); SCVector3 ras = location - atom; rasnorm = ras.norm(); radius = atominfo->vdw_radius(solute_->Z(isolute)); d6aa = solute_d6ii[isolute]; d8aa = solute_d8ii[isolute]; d10aa = solute_d10ii[isolute]; d6 = sqrt(d6aa*d6ss); d8 = sqrt(d8aa*d8ss); d10 = sqrt(d10aa*d10ss); double f = ras.dot(dA)*weight; double tdisp6 = f*disp6_contrib(rasnorm,d6); double tdisp8 = f*disp8_contrib(rasnorm,d8); double tdisp10 = f*disp10_contrib(rasnorm,d10); double trep = f*rep_contrib(rasnorm,radius,proberadius, solute_ki[isolute],solvent_ki, kcalpermol_to_hartree); double tdisp = tdisp6+tdisp8+tdisp10; // add in contributions to various energies; the minus sign // is there to get the normal pointing into the cavity edisprep_contrib -= tdisp+trep; edisp6_contrib -= tdisp6; edisp8_contrib -= tdisp8; edisp10_contrib -= tdisp10; erep_contrib -= trep; } } edisprep += edisprep_contrib*formula.nZ(iloop); edisp6 += edisp6_contrib*formula.nZ(iloop); edisp8 += edisp8_contrib*formula.nZ(iloop); edisp10 += edisp10_contrib*formula.nZ(iloop); erep += erep_contrib*formula.nZ(iloop); } delete[] solute_d6ii; delete[] solute_d8ii; delete[] solute_d10ii; delete[] solute_ki; // Multiply energies by number density of solvent // Print out individual energy contributions in kcal/mol ExEnv::out0().setf(ios::scientific,ios::floatfield); // use scientific format ExEnv::out0().precision(5); ExEnv::out0() << "Edisp6: " << edisp6*solvent_density_*unit->from_atomic_units() << " kcal/mol" << endl; ExEnv::out0() << "Edisp8: " << edisp8*solvent_density_*unit->from_atomic_units() << " kcal/mol" << endl; ExEnv::out0() << "Edisp10: " << edisp10*solvent_density_*unit->from_atomic_units() << " kcal/mol" << endl; ExEnv::out0() << "Total dispersion energy: " << (edisp6 + edisp8 + edisp10)*solvent_density_*unit->from_atomic_units() << " kcal/mol" << endl; ExEnv::out0() << "Repulsion energy: " << setw(12) << setfill(' ') << erep*solvent_density_*unit->from_atomic_units() << " kcal/mol" << endl; return edisprep*solvent_density_; // atomic units }