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,
561 GenTensor<TENSOR_RESULT_TYPE(T,Q)>& result,
562 GenTensor<TENSOR_RESULT_TYPE(T,Q)>& result0,
563 double tol,
564 const Q mufac,
565 GenTensor<TENSOR_RESULT_TYPE(T,Q)>& work1,
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 prod=1.0, sum=0.0;
657 for (std::size_t d=0; d<NDIM; ++d) {
658 double a = ops[d]->NSnormf;
659 double b = ops[d]->Tnormf;
660 double aa = std::min(a,b);
661 double bb = std::max(a,b);
662 prod *= bb;
663 if (bb > 0.0) sum +=(aa/bb);
664 }
665 if (n) prod *= sum;
666
667 return prod;
668 }
669
670
671 /// Computes the operator norm of one of the separated terms of the modified NS form
672 /// ... WITHOUT FACTOR INCLUDED
673 /// compute for 1 term, all dim, 1 disp, essentially for SeparatedConvolutionInternal
674 double munorm2_modified(Level n, const ConvolutionData1D<Q>* ops_1d[]) const {
676
677 // follows Eq. (21) ff of Beylkin 2008 (Beylkin Appl. Comput. Harmon. Anal. 24, pp 354)
678
679 // we have all combinations of difference, upsampled, F terms (d, u, f),
680 // with the constraint that d is in each term exactly once. In the mixed terms (udf)
681 // we just get all possible combinations, in the pure terms (dff, duu) we have
682 // to multiply each term (dff, fdf, ffd) with (NDIM-1)!, to get the right number.
683
684 double dff = 0.0;
685 double duu = 0.0;
686 double udf = 0.0;
687
688 // loop over d shifting over the dimensions dxx, xdx, xxd,
689 for (size_t d=0; d<NDIM; ++d) {
690 double dff_tmp = ops_1d[d]->N_diff;
691 double duu_tmp = ops_1d[d]->N_diff;
692 double udf_tmp = ops_1d[d]->N_diff;
693
694
695 for (size_t dd=0; dd<NDIM; ++dd) {
696 if (dd!=d) {
697 dff_tmp *= ops_1d[dd]->N_F;
698 duu_tmp *= ops_1d[dd]->N_up;
699
700 udf_tmp *= ops_1d[dd]->N_F;
701 for (size_t ddd=0; ddd<NDIM; ++ddd) {
702 if (ddd!=dd) udf += udf_tmp * ops_1d[ddd]->N_up;
703 }
704 }
705 }
706
707 dff+=dff_tmp;
708 duu+=duu_tmp;
709 }
710
711 // finalize with the factorial
712 double factorial=1.0;
713 for (int i=1; i<static_cast<int>(NDIM)-1; ++i) factorial*=double(i);
714 dff*=factorial;
715 duu*=factorial;
716
717 // Eq. (23) of Beylkin 2008, for one separated term WITHOUT the factor
718 double norm=(dff + udf + duu) /(factorial * double(NDIM));
719
720// // double check
721// if (NDIM==3) {
722// Tensor<Q> R_full=outer(ops_1d[0]->R,outer(ops_1d[1]->R,ops_1d[2]->R));
723// Tensor<Q> T_full=outer(ops_1d[0]->T,outer(ops_1d[1]->T,ops_1d[2]->T));
724// double n2=(R_full-T_full).normf();
725//// print("norm estimate, norm",norm, n2, norm<n2);
726// norm=n2;
727// }
728
729 return norm;
730
731 }
732
733
734 /// get the transformation matrices for 1 term and all dimensions and one displacement
735
736 /// use ConvolutionND, which uses ConvolutionData1D to collect the transformation matrices
738 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
740 for (std::size_t d=0; d<NDIM; ++d) {
741 op.ops[d] = ops[mu].getop(d)->nonstandard(n, disp.translation()[d]);
742 }
743 op.norm = munorm2(n, op.ops)*std::abs(ops[mu].getfac());
744
745// double newnorm = munorm2(n, op.ops);
746// // This rescaling empirically based upon BSH separated expansion
747// // ... needs more testing. OK also for TDSE.
748// // All is good except for some 000 blocks which are up to sqrt(k^d) off.
749// for (int d=0; d<NDIM; ++d) {
750// if (disp[d] == 0) newnorm *= 0.5;
751// else if (std::abs(disp[d]) == 1) newnorm *= 0.8;
752// }
753// double oldnorm = munorm(n, op.ops);
754// if (oldnorm > 1e-13 && (newnorm < 0.5*oldnorm || newnorm > 2.0*oldnorm) )
755// print("munorm", n, disp, mu, newnorm, oldnorm, newnorm/oldnorm);
756
757 return op;
758 }
759
760
761
762 /// get the transformation matrices for 1 term and all dimensions and one displacement
763
764 /// use ConvolutionND, which uses ConvolutionData1D to collect the transformation matrices
766 getmuop_modified(int mu, Level n, const Key<NDIM>& disp, const Key<NDIM>& source) const {
767 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
768
769
770 // SeparatedConvolutionInternal keeps data for 1 term and all dimensions
772
773 // in the modified NS form we need not only the displacement, but also the source Translation
774 // for correctly constructing the operator, b/c the operator is not Toeplitz
775
776 // op.ops is of type ConvolutionData1D (1 term, 1 dim, 1 disp)
777 // ops[mu] is of type ConvolutionND (1 term, all dim, 1 disp)
778 for (std::size_t d=0; d<NDIM; ++d) {
779 Translation sx=source.translation()[d]; // source translation
780 Translation tx=source.translation()[d]+disp.translation()[d]; // target translation
781
782 Key<2> op_key(n,Vector<Translation,2>{sx,tx});
783 op.ops[d] = ops[mu].getop(d)->mod_nonstandard(op_key);
784 }
785
786 // works for both modified and not modified NS form
787 op.norm = munorm2(n, op.ops)*std::abs(ops[mu].getfac());
788// op.norm=1.0;
789 return op;
790 }
791
792 /// get the data for all terms and all dimensions for one displacement
794
795 // in the NS form the operator depends only on the displacement
796 if (not modified()) return getop_ns(n,d);
797 return getop_modified(n, d, source);
798 }
799
800
801 /// get the data for all terms and all dimensions for one displacement
802
803 /// uses SeparatedConvolutionInternal (ConvolutionND, ConvolutionData1D) to construct
804 /// the transformation matrices.
805 /// @param[in] d displacement
806 /// @return pointer to cached operator
808 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
809 const SeparatedConvolutionData<Q,NDIM>* p = data.getptr(n,d);
810 if (p) return p;
811
812 // get the data for each term
814 for (int mu=0; mu<rank; ++mu) {
815 // op.muops is of type SeparatedConvolutionInternal (1 term, all dim, 1 disp)
816 // getmuop uses ConvolutionND
817 op.muops[mu] = getmuop(mu, n, d);
818 }
819
820 double norm = 0.0;
821 for (int mu=0; mu<rank; ++mu) {
822 const double munorm = op.muops[mu].norm;
823 norm += munorm*munorm;
824 }
825 //print("getop", n, d, norm);
826 op.norm = sqrt(norm);
827 data.set(n, d, op);
828 return data.getptr(n,d);
829 }
830
831
832
833 /// get the data for all terms and all dimensions for one displacement (modified NS form)
834
835 /// remember that the operator in the modified NS form is not Toeplitz, so we need
836 /// information about the displacement and the source key
837 /// @param[in] n level (=scale) (actually redundant, since included in source)
838 /// @param[in] disp displacement key
839 /// @param[in] source source key
840 /// @return pointer to cached operator
842 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
843
844 // in the modified NS form the upsampled part of the operator depends on the modulus of the source
845 Vector<Translation,NDIM> t=source.translation();
846 for (size_t i=0; i<NDIM; ++i) t[i]=t[i]%2;
847 Key<2*NDIM> key=disp.merge_with(Key<NDIM>(source.level(),t));
848
849 const SeparatedConvolutionData<Q,NDIM>* p = mod_data.getptr(n,key);
850 if (p) return p;
851
852 // get the data for each term
853 // op.muops is of type SeparatedConvolutionInternal (1 term, all dim, 1 disp)
854 // getmuop uses ConvolutionND
856 for (int mu=0; mu<rank; ++mu) op.muops[mu] = getmuop_modified(mu, n, disp, source);
857
858 double norm = 0.0;
859 for (int mu=0; mu<rank; ++mu) {
860 const double munorm = op.muops[mu].norm;
861 norm += munorm*munorm;
862 }
863
864 op.norm = sqrt(norm);
865 mod_data.set(n, key, op);
866 return mod_data.getptr(n,key);
867 }
868
869
870 void check_cubic() {
871 // !!! NB ... cell volume obtained from global defaults
873 // Check that the cell is cubic since currently is assumed
874 for (std::size_t d=1; d<NDIM; ++d) {
875 MADNESS_CHECK(fabs(cell_width(d)-cell_width(0L)) < 1e-14*cell_width(0L));
876 }
877 }
878
879
880 /// upsample some of the dimensions of coeff to its child indicated by key
881
882 /// @param[in] coeff the coeffs of dim 2*NDIM that will be upsampled
883 /// @param[in] key the key indicating the child -- only some dimensions will be "reproductive"
884 /// @param[in] particle if 0: upsample dimensions 0-2
885 /// if 1: upsample dimensions 3-5
886 /// @return a partially upsampled coefficient tensor
887 template<typename T, size_t FDIM>
888 GenTensor<T> partial_upsample(const Key<FDIM>& key, const GenTensor<T>& coeff, const int particle) const {
889
890 if (coeff.rank()==0) return GenTensor<T>();
891 MADNESS_ASSERT(coeff.dim(0)==k);
892 if (NDIM==coeff.ndim()) {
893 MADNESS_ASSERT(particle==1); // other particle, leave this particle unchanged
894 return coeff;
895 }
896
897 MADNESS_ASSERT(coeff.ndim()==FDIM);
898 MADNESS_ASSERT(particle==0 or (2*NDIM==FDIM));
899
900 // the twoscale coefficients: for upsampling use h0/h1; see Alpert Eq (3.35a/b)
901 // handle the spectator dimensions with the identity matrix
902 const Tensor<T> h[2] = {cdata.h0, cdata.h1};
903 Tensor<T> identity(k,k);
904 for (int i=0; i<k; ++i) identity(i,i)=1.0;
905 Tensor<T> matrices[2*NDIM];
906
907 // get the appropriate twoscale coefficients for each dimension
908 if (particle==0) {
909 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii]=h[key.translation()[ii]%2];
910 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii+NDIM]=identity;
911 } else if (particle==1) {
912 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii]=identity;
913 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii+NDIM]=h[key.translation()[ii+NDIM]%2];
914 } else {
915 MADNESS_EXCEPTION("unknown particle",1);
916 }
917
918 // transform and accumulate on the result
919 const GenTensor<T> result=general_transform(coeff,matrices);
920 return result;
921 }
922
923
924 /// upsample the sum coefficients of level 1 to sum coeffs on level n+1
925
926 /// specialization of the unfilter method, will transform only the sum coefficients
927 /// @param[in] key key of level n+1
928 /// @param[in] coeff sum coefficients of level n (does NOT belong to key!!)
929 /// @return sum coefficients on level n+1
930 template<typename T, size_t FDIM>
931 GenTensor<T> upsample(const Key<FDIM>& key, const GenTensor<T>& coeff) const {
932
933 // the twoscale coefficients: for upsampling use h0/h1; see Alpert Eq (3.35a/b)
934 // note there are no difference coefficients; if you want that use unfilter
935 const Tensor<T> h[2] = {cdata.h0, cdata.h1};
936 Tensor<T> matrices[FDIM];
937
938 // get the appropriate twoscale coefficients for each dimension
939 for (size_t ii=0; ii<FDIM; ++ii) matrices[ii]=h[key.translation()[ii]%2];
940
941 // transform and accumulate on the result
942 const GenTensor<T> result=general_transform(coeff,matrices);
943 return result;
944 }
945
946 /// initializes range using range of ops[0]
947 /// @pre `ops[i].range == ops[0].range`
948 void init_range() {
949 if (!ops.empty()) {
950 for (int d = 0; d != NDIM; ++d) {
951 for(const auto & op: ops) {
952 MADNESS_ASSERT(op.getop(d)->range == ops[0].getop(d)->range);
953 }
954 range[d] = ops[0].getop(d)->range;
955 }
956 }
957 }
958
959 /// initializes lattice_sum using `ops[0].lattice_summed()`
960 /// @pre `ops[i].lattice_summed() == ops[0].lattice_summed()`
962 if (!ops.empty()) {
963 for (int d = 0; d != NDIM; ++d) {
964 for (const auto &op : ops) {
965 MADNESS_ASSERT(op.lattice_summed() ==
966 ops[0].lattice_summed());
967 }
968 lattice_summed_ = ops[0].lattice_summed();
969 }
970 }
971 }
972
973 public:
974
975 // For separated convolutions with same operator in each direction (isotropic)
977 const std::vector< std::shared_ptr< Convolution1D<Q> > >& argops,
979 bool doleaves = false)
981 , info()
983 , lattice_summed_(false) // this will be overridden by init_lattice_summed below
984 , modified_(false)
985 , particle_(1)
986 , destructive_(false)
987 , k(k)
989 , rank(argops.size())
990 , vk(NDIM,k)
991 , v2k(NDIM,2*k)
992 , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1))
993 {
994
995 for (unsigned int mu=0; mu < argops.size(); ++mu) {
996 this->ops.push_back(ConvolutionND<Q,NDIM>(argops[mu]));
997 }
998 init_range();
1000
1001 this->process_pending();
1002 }
1003
1004 // For general convolutions
1006 const std::vector< ConvolutionND<Q,NDIM> >& argops,
1008 bool doleaves = false)
1010 , info()
1012 , lattice_summed_(false) // this will be overridden by init_lattice_summed below
1013 , modified_(false)
1014 , particle_(1)
1015 , destructive_(false)
1016 , ops(argops)
1017 , k(k)
1018 , cdata(FunctionCommonData<Q,NDIM>::get(k))
1019 , rank(argops.size())
1020 , vk(NDIM,k)
1021 , v2k(NDIM,2*k)
1022 , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1))
1023 {
1024 init_range();
1026 this->process_pending();
1027 }
1028
1029 /// Constructor for Gaussian Convolutions
1030 /// WARNING! bloch_k should only ever be nonzero if `Q` is a complex type.
1032 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1034 bool doleaves = false,
1035 const Vector<double, NDIM>& bloch_k = Vector<double, NDIM>(0.0))
1036 : SeparatedConvolution(world,Tensor<double>(0l),Tensor<double>(0l),info1.lo,info1.thresh,lattice_ranges,k,doleaves,info1.mu) {
1037 info.type=info1.type;
1039 info.range = info1.range;
1040 auto [coeff, expnt] = make_coeff_for_operator(world, info, lattice_ranges);
1041 rank=coeff.dim(0);
1042 range = info.template range_as_array<NDIM>();
1043 ops.resize(rank);
1044 initialize(coeff,expnt,lattice_ranges,range,bloch_k);
1046 }
1047
1048 /// Constructor for Gaussian Convolutions (mostly for backward compatability)
1050 const Tensor<Q>& coeff, const Tensor<double>& expnt,
1051 double lo, double thresh,
1052 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1054 bool doleaves = false,
1055 double mu=0.0)
1059 ,
1060 lattice_summed_(false) // will be updated by init_lattice_summed
1061 , ops(coeff.dim(0))
1062 , k(k)
1063 , cdata(FunctionCommonData<Q,NDIM>::get(k))
1064 , rank(coeff.dim(0))
1065 , vk(NDIM,k)
1066 , v2k(NDIM,2*k)
1067 , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1)) {
1068 initialize(coeff,expnt,lattice_ranges);
1069 init_range();
1071 }
1072
1073 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)) {
1075 const double pi = constants::pi;
1076
1077 for (int mu=0; mu<rank; ++mu) {
1078 Q c = std::pow(sqrt(expnt(mu)/pi),static_cast<int>(NDIM)); // Normalization coeff
1079
1080 // We cache the normalized operator so the factor is the value we must multiply
1081 // by to recover the coeff we want.
1082 ops[mu].setfac(coeff(mu)/c);
1083
1084 for (std::size_t d=0; d<NDIM; ++d) {
1085 ops[mu].setop(d,GaussianConvolution1DCache<Q>::get(k, expnt(mu)*width[d]*width[d], 0,
1086 lattice_range[d], bloch_k[d], range[d]));
1087 }
1088 }
1089 }
1090
1092
1093 void print_timer() const {
1094 if (this->get_world().rank()==0) {
1095 timer_full.print("op full tensor ");
1096 timer_low_transf.print("op low rank transform");
1097 timer_low_accumulate.print("op low rank addition ");
1098 }
1099 }
1100
1101 void reset_timer() const {
1102 if (this->get_world().rank()==0) {
1103 timer_full.reset();
1106 }
1107 }
1108
1109 const std::vector< Key<NDIM> >& get_disp(Level n) const {
1111 }
1112
1113 /// @return flag for each axis indicating whether lattice summation is performed in that direction
1115 /// @return flag for each axis indicating whether functions that this op acts on are periodic on the box in that direction (false by default)
1116 /// it is normally preferred to lattice sum, obtaining an equivalent problem with a lattice-summed operator on a non-periodic function
1118 /// changes domain periodicity
1119 /// \param domain_is_periodic
1120 void set_domain_periodicity(const array_of_bools<NDIM>& domain_is_periodic) { func_domain_is_periodic_ = domain_is_periodic;}
1121
1122 /// return the operator norm for all terms, all dimensions and 1 displacement
1123 double norm(Level n, const Key<NDIM>& d, const Key<NDIM>& source_key) const {
1124 // SeparatedConvolutionData keeps data for all terms and all dimensions and 1 displacement
1125// return 1.0;
1126 return getop(n, d, source_key)->norm;
1127 }
1128
1129 /// return that part of a hi-dim key that serves as the base for displacements of this operator
1130
1131 /// if the function and the operator have the same dimension return key
1132 /// if the function has a higher dimension than the operator (e.g. in the exchange operator)
1133 /// return only that part of key that corresponds to the particle this operator works on
1134 /// @param[in] key hi-dim key
1135 /// @return a lo-dim part of key; typically first or second half
1136 template<size_t FDIM>
1137 typename std::enable_if<FDIM!=NDIM, Key<NDIM> >::type
1138 get_source_key(const Key<FDIM> key) const {
1140 Key<FDIM-NDIM> dummykey;
1141 if (particle()==1) key.break_apart(source,dummykey);
1142 if (particle()==2) key.break_apart(dummykey,source);
1143 return source;
1144 }
1145
1146 /// return that part of a hi-dim key that serves as the base for displacements of this operator
1147
1148 /// if the function and the operator have the same dimension return key
1149 /// if the function has a higher dimension than the operator (e.g. in the exchange operator)
1150 /// return only that part of key that corresponds to the particle this operator works on
1151 /// @param[in] key hi-dim key
1152 /// @return a lo-dim part of key; typically first or second half
1153 template<size_t FDIM>
1154 typename std::enable_if<FDIM==NDIM, Key<NDIM> >::type
1155 get_source_key(const Key<FDIM> key) const {
1156 return key;
1157 }
1158
1159 /// apply this operator on a function f
1160
1161 /// the operator does not need to have the same dimension as the function, e,g,
1162 /// the Poisson kernel for the exchange operator acts only on 1 electron of a
1163 /// given (pair) function.
1164 /// @param[in] f a function of same or different dimension as this operator
1165 /// @return the result function of the same dimensionality as the input function f
1166 template <typename T, size_t FDIM>
1168 return madness::apply(*this, f);
1169 }
1170
1171 /// apply this on a vector of functions
1172 template <typename T, size_t FDIM>
1173 std::vector<Function<TENSOR_RESULT_TYPE(T,Q),FDIM>> operator()(const std::vector<Function<T,FDIM>>& f) const {
1174 return madness::apply(*this, f);
1175 }
1176
1177 /// apply this operator on a separable function f(1,2) = f(1) f(2)
1178
1179 /// @param[in] f1 a function of dim LDIM
1180 /// @param[in] f2 a function of dim LDIM
1181 /// @return the result function of dim NDIM=2*LDIM: g(1,2) = G(1,1',2,2') f(1',2')
1182 template <typename T, size_t LDIM>
1183 Function<TENSOR_RESULT_TYPE(T,Q),LDIM+LDIM>
1185 return madness::apply(*this, std::vector<Function<Q,LDIM>>({f1}),
1186 std::vector<Function<Q,LDIM>>({f2}));
1187 }
1188
1189 /// apply this operator on a sum of separable functions f(1,2) = \sum_i f_i(1) f_i(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>
1196 operator()(const std::vector<Function<T,LDIM>>& f1, const std::vector<Function<Q,LDIM>>& f2) const {
1197 return madness::apply(*this, f1, f2);
1198 }
1199
1200 /// apply this onto another suitable argument, returning the same type
1201
1202 /// argT must implement argT::apply(const SeparatedConvolution& op, const argT& arg)
1203 template<typename argT>
1204 argT operator()(const argT& argument) const {
1205 return madness::apply(*this,argument);
1206 }
1207
1208
1209 /// apply this operator on coefficients in full rank form
1210
1211 /// @param[in] coeff source coeffs in full rank
1212 /// @param[in] source the source key
1213 /// @param[in] shift the displacement, where the source coeffs come from
1214 /// @param[in] tol thresh/#neigh*cnorm
1215 /// @return a tensor of full rank with the result op(coeff)
1216 template <typename T>
1218 const Key<NDIM>& shift,
1219 const Tensor<T>& coeff,
1220 double tol) const {
1221 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
1222 MADNESS_ASSERT(coeff.ndim()==NDIM);
1223
1224 double cpu0=cpu_time();
1225
1226 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
1227 const Tensor<T>* input = &coeff;
1228 Tensor<T> dummy;
1229
1230 if (not modified()) {
1231 if (coeff.dim(0) == k) {
1232 // This processes leaf nodes with only scaling
1233 // coefficients ... FuncImpl::apply by default does not
1234 // apply the operator to these since for smoothing operators
1235 // it is not necessary. It is necessary for operators such
1236 // as differentiation and time evolution and will also occur
1237 // if the application of the operator widens the tree.
1238 dummy = Tensor<T>(v2k);
1239 dummy(s0) = coeff;
1240 input = &dummy;
1241 }
1242 else {
1243 MADNESS_ASSERT(coeff.dim(0)==2*k);
1244 }
1245 }
1246
1247 tol = 0.01*tol/rank; // Error is per separated term
1248 ApplyTerms at;
1249 at.r_term=true;
1250 at.t_term=(source.level()>0);
1251
1252 /// SeparatedConvolutionData keeps data for all terms and all dimensions and 1 displacement
1254
1255 //print("sepop",source,shift,op->norm,tol);
1256
1257 Tensor<resultT> r(v2k), r0(vk);
1258 Tensor<resultT> work1(v2k,false), work2(v2k,false);
1259
1260 if (modified()) {
1262 work1=Tensor<resultT>(vk,false);
1263 work2=Tensor<resultT>(vk,false);
1264 }
1265
1266 const Tensor<T> f0 = copy(coeff(s0));
1267 for (int mu=0; mu<rank; ++mu) {
1268 // SeparatedConvolutionInternal keeps data for 1 term and all dimensions and 1 displacement
1269 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1270 if (muop.norm > tol) {
1271 // ops is of ConvolutionND, returns data for 1 term and all dimensions
1272 Q fac = ops[mu].getfac();
1273 muopxv_fast(at, muop.ops, *input, f0, r, r0, tol/std::abs(fac), fac,
1274 work1, work2);
1275 }
1276 }
1277
1278 r(s0).gaxpy(1.0,r0,1.0);
1279 double cpu1=cpu_time();
1280 timer_full.accumulate(cpu1-cpu0);
1281
1282 return r;
1283 }
1284
1285
1286 /// apply this operator on only 1 particle of the coefficients in low rank form
1287
1288 /// note the unfortunate mess with NDIM: here NDIM is the operator dimension, and FDIM is the
1289 /// function's dimension, whereas in the function we have OPDIM for the operator and NDIM for
1290 /// the function
1291 /// @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.
1292 /// @param[in] coeff source coeffs in SVD (=optimal!) form, in high dimensionality (FDIM)
1293 /// @param[in] source the source key in low dimensionality (NDIM)
1294 /// @param[in] shift the displacement in low dimensionality (NDIM)
1295 /// @param[in] tol thresh/(#neigh*cnorm)
1296 /// @param[in] tol2 thresh/#neigh
1297 /// @return coeff result
1298 template<typename T>
1300 const Key<NDIM>& shift, const GenTensor<T>& coeff, double tol, double tol2) const {
1301
1302 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
1303
1304 // prepare access to the singular vectors
1305 const SVDTensor<T>& svdcoeff=coeff.get_svdtensor();
1306// std::vector<Slice> s(coeff.config().dim_per_vector()+1,_);
1307 std::vector<Slice> s(svdcoeff.dim_per_vector(particle()-1)+1,_);
1308 // can't use predefined slices and vectors -- they have the wrong dimension
1309 const std::vector<Slice> s00(coeff.ndim(),Slice(0,k-1));
1310
1311 // some checks
1312 MADNESS_ASSERT(coeff.is_svd_tensor()); // for now
1313 MADNESS_ASSERT(not modified());
1315 MADNESS_ASSERT(coeff.dim(0)==2*k);
1316 MADNESS_ASSERT(2*NDIM==coeff.ndim());
1317
1318 double cpu0=cpu_time();
1320
1321 // some workspace
1322 Tensor<resultT> work1(v2k,false), work2(v2k,false);
1323
1324 // sliced input and final result
1325 const GenTensor<T> f0 = copy(coeff(s00));
1326 GenTensor<resultT> final=copy(coeff);
1327 GenTensor<resultT> final0=copy(f0);
1328
1329 tol = tol/rank*0.01; // Error is per separated term
1330 tol2= tol2/rank;
1331
1332 // the operator norm is missing the identity working on the other particle
1333 // use as (muop.norm*exchange_norm < tol)
1334 // for some reason the screening is not working at all..
1335// double exchange_norm=std::pow(2.0*k,1.5);
1336
1337 for (int r=0; r<coeff.rank(); ++r) {
1338
1339 // get the appropriate singular vector (left or right depends on particle)
1340 // and apply the full tensor muopxv_fast on it, term by term
1341 s[0]=Slice(r,r);
1342 const Tensor<T> chunk=svdcoeff.ref_vector(particle()-1)(s).reshape(v2k);
1343 const Tensor<T> chunk0=f0.get_svdtensor().ref_vector(particle()-1)(s).reshape(vk);
1344// const double weight=std::abs(coeff.config().weights(r));
1345
1346 // accumulate all terms of the operator for a specific term of the function
1347 Tensor<resultT> result(v2k), result0(vk);
1348
1349 ApplyTerms at;
1350 at.r_term=true;
1351 at.t_term=source.level()>0;
1352
1353 // this loop will return on result and result0 the terms [(P+Q) G (P+Q)]_1,
1354 // and [P G P]_1, respectively
1355 for (int mu=0; mu<rank; ++mu) {
1356 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1357 Q fac = ops[mu].getfac();
1358 muopxv_fast(at, muop.ops, chunk, chunk0, result, result0,
1359 tol/std::abs(fac), fac, work1, work2);
1360 }
1361
1362 // reinsert the transformed terms into result, leaving the other particle unchanged
1363 MADNESS_ASSERT(final.get_svdtensor().has_structure());
1364 final.get_svdtensor().ref_vector(particle()-1)(s)=result;
1365
1366 if (source.level()>0) {
1367 final0.get_svdtensor().ref_vector(particle()-1)(s)=result0;
1368 } else {
1369 final0.get_svdtensor().ref_vector(0)(s)=0.0;
1370 final0.get_svdtensor().ref_vector(1)(s)=0.0;
1371 }
1372
1373 }
1374 double cpu1=cpu_time();
1375 timer_low_transf.accumulate(cpu1-cpu0);
1376
1377 double cpu00=cpu_time();
1378
1379 final.reduce_rank(tol2*0.5);
1380 final0.reduce_rank(tol2*0.5);
1381 final(s00)+=final0;
1382 final.reduce_rank(tol2);
1383
1384 double cpu11=cpu_time();
1385 timer_low_accumulate.accumulate(cpu11-cpu00);
1386 return final;
1387 }
1388
1389 /// apply this operator on coefficients in low rank form
1390
1391 /// @param[in] coeff source coeffs in SVD (=optimal!) form
1392 /// @param[in] tol thresh/#neigh*cnorm
1393 /// @param[in] tol2 thresh/#neigh
1394 template <typename T>
1396 const Key<NDIM>& shift,
1397 const GenTensor<T>& coeff,
1398 double tol, double tol2) const {
1400 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
1401
1402 MADNESS_ASSERT(coeff.ndim()==NDIM);
1403 MADNESS_ASSERT(coeff.is_svd_tensor()); // we use the rank below
1404// MADNESS_EXCEPTION("no apply2",1);
1405 const TensorType tt=TT_2D;
1406
1407 const GenTensor<T>* input = &coeff;
1408 GenTensor<T> dummy;
1409
1410 if (not modified()) {
1411 if (coeff.dim(0) == k) {
1412 // This processes leaf nodes with only scaling
1413 // coefficients ... FuncImpl::apply by default does not
1414 // apply the operator to these since for smoothing operators
1415 // it is not necessary. It is necessary for operators such
1416 // as differentiation and time evolution and will also occur
1417 // if the application of the operator widens the tree.
1418 dummy = GenTensor<T>(v2k,TT_2D);
1419 dummy(s0) += coeff;
1420 input = &dummy;
1421 }
1422 else {
1423 MADNESS_ASSERT(coeff.dim(0)==2*k);
1424 }
1425 }
1426
1427 tol = tol/rank; // Error is per separated term
1428 tol2= tol2/rank;
1429
1431
1432 GenTensor<resultT> r, r0, result, result0;
1433 GenTensor<resultT> work1(v2k,tt), work2(v2k,tt);
1434
1435 if (modified()) {
1436 r=GenTensor<resultT>(vk,tt);
1437 work1=GenTensor<resultT>(vk,tt);
1438 work2=GenTensor<resultT>(vk,tt);
1439 }
1440
1441 // collect the results of the individual operator terms
1442 std::list<GenTensor<T> > r_list;
1443 std::list<GenTensor<T> > r0_list;
1444
1445// const GenTensor<T> f0 = copy(coeff(s0));
1446 const GenTensor<T> f0 = copy((*input)(s0));
1447 for (int mu=0; mu<rank; ++mu) {
1448 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1449 //print("muop",source, shift, mu, muop.norm);
1450
1451 // delta(g) < delta(T) * || f ||
1452 if (muop.norm > tol) {
1453
1454 // get maximum rank of coeff to contribute:
1455 // delta(g) < eps < || T || * delta(f)
1456 // delta(coeff) * || T || < tol2
1457 const int r_max=SRConf<T>::max_sigma(tol2/muop.norm,coeff.rank(),coeff.get_svdtensor().weights_);
1458 // print("r_max",coeff.config().weights(r_max));
1459
1460 // note that max_sigma is inclusive!
1461 if (r_max>=0) {
1462 const GenTensor<resultT> chunk=SVDTensor<resultT>(input->get_svdtensor().get_configs(0,r_max));
1463 const GenTensor<resultT> chunk0=SVDTensor<resultT>(f0.get_svdtensor().get_configs(0,r_max));
1464
1465 double cpu0=cpu_time();
1466
1467 Q fac = ops[mu].getfac();
1468 muopxv_fast2(source.level(), muop.ops, chunk, chunk0, r, r0,
1469 tol/std::abs(fac), fac, work1, work2);
1470 double cpu1=cpu_time();
1471 timer_low_transf.accumulate(cpu1-cpu0);
1472
1473 r_list.push_back(r);
1474 r0_list.push_back(r0);
1475 }
1476 }
1477 }
1478
1479 // finally accumulate all the resultant terms into one tensor
1480 double cpu0=cpu_time();
1481
1482 result0=reduce(r0_list,tol2*rank);
1483 if (r_list.size()>0) r_list.front()(s0)+=result0;
1484 result=reduce(r_list,tol2*rank);
1485// result.reduce_rank(tol2*rank);
1486
1487 double cpu1=cpu_time();
1490 return result;
1491 }
1492
1493 /// estimate the ratio of cost of full rank versus low rank
1494
1495 /// @param[in] source source key
1496 /// @param[in] shift displacement
1497 /// @param[in] tol thresh/#neigh/cnorm
1498 /// @param[in] tol2 thresh/#neigh
1499 /// @return cost_ratio r=-1: no terms left
1500 /// 0<r<1: better to do full rank
1501 /// 1<r: better to do low rank
1502 template<typename T>
1504 const Key<NDIM>& shift,
1505 const GenTensor<T>& coeff,
1506 double tol, double tol2) const {
1507
1508 if (coeff.is_full_tensor()) return 0.5;
1509 if (2*NDIM==coeff.ndim()) return 1.5;
1510 MADNESS_ASSERT(NDIM==coeff.ndim());
1512
1514
1515 tol = tol/rank; // Error is per separated term
1516 tol2= tol2/rank;
1517
1518 const double full_operator_cost=pow(coeff.dim(0),NDIM+1);
1519 const double low_operator_cost=pow(coeff.dim(0),NDIM/2+1);
1520 const double low_reduction_cost=pow(coeff.dim(0),NDIM/2);
1521
1522 double full_cost=0.0;
1523 double low_cost=0.0;
1524
1525 long initial_rank=0;
1526 long final_rank=sqrt(coeff.size())*0.05; // size=ncol*nrow; final rank is 5% of max rank
1527
1528 for (int mu=0; mu<rank; ++mu) {
1529 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1530
1531 // delta(g) < delta(T) * || f ||
1532 if (muop.norm > tol) {
1533 // note that max_sigma is inclusive: it returns a slice w(Slice(0,i))
1534 long nterms=SRConf<T>::max_sigma(tol2/muop.norm,coeff.rank(),coeff.get_svdtensor().weights_)+1;
1535
1536 // take only the first overlap computation of rank reduction into account
1537// low_cost+=nterms*low_operator_cost + 2.0*nterms*nterms*low_reduction_cost;
1538 initial_rank+=nterms;
1539
1540 full_cost+=full_operator_cost;
1541 }
1542 }
1543 low_cost=initial_rank*low_operator_cost + initial_rank*final_rank*low_reduction_cost;
1544
1545 // include random empirical factor of 2
1546 double ratio=-1.0;
1547 if (low_cost>0.0) ratio=full_cost/low_cost;
1548// print("nterms, full, low, full/low", full_cost, low_cost,shift.distsq(), ratio);
1549 return ratio;
1550
1551 }
1552
1553 /// construct the tensortrain representation of the operator
1554
1555 /// @param[in] source source coefficient box
1556 /// @param[in] shift displacement
1557 /// @param[in] tol threshold for the TT truncation
1558 /// @param[in] do_R compute the R term of the operator (2k^d)
1559 /// @param[in] do_T compute the T term of the operator (k^d), including factor -1
1560 /// Both do_R and do_T may be used simultaneously, then the final
1561 /// operator will have dimensions (2k^d)
1563 const Key<NDIM>& shift, double tol, bool do_R, bool do_T) const {
1564
1565 if (not (do_R or do_T)) {
1566 print("no operator requested in make_tt_representation??");
1567 MADNESS_EXCEPTION("you're sure you know what you're doing?",1);
1568 }
1569
1570
1572
1573 // check for significant ranks since the R/T matrices' construction
1574 // might have been omitted. Tnorm is always smaller than Rnorm
1575 long lo=0,hi=rank;
1576 for (int mu=0; mu<rank; ++mu) {
1577 double Rnorm=1.0;
1578 for (std::size_t d=0; d<NDIM; ++d) Rnorm *= op->muops[mu].ops[d]->Rnorm;
1579 if (Rnorm>1.e-20) hi=mu;
1580 if ((Rnorm<1.e-20) and (mu<hi)) lo=mu;
1581 }
1582 hi++;lo++;
1583
1584 // think about dimensions
1585 long rank_eff=(hi-lo); // R or T matrices
1586 long step=1;
1587 if (do_R and do_T) { // R and T matrices
1588 rank_eff*=2;
1589 step*=2;
1590 }
1591
1592 long k2k=k; // T matrices
1593 if (do_R) k2k=2*k; // R matrices
1594
1595
1596 // construct empty TT cores and fill them with the significant R/T matrices
1597 std::vector<Tensor<double> > cores(NDIM,Tensor<double>(rank_eff,k2k,k2k,rank_eff));
1598 cores[0]=Tensor<double>(k2k,k2k,rank_eff);
1599 cores[NDIM-1]=Tensor<double>(rank_eff,k2k,k2k);
1600
1601
1602 for (int mu=lo, r=0; mu<hi; ++mu, ++r) {
1603 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1604 const Q fac = ops[mu].getfac();
1605 const Slice sr0(step*r, step*r, 0);
1606 const Slice sr1(step*r+step-1,step*r+step-1,0);
1607 const Slice s00(0,k-1,1);
1608
1609 if (do_R) {
1610 cores[0](_, _ ,sr0)=muop.ops[0]->R;
1611 for (std::size_t idim=1; idim<NDIM-1; ++idim) {
1612 cores[idim](sr0,_ ,_ ,sr0)=muop.ops[idim]->R;
1613 }
1614 cores[NDIM-1](sr0,_ ,_ )=muop.ops[NDIM-1]->R*fac;
1615 }
1616
1617 if (do_T) {
1618 cores[0](s00,s00,sr1)=muop.ops[0]->T;
1619 for (std::size_t idim=1; idim<NDIM-1; ++idim) {
1620 cores[idim](sr1,s00,s00,sr1)=muop.ops[idim]->T;
1621 }
1622 cores[NDIM-1](sr1,s00,s00)=muop.ops[NDIM-1]->T*(-fac);
1623 }
1624 }
1625
1626 // construct TT representation
1627 TensorTrain<double> tt(cores);
1628
1629 // need to reshape for the TT truncation
1630 tt.make_tensor();
1632 tt.make_operator();
1633
1634 return tt;
1635 }
1636
1637
1639 return (combine_OT(left,right).type!=OT_UNDEFINED);
1640 }
1641
1642 /// return operator type and other info of the combined operator (e.g. fg = f(1,2)* g(1,2)
1644 OperatorInfo info=left.info;
1645 if ((left.info.type==OT_F12) and (right.info.type==OT_G12)) {
1647 } else if ((left.info.type==OT_GAUSS) and (right.info.type==OT_GAUSS)) {
1648 info=right.info;
1650 info.mu=2.0*right.info.mu;
1651 } else if ((left.info.type==OT_SLATER) and (right.info.type==OT_SLATER)) {
1652 info=right.info;
1654 info.mu=2.0*right.info.mu;
1655 } else if ((left.info.type==OT_G12) and (right.info.type==OT_F12)) {
1656 info=right.info;
1658 } else if ((left.info.type==OT_G12) and (right.info.type==OT_F212)) {
1659 info=right.info;
1661 } else if (((left.info.type==OT_F212) and (right.info.type==OT_G12)) or
1662 ((left.info.type==OT_F12) and (right.info.type==OT_FG12)) or
1663 ((left.info.type==OT_FG12) and (right.info.type==OT_F12))) {
1664 info=right.info;
1666 if (right.info.type!=OT_G12) MADNESS_CHECK(right.info.mu == left.info.mu);
1667 } else if ((left.info.type==OT_F12) and (right.info.type==OT_F12)) {
1669 // keep the original gamma
1670 // (f12)^2 = (1- slater12)^2 = 1/(4 gamma) (1 - 2 exp(-gamma) + exp(-2 gamma))
1671 MADNESS_CHECK(right.info.mu == left.info.mu);
1672 } else {
1673 MADNESS_EXCEPTION("unknown combination of SeparatedConvolutions: feel free to extend in operator.h",1);
1674 }
1675 return info;
1676 }
1677
1678
1679 /// combine 2 convolution operators to one
1680 /// There's some information loss with this constructor - not recommended
1682 const SeparatedConvolution<Q,NDIM>& right) {
1683 MADNESS_CHECK(can_combine(left,right));
1684 MADNESS_CHECK(left.get_world().id()==right.get_world().id());
1685 MADNESS_CHECK(left.lattice_summed() == right.lattice_summed());
1686 std::array<LatticeRange, NDIM> lattice_summed;
1687 for (std::size_t i = 0; i < NDIM; ++i) {
1688 if (left.lattice_summed()[i]) lattice_summed[i].set_infinite();
1689 }
1690
1691 auto info=combine_OT(left,right);
1693 }
1694
1695 /// combine 2 convolution operators to one
1697 const std::shared_ptr<SeparatedConvolution<Q,NDIM>> right) {
1699 if (left and right) {
1700 return combine(*left, *right);
1701 } else if (left) {
1702 return *left;
1703 } else if (right) {
1704 return *right;
1705 } else {
1706 MADNESS_EXCEPTION("can't combine empty SeparatedConvolutions",1);
1707 }
1708 return result;
1709 }
1710 };
1711
1712
1713
1714 /// Factory function generating separated kernel for convolution with 1/r in 3D.
1715 /// N.B. bloch_k species how the function's phase changes as the **operator** translates,
1716 /// which (by translational invariance) is the additive inverse of how the function's
1717 /// phase changes as the **cell** shifts
1718 static
1719 inline
1721 Vector<double,3> bloch_k,
1722 double lo,
1723 double eps,
1724 const std::array<KernelRange, 3>& kernel_ranges = std::array<KernelRange, 3>(),
1725 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1727 return SeparatedConvolution<double_complex, 3>(world, OperatorInfo(0.0, lo, eps, OT_G12, std::nullopt, kernel_ranges),
1728 lattice_ranges, k, false, bloch_k);
1729 }
1730
1731 /// Factory function generating separated kernel for convolution with 1/r in 3D.
1732 /// N.B. bloch_k species how the function's phase changes as the **operator** translates,
1733 /// which (by translational invariance) is the additive inverse of how the function's
1734 /// phase changes as the **cell** shifts
1735 static
1736 inline
1738 Vector<double,3> bloch_k,
1739 double lo,
1740 double eps,
1741 const std::array<KernelRange, 3>& kernel_ranges = std::array<KernelRange, 3>(),
1742 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1744 return new SeparatedConvolution<double_complex, 3>(world, OperatorInfo(0.0, lo, eps, OT_G12, std::nullopt, kernel_ranges),
1745 lattice_ranges, k, false, bloch_k);
1746 }
1747
1748 /// Factory function generating separated kernel for convolution with 1/r in 3D.
1749 static
1750 inline
1752 double lo,
1753 double eps,
1754 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1756 {
1757 return SeparatedConvolution<double,3>(world,OperatorInfo(0.0,lo,eps,OT_G12),lattice_ranges,k);
1758 }
1759
1760
1761 /// Factory function generating separated kernel for convolution with 1/r in 3D.
1762 static
1763 inline
1765 double lo,
1766 double eps,
1767 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1769 {
1770 return new SeparatedConvolution<double,3>(world,OperatorInfo(0.0,lo,eps,OT_G12),lattice_ranges,k);
1771 }
1772
1773
1774 /// Factory function generating separated kernel for convolution with BSH kernel in general NDIM
1775 template <std::size_t NDIM>
1776 static inline
1777 SeparatedConvolution<double,NDIM>
1778 BSHOperator(World& world, double mu, double lo, double eps,
1779 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1781 if (eps>1.e-4) {
1782 if (world.rank()==0) print("the accuracy in BSHOperator is too small, tighten the threshold",eps);
1783 MADNESS_EXCEPTION("0",1);
1784 }
1785 return SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_BSH),lattice_ranges,k);
1786 }
1787
1788 /// Factory function generating separated kernel for convolution with BSH kernel in general NDIM
1789 template <std::size_t NDIM>
1790 static inline
1791 SeparatedConvolution<double,NDIM>*
1792 BSHOperatorPtr(World& world, double mu, double lo, double eps,
1793 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1795 if (eps>1.e-4) {
1796 if (world.rank()==0) print("the accuracy in BSHOperator is too small, tighten the threshold",eps);
1797 MADNESS_EXCEPTION("0",1);
1798 }
1799 return new SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_BSH),lattice_ranges,k);
1800 }
1801
1802
1803 /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D
1804 static inline SeparatedConvolution<double,3>
1805 BSHOperator3D(World& world, double mu, double lo, double eps,
1806 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1808 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_BSH),lattice_ranges,k);
1809 }
1810
1811 /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D
1812 static
1813 inline
1815 Vector<double,3> bloch_k,
1816 double mu,
1817 double lo,
1818 double eps,
1819 const std::array<KernelRange, 3>& kernel_ranges = std::array<KernelRange, 3>(),
1820 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1822
1823 {
1824 return SeparatedConvolution<double_complex, 3>(world, OperatorInfo(mu, lo, eps, OT_BSH, std::nullopt, kernel_ranges),
1825 lattice_ranges, k, false, bloch_k);
1826 }
1827
1828 /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D
1829 static inline
1831 Vector<double,3> bloch_k,
1832 double mu,
1833 double lo,
1834 double eps,
1835 const std::array<KernelRange, 3>& kernel_ranges = std::array<KernelRange, 3>(),
1836 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1838
1839 {
1840 return new SeparatedConvolution<double_complex, 3>(world, OperatorInfo(mu, lo, eps, OT_BSH, std::nullopt, kernel_ranges),
1841 lattice_ranges, k, false, bloch_k);
1842 }
1843
1844
1845 static inline SeparatedConvolution<double,3>
1846 SlaterF12Operator(World& world, double mu, double lo, double eps,
1847 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1849 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F12),lattice_ranges,k);
1850 }
1851
1853 double mu, double lo, double eps,
1854 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1856 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F212),lattice_ranges,k);
1857 }
1858
1860 double mu, double lo, double eps,
1861 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1863 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F212),lattice_ranges,k);
1864 }
1865
1866 /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D
1867 template<std::size_t NDIM=3>
1869 double mu, double lo, double eps,
1870 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1872 return SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_SLATER),lattice_ranges,k);
1873 }
1874
1875 /// Factory function generating separated kernel for convolution with exp(-mu*r*r)
1876
1877 /// lo and eps are not used here
1878 template<std::size_t NDIM>
1880 double mu, double lo=0.0, double eps=0.0,
1881 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1883 return SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_GAUSS),lattice_ranges,k);
1884 }
1885
1886 /// Factory function generating separated kernel for convolution with exp(-mu*r*r) in 3D
1887
1888 /// lo and eps are not used here
1889 template<std::size_t NDIM>
1891 double mu, double lo=0.0, double eps=0.0,
1892 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1894 return new SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_GAUSS),lattice_ranges,k);
1895 }
1896
1897
1898 /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D
1899 /// Note that the 1/(2mu) factor of SlaterF12Operator is not included, this is just the exponential function
1900 template<std::size_t NDIM>
1902 double mu, double lo, double eps,
1903 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1905 return new SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_SLATER),lattice_ranges,k);
1906 }
1907
1908 /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D
1909 /// Note that the 1/(2mu) factor of SlaterF12Operator is not included, this is just the exponential function
1911 double mu, double lo, double eps,
1912 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1913 int k = FunctionDefaults<3>::get_k()) {
1914 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_SLATER),lattice_ranges,k);
1915 }
1916
1917 /// Factory function generating separated kernel for convolution with (1 - exp(-mu*r))/(2 mu) in 3D
1918
1919 /// includes the factor 1/(2 mu)
1921 double mu, double lo, double eps,
1922 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1924 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F12),lattice_ranges,k);
1925 }
1926
1927
1928 /// Factory function generating separated kernel for convolution with 1/(2 mu)*(1 - exp(-mu*r))/r in 3D
1929
1930 /// fg = (1 - exp(-gamma r12)) / r12 = 1/r12 - exp(-gamma r12)/r12 = coulomb - bsh
1931 /// includes the factor 1/(2 mu)
1932 static inline SeparatedConvolution<double,3>
1933 FGOperator(World& world, double mu, double lo, double eps,
1934 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1936 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_FG12),lattice_ranges,k);
1937 }
1938
1939 /// Factory function generating separated kernel for convolution with 1/(2 mu)*(1 - exp(-mu*r))/r in 3D
1940
1941 /// fg = (1 - exp(-gamma r12)) / r12 = 1/r12 - exp(-gamma r12)/r12 = coulomb - bsh
1942 /// includes the factor 1/(2 mu)
1943 static inline SeparatedConvolution<double,3>*
1944 FGOperatorPtr(World& world, double mu, double lo, double eps,
1945 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1947 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_FG12),lattice_ranges,k);
1948 }
1949
1950 /// Factory function generating separated kernel for convolution with (1/(2 mu)*(1 - exp(-mu*r)))^2/r in 3D
1951
1952 /// f2g = (1/(2 gamma) (1 - exp(-gamma r12)))^2 / r12
1953 /// = 1/(4 gamma) * [ 1/r12 - 2 exp(-gamma r12)/r12 + exp(-2 gamma r12)/r12 ]
1954 /// includes the factor 1/(2 mu)^2
1955 static inline SeparatedConvolution<double,3>*
1956 F2GOperatorPtr(World& world, double mu, double lo, double eps,
1957 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1959 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F2G12),lattice_ranges,k);
1960 }
1961
1962 /// Factory function generating separated kernel for convolution with (1/(2 mu)*(1 - exp(-mu*r)))^2/r in 3D
1963
1964 /// f2g = (1/(2 gamma) (1 - exp(-gamma r12)))^2 / r12
1965 /// = 1/(4 gamma) * [ 1/r12 - 2 exp(-gamma r12)/r12 + exp(-2 gamma r12)/r12 ]
1966 /// includes the factor 1/(2 mu)^2
1967 static inline SeparatedConvolution<double,3>
1968 F2GOperator(World& world, double mu, double lo, double eps,
1969 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1971 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F2G12),lattice_ranges,k);
1972 }
1973
1974
1975 /// Factory function generating separated kernel for convolution a normalized
1976 /// Gaussian (aka a widened delta function)
1978 double eps,
1979 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1981
1982 double exponent = 1.0/(2.0*eps);
1983 Tensor<double> coeffs(1), exponents(1);
1984 exponents(0L) = exponent;
1985 coeffs(0L)=pow(exponent/M_PI,0.5*3.0); // norm of the gaussian
1986 return SeparatedConvolution<double,3>(world, coeffs, exponents, 1.e-8, eps, lattice_ranges, k);
1987 }
1988
1989 /// Factory function generating separated kernel for convolution a normalized
1990 /// Gaussian (aka a widened delta function)
1991 template<std::size_t NDIM>
1993 double eps,
1994 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1996
1997 double exponent = 1.0/(2.0*eps);
1998 Tensor<double> coeffs(1), exponents(1);
1999 exponents(0L) = exponent;
2000 coeffs(0L)=pow(exponent/M_PI,0.5*NDIM); // norm of the gaussian
2001 return SeparatedConvolution<double,NDIM>(world, coeffs, exponents, 1.e-8, eps, lattice_ranges, k);
2002 }
2003
2004 /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D
2005 static
2006 inline
2008 double mu,
2009 double lo,
2010 double eps,
2011 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
2014 double hi = cell_width.normf(); // Diagonal width of cell
2015 // Extend kernel range for lattice summation
2016 // N.B. if have periodic boundaries, extend range just in case will be using periodic domain
2017 const auto lattice_summed_any = std::any_of(lattice_ranges.begin(), lattice_ranges.end(), [](const auto& b) { return static_cast<bool>(b);});
2018 const auto infinite_any = std::any_of(lattice_ranges.begin(), lattice_ranges.end(), [](const auto& b) { return b.infinite();});
2019 if (lattice_summed_any) {
2020 hi *= 100;
2021 }
2022
2023 GFit<double, 3> fit = GFit<double, 3>::BSHFit(mu, lo, hi, eps, false);
2024 Tensor<double> coeff = fit.coeffs();
2025 Tensor<double> expnt = fit.exponents();
2026
2027 if (infinite_any) {
2028 // convolution with Gaussians of exponents <= 0.25/(L^2) contribute only a constant shift
2029 // the largest spacing along lattice summed axes thus controls the smallest Gaussian exponent that NEEDS to be included
2030 double max_lattice_spacing = 0;
2031 for(int d=0; d!=3; ++d) {
2032 if (lattice_ranges[d])
2033 max_lattice_spacing =
2034 std::max(max_lattice_spacing, cell_width(d));
2035 }
2036 // WARNING: discardG0 = true ignores the coefficients of truncated
2037 // terms
2038 fit.truncate_periodic_expansion(coeff, expnt, max_lattice_spacing,
2039 /* discardG0 = */ false);
2040 }
2041 return new SeparatedConvolution<double, 3>(world, coeff, expnt, lo, eps,
2042 lattice_ranges, k);
2043 }
2044
2045
2046 /// Factory function generating operator for convolution with grad(1/r) in 3D
2047
2048 /// Returns a 3-vector containing the convolution operator for the
2049 /// x, y, and z components of grad(1/r)
2050 static
2051 inline
2052 std::vector< std::shared_ptr< SeparatedConvolution<double,3> > >
2054 double lo,
2055 double eps,
2056 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
2059 typedef std::shared_ptr<real_convolution_3d> real_convolution_3d_ptr;
2060 const double pi = constants::pi;
2062 double hi = width.normf(); // Diagonal width of cell
2063 // Extend kernel range for lattice summation
2064 const auto lattice_sum_any = std::any_of(lattice_ranges.begin(), lattice_ranges.end(), [](const LatticeRange& b){ return static_cast<bool>(b); });
2065 if (lattice_sum_any) {
2066 hi *= 100;
2067 }
2068
2070 Tensor<double> coeff = fit.coeffs();
2071 Tensor<double> expnt = fit.exponents();
2072
2073 if (lattice_sum_any) {
2074 fit.truncate_periodic_expansion(coeff, expnt, width.max(), true);
2075 }
2076
2077 int rank = coeff.dim(0);
2078
2079 std::vector<real_convolution_3d_ptr> gradG(3);
2080
2081 for (int dir = 0; dir < 3; dir++) {
2082 std::vector<ConvolutionND<double, 3>> ops(rank);
2083 for (int mu = 0; mu < rank; mu++) {
2084 // We cache the normalized operator so the factor is the value we must multiply by to recover the coeff we want.
2085 double c = std::pow(sqrt(expnt(mu) / pi), 3); // Normalization coeff
2086 ops[mu].setfac(coeff(mu) / c / width[dir]);
2087
2088 for (int d = 0; d < 3; d++) {
2089 if (d != dir)
2091 k, expnt(mu) * width[d] * width[d], 0,
2092 lattice_ranges[d]));
2093 }
2095 k, expnt(mu) * width[dir] * width[dir], 1,
2096 lattice_ranges[dir]));
2097 }
2099 new SeparatedConvolution<double, 3>(world, ops));
2100 }
2101
2102 return gradG;
2103 }
2104
2105 /// Factory function generating operator for convolution with grad(bsh) in 3D
2106
2107 /// Returns a 3-vector containing the convolution operator for the
2108 /// x, y, and z components of grad(bsh)
2109 static
2110 inline
2111 std::vector< std::shared_ptr< SeparatedConvolution<double,3> > >
2113 double mu,
2114 double lo,
2115 double eps,
2116 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
2119 typedef std::shared_ptr<real_convolution_3d> real_convolution_3d_ptr;
2120 const double pi = constants::pi;
2122 double hi = width.normf(); // Diagonal width of cell
2123 // Extend kernel range for lattice summation
2124 bool lattice_sum_any = std::any_of(lattice_ranges.begin(), lattice_ranges.end(), [](const LatticeRange& b){ return b.get_range(); });
2125 if (lattice_sum_any) {
2126 hi *= 100;
2127 }
2128
2129 GFit<double, 3> fit = GFit<double, 3>::BSHFit(mu, lo, hi, eps, false);
2130 Tensor<double> coeff = fit.coeffs();
2131 Tensor<double> expnt = fit.exponents();
2132
2133 if (lattice_sum_any) {
2134 fit.truncate_periodic_expansion(coeff, expnt, width.max(), true);
2135 }
2136
2137 int rank = coeff.dim(0);
2138
2139 std::vector<real_convolution_3d_ptr> gradG(3);
2140
2141 for (int dir = 0; dir < 3; dir++) {
2142 std::vector<ConvolutionND<double, 3>> ops(rank);
2143 for (int mu = 0; mu < rank; mu++) {
2144 // We cache the normalized operator so the factor is the value we must multiply by to recover the coeff we want.
2145 double c = std::pow(sqrt(expnt(mu) / pi), 3); // Normalization coeff
2146 ops[mu].setfac(coeff(mu) / c / width[dir]);
2147
2148 for (int d = 0; d < 3; d++) {
2149 if (d != dir)
2151 k, expnt(mu) * width[d] * width[d], 0,
2152 lattice_ranges[d]));
2153 }
2155 k, expnt(mu) * width[dir] * width[dir], 1,
2156 lattice_ranges[dir]));
2157 }
2159 new SeparatedConvolution<double, 3>(world, ops));
2160 }
2161
2162 return gradG;
2163 }
2164
2165
2166
2167 namespace archive {
2168 template <class Archive, class T, std::size_t NDIM>
2169 struct ArchiveLoadImpl<Archive,const SeparatedConvolution<T,NDIM>*> {
2170 static inline void load(const Archive& ar, const SeparatedConvolution<T,NDIM>*& ptr) {
2172 ar & p;
2173 ptr = static_cast< const SeparatedConvolution<T,NDIM>* >(p);
2174 }
2175 };
2176
2177 template <class Archive, class T, std::size_t NDIM>
2178 struct ArchiveStoreImpl<Archive,const SeparatedConvolution<T,NDIM>*> {
2179 static inline void store(const Archive& ar, const SeparatedConvolution<T,NDIM>*const& ptr) {
2180 ar & static_cast< const WorldObject< SeparatedConvolution<T,NDIM> >* >(ptr);
2181 }
2182 };
2183 }
2184
2185}
2186
2187
2188
2189
2190#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:65
const std::vector< Key< NDIM > > & get_disp(Level n, const array_of_bools< NDIM > &kernel_lattice_sum_axes)
Definition displacements.h:236
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:379
A multiresolution adaptive numerical function.
Definition mra.h:144
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 &)
Definition gentensor.h:217
long rank() const
Definition gentensor.h:212
long size() const
Definition lowranktensor.h:488
SVDTensor< T > & get_svdtensor()
Definition gentensor.h:228
const BaseTensor * ptr() const
might return a NULL pointer!
Definition lowranktensor.h:715
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:70
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:487
const Vector< Translation, NDIM > & translation() const
Definition key.h:174
void break_apart(Key< LDIM > &key1, Key< KDIM > &key2) const
break key into two low-dimensional keys
Definition key.h:424
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:1049
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:1395
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:1114
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:1299
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:1184
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:793
void set_domain_periodicity(const array_of_bools< NDIM > &domain_is_periodic)
Definition operator.h:1120
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:1138
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:1155
virtual ~SeparatedConvolution()
Definition operator.h:1091
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:1204
Timer timer_full
Definition operator.h:164
const array_of_bools< NDIM > & func_domain_is_periodic() const
Definition operator.h:1117
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:976
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:1196
void init_lattice_summed()
Definition operator.h:961
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:1073
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:737
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:807
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:1167
bool doleaves
If should be applied to leaf coefficients ... false by default.
Definition operator.h:146
void print_timer() const
Definition operator.h:1093
SeparatedConvolution(World &world, const std::vector< ConvolutionND< Q, NDIM > > &argops, long k=FunctionDefaults< NDIM >::get_k(), bool doleaves=false)
Definition operator.h:1005
const std::vector< Key< NDIM > > & get_disp(Level n) const
Definition operator.h:1109
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:1681
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:1123
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:1562
void reset_timer() const
Definition operator.h:1101
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:1643
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:931
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:1503
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:1217
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:1173
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:1696
OperatorInfo info
Definition operator.h:144
Key< NDIM > keyT
Definition operator.h:162
void init_range()
Definition operator.h:948
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:870
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:1031
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:888
double munorm2_modified(Level n, const ConvolutionData1D< Q > *ops_1d[]) const
Definition operator.h:674
int & particle()
Definition operator.h:189
static bool can_combine(const SeparatedConvolution< Q, NDIM > &left, const SeparatedConvolution< Q, NDIM > &right)
Definition operator.h:1638
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:841
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:766
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:882
TensorTrain< T > & make_operator()
convert this into an operator representation (r,k',k,r)
Definition tensortrain.h:1187
TensorTrain< T > & make_tensor()
convert this into a tensor representation (r,k,r)
Definition tensortrain.h:1175
A tensor is a multidimensional array.
Definition tensor.h:318
float_scalar_type normf() const
Returns the Frobenius norm of the tensor.
Definition tensor.h:1727
T * ptr()
Returns a pointer to the internal data.
Definition tensor.h:1841
IsSupported< TensorTypeData< Q >, Tensor< T > & >::type scale(Q x)
Inplace multiplication by scalar of supported type (legacy name)
Definition tensor.h:687
T max(long *ind=0) const
Return the maximum value (and if ind is non-null, its index) in the Tensor.
Definition tensor.h:1704
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:491
void process_pending()
To be called from derived constructor to process pending messages.
Definition world_object.h:787
A parallel world class.
Definition world.h:134
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition world.h:344
unsigned long id() const
Definition world.h:324
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
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:1846
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:1814
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:128
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:1992
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:1968
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:1751
static SeparatedConvolution< double_complex, 3 > * PeriodicHFExchangeOperatorPtr(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:1737
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:1792
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:1956
int64_t Translation
Definition key.h:58
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:1910
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:1852
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:1977
static SeparatedConvolution< double, NDIM > * SlaterOperatorPtr_ND(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())
Definition operator.h:1901
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:1920
int Level
Definition key.h:59
@ 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:1720
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:227
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:2112
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:1859
TensorType
low rank representations of tensors (see gentensor.h)
Definition gentensor.h:120
@ TT_2D
Definition gentensor.h:120
NDIM & f
Definition mra.h:2622
static SeparatedConvolution< double, NDIM > SlaterOperator(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 exp(-mu*r) in 3D.
Definition operator.h:1868
GenTensor< T > reduce(std::list< GenTensor< T > > &addends, double, bool=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:1778
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:1764
std::string type(const PairType &n)
Definition PNOParameters.h:18
CCPairFunction< T, NDIM > apply(const SeparatedConvolution< T, NDIM/2 > &op, const CCPairFunction< T, NDIM > &arg)
apply the operator to the argument
Definition ccpairfunction.h:896
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:1933
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:1830
static SeparatedConvolution< double, NDIM > GaussOperator(World &world, double mu, double lo=0.0, double eps=0.0, 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 exp(-mu*r*r)
Definition operator.h:1879
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:2007
static SeparatedConvolution< double, NDIM > * GaussOperatorPtr(World &world, double mu, double lo=0.0, double eps=0.0, 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 exp(-mu*r*r) in 3D.
Definition operator.h:1890
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:1805
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:1944
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:2053
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:2187
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:219
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
World & world
Memoized reference to the world to which this object belongs.
Definition world_object.h:348
World & get_world() const
Definition world_object.h:446
static void load(const Archive &ar, const SeparatedConvolution< T, NDIM > *&ptr)
Definition operator.h:2170
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:2179
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