source: ThirdParty/mpqc_open/src/lib/chemistry/qc/basis/gaussshval.cc@ aae63a

Action_Thermostats Add_AtomRandomPerturbation Add_RotateAroundBondAction Add_SelectAtomByNameAction Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests AutomationFragmentation_failures Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_ChronosMutex Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion GeometryObjects Gui_displays_atomic_force_velocity IndependentFragmentGrids_IntegrationTest JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks RotateToPrincipalAxisSystem_UndoRedo StoppableMakroAction Subpackage_levmar Subpackage_vmg ThirdParty_MPQC_rebuilt_buildsystem TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes stable
Last change on this file since aae63a was 860145, checked in by Frederik Heber <heber@…>, 8 years ago

Merge commit '0b990dfaa8c6007a996d030163a25f7f5fc8a7e7' as 'ThirdParty/mpqc_open'

  • Property mode set to 100644
File size: 16.8 KB
Line 
1//
2// gaussshval.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#include <stdlib.h>
29#include <math.h>
30
31#include <util/misc/formio.h>
32#include <util/keyval/keyval.h>
33
34#include <chemistry/qc/basis/gaussshell.h>
35#include <chemistry/qc/basis/integral.h>
36#include <chemistry/qc/basis/cartiter.h>
37#include <chemistry/qc/basis/transform.h>
38
39using namespace std;
40using namespace sc;
41
42#define MAX_NPRIM 20
43#define MAX_NCON 10
44#define MAX_AM 8
45
46int
47GaussianShell::values(CartesianIter **civec, SphericalTransformIter **sivec,
48 const SCVector3& r, double* basis_values)
49{
50 return hessian_values(civec, sivec, r, 0, 0, basis_values);
51}
52
53int
54GaussianShell::grad_values(CartesianIter **civec,
55 SphericalTransformIter **sivec,
56 const SCVector3& r,
57 double* g_values,
58 double* basis_values) const
59{
60 return hessian_values(civec, sivec, r, 0, g_values, basis_values);
61}
62
63int
64GaussianShell::hessian_values(CartesianIter **civec,
65 SphericalTransformIter **sivec,
66 const SCVector3& r,
67 double* h_values,
68 double* g_values,
69 double* basis_values) const
70{
71
72 // compute the maximum angular momentum component of the shell
73 int maxam = max_am();
74 if (g_values || h_values) maxam++;
75 if (h_values) maxam++;
76
77 // check limitations
78 if (nprim > MAX_NPRIM || ncon > MAX_NCON || maxam >= MAX_AM) {
79 ExEnv::err0() << indent
80 << "GaussianShell::grad_values: limit exceeded:\n"
81 << indent
82 << scprintf(
83 "ncon = %d (%d max) nprim = %d (%d max) maxam = %d (%d max)\n",
84 ncon,MAX_NCON,nprim,MAX_NPRIM,maxam,MAX_AM-1);
85 abort();
86 }
87
88 // loop variables
89 int i,j;
90
91 // precompute powers of x, y, and z
92 double xs[MAX_AM];
93 double ys[MAX_AM];
94 double zs[MAX_AM];
95 xs[0] = ys[0] = zs[0] = 1.0;
96 if (maxam>0) {
97 xs[1] = r[0];
98 ys[1] = r[1];
99 zs[1] = r[2];
100 }
101 for (i=2; i<=maxam; i++) {
102 xs[i] = xs[i-1]*r[0];
103 ys[i] = ys[i-1]*r[1];
104 zs[i] = zs[i-1]*r[2];
105 }
106
107 // precompute r*r
108 double r2;
109 if (maxam<2) {
110 r2 = 0.0;
111 for (i=0; i<3; i++) {
112 r2+=r[i]*r[i];
113 }
114 }
115 else {
116 r2 = xs[2] + ys[2] + zs[2];
117 }
118
119 // precompute exponentials
120 double exps[MAX_NPRIM];
121 for (i=0; i<nprim; i++) {
122 exps[i]=::exp(-r2*exp[i]);
123 }
124
125 // precompute contractions over exponentials
126 double precon[MAX_NCON];
127 for (i=0; i<ncon; i++) {
128 precon[i] = 0.0;
129 for (j=0; j<nprim; j++) {
130 precon[i] += coef[i][j] * exps[j];
131 }
132 }
133
134 // precompute contractions over exponentials with exponent weighting
135 double precon_g[MAX_NCON];
136 if (g_values || h_values) {
137 for (i=0; i<ncon; i++) {
138 precon_g[i] = 0.0;
139 for (j=0; j<nprim; j++) {
140 precon_g[i] += exp[j] * coef[i][j] * exps[j];
141 }
142 precon_g[i] *= 2.0;
143 }
144 }
145
146 // precompute contractions over exponentials with exponent^2 weighting
147 double precon_h[MAX_NCON];
148 if (h_values) {
149 for (i=0; i<ncon; i++) {
150 precon_h[i] = 0.0;
151 for (j=0; j<nprim; j++) {
152 precon_h[i] += exp[j] * exp[j] * coef[i][j] * exps[j];
153 }
154 precon_h[i] *= 4.0;
155 }
156 }
157
158 // compute the shell values
159 int i_basis=0; // Basis function counter
160 if (basis_values) {
161 for (i=0; i<ncon; i++) {
162 // handle s functions with a special case to speed things up
163 if (l[i] == 0) {
164 basis_values[i_basis] = precon[i];
165 i_basis++;
166 }
167 else if (!puream[i]) {
168 CartesianIter *jp = civec[l[i]];
169 CartesianIter& j = *jp;
170 for (j.start(); j; j.next()) {
171 basis_values[i_basis] = xs[j.a()]*ys[j.b()]*zs[j.c()]
172 *precon[i];
173 i_basis++;
174 }
175 }
176 else {
177 double cart_basis_values[((MAX_AM+1)*(MAX_AM+2))/2];
178 CartesianIter *jp = civec[l[i]];
179 CartesianIter& j = *jp;
180 int i_cart = 0;
181 for (j.start(); j; j.next()) {
182 cart_basis_values[i_cart] = xs[j.a()]*ys[j.b()]*zs[j.c()]
183 *precon[i];
184 i_cart++;
185 }
186 SphericalTransformIter *ti = sivec[l[i]];
187 int n = ti->n();
188 memset(&basis_values[i_basis], 0, sizeof(double)*n);
189 for (ti->start(); ti->ready(); ti->next()) {
190 basis_values[i_basis + ti->pureindex()]
191 += ti->coef() * cart_basis_values[ti->cartindex()];
192 }
193 i_basis += n;
194 }
195 }
196 }
197
198 // compute the gradient of the shell values
199 if (g_values) {
200 int i_grad=0; // Basis function counter
201 for (i=0; i<ncon; i++) {
202 // handle s functions with a special case to speed things up
203 if (l[i] == 0) {
204 double norm_precon_g = precon_g[i];
205 g_values[i_grad] = -xs[1]*norm_precon_g;
206 i_grad++;
207 g_values[i_grad] = -ys[1]*norm_precon_g;
208 i_grad++;
209 g_values[i_grad] = -zs[1]*norm_precon_g;
210 i_grad++;
211 }
212 else if (!puream[i]) {
213 CartesianIter *jp = civec[l[i]];
214 CartesianIter& j = *jp;
215 for (j.start(); j; j.next()) {
216 double norm_precon = precon[i];
217 double norm_precon_g = precon_g[i];
218 g_values[i_grad] = - norm_precon_g
219 * xs[j.a()+1] * ys[j.b()] * zs[j.c()];
220 if (j.a()) g_values[i_grad] += j.a() * norm_precon
221 * xs[j.a()-1] * ys[j.b()] * zs[j.c()];
222 i_grad++;
223
224 g_values[i_grad] = - norm_precon_g
225 * xs[j.a()] * ys[j.b()+1] * zs[j.c()];
226 if (j.b()) g_values[i_grad] += j.b() * norm_precon
227 * xs[j.a()] * ys[j.b()-1] * zs[j.c()];
228 i_grad++;
229
230 g_values[i_grad] = - norm_precon_g
231 * xs[j.a()] * ys[j.b()] * zs[j.c()+1];
232 if (j.c()) g_values[i_grad] += j.c() * norm_precon
233 * xs[j.a()] * ys[j.b()] * zs[j.c()-1];
234 i_grad++;
235 }
236 }
237 else {
238 double cart_g_values[3*((MAX_AM+1)*(MAX_AM+2))/2];
239 CartesianIter *jp = civec[l[i]];
240 CartesianIter& j = *jp;
241 int i_cart = 0;
242 for (j.start(); j; j.next()) {
243 double norm_precon = precon[i];
244 double norm_precon_g = precon_g[i];
245 cart_g_values[i_cart] = - norm_precon_g
246 * xs[j.a()+1] * ys[j.b()] * zs[j.c()];
247 if (j.a()) cart_g_values[i_cart] += j.a() * norm_precon
248 * xs[j.a()-1] * ys[j.b()] * zs[j.c()];
249 i_cart++;
250
251 cart_g_values[i_cart] = - norm_precon_g
252 * xs[j.a()] * ys[j.b()+1] * zs[j.c()];
253 if (j.b()) cart_g_values[i_cart] += j.b() * norm_precon
254 * xs[j.a()] * ys[j.b()-1] * zs[j.c()];
255 i_cart++;
256
257 cart_g_values[i_cart] = - norm_precon_g
258 * xs[j.a()] * ys[j.b()] * zs[j.c()+1];
259 if (j.c()) cart_g_values[i_cart] += j.c() * norm_precon
260 * xs[j.a()] * ys[j.b()] * zs[j.c()-1];
261 i_cart++;
262 }
263 SphericalTransformIter *ti = sivec[l[i]];
264 int n = ti->n();
265 memset(&g_values[i_grad], 0, sizeof(double)*n*3);
266 for (ti->start(); ti->ready(); ti->next()) {
267 double coef = ti->coef();
268 int pi = ti->pureindex();
269 int ci = ti->cartindex();
270 for (int xyz=0; xyz<3; xyz++) {
271 g_values[i_grad + pi*3 + xyz]
272 += coef * cart_g_values[ci*3 + xyz];
273 }
274 }
275 i_grad += 3*n;
276 }
277 }
278 }
279
280 // compute the hessian of the shell values
281 if (h_values) {
282 int i_hess=0; // Basis function counter
283 for (i=0; i<ncon; i++) {
284 // handle s functions with a special case to speed things up
285 if (l[i] == 0) {
286 double norm_precon_g = precon_g[i];
287 double norm_precon_h = precon_h[i];
288 // xx
289 h_values[i_hess] = norm_precon_h*xs[2] - norm_precon_g;
290 i_hess++;
291 // yx
292 h_values[i_hess] = norm_precon_h*xs[1]*ys[1];
293 i_hess++;
294 // yy
295 h_values[i_hess] = norm_precon_h*ys[2] - norm_precon_g;
296 i_hess++;
297 // zx
298 h_values[i_hess] = norm_precon_h*zs[1]*xs[1];
299 i_hess++;
300 // zy
301 h_values[i_hess] = norm_precon_h*zs[1]*ys[1];
302 i_hess++;
303 // zz
304 h_values[i_hess] = norm_precon_h*zs[2] - norm_precon_g;
305 i_hess++;
306 }
307 else {
308 double *cart_h;
309 double tmp_cart_h[6*((MAX_AM+1)*(MAX_AM+2))/2];
310 if (!puream[i]) {
311 cart_h = &h_values[i_hess];
312 }
313 else {
314 cart_h = tmp_cart_h;
315 }
316 CartesianIter *jp = civec[l[i]];
317 CartesianIter& j = *jp;
318 int i_cart = 0;
319 for (j.start(); j; j.next()) {
320 double pre = precon[i];
321 double pre_g = - precon_g[i];
322 double pre_h = precon_h[i];
323 int a = j.a();
324 int b = j.b();
325 int c = j.c();
326 // xx
327 cart_h[i_cart] = pre_h * xs[a+2]*ys[b]*zs[c]
328 + pre_g * (a+1) * xs[a]*ys[b]*zs[c];
329 if (a>0) {
330 cart_h[i_cart] += pre_g * a*xs[a]*ys[b]*zs[c];
331 if (a>1) cart_h[i_cart] += pre * a*(a-1)
332 * xs[a-2]*ys[b]*zs[c];
333 }
334 i_cart++;
335
336 // yx
337 cart_h[i_cart] = pre_h * xs[a+1]*ys[b+1]*zs[c];
338 if (a>0)
339 cart_h[i_cart] += pre_g * a * xs[a-1]*ys[b+1]*zs[c];
340 if (b>0)
341 cart_h[i_cart] += pre_g * b * xs[a+1]*ys[b-1]*zs[c];
342 if (a>0 && b>0)
343 cart_h[i_cart] += pre * a*b * xs[a-1]*ys[b-1]*zs[c];
344 i_cart++;
345
346 // yy
347 cart_h[i_cart] = pre_h * xs[a]*ys[b+2]*zs[c]
348 + pre_g * (b+1) * xs[a]*ys[b]*zs[c];
349 if (b>0) {
350 cart_h[i_cart] += pre_g * b*xs[a]*ys[b]*zs[c];
351 if (b>1) cart_h[i_cart] += pre * b*(b-1)
352 * xs[a]*ys[b-2]*zs[c];
353 }
354 i_cart++;
355
356 // zx
357 cart_h[i_cart] = pre_h * xs[a+1]*ys[b]*zs[c+1];
358 if (a>0)
359 cart_h[i_cart] += pre_g * a * xs[a-1]*ys[b]*zs[c+1];
360 if (c>0)
361 cart_h[i_cart] += pre_g * c * xs[a+1]*ys[b]*zs[c-1];
362 if (a>0 && c>0)
363 cart_h[i_cart] += pre * a*c * xs[a-1]*ys[b]*zs[c-1];
364 i_cart++;
365
366 // zy
367 cart_h[i_cart] = pre_h * xs[a]*ys[b+1]*zs[c+1];
368 if (c>0)
369 cart_h[i_cart] += pre_g * c * xs[a]*ys[b+1]*zs[c-1];
370 if (b>0)
371 cart_h[i_cart] += pre_g * b * xs[a]*ys[b-1]*zs[c+1];
372 if (c>0 && b>0)
373 cart_h[i_cart] += pre * c*b * xs[a]*ys[b-1]*zs[c-1];
374 i_cart++;
375
376 // zz
377 cart_h[i_cart] = pre_h * xs[a]*ys[b]*zs[c+2]
378 + pre_g * (c+1) * xs[a]*ys[b]*zs[c];
379 if (c>0) {
380 cart_h[i_cart] += pre_g * c*xs[a]*ys[b]*zs[c];
381 if (c>1) cart_h[i_cart] += pre * c*(c-1)
382 * xs[a]*ys[b]*zs[c-2];
383 }
384 i_cart++;
385 }
386 if (puream[i]) {
387 SphericalTransformIter *ti = sivec[l[i]];
388 int n = ti->n();
389 memset(&h_values[i_hess], 0, sizeof(double)*n*6);
390 for (ti->start(); ti->ready(); ti->next()) {
391 double coef = ti->coef();
392 int pi = ti->pureindex();
393 int ci = ti->cartindex();
394 for (int xyz2=0; xyz2<6; xyz2++) {
395 h_values[i_hess + pi*6 + xyz2]
396 += coef * cart_h[ci*6 + xyz2];
397 }
398 }
399 i_hess += 6*n;
400 }
401 else {
402 i_hess += 3*(l[i]+1)*(l[i]+2);
403 }
404 }
405 }
406 }
407
408 return i_basis;
409}
410
411int
412GaussianShell::test_monobound(double &r, double &bound) const
413{
414 // compute the maximum angular momentum component of the shell
415 // add one since derivatives will be needed
416 int maxam = max_am() + 1;
417
418 // check limitations
419 if (nprim > MAX_NPRIM || ncon > MAX_NCON || maxam >= MAX_AM) {
420 ExEnv::err0() << indent
421 << "GaussianShell::gaussshval: limit exceeded:\n"
422 << indent
423 << scprintf(
424 "ncon = %d (%d max) nprim = %d (%d max) maxam = %d (%d max)\n",
425 ncon,MAX_NCON,nprim,MAX_NPRIM,maxam,MAX_AM-1);
426 abort();
427 }
428
429 // loop variables
430 int i,j;
431
432 // precompute powers of r
433 double rs[MAX_AM+1];
434 rs[0] = 1.0;
435 if (maxam>0) {
436 rs[1] = r;
437 }
438 for (i=2; i<=maxam; i++) {
439 rs[i] = rs[i-1]*r;
440 }
441
442 // precompute r*r
443 double r2 = r*r;
444
445 // precompute exponentials
446 double exps[MAX_NPRIM];
447 for (i=0; i<nprim; i++) {
448 exps[i]=::exp(-r2*exp[i]);
449 }
450
451 // precompute contractions over exponentials
452 double precon[MAX_NCON];
453 for (i=0; i<ncon; i++) {
454 precon[i] = 0.0;
455 for (j=0; j<nprim; j++) {
456 // using fabs since we want a monotonically decreasing bound
457 precon[i] += fabs(coef[i][j]) * exps[j];
458 }
459 }
460
461 // precompute contractions over exponentials with exponent weighting
462 double precon_w[MAX_NCON];
463 for (i=0; i<ncon; i++) {
464 precon_w[i] = 0.0;
465 for (j=0; j<nprim; j++) {
466 precon_w[i] += exp[j] * fabs(coef[i][j]) * exps[j];
467 }
468 }
469
470 double max_bound = 0.0;
471 bound = 0.0;
472 for (i=0; i<ncon; i++) {
473 // using r^l since r^l >= x^a y^b z^c
474 double component_bound = rs[l[i]]*precon[i];
475 if (l[i] > 0) {
476 double d1 = -2.0*rs[l[i]+1]*precon_w[i];
477 double d2 = l[i]*rs[l[i]-1]*precon[i];
478 if (d1+d2 > 0) {
479 // This bound is no good since the contraction is increasing
480 // at this position. Move r out and return to let the driver
481 // call again.
482 double rold = r;
483 r = sqrt(l[i]*precon[i]/(2.0*precon_w[i]));
484 if (r<rold+0.01) r = rold+0.01;
485 //ExEnv::outn() << "rejected at " << rold << " trying again at "
486 // << r << endl;
487 return 1;
488 }
489 }
490 if (component_bound > max_bound) {
491 max_bound = component_bound;
492 }
493 }
494
495 bound = max_bound;
496 return 0;
497}
498
499double
500GaussianShell::monobound(double r) const
501{
502 // doesn't work at r <= zero
503 if (r<=0.001) r = 0.001;
504 double b;
505 while (test_monobound(r, b));
506 return b;
507}
508
509/////////////////////////////////////////////////////////////////////////////
510
511// Local Variables:
512// mode: c++
513// c-file-style: "CLJ"
514// End:
Note: See TracBrowser for help on using the repository browser.