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