MADNESS 0.10.1
operator.h
Go to the documentation of this file.
1/*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program 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 2 of the License, or
9 (at your option) any later version.
10
11 This program 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 this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30*/
31
32#ifndef MADNESS_MRA_OPERATOR_H__INCLUDED
33#define MADNESS_MRA_OPERATOR_H__INCLUDED
34
35/// \file mra/operator.h
36/// \brief Implements most functionality of separated operators
37
38/// \ingroup function
39
40#include <type_traits>
41#include <limits.h>
42#include <madness/mra/adquad.h>
45#include <madness/constants.h>
46
51#include <madness/mra/gfit.h>
53
54namespace madness {
55
56 template<typename T, std::size_t NDIM>
57 class Function;
58
59 template<typename T, std::size_t NDIM>
60 class SeparatedConvolution;
61
62 template<typename T, std::size_t NDIM>
63 class CCPairFunction;
64
65 template <typename T, typename R, std::size_t NDIM, std::size_t KDIM>
66 std::vector< Function<TENSOR_RESULT_TYPE(T,R), NDIM> >
67 apply(const SeparatedConvolution<T,KDIM>& op, const std::vector< Function<R,NDIM> > f);
68
69 template<typename T, std::size_t NDIM>
70 std::vector<CCPairFunction<T,NDIM>> apply(const SeparatedConvolution<T,NDIM>& op, const std::vector<CCPairFunction<T,NDIM>>& argument);
71
72 template<typename T, std::size_t NDIM>
73 std::vector<CCPairFunction<T,NDIM>> apply(const SeparatedConvolution<T,NDIM/2>& op, const std::vector<CCPairFunction<T,NDIM>>& argument);
74
75 template<typename T, std::size_t NDIM>
76 CCPairFunction<T,NDIM> apply(const SeparatedConvolution<T,NDIM>& op, const CCPairFunction<T,NDIM>& argument);
77
78 template<typename T, std::size_t NDIM>
79 CCPairFunction<T,NDIM> apply(const SeparatedConvolution<T,NDIM/2>& op, const CCPairFunction<T,NDIM>& argument);
80
81 /// SeparatedConvolutionInternal keeps data for 1 term and all dimensions and 1 displacement
82 /// Why is this here?? Why don't you just use ConvolutionND in SeparatedConvolutionData??
83 template <typename Q, std::size_t NDIM>
88
89 /// SeparatedConvolutionData keeps data for all terms, all dimensions
90
91 /// this struct is used to cache the data that are generated by
92 template <typename Q, std::size_t NDIM>
94 std::vector< SeparatedConvolutionInternal<Q,NDIM> > muops;
95 double norm;
96
97 SeparatedConvolutionData(int rank) : muops(rank), norm(0.0) {}
99 muops = q.muops;
100 norm = q.norm;
101 }
102 };
103
104
105 /// Convolutions in separated form (including Gaussian)
106
107 /* this stuff is very confusing, poorly commented, and extremely poorly named!
108
109 I think it works like this:
110 We try to apply transition matrices to the compressed form of function coefficients.
111 Most of the code is about caching these transition matrices. They are cached (key of the map is the displacement)
112 in the SimpleCache "data", which is of type SeparatedConvolutionData, which keeps the matrices
113 for all separated terms and dimensions. These SeparatedConvolutionData are constructed using
114 ConvolutionND "ops", which is constructed at the construction of the SeparatedConvolution.
115
116 SeparatedConvolution (all terms, all dim, all displacements)
117
118 construction storage
119
120 SimpleCache<SeparatedConvolutionData>
121 (all terms, all dim) / (all disp)
122 vector<ConvolutionND>
123 (1 term, all dim) / (all terms)
124 vector<SeparatedConvolutionInternal>
125 (1 term, all dim) / (all terms)
126
127
128 vector<ConvolutionData1D>
129 (1 term, 1 dim) / (all dim)
130
131 ConvolutionND and SeparatedConvolutionInternal both point to the same data in ConvolutionData1D.
132 Why we need SeparatedConvolutionInternal in the first place I have no idea. ConvolutionND has the global
133 factor, and SeparatedConvolutionInternal has a norm.
134
135
136 */
137
138 template <typename Q, std::size_t NDIM>
139 class SeparatedConvolution : public WorldObject< SeparatedConvolution<Q,NDIM> > {
140 public:
141
142 typedef Q opT; ///< The apply function uses this to infer resultT=opT*inputT
143
145
146 bool doleaves; ///< If should be applied to leaf coefficients ... false by default
147
148 private:
150 lattice_summed_; ///< If lattice_summed_[d] is true, sum over lattice translations along axis d
151 ///< N.B. the resulting kernel can be non-zero at both ends of the simulation cell along that axis
152 array_of_bools<NDIM> func_domain_is_periodic_{false}; ///< If domain_is_periodic_[d]==false and lattice_summed_[d]==false,
153 ///< ignore periodicity of BC when applying this to function
154 std::array<KernelRange, NDIM> range; ///< kernel range is along axis d is limited by range[d] if it's nonnull
155
156 public:
157 bool modified_=false; ///< use modified NS form
158 int particle_=1; ///< must only be 1 or 2
159 bool destructive_=false; ///< destroy the argument or restore it (expensive for 6d functions)
160 bool print_timings=false;
161
163 const static size_t opdim=NDIM;
168
169 private:
170
171
172 mutable std::vector< ConvolutionND<Q,NDIM> > ops; ///< ConvolutionND keeps data for 1 term, all dimensions, 1 displacement
173 const int k;
175 int rank;
176 const std::vector<long> vk;
177 const std::vector<long> v2k;
178 const std::vector<Slice> s0;
179
180 // SeparatedConvolutionData keeps data for all terms and all dimensions and 1 displacement
181 mutable SimpleCache< SeparatedConvolutionData<Q,NDIM>, NDIM > data; ///< cache for all terms, dims and displacements
182 mutable SimpleCache< SeparatedConvolutionData<Q,NDIM>, 2*NDIM > mod_data; ///< cache for all terms, dims and displacements
183
184 public:
185
186 bool& modified() {return modified_;}
187 const bool& modified() const {return modified_;}
188
189 int& particle() {return particle_;}
190 const int& particle() const {return particle_;}
192 if (p!=1 and p!=2) throw std::runtime_error("particle must be 1 or 2");
193 particle_=p;
194 return *this;
195 }
196
197 bool& destructive() {return destructive_;}
198 const bool& destructive() const {return destructive_;}
199
200 const double& gamma() const {return info.mu;}
201 const double& mu() const {return info.mu;}
202 int get_rank() const { return rank; }
203 int get_k() const { return k; }
204 const std::vector<ConvolutionND<Q,NDIM>>& get_ops() const { return ops; }
205 const std::array<KernelRange, NDIM>& get_range() const { return range; }
206 bool range_restricted() const { return std::any_of(range.begin(), range.end(), [](const auto& v) { return v.finite(); }); }
207
208 private:
209
210 /// laziness for calling lists: which terms to apply
211 struct ApplyTerms {
212 ApplyTerms() : r_term(false), t_term(false) {}
213 bool r_term;
214 bool t_term;
215 bool any_terms() const {return r_term or t_term;}
216 };
217
218 /// too lazy for extended calling lists
220 long r; // Effective rank of transformation
221 const Q* U; // Ptr to matrix
222 const Q* VT;
223 };
224
225 static inline std::pair<Tensor<double>,Tensor<double>>
227 const std::array<LatticeRange, NDIM>& lattice_ranges) {
228
229 const Tensor<double> &cell_width =
231 double hi = cell_width.normf(); // Diagonal width of cell
232 // Extend kernel range for lattice summation
233 // N.B. if have periodic boundaries, extend range just in case will be using periodic domain
234 bool lattice_summed_any = std::any_of(
235 lattice_ranges.begin(), lattice_ranges.end(), [](const LatticeRange& b){ return static_cast<bool>(b); });
236 bool infinite_summed_any = false;
237 for (size_t i = 0; i < NDIM; i++) {
238 if (lattice_ranges[i].infinite() && info.range[i].infinite()) {
239 infinite_summed_any = true;
240 break;
241 }
242 }
243 if (lattice_summed_any || FunctionDefaults<NDIM>::get_bc().is_periodic_any()) {
244 hi *= 100;
245 }
246
247 info.hi = hi;
249
250 Tensor<double> coeff = fit.coeffs();
251 Tensor<double> expnt = fit.exponents();
252
253 if (info.truncate_lowexp_gaussians.value_or(infinite_summed_any)) {
254 // convolution with Gaussians of exponents <= 0.25/(L^2) contribute only a constant shift
255 // the largest spacing along lattice summed axes thus controls the smallest Gaussian exponent that NEEDS to be included
256 double max_lattice_spacing = 0;
257 for(int d=0; d!=NDIM; ++d) {
258 if (lattice_ranges[d])
259 max_lattice_spacing =
260 std::max(max_lattice_spacing, cell_width(d));
261 }
262 // WARNING: discardG0 = true ignores the coefficients of truncated
263 // terms
264 fit.truncate_periodic_expansion(coeff, expnt, max_lattice_spacing,
265 /* discardG0 = */ true);
267 }
268
269 return std::make_pair(coeff, expnt);
270 }
271
272// /// return the right block of the upsampled operator (modified NS only)
273//
274// /// unlike the operator matrices on the natural level the upsampled operator
275// /// matrices are not Toeplitz, so we need more information than just the displacement
276// ///.@param[in] source the source key
277// /// @param[in] disp the displacement
278// /// @param[in] upop the unfiltered operator matrix from scale n-1
279// /// @return (k,k) patch of the upop(2k,2k) matrix
280// static Tensor<Q> operator_patch(const Translation& source, const Translation& disp, const Tensor<Q>& upop) {
281//
282// // which of the 4 upsampled matrices do we need?
283// Translation sx=source%2; // source offset
284// Translation tx=(source+disp)%2; // target offset
285//
286// Tensor<Q> rij(k,k);
287// // those two are equivalent:
288///*
289// if (sx==0 and tx==0) copy_2d_patch(rij.ptr(), k, upop.ptr(), 2*k, k, k);
290// if (sx==1 and tx==0) copy_2d_patch(rij.ptr() + k, k, upop.ptr(), 2*k, k, k);
291// if (sx==0 and tx==1) copy_2d_patch(rij.ptr() + 2*k*k, k, upop.ptr(), 2*k, k, k);
292// if (sx==1 and tx==1) copy_2d_patch(rij.ptr() + 2*k*k + k, k, upop.ptr(), 2*k, k, k);
293//*/
294// Slice s0(0,k-1), s1(k,2*k-1);
295// if (sx==0 and tx==0) rij=Rm(s0,s0);
296// if (sx==1 and tx==0) rij=Rm(s1,s0);
297// if (sx==0 and tx==1) rij=Rm(s0,s1);
298// if (sx==1 and tx==1) rij=Rm(s1,s1);
299//
300// return rij;
301// }
302
303
304
305 /// accumulate into result
306 template <typename T, typename R>
307 void apply_transformation(long dimk,
308 const Transformation trans[NDIM],
309 const Tensor<T>& f,
310 Tensor<R>& work1,
311 Tensor<R>& work2,
312 const Q mufac,
313 Tensor<R>& result) const {
314
315 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
316 long size = 1;
317 for (std::size_t i=0; i<NDIM; ++i) size *= dimk;
318 long dimi = size/dimk;
319
320 R* MADNESS_RESTRICT w1=work1.ptr();
321 R* MADNESS_RESTRICT w2=work2.ptr();
322
323#ifdef HAVE_IBMBGQ
324 mTxmq_padding(dimi, trans[0].r, dimk, dimk, w1, f.ptr(), trans[0].U);
325#else
326 mTxmq(dimi, trans[0].r, dimk, w1, f.ptr(), trans[0].U, dimk);
327#endif
328
329 size = trans[0].r * size / dimk;
330 dimi = size/dimk;
331 for (std::size_t d=1; d<NDIM; ++d) {
332#ifdef HAVE_IBMBGQ
333 mTxmq_padding(dimi, trans[d].r, dimk, dimk, w2, w1, trans[d].U);
334#else
335 mTxmq(dimi, trans[d].r, dimk, w2, w1, trans[d].U, dimk);
336#endif
337 size = trans[d].r * size / dimk;
338 dimi = size/dimk;
339 std::swap(w1,w2);
340 }
341
342 // If all blocks are full rank we can skip the transposes
343 bool doit = false;
344 for (std::size_t d=0; d<NDIM; ++d) doit = doit || trans[d].VT;
345
346 if (doit) {
347 for (std::size_t d=0; d<NDIM; ++d) {
348 if (trans[d].VT) {
349 dimi = size/trans[d].r;
350#ifdef HAVE_IBMBGQ
351 mTxmq_padding(dimi, dimk, trans[d].r, dimk, w2, w1, trans[d].VT);
352#else
353 mTxmq(dimi, dimk, trans[d].r, w2, w1, trans[d].VT);
354#endif
355 size = dimk*size/trans[d].r;
356 }
357 else {
358 fast_transpose(dimk, dimi, w1, w2);
359 }
360 std::swap(w1,w2);
361 }
362 }
363 // Assuming here that result is contiguous and aligned
364 aligned_axpy(size, result.ptr(), w1, mufac);
365 }
366
367
368 /// accumulate into result
369 template <typename T, typename R>
371 const Tensor<T>& f,
372 const Q mufac,
373 Tensor<R>& result) const {
374
375 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
376
377 Tensor<R> result2=general_transform(f,trans2);
378 result2.scale(mufac);
379 result+=result2;
380
381 }
382
383
384
385 /// don't accumulate, since we want to do this at apply()
386 template <typename T, typename R>
387 void apply_transformation2(Level n, long dimk, double tol,
388 const Tensor<T> trans2[NDIM],
389 const GenTensor<T>& f,
390 GenTensor<R>& work1,
391 GenTensor<R>& work2,
392 const Q mufac,
393 GenTensor<R>& result) const {
394
395 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
396
397#if 1
398 result=general_transform(f,trans2);
399 result.scale(mufac);
400
401#else
402
403 long size = 1;
404 for (std::size_t i=0; i<NDIM; ++i) size *= dimk;
405 long dimi = size/dimk;
406
407 R* MADNESS_RESTRICT w1=work1.ptr();
408 R* MADNESS_RESTRICT w2=work2.ptr();
409
410 mTxmq(dimi, trans[0].r, dimk, w1, f.ptr(), trans[0].U, dimk);
411 size = trans[0].r * size / dimk;
412 dimi = size/dimk;
413 for (std::size_t d=1; d<NDIM; ++d) {
414 mTxmq(dimi, trans[d].r, dimk, w2, w1, trans[d].U, dimk);
415 size = trans[d].r * size / dimk;
416 dimi = size/dimk;
417 std::swap(w1,w2);
418 }
419
420 // If all blocks are full rank we can skip the transposes
421 bool doit = false;
422 for (std::size_t d=0; d<NDIM; ++d) doit = doit || trans[d].VT;
423
424 if (doit) {
425 for (std::size_t d=0; d<NDIM; ++d) {
426 if (trans[d].VT) {
427 dimi = size/trans[d].r;
428 mTxmq(dimi, dimk, trans[d].r, w2, w1, trans[d].VT);
429 size = dimk*size/trans[d].r;
430 }
431 else {
432 fast_transpose(dimk, dimi, w1, w2);
433 }
434 std::swap(w1,w2);
435 }
436 }
437 // Assuming here that result is contiguous and aligned
438 aligned_axpy(size, result.ptr(), w1, mufac);
439 // long one = 1;
440 //daxpy_(&size, &mufac, w1, &one, result.ptr(), &one);
441#endif
442 }
443
444
445 /// Apply one of the separated terms, accumulating into the result
446 template <typename T>
448 const ConvolutionData1D<Q>* const ops_1d[NDIM],
449 const Tensor<T>& f, const Tensor<T>& f0,
450 Tensor<TENSOR_RESULT_TYPE(T,Q)>& result,
451 Tensor<TENSOR_RESULT_TYPE(T,Q)>& result0,
452 const double tol,
453 const Q mufac,
454 Tensor<TENSOR_RESULT_TYPE(T,Q)>& work1,
455 Tensor<TENSOR_RESULT_TYPE(T,Q)>& work2) const {
456
457 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
458 Transformation trans[NDIM];
459 Tensor<T> trans2[NDIM];
460
461 double Rnorm = 1.0;
462 for (std::size_t d=0; d<NDIM; ++d) Rnorm *= ops_1d[d]->Rnorm;
463
464 if (at.r_term and (Rnorm > 1.e-20)) {
465
466 const auto tol_Rs = tol/(Rnorm*NDIM); // Errors are relative within here
467
468 // Determine rank of SVD to use or if to use the full matrix
469 long twok = 2*k;
470 if (modified()) twok=k;
471
472 long break_even;
473 if (NDIM==1) break_even = long(0.5*twok);
474 else if (NDIM==2) break_even = long(0.6*twok);
475 else if (NDIM==3) break_even=long(0.65*twok);
476 else break_even=long(0.7*twok);
477 bool rank_is_zero = false;
478 for (std::size_t d=0; d<NDIM; ++d) {
479 long r;
480 for (r=0; r<twok; ++r) {
481 if (ops_1d[d]->Rs[r] < tol_Rs) break;
482 }
483 if (r >= break_even) {
484 trans[d].r = twok;
485 trans[d].U = ops_1d[d]->R.ptr();
486 trans[d].VT = 0;
487 }
488 else {
489
490#ifdef USE_GENTENSOR
491 r = std::max(2L,r+(r&1L)); // (needed for 6D == when GENTENSOR is on) NOLONGER NEED TO FORCE OPERATOR RANK TO BE EVEN
492#endif
493 if (r == 0) {
494 rank_is_zero = true;
495 break;
496 }
497 trans[d].r = r;
498 trans[d].U = ops_1d[d]->RU.ptr();
499 trans[d].VT = ops_1d[d]->RVT.ptr();
500 }
501 trans2[d]=ops_1d[d]->R;
502 }
503
504 if (!rank_is_zero)
505 apply_transformation(twok, trans, f, work1, work2, mufac, result);
506
507 // apply_transformation2(n, twok, tol, trans2, f, work1, work2, mufac, result);
508// apply_transformation3(trans2, f, mufac, result);
509 }
510
511 double Tnorm = 1.0;
512 for (std::size_t d=0; d<NDIM; ++d) Tnorm *= ops_1d[d]->Tnorm;
513
514 if (at.t_term and (Tnorm>0.0)) {
515 const auto tol_Ts = tol/(Tnorm*NDIM); // Errors are relative within here
516
517 long break_even;
518 if (NDIM==1) break_even = long(0.5*k);
519 else if (NDIM==2) break_even = long(0.6*k);
520 else if (NDIM==3) break_even=long(0.65*k);
521 else break_even=long(0.7*k);
522 bool rank_is_zero = false;
523 for (std::size_t d=0; d<NDIM; ++d) {
524 long r;
525 for (r=0; r<k; ++r) {
526 if (ops_1d[d]->Ts[r] < tol_Ts) break;
527 }
528 if (r >= break_even) {
529 trans[d].r = k;
530 trans[d].U = ops_1d[d]->T.ptr();
531 trans[d].VT = 0;
532 }
533 else {
534
535#ifdef USE_GENTENSOR
536 r = std::max(2L,r+(r&1L)); // (needed for 6D == GENTENSOR is USED) NOLONGER NEED TO FORCE OPERATOR RANK TO BE EVEN
537#endif
538 if (r == 0) {
539 rank_is_zero = true;
540 break;
541 }
542 trans[d].r = r;
543 trans[d].U = ops_1d[d]->TU.ptr();
544 trans[d].VT = ops_1d[d]->TVT.ptr();
545 }
546 trans2[d]=ops_1d[d]->T;
547 }
548 if (!rank_is_zero)
549 apply_transformation(k, trans, f0, work1, work2, -mufac, result0);
550// apply_transformation2(n, k, tol, trans2, f0, work1, work2, -mufac, result0);
551// apply_transformation3(trans2, f0, -mufac, result0);
552 }
553 }
554
555
556 /// Apply one of the separated terms, accumulating into the result
557 template <typename T>
559 const ConvolutionData1D<Q>* const ops_1d[NDIM],
560 const GenTensor<T>& f, const GenTensor<T>& f0,
562 GenTensor<TENSOR_RESULT_TYPE(T,Q)>& result0,
563 double tol,
564 const Q mufac,
566 GenTensor<TENSOR_RESULT_TYPE(T,Q)>& work2) const {
567
569// Transformation trans[NDIM];
570 Tensor<T> trans2[NDIM];
571// MADNESS_EXCEPTION("no muopxv_fast2",1);
572
573 double Rnorm = 1.0;
574 for (std::size_t d=0; d<NDIM; ++d) Rnorm *= ops_1d[d]->Rnorm;
575 if (Rnorm == 0.0) return;
576
577 if (Rnorm > 1.e-20) {
578
579 tol = tol/(Rnorm*NDIM); // Errors are relative within here
580
581 // Determine rank of SVD to use or if to use the full matrix
582 long twok = 2*k;
583 if (modified()) twok=k;
584// long break_even;
585// if (NDIM==1) break_even = long(0.5*twok);
586// else if (NDIM==2) break_even = long(0.6*twok);
587// else if (NDIM==3) break_even=long(0.65*twok);
588// else break_even=long(0.7*twok);
589 for (std::size_t d=0; d<NDIM; ++d) {
590 // long r;
591 // for (r=0; r<twok; ++r) {
592 // if (ops_1d[d]->Rs[r] < tol) break;
593 // }
594// if (r >= break_even) {
595// trans[d].r = twok;
596// trans[d].U = ops_1d[d]->R.ptr();
597// trans[d].VT = 0;
598// }
599// else {
600// //r += std::max(2L,r&1L); // NOLONGER NEED TO FORCE OPERATOR RANK TO BE EVEN
601// trans[d].r = r;
602// trans[d].U = ops_1d[d]->RU.ptr();
603// trans[d].VT = ops_1d[d]->RVT.ptr();
604// }
605 trans2[d]=ops_1d[d]->R;
606 }
607 apply_transformation2(n, twok, tol, trans2, f, work1, work2, mufac, result);
608 }
609
610 double Tnorm = 1.0;
611 for (std::size_t d=0; d<NDIM; ++d) Tnorm *= ops_1d[d]->Tnorm;
612
613 if (n > 0 and (Tnorm>1.e-20)) {
614// long break_even;
615//
616// if (NDIM==1) break_even = long(0.5*k);
617// else if (NDIM==2) break_even = long(0.6*k);
618// else if (NDIM==3) break_even=long(0.65*k);
619// else break_even=long(0.7*k);
620 for (std::size_t d=0; d<NDIM; ++d) {
621 // long r;
622 // for (r=0; r<k; ++r) {
623 // if (ops_1d[d]->Ts[r] < tol) break;
624 // }
625// if (r >= break_even) {
626// trans[d].r = k;
627// trans[d].U = ops_1d[d]->T.ptr();
628// trans[d].VT = 0;
629// }
630// else {
631// //r += std::max(2L,r&1L); // NOLONGER NEED TO FORCE OPERATOR RANK TO BE EVEN
632// trans[d].r = r;
633// trans[d].U = ops_1d[d]->TU.ptr();
634// trans[d].VT = ops_1d[d]->TVT.ptr();
635// }
636 trans2[d]=ops_1d[d]->T;
637 }
638 apply_transformation2(n, k, tol, trans2, f0, work1, work2, -mufac, result0);
639 }
640 }
641
642
643 /// Computes the Frobenius norm of one of the separated terms ... WITHOUT FACTOR INCLUDED
644 /// compute for 1 term, all dim, 1 disp, essentially for SeparatedConvolutionInternal
645 double munorm2(Level n, const ConvolutionData1D<Q>* ops[]) const {
646 if (modified()) return munorm2_modified(n,ops);
647 return munorm2_ns(n,ops);
648 }
649
650 /// Computes the Frobenius norm of one of the separated terms for the NS form
651 /// ... WITHOUT FACTOR INCLUDED
652 /// compute for 1 term, all dim, 1 disp, essentially for SeparatedConvolutionInternal
653 double munorm2_ns(Level n, const ConvolutionData1D<Q>* ops[]) const {
654 //PROFILE_MEMBER_FUNC(SeparatedConvolution);
655
656 double prodR=1.0, prodT=1.0;
657 for (std::size_t d=0; d<NDIM; ++d) {
658 prodR *= ops[d]->Rnormf;
659 prodT *= ops[d]->Tnormf;
660
661 }
662// if (n) prodR = sqrt(std::max(prodR*prodR - prodT*prodT,0.0));
663
664 // this kicks in if the line above has no numerically significant digits.
665// if (prodR < 1e-8*prodT) {
666 double prod=1.0, sum=0.0;
667 for (std::size_t d=0; d<NDIM; ++d) {
668 double a = ops[d]->NSnormf;
669 double b = ops[d]->Tnormf;
670 double aa = std::min(a,b);
671 double bb = std::max(a,b);
672 prod *= bb;
673 if (bb > 0.0) sum +=(aa/bb);
674 }
675 if (n) prod *= sum;
676 prodR = prod;
677// }
678
679 return prodR;
680 }
681
682
683 /// Computes the operator norm of one of the separated terms of the modified NS form
684 /// ... WITHOUT FACTOR INCLUDED
685 /// compute for 1 term, all dim, 1 disp, essentially for SeparatedConvolutionInternal
686 double munorm2_modified(Level n, const ConvolutionData1D<Q>* ops_1d[]) const {
688
689 // follows Eq. (21) ff of Beylkin 2008 (Beylkin Appl. Comput. Harmon. Anal. 24, pp 354)
690
691 // we have all combinations of difference, upsampled, F terms (d, u, f),
692 // with the constraint that d is in each term exactly once. In the mixed terms (udf)
693 // we just get all possible combinations, in the pure terms (dff, duu) we have
694 // to multiply each term (dff, fdf, ffd) with (NDIM-1)!, to get the right number.
695
696 double dff = 0.0;
697 double duu = 0.0;
698 double udf = 0.0;
699
700 // loop over d shifting over the dimensions dxx, xdx, xxd,
701 for (size_t d=0; d<NDIM; ++d) {
702 double dff_tmp = ops_1d[d]->N_diff;
703 double duu_tmp = ops_1d[d]->N_diff;
704 double udf_tmp = ops_1d[d]->N_diff;
705
706
707 for (size_t dd=0; dd<NDIM; ++dd) {
708 if (dd!=d) {
709 dff_tmp *= ops_1d[dd]->N_F;
710 duu_tmp *= ops_1d[dd]->N_up;
711
712 udf_tmp *= ops_1d[dd]->N_F;
713 for (size_t ddd=0; ddd<NDIM; ++ddd) {
714 if (ddd!=dd) udf += udf_tmp * ops_1d[ddd]->N_up;
715 }
716 }
717 }
718
719 dff+=dff_tmp;
720 duu+=duu_tmp;
721 }
722
723 // finalize with the factorial
724 double factorial=1.0;
725 for (int i=1; i<static_cast<int>(NDIM)-1; ++i) factorial*=double(i);
726 dff*=factorial;
727 duu*=factorial;
728
729 // Eq. (23) of Beylkin 2008, for one separated term WITHOUT the factor
730 double norm=(dff + udf + duu) /(factorial * double(NDIM));
731
732// // double check
733// if (NDIM==3) {
734// Tensor<Q> R_full=outer(ops_1d[0]->R,outer(ops_1d[1]->R,ops_1d[2]->R));
735// Tensor<Q> T_full=outer(ops_1d[0]->T,outer(ops_1d[1]->T,ops_1d[2]->T));
736// double n2=(R_full-T_full).normf();
737//// print("norm estimate, norm",norm, n2, norm<n2);
738// norm=n2;
739// }
740
741 return norm;
742
743 }
744
745
746 /// get the transformation matrices for 1 term and all dimensions and one displacement
747
748 /// use ConvolutionND, which uses ConvolutionData1D to collect the transformation matrices
750 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
752 for (std::size_t d=0; d<NDIM; ++d) {
753 op.ops[d] = ops[mu].getop(d)->nonstandard(n, disp.translation()[d]);
754 }
755 op.norm = munorm2(n, op.ops)*std::abs(ops[mu].getfac());
756
757// double newnorm = munorm2(n, op.ops);
758// // This rescaling empirically based upon BSH separated expansion
759// // ... needs more testing. OK also for TDSE.
760// // All is good except for some 000 blocks which are up to sqrt(k^d) off.
761// for (int d=0; d<NDIM; ++d) {
762// if (disp[d] == 0) newnorm *= 0.5;
763// else if (std::abs(disp[d]) == 1) newnorm *= 0.8;
764// }
765// double oldnorm = munorm(n, op.ops);
766// if (oldnorm > 1e-13 && (newnorm < 0.5*oldnorm || newnorm > 2.0*oldnorm) )
767// print("munorm", n, disp, mu, newnorm, oldnorm, newnorm/oldnorm);
768
769 return op;
770 }
771
772
773
774 /// get the transformation matrices for 1 term and all dimensions and one displacement
775
776 /// use ConvolutionND, which uses ConvolutionData1D to collect the transformation matrices
778 getmuop_modified(int mu, Level n, const Key<NDIM>& disp, const Key<NDIM>& source) const {
779 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
780
781
782 // SeparatedConvolutionInternal keeps data for 1 term and all dimensions
784
785 // in the modified NS form we need not only the displacement, but also the source Translation
786 // for correctly constructing the operator, b/c the operator is not Toeplitz
787
788 // op.ops is of type ConvolutionData1D (1 term, 1 dim, 1 disp)
789 // ops[mu] is of type ConvolutionND (1 term, all dim, 1 disp)
790 for (std::size_t d=0; d<NDIM; ++d) {
791 Translation sx=source.translation()[d]; // source translation
792 Translation tx=source.translation()[d]+disp.translation()[d]; // target translation
793
794 Key<2> op_key(n,Vector<Translation,2>{sx,tx});
795 op.ops[d] = ops[mu].getop(d)->mod_nonstandard(op_key);
796 }
797
798 // works for both modified and not modified NS form
799 op.norm = munorm2(n, op.ops)*std::abs(ops[mu].getfac());
800// op.norm=1.0;
801 return op;
802 }
803
804 /// get the data for all terms and all dimensions for one displacement
806
807 // in the NS form the operator depends only on the displacement
808 if (not modified()) return getop_ns(n,d);
809 return getop_modified(n, d, source);
810 }
811
812
813 /// get the data for all terms and all dimensions for one displacement
814
815 /// uses SeparatedConvolutionInternal (ConvolutionND, ConvolutionData1D) to construct
816 /// the transformation matrices.
817 /// @param[in] d displacement
818 /// @return pointer to cached operator
820 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
821 const SeparatedConvolutionData<Q,NDIM>* p = data.getptr(n,d);
822 if (p) return p;
823
824 // get the data for each term
826 for (int mu=0; mu<rank; ++mu) {
827 // op.muops is of type SeparatedConvolutionInternal (1 term, all dim, 1 disp)
828 // getmuop uses ConvolutionND
829 op.muops[mu] = getmuop(mu, n, d);
830 }
831
832 double norm = 0.0;
833 for (int mu=0; mu<rank; ++mu) {
834 const double munorm = op.muops[mu].norm;
835 norm += munorm*munorm;
836 }
837 //print("getop", n, d, norm);
838 op.norm = sqrt(norm);
839 data.set(n, d, op);
840 return data.getptr(n,d);
841 }
842
843
844
845 /// get the data for all terms and all dimensions for one displacement (modified NS form)
846
847 /// remember that the operator in the modified NS form is not Toeplitz, so we need
848 /// information about the displacement and the source key
849 /// @param[in] n level (=scale) (actually redundant, since included in source)
850 /// @param[in] disp displacement key
851 /// @param[in] source source key
852 /// @return pointer to cached operator
854 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
855
856 // in the modified NS form the upsampled part of the operator depends on the modulus of the source
857 Vector<Translation,NDIM> t=source.translation();
858 for (size_t i=0; i<NDIM; ++i) t[i]=t[i]%2;
859 Key<2*NDIM> key=disp.merge_with(Key<NDIM>(source.level(),t));
860
861 const SeparatedConvolutionData<Q,NDIM>* p = mod_data.getptr(n,key);
862 if (p) return p;
863
864 // get the data for each term
865 // op.muops is of type SeparatedConvolutionInternal (1 term, all dim, 1 disp)
866 // getmuop uses ConvolutionND
868 for (int mu=0; mu<rank; ++mu) op.muops[mu] = getmuop_modified(mu, n, disp, source);
869
870 double norm = 0.0;
871 for (int mu=0; mu<rank; ++mu) {
872 const double munorm = op.muops[mu].norm;
873 norm += munorm*munorm;
874 }
875
876 op.norm = sqrt(norm);
877 mod_data.set(n, key, op);
878 return mod_data.getptr(n,key);
879 }
880
881
882 void check_cubic() {
883 // !!! NB ... cell volume obtained from global defaults
885 // Check that the cell is cubic since currently is assumed
886 for (std::size_t d=1; d<NDIM; ++d) {
887 MADNESS_CHECK(fabs(cell_width(d)-cell_width(0L)) < 1e-14*cell_width(0L));
888 }
889 }
890
891
892 /// upsample some of the dimensions of coeff to its child indicated by key
893
894 /// @param[in] coeff the coeffs of dim 2*NDIM that will be upsampled
895 /// @param[in] key the key indicating the child -- only some dimensions will be "reproductive"
896 /// @param[in] particle if 0: upsample dimensions 0-2
897 /// if 1: upsample dimensions 3-5
898 /// @return a partially upsampled coefficient tensor
899 template<typename T, size_t FDIM>
900 GenTensor<T> partial_upsample(const Key<FDIM>& key, const GenTensor<T>& coeff, const int particle) const {
901
902 if (coeff.rank()==0) return GenTensor<T>();
903 MADNESS_ASSERT(coeff.dim(0)==k);
904 if (NDIM==coeff.ndim()) {
905 MADNESS_ASSERT(particle==1); // other particle, leave this particle unchanged
906 return coeff;
907 }
908
909 MADNESS_ASSERT(coeff.ndim()==FDIM);
910 MADNESS_ASSERT(particle==0 or (2*NDIM==FDIM));
911
912 // the twoscale coefficients: for upsampling use h0/h1; see Alpert Eq (3.35a/b)
913 // handle the spectator dimensions with the identity matrix
914 const Tensor<T> h[2] = {cdata.h0, cdata.h1};
915 Tensor<T> identity(k,k);
916 for (int i=0; i<k; ++i) identity(i,i)=1.0;
917 Tensor<T> matrices[2*NDIM];
918
919 // get the appropriate twoscale coefficients for each dimension
920 if (particle==0) {
921 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii]=h[key.translation()[ii]%2];
922 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii+NDIM]=identity;
923 } else if (particle==1) {
924 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii]=identity;
925 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii+NDIM]=h[key.translation()[ii+NDIM]%2];
926 } else {
927 MADNESS_EXCEPTION("unknown particle",1);
928 }
929
930 // transform and accumulate on the result
931 const GenTensor<T> result=general_transform(coeff,matrices);
932 return result;
933 }
934
935
936 /// upsample the sum coefficients of level 1 to sum coeffs on level n+1
937
938 /// specialization of the unfilter method, will transform only the sum coefficients
939 /// @param[in] key key of level n+1
940 /// @param[in] coeff sum coefficients of level n (does NOT belong to key!!)
941 /// @return sum coefficients on level n+1
942 template<typename T, size_t FDIM>
943 GenTensor<T> upsample(const Key<FDIM>& key, const GenTensor<T>& coeff) const {
944
945 // the twoscale coefficients: for upsampling use h0/h1; see Alpert Eq (3.35a/b)
946 // note there are no difference coefficients; if you want that use unfilter
947 const Tensor<T> h[2] = {cdata.h0, cdata.h1};
948 Tensor<T> matrices[FDIM];
949
950 // get the appropriate twoscale coefficients for each dimension
951 for (size_t ii=0; ii<FDIM; ++ii) matrices[ii]=h[key.translation()[ii]%2];
952
953 // transform and accumulate on the result
954 const GenTensor<T> result=general_transform(coeff,matrices);
955 return result;
956 }
957
958 /// initializes range using range of ops[0]
959 /// @pre `ops[i].range == ops[0].range`
960 void init_range() {
961 if (!ops.empty()) {
962 for (int d = 0; d != NDIM; ++d) {
963 for(const auto & op: ops) {
964 MADNESS_ASSERT(op.getop(d)->range == ops[0].getop(d)->range);
965 }
966 range[d] = ops[0].getop(d)->range;
967 }
968 }
969 }
970
971 /// initializes lattice_sum using `ops[0].lattice_summed()`
972 /// @pre `ops[i].lattice_summed() == ops[0].lattice_summed()`
974 if (!ops.empty()) {
975 for (int d = 0; d != NDIM; ++d) {
976 for (const auto &op : ops) {
977 MADNESS_ASSERT(op.lattice_summed() ==
978 ops[0].lattice_summed());
979 }
980 lattice_summed_ = ops[0].lattice_summed();
981 }
982 }
983 }
984
985 public:
986
987 // For separated convolutions with same operator in each direction (isotropic)
989 const std::vector< std::shared_ptr< Convolution1D<Q> > >& argops,
991 bool doleaves = false)
993 , info()
995 , lattice_summed_(false) // this will be overridden by init_lattice_summed below
996 , modified_(false)
997 , particle_(1)
998 , destructive_(false)
999 , k(k)
1000 , cdata(FunctionCommonData<Q,NDIM>::get(k))
1001 , rank(argops.size())
1002 , vk(NDIM,k)
1003 , v2k(NDIM,2*k)
1004 , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1))
1005 {
1006
1007 for (unsigned int mu=0; mu < argops.size(); ++mu) {
1008 this->ops.push_back(ConvolutionND<Q,NDIM>(argops[mu]));
1009 }
1010 init_range();
1012
1013 this->process_pending();
1014 }
1015
1016 // For general convolutions
1018 const std::vector< ConvolutionND<Q,NDIM> >& argops,
1020 bool doleaves = false)
1022 , info()
1024 , lattice_summed_(false) // this will be overridden by init_lattice_summed below
1025 , modified_(false)
1026 , particle_(1)
1027 , destructive_(false)
1028 , ops(argops)
1029 , k(k)
1030 , cdata(FunctionCommonData<Q,NDIM>::get(k))
1031 , rank(argops.size())
1032 , vk(NDIM,k)
1033 , v2k(NDIM,2*k)
1034 , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1))
1035 {
1036 init_range();
1038 this->process_pending();
1039 }
1040
1041 /// Constructor for Gaussian Convolutions
1042 /// WARNING! bloch_k should only ever be nonzero if `Q` is a complex type.
1044 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1046 bool doleaves = false,
1047 const Vector<double, NDIM>& bloch_k = Vector<double, NDIM>(0.0))
1048 : SeparatedConvolution(world,Tensor<double>(0l),Tensor<double>(0l),info1.lo,info1.thresh,lattice_ranges,k,doleaves,info1.mu) {
1049 info.type=info1.type;
1051 info.range = info1.range;
1052 auto [coeff, expnt] = make_coeff_for_operator(world, info, lattice_ranges);
1053 rank=coeff.dim(0);
1054 range = info.template range_as_array<NDIM>();
1055 ops.resize(rank);
1056 initialize(coeff,expnt,lattice_ranges,range,bloch_k);
1058 }
1059
1060 /// Constructor for Gaussian Convolutions (mostly for backward compatability)
1062 const Tensor<Q>& coeff, const Tensor<double>& expnt,
1063 double lo, double thresh,
1064 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1066 bool doleaves = false,
1067 double mu=0.0)
1071 ,
1072 lattice_summed_(false) // will be updated by init_lattice_summed
1073 , ops(coeff.dim(0))
1074 , k(k)
1075 , cdata(FunctionCommonData<Q,NDIM>::get(k))
1076 , rank(coeff.dim(0))
1077 , vk(NDIM,k)
1078 , v2k(NDIM,2*k)
1079 , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1)) {
1080 initialize(coeff,expnt,lattice_ranges);
1081 init_range();
1083 }
1084
1085 void initialize(const Tensor<Q>& coeff, const Tensor<double>& expnt, std::array<LatticeRange, NDIM> lattice_range, std::array<KernelRange, NDIM> range = {}, const Vector<double, NDIM>& bloch_k = Vector<double, NDIM>(0.0)) {
1087 const double pi = constants::pi;
1088
1089 for (int mu=0; mu<rank; ++mu) {
1090 Q c = std::pow(sqrt(expnt(mu)/pi),static_cast<int>(NDIM)); // Normalization coeff
1091
1092 // We cache the normalized operator so the factor is the value we must multiply
1093 // by to recover the coeff we want.
1094 ops[mu].setfac(coeff(mu)/c);
1095
1096 for (std::size_t d=0; d<NDIM; ++d) {
1097 ops[mu].setop(d,GaussianConvolution1DCache<Q>::get(k, expnt(mu)*width[d]*width[d], 0,
1098 lattice_range[d], bloch_k[d], range[d]));
1099 }
1100 }
1101 }
1102
1104
1105 void print_timer() const {
1106 if (this->get_world().rank()==0) {
1107 timer_full.print("op full tensor ");
1108 timer_low_transf.print("op low rank transform");
1109 timer_low_accumulate.print("op low rank addition ");
1110 }
1111 }
1112
1113 void reset_timer() const {
1114 if (this->get_world().rank()==0) {
1115 timer_full.reset();
1118 }
1119 }
1120
1121 const std::vector< Key<NDIM> >& get_disp(Level n) const {
1123 }
1124
1125 /// @return flag for each axis indicating whether lattice summation is performed in that direction
1127 /// @return flag for each axis indicating whether functions that this op acts on are periodic on the box in that direction (false by default)
1128 /// it is normally preferred to lattice sum, obtaining an equivalent problem with a lattice-summed operator on a non-periodic function
1130 /// changes domain periodicity
1131 /// \param domain_is_periodic
1132 void set_domain_periodicity(const array_of_bools<NDIM>& domain_is_periodic) { func_domain_is_periodic_ = domain_is_periodic;}
1133
1134 /// return the operator norm for all terms, all dimensions and 1 displacement
1135 double norm(Level n, const Key<NDIM>& d, const Key<NDIM>& source_key) const {
1136 // SeparatedConvolutionData keeps data for all terms and all dimensions and 1 displacement
1137// return 1.0;
1138 return getop(n, d, source_key)->norm;
1139 }
1140
1141 /// return that part of a hi-dim key that serves as the base for displacements of this operator
1142
1143 /// if the function and the operator have the same dimension return key
1144 /// if the function has a higher dimension than the operator (e.g. in the exchange operator)
1145 /// return only that part of key that corresponds to the particle this operator works on
1146 /// @param[in] key hi-dim key
1147 /// @return a lo-dim part of key; typically first or second half
1148 template<size_t FDIM>
1149 typename std::enable_if<FDIM!=NDIM, Key<NDIM> >::type
1150 get_source_key(const Key<FDIM> key) const {
1152 Key<FDIM-NDIM> dummykey;
1153 if (particle()==1) key.break_apart(source,dummykey);
1154 if (particle()==2) key.break_apart(dummykey,source);
1155 return source;
1156 }
1157
1158 /// return that part of a hi-dim key that serves as the base for displacements of this operator
1159
1160 /// if the function and the operator have the same dimension return key
1161 /// if the function has a higher dimension than the operator (e.g. in the exchange operator)
1162 /// return only that part of key that corresponds to the particle this operator works on
1163 /// @param[in] key hi-dim key
1164 /// @return a lo-dim part of key; typically first or second half
1165 template<size_t FDIM>
1166 typename std::enable_if<FDIM==NDIM, Key<NDIM> >::type
1167 get_source_key(const Key<FDIM> key) const {
1168 return key;
1169 }
1170
1171 /// apply this operator on a function f
1172
1173 /// the operator does not need to have the same dimension as the function, e,g,
1174 /// the Poisson kernel for the exchange operator acts only on 1 electron of a
1175 /// given (pair) function.
1176 /// @param[in] f a function of same or different dimension as this operator
1177 /// @return the result function of the same dimensionality as the input function f
1178 template <typename T, size_t FDIM>
1180 return madness::apply(*this, f);
1181 }
1182
1183 /// apply this on a vector of functions
1184 template <typename T, size_t FDIM>
1185 std::vector<Function<TENSOR_RESULT_TYPE(T,Q),FDIM>> operator()(const std::vector<Function<T,FDIM>>& f) const {
1186 return madness::apply(*this, f);
1187 }
1188
1189 /// apply this operator on a separable function f(1,2) = f(1) f(2)
1190
1191 /// @param[in] f1 a function of dim LDIM
1192 /// @param[in] f2 a function of dim LDIM
1193 /// @return the result function of dim NDIM=2*LDIM: g(1,2) = G(1,1',2,2') f(1',2')
1194 template <typename T, size_t LDIM>
1195 Function<TENSOR_RESULT_TYPE(T,Q),LDIM+LDIM>
1197 return madness::apply(*this, std::vector<Function<Q,LDIM>>({f1}),
1198 std::vector<Function<Q,LDIM>>({f2}));
1199 }
1200
1201 /// apply this operator on a sum of separable functions f(1,2) = \sum_i f_i(1) f_i(2)
1202
1203 /// @param[in] f1 a function of dim LDIM
1204 /// @param[in] f2 a function of dim LDIM
1205 /// @return the result function of dim NDIM=2*LDIM: g(1,2) = G(1,1',2,2') f(1',2')
1206 template <typename T, size_t LDIM>
1207 Function<TENSOR_RESULT_TYPE(T,Q),LDIM+LDIM>
1208 operator()(const std::vector<Function<T,LDIM>>& f1, const std::vector<Function<Q,LDIM>>& f2) const {
1209 return madness::apply(*this, f1, f2);
1210 }
1211
1212 /// apply this onto another suitable argument, returning the same type
1213
1214 /// argT must implement argT::apply(const SeparatedConvolution& op, const argT& arg)
1215 template<typename argT>
1216 argT operator()(const argT& argument) const {
1217 return madness::apply(*this,argument);
1218 }
1219
1220
1221 /// apply this operator on coefficients in full rank form
1222
1223 /// @param[in] coeff source coeffs in full rank
1224 /// @param[in] source the source key
1225 /// @param[in] shift the displacement, where the source coeffs come from
1226 /// @param[in] tol thresh/#neigh*cnorm
1227 /// @return a tensor of full rank with the result op(coeff)
1228 template <typename T>
1230 const Key<NDIM>& shift,
1231 const Tensor<T>& coeff,
1232 double tol) const {
1233 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
1234 MADNESS_ASSERT(coeff.ndim()==NDIM);
1235
1236 double cpu0=cpu_time();
1237
1238 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
1239 const Tensor<T>* input = &coeff;
1240 Tensor<T> dummy;
1241
1242 if (not modified()) {
1243 if (coeff.dim(0) == k) {
1244 // This processes leaf nodes with only scaling
1245 // coefficients ... FuncImpl::apply by default does not
1246 // apply the operator to these since for smoothing operators
1247 // it is not necessary. It is necessary for operators such
1248 // as differentiation and time evolution and will also occur
1249 // if the application of the operator widens the tree.
1250 dummy = Tensor<T>(v2k);
1251 dummy(s0) = coeff;
1252 input = &dummy;
1253 }
1254 else {
1255 MADNESS_ASSERT(coeff.dim(0)==2*k);
1256 }
1257 }
1258
1259 tol = 0.01*tol/rank; // Error is per separated term
1260 ApplyTerms at;
1261 at.r_term=true;
1262 at.t_term=(source.level()>0);
1263
1264 /// SeparatedConvolutionData keeps data for all terms and all dimensions and 1 displacement
1266
1267 //print("sepop",source,shift,op->norm,tol);
1268
1269 Tensor<resultT> r(v2k), r0(vk);
1270 Tensor<resultT> work1(v2k,false), work2(v2k,false);
1271
1272 if (modified()) {
1274 work1=Tensor<resultT>(vk,false);
1275 work2=Tensor<resultT>(vk,false);
1276 }
1277
1278 const Tensor<T> f0 = copy(coeff(s0));
1279 for (int mu=0; mu<rank; ++mu) {
1280 // SeparatedConvolutionInternal keeps data for 1 term and all dimensions and 1 displacement
1281 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1282 if (muop.norm > tol) {
1283 // ops is of ConvolutionND, returns data for 1 term and all dimensions
1284 Q fac = ops[mu].getfac();
1285 muopxv_fast(at, muop.ops, *input, f0, r, r0, tol/std::abs(fac), fac,
1286 work1, work2);
1287 }
1288 }
1289
1290 r(s0).gaxpy(1.0,r0,1.0);
1291 double cpu1=cpu_time();
1292 timer_full.accumulate(cpu1-cpu0);
1293
1294 return r;
1295 }
1296
1297
1298 /// apply this operator on only 1 particle of the coefficients in low rank form
1299
1300 /// note the unfortunate mess with NDIM: here NDIM is the operator dimension, and FDIM is the
1301 /// function's dimension, whereas in the function we have OPDIM for the operator and NDIM for
1302 /// the function
1303 /// @tparam T the dimension of the function this operator is applied on. \todo MGR: Make sure info on T is correct. Was previously labeled FDIM.
1304 /// @param[in] coeff source coeffs in SVD (=optimal!) form, in high dimensionality (FDIM)
1305 /// @param[in] source the source key in low dimensionality (NDIM)
1306 /// @param[in] shift the displacement in low dimensionality (NDIM)
1307 /// @param[in] tol thresh/(#neigh*cnorm)
1308 /// @param[in] tol2 thresh/#neigh
1309 /// @return coeff result
1310 template<typename T>
1312 const Key<NDIM>& shift, const GenTensor<T>& coeff, double tol, double tol2) const {
1313
1314 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
1315
1316 // prepare access to the singular vectors
1317 const SVDTensor<T>& svdcoeff=coeff.get_svdtensor();
1318// std::vector<Slice> s(coeff.config().dim_per_vector()+1,_);
1319 std::vector<Slice> s(svdcoeff.dim_per_vector(particle()-1)+1,_);
1320 // can't use predefined slices and vectors -- they have the wrong dimension
1321 const std::vector<Slice> s00(coeff.ndim(),Slice(0,k-1));
1322
1323 // some checks
1324 MADNESS_ASSERT(coeff.is_svd_tensor()); // for now
1325 MADNESS_ASSERT(not modified());
1327 MADNESS_ASSERT(coeff.dim(0)==2*k);
1328 MADNESS_ASSERT(2*NDIM==coeff.ndim());
1329
1330 double cpu0=cpu_time();
1332
1333 // some workspace
1334 Tensor<resultT> work1(v2k,false), work2(v2k,false);
1335
1336 // sliced input and final result
1337 const GenTensor<T> f0 = copy(coeff(s00));
1338 GenTensor<resultT> final=copy(coeff);
1339 GenTensor<resultT> final0=copy(f0);
1340
1341 tol = tol/rank*0.01; // Error is per separated term
1342 tol2= tol2/rank;
1343
1344 // the operator norm is missing the identity working on the other particle
1345 // use as (muop.norm*exchange_norm < tol)
1346 // for some reason the screening is not working at all..
1347// double exchange_norm=std::pow(2.0*k,1.5);
1348
1349 for (int r=0; r<coeff.rank(); ++r) {
1350
1351 // get the appropriate singular vector (left or right depends on particle)
1352 // and apply the full tensor muopxv_fast on it, term by term
1353 s[0]=Slice(r,r);
1354 const Tensor<T> chunk=svdcoeff.ref_vector(particle()-1)(s).reshape(v2k);
1355 const Tensor<T> chunk0=f0.get_svdtensor().ref_vector(particle()-1)(s).reshape(vk);
1356// const double weight=std::abs(coeff.config().weights(r));
1357
1358 // accumulate all terms of the operator for a specific term of the function
1359 Tensor<resultT> result(v2k), result0(vk);
1360
1361 ApplyTerms at;
1362 at.r_term=true;
1363 at.t_term=source.level()>0;
1364
1365 // this loop will return on result and result0 the terms [(P+Q) G (P+Q)]_1,
1366 // and [P G P]_1, respectively
1367 for (int mu=0; mu<rank; ++mu) {
1368 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1369 Q fac = ops[mu].getfac();
1370 muopxv_fast(at, muop.ops, chunk, chunk0, result, result0,
1371 tol/std::abs(fac), fac, work1, work2);
1372 }
1373
1374 // reinsert the transformed terms into result, leaving the other particle unchanged
1375 MADNESS_ASSERT(final.get_svdtensor().has_structure());
1376 final.get_svdtensor().ref_vector(particle()-1)(s)=result;
1377
1378 if (source.level()>0) {
1379 final0.get_svdtensor().ref_vector(particle()-1)(s)=result0;
1380 } else {
1381 final0.get_svdtensor().ref_vector(0)(s)=0.0;
1382 final0.get_svdtensor().ref_vector(1)(s)=0.0;
1383 }
1384
1385 }
1386 double cpu1=cpu_time();
1387 timer_low_transf.accumulate(cpu1-cpu0);
1388
1389 double cpu00=cpu_time();
1390
1391 final.reduce_rank(tol2*0.5);
1392 final0.reduce_rank(tol2*0.5);
1393 final(s00)+=final0;
1394 final.reduce_rank(tol2);
1395
1396 double cpu11=cpu_time();
1397 timer_low_accumulate.accumulate(cpu11-cpu00);
1398 return final;
1399 }
1400
1401 /// apply this operator on coefficients in low rank form
1402
1403 /// @param[in] coeff source coeffs in SVD (=optimal!) form
1404 /// @param[in] tol thresh/#neigh*cnorm
1405 /// @param[in] tol2 thresh/#neigh
1406 template <typename T>
1408 const Key<NDIM>& shift,
1409 const GenTensor<T>& coeff,
1410 double tol, double tol2) const {
1412 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
1413
1414 MADNESS_ASSERT(coeff.ndim()==NDIM);
1415 MADNESS_ASSERT(coeff.is_svd_tensor()); // we use the rank below
1416// MADNESS_EXCEPTION("no apply2",1);
1417 const TensorType tt=TT_2D;
1418
1419 const GenTensor<T>* input = &coeff;
1420 GenTensor<T> dummy;
1421
1422 if (not modified()) {
1423 if (coeff.dim(0) == k) {
1424 // This processes leaf nodes with only scaling
1425 // coefficients ... FuncImpl::apply by default does not
1426 // apply the operator to these since for smoothing operators
1427 // it is not necessary. It is necessary for operators such
1428 // as differentiation and time evolution and will also occur
1429 // if the application of the operator widens the tree.
1430 dummy = GenTensor<T>(v2k,TT_2D);
1431 dummy(s0) += coeff;
1432 input = &dummy;
1433 }
1434 else {
1435 MADNESS_ASSERT(coeff.dim(0)==2*k);
1436 }
1437 }
1438
1439 tol = tol/rank; // Error is per separated term
1440 tol2= tol2/rank;
1441
1443
1444 GenTensor<resultT> r, r0, result, result0;
1445 GenTensor<resultT> work1(v2k,tt), work2(v2k,tt);
1446
1447 if (modified()) {
1448 r=GenTensor<resultT>(vk,tt);
1449 work1=GenTensor<resultT>(vk,tt);
1450 work2=GenTensor<resultT>(vk,tt);
1451 }
1452
1453 // collect the results of the individual operator terms
1454 std::list<GenTensor<T> > r_list;
1455 std::list<GenTensor<T> > r0_list;
1456
1457// const GenTensor<T> f0 = copy(coeff(s0));
1458 const GenTensor<T> f0 = copy((*input)(s0));
1459 for (int mu=0; mu<rank; ++mu) {
1460 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1461 //print("muop",source, shift, mu, muop.norm);
1462
1463 // delta(g) < delta(T) * || f ||
1464 if (muop.norm > tol) {
1465
1466 // get maximum rank of coeff to contribute:
1467 // delta(g) < eps < || T || * delta(f)
1468 // delta(coeff) * || T || < tol2
1469 const int r_max=SRConf<T>::max_sigma(tol2/muop.norm,coeff.rank(),coeff.get_svdtensor().weights_);
1470 // print("r_max",coeff.config().weights(r_max));
1471
1472 // note that max_sigma is inclusive!
1473 if (r_max>=0) {
1474 const GenTensor<resultT> chunk=SVDTensor<resultT>(input->get_svdtensor().get_configs(0,r_max));
1475 const GenTensor<resultT> chunk0=SVDTensor<resultT>(f0.get_svdtensor().get_configs(0,r_max));
1476
1477 double cpu0=cpu_time();
1478
1479 Q fac = ops[mu].getfac();
1480 muopxv_fast2(source.level(), muop.ops, chunk, chunk0, r, r0,
1481 tol/std::abs(fac), fac, work1, work2);
1482 double cpu1=cpu_time();
1483 timer_low_transf.accumulate(cpu1-cpu0);
1484
1485 r_list.push_back(r);
1486 r0_list.push_back(r0);
1487 }
1488 }
1489 }
1490
1491 // finally accumulate all the resultant terms into one tensor
1492 double cpu0=cpu_time();
1493
1494 result0=reduce(r0_list,tol2*rank);
1495 if (r_list.size()>0) r_list.front()(s0)+=result0;
1496 result=reduce(r_list,tol2*rank);
1497// result.reduce_rank(tol2*rank);
1498
1499 double cpu1=cpu_time();
1502 return result;
1503 }
1504
1505 /// estimate the ratio of cost of full rank versus low rank
1506
1507 /// @param[in] source source key
1508 /// @param[in] shift displacement
1509 /// @param[in] tol thresh/#neigh/cnorm
1510 /// @param[in] tol2 thresh/#neigh
1511 /// @return cost_ratio r=-1: no terms left
1512 /// 0<r<1: better to do full rank
1513 /// 1<r: better to do low rank
1514 template<typename T>
1516 const Key<NDIM>& shift,
1517 const GenTensor<T>& coeff,
1518 double tol, double tol2) const {
1519
1520 if (coeff.is_full_tensor()) return 0.5;
1521 if (2*NDIM==coeff.ndim()) return 1.5;
1522 MADNESS_ASSERT(NDIM==coeff.ndim());
1524
1526
1527 tol = tol/rank; // Error is per separated term
1528 tol2= tol2/rank;
1529
1530 const double full_operator_cost=pow(coeff.dim(0),NDIM+1);
1531 const double low_operator_cost=pow(coeff.dim(0),NDIM/2+1);
1532 const double low_reduction_cost=pow(coeff.dim(0),NDIM/2);
1533
1534 double full_cost=0.0;
1535 double low_cost=0.0;
1536
1537 long initial_rank=0;
1538 long final_rank=sqrt(coeff.size())*0.05; // size=ncol*nrow; final rank is 5% of max rank
1539
1540 for (int mu=0; mu<rank; ++mu) {
1541 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1542
1543 // delta(g) < delta(T) * || f ||
1544 if (muop.norm > tol) {
1545 // note that max_sigma is inclusive: it returns a slice w(Slice(0,i))
1546 long nterms=SRConf<T>::max_sigma(tol2/muop.norm,coeff.rank(),coeff.get_svdtensor().weights_)+1;
1547
1548 // take only the first overlap computation of rank reduction into account
1549// low_cost+=nterms*low_operator_cost + 2.0*nterms*nterms*low_reduction_cost;
1550 initial_rank+=nterms;
1551
1552 full_cost+=full_operator_cost;
1553 }
1554 }
1555 low_cost=initial_rank*low_operator_cost + initial_rank*final_rank*low_reduction_cost;
1556
1557 // include random empirical factor of 2
1558 double ratio=-1.0;
1559 if (low_cost>0.0) ratio=full_cost/low_cost;
1560// print("nterms, full, low, full/low", full_cost, low_cost,shift.distsq(), ratio);
1561 return ratio;
1562
1563 }
1564
1565 /// construct the tensortrain representation of the operator
1566
1567 /// @param[in] source source coefficient box
1568 /// @param[in] shift displacement
1569 /// @param[in] tol threshold for the TT truncation
1570 /// @param[in] do_R compute the R term of the operator (2k^d)
1571 /// @param[in] do_T compute the T term of the operator (k^d), including factor -1
1572 /// Both do_R and do_T may be used simultaneously, then the final
1573 /// operator will have dimensions (2k^d)
1575 const Key<NDIM>& shift, double tol, bool do_R, bool do_T) const {
1576
1577 if (not (do_R or do_T)) {
1578 print("no operator requested in make_tt_representation??");
1579 MADNESS_EXCEPTION("you're sure you know what you're doing?",1);
1580 }
1581
1582
1584
1585 // check for significant ranks since the R/T matrices' construction
1586 // might have been omitted. Tnorm is always smaller than Rnorm
1587 long lo=0,hi=rank;
1588 for (int mu=0; mu<rank; ++mu) {
1589 double Rnorm=1.0;
1590 for (std::size_t d=0; d<NDIM; ++d) Rnorm *= op->muops[mu].ops[d]->Rnorm;
1591 if (Rnorm>1.e-20) hi=mu;
1592 if ((Rnorm<1.e-20) and (mu<hi)) lo=mu;
1593 }
1594 hi++;lo++;
1595
1596 // think about dimensions
1597 long rank_eff=(hi-lo); // R or T matrices
1598 long step=1;
1599 if (do_R and do_T) { // R and T matrices
1600 rank_eff*=2;
1601 step*=2;
1602 }
1603
1604 long k2k=k; // T matrices
1605 if (do_R) k2k=2*k; // R matrices
1606
1607
1608 // construct empty TT cores and fill them with the significant R/T matrices
1609 std::vector<Tensor<double> > cores(NDIM,Tensor<double>(rank_eff,k2k,k2k,rank_eff));
1610 cores[0]=Tensor<double>(k2k,k2k,rank_eff);
1611 cores[NDIM-1]=Tensor<double>(rank_eff,k2k,k2k);
1612
1613
1614 for (int mu=lo, r=0; mu<hi; ++mu, ++r) {
1615 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1616 const Q fac = ops[mu].getfac();
1617 const Slice sr0(step*r, step*r, 0);
1618 const Slice sr1(step*r+step-1,step*r+step-1,0);
1619 const Slice s00(0,k-1,1);
1620
1621 if (do_R) {
1622 cores[0](_, _ ,sr0)=muop.ops[0]->R;
1623 for (std::size_t idim=1; idim<NDIM-1; ++idim) {
1624 cores[idim](sr0,_ ,_ ,sr0)=muop.ops[idim]->R;
1625 }
1626 cores[NDIM-1](sr0,_ ,_ )=muop.ops[NDIM-1]->R*fac;
1627 }
1628
1629 if (do_T) {
1630 cores[0](s00,s00,sr1)=muop.ops[0]->T;
1631 for (std::size_t idim=1; idim<NDIM-1; ++idim) {
1632 cores[idim](sr1,s00,s00,sr1)=muop.ops[idim]->T;
1633 }
1634 cores[NDIM-1](sr1,s00,s00)=muop.ops[NDIM-1]->T*(-fac);
1635 }
1636 }
1637
1638 // construct TT representation
1639 TensorTrain<double> tt(cores);
1640
1641 // need to reshape for the TT truncation
1642 tt.make_tensor();
1644 tt.make_operator();
1645
1646 return tt;
1647 }
1648
1649
1651 return (combine_OT(left,right).type!=OT_UNDEFINED);
1652 }
1653
1654 /// return operator type and other info of the combined operator (e.g. fg = f(1,2)* g(1,2)
1656 OperatorInfo info=left.info;
1657 if ((left.info.type==OT_F12) and (right.info.type==OT_G12)) {
1659 } else if ((left.info.type==OT_GAUSS) and (right.info.type==OT_GAUSS)) {
1660 info=right.info;
1662 info.mu=2.0*right.info.mu;
1663 } else if ((left.info.type==OT_SLATER) and (right.info.type==OT_SLATER)) {
1664 info=right.info;
1666 info.mu=2.0*right.info.mu;
1667 } else if ((left.info.type==OT_G12) and (right.info.type==OT_F12)) {
1668 info=right.info;
1670 } else if ((left.info.type==OT_G12) and (right.info.type==OT_F212)) {
1671 info=right.info;
1673 } else if (((left.info.type==OT_F212) and (right.info.type==OT_G12)) or
1674 ((left.info.type==OT_F12) and (right.info.type==OT_FG12)) or
1675 ((left.info.type==OT_FG12) and (right.info.type==OT_F12))) {
1676 info=right.info;
1678 if (right.info.type!=OT_G12) MADNESS_CHECK(right.info.mu == left.info.mu);
1679 } else if ((left.info.type==OT_F12) and (right.info.type==OT_F12)) {
1681 // keep the original gamma
1682 // (f12)^2 = (1- slater12)^2 = 1/(4 gamma) (1 - 2 exp(-gamma) + exp(-2 gamma))
1683 MADNESS_CHECK(right.info.mu == left.info.mu);
1684 } else {
1685 MADNESS_EXCEPTION("unknown combination of SeparatedConvolutions: feel free to extend in operator.h",1);
1686 }
1687 return info;
1688 }
1689
1690
1691 /// combine 2 convolution operators to one
1692 /// There's some information loss with this constructor - not recommended
1694 const SeparatedConvolution<Q,NDIM>& right) {
1695 MADNESS_CHECK(can_combine(left,right));
1696 MADNESS_CHECK(left.get_world().id()==right.get_world().id());
1697 MADNESS_CHECK(left.lattice_summed() == right.lattice_summed());
1698 std::array<LatticeRange, NDIM> lattice_summed;
1699 for (std::size_t i = 0; i < NDIM; ++i) {
1700 if (left.lattice_summed()[i]) lattice_summed[i].set_infinite();
1701 }
1702
1703 auto info=combine_OT(left,right);
1705 }
1706
1707 /// combine 2 convolution operators to one
1709 const std::shared_ptr<SeparatedConvolution<Q,NDIM>> right) {
1711 if (left and right) {
1712 return combine(*left, *right);
1713 } else if (left) {
1714 return *left;
1715 } else if (right) {
1716 return *right;
1717 } else {
1718 MADNESS_EXCEPTION("can't combine empty SeparatedConvolutions",1);
1719 }
1720 return result;
1721 }
1722 };
1723
1724
1725
1726 /// Factory function generating separated kernel for convolution with 1/r in 3D.
1727 /// N.B. bloch_k species how the function's phase changes as the **operator** translates,
1728 /// which (by translational invariance) is the additive inverse of how the function's
1729 /// phase changes as the **cell** shifts
1730 static
1731 inline
1733 Vector<double,3> bloch_k,
1734 double lo,
1735 double eps,
1736 const std::array<KernelRange, 3>& kernel_ranges = std::array<KernelRange, 3>(),
1737 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1739 return SeparatedConvolution<double_complex, 3>(world, OperatorInfo(0.0, lo, eps, OT_G12, std::nullopt, kernel_ranges),
1740 lattice_ranges, k, false, bloch_k);
1741 }
1742
1743 /// Factory function generating separated kernel for convolution with 1/r in 3D.
1744 static
1745 inline
1747 double lo,
1748 double eps,
1749 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1751 {
1752 return SeparatedConvolution<double,3>(world,OperatorInfo(0.0,lo,eps,OT_G12),lattice_ranges,k);
1753 }
1754
1755
1756 /// Factory function generating separated kernel for convolution with 1/r in 3D.
1757 static
1758 inline
1760 double lo,
1761 double eps,
1762 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1764 {
1765 return new SeparatedConvolution<double,3>(world,OperatorInfo(0.0,lo,eps,OT_G12),lattice_ranges,k);
1766 }
1767
1768
1769 /// Factory function generating separated kernel for convolution with BSH kernel in general NDIM
1770 template <std::size_t NDIM>
1771 static inline
1772 SeparatedConvolution<double,NDIM>
1773 BSHOperator(World& world, double mu, double lo, double eps,
1774 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1776 if (eps>1.e-4) {
1777 if (world.rank()==0) print("the accuracy in BSHOperator is too small, tighten the threshold",eps);
1778 MADNESS_EXCEPTION("0",1);
1779 }
1780 return SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_BSH),lattice_ranges,k);
1781 }
1782
1783 /// Factory function generating separated kernel for convolution with BSH kernel in general NDIM
1784 template <std::size_t NDIM>
1785 static inline
1786 SeparatedConvolution<double,NDIM>*
1787 BSHOperatorPtr(World& world, double mu, double lo, double eps,
1788 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1790 if (eps>1.e-4) {
1791 if (world.rank()==0) print("the accuracy in BSHOperator is too small, tighten the threshold",eps);
1792 MADNESS_EXCEPTION("0",1);
1793 }
1794 return new SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_BSH),lattice_ranges,k);
1795 }
1796
1797
1798 /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D
1799 static inline SeparatedConvolution<double,3>
1800 BSHOperator3D(World& world, double mu, double lo, double eps,
1801 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1803 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_BSH),lattice_ranges,k);
1804 }
1805
1806 /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D
1807 static
1808 inline
1810 Vector<double,3> bloch_k,
1811 double mu,
1812 double lo,
1813 double eps,
1814 const std::array<KernelRange, 3>& kernel_ranges = std::array<KernelRange, 3>(),
1815 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1817
1818 {
1819 return SeparatedConvolution<double_complex, 3>(world, OperatorInfo(mu, lo, eps, OT_BSH, std::nullopt, kernel_ranges),
1820 lattice_ranges, k, false, bloch_k);
1821 }
1822
1823 /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D
1824 static inline
1826 Vector<double,3> bloch_k,
1827 double mu,
1828 double lo,
1829 double eps,
1830 const std::array<KernelRange, 3>& kernel_ranges = std::array<KernelRange, 3>(),
1831 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1833
1834 {
1835 return new SeparatedConvolution<double_complex, 3>(world, OperatorInfo(mu, lo, eps, OT_BSH, std::nullopt, kernel_ranges),
1836 lattice_ranges, k, false, bloch_k);
1837 }
1838
1839
1840 static inline SeparatedConvolution<double,3>
1841 SlaterF12Operator(World& world, double mu, double lo, double eps,
1842 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1844 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F12),lattice_ranges,k);
1845 }
1846
1848 double mu, double lo, double eps,
1849 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1851 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F212),lattice_ranges,k);
1852 }
1853
1855 double mu, double lo, double eps,
1856 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1858 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F212),lattice_ranges,k);
1859 }
1860
1861 /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D
1862 template<std::size_t NDIM=3>
1864 double mu, double lo, double eps,
1865 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1867 return SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_SLATER),lattice_ranges,k);
1868 }
1869
1870 /// Factory function generating separated kernel for convolution with exp(-mu*r*r)
1871
1872 /// lo and eps are not used here
1873 template<std::size_t NDIM>
1875 double mu, double lo=0.0, double eps=0.0,
1879 }
1880
1881 /// Factory function generating separated kernel for convolution with exp(-mu*r*r) in 3D
1882
1883 /// lo and eps are not used here
1884 template<std::size_t NDIM>
1886 double mu, double lo=0.0, double eps=0.0,
1890 }
1891
1892
1893 /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D
1894 /// Note that the 1/(2mu) factor of SlaterF12Operator is not included, this is just the exponential function
1895 template<std::size_t NDIM>
1897 double mu, double lo, double eps,
1901 }
1902
1903 /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D
1904 /// Note that the 1/(2mu) factor of SlaterF12Operator is not included, this is just the exponential function
1906 double mu, double lo, double eps,
1907 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1908 int k = FunctionDefaults<3>::get_k()) {
1909 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_SLATER),lattice_ranges,k);
1910 }
1911
1912 /// Factory function generating separated kernel for convolution with (1 - exp(-mu*r))/(2 mu) in 3D
1913
1914 /// includes the factor 1/(2 mu)
1916 double mu, double lo, double eps,
1917 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1919 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F12),lattice_ranges,k);
1920 }
1921
1922
1923 /// Factory function generating separated kernel for convolution with 1/(2 mu)*(1 - exp(-mu*r))/r in 3D
1924
1925 /// fg = (1 - exp(-gamma r12)) / r12 = 1/r12 - exp(-gamma r12)/r12 = coulomb - bsh
1926 /// includes the factor 1/(2 mu)
1927 static inline SeparatedConvolution<double,3>
1928 FGOperator(World& world, double mu, double lo, double eps,
1929 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1931 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_FG12),lattice_ranges,k);
1932 }
1933
1934 /// Factory function generating separated kernel for convolution with 1/(2 mu)*(1 - exp(-mu*r))/r in 3D
1935
1936 /// fg = (1 - exp(-gamma r12)) / r12 = 1/r12 - exp(-gamma r12)/r12 = coulomb - bsh
1937 /// includes the factor 1/(2 mu)
1938 static inline SeparatedConvolution<double,3>*
1939 FGOperatorPtr(World& world, double mu, double lo, double eps,
1940 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1942 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_FG12),lattice_ranges,k);
1943 }
1944
1945 /// Factory function generating separated kernel for convolution with (1/(2 mu)*(1 - exp(-mu*r)))^2/r in 3D
1946
1947 /// f2g = (1/(2 gamma) (1 - exp(-gamma r12)))^2 / r12
1948 /// = 1/(4 gamma) * [ 1/r12 - 2 exp(-gamma r12)/r12 + exp(-2 gamma r12)/r12 ]
1949 /// includes the factor 1/(2 mu)^2
1950 static inline SeparatedConvolution<double,3>*
1951 F2GOperatorPtr(World& world, double mu, double lo, double eps,
1952 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1954 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F2G12),lattice_ranges,k);
1955 }
1956
1957 /// Factory function generating separated kernel for convolution with (1/(2 mu)*(1 - exp(-mu*r)))^2/r in 3D
1958
1959 /// f2g = (1/(2 gamma) (1 - exp(-gamma r12)))^2 / r12
1960 /// = 1/(4 gamma) * [ 1/r12 - 2 exp(-gamma r12)/r12 + exp(-2 gamma r12)/r12 ]
1961 /// includes the factor 1/(2 mu)^2
1962 static inline SeparatedConvolution<double,3>
1963 F2GOperator(World& world, double mu, double lo, double eps,
1964 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1966 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F2G12),lattice_ranges,k);
1967 }
1968
1969
1970 /// Factory function generating separated kernel for convolution a normalized
1971 /// Gaussian (aka a widened delta function)
1973 double eps,
1974 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1976
1977 double exponent = 1.0/(2.0*eps);
1978 Tensor<double> coeffs(1), exponents(1);
1979 exponents(0L) = exponent;
1980 coeffs(0L)=pow(exponent/M_PI,0.5*3.0); // norm of the gaussian
1981 return SeparatedConvolution<double,3>(world, coeffs, exponents, 1.e-8, eps, lattice_ranges, k);
1982 }
1983
1984 /// Factory function generating separated kernel for convolution a normalized
1985 /// Gaussian (aka a widened delta function)
1986 template<std::size_t NDIM>
1988 double eps,
1989 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1991
1992 double exponent = 1.0/(2.0*eps);
1993 Tensor<double> coeffs(1), exponents(1);
1994 exponents(0L) = exponent;
1995 coeffs(0L)=pow(exponent/M_PI,0.5*NDIM); // norm of the gaussian
1996 return SeparatedConvolution<double,NDIM>(world, coeffs, exponents, 1.e-8, eps, lattice_ranges, k);
1997 }
1998
1999 /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D
2000 static
2001 inline
2003 double mu,
2004 double lo,
2005 double eps,
2006 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
2009 double hi = cell_width.normf(); // Diagonal width of cell
2010 // Extend kernel range for lattice summation
2011 // N.B. if have periodic boundaries, extend range just in case will be using periodic domain
2012 const auto lattice_summed_any = std::any_of(lattice_ranges.begin(), lattice_ranges.end(), [](const auto& b) { return static_cast<bool>(b);});
2013 const auto infinite_any = std::any_of(lattice_ranges.begin(), lattice_ranges.end(), [](const auto& b) { return b.infinite();});
2014 if (lattice_summed_any) {
2015 hi *= 100;
2016 }
2017
2018 GFit<double, 3> fit = GFit<double, 3>::BSHFit(mu, lo, hi, eps, false);
2019 Tensor<double> coeff = fit.coeffs();
2020 Tensor<double> expnt = fit.exponents();
2021
2022 if (infinite_any) {
2023 // convolution with Gaussians of exponents <= 0.25/(L^2) contribute only a constant shift
2024 // the largest spacing along lattice summed axes thus controls the smallest Gaussian exponent that NEEDS to be included
2025 double max_lattice_spacing = 0;
2026 for(int d=0; d!=3; ++d) {
2027 if (lattice_ranges[d])
2028 max_lattice_spacing =
2029 std::max(max_lattice_spacing, cell_width(d));
2030 }
2031 // WARNING: discardG0 = true ignores the coefficients of truncated
2032 // terms
2033 fit.truncate_periodic_expansion(coeff, expnt, max_lattice_spacing,
2034 /* discardG0 = */ false);
2035 }
2036 return new SeparatedConvolution<double, 3>(world, coeff, expnt, lo, eps,
2037 lattice_ranges, k);
2038 }
2039
2040
2041 /// Factory function generating operator for convolution with grad(1/r) in 3D
2042
2043 /// Returns a 3-vector containing the convolution operator for the
2044 /// x, y, and z components of grad(1/r)
2045 static
2046 inline
2047 std::vector< std::shared_ptr< SeparatedConvolution<double,3> > >
2049 double lo,
2050 double eps,
2051 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
2054 typedef std::shared_ptr<real_convolution_3d> real_convolution_3d_ptr;
2055 const double pi = constants::pi;
2057 double hi = width.normf(); // Diagonal width of cell
2058 // Extend kernel range for lattice summation
2059 const auto lattice_sum_any = std::any_of(lattice_ranges.begin(), lattice_ranges.end(), [](const LatticeRange& b){ return static_cast<bool>(b); });
2060 if (lattice_sum_any) {
2061 hi *= 100;
2062 }
2063
2065 Tensor<double> coeff = fit.coeffs();
2066 Tensor<double> expnt = fit.exponents();
2067
2068 if (lattice_sum_any) {
2069 fit.truncate_periodic_expansion(coeff, expnt, width.max(), true);
2070 }
2071
2072 int rank = coeff.dim(0);
2073
2074 std::vector<real_convolution_3d_ptr> gradG(3);
2075
2076 for (int dir = 0; dir < 3; dir++) {
2077 std::vector<ConvolutionND<double, 3>> ops(rank);
2078 for (int mu = 0; mu < rank; mu++) {
2079 // We cache the normalized operator so the factor is the value we must multiply by to recover the coeff we want.
2080 double c = std::pow(sqrt(expnt(mu) / pi), 3); // Normalization coeff
2081 ops[mu].setfac(coeff(mu) / c / width[dir]);
2082
2083 for (int d = 0; d < 3; d++) {
2084 if (d != dir)
2086 k, expnt(mu) * width[d] * width[d], 0,
2087 lattice_ranges[d]));
2088 }
2090 k, expnt(mu) * width[dir] * width[dir], 1,
2091 lattice_ranges[dir]));
2092 }
2094 new SeparatedConvolution<double, 3>(world, ops));
2095 }
2096
2097 return gradG;
2098 }
2099
2100 /// Factory function generating operator for convolution with grad(bsh) in 3D
2101
2102 /// Returns a 3-vector containing the convolution operator for the
2103 /// x, y, and z components of grad(bsh)
2104 static
2105 inline
2106 std::vector< std::shared_ptr< SeparatedConvolution<double,3> > >
2108 double mu,
2109 double lo,
2110 double eps,
2111 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
2114 typedef std::shared_ptr<real_convolution_3d> real_convolution_3d_ptr;
2115 const double pi = constants::pi;
2117 double hi = width.normf(); // Diagonal width of cell
2118 // Extend kernel range for lattice summation
2119 bool lattice_sum_any = std::any_of(lattice_ranges.begin(), lattice_ranges.end(), [](const LatticeRange& b){ return b.get_range(); });
2120 if (lattice_sum_any) {
2121 hi *= 100;
2122 }
2123
2124 GFit<double, 3> fit = GFit<double, 3>::BSHFit(mu, lo, hi, eps, false);
2125 Tensor<double> coeff = fit.coeffs();
2126 Tensor<double> expnt = fit.exponents();
2127
2128 if (lattice_sum_any) {
2129 fit.truncate_periodic_expansion(coeff, expnt, width.max(), true);
2130 }
2131
2132 int rank = coeff.dim(0);
2133
2134 std::vector<real_convolution_3d_ptr> gradG(3);
2135
2136 for (int dir = 0; dir < 3; dir++) {
2137 std::vector<ConvolutionND<double, 3>> ops(rank);
2138 for (int mu = 0; mu < rank; mu++) {
2139 // We cache the normalized operator so the factor is the value we must multiply by to recover the coeff we want.
2140 double c = std::pow(sqrt(expnt(mu) / pi), 3); // Normalization coeff
2141 ops[mu].setfac(coeff(mu) / c / width[dir]);
2142
2143 for (int d = 0; d < 3; d++) {
2144 if (d != dir)
2146 k, expnt(mu) * width[d] * width[d], 0,
2147 lattice_ranges[d]));
2148 }
2150 k, expnt(mu) * width[dir] * width[dir], 1,
2151 lattice_ranges[dir]));
2152 }
2154 new SeparatedConvolution<double, 3>(world, ops));
2155 }
2156
2157 return gradG;
2158 }
2159
2160
2161
2162 namespace archive {
2163 template <class Archive, class T, std::size_t NDIM>
2164 struct ArchiveLoadImpl<Archive,const SeparatedConvolution<T,NDIM>*> {
2165 static inline void load(const Archive& ar, const SeparatedConvolution<T,NDIM>*& ptr) {
2167 ar & p;
2168 ptr = static_cast< const SeparatedConvolution<T,NDIM>* >(p);
2169 }
2170 };
2171
2172 template <class Archive, class T, std::size_t NDIM>
2174 static inline void store(const Archive& ar, const SeparatedConvolution<T,NDIM>*const& ptr) {
2175 ar & static_cast< const WorldObject< SeparatedConvolution<T,NDIM> >* >(ptr);
2176 }
2177 };
2178 }
2179
2180}
2181
2182
2183
2184
2185#endif // MADNESS_MRA_OPERATOR_H__INCLUDED
double q(double t)
Definition DKops.h:18
Provides routines for internal use optimized for aligned data.
long dim(int i) const
Returns the size of dimension i.
Definition basetensor.h:147
long ndim() const
Returns the number of dimensions in the tensor.
Definition basetensor.h:144
Provides the common functionality/interface of all 1D convolutions.
Definition convolution1d.h:259
Array of 1D convolutions (one / dimension)
Definition convolution1d.h:585
Holds displacements for applying operators to avoid replicating for all operators.
Definition displacements.h:64
const std::vector< Key< NDIM > > & get_disp(Level n, const array_of_bools< NDIM > &kernel_lattice_sum_axes)
Definition displacements.h:224
FunctionCommonData holds all Function data common for given k.
Definition function_common_data.h:52
Tensor< double > h0
Definition function_common_data.h:105
Tensor< double > h1
Definition function_common_data.h:105
FunctionDefaults holds default paramaters as static class members.
Definition funcdefaults.h:100
static const Tensor< double > & get_cell_width()
Returns the width of each user cell dimension.
Definition funcdefaults.h:370
A multiresolution adaptive numerical function.
Definition mra.h:139
Definition gfit.h:57
static GFit BSHFit(double mu, double lo, double hi, double eps, bool prnt=false)
return a fit for the bound-state Helmholtz function
Definition gfit.h:117
static GFit CoulombFit(double lo, double hi, double eps, bool prnt=false)
return a fit for the Coulomb function
Definition gfit.h:102
Definition lowranktensor.h:59
long dim(const int i) const
return the number of entries in dimension i
Definition lowranktensor.h:391
long ndim() const
Definition lowranktensor.h:386
constexpr bool is_full_tensor() const
Definition gentensor.h:224
void reduce_rank(const double &eps)
Definition gentensor.h:217
long rank() const
Definition gentensor.h:212
long size() const
Definition lowranktensor.h:482
SVDTensor< T > & get_svdtensor()
Definition gentensor.h:228
const BaseTensor * ptr() const
might return a NULL pointer!
Definition lowranktensor.h:709
IsSupported< TensorTypeData< Q >, GenTensor< T > & >::type scale(Q fac)
Inplace multiplication by scalar of supported type (legacy name)
Definition lowranktensor.h:426
constexpr bool is_svd_tensor() const
Definition gentensor.h:222
Key is the index for a node of the 2^NDIM-tree.
Definition key.h:69
Key< NDIM+LDIM > merge_with(const Key< LDIM > &rhs) const
merge with other key (ie concatenate), use level of rhs, not of this
Definition key.h:406
const Vector< Translation, NDIM > & translation() const
Definition key.h:173
void break_apart(Key< LDIM > &key1, Key< KDIM > &key2) const
break key into two low-dimensional keys
Definition key.h:343
Denotes lattice summation over range [-N, N]; N=0 is equivalent to including the simulation cell only...
Definition kernelrange.h:17
Tensor< T > & ref_vector(const unsigned int &idim)
return reference to one of the vectors F
Definition srconf.h:530
int dim_per_vector(int idim) const
return the number of physical dimensions
Definition srconf.h:665
static int max_sigma(const double &thresh, const long &rank, const Tensor< double > &w)
Definition srconf.h:109
Definition SVDTensor.h:42
Convolutions in separated form (including Gaussian)
Definition operator.h:139
SeparatedConvolution(World &world, const Tensor< Q > &coeff, const Tensor< double > &expnt, double lo, double thresh, const std::array< LatticeRange, NDIM > &lattice_ranges=FunctionDefaults< NDIM >::get_bc().lattice_range(), int k=FunctionDefaults< NDIM >::get_k(), bool doleaves=false, double mu=0.0)
Constructor for Gaussian Convolutions (mostly for backward compatability)
Definition operator.h:1061
Timer timer_low_transf
Definition operator.h:165
bool destructive_
destroy the argument or restore it (expensive for 6d functions)
Definition operator.h:159
GenTensor< TENSOR_RESULT_TYPE(T, Q)> apply2(const Key< NDIM > &source, const Key< NDIM > &shift, const GenTensor< T > &coeff, double tol, double tol2) const
apply this operator on coefficients in low rank form
Definition operator.h:1407
std::array< KernelRange, NDIM > range
kernel range is along axis d is limited by range[d] if it's nonnull
Definition operator.h:154
const array_of_bools< NDIM > & lattice_summed() const
Definition operator.h:1126
int particle_
must only be 1 or 2
Definition operator.h:158
void muopxv_fast2(Level n, const ConvolutionData1D< Q > *const ops_1d[NDIM], const GenTensor< T > &f, const GenTensor< T > &f0, GenTensor< TENSOR_RESULT_TYPE(T, Q)> &result, GenTensor< TENSOR_RESULT_TYPE(T, Q)> &result0, double tol, const Q mufac, GenTensor< TENSOR_RESULT_TYPE(T, Q)> &work1, GenTensor< TENSOR_RESULT_TYPE(T, Q)> &work2) const
Apply one of the separated terms, accumulating into the result.
Definition operator.h:558
const double & gamma() const
Definition operator.h:200
GenTensor< TENSOR_RESULT_TYPE(T, Q)> apply2_lowdim(const Key< NDIM > &source, const Key< NDIM > &shift, const GenTensor< T > &coeff, double tol, double tol2) const
apply this operator on only 1 particle of the coefficients in low rank form
Definition operator.h:1311
std::vector< ConvolutionND< Q, NDIM > > ops
ConvolutionND keeps data for 1 term, all dimensions, 1 displacement.
Definition operator.h:172
Function< TENSOR_RESULT_TYPE(T, Q), LDIM+LDIM > operator()(const Function< T, LDIM > &f1, const Function< Q, LDIM > &f2) const
apply this operator on a separable function f(1,2) = f(1) f(2)
Definition operator.h:1196
const SeparatedConvolutionData< Q, NDIM > * getop(Level n, const Key< NDIM > &d, const Key< NDIM > &source) const
get the data for all terms and all dimensions for one displacement
Definition operator.h:805
void set_domain_periodicity(const array_of_bools< NDIM > &domain_is_periodic)
Definition operator.h:1132
const double & mu() const
Definition operator.h:201
double munorm2(Level n, const ConvolutionData1D< Q > *ops[]) const
Definition operator.h:645
const bool & destructive() const
Definition operator.h:198
Timer timer_stats_accumulate
Definition operator.h:167
SimpleCache< SeparatedConvolutionData< Q, NDIM >, NDIM > data
cache for all terms, dims and displacements
Definition operator.h:181
std::enable_if< FDIM!=NDIM, Key< NDIM > >::type get_source_key(const Key< FDIM > key) const
return that part of a hi-dim key that serves as the base for displacements of this operator
Definition operator.h:1150
double munorm2_ns(Level n, const ConvolutionData1D< Q > *ops[]) const
Definition operator.h:653
std::enable_if< FDIM==NDIM, Key< NDIM > >::type get_source_key(const Key< FDIM > key) const
return that part of a hi-dim key that serves as the base for displacements of this operator
Definition operator.h:1167
virtual ~SeparatedConvolution()
Definition operator.h:1103
void muopxv_fast(ApplyTerms at, const ConvolutionData1D< Q > *const ops_1d[NDIM], const Tensor< T > &f, const Tensor< T > &f0, Tensor< TENSOR_RESULT_TYPE(T, Q)> &result, Tensor< TENSOR_RESULT_TYPE(T, Q)> &result0, const double tol, const Q mufac, Tensor< TENSOR_RESULT_TYPE(T, Q)> &work1, Tensor< TENSOR_RESULT_TYPE(T, Q)> &work2) const
Apply one of the separated terms, accumulating into the result.
Definition operator.h:447
SimpleCache< SeparatedConvolutionData< Q, NDIM >, 2 *NDIM > mod_data
cache for all terms, dims and displacements
Definition operator.h:182
argT operator()(const argT &argument) const
apply this onto another suitable argument, returning the same type
Definition operator.h:1216
Timer timer_full
Definition operator.h:164
const array_of_bools< NDIM > & func_domain_is_periodic() const
Definition operator.h:1129
SeparatedConvolution< Q, NDIM > & set_particle(const int p)
Definition operator.h:191
SeparatedConvolution(World &world, const std::vector< std::shared_ptr< Convolution1D< Q > > > &argops, long k=FunctionDefaults< NDIM >::get_k(), bool doleaves=false)
Definition operator.h:988
Function< TENSOR_RESULT_TYPE(T, Q), LDIM+LDIM > operator()(const std::vector< Function< T, LDIM > > &f1, const std::vector< Function< Q, LDIM > > &f2) const
apply this operator on a sum of separable functions f(1,2) = \sum_i f_i(1) f_i(2)
Definition operator.h:1208
void init_lattice_summed()
Definition operator.h:973
Q opT
The apply function uses this to infer resultT=opT*inputT.
Definition operator.h:142
void initialize(const Tensor< Q > &coeff, const Tensor< double > &expnt, std::array< LatticeRange, NDIM > lattice_range, std::array< KernelRange, NDIM > range={}, const Vector< double, NDIM > &bloch_k=Vector< double, NDIM >(0.0))
Definition operator.h:1085
const SeparatedConvolutionInternal< Q, NDIM > getmuop(int mu, Level n, const Key< NDIM > &disp) const
get the transformation matrices for 1 term and all dimensions and one displacement
Definition operator.h:749
const SeparatedConvolutionData< Q, NDIM > * getop_ns(Level n, const Key< NDIM > &d) const
get the data for all terms and all dimensions for one displacement
Definition operator.h:819
const std::vector< long > v2k
Definition operator.h:177
const std::array< KernelRange, NDIM > & get_range() const
Definition operator.h:205
int get_rank() const
Definition operator.h:202
Function< TENSOR_RESULT_TYPE(T, Q), FDIM > operator()(const Function< T, FDIM > &f) const
apply this operator on a function f
Definition operator.h:1179
bool doleaves
If should be applied to leaf coefficients ... false by default.
Definition operator.h:146
void print_timer() const
Definition operator.h:1105
SeparatedConvolution(World &world, const std::vector< ConvolutionND< Q, NDIM > > &argops, long k=FunctionDefaults< NDIM >::get_k(), bool doleaves=false)
Definition operator.h:1017
const std::vector< Key< NDIM > > & get_disp(Level n) const
Definition operator.h:1121
void apply_transformation3(const Tensor< T > trans2[NDIM], const Tensor< T > &f, const Q mufac, Tensor< R > &result) const
accumulate into result
Definition operator.h:370
static SeparatedConvolution< Q, NDIM > combine(const SeparatedConvolution< Q, NDIM > &left, const SeparatedConvolution< Q, NDIM > &right)
Definition operator.h:1693
const std::vector< long > vk
Definition operator.h:176
double norm(Level n, const Key< NDIM > &d, const Key< NDIM > &source_key) const
return the operator norm for all terms, all dimensions and 1 displacement
Definition operator.h:1135
TensorTrain< double > make_tt_representation(const Key< NDIM > &source, const Key< NDIM > &shift, double tol, bool do_R, bool do_T) const
construct the tensortrain representation of the operator
Definition operator.h:1574
void reset_timer() const
Definition operator.h:1113
static OperatorInfo combine_OT(const SeparatedConvolution< Q, NDIM > &left, const SeparatedConvolution< Q, NDIM > &right)
return operator type and other info of the combined operator (e.g. fg = f(1,2)* g(1,...
Definition operator.h:1655
GenTensor< T > upsample(const Key< FDIM > &key, const GenTensor< T > &coeff) const
upsample the sum coefficients of level 1 to sum coeffs on level n+1
Definition operator.h:943
bool print_timings
Definition operator.h:160
Timer timer_low_accumulate
Definition operator.h:166
double estimate_costs(const Key< NDIM > &source, const Key< NDIM > &shift, const GenTensor< T > &coeff, double tol, double tol2) const
estimate the ratio of cost of full rank versus low rank
Definition operator.h:1515
bool range_restricted() const
Definition operator.h:206
int get_k() const
Definition operator.h:203
Tensor< TENSOR_RESULT_TYPE(T, Q)> apply(const Key< NDIM > &source, const Key< NDIM > &shift, const Tensor< T > &coeff, double tol) const
apply this operator on coefficients in full rank form
Definition operator.h:1229
const std::vector< Slice > s0
Definition operator.h:178
array_of_bools< NDIM > lattice_summed_
Definition operator.h:150
void apply_transformation2(Level n, long dimk, double tol, const Tensor< T > trans2[NDIM], const GenTensor< T > &f, GenTensor< R > &work1, GenTensor< R > &work2, const Q mufac, GenTensor< R > &result) const
don't accumulate, since we want to do this at apply()
Definition operator.h:387
const int & particle() const
Definition operator.h:190
std::vector< Function< TENSOR_RESULT_TYPE(T, Q), FDIM > > operator()(const std::vector< Function< T, FDIM > > &f) const
apply this on a vector of functions
Definition operator.h:1185
const bool & modified() const
Definition operator.h:187
const FunctionCommonData< Q, NDIM > & cdata
Definition operator.h:174
bool & modified()
Definition operator.h:186
const int k
Definition operator.h:173
friend SeparatedConvolution< Q, NDIM > combine(const std::shared_ptr< SeparatedConvolution< Q, NDIM > > left, const std::shared_ptr< SeparatedConvolution< Q, NDIM > > right)
combine 2 convolution operators to one
Definition operator.h:1708
OperatorInfo info
Definition operator.h:144
Key< NDIM > keyT
Definition operator.h:162
void init_range()
Definition operator.h:960
static const size_t opdim
Definition operator.h:163
bool & destructive()
Definition operator.h:197
void apply_transformation(long dimk, const Transformation trans[NDIM], const Tensor< T > &f, Tensor< R > &work1, Tensor< R > &work2, const Q mufac, Tensor< R > &result) const
Definition operator.h:307
static std::pair< Tensor< double >, Tensor< double > > make_coeff_for_operator(World &world, OperatorInfo &info, const std::array< LatticeRange, NDIM > &lattice_ranges)
Definition operator.h:226
void check_cubic()
Definition operator.h:882
bool modified_
use modified NS form
Definition operator.h:157
int rank
Definition operator.h:175
SeparatedConvolution(World &world, const OperatorInfo info1, const std::array< LatticeRange, NDIM > &lattice_ranges=FunctionDefaults< NDIM >::get_bc().lattice_range(), int k=FunctionDefaults< NDIM >::get_k(), bool doleaves=false, const Vector< double, NDIM > &bloch_k=Vector< double, NDIM >(0.0))
Definition operator.h:1043
GenTensor< T > partial_upsample(const Key< FDIM > &key, const GenTensor< T > &coeff, const int particle) const
upsample some of the dimensions of coeff to its child indicated by key
Definition operator.h:900
double munorm2_modified(Level n, const ConvolutionData1D< Q > *ops_1d[]) const
Definition operator.h:686
int & particle()
Definition operator.h:189
static bool can_combine(const SeparatedConvolution< Q, NDIM > &left, const SeparatedConvolution< Q, NDIM > &right)
Definition operator.h:1650
const std::vector< ConvolutionND< Q, NDIM > > & get_ops() const
Definition operator.h:204
const SeparatedConvolutionData< Q, NDIM > * getop_modified(Level n, const Key< NDIM > &disp, const Key< NDIM > &source) const
get the data for all terms and all dimensions for one displacement (modified NS form)
Definition operator.h:853
array_of_bools< NDIM > func_domain_is_periodic_
ignore periodicity of BC when applying this to function
Definition operator.h:152
const SeparatedConvolutionInternal< Q, NDIM > getmuop_modified(int mu, Level n, const Key< NDIM > &disp, const Key< NDIM > &source) const
get the transformation matrices for 1 term and all dimensions and one displacement
Definition operator.h:778
Simplified interface around hash_map to cache stuff for 1D.
Definition simplecache.h:46
A slice defines a sub-range or patch of a dimension.
Definition slice.h:103
Definition tensortrain.h:123
std::enable_if<!std::is_arithmetic< R >::value, void >::type truncate(double eps)
recompress and truncate this TT representation
Definition tensortrain.h:883
TensorTrain< T > & make_operator()
convert this into an operator representation (r,k',k,r)
Definition tensortrain.h:1188
TensorTrain< T > & make_tensor()
convert this into a tensor representation (r,k,r)
Definition tensortrain.h:1176
A tensor is a multidimensional array.
Definition tensor.h:317
float_scalar_type normf() const
Returns the Frobenius norm of the tensor.
Definition tensor.h:1726
T * ptr()
Returns a pointer to the internal data.
Definition tensor.h:1840
IsSupported< TensorTypeData< Q >, Tensor< T > & >::type scale(Q x)
Inplace multiplication by scalar of supported type (legacy name)
Definition tensor.h:686
T max(long *ind=0) const
Return the maximum value (and if ind is non-null, its index) in the Tensor.
Definition tensor.h:1703
Definition function_common_data.h:169
void print(std::string line="") const
print timer
Definition function_common_data.h:216
void accumulate(const double time) const
accumulate timer
Definition function_common_data.h:183
void reset() const
Definition function_common_data.h:210
A simple, fixed dimension vector.
Definition vector.h:64
Implements most parts of a globally addressable object (via unique ID).
Definition world_object.h:366
World & get_world() const
Returns a reference to the world.
Definition world_object.h:719
World & world
The World this object belongs to. (Think globally, act locally).
Definition world_object.h:383
void process_pending()
To be called from derived constructor to process pending messages.
Definition world_object.h:658
A parallel world class.
Definition world.h:132
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition world.h:320
unsigned long id() const
Definition world.h:315
syntactic sugar for std::array<bool, N>
Definition array_of_bools.h:19
Defines common mathematical and physical constants.
Computes most matrix elements over 1D operators (including Gaussians)
static const double R
Definition csqrt.cc:46
double(* f1)(const coord_3d &)
Definition derivatives.cc:55
char * p(char *buf, const char *name, int k, int initial_level, double thresh, int order)
Definition derivatives.cc:72
double(* f2)(const coord_3d &)
Definition derivatives.cc:56
static double lo
Definition dirac-hatom.cc:23
static double shift
Definition dirac-hatom.cc:19
fit isotropic functions to a set of Gaussians with controlled precision
auto T(World &world, response_space &f) -> response_space
Definition global_functions.cc:28
static const double v
Definition hatom_sf_dirac.cc:20
Tensor< double > op(const Tensor< double > &x)
Definition kain.cc:508
static double pow(const double *a, const double *b)
Definition lda.h:74
#define max(a, b)
Definition lda.h:51
#define MADNESS_CHECK(condition)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:182
#define MADNESS_EXCEPTION(msg, value)
Macro for throwing a MADNESS exception.
Definition madness_exception.h:119
#define MADNESS_ASSERT(condition)
Assert a condition that should be free of side-effects since in release builds this might be a no-op.
Definition madness_exception.h:134
constexpr double pi
Mathematical constant .
Definition constants.h:48
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:10
static SeparatedConvolution< double, 3 > SlaterF12Operator(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Definition operator.h:1841
array_of_bools< NDIM > lattice_sum()
Definition bc.h:248
static SeparatedConvolution< double_complex, 3 > PeriodicBSHOperator3D(World &world, Vector< double, 3 > bloch_k, double mu, double lo, double eps, const std::array< KernelRange, 3 > &kernel_ranges=std::array< KernelRange, 3 >(), const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D.
Definition operator.h:1809
static SeparatedConvolution< double, NDIM > * GaussOperatorPtr(World &world, double mu, double lo=0.0, double eps=0.0, const array_of_bools< NDIM > &lattice_sum=FunctionDefaults< NDIM >::get_bc().is_periodic(), int k=FunctionDefaults< NDIM >::get_k())
Factory function generating separated kernel for convolution with exp(-mu*r*r) in 3D.
Definition operator.h:1885
std::shared_ptr< real_convolution_3d > real_convolution_3d_ptr
Definition functypedefs.h:150
static double cpu_time()
Returns the cpu time in seconds relative to an arbitrary origin.
Definition timers.h:127
SeparatedConvolution< double, 3 > real_convolution_3d
Definition functypedefs.h:136
GenTensor< TENSOR_RESULT_TYPE(R, Q)> general_transform(const GenTensor< R > &t, const Tensor< Q > c[])
Definition gentensor.h:274
void fast_transpose(long n, long m, const T *a, T *MADNESS_RESTRICT b)
a(n,m) --> b(m,n) ... optimized for smallish matrices
Definition convolution1d.h:71
static SeparatedConvolution< double, NDIM > SmoothingOperator(World &world, double eps, const std::array< LatticeRange, NDIM > &lattice_ranges=FunctionDefaults< NDIM >::get_bc().lattice_range(), int k=FunctionDefaults< NDIM >::get_k())
Definition operator.h:1987
static SeparatedConvolution< double, 3 > F2GOperator(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating separated kernel for convolution with (1/(2 mu)*(1 - exp(-mu*r)))^2/r in ...
Definition operator.h:1963
static SeparatedConvolution< double, 3 > CoulombOperator(World &world, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating separated kernel for convolution with 1/r in 3D.
Definition operator.h:1746
static SeparatedConvolution< double, NDIM > * BSHOperatorPtr(World &world, double mu, double lo, double eps, const std::array< LatticeRange, NDIM > &lattice_ranges=FunctionDefaults< NDIM >::get_bc().lattice_range(), int k=FunctionDefaults< NDIM >::get_k())
Factory function generating separated kernel for convolution with BSH kernel in general NDIM.
Definition operator.h:1787
static SeparatedConvolution< double, NDIM > GaussOperator(World &world, double mu, double lo=0.0, double eps=0.0, const array_of_bools< NDIM > &lattice_sum=FunctionDefaults< NDIM >::get_bc().is_periodic(), int k=FunctionDefaults< NDIM >::get_k())
Factory function generating separated kernel for convolution with exp(-mu*r*r)
Definition operator.h:1874
static SeparatedConvolution< double, 3 > * F2GOperatorPtr(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating separated kernel for convolution with (1/(2 mu)*(1 - exp(-mu*r)))^2/r in ...
Definition operator.h:1951
int64_t Translation
Definition key.h:57
static SeparatedConvolution< double, 3 > * SlaterOperatorPtr(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Definition operator.h:1905
static SeparatedConvolution< double, 3 > SlaterF12sqOperator(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Definition operator.h:1847
static SeparatedConvolution< double, 3 > SmoothingOperator3D(World &world, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Definition operator.h:1972
void mTxmq_padding(long dimi, long dimj, long dimk, long ext_b, cT *c, const aT *a, const bT *b)
Definition mtxmq.h:96
static const Slice _(0,-1, 1)
static SeparatedConvolution< double, 3 > * SlaterF12OperatorPtr(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating separated kernel for convolution with (1 - exp(-mu*r))/(2 mu) in 3D.
Definition operator.h:1915
int Level
Definition key.h:58
@ OT_FG12
1-exp(-r)
Definition operatorinfo.h:18
@ OT_SLATER
1/r
Definition operatorinfo.h:15
@ OT_GAUSS
exp(-r)
Definition operatorinfo.h:16
@ OT_BSH
(1-exp(-r))^2/r = 1/r + exp(-2r)/r - 2 exp(-r)/r
Definition operatorinfo.h:21
@ OT_F12
exp(-r2)
Definition operatorinfo.h:17
@ OT_F212
(1-exp(-r))/r
Definition operatorinfo.h:19
@ OT_UNDEFINED
Definition operatorinfo.h:12
@ OT_G12
indicates the identity
Definition operatorinfo.h:14
@ OT_F2G12
(1-exp(-r))^2
Definition operatorinfo.h:20
static SeparatedConvolution< double_complex, 3 > PeriodicHFExchangeOperator(World &world, Vector< double, 3 > bloch_k, double lo, double eps, const std::array< KernelRange, 3 > &kernel_ranges=std::array< KernelRange, 3 >(), const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Definition operator.h:1732
void print(const T &t, const Ts &... ts)
Print items to std::cout (items separated by spaces) and terminate with a new line.
Definition print.h:226
response_space apply(World &world, std::vector< std::vector< std::shared_ptr< real_convolution_3d > > > &op, response_space &f)
Definition basic_operators.cc:43
static std::vector< std::shared_ptr< SeparatedConvolution< double, 3 > > > GradBSHOperator(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating operator for convolution with grad(bsh) in 3D.
Definition operator.h:2107
static SeparatedConvolution< double, 3 > * SlaterF12sqOperatorPtr(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Definition operator.h:1854
TensorType
low rank representations of tensors (see gentensor.h)
Definition gentensor.h:120
@ TT_2D
Definition gentensor.h:120
NDIM & f
Definition mra.h:2528
static SeparatedConvolution< double, NDIM > SlaterOperator(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< NDIM >::get_bc().lattice_range(), int k=FunctionDefaults< NDIM >::get_k())
Factory function generating separated kernel for convolution with exp(-mu*r) in 3D.
Definition operator.h:1863
GenTensor< T > reduce(std::list< GenTensor< T > > &addends, double eps, bool are_optimal=false)
add all the GenTensors of a given list
Definition gentensor.h:246
static SeparatedConvolution< double, NDIM > BSHOperator(World &world, double mu, double lo, double eps, const std::array< LatticeRange, NDIM > &lattice_ranges=FunctionDefaults< NDIM >::get_bc().lattice_range(), int k=FunctionDefaults< NDIM >::get_k())
Factory function generating separated kernel for convolution with BSH kernel in general NDIM.
Definition operator.h:1773
static SeparatedConvolution< double, 3 > * CoulombOperatorPtr(World &world, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating separated kernel for convolution with 1/r in 3D.
Definition operator.h:1759
std::string type(const PairType &n)
Definition PNOParameters.h:18
static SeparatedConvolution< double, 3 > FGOperator(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating separated kernel for convolution with 1/(2 mu)*(1 - exp(-mu*r))/r in 3D.
Definition operator.h:1928
static SeparatedConvolution< double_complex, 3 > * PeriodicBSHOperatorPtr3D(World &world, Vector< double, 3 > bloch_k, double mu, double lo, double eps, const std::array< KernelRange, 3 > &kernel_ranges=std::array< KernelRange, 3 >(), const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D.
Definition operator.h:1825
static SeparatedConvolution< double, 3 > * BSHOperatorPtr3D(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D.
Definition operator.h:2002
static SeparatedConvolution< double, NDIM > * SlaterOperatorPtr_ND(World &world, double mu, double lo, double eps, const array_of_bools< NDIM > &lattice_sum=FunctionDefaults< NDIM >::get_bc().is_periodic(), int k=FunctionDefaults< NDIM >::get_k())
Definition operator.h:1896
static SeparatedConvolution< double, 3 > BSHOperator3D(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D.
Definition operator.h:1800
static SeparatedConvolution< double, 3 > * FGOperatorPtr(World &world, double mu, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating separated kernel for convolution with 1/(2 mu)*(1 - exp(-mu*r))/r in 3D.
Definition operator.h:1939
static std::vector< std::shared_ptr< SeparatedConvolution< double, 3 > > > GradCoulombOperator(World &world, double lo, double eps, const std::array< LatticeRange, 3 > &lattice_ranges=FunctionDefaults< 3 >::get_bc().lattice_range(), int k=FunctionDefaults< 3 >::get_k())
Factory function generating operator for convolution with grad(1/r) in 3D.
Definition operator.h:2048
Function< T, NDIM > copy(const Function< T, NDIM > &f, const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > &pmap, bool fence=true)
Create a new copy of the function with different distribution and optional fence.
Definition mra.h:2096
void mTxmq(long dimi, long dimj, long dimk, T *MADNESS_RESTRICT c, const T *a, const T *b, long ldb=-1)
Matrix = Matrix transpose * matrix ... MKL interface version.
Definition mxm.h:257
static const string dir
Definition corepotential.cc:249
static void aligned_axpy(long n, T *MADNESS_RESTRICT a, const T *MADNESS_RESTRICT b, Q s)
Definition aligned.h:75
Definition mraimpl.h:51
static long abs(long a)
Definition tensor.h:218
const double mu
Definition navstokes_cosines.cc:95
static const double b
Definition nonlinschro.cc:119
static const double d
Definition nonlinschro.cc:121
static const double a
Definition nonlinschro.cc:118
double Q(double a)
Definition relops.cc:20
static const double c
Definition relops.cc:10
static const double L
Definition rk.cc:46
static const double thresh
Definition rk.cc:45
static const long k
Definition rk.cc:44
Definition test_ccpairfunction.cc:22
!!! Note that if Rnormf is zero then ALL of the tensors are empty
Definition convolution1d.h:163
double N_up
Definition convolution1d.h:174
double N_F
the norms according to Beylkin 2008, Eq. (21) ff
Definition convolution1d.h:174
double N_diff
Definition convolution1d.h:174
Definition convolution1d.h:989
Definition operatorinfo.h:58
double hi
Definition operatorinfo.h:67
OpType type
introspection
Definition operatorinfo.h:66
double mu
some introspection
Definition operatorinfo.h:63
std::vector< KernelRange > range
Definition operatorinfo.h:68
std::optional< bool > truncate_lowexp_gaussians
Definition operatorinfo.h:70
SeparatedConvolutionData keeps data for all terms, all dimensions.
Definition operator.h:93
std::vector< SeparatedConvolutionInternal< Q, NDIM > > muops
Definition operator.h:94
SeparatedConvolutionData(int rank)
Definition operator.h:97
double norm
Definition operator.h:95
SeparatedConvolutionData(const SeparatedConvolutionData< Q, NDIM > &q)
Definition operator.h:98
double norm
Definition operator.h:85
const ConvolutionData1D< Q > * ops[NDIM]
Definition operator.h:86
laziness for calling lists: which terms to apply
Definition operator.h:211
bool t_term
Definition operator.h:214
bool r_term
Definition operator.h:213
bool any_terms() const
Definition operator.h:215
ApplyTerms()
Definition operator.h:212
too lazy for extended calling lists
Definition operator.h:219
const Q * VT
Definition operator.h:222
const Q * U
Definition operator.h:221
static void load(const Archive &ar, const SeparatedConvolution< T, NDIM > *&ptr)
Definition operator.h:2165
Default load of an object via serialize(ar, t).
Definition archive.h:667
static void store(const Archive &ar, const SeparatedConvolution< T, NDIM > *const &ptr)
Definition operator.h:2174
Default store of an object via serialize(ar, t).
Definition archive.h:612
Definition lowrankfunction.h:336
void doit(World &world)
Definition tdse.cc:921
Prototypes for a partial interface from Tensor to LAPACK.
int factorial(int n)
Definition test_BSHApply.cc:14
AtomicInt sum
Definition test_atomicint.cc:46
void e()
Definition test_sig.cc:75
double aa
Definition testbsh.cc:68
static const double pi
Definition testcosine.cc:6
std::vector< double > fit(size_t m, size_t n, const std::vector< double > N, const std::vector< double > &f)
Definition testfuns.cc:36
constexpr std::size_t NDIM
Definition testgconv.cc:54
double h(const coord_1d &r)
Definition testgconv.cc:175
double source(const coordT &r)
Definition testperiodic.cc:48
#define TENSOR_RESULT_TYPE(L, R)
This macro simplifies access to TensorResultType.
Definition type_data.h:205
#define PROFILE_MEMBER_FUNC(classname)
Definition worldprofile.h:210