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