LIBINT 2.7.2
vrr_1_onep_1.h
1/*
2 * Copyright (C) 2004-2021 Edward F. Valeev
3 *
4 * This file is part of Libint.
5 *
6 * Libint is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Libint is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Libint. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#ifndef _libint2_src_bin_libint_vrr1onep1_h_
22#define _libint2_src_bin_libint_vrr1onep1_h_
23
24#include <cassert>
25#include <generic_rr.h>
26#include <onep_1_1.h>
27
28namespace libint2 {
29
33 template <class BFSet, FunctionPosition where>
34 class VRR_1_Overlap_1 : public GenericRecurrenceRelation< VRR_1_Overlap_1<BFSet,where>,
35 BFSet,
36 GenIntegralSet_1_1<BFSet,OverlapOper,EmptySet> >
37 {
38 public:
44 static const unsigned int max_nchildren = 9;
45
47
49 static bool directional() { return ParentType::default_directional(); }
50
51 private:
52 using ParentType::RecurrenceRelation::expr_;
53 using ParentType::RecurrenceRelation::nflops_;
54 using ParentType::target_;
56
58 VRR_1_Overlap_1(const SafePtr<TargetType>&, unsigned int dir);
59
60 static std::string descr() { return "OSVRROverlap"; }
61 };
62
63 template <class F, FunctionPosition where>
64 VRR_1_Overlap_1<F,where>::VRR_1_Overlap_1(const SafePtr< TargetType >& Tint,
65 unsigned int dir) :
66 ParentType(Tint,dir)
67 {
68 using namespace libint2::algebra;
69 using namespace libint2::prefactor;
70 using namespace libint2::braket;
71 const F& _1 = unit<F>(dir);
72
73 { // can't apply to contracted basis functions
74 F a(Tint->bra(0,0));
75 F b(Tint->ket(0,0));
76 if (a.contracted() ||
77 b.contracted())
78 return;
79 }
80
81 // if derivative integrals, there will be extra terms (Eq. (143) in Obara & Saika JCP 89)
82 const OriginDerivative<3u> dA = Tint->bra(0,0).deriv();
83 const OriginDerivative<3u> dB = Tint->ket(0,0).deriv();
84 const bool deriv = !dA.zero() ||
85 !dB.zero();
86
87 typedef TargetType ChildType;
88 ChildFactory<ThisType,ChildType> factory(this);
89
90 // Build on A or B
91 {
92 // bf quantum on the build center subtracted by 1
93 auto a = ( where == InBra ? Tint->bra(0,0) - _1 : Tint->bra(0,0) );
94 if (!exists(a)) return;
95 auto b = ( where == InKet ? Tint->ket(0,0) - _1 : Tint->ket(0,0) );
96 if (!exists(b)) return;
97
98 auto AB = factory.make_child(a,b);
99 if (is_simple()) { expr_ = Vector(where == InBra ? "PA" : "PB")[dir] * AB; nflops_+=1; }
100
101 auto am1 = a - _1; auto am1_exists = exists(am1);
102 auto bm1 = b - _1; auto bm1_exists = exists(bm1);
103
104 if (am1_exists) {
105 auto Am1B = factory.make_child(am1,b);
106 if (is_simple()) { expr_ += (Scalar(a[dir]) * Scalar("oo2z")) * Am1B; nflops_+=3; }
107 }
108 if (bm1_exists) {
109 auto ABm1 = factory.make_child(a,bm1);
110 if (is_simple()) { expr_ += (Scalar(b[dir]) * Scalar("oo2z")) * ABm1; nflops_+=3; }
111 }
112 }
113
114 // if got here, can decrement by at least 1 quantum
115 // add additional derivative terms
116 if (deriv) {
117 // bf quantum on the build center subtracted by 1
118 F a( where == InBra ? Tint->bra(0,0) - _1 : Tint->bra(0,0) );
119 F b( where == InKet ? Tint->ket(0,0) - _1 : Tint->ket(0,0) );
120
121 // treatment of derivative terms differs for shell sets and integrals
122 // since in computing shell sets transfer/build will occur in all 3 directions
123 // change in up to all three derivative indices will occur
124 for(unsigned int dxyz=0; dxyz<3; ++dxyz) {
125
126 if (is_simple() && dxyz != dir) // for integrals only consider derivatives in THE build direction
127 continue;
128
129 OriginDerivative<3u> _d1; _d1.inc(dxyz);
130
131 SafePtr<DGVertex> _nullptr;
132
133 // dA - _1?
134 {
135 const OriginDerivative<3u> dAm1(dA - _d1);
136 if (exists(dAm1)) { // yes
137 a.deriv() = dAm1;
138 auto AB = factory.make_child(a,b);
139 if (is_simple()) {
140 if (where == InBra) { // building on A
141 expr_ -= Vector(dA)[dxyz] * Scalar("rho12_over_alpha1") * AB; nflops_ += 3; }
142 if (where == InKet) { // building on B
143 expr_ += Vector(dA)[dxyz] * Scalar("rho12_over_alpha2") * AB; nflops_ += 3; }
144 }
145 a.deriv() = dA;
146 }
147 }
148
149 // dB - _1?
150 {
151 const OriginDerivative<3u> dBm1(dB - _d1);
152 if (exists(dBm1)) { // yes
153 b.deriv() = dBm1;
154 auto AB = factory.make_child(a,b);
155 if (is_simple()) {
156 if (where == InBra) { // building on A
157 expr_ += Vector(dB)[dxyz] * Scalar("rho12_over_alpha1") * AB; nflops_ += 3; }
158 if (where == InKet) { // building on B
159 expr_ -= Vector(dB)[dxyz] * Scalar("rho12_over_alpha2") * AB; nflops_ += 3; }
160 }
161 b.deriv() = dB;
162 }
163 }
164
165 }
166 } // end of deriv
167
168 return;
169 }
170
174 template <CartesianAxis Axis, FunctionPosition where>
175 class VRR_1_Overlap_1_1d : public GenericRecurrenceRelation< VRR_1_Overlap_1_1d<Axis,where>,
176 CGF1d<Axis>,
177 GenIntegralSet_1_1<CGF1d<Axis>,OverlapOper,EmptySet> >
178 {
179 public:
185 static const unsigned int max_nchildren = 9;
186 static constexpr auto axis = Axis;
187
189
192
193 private:
194 using ParentType::RecurrenceRelation::expr_;
195 using ParentType::RecurrenceRelation::nflops_;
196 using ParentType::target_;
198
200 VRR_1_Overlap_1_1d(const SafePtr<TargetType>&, unsigned int dir);
201
202 static std::string descr() { return std::string("OSVRROverlap") + to_string(axis); }
203 };
204
205 template <CartesianAxis Axis, FunctionPosition where>
206 VRR_1_Overlap_1_1d<Axis,where>::VRR_1_Overlap_1_1d(const SafePtr< TargetType >& Tint,
207 unsigned int dir) :
208 ParentType(Tint,dir)
209 {
210 assert(dir == 0); // this integral is along 1 axis only
211
212 using namespace libint2::algebra;
213 using namespace libint2::prefactor;
214 using namespace libint2::braket;
215 typedef CGF1d<Axis> F;
216 const F& _1 = unit<F>(dir);
217
218 { // can't apply to contracted basis functions
219 F a(Tint->bra(0,0));
220 F b(Tint->ket(0,0));
221 if (a.contracted() ||
222 b.contracted())
223 return;
224 }
225
226 // if derivative integrals, there will be extra terms (Eq. (143) in Obara & Saika JCP 89)
227 const OriginDerivative<1u> dA = Tint->bra(0,0).deriv();
228 const OriginDerivative<1u> dB = Tint->ket(0,0).deriv();
229 const bool deriv = !dA.zero() ||
230 !dB.zero();
231
232 typedef TargetType ChildType;
233 ChildFactory<ThisType,ChildType> factory(this);
234
235 // handle the special case of (0|0) integral
236 // to avoid complications with non-precomputed shell blocks it's "computed
237 // by copying from inteval
238 auto zero = Tint->bra(0,0).zero() and Tint->ket(0,0).zero() and not deriv;
239 if (zero) {
240 SafePtr<DGVertex> int00 = Vector("_0_Overlap_0")[Axis];
241 expr_ = Scalar(0u) + int00;
242 this->add_child(int00);
243 return;
244 }
245
246 // Build on A or B
247 {
248 // bf quantum on the build center subtracted by 1
249 auto a = ( where == InBra ? Tint->bra(0,0) - _1 : Tint->bra(0,0) );
250 if (!exists(a)) return;
251 auto b = ( where == InKet ? Tint->ket(0,0) - _1 : Tint->ket(0,0) );
252 if (!exists(b)) return;
253
254 auto AB = factory.make_child(a,b);
255 if (is_simple()) { expr_ = Vector(where == InBra ? "PA" : "PB")[Axis] * AB; nflops_+=1; }
256
257 auto am1 = a - _1; auto am1_exists = exists(am1);
258 auto bm1 = b - _1; auto bm1_exists = exists(bm1);
259
260 if (am1_exists) {
261 auto Am1B = factory.make_child(am1,b);
262 if (is_simple()) { expr_ += (Scalar(a.qn()) * Scalar("oo2z")) * Am1B; nflops_+=3; }
263 }
264 if (bm1_exists) {
265 auto ABm1 = factory.make_child(a,bm1);
266 if (is_simple()) { expr_ += (Scalar(b.qn()) * Scalar("oo2z")) * ABm1; nflops_+=3; }
267 }
268 }
269
270 // if got here, can decrement by at least 1 quantum
271 // add additional derivative terms
272 if (deriv) {
273 // bf quantum on the build center subtracted by 1
274 F a( where == InBra ? Tint->bra(0,0) - _1 : Tint->bra(0,0) );
275 F b( where == InKet ? Tint->ket(0,0) - _1 : Tint->ket(0,0) );
276
277 {
278 OriginDerivative<1u> _d1; _d1.inc(0);
279
280 SafePtr<DGVertex> _nullptr;
281
282 // dA - _1?
283 {
284 const OriginDerivative<1u> dAm1(dA - _d1);
285 if (exists(dAm1)) { // yes
286 a.deriv() = dAm1;
287 auto AB = factory.make_child(a,b);
288 if (is_simple()) {
289 if (where == InBra) { // building on A
290 expr_ -= Scalar(dA[0]) * Scalar("rho12_over_alpha1") * AB; nflops_ += 3; }
291 if (where == InKet) { // building on B
292 expr_ += Scalar(dA[0]) * Scalar("rho12_over_alpha2") * AB; nflops_ += 3; }
293 }
294 a.deriv() = dA;
295 }
296 }
297
298 // dB - _1?
299 {
300 const OriginDerivative<1u> dBm1(dB - _d1);
301 if (exists(dBm1)) { // yes
302 b.deriv() = dBm1;
303 auto AB = factory.make_child(a,b);
304 if (is_simple()) {
305 if (where == InBra) { // building on A
306 expr_ += Scalar(dB[0]) * Scalar("rho12_over_alpha1") * AB; nflops_ += 3; }
307 if (where == InKet) { // building on B
308 expr_ -= Scalar(dB[0]) * Scalar("rho12_over_alpha2") * AB; nflops_ += 3; }
309 }
310 b.deriv() = dB;
311 }
312 }
313
314 }
315 } // end of deriv
316
317 return;
318 }
319
320
324 template <class BFSet, FunctionPosition where>
325 class VRR_1_Kinetic_1 : public GenericRecurrenceRelation< VRR_1_Kinetic_1<BFSet,where>,
326 BFSet,
327 GenIntegralSet_1_1<BFSet,KineticOper,EmptySet> >
328 {
329 public:
331 typedef BFSet BasisFunctionType;
335 static const unsigned int max_nchildren = 9;
336
338
341
342 private:
343 using ParentType::RecurrenceRelation::expr_;
344 using ParentType::RecurrenceRelation::nflops_;
345 using ParentType::target_;
347
349 VRR_1_Kinetic_1(const SafePtr<TargetType>&, unsigned int dir);
350
351 static std::string descr() { return "OSVRRKinetic"; }
352 };
353
354 template <class F, FunctionPosition where>
355 VRR_1_Kinetic_1<F,where>::VRR_1_Kinetic_1(const SafePtr< TargetType >& Tint,
356 unsigned int dir) :
357 ParentType(Tint,dir)
358 {
359 using namespace libint2::algebra;
360 using namespace libint2::prefactor;
361 using namespace libint2::braket;
362 const F& _1 = unit<F>(dir);
363
364 { // can't apply to contracted basis functions
365 F a(Tint->bra(0,0));
366 F b(Tint->ket(0,0));
367 if (a.contracted() ||
368 b.contracted())
369 return;
370 }
371
372 // if derivative integrals, there will be extra terms (Eq. (143) in Obara & Saika JCP 89)
373 const OriginDerivative<3u> dA = Tint->bra(0,0).deriv();
374 const OriginDerivative<3u> dB = Tint->ket(0,0).deriv();
375 const bool deriv = !dA.zero() ||
376 !dB.zero();
377
378 typedef TargetType Child1Type;
379 ChildFactory<ThisType,Child1Type> factory(this);
380 typedef GenIntegralSet_1_1<F,OverlapOper,EmptySet> Child2Type;
381 ChildFactory<ThisType,Child2Type> overlap_factory(this);
382
383 // Build on A or B
384 {
385 // bf quantum on the build center subtracted by 1
386 auto a = ( where == InBra ? Tint->bra(0,0) - _1 : Tint->bra(0,0) );
387 if (!exists(a)) return;
388 auto b = ( where == InKet ? Tint->ket(0,0) - _1 : Tint->ket(0,0) );
389 if (!exists(b)) return;
390
391 auto AB = factory.make_child(a,b);
392 if (is_simple()) { expr_ = Vector(where == InBra ? "PA" : "PB")[dir] * AB; nflops_+=1; }
393
394 auto am1 = a - _1;
395 if (exists(am1)) {
396 auto Am1B = factory.make_child(am1,b);
397 auto S_Am1B = (where == InBra) ? overlap_factory.make_child(am1,b) : SafePtr<DGVertex>();
398 if (is_simple()) {
399 if (where == InBra) {
400 expr_ += Scalar(a[dir]) * ( Scalar("oo2z") * Am1B -
401 Scalar("rho12_over_alpha1") * S_Am1B );
402 nflops_+=5;
403 }
404 else {
405 expr_ += Scalar(a[dir]) * Scalar("oo2z") * Am1B;
406 nflops_+=3;
407 }
408 }
409 }
410 auto bm1 = b - _1;
411 if (exists(bm1)) {
412 auto ABm1 = factory.make_child(a,bm1);
413 auto S_ABm1 = (where == InKet) ? overlap_factory.make_child(a,bm1) : SafePtr<DGVertex>();
414 if (is_simple()) {
415 if (where == InKet) {
416 expr_ += Scalar(b[dir]) * ( Scalar("oo2z") * ABm1 -
417 Scalar("rho12_over_alpha2") * S_ABm1 );
418 nflops_+=5;
419 }
420 else {
421 expr_ += Scalar(b[dir]) * Scalar("oo2z") * ABm1;
422 nflops_+=3;
423 }
424 }
425 }
426
427 {
428 auto S_AB_target = where == InBra ? overlap_factory.make_child(a + _1,b) : overlap_factory.make_child(a,b + _1);
429 if (is_simple()) {
430 expr_ += Scalar("two_rho12") * S_AB_target;
431 nflops_+=2;
432 }
433 }
434
435 }
436
437 // if got here, can decrement by at least 1 quantum
438 // add additional derivative terms
439 if (deriv) {
440 assert(false); // not yet implemented
441
442 // bf quantum on the build center subtracted by 1
443 F a( where == InBra ? Tint->bra(0,0) - _1 : Tint->bra(0,0) );
444 F b( where == InKet ? Tint->ket(0,0) - _1 : Tint->ket(0,0) );
445
446 // treatment of derivative terms differs for shell sets and integrals
447 // since in computing shell sets transfer/build will occur in all 3 directions
448 // change in up to all three derivative indices will occur
449 for(unsigned int dxyz=0; dxyz<3; ++dxyz) {
450
451 if (is_simple() && dxyz != dir) // for integrals only consider derivatives in THE build direction
452 continue;
453
454 OriginDerivative<3u> _d1; _d1.inc(dxyz);
455
456 SafePtr<DGVertex> _nullptr;
457
458 // dA - _1?
459 {
460 const OriginDerivative<3u> dAm1(dA - _d1);
461 if (exists(dAm1)) { // yes
462 a.deriv() = dAm1;
463 auto AB = factory.make_child(a,b);
464 if (is_simple()) {
465 if (where == InBra) { // building on A
466 expr_ -= Vector(dA)[dxyz] * Scalar("rho12_over_alpha1") * AB; nflops_ += 3; }
467 if (where == InKet) { // building on B
468 expr_ += Vector(dA)[dxyz] * Scalar("rho12_over_alpha2") * AB; nflops_ += 3; }
469 }
470 a.deriv() = dA;
471 }
472 }
473
474 // dB - _1?
475 {
476 const OriginDerivative<3u> dBm1(dB - _d1);
477 if (exists(dBm1)) { // yes
478 b.deriv() = dBm1;
479 auto AB = factory.make_child(a,b);
480 if (is_simple()) {
481 if (where == InBra) { // building on A
482 expr_ += Vector(dB)[dxyz] * Scalar("rho12_over_alpha1") * AB; nflops_ += 3; }
483 if (where == InKet) { // building on B
484 expr_ -= Vector(dB)[dxyz] * Scalar("rho12_over_alpha2") * AB; nflops_ += 3; }
485 }
486 b.deriv() = dB;
487 }
488 }
489
490 }
491 } // end of deriv
492
493 return;
494 }
495
499 template <class BFSet, FunctionPosition where>
500 class VRR_1_ElecPot_1 : public GenericRecurrenceRelation< VRR_1_ElecPot_1<BFSet,where>,
501 BFSet,
502 GenIntegralSet_1_1<BFSet,ElecPotOper,mType> >
503 {
504 public:
506 typedef BFSet BasisFunctionType;
510 static const unsigned int max_nchildren = 9;
511
513
516
517 private:
518 using ParentType::RecurrenceRelation::expr_;
519 using ParentType::RecurrenceRelation::nflops_;
520 using ParentType::target_;
522
524 VRR_1_ElecPot_1(const SafePtr<TargetType>&, unsigned int dir);
525
526 static std::string descr() { return "OSVRRElecPot"; }
530 std::string generate_label() const override
531 {
532 typedef typename TargetType::AuxIndexType mType;
533 static SafePtr<mType> aux0(new mType(0u));
534 std::ostringstream os;
535 os << descr() << to_string(where)
536 << genintegralset_label(target_->bra(),target_->ket(),aux0,target_->oper());
537 return os.str();
538 }
539 };
540
541 template <class F, FunctionPosition where>
542 VRR_1_ElecPot_1<F,where>::VRR_1_ElecPot_1(const SafePtr< TargetType >& Tint,
543 unsigned int dir) :
544 ParentType(Tint,dir)
545 {
546 using namespace libint2::algebra;
547 using namespace libint2::prefactor;
548 using namespace libint2::braket;
549 const unsigned int m = Tint->aux()->elem(0);
550 const F& _1 = unit<F>(dir);
551
552 { // can't apply to contracted basis functions
553 F a(Tint->bra(0,0));
554 F b(Tint->ket(0,0));
555 if (a.contracted() ||
556 b.contracted())
557 return;
558 }
559
560 // if derivative integrals, there will be extra terms (Eq. (143) in Obara & Saika JCP 89)
561 const OriginDerivative<3u> dA = Tint->bra(0,0).deriv();
562 const OriginDerivative<3u> dB = Tint->ket(0,0).deriv();
563 const bool deriv = !dA.zero() ||
564 !dB.zero();
565
566 typedef TargetType ChildType;
567 ChildFactory<ThisType,ChildType> factory(this);
568
569 // Build on A or B
570 {
571 // bf quantum on the build center subtracted by 1
572 auto a = ( where == InBra ? Tint->bra(0,0) - _1 : Tint->bra(0,0) );
573 if (!exists(a)) return;
574 auto b = ( where == InKet ? Tint->ket(0,0) - _1 : Tint->ket(0,0) );
575 if (!exists(b)) return;
576
577 auto AB_m = factory.make_child(a,b,m);
578 auto AB_mp1 = factory.make_child(a,b,m+1);
579 if (is_simple()) {
580 expr_ = Vector(where == InBra ? "PA" : "PB")[dir] * AB_m -
581 Vector("PC")[dir] * AB_mp1;
582 nflops_+=3;
583 }
584
585 auto am1 = a - _1;
586 if (exists(am1)) {
587 auto Am1B_m = factory.make_child(am1,b,m);
588 auto Am1B_mp1 = factory.make_child(am1,b,m+1);
589 if (is_simple()) { expr_ += Scalar(a[dir]) * Scalar("oo2z") * (Am1B_m - Am1B_mp1); nflops_+=4; }
590 }
591 auto bm1 = b - _1;
592 if (exists(bm1)) {
593 auto ABm1_m = factory.make_child(a,bm1,m);
594 auto ABm1_mp1 = factory.make_child(a,bm1,m+1);
595 if (is_simple()) { expr_ += Scalar(b[dir]) * Scalar("oo2z") * (ABm1_m - ABm1_mp1); nflops_+=4; }
596 }
597 }
598
599 // if got here, can decrement by at least 1 quantum
600 // add additional derivative terms
601 if (deriv) {
602 // bf quantum on the build center subtracted by 1
603 F a( where == InBra ? Tint->bra(0,0) - _1 : Tint->bra(0,0) );
604 F b( where == InKet ? Tint->ket(0,0) - _1 : Tint->ket(0,0) );
605
606 // treatment of derivative terms differs for shell sets and integrals
607 // since in computing shell sets transfer/build will occur in all 3 directions
608 // change in up to all three derivative indices will occur
609 for(unsigned int dxyz=0; dxyz<3; ++dxyz) {
610
611 if (is_simple() && dxyz != dir) // for integrals only consider derivatives in THE build direction
612 continue;
613
614 OriginDerivative<3u> _d1; _d1.inc(dxyz);
615
616 SafePtr<DGVertex> _nullptr;
617
618 // dA - _1?
619 {
620 const OriginDerivative<3u> dAm1(dA - _d1);
621 if (exists(dAm1)) { // yes
622 a.deriv() = dAm1;
623 auto AB_m = factory.make_child(a,b,m);
624 auto AB_mp1 = factory.make_child(a,b,m+1);
625 if (is_simple()) {
626 if (where == InBra) { // building on A -> derivative of (PA)_i and (PC)_i prefactors w.r.t A_i
627 expr_ -= Vector(dA)[dxyz] * (Scalar("rho12_over_alpha1") * AB_m + Scalar("rho12_over_alpha2") * AB_mp1); nflops_ += 5; }
628 if (where == InKet) { // building on B -> derivative of (PB)_i and (PC)_i prefactors w.r.t A_i
629 expr_ += Vector(dA)[dxyz] * Scalar("rho12_over_alpha2") * (AB_m - AB_mp1); nflops_ += 4; }
630 }
631 a.deriv() = dA;
632 }
633 }
634
635 // dB - _1?
636 {
637 const OriginDerivative<3u> dBm1(dB - _d1);
638 if (exists(dBm1)) { // yes
639 b.deriv() = dBm1;
640 auto AB_m = factory.make_child(a,b,m);
641 auto AB_mp1 = factory.make_child(a,b,m+1);
642 if (is_simple()) {
643 if (where == InBra) { // building on A -> derivative of (PA)_i and (PC)_i prefactors w.r.t B_i
644 expr_ += Vector(dB)[dxyz] * Scalar("rho12_over_alpha1") * (AB_m - AB_mp1); nflops_ += 4; }
645 if (where == InKet) { // building on B -> derivative of (PB)_i and (PC)_i prefactors w.r.t B_i
646 expr_ -= Vector(dB)[dxyz] * (Scalar("rho12_over_alpha2") * AB_m + Scalar("rho12_over_alpha1") * AB_mp1); nflops_ += 5; }
647 }
648 b.deriv() = dB;
649 }
650 }
651
652 }
653 } // end of deriv
654
655 return;
656 }
657
661 template <class BFSet, FunctionPosition where>
662 class VRR_1_SMultipole_1 : public GenericRecurrenceRelation< VRR_1_SMultipole_1<BFSet,where>,
663 BFSet,
664 GenIntegralSet_1_1<BFSet,SphericalMultipoleOper,EmptySet> >
665 {
666 public:
668 typedef BFSet BasisFunctionType;
673 static const unsigned int max_nchildren = 8;
674
676
679
680 private:
681 using ParentType::RecurrenceRelation::expr_;
682 using ParentType::RecurrenceRelation::nflops_;
683 using ParentType::target_;
685 using typename ParentType::RecurrenceRelation::ExprType;
686
687 static std::string descr() { return "OSVRRSMultipole"; }
688
690 VRR_1_SMultipole_1(const SafePtr<TargetType>& Tint, unsigned int dir) :
691 ParentType(Tint,dir)
692 {
693 using namespace libint2::algebra;
694 using namespace libint2::prefactor;
695 using namespace libint2::braket;
696 using Sign = SphericalMultipoleQuanta::Sign;
697 using F = BFSet;
698 const F& _1 = unit<F>(dir);
699
700 { // can't apply to contracted basis functions
701 F a(Tint->bra(0,0));
702 F b(Tint->ket(0,0));
703 if (a.contracted() ||
704 b.contracted())
705 return;
706 }
707
708 // implementation follows J.M. Pérez-Jordá and W. Yang, J Chem Phys 107, 1218 (1997).
709 // Eqs. (58-61) for gaussian quanta, and
710 // J.M. Pérez-Jordá and W. Yang, J Chem Phys 104, 8003 (1996), Eqs. (23-27) for multipole quanta
711 const OriginDerivative<3u> dA = Tint->bra(0,0).deriv();
712 const OriginDerivative<3u> dB = Tint->ket(0,0).deriv();
713 const bool deriv = !dA.zero() ||
714 !dB.zero();
715 if (deriv) // derivative relations not yet implemented
716 return;
717
718 auto O_l_m = Tint->oper()->descr();
719 const auto l = O_l_m.l();
720 const auto m = O_l_m.m();
721 const auto sign = O_l_m.sign();
722
723 typedef TargetType ChildType;
724 ChildFactory<ThisType,ChildType> factory(this);
725
726 auto make_child = [&](const F& bra, const F& ket, const OperType::Descriptor& descr) -> SafePtr<DGVertex> {
727 return factory.make_child(bra, ket, EmptySet(), descr);
728 };
729
730 // Build on A or B if either bra or ket has quanta, otherwise build multipole quanta
731 if (Tint->bra(0,0).norm() != 0 || Tint->ket(0,0).norm() != 0) {
732 // build A or B
733
734 // bf quantum on the build center subtracted by 1
735 auto a = ( where == InBra ? Tint->bra(0,0) - _1 : Tint->bra(0,0) );
736 if (!exists(a)) return;
737 auto b = ( where == InKet ? Tint->ket(0,0) - _1 : Tint->ket(0,0) );
738 if (!exists(b)) return;
739
740 //
741 // first 2 terms are common to Eqs. (58-60)
742 //
743 auto AB = make_child(a, b, O_l_m);
744 if (is_simple()) { expr_ = Vector(where == InBra ? "PA" : "PB")[dir] * AB; nflops_+=1; }
745
746 auto am1 = a - _1; auto am1_exists = exists(am1);
747 auto bm1 = b - _1; auto bm1_exists = exists(bm1);
748
749 SafePtr<ExprType> subexpr; // to be multiplied by 1/(2 zeta)
750
751 if (am1_exists) {
752 auto Am1B = make_child(am1, b, O_l_m);
753 if (is_simple()) { subexpr += Scalar(a[dir]) * Am1B; nflops_+=1; }
754 }
755 if (bm1_exists) {
756 auto ABm1 = make_child(a, bm1, O_l_m);
757 if (is_simple()) { subexpr += Scalar(b[dir]) * ABm1; nflops_+=1; }
758 }
759
760 // Eq. (58)
761 // (a|N_{l,m}|b) += 0.5 * ((a|N_{l-1,m+1}|b) - (a|N_{l-1,m-1}|b))
762 auto O_lm1_mp1 = SphericalMultipole_Descr(l-1, m+1, sign);
763 if (exists(O_lm1_mp1)) {
764 auto AB_O_lm1_mp1 = make_child(a, b, O_lm1_mp1);
765 if (is_simple() && dir == 0) {
766 subexpr += Scalar(O_lm1_mp1.phase() > 0 ? 0.5 : -0.5) * AB_O_lm1_mp1;
767 nflops_ += 1;
768 }
769 }
770
771 auto O_lm1_mm1 = SphericalMultipole_Descr(l-1, m-1, sign);
772 if (exists(O_lm1_mm1)) {
773 auto AB_O_lm1_mm1 = make_child(a, b, O_lm1_mm1);
774 if (is_simple() && dir == 0) {
775 subexpr -= Scalar(O_lm1_mm1.phase() > 0 ? 0.5 : -0.5) * AB_O_lm1_mm1;
776 nflops_ += 1;
777 }
778 }
779
780 // Eq. (59)
781 // (a|N^{+-}_{l,m}|b) {+-}= 0.5 * ((a|N^{-+}_{l-1,m+1}|b) + (a|N^{-+}_{l-1,m-1}|b))
782 const auto m_pfac = sign == Sign::plus ? 1 : -1;
783 auto Om_lm1_mp1 = SphericalMultipole_Descr(l-1, m+1, flip(sign));
784 if (exists(Om_lm1_mp1)) {
785 auto AB_Om_lm1_mp1 = make_child(a, b, Om_lm1_mp1);
786 if (is_simple() && dir == 1) {
787 subexpr += Scalar(m_pfac * (Om_lm1_mp1.phase() > 0 ? 0.5 : -0.5)) * AB_Om_lm1_mp1;
788 nflops_ += 1;
789 }
790 }
791
792 auto Om_lm1_mm1 = SphericalMultipole_Descr(l-1, m-1, flip(sign));
793 if (exists(Om_lm1_mm1)) {
794 auto AB_Om_lm1_mm1 = make_child(a, b, Om_lm1_mm1);
795 if (is_simple() && dir == 1) {
796 subexpr += Scalar(m_pfac * (Om_lm1_mm1.phase() > 0 ? 0.5 : -0.5)) * AB_Om_lm1_mm1;
797 nflops_ += 1;
798 }
799 }
800
801 // Eq. (60)
802 auto O_lm1_m = SphericalMultipole_Descr(l-1, m, sign);
803 if (exists(O_lm1_m)) {
804 auto AB_O_lm1_m = make_child(a, b, O_lm1_m);
805 if (is_simple() && dir == 2) {
806 subexpr += AB_O_lm1_m;
807 nflops_ += 1;
808 }
809 }
810
811 if (is_simple()) {
812 if(subexpr)
813 expr_ += Scalar("oo2z") * subexpr;
814 }
815 }
816 else {
817 // build multipole quanta only if dir == 0
818 if (dir != 0) return;
819 auto a = Tint->bra(0,0);
820 auto b = Tint->ket(0,0);
821
822 if (l == m) {
823 if (l == 0) { // Eq.
824 assert(sign == Sign::plus); // Eq. (24) should not be needed
825 // since N^-_{0,0} should just be
826 // omitted above
827 typedef GenIntegralSet_1_1<BFSet, CartesianMultipoleOper<3u>, EmptySet>
828 OverlapType;
829 ChildFactory<ThisType, OverlapType> overlap_factory(this);
830 auto S00 = overlap_factory.make_child(a, b);
831 if (is_simple()) {
832 expr_ = Scalar(1) * S00; // Eq. (25) and Eq. (61)
833 }
834 } else {
835 SafePtr<ExprType> subexpr; // to be multiplied by - 1/(2 m)
836
837 // Eqs. (25-26)
838 // (0|N^+_{m,m}|0) = -(1/(2m)) ( x (0|N^+_{m-1,m-1}|0) - y
839 // (0|N^-_{m-1,m-1}|0) )
840 auto Op_lm1_mm1 =
841 SphericalMultipole_Descr(l - 1, m - 1, Sign::plus);
842 auto AB_Op_lm1_mm1 = make_child(a, b, Op_lm1_mm1);
843 if (is_simple()) {
844 subexpr = Scalar(sign == Sign::plus ? "PO_x" : "PO_y") *
845 AB_Op_lm1_mm1;
846 }
847 auto Om_lm1_mm1 =
848 SphericalMultipole_Descr(l - 1, m - 1, Sign::minus);
849 if (exists(Om_lm1_mm1)) {
850 auto AB_Om_lm1_mm1 = make_child(a, b, Om_lm1_mm1);
851 if (is_simple()) {
852 if (sign == Sign::plus)
853 subexpr -= Scalar("PO_y") * AB_Om_lm1_mm1;
854 else // sign == Sign::minus
855 subexpr += Scalar("PO_x") * AB_Om_lm1_mm1;
856 }
857 }
858 if (is_simple()) {
859 assert(subexpr);
860 expr_ = Scalar(-0.5 / m) * subexpr;
861 }
862 }
863 } else { // l != m, use Eq. 27
864 SafePtr<ExprType> subexpr; // to be multiplied by 1/((l+m)(l-m))
865
866 auto O_lm1_m = SphericalMultipole_Descr(l - 1, m, sign);
867 if (exists(O_lm1_m)) {
868 auto AB_O_lm1_m = make_child(a, b, O_lm1_m);
869 if (is_simple())
870 subexpr = Scalar((2 * l - 1)) * Scalar("PO_z") * AB_O_lm1_m;
871 }
872
873 auto O_lm2_m = SphericalMultipole_Descr(l - 2, m, sign);
874 if (exists(O_lm2_m)) {
875 auto AB_O_lm2_m = make_child(a, b, O_lm2_m);
876 if (is_simple())
877 subexpr -= Scalar("PO2") * AB_O_lm2_m;
878 }
879
880 if (is_simple()) {
881 assert(subexpr);
882 expr_ = Scalar(1.0 / ((l + m) * (l - m))) * subexpr;
883 }
884 }
885 }
886
887 return;
888 }
889
890 }; // VRR_1_SMultipole_1
891
892}; // namespace libint2
893
894#endif
Set of basis functions.
Definition: bfset.h:42
Cartesian components of 3D CGF = 1D CGF.
Definition: bfset.h:440
Generic integral over a one-body operator with one bfs for each particle in bra and ket.
Definition: integral_1_1.h:33
GenOper is a single operator described by descriptor Descr.
Definition: oper.h:162
RRImpl must inherit GenericRecurrenceRelation<RRImpl>
Definition: generic_rr.h:47
const SafePtr< DGVertex > & make_child(const typename RealChildType::BasisFunctionType &A, const typename RealChildType::BasisFunctionType &B, const typename RealChildType::BasisFunctionType &C, const typename RealChildType::BasisFunctionType &D, const typename RealChildType::AuxIndexType &aux=typename RealChildType::AuxIndexType(), const typename RealChildType::OperType &oper=typename RealChildType::OperType())
make_child should really looks something like this, but gcc 4.3.0 craps out TODO test is this works
Definition: generic_rr.h:126
bool is_simple() const override
Implementation of RecurrenceRelation::is_simple()
Definition: generic_rr.h:79
const SafePtr< DGVertex > & add_child(const SafePtr< DGVertex > &child)
add child
Definition: generic_rr.h:108
static SafePtr< RRImpl > Instance(const SafePtr< TargetType > &Tint, unsigned int dir)
Return an instance if applicable, or a null pointer otherwise.
Definition: generic_rr.h:55
static bool default_directional()
is this recurrence relation parameterized by a direction (x, y, or z).
Definition: generic_rr.h:99
VRR Recurrence Relation for 1-e electrostatic potential integrals.
Definition: vrr_1_onep_1.h:503
static bool directional()
Default directionality.
Definition: vrr_1_onep_1.h:515
VRR Recurrence Relation for 1-e kinetic energy integrals.
Definition: vrr_1_onep_1.h:328
static bool directional()
Default directionality.
Definition: vrr_1_onep_1.h:340
VRR Recurrence Relation for 1-d overlap integrals.
Definition: vrr_1_onep_1.h:178
static bool directional()
Default directionality.
Definition: vrr_1_onep_1.h:191
VRR Recurrence Relation for 1-e overlap integrals.
Definition: vrr_1_onep_1.h:37
static bool directional()
Default directionality.
Definition: vrr_1_onep_1.h:49
VRR Recurrence Relation for 1-e spherical multipole moment aka regular solid harmonics integrals.
Definition: vrr_1_onep_1.h:665
static bool directional()
Default directionality.
Definition: vrr_1_onep_1.h:678
these objects help to construct BraketPairs
Definition: src/bin/libint/braket.h:270
Defaults definitions for various parameters assumed by Libint.
Definition: algebra.cc:24
bool exists(const IncableBFSet &A)
Return true if A is valid.
Definition: bfset.h:92
DefaultQuantumNumbers< unsignedint, 1 >::Result mType
mType is the type that describes the auxiliary index of standard 2-body repulsion integrals
Definition: quanta.h:408
std::string to_string(const T &x)
Converts x to its string representation.
Definition: entity.h:74
DefaultQuantumNumbers< int, 0 >::Result EmptySet
EmptySet is the type that describes null set of auxiliary indices.
Definition: quanta.h:404
SphericalMultipoleQuanta::Sign flip(const SphericalMultipoleQuanta::Sign &s)
plus <-> minus
Definition: multipole.h:240