LIBINT 2.7.2
comp_deriv_gauss.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_compderivgauss_h_
22#define _libint2_src_bin_libint_compderivgauss_h_
23
24#include <generic_rr.h>
25#include <set>
26
27namespace libint2 {
28
30 static CR_DerivGauss_GenericInstantiator instance_;
31
32 CR_DerivGauss_GenericInstantiator(); // this is a singleton
34
35 // pairs of L,vectorize specify the instances of GenericGaussDeriv template to be created
36 std::set<std::pair<unsigned int, bool> > template_instances_;
37
38 public:
39 static CR_DerivGauss_GenericInstantiator& instance();
40 void add(unsigned int L, bool vectorize);
41 };
42
59 template <class IntType,
60 int part,
61 FunctionPosition where,
62 int trans_inv_part = -1,
63 FunctionPosition trans_inv_where = InBra>
64 class CR_DerivGauss : public GenericRecurrenceRelation< CR_DerivGauss<IntType,part,where,trans_inv_part,trans_inv_where>,
65 typename IntType::BasisFunctionType,
66 IntType >
67 {
68 private:
69 static constexpr auto trans_inv_oper = not IntType::OperType::Properties::odep;
70 // can use translational invariance iff the operator is translationally-invariant
71 static constexpr auto using_trans_inv = trans_inv_oper &&
72 (part == trans_inv_part) &&
73 (where == trans_inv_where);
74
75 public:
76 typedef CR_DerivGauss ThisType;
77 typedef typename IntType::BasisFunctionType BasisFunctionType;
78 typedef IntType TargetType;
80 friend class GenericRecurrenceRelation<ThisType,BasisFunctionType,TargetType>;
81 // # of children varies:
82 // 1. translational invariance makes num_functions - 1 children
83 // 2. direct differentiation always makes at most 2 Gaussians
84 static constexpr auto max_nchildren = using_trans_inv ? (IntType::num_bf - 1) : 2u;
85
87
89 static bool directional() { return true; }
90
91 private:
92 using ParentType::RecurrenceRelation::expr_;
93 using ParentType::RecurrenceRelation::nflops_;
94 using ParentType::target_;
96
98 CR_DerivGauss(const SafePtr<TargetType>&, unsigned int dir);
99
100 static std::string descr() { return "CR_DerivGauss"; }
104 std::string generate_label() const override
105 {
106 typedef typename TargetType::AuxIndexType mType;
107 static SafePtr<mType> aux0(new mType(0u));
108 std::ostringstream os;
109 os << descr() << "P" << part << to_string(where)
110 << genintegralset_label(target_->bra(),target_->ket(),aux0,target_->oper());
111 return os.str();
112 }
113
114#if LIBINT_ENABLE_GENERIC_CODE
116 bool has_generic(const SafePtr<CompilationParameters>& cparams) const override;
118 std::string generic_header() const override;
120 std::string generic_instance(const SafePtr<CodeContext>& context, const SafePtr<CodeSymbols>& args) const override;
121#endif
122 };
123
124 template <class IntType, int part, FunctionPosition where,
125 int trans_inv_part, FunctionPosition trans_inv_where>
126 CR_DerivGauss<IntType,part,where,trans_inv_part,trans_inv_where>::CR_DerivGauss(
127 const SafePtr< TargetType >& Tint,
128 unsigned int dir) :
129 ParentType(Tint,dir)
130 {
131 using namespace libint2::algebra;
132 using namespace libint2::prefactor;
133 using namespace libint2::braket;
134 typedef BasisFunctionType F;
135 const F& _1 = unit<F>(is_simple() ? dir : 0); // for shell sets increment the first index
136
137 const typename IntType::AuxQuantaType& aux = Tint->aux();
138 const typename IntType::OperType& oper = Tint->oper();
139
140 // WARNING assuming one function per position
141
142 // the Gaussian must be differentiated in direction dir
143 {
144 if (where == InBra && Tint->bra(part,0).deriv().d(dir) == 0)
145 return;
146 if (where == InKet && Tint->ket(part,0).deriv().d(dir) == 0)
147 return;
148 }
149
150 // if not using translational invariance ...
151 // can expand derivatives of primitive Gaussians only
152 if (not using_trans_inv) {
153 if (where == InBra && Tint->bra(part,0).contracted())
154 return;
155 if (where == InKet && Tint->ket(part,0).contracted())
156 return;
157 }
158
159 typedef typename IntType::BraType IBraType;
160 typedef typename IntType::KetType IKetType;
161 IBraType* bra = new IBraType(Tint->bra());
162 IKetType* ket = new IKetType(Tint->ket());
163
164 if (not using_trans_inv) { // differentiate
165
166 if (where == InBra) {
167 F a(bra->member(part,0));
168
169 // add a+1
170 F ap1(bra->member(part,0) + _1);
171 ap1.deriv().dec(dir);
172 bra->set_member(ap1,part,0);
173 auto int_ap1 = this->add_child(IntType::Instance(*bra,*ket,aux,oper));
174 bra->set_member(a,part,0);
175 if (is_simple()) {
176 std::ostringstream oss;
177 oss << "two_alpha" << part << "_bra";
178 expr_ = Scalar(oss.str()) * int_ap1; nflops_+=1;
179 }
180
181 // See if a-1 exists
182 F am1(bra->member(part,0) - _1);
183 if (exists(am1)) {
184 am1.deriv().dec(dir);
185 bra->set_member(am1,part,0);
186 auto int_am1 = this->add_child(IntType::Instance(*bra,*ket,aux,oper));
187 bra->set_member(a,part,0);
188 if (is_simple()) {
189 expr_ -= Scalar(a[dir]) * int_am1; nflops_+=2;
190 }
191 }
192 return;
193 }
194
195 if (where == InKet) {
196 F a(ket->member(part,0));
197
198 // add a+1
199 F ap1(ket->member(part,0) + _1);
200 ap1.deriv().dec(dir);
201 ket->set_member(ap1,part,0);
202 auto int_ap1 = this->add_child(IntType::Instance(*bra,*ket,aux,oper));
203 ket->set_member(a,part,0);
204 if (is_simple()) {
205 std::ostringstream oss;
206 oss << "two_alpha" << part << "_ket";
207 expr_ = Scalar(oss.str()) * int_ap1; nflops_+=1;
208 }
209
210 // See if a-1 exists
211 F am1(ket->member(part,0) - _1);
212 if (exists(am1)) {
213 am1.deriv().dec(dir);
214 ket->set_member(am1,part,0);
215 auto int_am1 = this->add_child(IntType::Instance(*bra,*ket,aux,oper));
216 ket->set_member(a,part,0);
217 if (is_simple()) {
218 expr_ -= Scalar(a[dir]) * int_am1; nflops_+=2;
219 }
220 }
221 return;
222 }
223 } else { // use translational invariance
224
225 // remove one deriv quantum from the target function
226 if (where == InBra) bra->member(part,0).deriv().dec(dir);
227 if (where == InKet) ket->member(part,0).deriv().dec(dir);
228
229 int term_count = 0;
230 for (int p = 0; p != IntType::num_particles; ++p) {
231 if (p != trans_inv_part || trans_inv_where != InBra) {
232 F a(bra->member(p, 0));
233 if (not a.is_unit()) {
234 F da(a);
235 da.deriv().inc(dir);
236 bra->set_member(da, p, 0);
237 auto int_da =
238 this->add_child(IntType::Instance(*bra, *ket, aux, oper));
239 bra->set_member(a, p, 0);
240 if (is_simple()) {
241 std::ostringstream oss;
242 if (term_count == 0)
243 expr_ = Scalar(-1) * int_da;
244 else
245 expr_ -= int_da;
246 ++term_count;
247 nflops_ += 1;
248 }
249 }
250 }
251 if (p != trans_inv_part || trans_inv_where != InKet) {
252 F a(ket->member(p, 0));
253 if (not a.is_unit()) {
254 F da(a);
255 da.deriv().inc(dir);
256 ket->set_member(da, p, 0);
257 auto int_da =
258 this->add_child(IntType::Instance(*bra, *ket, aux, oper));
259 ket->set_member(a, p, 0);
260 if (is_simple()) {
261 std::ostringstream oss;
262 if (term_count == 0)
263 expr_ = Scalar(-1) * int_da;
264 else
265 expr_ -= int_da;
266 ++term_count;
267 nflops_ += 1;
268 }
269 }
270 }
271 }
272 }
273
274 return;
275 }
276
277#if LIBINT_ENABLE_GENERIC_CODE
278 template <class IntType, int part, FunctionPosition where,
279 int trans_inv_part, FunctionPosition trans_inv_where>
280 bool
281 CR_DerivGauss<IntType,part,where,trans_inv_part,trans_inv_where>::has_generic(
282 const SafePtr<CompilationParameters>& cparams
283 ) const
284 {
285 // not implemented generic relation for translational invariance yet
286 if (using_trans_inv) return false;
287
288 if (TrivialBFSet<BasisFunctionType>::result)
289 return false;
290
291 // generate generic code if the average quantum number > max_l_opt
292 const unsigned int max_opt_am = cparams->max_am_opt();
293 unsigned int am_total = 0;
294 unsigned int nfunctions = 0;
295 const unsigned int np = IntType::OperType::Properties::np;
296 for(unsigned int p=0; p<np; p++) {
297 unsigned int nbra = target_->bra().num_members(p);
298 for(unsigned int i=0; i<nbra; i++) {
299 am_total += target_->bra(p,i).norm();
300 ++nfunctions;
301 }
302 unsigned int nket = target_->ket().num_members(p);
303 for(unsigned int i=0; i<nket; i++) {
304 am_total += target_->ket(p,i).norm();
305 ++nfunctions;
306 }
307 }
308 if (am_total > max_opt_am*nfunctions)
309 return true;
310
311 // else generate explicit code
312 return false;
313 }
314
315 template <class IntType, int part, FunctionPosition where,
316 int trans_inv_part, FunctionPosition trans_inv_where>
317 std::string
318 CR_DerivGauss<IntType,part,where,trans_inv_part,trans_inv_where>::generic_header() const
319 {
320 return std::string("GenericGaussDeriv.h");
321 }
322
323 template <class IntType, int part, FunctionPosition where,
324 int trans_inv_part, FunctionPosition trans_inv_where>
325 std::string
326 CR_DerivGauss<IntType,part,where,trans_inv_part,trans_inv_where>::generic_instance(
327 const SafePtr<CodeContext>& context, const SafePtr<CodeSymbols>& args
328 ) const
329 {
330 std::ostringstream oss;
331
332 oss << "using namespace libint2;" << std::endl;
333
334 BasisFunctionType sh(where == InBra ? target_->bra(part,0) : target_->ket(part,0));
335
336 const unsigned int L = sh.norm();
337 const bool vectorize = (context->cparams()->max_vector_length() == 1) ? false : true;
338 oss << "libint2::GenericGaussDeriv<" << L << ","
339 << (vectorize ? "true" : "false")
340 << ">::compute(inteval";
341
342 oss << "," << args->symbol(0); // target
343 const unsigned int nargs = args->n();
344 for(unsigned int a=1; a<nargs; a++) {
345 oss << "," << args->symbol(a);
346 }
347 // L == 0 => second argument not needed
348 if (nargs == 2)
349 oss << ",0";
350
351 // then dimensions of basis function sets not involved in the transfer
352 unsigned int hsr = 1;
353 unsigned int lsr = 1;
354 const unsigned int np = IntType::OperType::Properties::np;
355 // a cleaner way to count the number of function sets referring
356 // to some particles is to construct a dummy integral and
357 // use subiterator policy
358 // WARNING !!!
359 for(int p=0; p<static_cast<int>(np); p++) {
360 unsigned int nbra = target_->bra().num_members(p);
361 assert(nbra == 1);
362 for(unsigned int i=0; i<nbra; i++) {
363 SubIterator* iter = target_->bra().member_subiter(p,i);
364 if (p < part || (p == part && where == InKet))
365 hsr *= iter->num_iter();
366 // skip p == part && where == InBra
367 if (p > part)
368 lsr *= iter->num_iter();
369 delete iter;
370 }
371 unsigned int nket = target_->ket().num_members(p);
372 assert(nket == 1);
373 for(unsigned int i=0; i<nket; i++) {
374 SubIterator* iter = target_->ket().member_subiter(p,i);
375 if (p < part)
376 hsr *= iter->num_iter();
377 // skip p == part && where == InKet
378 if (p > part || (p == part && where == InBra))
379 lsr *= iter->num_iter();
380 delete iter;
381 }
382 }
383 oss << "," << hsr << "," << lsr;
384
385 // direction
386 oss << "," << this->dir();
387
388 // two_alpha prefactor
389 oss << ",inteval->two_alpha" << part << "_" << (where == InBra ? "bra" : "ket");
390
391 oss << ");";
392
393 CR_DerivGauss_GenericInstantiator::instance().add(L, vectorize);
394
395 return oss.str();
396 }
397#endif // #if !LIBINT_ENABLE_GENERIC_CODE
398
399}; // namespace libint2
400
401#endif
Definition: comp_deriv_gauss.h:29
Compute relation for (geometric) derivative Gaussian ints of generic type IntType .
Definition: comp_deriv_gauss.h:67
static bool directional()
always directional! Cartesian derivatives are applied in a particular direction
Definition: comp_deriv_gauss.h:89
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
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
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