| [0b990d] | 1 | //
 | 
|---|
 | 2 | // solvent.cc
 | 
|---|
 | 3 | //
 | 
|---|
 | 4 | // Copyright (C) 1997 Limit Point Systems, Inc.
 | 
|---|
 | 5 | //
 | 
|---|
 | 6 | // Author: Curtis Janssen <cljanss@limitpt.com>
 | 
|---|
 | 7 | // Maintainer: LPS
 | 
|---|
 | 8 | //
 | 
|---|
 | 9 | // This file is part of the SC Toolkit.
 | 
|---|
 | 10 | //
 | 
|---|
 | 11 | // The SC Toolkit is free software; you can redistribute it and/or modify
 | 
|---|
 | 12 | // it under the terms of the GNU Library General Public License as published by
 | 
|---|
 | 13 | // the Free Software Foundation; either version 2, or (at your option)
 | 
|---|
 | 14 | // any later version.
 | 
|---|
 | 15 | //
 | 
|---|
 | 16 | // The SC Toolkit is distributed in the hope that it will be useful,
 | 
|---|
 | 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
 | 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
 | 19 | // GNU Library General Public License for more details.
 | 
|---|
 | 20 | //
 | 
|---|
 | 21 | // You should have received a copy of the GNU Library General Public License
 | 
|---|
 | 22 | // along with the SC Toolkit; see the file COPYING.LIB.  If not, write to
 | 
|---|
 | 23 | // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
|---|
 | 24 | //
 | 
|---|
 | 25 | // The U.S. Government is granted a limited license as per AL 91-7.
 | 
|---|
 | 26 | //
 | 
|---|
 | 27 | 
 | 
|---|
 | 28 | #ifdef __GNUC__
 | 
|---|
 | 29 | #pragma implementation
 | 
|---|
 | 30 | #endif
 | 
|---|
 | 31 | 
 | 
|---|
 | 32 | #include <util/misc/timer.h>
 | 
|---|
 | 33 | #include <util/misc/formio.h>
 | 
|---|
 | 34 | #include <util/state/stateio.h>
 | 
|---|
 | 35 | #include <chemistry/qc/basis/petite.h>
 | 
|---|
 | 36 | #include <chemistry/qc/wfn/solvent.h>
 | 
|---|
 | 37 | 
 | 
|---|
 | 38 | #include <math/isosurf/volume.h>
 | 
|---|
 | 39 | #include <chemistry/qc/dft/integrator.h>
 | 
|---|
 | 40 | #include <chemistry/qc/dft/functional.h>
 | 
|---|
 | 41 | 
 | 
|---|
 | 42 | #include <iomanip>
 | 
|---|
 | 43 | 
 | 
|---|
 | 44 | using namespace std;
 | 
|---|
 | 45 | using namespace sc;
 | 
|---|
 | 46 | 
 | 
|---|
 | 47 | namespace sc {
 | 
|---|
 | 48 | 
 | 
|---|
 | 49 | //. The \clsnm{NElFunctional} computes the number of electrons.
 | 
|---|
 | 50 | //. It is primarily for testing the integrator.
 | 
|---|
 | 51 | class NElInShapeFunctional: public DenFunctional {
 | 
|---|
 | 52 |   private:
 | 
|---|
 | 53 |     Ref<Volume> vol_;
 | 
|---|
 | 54 |     double isoval_;
 | 
|---|
 | 55 |   public:
 | 
|---|
 | 56 |     NElInShapeFunctional(const Ref<Volume> &, double);
 | 
|---|
 | 57 |     ~NElInShapeFunctional();
 | 
|---|
 | 58 | 
 | 
|---|
 | 59 |     void point(const PointInputData&, PointOutputData&);
 | 
|---|
 | 60 | };
 | 
|---|
 | 61 | 
 | 
|---|
 | 62 | /////////////////////////////////////////////////////////////////////////////
 | 
|---|
 | 63 | // NElFunctional
 | 
|---|
 | 64 | 
 | 
|---|
 | 65 | static ClassDesc NElInShapeFunctional_cd(
 | 
|---|
 | 66 |   typeid(NElInShapeFunctional),"NElInShapeFunctional",1,"public DenFunctional",
 | 
|---|
 | 67 |   0, 0, 0);
 | 
|---|
 | 68 | 
 | 
|---|
 | 69 | NElInShapeFunctional::NElInShapeFunctional(const Ref<Volume>& vol,
 | 
|---|
 | 70 |                                            double isoval)
 | 
|---|
 | 71 | {
 | 
|---|
 | 72 |   vol_ = vol;
 | 
|---|
 | 73 |   isoval_ = isoval;
 | 
|---|
 | 74 | }
 | 
|---|
 | 75 | 
 | 
|---|
 | 76 | NElInShapeFunctional::~NElInShapeFunctional()
 | 
|---|
 | 77 | {
 | 
|---|
 | 78 | }
 | 
|---|
 | 79 | 
 | 
|---|
 | 80 | void
 | 
|---|
 | 81 | NElInShapeFunctional::point(const PointInputData &id,
 | 
|---|
 | 82 |                             PointOutputData &od)
 | 
|---|
 | 83 | {
 | 
|---|
 | 84 |   vol_->set_x(id.r);
 | 
|---|
 | 85 |   if (vol_->value() <= isoval_) {
 | 
|---|
 | 86 |       od.energy = id.a.rho + id.b.rho;
 | 
|---|
 | 87 |     }
 | 
|---|
 | 88 |   else {
 | 
|---|
 | 89 |       od.energy = 0.0;
 | 
|---|
 | 90 |     }
 | 
|---|
 | 91 | }
 | 
|---|
 | 92 | 
 | 
|---|
 | 93 | /////////////////////////////////////////////////////////////////////////////
 | 
|---|
 | 94 | 
 | 
|---|
 | 95 | static ClassDesc BEMSolventH_cd(
 | 
|---|
 | 96 |   typeid(BEMSolventH),"BEMSolventH",1,"public AccumH",
 | 
|---|
 | 97 |   0, create<BEMSolventH>, create<BEMSolventH>);
 | 
|---|
 | 98 | 
 | 
|---|
 | 99 | BEMSolventH::BEMSolventH(const Ref<KeyVal>&keyval):
 | 
|---|
 | 100 |   AccumH(keyval)
 | 
|---|
 | 101 | {
 | 
|---|
 | 102 |   charge_positions_ = 0;
 | 
|---|
 | 103 |   normals_ = 0;
 | 
|---|
 | 104 |   efield_dot_normals_ = 0;
 | 
|---|
 | 105 |   charges_ = 0;
 | 
|---|
 | 106 |   charges_n_ = 0;
 | 
|---|
 | 107 |   solvent_ << keyval->describedclassvalue("solvent");
 | 
|---|
 | 108 |   gamma_ = keyval->doublevalue("gamma");
 | 
|---|
 | 109 |   if (keyval->error() != KeyVal::OK) {
 | 
|---|
 | 110 |       Ref<Units> npm = new Units("dyne/cm");
 | 
|---|
 | 111 |       gamma_ = 72.75 * npm->to_atomic_units();
 | 
|---|
 | 112 |     }
 | 
|---|
 | 113 |   // If onebody add a term to the one body hamiltonian, h.
 | 
|---|
 | 114 |   // Otherwise the energy contribution is scalar.
 | 
|---|
 | 115 |   onebody_ = keyval->booleanvalue("onebody");
 | 
|---|
 | 116 |   if (keyval->error() != KeyVal::OK) onebody_ = 1;
 | 
|---|
 | 117 |   // Normalize the charges if normalize_q is set.
 | 
|---|
 | 118 |   normalize_q_ = keyval->booleanvalue("normalize_q");
 | 
|---|
 | 119 |   if (keyval->error() != KeyVal::OK) normalize_q_ = 1;
 | 
|---|
 | 120 |   // Compute separately contributes to the energy from surfaces
 | 
|---|
 | 121 |   // charges induced by the nuclear and electronic charge densities.
 | 
|---|
 | 122 |   separate_surf_charges_ = keyval->booleanvalue("separate_surf_charges");
 | 
|---|
 | 123 |   if (keyval->error() != KeyVal::OK) separate_surf_charges_ = 0;
 | 
|---|
 | 124 |   // The Cammi-Tomasi Y term is set equal to the J term (as it formally is).
 | 
|---|
 | 125 |   y_equals_j_ = keyval->booleanvalue("y_equals_j");
 | 
|---|
 | 126 |   if (keyval->error() != KeyVal::OK) y_equals_j_ = 0;
 | 
|---|
 | 127 |   // As a test, integrate the number of electrons inside the surface.
 | 
|---|
 | 128 |   integrate_nelectron_ = keyval->booleanvalue("integrate_nelectron");
 | 
|---|
 | 129 |   if (keyval->error() != KeyVal::OK) integrate_nelectron_ = 0;
 | 
|---|
 | 130 | }
 | 
|---|
 | 131 | 
 | 
|---|
 | 132 | BEMSolventH::BEMSolventH(StateIn&s):
 | 
|---|
 | 133 |   SavableState(s),
 | 
|---|
 | 134 |   AccumH(s)
 | 
|---|
 | 135 | {
 | 
|---|
 | 136 |   charge_positions_ = 0;
 | 
|---|
 | 137 |   normals_ = 0;
 | 
|---|
 | 138 |   efield_dot_normals_ = 0;
 | 
|---|
 | 139 |   charges_ = 0;
 | 
|---|
 | 140 |   charges_n_ = 0;
 | 
|---|
 | 141 |   escalar_ = 0;
 | 
|---|
 | 142 | 
 | 
|---|
 | 143 |   wfn_ << SavableState::restore_state(s);
 | 
|---|
 | 144 |   //solvent_.restore_state(s);
 | 
|---|
 | 145 |   abort();
 | 
|---|
 | 146 | }
 | 
|---|
 | 147 | 
 | 
|---|
 | 148 | BEMSolventH::~BEMSolventH()
 | 
|---|
 | 149 | {
 | 
|---|
 | 150 |   // just in case
 | 
|---|
 | 151 |   done();
 | 
|---|
 | 152 | }
 | 
|---|
 | 153 | 
 | 
|---|
 | 154 | void
 | 
|---|
 | 155 | BEMSolventH::save_data_state(StateOut&s)
 | 
|---|
 | 156 | {
 | 
|---|
 | 157 |   AccumH::save_data_state(s);
 | 
|---|
 | 158 | 
 | 
|---|
 | 159 |   SavableState::save_state(wfn_.pointer(),s);
 | 
|---|
 | 160 |   //solvent_.save_state(s);
 | 
|---|
 | 161 |   abort();
 | 
|---|
 | 162 | }
 | 
|---|
 | 163 | 
 | 
|---|
 | 164 | void
 | 
|---|
 | 165 | BEMSolventH::init(const Ref<Wavefunction>& wfn)
 | 
|---|
 | 166 | {
 | 
|---|
 | 167 |   tim_enter("solvent");
 | 
|---|
 | 168 |   tim_enter("init");
 | 
|---|
 | 169 |   wfn_ = wfn;
 | 
|---|
 | 170 |   // just in case
 | 
|---|
 | 171 |   done();
 | 
|---|
 | 172 |   solvent_->init();
 | 
|---|
 | 173 |   charge_positions_ = solvent_->alloc_charge_positions();
 | 
|---|
 | 174 |   normals_ = solvent_->alloc_normals();
 | 
|---|
 | 175 |   efield_dot_normals_ = solvent_->alloc_efield_dot_normals();
 | 
|---|
 | 176 |   charges_ = solvent_->alloc_charges();
 | 
|---|
 | 177 |   charges_n_ = solvent_->alloc_charges();
 | 
|---|
 | 178 | 
 | 
|---|
 | 179 |   // get the positions of the charges
 | 
|---|
 | 180 |   solvent_->charge_positions(charge_positions_);
 | 
|---|
 | 181 | 
 | 
|---|
 | 182 |   // get the surface normals
 | 
|---|
 | 183 |   solvent_->normals(normals_);
 | 
|---|
 | 184 | 
 | 
|---|
 | 185 |   if (integrate_nelectron_) {
 | 
|---|
 | 186 |       Ref<DenIntegrator> integrator = new RadialAngularIntegrator();
 | 
|---|
 | 187 |       Ref<DenFunctional> functional
 | 
|---|
 | 188 |           = new NElInShapeFunctional(solvent_->surface()->volume_object(),
 | 
|---|
 | 189 |                                      solvent_->surface()->isovalue());
 | 
|---|
 | 190 |       integrator->init(wfn_);
 | 
|---|
 | 191 |       integrator->integrate(functional);
 | 
|---|
 | 192 |       integrator->done();
 | 
|---|
 | 193 |       ExEnv::out0() << indent
 | 
|---|
 | 194 |            << scprintf("N(e) in isosurf = %12.8f", integrator->value())
 | 
|---|
 | 195 |            << endl;
 | 
|---|
 | 196 |     }
 | 
|---|
 | 197 | 
 | 
|---|
 | 198 |   edisprep_ = solvent_->disprep();
 | 
|---|
 | 199 | 
 | 
|---|
 | 200 |   tim_exit("init");
 | 
|---|
 | 201 |   tim_exit("solvent");
 | 
|---|
 | 202 | }
 | 
|---|
 | 203 | 
 | 
|---|
 | 204 | // This adds J + X to h, where J and X are the matrices defined
 | 
|---|
 | 205 | // by Canni and Tomasi, J Comp Chem, 16(12), 1457, 1995.
 | 
|---|
 | 206 | // The resulting SCF free energy expression is
 | 
|---|
 | 207 | //    G = 1/2TrP[h' + F'] + Une + Unn + Vnn
 | 
|---|
 | 208 | //        -1/2(Uee+Uen+Une+Unn)
 | 
|---|
 | 209 | // which in the Canni-Tomasi notation is
 | 
|---|
 | 210 | //      = 1/2TrP[h+1/2(X+J+Y+G)] + Vnn + 1/2Unn
 | 
|---|
 | 211 | // which is identical to the Canni-Tomasi energy expression.
 | 
|---|
 | 212 | // My Fock matrix is
 | 
|---|
 | 213 | //       F' = h + J + X + G
 | 
|---|
 | 214 | // while the Canni-Tomasi Fock matrix is F' = h + 1/2(J+Y) + X + G.
 | 
|---|
 | 215 | // However, since J = Y formally, (assuming no numerical errors
 | 
|---|
 | 216 | // and all charge is enclosed, Canni-Tomasi use F' = h + J + X + G
 | 
|---|
 | 217 | // to get better numerical results.
 | 
|---|
 | 218 | //
 | 
|---|
 | 219 | //   If the y_equals_j option is true, the energy expression used
 | 
|---|
 | 220 | // here is G = 1/2TrP[h+1/2(X+2J+G)] + Vnn + 1/2Unn, however, THIS
 | 
|---|
 | 221 | // IS NOT RECOMMENDED.
 | 
|---|
 | 222 | void
 | 
|---|
 | 223 | BEMSolventH::accum(const RefSymmSCMatrix& h)
 | 
|---|
 | 224 | {
 | 
|---|
 | 225 |   tim_enter("solvent");
 | 
|---|
 | 226 |   tim_enter("accum");
 | 
|---|
 | 227 |   int i,j;
 | 
|---|
 | 228 | 
 | 
|---|
 | 229 |   //// compute the polarization charges
 | 
|---|
 | 230 | 
 | 
|---|
 | 231 |   // compute the e-field at each point and dot with normals
 | 
|---|
 | 232 |   tim_enter("efield");
 | 
|---|
 | 233 |   int ncharge = solvent_->ncharge();
 | 
|---|
 | 234 |   Ref<EfieldDotVectorData> efdn_dat = new EfieldDotVectorData;
 | 
|---|
 | 235 |   Ref<OneBodyInt> efdn = wfn_->integral()->efield_dot_vector(efdn_dat);
 | 
|---|
 | 236 |   Ref<SCElementOp> efdn_op = new OneBodyIntOp(efdn);
 | 
|---|
 | 237 |   RefSymmSCMatrix ao_density = wfn_->ao_density()->copy();
 | 
|---|
 | 238 |   RefSymmSCMatrix efdn_mat(ao_density->dim(), ao_density->kit());
 | 
|---|
 | 239 |   // for the scalar products, scale the density's off-diagonals by two
 | 
|---|
 | 240 |   ao_density->scale(2.0);
 | 
|---|
 | 241 |   ao_density->scale_diagonal(0.5);
 | 
|---|
 | 242 |   Ref<SCElementScalarProduct> sp = new SCElementScalarProduct;
 | 
|---|
 | 243 |   Ref<SCElementOp2> generic_sp(sp.pointer());
 | 
|---|
 | 244 |   for (i=0; i<ncharge; i++) {
 | 
|---|
 | 245 |       efdn_dat->set_position(charge_positions_[i]);
 | 
|---|
 | 246 |       efdn_dat->set_vector(normals_[i]);
 | 
|---|
 | 247 |       efdn->reinitialize();
 | 
|---|
 | 248 |       efdn_mat->assign(0.0);
 | 
|---|
 | 249 |       efdn_mat->element_op(efdn_op);
 | 
|---|
 | 250 |       sp->init();
 | 
|---|
 | 251 |       efdn_mat->element_op(generic_sp, ao_density);
 | 
|---|
 | 252 |       efield_dot_normals_[i] = sp->result();
 | 
|---|
 | 253 |     }
 | 
|---|
 | 254 |   RefSCDimension aodim = ao_density.dim();
 | 
|---|
 | 255 |   Ref<SCMatrixKit> aokit = ao_density.kit();
 | 
|---|
 | 256 |   ao_density = 0;
 | 
|---|
 | 257 |   efdn_mat = 0;
 | 
|---|
 | 258 |   tim_exit("efield");
 | 
|---|
 | 259 | 
 | 
|---|
 | 260 |   // compute a new set of charges
 | 
|---|
 | 261 |   tim_enter("charges");
 | 
|---|
 | 262 |   // electron contrib
 | 
|---|
 | 263 |   solvent_->compute_charges(efield_dot_normals_, charges_);
 | 
|---|
 | 264 |   double qeenc = solvent_->computed_enclosed_charge();
 | 
|---|
 | 265 |   // nuclear contrib
 | 
|---|
 | 266 |   for (i=0; i<ncharge; i++) {
 | 
|---|
 | 267 |       double nuc_efield[3];
 | 
|---|
 | 268 |       wfn_->molecule()->nuclear_efield(charge_positions_[i], nuc_efield);
 | 
|---|
 | 269 |       double tmp = 0.0;
 | 
|---|
 | 270 |       for (j=0; j<3; j++) {
 | 
|---|
 | 271 |           tmp += nuc_efield[j] * normals_[i][j];
 | 
|---|
 | 272 |         }
 | 
|---|
 | 273 |       efield_dot_normals_[i] = tmp;
 | 
|---|
 | 274 |     }
 | 
|---|
 | 275 |   solvent_->compute_charges(efield_dot_normals_, charges_n_);
 | 
|---|
 | 276 |   double qnenc = solvent_->computed_enclosed_charge();
 | 
|---|
 | 277 |   tim_exit("charges");
 | 
|---|
 | 278 | 
 | 
|---|
 | 279 |   // normalize the charges
 | 
|---|
 | 280 |   // e and n are independently normalized since the nature of the
 | 
|---|
 | 281 |   // errors in e and n are different: n error is just numerical and
 | 
|---|
 | 282 |   // e error is numerical plus diffuseness of electron distribution
 | 
|---|
 | 283 |   if (normalize_q_) {
 | 
|---|
 | 284 |       tim_enter("norm");
 | 
|---|
 | 285 |       // electron contrib
 | 
|---|
 | 286 |       solvent_->normalize_charge(-wfn_->nelectron(), charges_);
 | 
|---|
 | 287 |       // nuclear contrib
 | 
|---|
 | 288 |       solvent_->normalize_charge(wfn_->molecule()->nuclear_charge(),
 | 
|---|
 | 289 |                                  charges_n_);
 | 
|---|
 | 290 |       tim_exit("norm");
 | 
|---|
 | 291 |     }
 | 
|---|
 | 292 |   // sum the nuclear and electron contrib
 | 
|---|
 | 293 |   for (i=0; i<ncharge; i++) charges_[i] += charges_n_[i];
 | 
|---|
 | 294 | 
 | 
|---|
 | 295 |   //// compute scalar contributions
 | 
|---|
 | 296 |   double A = solvent_->area();
 | 
|---|
 | 297 | 
 | 
|---|
 | 298 |   // the cavitation energy
 | 
|---|
 | 299 |   ecavitation_ = A * gamma_;
 | 
|---|
 | 300 | 
 | 
|---|
 | 301 |   // compute the nuclear-surface interaction energy
 | 
|---|
 | 302 |   tim_enter("n-s");
 | 
|---|
 | 303 |   enucsurf_
 | 
|---|
 | 304 |       = solvent_->nuclear_interaction_energy(charge_positions_, charges_);
 | 
|---|
 | 305 |   tim_exit("n-s");
 | 
|---|
 | 306 | 
 | 
|---|
 | 307 |   double enqn = 0.0, enqe = 0.0;
 | 
|---|
 | 308 |   if (y_equals_j_ || separate_surf_charges_) {
 | 
|---|
 | 309 |       tim_enter("n-qn");
 | 
|---|
 | 310 |       enqn = solvent_->nuclear_interaction_energy(charge_positions_,
 | 
|---|
 | 311 |                                                   charges_n_);
 | 
|---|
 | 312 |       enqe = enucsurf_ - enqn;
 | 
|---|
 | 313 |       tim_exit("n-qn");
 | 
|---|
 | 314 |     }
 | 
|---|
 | 315 | 
 | 
|---|
 | 316 |   //// compute one body contributions
 | 
|---|
 | 317 | 
 | 
|---|
 | 318 |   // compute the electron-surface interaction matrix elements
 | 
|---|
 | 319 |   tim_enter("e-s");
 | 
|---|
 | 320 |   Ref<PointChargeData> pc_dat = new PointChargeData(ncharge,
 | 
|---|
 | 321 |                                                   charge_positions_, charges_);
 | 
|---|
 | 322 |   Ref<OneBodyInt> pc = wfn_->integral()->point_charge(pc_dat);
 | 
|---|
 | 323 |   Ref<SCElementOp> pc_op = new OneBodyIntOp(pc);
 | 
|---|
 | 324 | 
 | 
|---|
 | 325 |   // compute matrix elements in the ao basis
 | 
|---|
 | 326 |   RefSymmSCMatrix h_ao(aodim, aokit);
 | 
|---|
 | 327 |   h_ao.assign(0.0);
 | 
|---|
 | 328 |   h_ao.element_op(pc_op);
 | 
|---|
 | 329 |   // transform to the so basis and add to h
 | 
|---|
 | 330 |   RefSymmSCMatrix h_so = wfn_->integral()->petite_list()->to_SO_basis(h_ao);
 | 
|---|
 | 331 |   if (onebody_) h->accumulate(h_so);
 | 
|---|
 | 332 |   // compute the contribution to the energy
 | 
|---|
 | 333 |   sp->init();
 | 
|---|
 | 334 |   RefSymmSCMatrix so_density = wfn_->density()->copy();
 | 
|---|
 | 335 |   // for the scalar products, scale the density's off-diagonals by two
 | 
|---|
 | 336 |   so_density->scale(2.0);
 | 
|---|
 | 337 |   so_density->scale_diagonal(0.5);
 | 
|---|
 | 338 |   h_so->element_op(generic_sp, so_density);
 | 
|---|
 | 339 |   eelecsurf_ = sp->result();
 | 
|---|
 | 340 |   tim_exit("e-s");
 | 
|---|
 | 341 | 
 | 
|---|
 | 342 |   double eeqn = 0.0, eeqe = 0.0;
 | 
|---|
 | 343 |   if (y_equals_j_ || separate_surf_charges_) {
 | 
|---|
 | 344 |       tim_enter("e-qn");
 | 
|---|
 | 345 |       pc_dat = new PointChargeData(ncharge, charge_positions_, charges_n_);
 | 
|---|
 | 346 |       pc = wfn_->integral()->point_charge(pc_dat);
 | 
|---|
 | 347 |       pc_op = new OneBodyIntOp(pc);
 | 
|---|
 | 348 | 
 | 
|---|
 | 349 |       // compute matrix elements in the ao basis
 | 
|---|
 | 350 |       h_ao.assign(0.0);
 | 
|---|
 | 351 |       h_ao.element_op(pc_op);
 | 
|---|
 | 352 |       // transform to the so basis
 | 
|---|
 | 353 |       h_so = wfn_->integral()->petite_list()->to_SO_basis(h_ao);
 | 
|---|
 | 354 |       // compute the contribution to the energy
 | 
|---|
 | 355 |       sp->init();
 | 
|---|
 | 356 |       h_so->element_op(generic_sp, so_density);
 | 
|---|
 | 357 |       eeqn = sp->result();
 | 
|---|
 | 358 |       eeqe = eelecsurf_ - eeqn;
 | 
|---|
 | 359 |       tim_exit("e-qn");
 | 
|---|
 | 360 |     }
 | 
|---|
 | 361 | 
 | 
|---|
 | 362 |   if (y_equals_j_) {
 | 
|---|
 | 363 |       // Remove the y term (enqe) and add the j term (eeqn).  Formally,
 | 
|---|
 | 364 |       // they are equal, but they are not because some e-density is outside
 | 
|---|
 | 365 |       // the surface and because of the numerical approximations.
 | 
|---|
 | 366 |       enucsurf_ += eeqn - enqe;
 | 
|---|
 | 367 |     }
 | 
|---|
 | 368 | 
 | 
|---|
 | 369 |   // compute the surface-surface interaction energy
 | 
|---|
 | 370 |   esurfsurf_ = -0.5*(eelecsurf_+enucsurf_);
 | 
|---|
 | 371 |   // (this can also be computed as below, but is much more expensive)
 | 
|---|
 | 372 |   //tim_enter("s-s");
 | 
|---|
 | 373 |   //double esurfsurf_;
 | 
|---|
 | 374 |   //esurfsurf_ = solvent_->self_interaction_energy(charge_positions_, charges_);
 | 
|---|
 | 375 |   //tim_exit("s-s");
 | 
|---|
 | 376 | 
 | 
|---|
 | 377 |   escalar_ = enucsurf_ + esurfsurf_ + ecavitation_ + edisprep_;
 | 
|---|
 | 378 |   // NOTE: SCF currently only adds h_so to the Fock matrix
 | 
|---|
 | 379 |   // so a term is missing in the energy.  This term is added here
 | 
|---|
 | 380 |   // and when SCF is fixed, should no longer be included.
 | 
|---|
 | 381 |   if (onebody_) escalar_ += 0.5 * eelecsurf_;
 | 
|---|
 | 382 | 
 | 
|---|
 | 383 |   if (!onebody_) escalar_ += eelecsurf_;
 | 
|---|
 | 384 | 
 | 
|---|
 | 385 |   ExEnv::out0() << incindent;
 | 
|---|
 | 386 |   ExEnv::out0() << indent
 | 
|---|
 | 387 |        << "Solvent: "
 | 
|---|
 | 388 |        << scprintf("q(e-enc)=%12.10f q(n-enc)=%12.10f", qeenc, qnenc)
 | 
|---|
 | 389 |        << endl;
 | 
|---|
 | 390 |   ExEnv::out0() << incindent;
 | 
|---|
 | 391 |   if (separate_surf_charges_) {
 | 
|---|
 | 392 |       ExEnv::out0() << indent
 | 
|---|
 | 393 |            << scprintf("E(n-qn)=%10.8f ", enqn)
 | 
|---|
 | 394 |            << scprintf("E(n-qe)=%10.8f", enqe)
 | 
|---|
 | 395 |            << endl;
 | 
|---|
 | 396 |       ExEnv::out0() << indent
 | 
|---|
 | 397 |            << scprintf("E(e-qn)=%10.8f ", eeqn)
 | 
|---|
 | 398 |            << scprintf("E(e-qe)=%10.8f", eeqe)
 | 
|---|
 | 399 |            << endl;
 | 
|---|
 | 400 |       //ExEnv::out0() << indent
 | 
|---|
 | 401 |       //     << scprintf("DG = %12.8f ", 0.5*627.51*(enqn+enqe+eeqn+eeqe))
 | 
|---|
 | 402 |       //     << scprintf("DG(Y=J) = %12.8f", 0.5*627.51*(enqn+2*eeqn+eeqe))
 | 
|---|
 | 403 |       //     << endl;
 | 
|---|
 | 404 |     }
 | 
|---|
 | 405 |   ExEnv::out0() << indent
 | 
|---|
 | 406 |        << scprintf("E(c)=%10.8f ", ecavitation_)
 | 
|---|
 | 407 |        << scprintf("E(disp-rep)=%10.8f", edisprep_)
 | 
|---|
 | 408 |        << endl;
 | 
|---|
 | 409 |   ExEnv::out0() << indent
 | 
|---|
 | 410 |        << scprintf("E(n-s)=%10.8f ", enucsurf_)
 | 
|---|
 | 411 |        << scprintf("E(e-s)=%10.8f ", eelecsurf_)
 | 
|---|
 | 412 |        << scprintf("E(s-s)=%10.8f ", esurfsurf_)
 | 
|---|
 | 413 |        << endl;
 | 
|---|
 | 414 |   ExEnv::out0() << decindent;
 | 
|---|
 | 415 |   ExEnv::out0() << decindent;
 | 
|---|
 | 416 | 
 | 
|---|
 | 417 |   tim_exit("accum");
 | 
|---|
 | 418 |   tim_exit("solvent");
 | 
|---|
 | 419 | }
 | 
|---|
 | 420 | 
 | 
|---|
 | 421 | void
 | 
|---|
 | 422 | BEMSolventH::done()
 | 
|---|
 | 423 | {
 | 
|---|
 | 424 |   solvent_->free_normals(normals_);
 | 
|---|
 | 425 |   normals_ = 0;
 | 
|---|
 | 426 |   solvent_->free_efield_dot_normals(efield_dot_normals_);
 | 
|---|
 | 427 |   efield_dot_normals_ = 0;
 | 
|---|
 | 428 |   solvent_->free_charges(charges_);
 | 
|---|
 | 429 |   solvent_->free_charges(charges_n_);
 | 
|---|
 | 430 |   charges_ = 0;
 | 
|---|
 | 431 |   charges_n_ = 0;
 | 
|---|
 | 432 |   solvent_->free_charge_positions(charge_positions_);
 | 
|---|
 | 433 |   charge_positions_ = 0;
 | 
|---|
 | 434 |   solvent_->done();
 | 
|---|
 | 435 | }
 | 
|---|
 | 436 | 
 | 
|---|
 | 437 | void
 | 
|---|
 | 438 | BEMSolventH::print_summary()
 | 
|---|
 | 439 | {
 | 
|---|
 | 440 |   Ref<Units> unit = new Units("kcal/mol");
 | 
|---|
 | 441 |   ExEnv::out0() << endl;
 | 
|---|
 | 442 |   ExEnv::out0() << "Summary of solvation calculation:" << endl;
 | 
|---|
 | 443 |   ExEnv::out0() << "_______________________________________________" << endl;
 | 
|---|
 | 444 |   ExEnv::out0() << endl;
 | 
|---|
 | 445 |   ExEnv::out0().setf(ios::scientific,ios::floatfield); // use scientific format
 | 
|---|
 | 446 |   ExEnv::out0().precision(5);
 | 
|---|
 | 447 |   ExEnv::out0() << indent << "E(nuc-surf):              " 
 | 
|---|
 | 448 |        << setw(12) << setfill(' ')
 | 
|---|
 | 449 |        << enucsurf_*unit->from_atomic_units() << " kcal/mol" << endl; 
 | 
|---|
 | 450 |   ExEnv::out0() << indent << "E(elec-surf):             " 
 | 
|---|
 | 451 |        << setw(12) << setfill(' ')
 | 
|---|
 | 452 |        << eelecsurf_*unit->from_atomic_units() << " kcal/mol" << endl; 
 | 
|---|
 | 453 |   ExEnv::out0() << indent << "E(surf-surf):             " 
 | 
|---|
 | 454 |        << setw(12) << setfill(' ')
 | 
|---|
 | 455 |        << esurfsurf_*unit->from_atomic_units() << " kcal/mol" << endl; 
 | 
|---|
 | 456 |   ExEnv::out0() << indent << "Electrostatic energy:     " 
 | 
|---|
 | 457 |        << setw(12) << setfill(' ')
 | 
|---|
 | 458 |        << (enucsurf_+eelecsurf_+esurfsurf_)*unit->from_atomic_units()
 | 
|---|
 | 459 |        << " kcal/mol" << endl; 
 | 
|---|
 | 460 |   ExEnv::out0() << "_______________________________________________" << endl;
 | 
|---|
 | 461 |   ExEnv::out0() << endl;
 | 
|---|
 | 462 |   ExEnv::out0() << indent << "E(cav):                   " 
 | 
|---|
 | 463 |        << setw(12) << setfill(' ')
 | 
|---|
 | 464 |        << ecavitation_*unit->from_atomic_units() << " kcal/mol" << endl; 
 | 
|---|
 | 465 |   ExEnv::out0() << indent << "E(disp):                  " 
 | 
|---|
 | 466 |        << setw(12) << setfill(' ')
 | 
|---|
 | 467 |        << solvent_->disp()*unit->from_atomic_units() << " kcal/mol" << endl; 
 | 
|---|
 | 468 |   ExEnv::out0() << indent << "E(rep):                   " 
 | 
|---|
 | 469 |        << setw(12) << setfill(' ')
 | 
|---|
 | 470 |        << solvent_->rep()*unit->from_atomic_units() << " kcal/mol" << endl; 
 | 
|---|
 | 471 |   ExEnv::out0() << indent << "Non-electrostatic energy: "
 | 
|---|
 | 472 |        << setw(12) << setfill(' ')
 | 
|---|
 | 473 |        << (ecavitation_+solvent_->disp()+solvent_->rep())
 | 
|---|
 | 474 |           *unit->from_atomic_units() << " kcal/mol" << endl; 
 | 
|---|
 | 475 |   ExEnv::out0() << "_______________________________________________" << endl;
 | 
|---|
 | 476 | 
 | 
|---|
 | 477 | }
 | 
|---|
 | 478 | 
 | 
|---|
 | 479 | double
 | 
|---|
 | 480 | BEMSolventH::e()
 | 
|---|
 | 481 | {
 | 
|---|
 | 482 |   return escalar_;
 | 
|---|
 | 483 | }
 | 
|---|
 | 484 | 
 | 
|---|
 | 485 | /////////////////////////////////////////////////////////////////////////////
 | 
|---|
 | 486 | 
 | 
|---|
 | 487 | }
 | 
|---|
 | 488 | 
 | 
|---|
 | 489 | // Local Variables:
 | 
|---|
 | 490 | // mode: c++
 | 
|---|
 | 491 | // c-file-style: "CLJ"
 | 
|---|
 | 492 | // End:
 | 
|---|