[0b990d] | 1 | //
|
---|
| 2 | // density.cc
|
---|
| 3 | //
|
---|
| 4 | // Copyright (C) 1996 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 <stdexcept>
|
---|
| 33 |
|
---|
| 34 | #include <util/misc/formio.h>
|
---|
| 35 | #include <util/render/polygons.h>
|
---|
| 36 | #include <math/scmat/local.h>
|
---|
| 37 | #include <math/scmat/vector3.h>
|
---|
| 38 | #include <chemistry/molecule/molecule.h>
|
---|
| 39 | #include <chemistry/qc/wfn/density.h>
|
---|
| 40 |
|
---|
| 41 | using namespace std;
|
---|
| 42 | using namespace sc;
|
---|
| 43 |
|
---|
| 44 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 45 | // ElectronDensity
|
---|
| 46 |
|
---|
| 47 | static ClassDesc ElectronDensity_cd(
|
---|
| 48 | typeid(ElectronDensity),"ElectronDensity",1,"public Volume",
|
---|
| 49 | 0, create<ElectronDensity>, 0);
|
---|
| 50 |
|
---|
| 51 | ElectronDensity::ElectronDensity(const Ref<KeyVal> &keyval):
|
---|
| 52 | Volume(keyval)
|
---|
| 53 | {
|
---|
| 54 | wfn_ << keyval->describedclassvalue("wfn");
|
---|
| 55 | }
|
---|
| 56 |
|
---|
| 57 | ElectronDensity::ElectronDensity(const Ref<Wavefunction>& wfn):
|
---|
| 58 | Volume(),
|
---|
| 59 | wfn_(wfn)
|
---|
| 60 | {
|
---|
| 61 | }
|
---|
| 62 |
|
---|
| 63 | ElectronDensity::~ElectronDensity()
|
---|
| 64 | {
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 | void
|
---|
| 68 | ElectronDensity::compute()
|
---|
| 69 | {
|
---|
| 70 | SCVector3 r;
|
---|
| 71 | get_x(r);
|
---|
| 72 | // do_gradient will automatically cause the value to be computed
|
---|
| 73 | if (gradient_needed()) {
|
---|
| 74 | double v[3];
|
---|
| 75 | set_value(wfn_->density_gradient(r,v));
|
---|
| 76 | set_actual_value_accuracy(desired_value_accuracy());
|
---|
| 77 | SCVector3 d(v);
|
---|
| 78 | set_gradient(d);
|
---|
| 79 | set_actual_gradient_accuracy(desired_gradient_accuracy());
|
---|
| 80 | }
|
---|
| 81 | else if (value_needed()) {
|
---|
| 82 | set_value(wfn_->density(r));
|
---|
| 83 | set_actual_value_accuracy(desired_value_accuracy());
|
---|
| 84 | }
|
---|
| 85 | if (hessian_needed()) {
|
---|
| 86 | ExEnv::err0() << indent
|
---|
| 87 | << "ElectronDensity::compute(): hessian isn't yet implemented\n";
|
---|
| 88 | abort();
|
---|
| 89 | }
|
---|
| 90 | }
|
---|
| 91 |
|
---|
| 92 | // make a wild guess about the bounding box
|
---|
| 93 | void
|
---|
| 94 | ElectronDensity::boundingbox(double valuemin,
|
---|
| 95 | double valuemax,
|
---|
| 96 | SCVector3& p1, SCVector3& p2)
|
---|
| 97 | {
|
---|
| 98 | Molecule& mol = *wfn_->molecule();
|
---|
| 99 |
|
---|
| 100 | if (mol.natom() == 0) {
|
---|
| 101 | for (int i=0; i<3; i++) p1[i] = p2[i] = 0.0;
|
---|
| 102 | }
|
---|
| 103 |
|
---|
| 104 | int i;
|
---|
| 105 | for (i=0; i<3; i++) p1[i] = p2[i] = mol.r(0,i);
|
---|
| 106 | for (i=1; i<mol.natom(); i++) {
|
---|
| 107 | for (int j=0; j<3; j++) {
|
---|
| 108 | if (mol.r(i,j) < p1[j]) p1[j] = mol.r(i,j);
|
---|
| 109 | if (mol.r(i,j) > p2[j]) p2[j] = mol.r(i,j);
|
---|
| 110 | }
|
---|
| 111 | }
|
---|
| 112 | for (i=0; i<3; i++) {
|
---|
| 113 | p1[i] = p1[i] - 3.0;
|
---|
| 114 | p2[i] = p2[i] + 3.0;
|
---|
| 115 | }
|
---|
| 116 | }
|
---|
| 117 |
|
---|
| 118 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 119 | // BatchElectronDensity
|
---|
| 120 |
|
---|
| 121 | static ClassDesc BatchElectronDensity_cd(
|
---|
| 122 | typeid(BatchElectronDensity),"BatchElectronDensity",1,"public Volume",
|
---|
| 123 | 0, create<BatchElectronDensity>, 0);
|
---|
| 124 |
|
---|
| 125 | BatchElectronDensity::BatchElectronDensity(const Ref<Wavefunction> &wfn,
|
---|
| 126 | double accuracy):
|
---|
| 127 | Volume()
|
---|
| 128 | {
|
---|
| 129 | wfn_ = wfn;
|
---|
| 130 | accuracy_ = accuracy;
|
---|
| 131 | zero_pointers();
|
---|
| 132 | using_shared_data_ = false;
|
---|
| 133 | linear_scaling_ = true;
|
---|
| 134 | use_dmat_bound_ = true;
|
---|
| 135 | need_basis_gradient_ = false;
|
---|
| 136 | need_basis_hessian_ = false;
|
---|
| 137 | }
|
---|
| 138 |
|
---|
| 139 | BatchElectronDensity::BatchElectronDensity(const Ref<KeyVal> &keyval):
|
---|
| 140 | Volume(keyval)
|
---|
| 141 | {
|
---|
| 142 | wfn_ << keyval->describedclassvalue("wfn");
|
---|
| 143 | accuracy_ = keyval->doublevalue("accuracy");
|
---|
| 144 | zero_pointers();
|
---|
| 145 | using_shared_data_ = false;
|
---|
| 146 | linear_scaling_ = true;
|
---|
| 147 | use_dmat_bound_ = true;
|
---|
| 148 | need_basis_gradient_ = false;
|
---|
| 149 | need_basis_hessian_ = false;
|
---|
| 150 | }
|
---|
| 151 |
|
---|
| 152 | BatchElectronDensity::BatchElectronDensity(const Ref<BatchElectronDensity>&d,
|
---|
| 153 | bool reference_parent_data):
|
---|
| 154 | Volume()
|
---|
| 155 | {
|
---|
| 156 | wfn_ = d->wfn_;
|
---|
| 157 | zero_pointers();
|
---|
| 158 | using_shared_data_ = reference_parent_data;
|
---|
| 159 | accuracy_ = d->accuracy_;
|
---|
| 160 | need_basis_gradient_ = d->need_basis_gradient_;
|
---|
| 161 | need_basis_hessian_ = d->need_basis_hessian_;
|
---|
| 162 | if (using_shared_data_) {
|
---|
| 163 | if (d->alpha_dmat_ == 0) {
|
---|
| 164 | throw std::runtime_error("BatchElectronDensity: attempted to use shared data, but parent data not initialized");
|
---|
| 165 | }
|
---|
| 166 |
|
---|
| 167 | spin_polarized_ = d->spin_polarized_;
|
---|
| 168 | nshell_ = d->nshell_;
|
---|
| 169 | nbasis_ = d->nbasis_;
|
---|
| 170 | basis_ = d->basis_;
|
---|
| 171 | extent_ = d->extent_;
|
---|
| 172 | alpha_dmat_ = d->alpha_dmat_;
|
---|
| 173 | beta_dmat_ = d->beta_dmat_;
|
---|
| 174 | dmat_bound_ = d->dmat_bound_;
|
---|
| 175 | linear_scaling_ = d->linear_scaling_;
|
---|
| 176 | use_dmat_bound_ = d->use_dmat_bound_;
|
---|
| 177 |
|
---|
| 178 | init_scratch_data();
|
---|
| 179 | }
|
---|
| 180 | }
|
---|
| 181 |
|
---|
| 182 | BatchElectronDensity::~BatchElectronDensity()
|
---|
| 183 | {
|
---|
| 184 | clear();
|
---|
| 185 | }
|
---|
| 186 |
|
---|
| 187 | void
|
---|
| 188 | BatchElectronDensity::zero_pointers()
|
---|
| 189 | {
|
---|
| 190 | valdat_ = 0;
|
---|
| 191 | extent_ = 0;
|
---|
| 192 |
|
---|
| 193 | alpha_dmat_ = 0;
|
---|
| 194 | beta_dmat_ = 0;
|
---|
| 195 | dmat_bound_ = 0;
|
---|
| 196 | contrib_ = 0;
|
---|
| 197 | contrib_bf_ = 0;
|
---|
| 198 | bs_values_ = 0;
|
---|
| 199 | bsg_values_ = 0;
|
---|
| 200 | bsh_values_ = 0;
|
---|
| 201 | }
|
---|
| 202 |
|
---|
| 203 | void
|
---|
| 204 | BatchElectronDensity::clear()
|
---|
| 205 | {
|
---|
| 206 | if (!using_shared_data_) {
|
---|
| 207 | delete extent_;
|
---|
| 208 | delete[] alpha_dmat_;
|
---|
| 209 | delete[] beta_dmat_;
|
---|
| 210 | delete[] dmat_bound_;
|
---|
| 211 | }
|
---|
| 212 |
|
---|
| 213 | delete[] contrib_;
|
---|
| 214 | delete[] contrib_bf_;
|
---|
| 215 | delete[] bs_values_;
|
---|
| 216 | delete[] bsg_values_;
|
---|
| 217 | delete[] bsh_values_;
|
---|
| 218 | delete valdat_;
|
---|
| 219 |
|
---|
| 220 | zero_pointers();
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 | void
|
---|
| 224 | BatchElectronDensity::init(bool initialize_density_matrices)
|
---|
| 225 | {
|
---|
| 226 | if (using_shared_data_)
|
---|
| 227 | throw std::runtime_error("BatchElectronDensity::init: should not be called if using_shared_data");
|
---|
| 228 |
|
---|
| 229 | clear();
|
---|
| 230 | init_common_data(initialize_density_matrices);
|
---|
| 231 | init_scratch_data();
|
---|
| 232 | }
|
---|
| 233 |
|
---|
| 234 | void
|
---|
| 235 | BatchElectronDensity::init_common_data(bool initialize_density_matrices)
|
---|
| 236 | {
|
---|
| 237 | spin_polarized_ = wfn_->spin_polarized();
|
---|
| 238 | nshell_ = wfn_->basis()->nshell();
|
---|
| 239 | nbasis_ = wfn_->basis()->nbasis();
|
---|
| 240 | basis_ = wfn_->basis();
|
---|
| 241 |
|
---|
| 242 | if (linear_scaling_) {
|
---|
| 243 | extent_ = new ShellExtent;
|
---|
| 244 | extent_->init(wfn_->basis());
|
---|
| 245 | }
|
---|
| 246 |
|
---|
| 247 | alpha_dmat_ = new double[(nbasis_*(nbasis_+1))/2];
|
---|
| 248 |
|
---|
| 249 | beta_dmat_ = 0;
|
---|
| 250 | if (spin_polarized_) {
|
---|
| 251 | beta_dmat_ = new double[(nbasis_*(nbasis_+1))/2];
|
---|
| 252 | }
|
---|
| 253 |
|
---|
| 254 | dmat_bound_ = new double[(nshell_*(nshell_+1))/2];
|
---|
| 255 |
|
---|
| 256 | if (initialize_density_matrices) {
|
---|
| 257 | RefSymmSCMatrix beta_ao_density;
|
---|
| 258 | if (spin_polarized_) beta_ao_density = wfn_->beta_ao_density();
|
---|
| 259 | set_densities(wfn_->alpha_ao_density(), beta_ao_density);
|
---|
| 260 | }
|
---|
| 261 | }
|
---|
| 262 |
|
---|
| 263 | void
|
---|
| 264 | BatchElectronDensity::set_densities(const RefSymmSCMatrix &aden,
|
---|
| 265 | const RefSymmSCMatrix &bden)
|
---|
| 266 | {
|
---|
| 267 | RefSymmSCMatrix ad = aden;
|
---|
| 268 | RefSymmSCMatrix bd = bden;
|
---|
| 269 | if (ad.null()) ad = wfn_->alpha_ao_density();
|
---|
| 270 | if (bd.null()) bd = wfn_->beta_ao_density();
|
---|
| 271 |
|
---|
| 272 | ad->convert(alpha_dmat_);
|
---|
| 273 | if (spin_polarized_) bd->convert(beta_dmat_);
|
---|
| 274 |
|
---|
| 275 | int ij = 0;
|
---|
| 276 | for (int i=0; i<nshell_; i++) {
|
---|
| 277 | int ni = wfn_->basis()->shell(i).nfunction();
|
---|
| 278 | for (int j=0; j<=i; j++,ij++) {
|
---|
| 279 | int nj = wfn_->basis()->shell(j).nfunction();
|
---|
| 280 | double bound = 0.0;
|
---|
| 281 | int ibf = wfn_->basis()->shell_to_function(i);
|
---|
| 282 | for (int k=0; k<ni; k++,ibf++) {
|
---|
| 283 | int lmax = nj-1;
|
---|
| 284 | if (i==j) lmax = k;
|
---|
| 285 | int jbf = wfn_->basis()->shell_to_function(j);
|
---|
| 286 | int ijbf = (ibf*(ibf+1))/2 + jbf;
|
---|
| 287 | for (int l=0; l<=lmax; l++,ijbf++) {
|
---|
| 288 | double a = fabs(alpha_dmat_[ijbf]);
|
---|
| 289 | if (a > bound) bound = a;
|
---|
| 290 | if (beta_dmat_) {
|
---|
| 291 | double b = fabs(beta_dmat_[ijbf]);
|
---|
| 292 | if (b > bound) bound = b;
|
---|
| 293 | }
|
---|
| 294 | }
|
---|
| 295 | }
|
---|
| 296 | dmat_bound_[ij] = bound;
|
---|
| 297 | }
|
---|
| 298 | }
|
---|
| 299 | }
|
---|
| 300 |
|
---|
| 301 | void
|
---|
| 302 | BatchElectronDensity::init_scratch_data()
|
---|
| 303 | {
|
---|
| 304 | contrib_ = new int[nshell_];
|
---|
| 305 | contrib_bf_ = new int[nbasis_];
|
---|
| 306 | bs_values_ = new double[nbasis_];
|
---|
| 307 | bsg_values_ = new double[3*nbasis_];
|
---|
| 308 | bsh_values_ = new double[6*nbasis_];
|
---|
| 309 | valdat_ = new GaussianBasisSet::ValueData(basis_, wfn_->integral());
|
---|
| 310 | }
|
---|
| 311 |
|
---|
| 312 | void
|
---|
| 313 | BatchElectronDensity::compute_basis_values(const SCVector3&r)
|
---|
| 314 | {
|
---|
| 315 | // only consider those shells for which phi_i * (Max_j D_ij phi_j) > tol
|
---|
| 316 | if (linear_scaling_ && use_dmat_bound_ && extent_ != 0) {
|
---|
| 317 | const std::vector<ExtentData> &cs = extent_->contributing_shells(r[0],r[1],r[2]);
|
---|
| 318 | ncontrib_ = 0;
|
---|
| 319 | for (int i=0; i<cs.size(); i++) {
|
---|
| 320 | int ish = cs[i].shell;
|
---|
| 321 | int contrib = 0;
|
---|
| 322 | for (int j=0; j<cs.size(); j++) {
|
---|
| 323 | int jsh = cs[j].shell;
|
---|
| 324 | int ijsh = (ish>jsh)?((ish*(ish+1))/2+jsh):((jsh*(jsh+1))/2+ish);
|
---|
| 325 | // std::cout << "cs[i].bound = " << cs[i].bound << std::endl;
|
---|
| 326 | // std::cout << "cs[j].bound = " << cs[j].bound << std::endl;
|
---|
| 327 | // std::cout << "dmat_bound_[ijsh] = " << dmat_bound_[ijsh] << std::endl;
|
---|
| 328 | // std::cout << "accuracy_ = " << accuracy_ << std::endl;
|
---|
| 329 | if (cs[i].bound*cs[j].bound*dmat_bound_[ijsh] > 0.00001*accuracy_) {
|
---|
| 330 | contrib = 1;
|
---|
| 331 | break;
|
---|
| 332 | }
|
---|
| 333 | }
|
---|
| 334 | if (contrib) {
|
---|
| 335 | contrib_[ncontrib_++] = ish;
|
---|
| 336 | }
|
---|
| 337 | }
|
---|
| 338 | }
|
---|
| 339 | else if (linear_scaling_ && extent_ != 0) {
|
---|
| 340 | const std::vector<ExtentData> &cs = extent_->contributing_shells(r[0],r[1],r[2]);
|
---|
| 341 | ncontrib_ = cs.size();
|
---|
| 342 | for (int i=0; i<ncontrib_; i++) {
|
---|
| 343 | contrib_[i] = cs[i].shell;
|
---|
| 344 | }
|
---|
| 345 | }
|
---|
| 346 | else {
|
---|
| 347 | ncontrib_ = nshell_;
|
---|
| 348 | for (int i=0; i<nshell_; i++) contrib_[i] = i;
|
---|
| 349 | }
|
---|
| 350 |
|
---|
| 351 | ncontrib_bf_ = 0;
|
---|
| 352 | for (int i=0; i<ncontrib_; i++) {
|
---|
| 353 | int nbf = basis_->shell(contrib_[i]).nfunction();
|
---|
| 354 | int bf = basis_->shell_to_function(contrib_[i]);
|
---|
| 355 | for (int j=0; j<nbf; j++, bf++) {
|
---|
| 356 | contrib_bf_[ncontrib_bf_++] = bf;
|
---|
| 357 | }
|
---|
| 358 | }
|
---|
| 359 |
|
---|
| 360 | // compute the basis set values
|
---|
| 361 | double *bsv = bs_values_;
|
---|
| 362 | double *bsg = ((need_basis_gradient_||need_gradient_)?bsg_values_:0);
|
---|
| 363 | double *bsh = ((need_basis_hessian_||need_hessian_)?bsh_values_:0);
|
---|
| 364 | for (int i=0; i<ncontrib_; i++) {
|
---|
| 365 | basis_->hessian_shell_values(r,contrib_[i],valdat_,bsh,bsg,bsv);
|
---|
| 366 | int shsize = basis_->shell(contrib_[i]).nfunction();
|
---|
| 367 |
|
---|
| 368 | if (bsh) bsh += 6 * shsize;
|
---|
| 369 | if (bsg) bsg += 3 * shsize;
|
---|
| 370 | if (bsv) bsv += shsize;
|
---|
| 371 | }
|
---|
| 372 | }
|
---|
| 373 |
|
---|
| 374 | void
|
---|
| 375 | BatchElectronDensity::compute_spin_density(const double *dmat,
|
---|
| 376 | double *rho,
|
---|
| 377 | double *grad,
|
---|
| 378 | double *hess)
|
---|
| 379 | {
|
---|
| 380 | int i, j;
|
---|
| 381 |
|
---|
| 382 | double tmp = 0.0;
|
---|
| 383 | double densij;
|
---|
| 384 | double bvi, bvix, bviy, bviz;
|
---|
| 385 | double bvixx, bviyx, bviyy, bvizx, bvizy, bvizz;
|
---|
| 386 |
|
---|
| 387 | if (need_gradient_) for (i=0; i<3; i++) grad[i] = 0.0;
|
---|
| 388 | if (need_hessian_) for (i=0; i<6; i++) hess[i] = 0.0;
|
---|
| 389 |
|
---|
| 390 | if (need_gradient_ || need_hessian_) {
|
---|
| 391 | for (i=0; i < ncontrib_bf_; i++) {
|
---|
| 392 | int it = contrib_bf_[i];
|
---|
| 393 | bvi = bs_values_[i];
|
---|
| 394 | if (need_gradient_) {
|
---|
| 395 | bvix = bsg_values_[i*3+X];
|
---|
| 396 | bviy = bsg_values_[i*3+Y];
|
---|
| 397 | bviz = bsg_values_[i*3+Z];
|
---|
| 398 | }
|
---|
| 399 | if (need_hessian_) {
|
---|
| 400 | bvixx = bsh_values_[i*6+XX];
|
---|
| 401 | bviyx = bsh_values_[i*6+YX];
|
---|
| 402 | bviyy = bsh_values_[i*6+YY];
|
---|
| 403 | bvizx = bsh_values_[i*6+ZX];
|
---|
| 404 | bvizy = bsh_values_[i*6+ZY];
|
---|
| 405 | bvizz = bsh_values_[i*6+ZZ];
|
---|
| 406 | }
|
---|
| 407 | int j3 = 0, j6 = 0;
|
---|
| 408 | int itoff = (it*(it+1))>>1;
|
---|
| 409 | int itjt;
|
---|
| 410 | double t = 0.0;
|
---|
| 411 | for (j=0; j < i; j++) {
|
---|
| 412 | int jt = contrib_bf_[j];
|
---|
| 413 | itjt = itoff+jt;
|
---|
| 414 |
|
---|
| 415 | densij = dmat[itjt];
|
---|
| 416 | double bvj = bs_values_[j];
|
---|
| 417 |
|
---|
| 418 | t += densij*bvi*bvj;
|
---|
| 419 |
|
---|
| 420 | double bvjx, bvjy, bvjz;
|
---|
| 421 | if (need_gradient_) {
|
---|
| 422 | bvjx = bsg_values_[j3+X];
|
---|
| 423 | bvjy = bsg_values_[j3+Y];
|
---|
| 424 | bvjz = bsg_values_[j3+Z];
|
---|
| 425 | grad[X] += densij*(bvi*bvjx + bvj*bvix);
|
---|
| 426 | grad[Y] += densij*(bvi*bvjy + bvj*bviy);
|
---|
| 427 | grad[Z] += densij*(bvi*bvjz + bvj*bviz);
|
---|
| 428 | j3 += 3;
|
---|
| 429 | }
|
---|
| 430 |
|
---|
| 431 | if (need_hessian_) {
|
---|
| 432 | double bvjxx = bsh_values_[j6+XX];
|
---|
| 433 | double bvjyx = bsh_values_[j6+YX];
|
---|
| 434 | double bvjyy = bsh_values_[j6+YY];
|
---|
| 435 | double bvjzx = bsh_values_[j6+ZX];
|
---|
| 436 | double bvjzy = bsh_values_[j6+ZY];
|
---|
| 437 | double bvjzz = bsh_values_[j6+ZZ];
|
---|
| 438 |
|
---|
| 439 | hess[XX] += densij*(bvi*bvjxx+bvix*bvjx+bvjx*bvix+bvixx*bvj);
|
---|
| 440 | hess[YX] += densij*(bvi*bvjyx+bviy*bvjx+bvjy*bvix+bviyx*bvj);
|
---|
| 441 | hess[YY] += densij*(bvi*bvjyy+bviy*bvjy+bvjy*bviy+bviyy*bvj);
|
---|
| 442 | hess[ZX] += densij*(bvi*bvjzx+bviz*bvjx+bvjz*bvix+bvizx*bvj);
|
---|
| 443 | hess[ZY] += densij*(bvi*bvjzy+bviz*bvjy+bvjz*bviy+bvizy*bvj);
|
---|
| 444 | hess[ZZ] += densij*(bvi*bvjzz+bviz*bvjz+bvjz*bviz+bvizz*bvj);
|
---|
| 445 |
|
---|
| 446 | j6 += 6;
|
---|
| 447 | }
|
---|
| 448 | }
|
---|
| 449 | densij = dmat[itoff+it]*bvi;
|
---|
| 450 | tmp += t + 0.5*densij*bvi;
|
---|
| 451 | if (need_gradient_) {
|
---|
| 452 | grad[X] += densij*bvix;
|
---|
| 453 | grad[Y] += densij*bviy;
|
---|
| 454 | grad[Z] += densij*bviz;
|
---|
| 455 | }
|
---|
| 456 | if (need_hessian_) {
|
---|
| 457 | hess[XX] += densij*bvixx;
|
---|
| 458 | hess[YX] += densij*bviyx;
|
---|
| 459 | hess[YY] += densij*bviyy;
|
---|
| 460 | hess[ZX] += densij*bvizx;
|
---|
| 461 | hess[ZY] += densij*bvizy;
|
---|
| 462 | hess[ZZ] += densij*bvizz;
|
---|
| 463 | }
|
---|
| 464 | }
|
---|
| 465 | }
|
---|
| 466 | else {
|
---|
| 467 | for (i=0; i < ncontrib_bf_; i++) {
|
---|
| 468 | int it = contrib_bf_[i];
|
---|
| 469 | bvi = bs_values_[i];
|
---|
| 470 | int itoff = (it*(it+1))>>1;
|
---|
| 471 | int itjt;
|
---|
| 472 | double t = 0.0;
|
---|
| 473 | for (j=0; j < i; j++) {
|
---|
| 474 | int jt = contrib_bf_[j];
|
---|
| 475 | itjt = itoff+jt;
|
---|
| 476 |
|
---|
| 477 | densij = dmat[itjt];
|
---|
| 478 | double bvj = bs_values_[j];
|
---|
| 479 |
|
---|
| 480 | t += densij*bvi*bvj;
|
---|
| 481 | }
|
---|
| 482 | densij = dmat[itoff+it]*bvi;
|
---|
| 483 | tmp += t + 0.5*densij*bvi;
|
---|
| 484 | }
|
---|
| 485 | }
|
---|
| 486 | if (rho!=0) *rho = tmp;
|
---|
| 487 |
|
---|
| 488 | }
|
---|
| 489 |
|
---|
| 490 | void
|
---|
| 491 | BatchElectronDensity::compute_density(const SCVector3 &r,
|
---|
| 492 | double *adens,
|
---|
| 493 | double *agrad,
|
---|
| 494 | double *ahess,
|
---|
| 495 | double *bdens,
|
---|
| 496 | double *bgrad,
|
---|
| 497 | double *bhess)
|
---|
| 498 | {
|
---|
| 499 | if (alpha_dmat_ == 0) init();
|
---|
| 500 |
|
---|
| 501 | need_gradient_ = (agrad!=0) || (bgrad!=0);
|
---|
| 502 | need_hessian_ = (ahess!=0) || (bhess!=0);
|
---|
| 503 |
|
---|
| 504 | compute_basis_values(r);
|
---|
| 505 |
|
---|
| 506 | compute_spin_density(alpha_dmat_,
|
---|
| 507 | adens,
|
---|
| 508 | agrad,
|
---|
| 509 | ahess);
|
---|
| 510 |
|
---|
| 511 | bool mismatch = (adens==0 && bdens!=0)
|
---|
| 512 | ||(agrad==0 && bgrad!=0)
|
---|
| 513 | ||(ahess==0 && bhess!=0);
|
---|
| 514 |
|
---|
| 515 | if (spin_polarized_ || mismatch) {
|
---|
| 516 | compute_spin_density(beta_dmat_,
|
---|
| 517 | bdens,
|
---|
| 518 | bgrad,
|
---|
| 519 | bhess);
|
---|
| 520 | }
|
---|
| 521 | else {
|
---|
| 522 | if (bdens!=0) *bdens = *adens;
|
---|
| 523 | if (bgrad!=0)
|
---|
| 524 | for (int i=0;i<3;i++) bgrad[i] = agrad[i];
|
---|
| 525 | if (bhess!=0)
|
---|
| 526 | for (int i=0;i<6;i++) bhess[i] = ahess[i];
|
---|
| 527 | }
|
---|
| 528 |
|
---|
| 529 | if (adens!=0) *adens *= 2.0;
|
---|
| 530 | if (agrad!=0)
|
---|
| 531 | for (int i=0;i<3;i++) agrad[i] *= 2.0;
|
---|
| 532 | if (ahess!=0)
|
---|
| 533 | for (int i=0;i<6;i++) ahess[i] *= 2.0;
|
---|
| 534 | if (bdens!=0) *bdens *= 2.0;
|
---|
| 535 | if (bgrad!=0)
|
---|
| 536 | for (int i=0;i<3;i++) bgrad[i] *= 2.0;
|
---|
| 537 | if (bhess!=0)
|
---|
| 538 | for (int i=0;i<6;i++) bhess[i] *= 2.0;
|
---|
| 539 |
|
---|
| 540 | // if (agrad) {
|
---|
| 541 | // cout << scprintf("compute_density: agrad = %12.8f %12.8f %12.8f",
|
---|
| 542 | // agrad[0], agrad[1], agrad[2])
|
---|
| 543 | // << endl;
|
---|
| 544 | // }
|
---|
| 545 |
|
---|
| 546 | // cout << "compute_density: exiting"
|
---|
| 547 | // << std::endl;
|
---|
| 548 |
|
---|
| 549 | }
|
---|
| 550 |
|
---|
| 551 | void
|
---|
| 552 | BatchElectronDensity::compute()
|
---|
| 553 | {
|
---|
| 554 | SCVector3 r;
|
---|
| 555 | get_x(r);
|
---|
| 556 |
|
---|
| 557 | double val;
|
---|
| 558 | double grad[3];
|
---|
| 559 | double hess[6];
|
---|
| 560 | double aval;
|
---|
| 561 | double agrad[3];
|
---|
| 562 | double ahess[6];
|
---|
| 563 | double bval;
|
---|
| 564 | double bgrad[3];
|
---|
| 565 | double bhess[6];
|
---|
| 566 | compute_density(r,
|
---|
| 567 | &aval,
|
---|
| 568 | (gradient_needed()?agrad:0),
|
---|
| 569 | (hessian_needed()?ahess:0),
|
---|
| 570 | &bval,
|
---|
| 571 | (gradient_needed()?bgrad:0),
|
---|
| 572 | (hessian_needed()?bhess:0));
|
---|
| 573 | val = aval + bval;
|
---|
| 574 | for (int i=0; i<3; i++) grad[i] = agrad[i] + bgrad[i];
|
---|
| 575 | for (int i=0; i<6; i++) hess[i] = ahess[i] + bhess[i];
|
---|
| 576 |
|
---|
| 577 | if (value_needed()) {
|
---|
| 578 | set_value(val);
|
---|
| 579 | set_actual_value_accuracy(desired_value_accuracy());
|
---|
| 580 | }
|
---|
| 581 | if (gradient_needed()) {
|
---|
| 582 | set_value(val);
|
---|
| 583 | set_actual_value_accuracy(desired_value_accuracy());
|
---|
| 584 | SCVector3 d(grad);
|
---|
| 585 | set_gradient(d);
|
---|
| 586 | set_actual_gradient_accuracy(desired_gradient_accuracy());
|
---|
| 587 | }
|
---|
| 588 | if (hessian_needed()) {
|
---|
| 589 | ExEnv::err0() << indent
|
---|
| 590 | << "BatchElectronDensity::compute(): hessian isn't yet implemented\n";
|
---|
| 591 | abort();
|
---|
| 592 | }
|
---|
| 593 | }
|
---|
| 594 |
|
---|
| 595 | void
|
---|
| 596 | BatchElectronDensity::boundingbox(double valuemin,
|
---|
| 597 | double valuemax,
|
---|
| 598 | SCVector3& p1, SCVector3& p2)
|
---|
| 599 | {
|
---|
| 600 | #if 0
|
---|
| 601 | // this is a very conservative bounding box
|
---|
| 602 | // also, this code is not correct since extent is not
|
---|
| 603 | // necessarily initialized
|
---|
| 604 | if (alpha_dmat_ == 0) init();
|
---|
| 605 | for (int i=0; i<3; i++) p1[i] = extent_->lower(i);
|
---|
| 606 | for (int i=0; i<3; i++) p2[i] = extent_->upper(i);
|
---|
| 607 | #else
|
---|
| 608 | Molecule& mol = *wfn_->molecule();
|
---|
| 609 |
|
---|
| 610 | if (mol.natom() == 0) {
|
---|
| 611 | for (int i=0; i<3; i++) p1[i] = p2[i] = 0.0;
|
---|
| 612 | }
|
---|
| 613 |
|
---|
| 614 | int i;
|
---|
| 615 | for (i=0; i<3; i++) p1[i] = p2[i] = mol.r(0,i);
|
---|
| 616 | for (i=1; i<mol.natom(); i++) {
|
---|
| 617 | for (int j=0; j<3; j++) {
|
---|
| 618 | if (mol.r(i,j) < p1[j]) p1[j] = mol.r(i,j);
|
---|
| 619 | if (mol.r(i,j) > p2[j]) p2[j] = mol.r(i,j);
|
---|
| 620 | }
|
---|
| 621 | }
|
---|
| 622 | for (i=0; i<3; i++) {
|
---|
| 623 | p1[i] = p1[i] - 3.0;
|
---|
| 624 | p2[i] = p2[i] + 3.0;
|
---|
| 625 | }
|
---|
| 626 | #endif
|
---|
| 627 | }
|
---|
| 628 |
|
---|
| 629 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 630 | // DensityColorizer
|
---|
| 631 |
|
---|
| 632 | static ClassDesc DensityColorizer_cd(
|
---|
| 633 | typeid(DensityColorizer),"DensityColorizer",1,"public MoleculeColorizer",
|
---|
| 634 | 0, create<DensityColorizer>, 0);
|
---|
| 635 |
|
---|
| 636 | DensityColorizer::DensityColorizer(const Ref<KeyVal>&keyval):
|
---|
| 637 | MoleculeColorizer(keyval)
|
---|
| 638 | {
|
---|
| 639 | wfn_ << keyval->describedclassvalue("wfn");
|
---|
| 640 | reference_ = keyval->doublevalue("reference");
|
---|
| 641 | if (keyval->error() == KeyVal::OK) have_reference_ = 1;
|
---|
| 642 | else have_reference_ = 0;
|
---|
| 643 | scale_ = keyval->doublevalue("scale");
|
---|
| 644 | if (keyval->error() == KeyVal::OK) have_scale_ = 1;
|
---|
| 645 | else have_scale_ = 0;
|
---|
| 646 | }
|
---|
| 647 |
|
---|
| 648 | DensityColorizer::~DensityColorizer()
|
---|
| 649 | {
|
---|
| 650 | }
|
---|
| 651 |
|
---|
| 652 | void
|
---|
| 653 | DensityColorizer::colorize(const Ref<RenderedPolygons> &poly)
|
---|
| 654 | {
|
---|
| 655 | const double base = 0.3;
|
---|
| 656 | int i;
|
---|
| 657 | int nvertex = poly->nvertex();
|
---|
| 658 |
|
---|
| 659 | if (nvertex) {
|
---|
| 660 | double *data = new double[nvertex];
|
---|
| 661 |
|
---|
| 662 | for (i=0; i<nvertex; i++) {
|
---|
| 663 | SCVector3 v(poly->vertex(i));
|
---|
| 664 | data[i] = wfn_->density(v);
|
---|
| 665 | }
|
---|
| 666 |
|
---|
| 667 | double min = data[0], max = data[0];
|
---|
| 668 | for (i=1; i<nvertex; i++) {
|
---|
| 669 | if (min > data[i]) min = data[i];
|
---|
| 670 | if (max < data[i]) max = data[i];
|
---|
| 671 | }
|
---|
| 672 |
|
---|
| 673 | double center, scale;
|
---|
| 674 |
|
---|
| 675 | if (have_reference_) center = reference_;
|
---|
| 676 | else center = (max+min)/2.0;
|
---|
| 677 |
|
---|
| 678 | double maxdiff = fabs(max - center);
|
---|
| 679 | double mindiff = fabs(min - center);
|
---|
| 680 |
|
---|
| 681 | if (have_scale_) {
|
---|
| 682 | scale = scale_;
|
---|
| 683 | }
|
---|
| 684 | else {
|
---|
| 685 | if (maxdiff>mindiff && maxdiff>1.0e-6) scale = (1.0-base)/maxdiff;
|
---|
| 686 | else if (mindiff>1.0e-6) scale = (1.0-base)/mindiff;
|
---|
| 687 | else scale = (1.0-base);
|
---|
| 688 | }
|
---|
| 689 |
|
---|
| 690 | ExEnv::out0() << indent << "DensityColorizer:"
|
---|
| 691 | << scprintf(" reference=%6.5f", center)
|
---|
| 692 | << scprintf(" scale=%8.4f",scale)
|
---|
| 693 | << scprintf(" (%6.5f<=rho<=%6.5f)", max, min)
|
---|
| 694 | << endl;
|
---|
| 695 | for (i=0; i<nvertex; i++) {
|
---|
| 696 | data[i] = (data[i]-center)*scale;
|
---|
| 697 | }
|
---|
| 698 |
|
---|
| 699 | for (i=0; i<nvertex; i++) {
|
---|
| 700 | Color c;
|
---|
| 701 | if (data[i] < 0.0) c.set_rgb(-data[i]+base,0.3,0.3);
|
---|
| 702 | else c.set_rgb(0.3,0.3,data[i]+base);
|
---|
| 703 | poly->set_vertex_color(i,c);
|
---|
| 704 | }
|
---|
| 705 |
|
---|
| 706 | delete[] data;
|
---|
| 707 | }
|
---|
| 708 | }
|
---|
| 709 |
|
---|
| 710 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 711 | // GradDensityColorizer
|
---|
| 712 |
|
---|
| 713 | static ClassDesc GradDensityColorizer_cd(
|
---|
| 714 | typeid(GradDensityColorizer),"GradDensityColorizer",1,"public MoleculeColorizer",
|
---|
| 715 | 0, create<GradDensityColorizer>, 0);
|
---|
| 716 |
|
---|
| 717 | GradDensityColorizer::GradDensityColorizer(const Ref<KeyVal>&keyval):
|
---|
| 718 | MoleculeColorizer(keyval)
|
---|
| 719 | {
|
---|
| 720 | wfn_ << keyval->describedclassvalue("wfn");
|
---|
| 721 | reference_ = keyval->doublevalue("reference");
|
---|
| 722 | if (keyval->error() == KeyVal::OK) have_reference_ = 1;
|
---|
| 723 | else have_reference_ = 0;
|
---|
| 724 | scale_ = keyval->doublevalue("scale");
|
---|
| 725 | if (keyval->error() == KeyVal::OK) have_scale_ = 1;
|
---|
| 726 | else have_scale_ = 0;
|
---|
| 727 | }
|
---|
| 728 |
|
---|
| 729 | GradDensityColorizer::~GradDensityColorizer()
|
---|
| 730 | {
|
---|
| 731 | }
|
---|
| 732 |
|
---|
| 733 | void
|
---|
| 734 | GradDensityColorizer::colorize(const Ref<RenderedPolygons> &poly)
|
---|
| 735 | {
|
---|
| 736 | const double base = 0.3;
|
---|
| 737 | int i;
|
---|
| 738 | int nvertex = poly->nvertex();
|
---|
| 739 |
|
---|
| 740 | Ref<BatchElectronDensity> den = new BatchElectronDensity(wfn_);
|
---|
| 741 |
|
---|
| 742 | if (nvertex) {
|
---|
| 743 | double *data = new double[nvertex];
|
---|
| 744 |
|
---|
| 745 | for (i=0; i<nvertex; i++) {
|
---|
| 746 | SCVector3 v(poly->vertex(i));
|
---|
| 747 | SCVector3 g;
|
---|
| 748 | den->set_x(v);
|
---|
| 749 | den->get_gradient(g);
|
---|
| 750 | data[i] = g.norm();
|
---|
| 751 | }
|
---|
| 752 |
|
---|
| 753 | double min = data[0], max = data[0];
|
---|
| 754 | for (i=1; i<nvertex; i++) {
|
---|
| 755 | if (min > data[i]) min = data[i];
|
---|
| 756 | if (max < data[i]) max = data[i];
|
---|
| 757 | }
|
---|
| 758 |
|
---|
| 759 | double center, scale;
|
---|
| 760 |
|
---|
| 761 | if (have_reference_) center = reference_;
|
---|
| 762 | else center = (max+min)/2.0;
|
---|
| 763 |
|
---|
| 764 | double maxdiff = fabs(max - center);
|
---|
| 765 | double mindiff = fabs(min - center);
|
---|
| 766 |
|
---|
| 767 | if (have_scale_) {
|
---|
| 768 | scale = scale_;
|
---|
| 769 | }
|
---|
| 770 | else {
|
---|
| 771 | if (maxdiff>mindiff && maxdiff>1.0e-6) scale = (1.0-base)/maxdiff;
|
---|
| 772 | else if (mindiff>1.0e-6) scale = (1.0-base)/mindiff;
|
---|
| 773 | else scale = (1.0-base);
|
---|
| 774 | }
|
---|
| 775 |
|
---|
| 776 | ExEnv::out0() << indent << "GradDensityColorizer:"
|
---|
| 777 | << scprintf(" reference=%6.5f", center)
|
---|
| 778 | << scprintf(" scale=%6.2f",scale)
|
---|
| 779 | << scprintf(" (%6.5f<=rho<=%6.5f)", max, min)
|
---|
| 780 | << endl;
|
---|
| 781 | for (i=0; i<nvertex; i++) {
|
---|
| 782 | data[i] = (data[i]-center)*scale;
|
---|
| 783 | }
|
---|
| 784 |
|
---|
| 785 | for (i=0; i<nvertex; i++) {
|
---|
| 786 | Color c;
|
---|
| 787 | if (data[i] > 0.0) c.set_rgb(data[i]+base,0.3,0.3);
|
---|
| 788 | else c.set_rgb(0.3,0.3,-data[i]+base);
|
---|
| 789 | poly->set_vertex_color(i,c);
|
---|
| 790 | }
|
---|
| 791 |
|
---|
| 792 | delete[] data;
|
---|
| 793 | }
|
---|
| 794 | }
|
---|
| 795 |
|
---|
| 796 | /////////////////////////////////////////////////////////////////////////////
|
---|
| 797 |
|
---|
| 798 | // Local Variables:
|
---|
| 799 | // mode: c++
|
---|
| 800 | // c-file-style: "CLJ"
|
---|
| 801 | // End:
|
---|