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 mTxmq(dimi, trans[0].r, dimk, w1, f.ptr(), trans[0].U, dimk);
324
325 size = trans[0].r * size / dimk;
326 dimi = size/dimk;
327 for (std::size_t d=1; d<NDIM; ++d) {
328 mTxmq(dimi, trans[d].r, dimk, w2, w1, trans[d].U, dimk);
329 size = trans[d].r * size / dimk;
330 dimi = size/dimk;
331 std::swap(w1,w2);
332 }
333
334 // If all blocks are full rank we can skip the transposes
335 bool doit = false;
336 for (std::size_t d=0; d<NDIM; ++d) doit = doit || trans[d].VT;
337
338 if (doit) {
339 for (std::size_t d=0; d<NDIM; ++d) {
340 if (trans[d].VT) {
341 dimi = size/trans[d].r;
342 mTxmq(dimi, dimk, trans[d].r, w2, w1, trans[d].VT);
343 size = dimk*size/trans[d].r;
344 }
345 else {
346 fast_transpose(dimk, dimi, w1, w2);
347 }
348 std::swap(w1,w2);
349 }
350 }
351 // Assuming here that result is contiguous and aligned
352 aligned_axpy(size, result.ptr(), w1, mufac);
353 }
354
355
356 /// accumulate into result
357 template <typename T, typename R>
359 const Tensor<T>& f,
360 const Q mufac,
361 Tensor<R>& result) const {
362
363 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
364
365 Tensor<R> result2=general_transform(f,trans2);
366 result2.scale(mufac);
367 result+=result2;
368
369 }
370
371
372
373 /// don't accumulate, since we want to do this at apply()
374 template <typename T, typename R>
375 void apply_transformation2(Level n, long dimk, double tol,
376 const Tensor<T> trans2[NDIM],
377 const GenTensor<T>& f,
378 GenTensor<R>& work1,
379 GenTensor<R>& work2,
380 const Q mufac,
381 GenTensor<R>& result) const {
382
383 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
384
385#if 1
386 result=general_transform(f,trans2);
387 result.scale(mufac);
388
389#else
390
391 long size = 1;
392 for (std::size_t i=0; i<NDIM; ++i) size *= dimk;
393 long dimi = size/dimk;
394
395 R* MADNESS_RESTRICT w1=work1.ptr();
396 R* MADNESS_RESTRICT w2=work2.ptr();
397
398 mTxmq(dimi, trans[0].r, dimk, w1, f.ptr(), trans[0].U, dimk);
399 size = trans[0].r * size / dimk;
400 dimi = size/dimk;
401 for (std::size_t d=1; d<NDIM; ++d) {
402 mTxmq(dimi, trans[d].r, dimk, w2, w1, trans[d].U, dimk);
403 size = trans[d].r * size / dimk;
404 dimi = size/dimk;
405 std::swap(w1,w2);
406 }
407
408 // If all blocks are full rank we can skip the transposes
409 bool doit = false;
410 for (std::size_t d=0; d<NDIM; ++d) doit = doit || trans[d].VT;
411
412 if (doit) {
413 for (std::size_t d=0; d<NDIM; ++d) {
414 if (trans[d].VT) {
415 dimi = size/trans[d].r;
416 mTxmq(dimi, dimk, trans[d].r, w2, w1, trans[d].VT);
417 size = dimk*size/trans[d].r;
418 }
419 else {
420 fast_transpose(dimk, dimi, w1, w2);
421 }
422 std::swap(w1,w2);
423 }
424 }
425 // Assuming here that result is contiguous and aligned
426 aligned_axpy(size, result.ptr(), w1, mufac);
427 // long one = 1;
428 //daxpy_(&size, &mufac, w1, &one, result.ptr(), &one);
429#endif
430 }
431
432
433 /// Apply one of the separated terms, accumulating into the result
434 template <typename T>
436 const ConvolutionData1D<Q>* const ops_1d[NDIM],
437 const Tensor<T>& f, const Tensor<T>& f0,
438 Tensor<TENSOR_RESULT_TYPE(T,Q)>& result,
439 Tensor<TENSOR_RESULT_TYPE(T,Q)>& result0,
440 const double tol,
441 const Q mufac,
442 Tensor<TENSOR_RESULT_TYPE(T,Q)>& work1,
443 Tensor<TENSOR_RESULT_TYPE(T,Q)>& work2) const {
444
445 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
446 Transformation trans[NDIM];
447 Tensor<T> trans2[NDIM];
448
449 double Rnorm = 1.0;
450 for (std::size_t d=0; d<NDIM; ++d) Rnorm *= ops_1d[d]->Rnorm;
451
452 if (at.r_term and (Rnorm > 1.e-20)) {
453
454 const auto tol_Rs = tol/(Rnorm*NDIM); // Errors are relative within here
455
456 // Determine rank of SVD to use or if to use the full matrix
457 long twok = 2*k;
458 if (modified()) twok=k;
459
460 long break_even;
461 if (NDIM==1) break_even = long(0.5*twok);
462 else if (NDIM==2) break_even = long(0.6*twok);
463 else if (NDIM==3) break_even=long(0.65*twok);
464 else break_even=long(0.7*twok);
465 bool rank_is_zero = false;
466 for (std::size_t d=0; d<NDIM; ++d) {
467 long r;
468 for (r=0; r<twok; ++r) {
469 if (ops_1d[d]->Rs[r] < tol_Rs) break;
470 }
471 if (r >= break_even) {
472 trans[d].r = twok;
473 trans[d].U = ops_1d[d]->R.ptr();
474 trans[d].VT = 0;
475 }
476 else {
477
478#ifdef USE_GENTENSOR
479 r = std::max(2L,r+(r&1L)); // (needed for 6D == when GENTENSOR is on) NOLONGER NEED TO FORCE OPERATOR RANK TO BE EVEN
480#endif
481 if (r == 0) {
482 rank_is_zero = true;
483 break;
484 }
485 trans[d].r = r;
486 trans[d].U = ops_1d[d]->RU.ptr();
487 trans[d].VT = ops_1d[d]->RVT.ptr();
488 }
489 trans2[d]=ops_1d[d]->R;
490 }
491
492 if (!rank_is_zero)
493 apply_transformation(twok, trans, f, work1, work2, mufac, result);
494
495 // apply_transformation2(n, twok, tol, trans2, f, work1, work2, mufac, result);
496// apply_transformation3(trans2, f, mufac, result);
497 }
498
499 double Tnorm = 1.0;
500 for (std::size_t d=0; d<NDIM; ++d) Tnorm *= ops_1d[d]->Tnorm;
501
502 if (at.t_term and (Tnorm>0.0)) {
503 const auto tol_Ts = tol/(Tnorm*NDIM); // Errors are relative within here
504
505 long break_even;
506 if (NDIM==1) break_even = long(0.5*k);
507 else if (NDIM==2) break_even = long(0.6*k);
508 else if (NDIM==3) break_even=long(0.65*k);
509 else break_even=long(0.7*k);
510 bool rank_is_zero = false;
511 for (std::size_t d=0; d<NDIM; ++d) {
512 long r;
513 for (r=0; r<k; ++r) {
514 if (ops_1d[d]->Ts[r] < tol_Ts) break;
515 }
516 if (r >= break_even) {
517 trans[d].r = k;
518 trans[d].U = ops_1d[d]->T.ptr();
519 trans[d].VT = 0;
520 }
521 else {
522
523#ifdef USE_GENTENSOR
524 r = std::max(2L,r+(r&1L)); // (needed for 6D == GENTENSOR is USED) NOLONGER NEED TO FORCE OPERATOR RANK TO BE EVEN
525#endif
526 if (r == 0) {
527 rank_is_zero = true;
528 break;
529 }
530 trans[d].r = r;
531 trans[d].U = ops_1d[d]->TU.ptr();
532 trans[d].VT = ops_1d[d]->TVT.ptr();
533 }
534 trans2[d]=ops_1d[d]->T;
535 }
536 if (!rank_is_zero)
537 apply_transformation(k, trans, f0, work1, work2, -mufac, result0);
538// apply_transformation2(n, k, tol, trans2, f0, work1, work2, -mufac, result0);
539// apply_transformation3(trans2, f0, -mufac, result0);
540 }
541 }
542
543
544 /// Apply one of the separated terms, accumulating into the result
545 template <typename T>
547 const ConvolutionData1D<Q>* const ops_1d[NDIM],
548 const GenTensor<T>& f, const GenTensor<T>& f0,
549 GenTensor<TENSOR_RESULT_TYPE(T,Q)>& result,
550 GenTensor<TENSOR_RESULT_TYPE(T,Q)>& result0,
551 double tol,
552 const Q mufac,
553 GenTensor<TENSOR_RESULT_TYPE(T,Q)>& work1,
554 GenTensor<TENSOR_RESULT_TYPE(T,Q)>& work2) const {
555
557// Transformation trans[NDIM];
558 Tensor<T> trans2[NDIM];
559// MADNESS_EXCEPTION("no muopxv_fast2",1);
560
561 double Rnorm = 1.0;
562 for (std::size_t d=0; d<NDIM; ++d) Rnorm *= ops_1d[d]->Rnorm;
563 if (Rnorm == 0.0) return;
564
565 if (Rnorm > 1.e-20) {
566
567 tol = tol/(Rnorm*NDIM); // Errors are relative within here
568
569 // Determine rank of SVD to use or if to use the full matrix
570 long twok = 2*k;
571 if (modified()) twok=k;
572// long break_even;
573// if (NDIM==1) break_even = long(0.5*twok);
574// else if (NDIM==2) break_even = long(0.6*twok);
575// else if (NDIM==3) break_even=long(0.65*twok);
576// else break_even=long(0.7*twok);
577 for (std::size_t d=0; d<NDIM; ++d) {
578 // long r;
579 // for (r=0; r<twok; ++r) {
580 // if (ops_1d[d]->Rs[r] < tol) break;
581 // }
582// if (r >= break_even) {
583// trans[d].r = twok;
584// trans[d].U = ops_1d[d]->R.ptr();
585// trans[d].VT = 0;
586// }
587// else {
588// //r += std::max(2L,r&1L); // NOLONGER NEED TO FORCE OPERATOR RANK TO BE EVEN
589// trans[d].r = r;
590// trans[d].U = ops_1d[d]->RU.ptr();
591// trans[d].VT = ops_1d[d]->RVT.ptr();
592// }
593 trans2[d]=ops_1d[d]->R;
594 }
595 apply_transformation2(n, twok, tol, trans2, f, work1, work2, mufac, result);
596 }
597
598 double Tnorm = 1.0;
599 for (std::size_t d=0; d<NDIM; ++d) Tnorm *= ops_1d[d]->Tnorm;
600
601 if (n > 0 and (Tnorm>1.e-20)) {
602// long break_even;
603//
604// if (NDIM==1) break_even = long(0.5*k);
605// else if (NDIM==2) break_even = long(0.6*k);
606// else if (NDIM==3) break_even=long(0.65*k);
607// else break_even=long(0.7*k);
608 for (std::size_t d=0; d<NDIM; ++d) {
609 // long r;
610 // for (r=0; r<k; ++r) {
611 // if (ops_1d[d]->Ts[r] < tol) break;
612 // }
613// if (r >= break_even) {
614// trans[d].r = k;
615// trans[d].U = ops_1d[d]->T.ptr();
616// trans[d].VT = 0;
617// }
618// else {
619// //r += std::max(2L,r&1L); // NOLONGER NEED TO FORCE OPERATOR RANK TO BE EVEN
620// trans[d].r = r;
621// trans[d].U = ops_1d[d]->TU.ptr();
622// trans[d].VT = ops_1d[d]->TVT.ptr();
623// }
624 trans2[d]=ops_1d[d]->T;
625 }
626 apply_transformation2(n, k, tol, trans2, f0, work1, work2, -mufac, result0);
627 }
628 }
629
630
631 /// Computes the Frobenius norm of one of the separated terms ... WITHOUT FACTOR INCLUDED
632 /// compute for 1 term, all dim, 1 disp, essentially for SeparatedConvolutionInternal
633 double munorm2(Level n, const ConvolutionData1D<Q>* ops[]) const {
634 if (modified()) return munorm2_modified(n,ops);
635 return munorm2_ns(n,ops);
636 }
637
638 /// Computes the Frobenius norm of one of the separated terms for the NS form
639 /// ... WITHOUT FACTOR INCLUDED
640 /// compute for 1 term, all dim, 1 disp, essentially for SeparatedConvolutionInternal
641 double munorm2_ns(Level n, const ConvolutionData1D<Q>* ops[]) const {
642 //PROFILE_MEMBER_FUNC(SeparatedConvolution);
643
644 double prod=1.0, sum=0.0;
645 for (std::size_t d=0; d<NDIM; ++d) {
646 double a = ops[d]->NSnormf;
647 double b = ops[d]->Tnormf;
648 double aa = std::min(a,b);
649 double bb = std::max(a,b);
650 prod *= bb;
651 if (bb > 0.0) sum +=(aa/bb);
652 }
653 if (n) prod *= sum;
654
655 return prod;
656 }
657
658
659 /// Computes the operator norm of one of the separated terms of the modified NS form
660 /// ... WITHOUT FACTOR INCLUDED
661 /// compute for 1 term, all dim, 1 disp, essentially for SeparatedConvolutionInternal
662 double munorm2_modified(Level n, const ConvolutionData1D<Q>* ops_1d[]) const {
664
665 // follows Eq. (21) ff of Beylkin 2008 (Beylkin Appl. Comput. Harmon. Anal. 24, pp 354)
666
667 // we have all combinations of difference, upsampled, F terms (d, u, f),
668 // with the constraint that d is in each term exactly once. In the mixed terms (udf)
669 // we just get all possible combinations, in the pure terms (dff, duu) we have
670 // to multiply each term (dff, fdf, ffd) with (NDIM-1)!, to get the right number.
671
672 double dff = 0.0;
673 double duu = 0.0;
674 double udf = 0.0;
675
676 // loop over d shifting over the dimensions dxx, xdx, xxd,
677 for (size_t d=0; d<NDIM; ++d) {
678 double dff_tmp = ops_1d[d]->N_diff;
679 double duu_tmp = ops_1d[d]->N_diff;
680 double udf_tmp = ops_1d[d]->N_diff;
681
682
683 for (size_t dd=0; dd<NDIM; ++dd) {
684 if (dd!=d) {
685 dff_tmp *= ops_1d[dd]->N_F;
686 duu_tmp *= ops_1d[dd]->N_up;
687
688 udf_tmp *= ops_1d[dd]->N_F;
689 for (size_t ddd=0; ddd<NDIM; ++ddd) {
690 if (ddd!=dd) udf += udf_tmp * ops_1d[ddd]->N_up;
691 }
692 }
693 }
694
695 dff+=dff_tmp;
696 duu+=duu_tmp;
697 }
698
699 // finalize with the factorial
700 double factorial=1.0;
701 for (int i=1; i<static_cast<int>(NDIM)-1; ++i) factorial*=double(i);
702 dff*=factorial;
703 duu*=factorial;
704
705 // Eq. (23) of Beylkin 2008, for one separated term WITHOUT the factor
706 double norm=(dff + udf + duu) /(factorial * double(NDIM));
707
708// // double check
709// if (NDIM==3) {
710// Tensor<Q> R_full=outer(ops_1d[0]->R,outer(ops_1d[1]->R,ops_1d[2]->R));
711// Tensor<Q> T_full=outer(ops_1d[0]->T,outer(ops_1d[1]->T,ops_1d[2]->T));
712// double n2=(R_full-T_full).normf();
713//// print("norm estimate, norm",norm, n2, norm<n2);
714// norm=n2;
715// }
716
717 return norm;
718
719 }
720
721
722 /// get the transformation matrices for 1 term and all dimensions and one displacement
723
724 /// use ConvolutionND, which uses ConvolutionData1D to collect the transformation matrices
726 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
728 for (std::size_t d=0; d<NDIM; ++d) {
729 op.ops[d] = ops[mu].getop(d)->nonstandard(n, disp.translation()[d]);
730 }
731 op.norm = munorm2(n, op.ops)*std::abs(ops[mu].getfac());
732
733// double newnorm = munorm2(n, op.ops);
734// // This rescaling empirically based upon BSH separated expansion
735// // ... needs more testing. OK also for TDSE.
736// // All is good except for some 000 blocks which are up to sqrt(k^d) off.
737// for (int d=0; d<NDIM; ++d) {
738// if (disp[d] == 0) newnorm *= 0.5;
739// else if (std::abs(disp[d]) == 1) newnorm *= 0.8;
740// }
741// double oldnorm = munorm(n, op.ops);
742// if (oldnorm > 1e-13 && (newnorm < 0.5*oldnorm || newnorm > 2.0*oldnorm) )
743// print("munorm", n, disp, mu, newnorm, oldnorm, newnorm/oldnorm);
744
745 return op;
746 }
747
748
749
750 /// get the transformation matrices for 1 term and all dimensions and one displacement
751
752 /// use ConvolutionND, which uses ConvolutionData1D to collect the transformation matrices
754 getmuop_modified(int mu, Level n, const Key<NDIM>& disp, const Key<NDIM>& source) const {
755 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
756
757
758 // SeparatedConvolutionInternal keeps data for 1 term and all dimensions
760
761 // in the modified NS form we need not only the displacement, but also the source Translation
762 // for correctly constructing the operator, b/c the operator is not Toeplitz
763
764 // op.ops is of type ConvolutionData1D (1 term, 1 dim, 1 disp)
765 // ops[mu] is of type ConvolutionND (1 term, all dim, 1 disp)
766 for (std::size_t d=0; d<NDIM; ++d) {
767 Translation sx=source.translation()[d]; // source translation
768 Translation tx=source.translation()[d]+disp.translation()[d]; // target translation
769
770 Key<2> op_key(n,Vector<Translation,2>{sx,tx});
771 op.ops[d] = ops[mu].getop(d)->mod_nonstandard(op_key);
772 }
773
774 // works for both modified and not modified NS form
775 op.norm = munorm2(n, op.ops)*std::abs(ops[mu].getfac());
776// op.norm=1.0;
777 return op;
778 }
779
780 /// get the data for all terms and all dimensions for one displacement
782
783 // in the NS form the operator depends only on the displacement
784 if (not modified()) return getop_ns(n,d);
785 return getop_modified(n, d, source);
786 }
787
788
789 /// get the data for all terms and all dimensions for one displacement
790
791 /// uses SeparatedConvolutionInternal (ConvolutionND, ConvolutionData1D) to construct
792 /// the transformation matrices.
793 /// @param[in] d displacement
794 /// @return pointer to cached operator
796 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
797 const SeparatedConvolutionData<Q,NDIM>* p = data.getptr(n,d);
798 if (p) return p;
799
800 // get the data for each term
802 for (int mu=0; mu<rank; ++mu) {
803 // op.muops is of type SeparatedConvolutionInternal (1 term, all dim, 1 disp)
804 // getmuop uses ConvolutionND
805 op.muops[mu] = getmuop(mu, n, d);
806 }
807
808 double norm = 0.0;
809 for (int mu=0; mu<rank; ++mu) {
810 const double munorm = op.muops[mu].norm;
811 norm += munorm*munorm;
812 }
813 //print("getop", n, d, norm);
814 op.norm = sqrt(norm);
815 data.set(n, d, op);
816 return data.getptr(n,d);
817 }
818
819
820
821 /// get the data for all terms and all dimensions for one displacement (modified NS form)
822
823 /// remember that the operator in the modified NS form is not Toeplitz, so we need
824 /// information about the displacement and the source key
825 /// @param[in] n level (=scale) (actually redundant, since included in source)
826 /// @param[in] disp displacement key
827 /// @param[in] source source key
828 /// @return pointer to cached operator
830 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
831
832 // in the modified NS form the upsampled part of the operator depends on the modulus of the source
833 Vector<Translation,NDIM> t=source.translation();
834 for (size_t i=0; i<NDIM; ++i) t[i]=t[i]%2;
835 Key<2*NDIM> key=disp.merge_with(Key<NDIM>(source.level(),t));
836
837 const SeparatedConvolutionData<Q,NDIM>* p = mod_data.getptr(n,key);
838 if (p) return p;
839
840 // get the data for each term
841 // op.muops is of type SeparatedConvolutionInternal (1 term, all dim, 1 disp)
842 // getmuop uses ConvolutionND
844 for (int mu=0; mu<rank; ++mu) op.muops[mu] = getmuop_modified(mu, n, disp, source);
845
846 double norm = 0.0;
847 for (int mu=0; mu<rank; ++mu) {
848 const double munorm = op.muops[mu].norm;
849 norm += munorm*munorm;
850 }
851
852 op.norm = sqrt(norm);
853 mod_data.set(n, key, op);
854 return mod_data.getptr(n,key);
855 }
856
857
858 void check_cubic() {
859 // !!! NB ... cell volume obtained from global defaults
861 // Check that the cell is cubic since currently is assumed
862 for (std::size_t d=1; d<NDIM; ++d) {
863 MADNESS_CHECK(fabs(cell_width(d)-cell_width(0L)) < 1e-14*cell_width(0L));
864 }
865 }
866
867
868 /// upsample some of the dimensions of coeff to its child indicated by key
869
870 /// @param[in] coeff the coeffs of dim 2*NDIM that will be upsampled
871 /// @param[in] key the key indicating the child -- only some dimensions will be "reproductive"
872 /// @param[in] particle if 0: upsample dimensions 0-2
873 /// if 1: upsample dimensions 3-5
874 /// @return a partially upsampled coefficient tensor
875 template<typename T, size_t FDIM>
876 GenTensor<T> partial_upsample(const Key<FDIM>& key, const GenTensor<T>& coeff, const int particle) const {
877
878 if (coeff.rank()==0) return GenTensor<T>();
879 MADNESS_ASSERT(coeff.dim(0)==k);
880 if (NDIM==coeff.ndim()) {
881 MADNESS_ASSERT(particle==1); // other particle, leave this particle unchanged
882 return coeff;
883 }
884
885 MADNESS_ASSERT(coeff.ndim()==FDIM);
886 MADNESS_ASSERT(particle==0 or (2*NDIM==FDIM));
887
888 // the twoscale coefficients: for upsampling use h0/h1; see Alpert Eq (3.35a/b)
889 // handle the spectator dimensions with the identity matrix
890 const Tensor<T> h[2] = {cdata.h0, cdata.h1};
891 Tensor<T> identity(k,k);
892 for (int i=0; i<k; ++i) identity(i,i)=1.0;
893 Tensor<T> matrices[2*NDIM];
894
895 // get the appropriate twoscale coefficients for each dimension
896 if (particle==0) {
897 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii]=h[key.translation()[ii]%2];
898 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii+NDIM]=identity;
899 } else if (particle==1) {
900 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii]=identity;
901 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii+NDIM]=h[key.translation()[ii+NDIM]%2];
902 } else {
903 MADNESS_EXCEPTION("unknown particle",1);
904 }
905
906 // transform and accumulate on the result
907 const GenTensor<T> result=general_transform(coeff,matrices);
908 return result;
909 }
910
911
912 /// upsample the sum coefficients of level 1 to sum coeffs on level n+1
913
914 /// specialization of the unfilter method, will transform only the sum coefficients
915 /// @param[in] key key of level n+1
916 /// @param[in] coeff sum coefficients of level n (does NOT belong to key!!)
917 /// @return sum coefficients on level n+1
918 template<typename T, size_t FDIM>
919 GenTensor<T> upsample(const Key<FDIM>& key, const GenTensor<T>& coeff) const {
920
921 // the twoscale coefficients: for upsampling use h0/h1; see Alpert Eq (3.35a/b)
922 // note there are no difference coefficients; if you want that use unfilter
923 const Tensor<T> h[2] = {cdata.h0, cdata.h1};
924 Tensor<T> matrices[FDIM];
925
926 // get the appropriate twoscale coefficients for each dimension
927 for (size_t ii=0; ii<FDIM; ++ii) matrices[ii]=h[key.translation()[ii]%2];
928
929 // transform and accumulate on the result
930 const GenTensor<T> result=general_transform(coeff,matrices);
931 return result;
932 }
933
934 /// initializes range using range of ops[0]
935 /// @pre `ops[i].range == ops[0].range`
936 void init_range() {
937 if (!ops.empty()) {
938 for (int d = 0; d != NDIM; ++d) {
939 for(const auto & op: ops) {
940 MADNESS_ASSERT(op.getop(d)->range == ops[0].getop(d)->range);
941 }
942 range[d] = ops[0].getop(d)->range;
943 }
944 }
945 }
946
947 /// initializes lattice_sum using `ops[0].lattice_summed()`
948 /// @pre `ops[i].lattice_summed() == ops[0].lattice_summed()`
950 if (!ops.empty()) {
951 for (int d = 0; d != NDIM; ++d) {
952 for (const auto &op : ops) {
953 MADNESS_ASSERT(op.lattice_summed() ==
954 ops[0].lattice_summed());
955 }
956 lattice_summed_ = ops[0].lattice_summed();
957 }
958 }
959 }
960
961 public:
962
963 // For separated convolutions with same operator in each direction (isotropic)
965 const std::vector< std::shared_ptr< Convolution1D<Q> > >& argops,
967 bool doleaves = false)
969 , info()
971 , lattice_summed_(false) // this will be overridden by init_lattice_summed below
972 , modified_(false)
973 , particle_(1)
974 , destructive_(false)
975 , k(k)
977 , rank(argops.size())
978 , vk(NDIM,k)
979 , v2k(NDIM,2*k)
980 , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1))
981 {
982
983 for (unsigned int mu=0; mu < argops.size(); ++mu) {
984 this->ops.push_back(ConvolutionND<Q,NDIM>(argops[mu]));
985 }
986 init_range();
988
989 this->process_pending();
990 }
991
992 // For general convolutions
994 const std::vector< ConvolutionND<Q,NDIM> >& argops,
996 bool doleaves = false)
998 , info()
1000 , lattice_summed_(false) // this will be overridden by init_lattice_summed below
1001 , modified_(false)
1002 , particle_(1)
1003 , destructive_(false)
1004 , ops(argops)
1005 , k(k)
1006 , cdata(FunctionCommonData<Q,NDIM>::get(k))
1007 , rank(argops.size())
1008 , vk(NDIM,k)
1009 , v2k(NDIM,2*k)
1010 , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1))
1011 {
1012 init_range();
1014 this->process_pending();
1015 }
1016
1017 /// Constructor for Gaussian Convolutions
1018 /// WARNING! bloch_k should only ever be nonzero if `Q` is a complex type.
1020 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1022 bool doleaves = false,
1023 const Vector<double, NDIM>& bloch_k = Vector<double, NDIM>(0.0))
1024 : SeparatedConvolution(world,Tensor<double>(0l),Tensor<double>(0l),info1.lo,info1.thresh,lattice_ranges,k,doleaves,info1.mu) {
1025 info.type=info1.type;
1027 info.range = info1.range;
1028 auto [coeff, expnt] = make_coeff_for_operator(world, info, lattice_ranges);
1029 rank=coeff.dim(0);
1030 range = info.template range_as_array<NDIM>();
1031 ops.resize(rank);
1032 initialize(coeff,expnt,lattice_ranges,range,bloch_k);
1034 }
1035
1036 /// Constructor for Gaussian Convolutions (mostly for backward compatability)
1038 const Tensor<Q>& coeff, const Tensor<double>& expnt,
1039 double lo, double thresh,
1040 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1042 bool doleaves = false,
1043 double mu=0.0)
1047 ,
1048 lattice_summed_(false) // will be updated by init_lattice_summed
1049 , ops(coeff.dim(0))
1050 , k(k)
1051 , cdata(FunctionCommonData<Q,NDIM>::get(k))
1052 , rank(coeff.dim(0))
1053 , vk(NDIM,k)
1054 , v2k(NDIM,2*k)
1055 , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1)) {
1056 initialize(coeff,expnt,lattice_ranges);
1057 init_range();
1059 }
1060
1061 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)) {
1063 const double pi = constants::pi;
1064
1065 for (int mu=0; mu<rank; ++mu) {
1066 Q c = std::pow(sqrt(expnt(mu)/pi),static_cast<int>(NDIM)); // Normalization coeff
1067
1068 // We cache the normalized operator so the factor is the value we must multiply
1069 // by to recover the coeff we want.
1070 ops[mu].setfac(coeff(mu)/c);
1071
1072 for (std::size_t d=0; d<NDIM; ++d) {
1073 ops[mu].setop(d,GaussianConvolution1DCache<Q>::get(k, expnt(mu)*width[d]*width[d], 0,
1074 lattice_range[d], bloch_k[d], range[d]));
1075 }
1076 }
1077 }
1078
1080
1081 void print_timer() const {
1082 if (this->get_world().rank()==0) {
1083 timer_full.print("op full tensor ");
1084 timer_low_transf.print("op low rank transform");
1085 timer_low_accumulate.print("op low rank addition ");
1086 }
1087 }
1088
1089 void reset_timer() const {
1090 if (this->get_world().rank()==0) {
1091 timer_full.reset();
1094 }
1095 }
1096
1097 const std::vector< Key<NDIM> >& get_disp(Level n) const {
1099 }
1100
1101 /// @return flag for each axis indicating whether lattice summation is performed in that direction
1103 /// @return flag for each axis indicating whether functions that this op acts on are periodic on the box in that direction (false by default)
1104 /// it is normally preferred to lattice sum, obtaining an equivalent problem with a lattice-summed operator on a non-periodic function
1106 /// changes domain periodicity
1107 /// \param domain_is_periodic
1108 void set_domain_periodicity(const array_of_bools<NDIM>& domain_is_periodic) { func_domain_is_periodic_ = domain_is_periodic;}
1109
1110 /// return the operator norm for all terms, all dimensions and 1 displacement
1111 double norm(Level n, const Key<NDIM>& d, const Key<NDIM>& source_key) const {
1112 // SeparatedConvolutionData keeps data for all terms and all dimensions and 1 displacement
1113// return 1.0;
1114 return getop(n, d, source_key)->norm;
1115 }
1116
1117 /// return that part of a hi-dim key that serves as the base for displacements of this operator
1118
1119 /// if the function and the operator have the same dimension return key
1120 /// if the function has a higher dimension than the operator (e.g. in the exchange operator)
1121 /// return only that part of key that corresponds to the particle this operator works on
1122 /// @param[in] key hi-dim key
1123 /// @return a lo-dim part of key; typically first or second half
1124 template<size_t FDIM>
1125 typename std::enable_if<FDIM!=NDIM, Key<NDIM> >::type
1126 get_source_key(const Key<FDIM> key) const {
1128 Key<FDIM-NDIM> dummykey;
1129 if (particle()==1) key.break_apart(source,dummykey);
1130 if (particle()==2) key.break_apart(dummykey,source);
1131 return source;
1132 }
1133
1134 /// return that part of a hi-dim key that serves as the base for displacements of this operator
1135
1136 /// if the function and the operator have the same dimension return key
1137 /// if the function has a higher dimension than the operator (e.g. in the exchange operator)
1138 /// return only that part of key that corresponds to the particle this operator works on
1139 /// @param[in] key hi-dim key
1140 /// @return a lo-dim part of key; typically first or second half
1141 template<size_t FDIM>
1142 typename std::enable_if<FDIM==NDIM, Key<NDIM> >::type
1143 get_source_key(const Key<FDIM> key) const {
1144 return key;
1145 }
1146
1147 /// apply this operator on a function f
1148
1149 /// the operator does not need to have the same dimension as the function, e,g,
1150 /// the Poisson kernel for the exchange operator acts only on 1 electron of a
1151 /// given (pair) function.
1152 /// @param[in] f a function of same or different dimension as this operator
1153 /// @return the result function of the same dimensionality as the input function f
1154 template <typename T, size_t FDIM>
1156 return madness::apply(*this, f);
1157 }
1158
1159 /// apply this on a vector of functions
1160 template <typename T, size_t FDIM>
1161 std::vector<Function<TENSOR_RESULT_TYPE(T,Q),FDIM>> operator()(const std::vector<Function<T,FDIM>>& f) const {
1162 return madness::apply(*this, f);
1163 }
1164
1165 /// apply this operator on a separable function f(1,2) = f(1) f(2)
1166
1167 /// @param[in] f1 a function of dim LDIM
1168 /// @param[in] f2 a function of dim LDIM
1169 /// @return the result function of dim NDIM=2*LDIM: g(1,2) = G(1,1',2,2') f(1',2')
1170 template <typename T, size_t LDIM>
1171 Function<TENSOR_RESULT_TYPE(T,Q),LDIM+LDIM>
1173 return madness::apply(*this, std::vector<Function<Q,LDIM>>({f1}),
1174 std::vector<Function<Q,LDIM>>({f2}));
1175 }
1176
1177 /// apply this operator on a sum of separable functions f(1,2) = \sum_i f_i(1) f_i(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>
1184 operator()(const std::vector<Function<T,LDIM>>& f1, const std::vector<Function<Q,LDIM>>& f2) const {
1185 return madness::apply(*this, f1, f2);
1186 }
1187
1188 /// apply this onto another suitable argument, returning the same type
1189
1190 /// argT must implement argT::apply(const SeparatedConvolution& op, const argT& arg)
1191 template<typename argT>
1192 argT operator()(const argT& argument) const {
1193 return madness::apply(*this,argument);
1194 }
1195
1196
1197 /// apply this operator on coefficients in full rank form
1198
1199 /// @param[in] coeff source coeffs in full rank
1200 /// @param[in] source the source key
1201 /// @param[in] shift the displacement, where the source coeffs come from
1202 /// @param[in] tol thresh/#neigh*cnorm
1203 /// @return a tensor of full rank with the result op(coeff)
1204 template <typename T>
1206 const Key<NDIM>& shift,
1207 const Tensor<T>& coeff,
1208 double tol) const {
1209 //PROFILE_MEMBER_FUNC(SeparatedConvolution); // Too fine grain for routine profiling
1210 MADNESS_ASSERT(coeff.ndim()==NDIM);
1211
1212 double cpu0=cpu_time();
1213
1214 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
1215 const Tensor<T>* input = &coeff;
1216 Tensor<T> dummy;
1217
1218 if (not modified()) {
1219 if (coeff.dim(0) == k) {
1220 // This processes leaf nodes with only scaling
1221 // coefficients ... FuncImpl::apply by default does not
1222 // apply the operator to these since for smoothing operators
1223 // it is not necessary. It is necessary for operators such
1224 // as differentiation and time evolution and will also occur
1225 // if the application of the operator widens the tree.
1226 dummy = Tensor<T>(v2k);
1227 dummy(s0) = coeff;
1228 input = &dummy;
1229 }
1230 else {
1231 MADNESS_ASSERT(coeff.dim(0)==2*k);
1232 }
1233 }
1234
1235 tol = 0.01*tol/rank; // Error is per separated term
1236 ApplyTerms at;
1237 at.r_term=true;
1238 at.t_term=(source.level()>0);
1239
1240 /// SeparatedConvolutionData keeps data for all terms and all dimensions and 1 displacement
1242
1243 //print("sepop",source,shift,op->norm,tol);
1244
1245 Tensor<resultT> r(v2k), r0(vk);
1246 Tensor<resultT> work1(v2k,false), work2(v2k,false);
1247
1248 if (modified()) {
1250 work1=Tensor<resultT>(vk,false);
1251 work2=Tensor<resultT>(vk,false);
1252 }
1253
1254 const Tensor<T> f0 = copy(coeff(s0));
1255 for (int mu=0; mu<rank; ++mu) {
1256 // SeparatedConvolutionInternal keeps data for 1 term and all dimensions and 1 displacement
1257 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1258 if (muop.norm > tol) {
1259 // ops is of ConvolutionND, returns data for 1 term and all dimensions
1260 Q fac = ops[mu].getfac();
1261 muopxv_fast(at, muop.ops, *input, f0, r, r0, tol/std::abs(fac), fac,
1262 work1, work2);
1263 }
1264 }
1265
1266 r(s0).gaxpy(1.0,r0,1.0);
1267 double cpu1=cpu_time();
1268 timer_full.accumulate(cpu1-cpu0);
1269
1270 return r;
1271 }
1272
1273
1274 /// apply this operator on only 1 particle of the coefficients in low rank form
1275
1276 /// note the unfortunate mess with NDIM: here NDIM is the operator dimension, and FDIM is the
1277 /// function's dimension, whereas in the function we have OPDIM for the operator and NDIM for
1278 /// the function
1279 /// @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.
1280 /// @param[in] coeff source coeffs in SVD (=optimal!) form, in high dimensionality (FDIM)
1281 /// @param[in] source the source key in low dimensionality (NDIM)
1282 /// @param[in] shift the displacement in low dimensionality (NDIM)
1283 /// @param[in] tol thresh/(#neigh*cnorm)
1284 /// @param[in] tol2 thresh/#neigh
1285 /// @return coeff result
1286 template<typename T>
1288 const Key<NDIM>& shift, const GenTensor<T>& coeff, double tol, double tol2) const {
1289
1290 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
1291
1292 // prepare access to the singular vectors
1293 const SVDTensor<T>& svdcoeff=coeff.get_svdtensor();
1294// std::vector<Slice> s(coeff.config().dim_per_vector()+1,_);
1295 std::vector<Slice> s(svdcoeff.dim_per_vector(particle()-1)+1,_);
1296 // can't use predefined slices and vectors -- they have the wrong dimension
1297 const std::vector<Slice> s00(coeff.ndim(),Slice(0,k-1));
1298
1299 // some checks
1300 MADNESS_ASSERT(coeff.is_svd_tensor()); // for now
1301 MADNESS_ASSERT(not modified());
1303 MADNESS_ASSERT(coeff.dim(0)==2*k);
1304 MADNESS_ASSERT(2*NDIM==coeff.ndim());
1305
1306 double cpu0=cpu_time();
1308
1309 // some workspace
1310 Tensor<resultT> work1(v2k,false), work2(v2k,false);
1311
1312 // sliced input and final result
1313 const GenTensor<T> f0 = copy(coeff(s00));
1314 GenTensor<resultT> final=copy(coeff);
1315 GenTensor<resultT> final0=copy(f0);
1316
1317 tol = tol/rank*0.01; // Error is per separated term
1318 tol2= tol2/rank;
1319
1320 // the operator norm is missing the identity working on the other particle
1321 // use as (muop.norm*exchange_norm < tol)
1322 // for some reason the screening is not working at all..
1323// double exchange_norm=std::pow(2.0*k,1.5);
1324
1325 for (int r=0; r<coeff.rank(); ++r) {
1326
1327 // get the appropriate singular vector (left or right depends on particle)
1328 // and apply the full tensor muopxv_fast on it, term by term
1329 s[0]=Slice(r,r);
1330 const Tensor<T> chunk=svdcoeff.ref_vector(particle()-1)(s).reshape(v2k);
1331 const Tensor<T> chunk0=f0.get_svdtensor().ref_vector(particle()-1)(s).reshape(vk);
1332// const double weight=std::abs(coeff.config().weights(r));
1333
1334 // accumulate all terms of the operator for a specific term of the function
1335 Tensor<resultT> result(v2k), result0(vk);
1336
1337 ApplyTerms at;
1338 at.r_term=true;
1339 at.t_term=source.level()>0;
1340
1341 // this loop will return on result and result0 the terms [(P+Q) G (P+Q)]_1,
1342 // and [P G P]_1, respectively
1343 for (int mu=0; mu<rank; ++mu) {
1344 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1345 Q fac = ops[mu].getfac();
1346 muopxv_fast(at, muop.ops, chunk, chunk0, result, result0,
1347 tol/std::abs(fac), fac, work1, work2);
1348 }
1349
1350 // reinsert the transformed terms into result, leaving the other particle unchanged
1351 MADNESS_ASSERT(final.get_svdtensor().has_structure());
1352 final.get_svdtensor().ref_vector(particle()-1)(s)=result;
1353
1354 if (source.level()>0) {
1355 final0.get_svdtensor().ref_vector(particle()-1)(s)=result0;
1356 } else {
1357 final0.get_svdtensor().ref_vector(0)(s)=0.0;
1358 final0.get_svdtensor().ref_vector(1)(s)=0.0;
1359 }
1360
1361 }
1362 double cpu1=cpu_time();
1363 timer_low_transf.accumulate(cpu1-cpu0);
1364
1365 double cpu00=cpu_time();
1366
1367 final.reduce_rank(tol2*0.5);
1368 final0.reduce_rank(tol2*0.5);
1369 final(s00)+=final0;
1370 final.reduce_rank(tol2);
1371
1372 double cpu11=cpu_time();
1373 timer_low_accumulate.accumulate(cpu11-cpu00);
1374 return final;
1375 }
1376
1377 /// apply this operator on coefficients in low rank form
1378
1379 /// @param[in] coeff source coeffs in SVD (=optimal!) form
1380 /// @param[in] tol thresh/#neigh*cnorm
1381 /// @param[in] tol2 thresh/#neigh
1382 template <typename T>
1384 const Key<NDIM>& shift,
1385 const GenTensor<T>& coeff,
1386 double tol, double tol2) const {
1388 typedef TENSOR_RESULT_TYPE(T,Q) resultT;
1389
1390 MADNESS_ASSERT(coeff.ndim()==NDIM);
1391 MADNESS_ASSERT(coeff.is_svd_tensor()); // we use the rank below
1392// MADNESS_EXCEPTION("no apply2",1);
1393 const TensorType tt=TT_2D;
1394
1395 const GenTensor<T>* input = &coeff;
1396 GenTensor<T> dummy;
1397
1398 if (not modified()) {
1399 if (coeff.dim(0) == k) {
1400 // This processes leaf nodes with only scaling
1401 // coefficients ... FuncImpl::apply by default does not
1402 // apply the operator to these since for smoothing operators
1403 // it is not necessary. It is necessary for operators such
1404 // as differentiation and time evolution and will also occur
1405 // if the application of the operator widens the tree.
1406 dummy = GenTensor<T>(v2k,TT_2D);
1407 dummy(s0) += coeff;
1408 input = &dummy;
1409 }
1410 else {
1411 MADNESS_ASSERT(coeff.dim(0)==2*k);
1412 }
1413 }
1414
1415 tol = tol/rank; // Error is per separated term
1416 tol2= tol2/rank;
1417
1419
1420 GenTensor<resultT> r, r0, result, result0;
1421 GenTensor<resultT> work1(v2k,tt), work2(v2k,tt);
1422
1423 if (modified()) {
1424 r=GenTensor<resultT>(vk,tt);
1425 work1=GenTensor<resultT>(vk,tt);
1426 work2=GenTensor<resultT>(vk,tt);
1427 }
1428
1429 // collect the results of the individual operator terms
1430 std::list<GenTensor<T> > r_list;
1431 std::list<GenTensor<T> > r0_list;
1432
1433// const GenTensor<T> f0 = copy(coeff(s0));
1434 const GenTensor<T> f0 = copy((*input)(s0));
1435 for (int mu=0; mu<rank; ++mu) {
1436 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1437 //print("muop",source, shift, mu, muop.norm);
1438
1439 // delta(g) < delta(T) * || f ||
1440 if (muop.norm > tol) {
1441
1442 // get maximum rank of coeff to contribute:
1443 // delta(g) < eps < || T || * delta(f)
1444 // delta(coeff) * || T || < tol2
1445 const int r_max=SRConf<T>::max_sigma(tol2/muop.norm,coeff.rank(),coeff.get_svdtensor().weights_);
1446 // print("r_max",coeff.config().weights(r_max));
1447
1448 // note that max_sigma is inclusive!
1449 if (r_max>=0) {
1450 const GenTensor<resultT> chunk=SVDTensor<resultT>(input->get_svdtensor().get_configs(0,r_max));
1451 const GenTensor<resultT> chunk0=SVDTensor<resultT>(f0.get_svdtensor().get_configs(0,r_max));
1452
1453 double cpu0=cpu_time();
1454
1455 Q fac = ops[mu].getfac();
1456 muopxv_fast2(source.level(), muop.ops, chunk, chunk0, r, r0,
1457 tol/std::abs(fac), fac, work1, work2);
1458 double cpu1=cpu_time();
1459 timer_low_transf.accumulate(cpu1-cpu0);
1460
1461 r_list.push_back(r);
1462 r0_list.push_back(r0);
1463 }
1464 }
1465 }
1466
1467 // finally accumulate all the resultant terms into one tensor
1468 double cpu0=cpu_time();
1469
1470 result0=reduce(r0_list,tol2*rank);
1471 if (r_list.size()>0) r_list.front()(s0)+=result0;
1472 result=reduce(r_list,tol2*rank);
1473// result.reduce_rank(tol2*rank);
1474
1475 double cpu1=cpu_time();
1478 return result;
1479 }
1480
1481 /// estimate the ratio of cost of full rank versus low rank
1482
1483 /// @param[in] source source key
1484 /// @param[in] shift displacement
1485 /// @param[in] tol thresh/#neigh/cnorm
1486 /// @param[in] tol2 thresh/#neigh
1487 /// @return cost_ratio r=-1: no terms left
1488 /// 0<r<1: better to do full rank
1489 /// 1<r: better to do low rank
1490 template<typename T>
1492 const Key<NDIM>& shift,
1493 const GenTensor<T>& coeff,
1494 double tol, double tol2) const {
1495
1496 if (coeff.is_full_tensor()) return 0.5;
1497 if (2*NDIM==coeff.ndim()) return 1.5;
1498 MADNESS_ASSERT(NDIM==coeff.ndim());
1500
1502
1503 tol = tol/rank; // Error is per separated term
1504 tol2= tol2/rank;
1505
1506 const double full_operator_cost=pow(coeff.dim(0),NDIM+1);
1507 const double low_operator_cost=pow(coeff.dim(0),NDIM/2+1);
1508 const double low_reduction_cost=pow(coeff.dim(0),NDIM/2);
1509
1510 double full_cost=0.0;
1511 double low_cost=0.0;
1512
1513 long initial_rank=0;
1514 long final_rank=sqrt(coeff.size())*0.05; // size=ncol*nrow; final rank is 5% of max rank
1515
1516 for (int mu=0; mu<rank; ++mu) {
1517 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1518
1519 // delta(g) < delta(T) * || f ||
1520 if (muop.norm > tol) {
1521 // note that max_sigma is inclusive: it returns a slice w(Slice(0,i))
1522 long nterms=SRConf<T>::max_sigma(tol2/muop.norm,coeff.rank(),coeff.get_svdtensor().weights_)+1;
1523
1524 // take only the first overlap computation of rank reduction into account
1525// low_cost+=nterms*low_operator_cost + 2.0*nterms*nterms*low_reduction_cost;
1526 initial_rank+=nterms;
1527
1528 full_cost+=full_operator_cost;
1529 }
1530 }
1531 low_cost=initial_rank*low_operator_cost + initial_rank*final_rank*low_reduction_cost;
1532
1533 // include random empirical factor of 2
1534 double ratio=-1.0;
1535 if (low_cost>0.0) ratio=full_cost/low_cost;
1536// print("nterms, full, low, full/low", full_cost, low_cost,shift.distsq(), ratio);
1537 return ratio;
1538
1539 }
1540
1541 /// construct the tensortrain representation of the operator
1542
1543 /// @param[in] source source coefficient box
1544 /// @param[in] shift displacement
1545 /// @param[in] tol threshold for the TT truncation
1546 /// @param[in] do_R compute the R term of the operator (2k^d)
1547 /// @param[in] do_T compute the T term of the operator (k^d), including factor -1
1548 /// Both do_R and do_T may be used simultaneously, then the final
1549 /// operator will have dimensions (2k^d)
1551 const Key<NDIM>& shift, double tol, bool do_R, bool do_T) const {
1552
1553 if (not (do_R or do_T)) {
1554 print("no operator requested in make_tt_representation??");
1555 MADNESS_EXCEPTION("you're sure you know what you're doing?",1);
1556 }
1557
1558
1560
1561 // check for significant ranks since the R/T matrices' construction
1562 // might have been omitted. Tnorm is always smaller than Rnorm
1563 long lo=0,hi=rank;
1564 for (int mu=0; mu<rank; ++mu) {
1565 double Rnorm=1.0;
1566 for (std::size_t d=0; d<NDIM; ++d) Rnorm *= op->muops[mu].ops[d]->Rnorm;
1567 if (Rnorm>1.e-20) hi=mu;
1568 if ((Rnorm<1.e-20) and (mu<hi)) lo=mu;
1569 }
1570 hi++;lo++;
1571
1572 // think about dimensions
1573 long rank_eff=(hi-lo); // R or T matrices
1574 long step=1;
1575 if (do_R and do_T) { // R and T matrices
1576 rank_eff*=2;
1577 step*=2;
1578 }
1579
1580 long k2k=k; // T matrices
1581 if (do_R) k2k=2*k; // R matrices
1582
1583
1584 // construct empty TT cores and fill them with the significant R/T matrices
1585 std::vector<Tensor<double> > cores(NDIM,Tensor<double>(rank_eff,k2k,k2k,rank_eff));
1586 cores[0]=Tensor<double>(k2k,k2k,rank_eff);
1587 cores[NDIM-1]=Tensor<double>(rank_eff,k2k,k2k);
1588
1589
1590 for (int mu=lo, r=0; mu<hi; ++mu, ++r) {
1591 const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1592 const Q fac = ops[mu].getfac();
1593 const Slice sr0(step*r, step*r, 0);
1594 const Slice sr1(step*r+step-1,step*r+step-1,0);
1595 const Slice s00(0,k-1,1);
1596
1597 if (do_R) {
1598 cores[0](_, _ ,sr0)=muop.ops[0]->R;
1599 for (std::size_t idim=1; idim<NDIM-1; ++idim) {
1600 cores[idim](sr0,_ ,_ ,sr0)=muop.ops[idim]->R;
1601 }
1602 cores[NDIM-1](sr0,_ ,_ )=muop.ops[NDIM-1]->R*fac;
1603 }
1604
1605 if (do_T) {
1606 cores[0](s00,s00,sr1)=muop.ops[0]->T;
1607 for (std::size_t idim=1; idim<NDIM-1; ++idim) {
1608 cores[idim](sr1,s00,s00,sr1)=muop.ops[idim]->T;
1609 }
1610 cores[NDIM-1](sr1,s00,s00)=muop.ops[NDIM-1]->T*(-fac);
1611 }
1612 }
1613
1614 // construct TT representation
1615 TensorTrain<double> tt(cores);
1616
1617 // need to reshape for the TT truncation
1618 tt.make_tensor();
1620 tt.make_operator();
1621
1622 return tt;
1623 }
1624
1625
1627 return (combine_OT(left,right).type!=OT_UNDEFINED);
1628 }
1629
1630 /// return operator type and other info of the combined operator (e.g. fg = f(1,2)* g(1,2)
1632 OperatorInfo info=left.info;
1633 if ((left.info.type==OT_F12) and (right.info.type==OT_G12)) {
1635 } else if ((left.info.type==OT_GAUSS) and (right.info.type==OT_GAUSS)) {
1636 info=right.info;
1638 info.mu=2.0*right.info.mu;
1639 } else if ((left.info.type==OT_SLATER) and (right.info.type==OT_SLATER)) {
1640 info=right.info;
1642 info.mu=2.0*right.info.mu;
1643 } else if ((left.info.type==OT_G12) and (right.info.type==OT_F12)) {
1644 info=right.info;
1646 } else if ((left.info.type==OT_G12) and (right.info.type==OT_F212)) {
1647 info=right.info;
1649 } else if (((left.info.type==OT_F212) and (right.info.type==OT_G12)) or
1650 ((left.info.type==OT_F12) and (right.info.type==OT_FG12)) or
1651 ((left.info.type==OT_FG12) and (right.info.type==OT_F12))) {
1652 info=right.info;
1654 if (right.info.type!=OT_G12) MADNESS_CHECK(right.info.mu == left.info.mu);
1655 } else if ((left.info.type==OT_F12) and (right.info.type==OT_F12)) {
1657 // keep the original gamma
1658 // (f12)^2 = (1- slater12)^2 = 1/(4 gamma) (1 - 2 exp(-gamma) + exp(-2 gamma))
1659 MADNESS_CHECK(right.info.mu == left.info.mu);
1660 } else {
1661 MADNESS_EXCEPTION("unknown combination of SeparatedConvolutions: feel free to extend in operator.h",1);
1662 }
1663 return info;
1664 }
1665
1666
1667 /// combine 2 convolution operators to one
1668 /// There's some information loss with this constructor - not recommended
1670 const SeparatedConvolution<Q,NDIM>& right) {
1671 MADNESS_CHECK(can_combine(left,right));
1672 MADNESS_CHECK(left.get_world().id()==right.get_world().id());
1673 MADNESS_CHECK(left.lattice_summed() == right.lattice_summed());
1674 std::array<LatticeRange, NDIM> lattice_summed;
1675 for (std::size_t i = 0; i < NDIM; ++i) {
1676 if (left.lattice_summed()[i]) lattice_summed[i].set_infinite();
1677 }
1678
1679 auto info=combine_OT(left,right);
1681 }
1682
1683 /// combine 2 convolution operators to one
1685 const std::shared_ptr<SeparatedConvolution<Q,NDIM>> right) {
1687 if (left and right) {
1688 return combine(*left, *right);
1689 } else if (left) {
1690 return *left;
1691 } else if (right) {
1692 return *right;
1693 } else {
1694 MADNESS_EXCEPTION("can't combine empty SeparatedConvolutions",1);
1695 }
1696 return result;
1697 }
1698 };
1699
1700
1701
1702 /// Factory function generating separated kernel for convolution with 1/r in 3D.
1703 /// N.B. bloch_k species how the function's phase changes as the **operator** translates,
1704 /// which (by translational invariance) is the additive inverse of how the function's
1705 /// phase changes as the **cell** shifts
1706 static
1707 inline
1709 Vector<double,3> bloch_k,
1710 double lo,
1711 double eps,
1712 const std::array<KernelRange, 3>& kernel_ranges = std::array<KernelRange, 3>(),
1713 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1715 return SeparatedConvolution<double_complex, 3>(world, OperatorInfo(0.0, lo, eps, OT_G12, std::nullopt, kernel_ranges),
1716 lattice_ranges, k, false, bloch_k);
1717 }
1718
1719 /// Factory function generating separated kernel for convolution with 1/r in 3D.
1720 /// N.B. bloch_k species how the function's phase changes as the **operator** translates,
1721 /// which (by translational invariance) is the additive inverse of how the function's
1722 /// phase changes as the **cell** shifts
1723 static
1724 inline
1726 Vector<double,3> bloch_k,
1727 double lo,
1728 double eps,
1729 const std::array<KernelRange, 3>& kernel_ranges = std::array<KernelRange, 3>(),
1730 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1732 return new SeparatedConvolution<double_complex, 3>(world, OperatorInfo(0.0, lo, eps, OT_G12, std::nullopt, kernel_ranges),
1733 lattice_ranges, k, false, bloch_k);
1734 }
1735
1736 /// Factory function generating separated kernel for convolution with 1/r in 3D.
1737 static
1738 inline
1740 double lo,
1741 double eps,
1742 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1744 {
1745 return SeparatedConvolution<double,3>(world,OperatorInfo(0.0,lo,eps,OT_G12),lattice_ranges,k);
1746 }
1747
1748
1749 /// Factory function generating separated kernel for convolution with 1/r in 3D.
1750 static
1751 inline
1753 double lo,
1754 double eps,
1755 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1757 {
1758 return new SeparatedConvolution<double,3>(world,OperatorInfo(0.0,lo,eps,OT_G12),lattice_ranges,k);
1759 }
1760
1761
1762 /// Factory function generating separated kernel for convolution with BSH kernel in general NDIM
1763 template <std::size_t NDIM>
1764 static inline
1765 SeparatedConvolution<double,NDIM>
1766 BSHOperator(World& world, double mu, double lo, double eps,
1767 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1769 if (eps>1.e-4) {
1770 if (world.rank()==0) print("the accuracy in BSHOperator is too small, tighten the threshold",eps);
1771 MADNESS_EXCEPTION("0",1);
1772 }
1773 return SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_BSH),lattice_ranges,k);
1774 }
1775
1776 /// Factory function generating separated kernel for convolution with BSH kernel in general NDIM
1777 template <std::size_t NDIM>
1778 static inline
1779 SeparatedConvolution<double,NDIM>*
1780 BSHOperatorPtr(World& world, double mu, double lo, double eps,
1781 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1783 if (eps>1.e-4) {
1784 if (world.rank()==0) print("the accuracy in BSHOperator is too small, tighten the threshold",eps);
1785 MADNESS_EXCEPTION("0",1);
1786 }
1787 return new SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_BSH),lattice_ranges,k);
1788 }
1789
1790
1791 /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D
1792 static inline SeparatedConvolution<double,3>
1793 BSHOperator3D(World& world, double mu, double lo, double eps,
1794 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1796 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_BSH),lattice_ranges,k);
1797 }
1798
1799 /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D
1800 static
1801 inline
1803 Vector<double,3> bloch_k,
1804 double mu,
1805 double lo,
1806 double eps,
1807 const std::array<KernelRange, 3>& kernel_ranges = std::array<KernelRange, 3>(),
1808 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1810
1811 {
1812 return SeparatedConvolution<double_complex, 3>(world, OperatorInfo(mu, lo, eps, OT_BSH, std::nullopt, kernel_ranges),
1813 lattice_ranges, k, false, bloch_k);
1814 }
1815
1816 /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D
1817 static inline
1819 Vector<double,3> bloch_k,
1820 double mu,
1821 double lo,
1822 double eps,
1823 const std::array<KernelRange, 3>& kernel_ranges = std::array<KernelRange, 3>(),
1824 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1826
1827 {
1828 return new SeparatedConvolution<double_complex, 3>(world, OperatorInfo(mu, lo, eps, OT_BSH, std::nullopt, kernel_ranges),
1829 lattice_ranges, k, false, bloch_k);
1830 }
1831
1832
1833 static inline SeparatedConvolution<double,3>
1834 SlaterF12Operator(World& world, double mu, double lo, double eps,
1835 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1837 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F12),lattice_ranges,k);
1838 }
1839
1841 double mu, double lo, double eps,
1842 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1844 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F212),lattice_ranges,k);
1845 }
1846
1848 double mu, double lo, double eps,
1849 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1851 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F212),lattice_ranges,k);
1852 }
1853
1854 /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D
1855 template<std::size_t NDIM=3>
1857 double mu, double lo, double eps,
1858 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1860 return SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_SLATER),lattice_ranges,k);
1861 }
1862
1863 /// Factory function generating separated kernel for convolution with exp(-mu*r*r)
1864
1865 /// lo and eps are not used here
1866 template<std::size_t NDIM>
1868 double mu, double lo=0.0, double eps=0.0,
1869 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1871 return SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_GAUSS),lattice_ranges,k);
1872 }
1873
1874 /// Factory function generating separated kernel for convolution with exp(-mu*r*r) in 3D
1875
1876 /// lo and eps are not used here
1877 template<std::size_t NDIM>
1879 double mu, double lo=0.0, double eps=0.0,
1880 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1882 return new SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_GAUSS),lattice_ranges,k);
1883 }
1884
1885
1886 /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D
1887 /// Note that the 1/(2mu) factor of SlaterF12Operator is not included, this is just the exponential function
1888 template<std::size_t NDIM>
1890 double mu, double lo, double eps,
1891 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1893 return new SeparatedConvolution<double,NDIM>(world,OperatorInfo(mu,lo,eps,OT_SLATER),lattice_ranges,k);
1894 }
1895
1896 /// Factory function generating separated kernel for convolution with exp(-mu*r) in 3D
1897 /// Note that the 1/(2mu) factor of SlaterF12Operator is not included, this is just the exponential function
1899 double mu, double lo, double eps,
1900 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1901 int k = FunctionDefaults<3>::get_k()) {
1902 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_SLATER),lattice_ranges,k);
1903 }
1904
1905 /// Factory function generating separated kernel for convolution with (1 - exp(-mu*r))/(2 mu) in 3D
1906
1907 /// includes the factor 1/(2 mu)
1909 double mu, double lo, double eps,
1910 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1912 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F12),lattice_ranges,k);
1913 }
1914
1915
1916 /// Factory function generating separated kernel for convolution with 1/(2 mu)*(1 - exp(-mu*r))/r in 3D
1917
1918 /// fg = (1 - exp(-gamma r12)) / r12 = 1/r12 - exp(-gamma r12)/r12 = coulomb - bsh
1919 /// includes the factor 1/(2 mu)
1920 static inline SeparatedConvolution<double,3>
1921 FGOperator(World& world, double mu, double lo, double eps,
1922 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1924 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_FG12),lattice_ranges,k);
1925 }
1926
1927 /// Factory function generating separated kernel for convolution with 1/(2 mu)*(1 - exp(-mu*r))/r in 3D
1928
1929 /// fg = (1 - exp(-gamma r12)) / r12 = 1/r12 - exp(-gamma r12)/r12 = coulomb - bsh
1930 /// includes the factor 1/(2 mu)
1931 static inline SeparatedConvolution<double,3>*
1932 FGOperatorPtr(World& world, double mu, double lo, double eps,
1933 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1935 return new SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_FG12),lattice_ranges,k);
1936 }
1937
1938 /// Factory function generating separated kernel for convolution with (1/(2 mu)*(1 - exp(-mu*r)))^2/r in 3D
1939
1940 /// f2g = (1/(2 gamma) (1 - exp(-gamma r12)))^2 / r12
1941 /// = 1/(4 gamma) * [ 1/r12 - 2 exp(-gamma r12)/r12 + exp(-2 gamma r12)/r12 ]
1942 /// includes the factor 1/(2 mu)^2
1943 static inline SeparatedConvolution<double,3>*
1944 F2GOperatorPtr(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_F2G12),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 F2GOperator(World& world, double mu, double lo, double eps,
1957 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1959 return SeparatedConvolution<double,3>(world,OperatorInfo(mu,lo,eps,OT_F2G12),lattice_ranges,k);
1960 }
1961
1962
1963 /// Factory function generating separated kernel for convolution a normalized
1964 /// Gaussian (aka a widened delta function)
1966 double eps,
1967 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
1969
1970 double exponent = 1.0/(2.0*eps);
1971 Tensor<double> coeffs(1), exponents(1);
1972 exponents(0L) = exponent;
1973 coeffs(0L)=pow(exponent/M_PI,0.5*3.0); // norm of the gaussian
1974 return SeparatedConvolution<double,3>(world, coeffs, exponents, 1.e-8, eps, lattice_ranges, k);
1975 }
1976
1977 /// Factory function generating separated kernel for convolution a normalized
1978 /// Gaussian (aka a widened delta function)
1979 template<std::size_t NDIM>
1981 double eps,
1982 const std::array<LatticeRange, NDIM>& lattice_ranges = FunctionDefaults<NDIM>::get_bc().lattice_range(),
1984
1985 double exponent = 1.0/(2.0*eps);
1986 Tensor<double> coeffs(1), exponents(1);
1987 exponents(0L) = exponent;
1988 coeffs(0L)=pow(exponent/M_PI,0.5*NDIM); // norm of the gaussian
1989 return SeparatedConvolution<double,NDIM>(world, coeffs, exponents, 1.e-8, eps, lattice_ranges, k);
1990 }
1991
1992 /// Factory function generating separated kernel for convolution with exp(-mu*r)/(4*pi*r) in 3D
1993 static
1994 inline
1996 double mu,
1997 double lo,
1998 double eps,
1999 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
2002 double hi = cell_width.normf(); // Diagonal width of cell
2003 // Extend kernel range for lattice summation
2004 // N.B. if have periodic boundaries, extend range just in case will be using periodic domain
2005 const auto lattice_summed_any = std::any_of(lattice_ranges.begin(), lattice_ranges.end(), [](const auto& b) { return static_cast<bool>(b);});
2006 const auto infinite_any = std::any_of(lattice_ranges.begin(), lattice_ranges.end(), [](const auto& b) { return b.infinite();});
2007 if (lattice_summed_any) {
2008 hi *= 100;
2009 }
2010
2011 GFit<double, 3> fit = GFit<double, 3>::BSHFit(mu, lo, hi, eps, false);
2012 Tensor<double> coeff = fit.coeffs();
2013 Tensor<double> expnt = fit.exponents();
2014
2015 if (infinite_any) {
2016 // convolution with Gaussians of exponents <= 0.25/(L^2) contribute only a constant shift
2017 // the largest spacing along lattice summed axes thus controls the smallest Gaussian exponent that NEEDS to be included
2018 double max_lattice_spacing = 0;
2019 for(int d=0; d!=3; ++d) {
2020 if (lattice_ranges[d])
2021 max_lattice_spacing =
2022 std::max(max_lattice_spacing, cell_width(d));
2023 }
2024 // WARNING: discardG0 = true ignores the coefficients of truncated
2025 // terms
2026 fit.truncate_periodic_expansion(coeff, expnt, max_lattice_spacing,
2027 /* discardG0 = */ false);
2028 }
2029 return new SeparatedConvolution<double, 3>(world, coeff, expnt, lo, eps,
2030 lattice_ranges, k);
2031 }
2032
2033
2034 /// Factory function generating operator for convolution with grad(1/r) in 3D
2035
2036 /// Returns a 3-vector containing the convolution operator for the
2037 /// x, y, and z components of grad(1/r)
2038 static
2039 inline
2040 std::vector< std::shared_ptr< SeparatedConvolution<double,3> > >
2042 double lo,
2043 double eps,
2044 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
2047 typedef std::shared_ptr<real_convolution_3d> real_convolution_3d_ptr;
2048 const double pi = constants::pi;
2050 double hi = width.normf(); // Diagonal width of cell
2051 // Extend kernel range for lattice summation
2052 const auto lattice_sum_any = std::any_of(lattice_ranges.begin(), lattice_ranges.end(), [](const LatticeRange& b){ return static_cast<bool>(b); });
2053 if (lattice_sum_any) {
2054 hi *= 100;
2055 }
2056
2058 Tensor<double> coeff = fit.coeffs();
2059 Tensor<double> expnt = fit.exponents();
2060
2061 if (lattice_sum_any) {
2062 fit.truncate_periodic_expansion(coeff, expnt, width.max(), true);
2063 }
2064
2065 int rank = coeff.dim(0);
2066
2067 std::vector<real_convolution_3d_ptr> gradG(3);
2068
2069 for (int dir = 0; dir < 3; dir++) {
2070 std::vector<ConvolutionND<double, 3>> ops(rank);
2071 for (int mu = 0; mu < rank; mu++) {
2072 // We cache the normalized operator so the factor is the value we must multiply by to recover the coeff we want.
2073 double c = std::pow(sqrt(expnt(mu) / pi), 3); // Normalization coeff
2074 ops[mu].setfac(coeff(mu) / c / width[dir]);
2075
2076 for (int d = 0; d < 3; d++) {
2077 if (d != dir)
2079 k, expnt(mu) * width[d] * width[d], 0,
2080 lattice_ranges[d]));
2081 }
2083 k, expnt(mu) * width[dir] * width[dir], 1,
2084 lattice_ranges[dir]));
2085 }
2087 new SeparatedConvolution<double, 3>(world, ops));
2088 }
2089
2090 return gradG;
2091 }
2092
2093 /// Factory function generating operator for convolution with grad(bsh) in 3D
2094
2095 /// Returns a 3-vector containing the convolution operator for the
2096 /// x, y, and z components of grad(bsh)
2097 static
2098 inline
2099 std::vector< std::shared_ptr< SeparatedConvolution<double,3> > >
2101 double mu,
2102 double lo,
2103 double eps,
2104 const std::array<LatticeRange, 3>& lattice_ranges = FunctionDefaults<3>::get_bc().lattice_range(),
2107 typedef std::shared_ptr<real_convolution_3d> real_convolution_3d_ptr;
2108 const double pi = constants::pi;
2110 double hi = width.normf(); // Diagonal width of cell
2111 // Extend kernel range for lattice summation
2112 bool lattice_sum_any = std::any_of(lattice_ranges.begin(), lattice_ranges.end(), [](const LatticeRange& b){ return b.get_range(); });
2113 if (lattice_sum_any) {
2114 hi *= 100;
2115 }
2116
2117 GFit<double, 3> fit = GFit<double, 3>::BSHFit(mu, lo, hi, eps, false);
2118 Tensor<double> coeff = fit.coeffs();
2119 Tensor<double> expnt = fit.exponents();
2120
2121 if (lattice_sum_any) {
2122 fit.truncate_periodic_expansion(coeff, expnt, width.max(), true);
2123 }
2124
2125 int rank = coeff.dim(0);
2126
2127 std::vector<real_convolution_3d_ptr> gradG(3);
2128
2129 for (int dir = 0; dir < 3; dir++) {
2130 std::vector<ConvolutionND<double, 3>> ops(rank);
2131 for (int mu = 0; mu < rank; mu++) {
2132 // We cache the normalized operator so the factor is the value we must multiply by to recover the coeff we want.
2133 double c = std::pow(sqrt(expnt(mu) / pi), 3); // Normalization coeff
2134 ops[mu].setfac(coeff(mu) / c / width[dir]);
2135
2136 for (int d = 0; d < 3; d++) {
2137 if (d != dir)
2139 k, expnt(mu) * width[d] * width[d], 0,
2140 lattice_ranges[d]));
2141 }
2143 k, expnt(mu) * width[dir] * width[dir], 1,
2144 lattice_ranges[dir]));
2145 }
2147 new SeparatedConvolution<double, 3>(world, ops));
2148 }
2149
2150 return gradG;
2151 }
2152
2153
2154
2155 namespace archive {
2156 template <class Archive, class T, std::size_t NDIM>
2157 struct ArchiveLoadImpl<Archive,const SeparatedConvolution<T,NDIM>*> {
2158 static inline void load(const Archive& ar, const SeparatedConvolution<T,NDIM>*& ptr) {
2160 ar & p;
2161 ptr = static_cast< const SeparatedConvolution<T,NDIM>* >(p);
2162 }
2163 };
2164
2165 template <class Archive, class T, std::size_t NDIM>
2166 struct ArchiveStoreImpl<Archive,const SeparatedConvolution<T,NDIM>*> {
2167 static inline void store(const Archive& ar, const SeparatedConvolution<T,NDIM>*const& ptr) {
2168 ar & static_cast< const WorldObject< SeparatedConvolution<T,NDIM> >* >(ptr);
2169 }
2170 };
2171 }
2172
2173}
2174
2175
2176
2177
2178#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:66
const std::vector< Key< NDIM > > & get_disp(Level n, const array_of_bools< NDIM > &kernel_lattice_sum_axes)
Definition displacements.h:237
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:101
static const Tensor< double > & get_cell_width()
Returns the width of each user cell dimension.
Definition funcdefaults.h:390
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:1037
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:1383
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:1102
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:546
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:1287
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:1172
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:781
void set_domain_periodicity(const array_of_bools< NDIM > &domain_is_periodic)
Definition operator.h:1108
const double & mu() const
Definition operator.h:201
double munorm2(Level n, const ConvolutionData1D< Q > *ops[]) const
Definition operator.h:633
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:1126
double munorm2_ns(Level n, const ConvolutionData1D< Q > *ops[]) const
Definition operator.h:641
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:1143
virtual ~SeparatedConvolution()
Definition operator.h:1079
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:435
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:1192
Timer timer_full
Definition operator.h:164
const array_of_bools< NDIM > & func_domain_is_periodic() const
Definition operator.h:1105
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:964
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:1184
void init_lattice_summed()
Definition operator.h:949
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:1061
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:725
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:795
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:1155
bool doleaves
If should be applied to leaf coefficients ... false by default.
Definition operator.h:146
void print_timer() const
Definition operator.h:1081
SeparatedConvolution(World &world, const std::vector< ConvolutionND< Q, NDIM > > &argops, long k=FunctionDefaults< NDIM >::get_k(), bool doleaves=false)
Definition operator.h:993
const std::vector< Key< NDIM > > & get_disp(Level n) const
Definition operator.h:1097
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:358
static SeparatedConvolution< Q, NDIM > combine(const SeparatedConvolution< Q, NDIM > &left, const SeparatedConvolution< Q, NDIM > &right)
Definition operator.h:1669
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:1111
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:1550
void reset_timer() const
Definition operator.h:1089
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:1631
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:919
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:1491
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:1205
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:375
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:1161
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:1684
OperatorInfo info
Definition operator.h:144
Key< NDIM > keyT
Definition operator.h:162
void init_range()
Definition operator.h:936
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:858
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:1019
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:876
double munorm2_modified(Level n, const ConvolutionData1D< Q > *ops_1d[]) const
Definition operator.h:662
int & particle()
Definition operator.h:189
static bool can_combine(const SeparatedConvolution< Q, NDIM > &left, const SeparatedConvolution< Q, NDIM > &right)
Definition operator.h:1626
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:829
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:754
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_RESTRICT
Definition mTxmq.h:37
#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 DFConvergence.h:9
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:1834
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:1802
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:1980
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:1956
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:1739
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:1725
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:1780
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:1944
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:1898
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:1840
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:1965
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:1889
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:1908
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:1708
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:2100
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:1847
TensorType
low rank representations of tensors (see gentensor.h)
Definition gentensor.h:120
@ TT_2D
Definition gentensor.h:120
NDIM & f
Definition mra.h:2668
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:1856
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:1766
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:1752
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:1921
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:1818
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:1867
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:1995
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:1878
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:1793
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:1932
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:2041
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:2233
void mTxmq(long dimi, long dimj, long dimk, double *MADNESS_RESTRICT c, const double *a, const double *b, long ldb)
Explicit template specializations for homogeneous types (implemented in mTxmq.cc)
Definition mTxmq.cc:551
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:53
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:2158
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:2167
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