[0b990d] | 1 |
|
---|
| 2 | #ifdef HAVE_CONFIG_H
|
---|
| 3 | #include <scconfig.h>
|
---|
| 4 | #endif
|
---|
| 5 |
|
---|
| 6 | #include <fstream>
|
---|
| 7 |
|
---|
| 8 | #include <util/keyval/keyval.h>
|
---|
| 9 | #include <math/isosurf/shape.h>
|
---|
| 10 | #include <chemistry/qc/wfn/solvent.h>
|
---|
| 11 | #include <chemistry/molecule/formula.h>
|
---|
| 12 |
|
---|
| 13 | #ifdef USING_NAMESPACE_STD
|
---|
| 14 | using namespace std;
|
---|
| 15 | #endif
|
---|
| 16 | using namespace sc;
|
---|
| 17 |
|
---|
| 18 | static inline double
|
---|
| 19 | get_ki(int z)
|
---|
| 20 | {
|
---|
| 21 | // The ki values (used in the computation of the dispersion coefficients)
|
---|
| 22 | // for H, C, and N were taken from Vigne-Maeder and Claverie, JACS 1987, v109, pp24-28
|
---|
| 23 | // and the value for O from Huron and Claverie, J. Phys. Chem. 1974, v78, p1862
|
---|
| 24 |
|
---|
| 25 | double ki;
|
---|
| 26 |
|
---|
| 27 | if (z <= 0) {
|
---|
| 28 | ExEnv::errn() << "Non-positive nuclear charge encountered in computation of"
|
---|
| 29 | << " dispersion coefficient" << endl;
|
---|
| 30 | abort();
|
---|
| 31 | }
|
---|
| 32 | else if (z == 1) ki = 1.0;
|
---|
| 33 | else if (z == 6) ki = 1.0;
|
---|
| 34 | else if (z == 7) ki = 1.18;
|
---|
| 35 | else if (z == 8) ki = 1.36; // from Huron & Claverie, J.Phys.Chem v78, 1974, p1862
|
---|
| 36 | else if (z > 1 && z < 6) {
|
---|
| 37 | ki = 1.0;
|
---|
| 38 | ExEnv::out0() << "Warning: No d6 dispersion coefficient available for atomic number " <<
|
---|
| 39 | z << "; using value for carbon instead" << endl;
|
---|
| 40 | }
|
---|
| 41 | else {
|
---|
| 42 | ki = 1.18;
|
---|
| 43 | ExEnv::out0() << "Warning: No d6 dispersion coefficient available for atomic number " <<
|
---|
| 44 | z << "; using value for nitrogen instead" << endl;
|
---|
| 45 | }
|
---|
| 46 |
|
---|
| 47 | return ki;
|
---|
| 48 | }
|
---|
| 49 |
|
---|
| 50 | static inline double
|
---|
| 51 | get_d6ii(int z, double r_vdw)
|
---|
| 52 | {
|
---|
| 53 | // The dispersion coefficient d6 for a pair of atoms ij can be computed
|
---|
| 54 | // from the dispersion coefficient d6ii for atom pair ii and d6jj for
|
---|
| 55 | // atom pair jj by the formula: d6 = sqrt(d6ii*d6jj).
|
---|
| 56 | // The dispersion coefficients d8 and d10 can be obtained from d6.
|
---|
| 57 | // The d6ii values given below were taken from: Vigne-Maeder and Claverie
|
---|
| 58 | // JACS 1987, v. 109, pp. 24-28.
|
---|
| 59 |
|
---|
| 60 | const double a6 = 0.143; // [kcal/mol]
|
---|
| 61 | double d6ii;
|
---|
| 62 | double ki;
|
---|
| 63 |
|
---|
| 64 | Ref<Units> unit = new Units("kcal/mol");
|
---|
| 65 |
|
---|
| 66 | ki = get_ki(z);
|
---|
| 67 | d6ii = ki*ki*a6*pow(4*r_vdw*r_vdw,3.0); // units of (kcal mol^-1)*bohr^6
|
---|
| 68 | d6ii *= unit->to_atomic_units(); // convert to atomic units
|
---|
| 69 | return d6ii;
|
---|
| 70 | }
|
---|
| 71 |
|
---|
| 72 | static inline double
|
---|
| 73 | get_d8ii(double d6ii, double r_vdw)
|
---|
| 74 | {
|
---|
| 75 | // The value of c8 was taken from Vigne-Maeder and Claverie, JACS 1987,
|
---|
| 76 | // v. 109, pp 24-28 and is here obtained in atomic units by using
|
---|
| 77 | // atomic units for d6ii and r_vdw
|
---|
| 78 |
|
---|
| 79 | double d8ii;
|
---|
| 80 | const double c8 = 0.26626;
|
---|
| 81 |
|
---|
| 82 | d8ii = d6ii*c8*4*pow(r_vdw,2.0);
|
---|
| 83 |
|
---|
| 84 | return d8ii;
|
---|
| 85 | }
|
---|
| 86 |
|
---|
| 87 | static inline double
|
---|
| 88 | get_d10ii(double d6ii, double r_vdw)
|
---|
| 89 | {
|
---|
| 90 | // The value of c10 was taken from Vigne-Maeder and Claverie, JACS 1987,
|
---|
| 91 | // v. 109, pp 24-28 and is here obtained in atomic units by using
|
---|
| 92 | // atomic units for d6ii and r_vdw
|
---|
| 93 |
|
---|
| 94 | double d10ii;
|
---|
| 95 | const double c10 = 0.095467;
|
---|
| 96 |
|
---|
| 97 | d10ii = d6ii*c10*16*pow(r_vdw,4.0);
|
---|
| 98 |
|
---|
| 99 | return d10ii;
|
---|
| 100 | }
|
---|
| 101 |
|
---|
| 102 | // For debugging compute 6, 8, and 10 contributions separately
|
---|
| 103 | static inline double
|
---|
| 104 | disp6_contrib(double rasnorm, double d6)
|
---|
| 105 | {
|
---|
| 106 | double edisp6_contrib;
|
---|
| 107 |
|
---|
| 108 | edisp6_contrib = d6/(3*pow(rasnorm,6.0)); // atomic units
|
---|
| 109 |
|
---|
| 110 | return edisp6_contrib;
|
---|
| 111 | }
|
---|
| 112 |
|
---|
| 113 | static inline double
|
---|
| 114 | disp8_contrib(double rasnorm, double d8)
|
---|
| 115 | {
|
---|
| 116 | double edisp8_contrib;
|
---|
| 117 |
|
---|
| 118 | edisp8_contrib = d8/(5*pow(rasnorm,8.0)); // atomic units
|
---|
| 119 |
|
---|
| 120 | return edisp8_contrib;
|
---|
| 121 | }
|
---|
| 122 |
|
---|
| 123 | static inline double
|
---|
| 124 | disp10_contrib(double rasnorm, double d10)
|
---|
| 125 | {
|
---|
| 126 | double edisp10_contrib;
|
---|
| 127 |
|
---|
| 128 | edisp10_contrib = d10/(7*pow(rasnorm,10.0)); // atomic units
|
---|
| 129 |
|
---|
| 130 | return edisp10_contrib;
|
---|
| 131 | }
|
---|
| 132 |
|
---|
| 133 | static inline double
|
---|
| 134 | disp_contrib(double rasnorm, double d6, double d8, double d10)
|
---|
| 135 | {
|
---|
| 136 | double edisp_contrib;
|
---|
| 137 |
|
---|
| 138 | edisp_contrib = d6/(3*pow(rasnorm,6.0)) + d8/(5*pow(rasnorm,8.0))
|
---|
| 139 | + d10/(7*pow(rasnorm,10.0));
|
---|
| 140 |
|
---|
| 141 | return edisp_contrib;
|
---|
| 142 | }
|
---|
| 143 |
|
---|
| 144 | static inline double
|
---|
| 145 | rep_contrib(double rasnorm, double ri_vdw, double rj_vdw, double ki, double kj,
|
---|
| 146 | double kcalpermol_to_hartree)
|
---|
| 147 | {
|
---|
| 148 | // The expression and the parameters used for the repulsion energy
|
---|
| 149 | // were taken from Vigne-Maeder and Claverie, JACS 1987, v109, pp24-28
|
---|
| 150 | // NB: We have omitted the factor Gij
|
---|
| 151 |
|
---|
| 152 | const double c = 90000; // [kcal/mol]
|
---|
| 153 | const double gamma = 12.35;
|
---|
| 154 | double erep_contrib;
|
---|
| 155 | double tmp;
|
---|
| 156 |
|
---|
| 157 | tmp = gamma*rasnorm/(2.0*sqrt(ri_vdw*rj_vdw));
|
---|
| 158 |
|
---|
| 159 | erep_contrib = -ki*kj*c*(1.0/tmp + 2.0/(tmp*tmp) + 2.0/(tmp*tmp*tmp))*exp(-tmp);
|
---|
| 160 | erep_contrib *= kcalpermol_to_hartree; // convert from kcal/mol to atomic units
|
---|
| 161 |
|
---|
| 162 | return erep_contrib;
|
---|
| 163 | }
|
---|
| 164 |
|
---|
| 165 | double
|
---|
| 166 | BEMSolvent::disprep()
|
---|
| 167 | {
|
---|
| 168 | double edisprep = 0.0;
|
---|
| 169 | double edisprep_contrib;
|
---|
| 170 | double edisp6_contrib, edisp8_contrib, edisp10_contrib; // for debugging
|
---|
| 171 | double erep_contrib;
|
---|
| 172 | double edisp6 = 0.0; // for debugging
|
---|
| 173 | double edisp8 = 0.0; // for debugging
|
---|
| 174 | double edisp10 = 0.0; // for debugging
|
---|
| 175 | double erep = 0.0;
|
---|
| 176 | double proberadius;
|
---|
| 177 | double radius;
|
---|
| 178 | double rasnorm;
|
---|
| 179 | double weight;
|
---|
| 180 | double d6, d8, d10; // dispersion coefficients
|
---|
| 181 | double d6aa, d8aa, d10aa; // dispersion coefficients for atom pair aa
|
---|
| 182 | double d6ss, d8ss, d10ss; // dispersion coefficients for atom pair ss
|
---|
| 183 | int i, iloop, isolute;
|
---|
| 184 | int natomtypes;
|
---|
| 185 | int z_solvent_atom;
|
---|
| 186 |
|
---|
| 187 | Ref<Units> unit = new Units("kcal/mol");
|
---|
| 188 | double kcalpermol_to_hartree = unit->to_atomic_units();
|
---|
| 189 |
|
---|
| 190 | Ref<AtomInfo> atominfo = solute_->atominfo();
|
---|
| 191 | Ref<AtomInfo> solventatominfo = solvent_->atominfo();
|
---|
| 192 | MolecularFormula formula(solvent_);
|
---|
| 193 |
|
---|
| 194 | // Compute number of different atom types in solvent molecule
|
---|
| 195 | natomtypes = formula.natomtypes();
|
---|
| 196 |
|
---|
| 197 | double *solute_d6ii = new double[solute_->natom()];
|
---|
| 198 | double *solute_d8ii = new double[solute_->natom()];
|
---|
| 199 | double *solute_d10ii = new double[solute_->natom()];
|
---|
| 200 | double *solute_ki = new double[solute_->natom()];
|
---|
| 201 |
|
---|
| 202 | for (isolute=0; isolute<solute_->natom(); isolute++) {
|
---|
| 203 | int Z_solute = solute_->Z(isolute);
|
---|
| 204 | double radius = atominfo->vdw_radius(Z_solute);
|
---|
| 205 | solute_d6ii[isolute] = get_d6ii(Z_solute,radius);
|
---|
| 206 | solute_d8ii[isolute] = get_d8ii(solute_d6ii[isolute],radius);
|
---|
| 207 | solute_d10ii[isolute] = get_d10ii(solute_d6ii[isolute],radius);
|
---|
| 208 | solute_ki[isolute] = get_ki(Z_solute);
|
---|
| 209 | }
|
---|
| 210 |
|
---|
| 211 | // Loop over atom types in solvent molecule
|
---|
| 212 | for (iloop=0; iloop<natomtypes; iloop++) {
|
---|
| 213 |
|
---|
| 214 | // define the shape of the surface for current atom type
|
---|
| 215 | Ref<UnionShape> us = new UnionShape;
|
---|
| 216 | z_solvent_atom = formula.Z(iloop);
|
---|
| 217 | proberadius = solventatominfo->vdw_radius(z_solvent_atom);
|
---|
| 218 | for (i=0; i<solute_->natom(); i++) {
|
---|
| 219 | us->add_shape(new SphereShape(solute_->r(i),
|
---|
| 220 | atominfo->vdw_radius(solute_->Z(i))+proberadius));
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 | // triangulate the surface
|
---|
| 224 | Ref<AssignedKeyVal> keyval = new AssignedKeyVal;
|
---|
| 225 | keyval->assign("volume", us.pointer());
|
---|
| 226 | keyval->assign("order", 2);
|
---|
| 227 | keyval->assign("remove_short_edges", 1);
|
---|
| 228 | keyval->assign("remove_small_triangles", 1);
|
---|
| 229 | keyval->assign("remove_slender_triangles", 1);
|
---|
| 230 | keyval->assign("short_edge_factor", 0.8);
|
---|
| 231 | keyval->assign("small_triangle_factor", 0.8);
|
---|
| 232 | keyval->assign("slender_triangle_factor", 0.8);
|
---|
| 233 | Ref<TriangulatedImplicitSurface> ts = new TriangulatedImplicitSurface(keyval.pointer());
|
---|
| 234 | ts->init();
|
---|
| 235 |
|
---|
| 236 | // Debug print: check the triangulated surface
|
---|
| 237 | // if (iloop == 0) {
|
---|
| 238 | // ofstream geomviewfile("geomview.input");
|
---|
| 239 | // ts->print_geomview_format(geomviewfile);
|
---|
| 240 | // }
|
---|
| 241 |
|
---|
| 242 | ExEnv::out0().setf(ios::scientific,ios::floatfield); // use scientific format
|
---|
| 243 | ExEnv::out0() << "Area of disp-rep surface generated with atom number "
|
---|
| 244 | << setw(3) << setfill(' ') << z_solvent_atom
|
---|
| 245 | << " as probe: " << setprecision(4) << ts->area()
|
---|
| 246 | << " bohr^2" << endl;
|
---|
| 247 |
|
---|
| 248 | edisprep_contrib = 0.0;
|
---|
| 249 | edisp6_contrib = 0.0; // for debugging
|
---|
| 250 | edisp8_contrib = 0.0; // for debugging
|
---|
| 251 | edisp10_contrib = 0.0; // for debugging
|
---|
| 252 | erep_contrib = 0.0;
|
---|
| 253 | TriangulatedSurfaceIntegrator triint(ts.pointer());
|
---|
| 254 |
|
---|
| 255 | double solvent_ki = get_ki(z_solvent_atom);
|
---|
| 256 | d6ss = get_d6ii(z_solvent_atom,proberadius);
|
---|
| 257 | d8ss = get_d8ii(d6ss, proberadius);
|
---|
| 258 | d10ss = get_d10ii(d6ss, proberadius);
|
---|
| 259 |
|
---|
| 260 | // integrate the surface
|
---|
| 261 | for (triint=0; triint.update(); triint++) {
|
---|
| 262 | SCVector3 dA = triint.dA();
|
---|
| 263 | SCVector3 location = triint.current()->point();
|
---|
| 264 | weight = triint.weight();
|
---|
| 265 |
|
---|
| 266 | //Loop over atoms in solute
|
---|
| 267 | for (isolute=0; isolute<solute_->natom(); isolute++) {
|
---|
| 268 |
|
---|
| 269 | SCVector3 atom(solute_->r(isolute));
|
---|
| 270 | SCVector3 ras = location - atom;
|
---|
| 271 | rasnorm = ras.norm();
|
---|
| 272 | radius = atominfo->vdw_radius(solute_->Z(isolute));
|
---|
| 273 | d6aa = solute_d6ii[isolute];
|
---|
| 274 | d8aa = solute_d8ii[isolute];
|
---|
| 275 | d10aa = solute_d10ii[isolute];
|
---|
| 276 | d6 = sqrt(d6aa*d6ss);
|
---|
| 277 | d8 = sqrt(d8aa*d8ss);
|
---|
| 278 | d10 = sqrt(d10aa*d10ss);
|
---|
| 279 |
|
---|
| 280 | double f = ras.dot(dA)*weight;
|
---|
| 281 | double tdisp6 = f*disp6_contrib(rasnorm,d6);
|
---|
| 282 | double tdisp8 = f*disp8_contrib(rasnorm,d8);
|
---|
| 283 | double tdisp10 = f*disp10_contrib(rasnorm,d10);
|
---|
| 284 | double trep = f*rep_contrib(rasnorm,radius,proberadius,
|
---|
| 285 | solute_ki[isolute],solvent_ki,
|
---|
| 286 | kcalpermol_to_hartree);
|
---|
| 287 | double tdisp = tdisp6+tdisp8+tdisp10;
|
---|
| 288 |
|
---|
| 289 | // add in contributions to various energies; the minus sign
|
---|
| 290 | // is there to get the normal pointing into the cavity
|
---|
| 291 | edisprep_contrib -= tdisp+trep;
|
---|
| 292 | edisp6_contrib -= tdisp6;
|
---|
| 293 | edisp8_contrib -= tdisp8;
|
---|
| 294 | edisp10_contrib -= tdisp10;
|
---|
| 295 | erep_contrib -= trep;
|
---|
| 296 |
|
---|
| 297 | }
|
---|
| 298 | }
|
---|
| 299 |
|
---|
| 300 | edisprep += edisprep_contrib*formula.nZ(iloop);
|
---|
| 301 | edisp6 += edisp6_contrib*formula.nZ(iloop);
|
---|
| 302 | edisp8 += edisp8_contrib*formula.nZ(iloop);
|
---|
| 303 | edisp10 += edisp10_contrib*formula.nZ(iloop);
|
---|
| 304 | erep += erep_contrib*formula.nZ(iloop);
|
---|
| 305 | }
|
---|
| 306 |
|
---|
| 307 | delete[] solute_d6ii;
|
---|
| 308 | delete[] solute_d8ii;
|
---|
| 309 | delete[] solute_d10ii;
|
---|
| 310 | delete[] solute_ki;
|
---|
| 311 |
|
---|
| 312 | // Multiply energies by number density of solvent
|
---|
| 313 | // Print out individual energy contributions in kcal/mol
|
---|
| 314 |
|
---|
| 315 | ExEnv::out0().setf(ios::scientific,ios::floatfield); // use scientific format
|
---|
| 316 | ExEnv::out0().precision(5);
|
---|
| 317 | ExEnv::out0() << "Edisp6: " << edisp6*solvent_density_*unit->from_atomic_units()
|
---|
| 318 | << " kcal/mol" << endl;
|
---|
| 319 | ExEnv::out0() << "Edisp8: " << edisp8*solvent_density_*unit->from_atomic_units()
|
---|
| 320 | << " kcal/mol" << endl;
|
---|
| 321 | ExEnv::out0() << "Edisp10: " << edisp10*solvent_density_*unit->from_atomic_units()
|
---|
| 322 | << " kcal/mol" << endl;
|
---|
| 323 |
|
---|
| 324 |
|
---|
| 325 | ExEnv::out0() << "Total dispersion energy: "
|
---|
| 326 | << (edisp6 + edisp8 + edisp10)*solvent_density_*unit->from_atomic_units()
|
---|
| 327 | << " kcal/mol" << endl;
|
---|
| 328 | ExEnv::out0() << "Repulsion energy: " << setw(12) << setfill(' ')
|
---|
| 329 | << erep*solvent_density_*unit->from_atomic_units() << " kcal/mol" << endl;
|
---|
| 330 |
|
---|
| 331 | return edisprep*solvent_density_; // atomic units
|
---|
| 332 |
|
---|
| 333 | }
|
---|
| 334 |
|
---|
| 335 |
|
---|