LIBINT 2.7.2
vrr_11_twoprep_11.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_vrr11twoprep11_h_
22#define _libint2_src_bin_libint_vrr11twoprep11_h_
23
24#include <generic_rr.h>
25#include <twoprep_11_11.h>
26
27namespace libint2 {
28
32 template <class BFSet, int part, FunctionPosition where>
33 class VRR_11_TwoPRep_11 : public GenericRecurrenceRelation< VRR_11_TwoPRep_11<BFSet,part,where>,
34 BFSet,
35 GenIntegralSet_11_11<BFSet,TwoPRep,mType> >
36 {
37 public:
43 static const unsigned int max_nchildren = 26;
44
46
48 static bool directional() { return ParentType::default_directional(); }
49
50 private:
51 using ParentType::RecurrenceRelation::expr_;
52 using ParentType::RecurrenceRelation::nflops_;
53 using ParentType::target_;
55
57 VRR_11_TwoPRep_11(const SafePtr<TargetType>&, unsigned int dir);
58
59 static std::string descr() { return "OSVRR"; }
63 std::string generate_label() const override
64 {
65 typedef typename TargetType::AuxIndexType mType;
66 static SafePtr<mType> aux0(new mType(0u));
67 std::ostringstream os;
68 os << descr() << "P" << part << to_string(where)
69 << genintegralset_label(target_->bra(),target_->ket(),aux0,target_->oper());
70 return os.str();
71 }
72
73 #if LIBINT_ENABLE_GENERIC_CODE
75 bool has_generic(const SafePtr<CompilationParameters>& cparams) const override;
77 std::string generic_header() const override;
79 std::string generic_instance(const SafePtr<CodeContext>& context, const SafePtr<CodeSymbols>& args) const override;
80 #endif
81 };
82
83 template <class F, int part, FunctionPosition where>
84 VRR_11_TwoPRep_11<F,part,where>::VRR_11_TwoPRep_11(const SafePtr< TargetType >& Tint,
85 unsigned int dir) :
86 ParentType(Tint,dir)
87 {
88 using namespace libint2::algebra;
89 using namespace libint2::prefactor;
90 using namespace libint2::braket;
91 const unsigned int m = Tint->aux()->elem(0);
92 const F& _1 = unit<F>(dir);
93
94 { // can't apply to contracted basis functions
95 F a(Tint->bra(0,0));
96 F b(Tint->ket(0,0));
97 F c(Tint->bra(1,0));
98 F d(Tint->ket(1,0));
99 if (a.contracted() ||
100 b.contracted() ||
101 c.contracted() ||
102 d.contracted())
103 return;
104 }
105
106 // if derivative integrals, there will be extra terms (Eq. (143) in Obara & Saika JCP 89)
107 const OriginDerivative<3u> dA = Tint->bra(0,0).deriv();
108 const OriginDerivative<3u> dB = Tint->ket(0,0).deriv();
109 const OriginDerivative<3u> dC = Tint->bra(1,0).deriv();
110 const OriginDerivative<3u> dD = Tint->ket(1,0).deriv();
111 const bool deriv = !dA.zero() ||
112 !dB.zero() ||
113 !dC.zero() ||
114 !dD.zero();
115
116 // This is a hack to avoid creating recurrence relations for which generic code has not been yet implemented
117#if LIBINT_ENABLE_GENERIC_CODE
118 {
119 F sh_a(target_->bra(0,0));
120 F sh_b(target_->ket(0,0));
121 F sh_c(target_->bra(1,0));
122 F sh_d(target_->ket(1,0));
123 // generic code works for a0c0 of 0a0c classes where am(a) > 1 and am(c) > 1
124 // to generate optimized code for xxxx integral need to generate specialized code for up to (x+x)0(x+x)0 integrals
125 if (sh_b.zero() && sh_d.zero() &&
126 (sh_a.norm() > 1u && sh_c.norm() > 1u)
127 ) { // have a generic implemented ...
128 if (part != 0) // ... but only implemented build on A in this case
129 return;
130 }
131 if (sh_a.zero() && sh_c.zero() &&
132 (sh_b.norm() > 1u && sh_d.norm() > 1u)
133 ) {
134 if (part != 0) // but only implemented build on B in this case
135 return;
136 }
137 }
138#endif
139
140 typedef TargetType ChildType;
141 ChildFactory<ThisType,ChildType> factory(this);
142
143 bool part0_has_unit=false, part1_has_unit=false;
144
145 // Build on A
146 if (part == 0 && where == InBra) {
147 F a(Tint->bra(0,0) - _1);
148 if (!exists(a)) return;
149 F b(Tint->ket(0,0)); const bool unit_b = (b == F::unit()); part0_has_unit |= unit_b;
150 F c(Tint->bra(1,0));
151 F d(Tint->ket(1,0));
152
153 SafePtr<DGVertex> ABCD_m; if (not unit_b) ABCD_m = factory.make_child(a,b,c,d,m);
154 auto ABCD_mp1 = factory.make_child(a,b,c,d,m+1);
155 if (is_simple()) {
156 if (not unit_b) {
157 expr_ = Vector("PA")[dir] * ABCD_m + Vector("WP")[dir] * ABCD_mp1; nflops_+=3;
158 }
159 else {
160 expr_ = Vector("WP")[dir] * ABCD_mp1; nflops_+=1;
161 }
162 }
163
164 // simplified 3-center VRR due to Ahlrichs (PCCP 6, 5119 (2004))
165 const bool ahlrichs_simplification = a.pure_sh() && unit_b;
166 auto am1 = a - _1;
167 if (exists(am1) && not ahlrichs_simplification) {
168 auto Am1BCD_m = factory.make_child(am1,b,c,d,m);
169 auto Am1BCD_mp1 = factory.make_child(am1,b,c,d,m+1);
170#if LIBINT_GENERATE_FMA
171 // this form is amenable to generation of fmsub
172 if (is_simple()) { expr_ -= Scalar(a[dir]) * Scalar("oo2z") * (Scalar("roz") * Am1BCD_mp1 - Am1BCD_m); nflops_+=5; }
173#else
174 if (is_simple()) { expr_ += Scalar(a[dir]) * Scalar("oo2z") * (Am1BCD_m - Scalar("roz") * Am1BCD_mp1); nflops_+=5; }
175#endif
176 }
177 const F& bm1 = b - _1;
178 if (exists(bm1)) {
179 auto ABm1CD_m = factory.make_child(a,bm1,c,d,m);
180 auto ABm1CD_mp1 = factory.make_child(a,bm1,c,d,m+1);
181#if LIBINT_GENERATE_FMA
182 // this form is amenable to generation of fmsub
183 if (is_simple()) { expr_ -= Scalar(b[dir]) * Scalar("oo2z") * (Scalar("roz") * ABm1CD_mp1 - ABm1CD_m); nflops_+=5; }
184#else
185 if (is_simple()) { expr_ += Scalar(b[dir]) * Scalar("oo2z") * (ABm1CD_m - Scalar("roz") * ABm1CD_mp1); nflops_+=5; }
186#endif
187 }
188 const F& cm1 = c - _1;
189 if (exists(cm1)) {
190 auto ABCm1D_mp1 = factory.make_child(a,b,cm1,d,m+1);
191 if (is_simple()) { expr_ += Scalar(c[dir]) * Scalar("oo2ze") * ABCm1D_mp1; nflops_+=3; }
192 }
193 const F& dm1 = d - _1;
194 if (exists(dm1)) {
195 auto ABCDm1_mp1 = factory.make_child(a,b,c,dm1,m+1);
196 if (is_simple()) { expr_ += Scalar(d[dir]) * Scalar("oo2ze") * ABCDm1_mp1; nflops_+=3; }
197 }
198 }
199 // Build on B
200 if (part == 0 && where == InKet) {
201 F a(Tint->bra(0,0)); const bool unit_a = (a == F::unit()); part0_has_unit |= unit_a;
202 F b(Tint->ket(0,0) - _1);
203 if (!exists(b)) return;
204 F c(Tint->bra(1,0));
205 F d(Tint->ket(1,0));
206
207 SafePtr<DGVertex> ABCD_m; if (not unit_a) ABCD_m = factory.make_child(a,b,c,d,m);
208 auto ABCD_mp1 = factory.make_child(a,b,c,d,m+1);
209 if (is_simple()) {
210 if (not unit_a) {
211 expr_ = Vector("PB")[dir] * ABCD_m + Vector("WP")[dir] * ABCD_mp1; nflops_+=3;
212 }
213 else {
214 expr_ = Vector("WP")[dir] * ABCD_mp1; nflops_+=1;
215 }
216 }
217
218 const F& am1 = a - _1;
219 if (exists(am1)) {
220 auto Am1BCD_m = factory.make_child(am1,b,c,d,m);
221 auto Am1BCD_mp1 = factory.make_child(am1,b,c,d,m+1);
222#if LIBINT_GENERATE_FMA
223 // this form is amenable to generation of fmsub
224 if (is_simple()) { expr_ -= Scalar(a[dir]) * Scalar("oo2z") * (Scalar("roz") * Am1BCD_mp1 - Am1BCD_m); nflops_+=5; }
225#else
226 if (is_simple()) { expr_ += Scalar(a[dir]) * Scalar("oo2z") * (Am1BCD_m - Scalar("roz") * Am1BCD_mp1); nflops_+=5; }
227#endif
228 }
229 // simplified 3-center VRR due to Ahlrichs (PCCP 6, 5119 (2004))
230 const bool ahlrichs_simplification = b.pure_sh() && unit_a;
231 const F& bm1 = b - _1;
232 if (exists(bm1) && not ahlrichs_simplification) {
233 auto ABm1CD_m = factory.make_child(a,bm1,c,d,m);
234 auto ABm1CD_mp1 = factory.make_child(a,bm1,c,d,m+1);
235#if LIBINT_GENERATE_FMA
236 // this form is amenable to generation of fmsub
237 if (is_simple()) { expr_ -= Scalar(b[dir]) * Scalar("oo2z") * (Scalar("roz") * ABm1CD_mp1 - ABm1CD_m); nflops_+=5; }
238#else
239 if (is_simple()) { expr_ += Scalar(b[dir]) * Scalar("oo2z") * (ABm1CD_m - Scalar("roz") * ABm1CD_mp1); nflops_+=5; }
240#endif
241 }
242 const F& cm1 = c - _1;
243 if (exists(cm1)) {
244 auto ABCm1D_mp1 = factory.make_child(a,b,cm1,d,m+1);
245 if (is_simple()) { expr_ += Scalar(c[dir]) * Scalar("oo2ze") * ABCm1D_mp1; nflops_+=3; }
246 }
247 const F& dm1 = d - _1;
248 if (exists(dm1)) {
249 auto ABCDm1_mp1 = factory.make_child(a,b,c,dm1,m+1);
250 if (is_simple()) { expr_ += Scalar(d[dir]) * Scalar("oo2ze") * ABCDm1_mp1; nflops_+=3; }
251 }
252 }
253 // Build on C
254 if (part == 1 && where == InBra) {
255 F a(Tint->bra(0,0));
256 F b(Tint->ket(0,0));
257 F c(Tint->bra(1,0) - _1);
258 if (!exists(c)) return;
259 F d(Tint->ket(1,0)); const bool unit_d = (d == F::unit()); part1_has_unit |= unit_d;
260
261 SafePtr<DGVertex> ABCD_m; if (not unit_d) ABCD_m = factory.make_child(a,b,c,d,m);
262 auto ABCD_mp1 = factory.make_child(a,b,c,d,m+1);
263 if (is_simple()) {
264 if (not unit_d) {
265 expr_ = Vector("QC")[dir] * ABCD_m + Vector("WQ")[dir] * ABCD_mp1; nflops_+=3;
266 }
267 else {
268 expr_ = Vector("WQ")[dir] * ABCD_mp1; nflops_+=1;
269 }
270 }
271
272 // simplified 3-center VRR due to Ahlrichs (PCCP 6, 5119 (2004))
273 const bool ahlrichs_simplification = c.pure_sh() && unit_d;
274 const F& cm1 = c - _1;
275 if (exists(cm1) && not ahlrichs_simplification) {
276 auto ABCm1D_m = factory.make_child(a,b,cm1,d,m);
277 auto ABCm1D_mp1 = factory.make_child(a,b,cm1,d,m+1);
278#if LIBINT_GENERATE_FMA
279 // this form is amenable to generation of fmsub
280 if (is_simple()) { expr_ -= Scalar(c[dir]) * Scalar("oo2e") * (Scalar("roe") * ABCm1D_mp1 - ABCm1D_m); nflops_+=5; }
281#else
282 if (is_simple()) { expr_ += Scalar(c[dir]) * Scalar("oo2e") * (ABCm1D_m - Scalar("roe") * ABCm1D_mp1); nflops_+=5; }
283#endif
284 }
285 const F& dm1 = d - _1;
286 if (exists(dm1)) {
287 auto ABCDm1_m = factory.make_child(a,b,c,dm1,m);
288 auto ABCDm1_mp1 = factory.make_child(a,b,c,dm1,m+1);
289#if LIBINT_GENERATE_FMA
290 // this form is amenable to generation of fmsub
291 if (is_simple()) { expr_ -= Scalar(d[dir]) * Scalar("oo2e") * (Scalar("roe") * ABCDm1_mp1 - ABCDm1_m); nflops_+=5; }
292#else
293 if (is_simple()) { expr_ += Scalar(d[dir]) * Scalar("oo2e") * (ABCDm1_m - Scalar("roe") * ABCDm1_mp1); nflops_+=5; }
294#endif
295 }
296 const F& am1 = a - _1;
297 if (exists(am1)) {
298 auto Am1BCD_mp1 = factory.make_child(am1,b,c,d,m+1);
299 if (is_simple()) { expr_ += Scalar(a[dir]) * Scalar("oo2ze") * Am1BCD_mp1; nflops_+=3; }
300 }
301 const F& bm1 = b - _1;
302 if (exists(bm1)) {
303 auto ABm1CD_mp1 = factory.make_child(a,bm1,c,d,m+1);
304 if (is_simple()) { expr_ += Scalar(b[dir]) * Scalar("oo2ze") * ABm1CD_mp1; nflops_+=3; }
305 }
306 }
307 // Build on D
308 if (part == 1 && where == InKet) {
309 F a(Tint->bra(0,0));
310 F b(Tint->ket(0,0));
311 F c(Tint->bra(1,0)); const bool unit_c = (c == F::unit()); part1_has_unit |= unit_c;
312 F d(Tint->ket(1,0) - _1);
313 if (!exists(d)) return;
314
315 SafePtr<DGVertex> ABCD_m; if (not unit_c) ABCD_m = factory.make_child(a,b,c,d,m);
316 auto ABCD_mp1 = factory.make_child(a,b,c,d,m+1);
317 if (is_simple()) {
318 if (not unit_c) {
319 expr_ = Vector("QD")[dir] * ABCD_m + Vector("WQ")[dir] * ABCD_mp1; nflops_+=3;
320 }
321 else {
322 expr_ = Vector("WQ")[dir] * ABCD_mp1; nflops_+=1;
323 }
324 }
325
326 const F& cm1 = c - _1;
327 if (exists(cm1)) {
328 auto ABCm1D_m = factory.make_child(a,b,cm1,d,m);
329 auto ABCm1D_mp1 = factory.make_child(a,b,cm1,d,m+1);
330#if LIBINT_GENERATE_FMA
331 // this form is amenable to generation of fmsub
332 if (is_simple()) { expr_ -= Scalar(c[dir]) * Scalar("oo2e") * (Scalar("roe") * ABCm1D_mp1 - ABCm1D_m); nflops_+=5; }
333#else
334 if (is_simple()) { expr_ += Scalar(c[dir]) * Scalar("oo2e") * (ABCm1D_m - Scalar("roe") * ABCm1D_mp1); nflops_+=5; }
335#endif
336 }
337 // simplified 3-center VRR due to Ahlrichs (PCCP 6, 5119 (2004))
338 const bool ahlrichs_simplification = d.pure_sh() && unit_c;
339 const F& dm1 = d - _1;
340 if (exists(dm1) && not ahlrichs_simplification) {
341 auto ABCDm1_m = factory.make_child(a,b,c,dm1,m);
342 auto ABCDm1_mp1 = factory.make_child(a,b,c,dm1,m+1);
343#if LIBINT_GENERATE_FMA
344 // this form is amenable to generation of fmsub
345 if (is_simple()) { expr_ -= Scalar(d[dir]) * Scalar("oo2e") * (Scalar("roe") * ABCDm1_mp1 - ABCDm1_m); nflops_+=5; }
346#else
347 if (is_simple()) { expr_ += Scalar(d[dir]) * Scalar("oo2e") * (ABCDm1_m - Scalar("roe") * ABCDm1_mp1); nflops_+=5; }
348#endif
349 }
350 const F& am1 = a - _1;
351 if (exists(am1)) {
352 auto Am1BCD_mp1 = factory.make_child(am1,b,c,d,m+1);
353 if (is_simple()) { expr_ += Scalar(a[dir]) * Scalar("oo2ze") * Am1BCD_mp1; nflops_+=3; }
354 }
355 const F& bm1 = b - _1;
356 if (exists(bm1)) {
357 auto ABm1CD_mp1 = factory.make_child(a,bm1,c,d,m+1);
358 if (is_simple()) { expr_ += Scalar(b[dir]) * Scalar("oo2ze") * ABm1CD_mp1; nflops_+=3; }
359 }
360 }
361
362 // if got here, can decrement by at least 1 quantum
363 // add additional derivative terms
364 if (deriv) {
365 // bf quantum on the build center subtracted by 1
366 F a( part == 0 && where == InBra ? Tint->bra(0,0) - _1 : Tint->bra(0,0) );
367 F b( part == 0 && where == InKet ? Tint->ket(0,0) - _1 : Tint->ket(0,0) );
368 F c( part == 1 && where == InBra ? Tint->bra(1,0) - _1 : Tint->bra(1,0) );
369 F d( part == 1 && where == InKet ? Tint->ket(1,0) - _1 : Tint->ket(1,0) );
370
371 // treatment of derivative terms differs for shell sets and integrals
372 // since in computing shell sets transfer/build will occur in all 3 directions
373 // change in up to all three derivative indices will occur
374 for(unsigned int dxyz=0; dxyz<3; ++dxyz) {
375
376 if (is_simple() && dxyz != dir) // for integrals only consider derivatives in THE build direction
377 continue;
378
379 OriginDerivative<3u> _d1; _d1.inc(dxyz);
380
381 SafePtr<DGVertex> _nullptr;
382
383 // dA - _1?
384 {
385 const OriginDerivative<3u> dAm1(dA - _d1);
386 if (exists(dAm1)) { // yes
387 a.deriv() = dAm1;
388 auto ABCD_m = (part == 0 && not part0_has_unit) ? factory.make_child(a,b,c,d,m) : _nullptr;
389 auto ABCD_mp1 = factory.make_child(a,b,c,d,m+1);
390 if (is_simple()) {
391 if (part == 0 && where == InBra) { // building on A
392 if (not part0_has_unit) {
393 expr_ -= Vector(dA)[dxyz] * (Scalar("rho12_over_alpha1") * ABCD_m + Scalar("alpha1_rho_over_zeta2") * ABCD_mp1); nflops_ += 5;
394 }
395 else {
396 expr_ -= Vector(dA)[dxyz] * (Scalar("alpha1_rho_over_zeta2") * ABCD_mp1); nflops_ += 3;
397 }
398 }
399 if (part == 0 && where == InKet) { // building on B
400 if (not part0_has_unit) {
401 expr_ += Vector(dA)[dxyz] * (Scalar("rho12_over_alpha2") * ABCD_m - Scalar("alpha1_rho_over_zeta2") * ABCD_mp1); nflops_ += 5;
402 }
403 else {
404 expr_ -= Vector(dA)[dxyz] * (Scalar("alpha1_rho_over_zeta2") * ABCD_mp1); nflops_ += 3;
405 }
406 }
407 if (part == 1) { // building on C or D
408 expr_ += Vector(dA)[dxyz] * Scalar("alpha1_over_zetapluseta") * ABCD_mp1; nflops_ += 3; }
409 }
410 a.deriv() = dA;
411 }
412 }
413
414 // dB - _1?
415 {
416 const OriginDerivative<3u> dBm1(dB - _d1);
417 if (exists(dBm1)) { // yes
418 b.deriv() = dBm1;
419 auto ABCD_m = (part == 0 && not part0_has_unit) ? factory.make_child(a,b,c,d,m) : _nullptr;
420 auto ABCD_mp1 = factory.make_child(a,b,c,d,m+1);
421 if (is_simple()) {
422 if (part == 0 && where == InBra) { // building on A
423 if (not part0_has_unit) {
424 expr_ += Vector(dB)[dxyz] * (Scalar("rho12_over_alpha1") * ABCD_m - Scalar("alpha2_rho_over_zeta2") * ABCD_mp1); nflops_ += 5;
425 }
426 else {
427 expr_ -= Vector(dB)[dxyz] * (Scalar("alpha2_rho_over_zeta2") * ABCD_mp1); nflops_ += 3;
428 }
429 }
430 if (part == 0 && where == InKet) { // building on B
431 if (not part0_has_unit) {
432 expr_ -= Vector(dB)[dxyz] * (Scalar("rho12_over_alpha2") * ABCD_m + Scalar("alpha2_rho_over_zeta2") * ABCD_mp1); nflops_ += 5;
433 }
434 else {
435 expr_ -= Vector(dB)[dxyz] * (Scalar("alpha2_rho_over_zeta2") * ABCD_mp1); nflops_ += 3;
436 }
437 }
438 if (part == 1) { // building on C or D
439 expr_ += Vector(dB)[dxyz] * Scalar("alpha2_over_zetapluseta") * ABCD_mp1; nflops_ += 3; }
440 }
441 b.deriv() = dB;
442 }
443 }
444
445 // dC - _1?
446 {
447 const OriginDerivative<3u> dCm1(dC - _d1);
448 if (exists(dCm1)) { // yes
449 c.deriv() = dCm1;
450 auto ABCD_m = (part == 1 && not part1_has_unit) ? factory.make_child(a,b,c,d,m) : _nullptr;
451 auto ABCD_mp1 = factory.make_child(a,b,c,d,m+1);
452 if (is_simple()) {
453 if (part == 0) { // building on A or B
454 expr_ += Vector(dC)[dxyz] * Scalar("alpha3_over_zetapluseta") * ABCD_mp1; nflops_ += 3; }
455 if (part == 1 && where == InBra) { // building on C
456 if (not part1_has_unit) {
457 expr_ -= Vector(dC)[dxyz] * (Scalar("rho34_over_alpha3") * ABCD_m + Scalar("alpha3_rho_over_eta2") * ABCD_mp1); nflops_ += 5;
458 }
459 else {
460 expr_ -= Vector(dC)[dxyz] * (Scalar("alpha3_rho_over_eta2") * ABCD_mp1); nflops_ += 3;
461 }
462 }
463 if (part == 1 && where == InKet) { // building on D
464 if (not part1_has_unit) {
465 expr_ += Vector(dC)[dxyz] * (Scalar("rho34_over_alpha4") * ABCD_m - Scalar("alpha3_rho_over_eta2") * ABCD_mp1); nflops_ += 5;
466 }
467 else {
468 expr_ -= Vector(dC)[dxyz] * (Scalar("alpha3_rho_over_eta2") * ABCD_mp1); nflops_ += 3;
469 }
470 }
471 }
472 c.deriv() = dC;
473 }
474 }
475
476 // dD - _1?
477 {
478 const OriginDerivative<3u> dDm1(dD - _d1);
479 if (exists(dDm1)) { // yes
480 d.deriv() = dDm1;
481 auto ABCD_m = (part == 1 && not part1_has_unit) ? factory.make_child(a,b,c,d,m) : _nullptr;
482 auto ABCD_mp1 = factory.make_child(a,b,c,d,m+1);
483 if (is_simple()) {
484 if (part == 0) { // building on A or B
485 expr_ += Vector(dD)[dxyz] * Scalar("alpha4_over_zetapluseta") * ABCD_mp1; nflops_ += 3; }
486 if (part == 1 && where == InBra) { // building on C
487 if (not part1_has_unit) {
488 expr_ += Vector(dD)[dxyz] * (Scalar("rho34_over_alpha3") * ABCD_m - Scalar("alpha4_rho_over_eta2") * ABCD_mp1); nflops_ += 5;
489 }
490 else {
491 expr_ -= Vector(dD)[dxyz] * (Scalar("alpha4_rho_over_eta2") * ABCD_mp1); nflops_ += 3;
492 }
493 }
494 if (part == 1 && where == InKet) { // building on D
495 if (not part1_has_unit) {
496 expr_ -= Vector(dD)[dxyz] * (Scalar("rho34_over_alpha4") * ABCD_m + Scalar("alpha4_rho_over_eta2") * ABCD_mp1); nflops_ += 5;
497 }
498 else {
499 expr_ -= Vector(dD)[dxyz] * (Scalar("alpha4_rho_over_eta2") * ABCD_mp1); nflops_ += 3;
500 }
501 }
502 }
503 d.deriv() = dD;
504 }
505 }
506 }
507 } // end of deriv
508
509 return;
510 }
511
512#if LIBINT_ENABLE_GENERIC_CODE
513 template <class F, int part, FunctionPosition where>
514 bool
515 VRR_11_TwoPRep_11<F,part,where>::has_generic(const SafePtr<CompilationParameters>& cparams) const
516 {
517 if (TrivialBFSet<F>::result)
518 return false;
519
520 F sh_a(target_->bra(0,0));
521 F sh_b(target_->ket(0,0));
522 F sh_c(target_->bra(1,0));
523 F sh_d(target_->ket(1,0));
524 const unsigned int max_opt_am = cparams->max_am_opt();
525 // generic code works for a0c0 of 0a0c classes where am(a) > 1 and am(c) > 1
526 // to generate optimized code for xxxx integral need to generate specialized code for up to (x+x)0(x+x)0 integrals
527 if (sh_b.zero() && sh_d.zero() &&
528 (sh_a.norm() > std::max(2*max_opt_am,1u) ||
529 sh_c.norm() > std::max(2*max_opt_am,1u)
530 ) &&
531 (sh_a.norm() > 1u && sh_c.norm() > 1u)
532 ) {
533 assert(part == 0); // has only implemented build on A in this case
534 return true;
535 }
536 if (sh_a.zero() && sh_c.zero() &&
537 (sh_b.norm() > std::max(2*max_opt_am,1u) ||
538 sh_d.norm() > std::max(2*max_opt_am,1u)
539 ) &&
540 (sh_b.norm() > 1u && sh_d.norm() > 1u)
541 ) {
542 assert(part == 0); // has only implemented build on B in this case
543 return true;
544 }
545 return false;
546 }
547
548 template <class F, int part, FunctionPosition where>
549 std::string
550 VRR_11_TwoPRep_11<F,part,where>::generic_header() const
551 {
552 F sh_a(target_->bra(0,0));
553 F sh_b(target_->ket(0,0));
554 F sh_c(target_->bra(1,0));
555 F sh_d(target_->ket(1,0));
556 const bool xsxs = sh_b.zero() && sh_d.zero();
557 const bool sxsx = sh_a.zero() && sh_c.zero();
558
559 const OriginDerivative<3u> dA = target_->bra(0,0).deriv();
560 const OriginDerivative<3u> dB = target_->ket(0,0).deriv();
561 const OriginDerivative<3u> dC = target_->bra(1,0).deriv();
562 const OriginDerivative<3u> dD = target_->ket(1,0).deriv();
563 const bool deriv = !dA.zero() ||
564 !dB.zero() ||
565 !dC.zero() ||
566 !dD.zero();
567
568 if (!deriv) {
569 if (xsxs) return std::string("OSVRR_xs_xs.h");
570 if (sxsx) return std::string("OSVRR_sx_sx.h");
571 }
572 else {
573 if (xsxs) return std::string("OSVRR_xs_xs_deriv.h");
574 if (sxsx) return std::string("OSVRR_sx_sx_deriv.h");
575 }
576 abort(); // unreachable
577 }
578
579 template <class F, int part, FunctionPosition where>
580 std::string
581 VRR_11_TwoPRep_11<F,part,where>::generic_instance(const SafePtr<CodeContext>& context, const SafePtr<CodeSymbols>& args) const
582 {
583 std::ostringstream oss;
584 F sh_a(target_->bra(0,0));
585 F sh_b(target_->ket(0,0));
586 F sh_c(target_->bra(1,0));
587 F sh_d(target_->ket(1,0));
588 const bool xsxs = sh_b.zero() && sh_d.zero();
589 const bool sxsx = sh_a.zero() && sh_c.zero();
590 bool ahlrichs_simplification = false;
591 bool unit_s = false;
592 bool part0_has_unit = false;
593 bool part1_has_unit = false;
594 if (xsxs) {
595 ahlrichs_simplification = (sh_a.pure_sh() && sh_b.is_unit()) ||
596 (sh_c.pure_sh() && sh_d.is_unit());
597 unit_s = sh_b.is_unit();
598 part0_has_unit = sh_b.is_unit();
599 part1_has_unit = sh_d.is_unit();
600 }
601 if (sxsx) {
602 ahlrichs_simplification = (sh_b.pure_sh() && sh_a.is_unit()) ||
603 (sh_d.pure_sh() && sh_c.is_unit());
604 unit_s = sh_a.is_unit();
605 part0_has_unit = sh_a.is_unit();
606 part1_has_unit = sh_c.is_unit();
607 }
608
609 const OriginDerivative<3u> dA = target_->bra(0,0).deriv();
610 const OriginDerivative<3u> dB = target_->ket(0,0).deriv();
611 const OriginDerivative<3u> dC = target_->bra(1,0).deriv();
612 const OriginDerivative<3u> dD = target_->ket(1,0).deriv();
613 const bool deriv = !dA.zero() ||
614 !dB.zero() ||
615 !dC.zero() ||
616 !dD.zero();
617
618 oss << "using namespace libint2;" << std::endl;
619
620 if (!deriv) { // for regular integrals I know exactly how many prerequisites I need
621 if(xsxs) {
622 oss << "libint2::OS" << (ahlrichs_simplification ? "A" : "")
623 << "VRR_xs_xs<" << part << "," << sh_a.norm() << "," << sh_c.norm() << ",";
624 }
625 if (sxsx) {
626 oss << "libint2::OS" << (ahlrichs_simplification ? "A" : "")
627 << "VRR_sx_sx<" << part << "," << sh_b.norm() << "," << sh_d.norm() << ",";
628 }
629 if (not ahlrichs_simplification) oss << (unit_s ? "true," : "false,");
630 oss << ((context->cparams()->max_vector_length() == 1) ? "false" : "true");
631 oss << ">::compute(inteval";
632
633 oss << "," << args->symbol(0); // target
634 if (not ahlrichs_simplification && unit_s) // purely to avoid having a 4-term generic RR, reuse 5-term with dummy argument
635 oss << ",0"; // src0-> 0x0
636 const unsigned int nargs = args->n();
637 for(unsigned int a=1; a<nargs; a++) {
638 oss << "," << args->symbol(a);
639 }
640 oss << ");";
641 }
642 else { // deriv == true -> only some arguments are needed
643 if(xsxs) {
644 oss << "libint2::OS" << (ahlrichs_simplification ? "A" : "")
645 << "VRR_xs_xs_deriv<" << part << "," << sh_a.norm() << "," << sh_c.norm() << ",";
646 }
647 if(sxsx) {
648 oss << "libint2::OS" << (ahlrichs_simplification ? "A" : "")
649 << "VRR_sx_sx_deriv<" << part << "," << sh_b.norm() << "," << sh_d.norm() << ",";
650 }
651
652 for(unsigned int xyz=0; xyz<3; ++xyz) oss << sh_a.deriv().d(xyz) << ",";
653 for(unsigned int xyz=0; xyz<3; ++xyz) oss << sh_b.deriv().d(xyz) << ",";
654 for(unsigned int xyz=0; xyz<3; ++xyz) oss << sh_c.deriv().d(xyz) << ",";
655 for(unsigned int xyz=0; xyz<3; ++xyz) oss << sh_d.deriv().d(xyz) << ",";
656 if (not ahlrichs_simplification) oss << (unit_s ? "true," : "false,");
657 oss << ((context->cparams()->max_vector_length() == 1) ? "false" : "true");
658 oss << ">::compute(inteval";
659 // out of all 22 possible prerequisites first few have same derivative degree as the target
660 // 5 if standard 4-center integral
661 // 1+4 if the center opposite the build center carries a unit function
662 // will pass 0 instead of src0
663 // 2 if Ahlrichs
664 oss << "," << args->symbol(0); // target
665 if (not ahlrichs_simplification && unit_s) // purely to avoid having a 4-term generic RR, reuse 5-term with dummy argument
666 oss << ",0"; // src0-> 0x0
667 //const unsigned int nargs = args->n();
668 unsigned int arg = 1;
669 for(;
670 arg<(ahlrichs_simplification? 3 : (unit_s ? 5 : 6)); // nargs + 1 target
671 arg++) {
672 oss << "," << args->symbol(arg);
673 }
674 for(unsigned int xyz=0; xyz<3; ++xyz) {
675 if (sh_a.deriv().d(xyz) > 0) {
676 // see the dA-1 clause: (ab|cd)^m is skipped
677 oss << "," << (part0_has_unit ? std::to_string(0) : args->symbol(arg++));
678 oss << "," << args->symbol(arg++);
679 }
680 else
681 oss << ",0,0";
682 if (sh_b.deriv().d(xyz) > 0) {
683 // see the dB-1 clause: (ab|cd)^m is skipped
684 oss << "," << (part0_has_unit ? std::to_string(0) : args->symbol(arg++));
685 oss << "," << args->symbol(arg++);
686 }
687 else
688 oss << ",0,0";
689 if (sh_c.deriv().d(xyz) > 0) {
690 oss << "," << args->symbol(arg++);
691 }
692 else
693 oss << ",0";
694 if (sh_d.deriv().d(xyz) > 0) {
695 oss << "," << args->symbol(arg++);
696 }
697 else
698 oss << ",0";
699 }
700 oss << ");";
701 }
702
703 return oss.str();
704 }
705#endif // #if !LIBINT_ENABLE_GENERIC_CODE
706
707};
708
709#endif
Set of basis functions.
Definition: bfset.h:42
Generic integral over a two-body operator with one bfs for each particle in bra and ket.
Definition: integral_11_11.h:33
RRImpl must inherit GenericRecurrenceRelation<RRImpl>
Definition: generic_rr.h:47
bool is_simple() const override
Implementation of RecurrenceRelation::is_simple()
Definition: generic_rr.h:79
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 2-e ERI.
Definition: vrr_11_twoprep_11.h:36
static bool directional()
Default directionality.
Definition: vrr_11_twoprep_11.h:48
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