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