| 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 |  | 
|---|