MADNESS 0.10.1
convolution1d.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_CONVOLUTION1D_H__INCLUDED
33#define MADNESS_MRA_CONVOLUTION1D_H__INCLUDED
34
36#include <madness/constants.h>
37#include <limits.h>
40#include <madness/mra/adquad.h>
44#include <algorithm>
45
46/// \file mra/convolution1d.h
47/// \brief Compuates most matrix elements over 1D operators (including Gaussians)
48
49/// \ingroup function
50
51namespace madness {
52
53 void aligned_add(long n, double* MADNESS_RESTRICT a, const double* MADNESS_RESTRICT b);
54 void aligned_sub(long n, double* MADNESS_RESTRICT a, const double* MADNESS_RESTRICT b);
55 void aligned_add(long n, double_complex* MADNESS_RESTRICT a, const double_complex* MADNESS_RESTRICT b);
56 void aligned_sub(long n, double_complex* MADNESS_RESTRICT a, const double_complex* MADNESS_RESTRICT b);
57
58 template <typename T>
59 static void copy_2d_patch(T* MADNESS_RESTRICT out, long ldout, const T* MADNESS_RESTRICT in, long ldin, long n, long m) {
60 for (long i=0; i<n; ++i, out+=ldout, in+=ldin) {
61 for (long j=0; j<m; ++j) {
62 out[j] = in[j];
63 }
64 }
65 }
66
67 /// a(n,m) --> b(m,n) ... optimized for smallish matrices
68 template <typename T>
69 inline void fast_transpose(long n, long m, const T* a, T* MADNESS_RESTRICT b) {
70 // n will always be k or 2k (k=wavelet order) and m will be anywhere
71 // from 2^(NDIM-1) to (2k)^(NDIM-1).
72
73// for (long i=0; i<n; ++i)
74// for (long j=0; j<m; ++j)
75// b[j*n+i] = a[i*m+j];
76// return;
77
78 if (n==1 || m==1) {
79 long nm=n*m;
80 for (long i=0; i<nm; ++i) b[i] = a[i];
81 return;
82 }
83
84 long n4 = (n>>2)<<2;
85 long m4 = m<<2;
86 const T* a0 = a;
87 for (long i=0; i<n4; i+=4, a0+=m4) {
88 const T* a1 = a0+m;
89 const T* a2 = a1+m;
90 const T* a3 = a2+m;
91 T* MADNESS_RESTRICT bi = b+i;
92 for (long j=0; j<m; ++j, bi+=n) {
93 T tmp0 = a0[j];
94 T tmp1 = a1[j];
95 T tmp2 = a2[j];
96 T tmp3 = a3[j];
97
98 bi[0] = tmp0;
99 bi[1] = tmp1;
100 bi[2] = tmp2;
101 bi[3] = tmp3;
102 }
103 }
104
105 for (long i=n4; i<n; ++i)
106 for (long j=0; j<m; ++j)
107 b[j*n+i] = a[i*m+j];
108
109 }
110
111 // /// a(i,j) --> b(i,j) for i=0..n-1 and j=0..r-1 noting dimensions are a(n,m) and b(n,r).
112
113 // /// returns b
114 // template <typename T>
115 // inline T* shrink(long n, long m, long r, const T* a, T* MADNESS_RESTRICT b) {
116 // T* result = b;
117 // if (r == 0) {
118 // ;
119 // }
120 // else if (r == 1) {
121 // for (long i=0; i<n; ++i) {
122 // b[i] = a[i];
123 // }
124 // }
125 // else if (r == 2) {
126 // for (long i=0; i<n; ++i, a+=m, b+=2) {
127 // b[0] = a[0];
128 // b[1] = a[1];
129 // }
130 // }
131 // else if (r == 3) {
132 // for (long i=0; i<n; ++i, a+=m, b+=3) {
133 // b[0] = a[0];
134 // b[1] = a[1];
135 // b[2] = a[2];
136 // }
137 // }
138 // else if (r == 4) {
139 // for (long i=0; i<n; ++i, a+=m, b+=4) {
140 // b[0] = a[0];
141 // b[1] = a[1];
142 // b[2] = a[2];
143 // b[3] = a[3];
144 // }
145 // }
146 // else {
147 // for (long i=0; i<n; ++i, a+=m, b+=r) {
148 // for (long j=0; j<r; j++) {
149 // b[j] = a[j];
150 // }
151 // }
152 // }
153 // return result;
154 // }
155
156 /// actual data for 1 dimension and for 1 term and for 1 displacement for a convolution operator
157 /// here we keep the transformation matrices
158
159 /// !!! Note that if Rnormf is zero then ***ALL*** of the tensors are empty
160 template <typename Q>
162
163
164 Tensor<Q> R, T; ///< if NS: R=ns, T=T part of ns; if modified NS: T=\uparrow r^(n-1)
165 Tensor<Q> RU, RVT, TU, TVT; ///< SVD approximations to R and T
166 Tensor<typename Tensor<Q>::scalar_type> Rs, Ts; ///< hold relative errors, NOT the singular values..
167
168 // norms for NS form
170
171 // norms for modified NS form
172 double N_up, N_diff, N_F; ///< the norms according to Beylkin 2008, Eq. (21) ff
173
174
175 /// ctor for NS form
176 /// make the operator matrices r^n and \uparrow r^(n-1)
177 /// @param[in] R operator matrix of the requested level; NS: unfilter(r^(n+1)); modified NS: r^n
178 /// @param[in] T upsampled operator matrix from level n-1; NS: r^n; modified NS: filter( r^(n-1) )
179 ConvolutionData1D(const Tensor<Q>& R, const Tensor<Q>& T) : R(R), T(T) {
180 Rnormf = R.normf();
181 // Making the approximations is expensive ... only do it for
182 // significant components
183 if (Rnormf > 1e-20) {
184 Tnormf = T.normf();
185 make_approx(T, TU, Ts, TVT, Tnorm);
186 make_approx(R, RU, Rs, RVT, Rnorm);
187 int k = T.dim(0);
188
189 Tensor<Q> NS = copy(R);
190 for (int i=0; i<k; ++i)
191 for (int j=0; j<k; ++j)
192 NS(i,j) = 0.0;
193 NSnormf = NS.normf();
194
195 }
196 else {
197 Rnorm = Tnorm = Rnormf = Tnormf = NSnormf = 0.0;
198 N_F = N_up = N_diff = 0.0;
199 }
200 }
201
202 /// ctor for modified NS form
203 /// make the operator matrices r^n and \uparrow r^(n-1)
204 /// @param[in] R operator matrix of the requested level; NS: unfilter(r^(n+1)); modified NS: r^n
205 /// @param[in] T upsampled operator matrix from level n-1; NS: r^n; modified NS: filter( r^(n-1) )
206 /// @param[in] modified use (un) modified NS form
207 ConvolutionData1D(const Tensor<Q>& R, const Tensor<Q>& T, const bool modified) : R(R), T(T) {
208
209 // note that R can be small, but T still be large
210
211 Rnormf = R.normf();
212 Tnormf = T.normf();
213 // Making the approximations is expensive ... only do it for
214 // significant components
215 if (Rnormf > 1e-20) make_approx(R, RU, Rs, RVT, Rnorm);
216 if (Tnormf > 1e-20) make_approx(T, TU, Ts, TVT, Tnorm);
217
218 // norms for modified NS form: follow Beylkin, 2008, Eq. (21) ff
219 N_F=Rnormf;
220 N_up=Tnormf;
221 N_diff=(R-T).normf();
222 }
223
224
225
226 /// approximate the operator matrices using SVD, and abuse Rs to hold the error instead of
227 /// the singular values (seriously, who named this??)
229 Tensor<Q>& RU, Tensor<typename Tensor<Q>::scalar_type>& Rs, Tensor<Q>& RVT, double& norm) {
230 int n = R.dim(0);
231 svd(R, RU, Rs, RVT);
232 for (int i=0; i<n; ++i) {
233 for (int j=0; j<n; ++j) {
234 RVT(i,j) *= Rs[i];
235 }
236 }
237 for (int i=n-1; i>1; --i) { // Form cumulative sum of norms
238 Rs[i-1] += Rs[i];
239 }
240
241 norm = Rs[0];
242 if (Rs[0]>0.0) { // Turn into relative errors
243 double rnorm = 1.0/norm;
244 for (int i=0; i<n; ++i) {
245 Rs[i] *= rnorm;
246 }
247 }
248 }
249 };
250
251 /// Provides the common functionality/interface of all 1D convolutions
252
253 /// interface for 1 term and for 1 dimension;
254 /// the actual data are kept in ConvolutionData1D
255 /// Derived classes must implement rnlp, issmall, natural_level
256 template <typename Q>
258 public:
259 typedef Q opT; ///< The apply function uses this to infer resultT=opT*inputT
260 int k; ///< Wavelet order
261 int npt; ///< Number of quadrature points (is this used?)
262 int maxR; ///< Number of lattice translations for sum
268 double arg;
269
274
275 virtual ~Convolution1D() {};
276
277 Convolution1D(int k, int npt, int maxR, double arg = 0.0)
278 : k(k)
279 , npt(npt)
280 , maxR(maxR)
281 , quad_x(npt)
282 , quad_w(npt)
283 , arg(arg)
284 {
285 auto success = autoc(k,&c);
286 MADNESS_CHECK(success);
287
288 gauss_legendre(npt,0.0,1.0,quad_x.ptr(),quad_w.ptr());
289 success = two_scale_hg(k,&hg);
290 MADNESS_ASSERT(success);
291 hgT = transpose(hg);
292 success = two_scale_hg(2*k,&hgT2k);
293 MADNESS_ASSERT(success);
295
296 // Cannot construct the coefficients here since the
297 // derived class is not yet constructed so cannot call
298 // (even indirectly) a virtual method
299 }
300
301 /// Compute the projection of the operator onto the double order polynomials
302 virtual Tensor<Q> rnlp(Level n, Translation lx) const = 0;
303
304 /// Returns true if the block of rnlp is expected to be small
305 virtual bool issmall(Level n, Translation lx) const = 0;
306
307 /// Returns true if the block of rnlp is expected to be small including periodicity
308 bool get_issmall(Level n, Translation lx) const {
309 if (maxR == 0) {
310 return issmall(n, lx);
311 }
312 else {
313 Translation twon = Translation(1)<<n;
314 for (int R=-maxR; R<=maxR; ++R) {
315 if (!issmall(n, R*twon+lx)) return false;
316 }
317 return true;
318 }
319 }
320
321 /// Returns the level for projection
322 //virtual Level natural_level() const {
323 // return 13;
324 //}
325 virtual Level natural_level() const {return 13;}
326
327 /// Computes the transition matrix elements for the convolution for n,l
328
329 /// Returns the tensor
330 /// \code
331 /// r(i,j) = int(K(x-y) phi[n0](x) phi[nl](y), x=0..1, y=0..1)
332 /// \endcode
333 /// This is computed from the matrix elements over the correlation
334 /// function which in turn are computed from the matrix elements
335 /// over the double order legendre polynomials.
336 const Tensor<Q>& rnlij(Level n, Translation lx, bool do_transpose=false) const {
337 const Tensor<Q>* p=rnlij_cache.getptr(n,lx);
338 if (p) return *p;
339
340 // PROFILE_MEMBER_FUNC(Convolution1D); // Too fine grain for routine profiling
341
342 long twok = 2*k;
343 Tensor<Q> R(2*twok);
344 R(Slice(0,twok-1)) = get_rnlp(n,lx-1);
345 R(Slice(twok,2*twok-1)) = get_rnlp(n,lx);
346
347 R.scale(pow(0.5,0.5*n));
348 R = inner(c,R);
349 if (do_transpose) R = transpose(R);
350 rnlij_cache.set(n,lx,R);
351 return *rnlij_cache.getptr(n,lx);
352 };
353
354
355 /// Returns a pointer to the cached modified make_nonstandard form of the operator
356
357 /// @param[in] op_key holds the scale and the source and target translations
358 /// @return a pointer to the cached modified make_nonstandard form of the operator
359 const ConvolutionData1D<Q>* mod_nonstandard(const Key<2>& op_key) const {
360
361 const Level& n=op_key.level();
362 const Translation& sx=op_key.translation()[0]; // source translation
363 const Translation& tx=op_key.translation()[1]; // target translation
364 const Translation lx=tx-sx; // displacement
365 const Translation s_off=sx%2;
366 const Translation t_off=tx%2;
367
368 // we cache translation and source offset
369 const Key<2> cache_key(n, Vector<Translation,2>{lx, s_off} );
370 const ConvolutionData1D<Q>* p = mod_ns_cache.getptr(cache_key);
371 if (p) return p;
372
373 // for paranoid me
374 MADNESS_ASSERT(sx>=0 and tx>=0);
375
376
377 Tensor<Q> R, T, Rm;
378// if (!get_issmall(n, lx)) {
379// print("no issmall", lx, source, n);
380
381 const Translation lx_half = tx/2 - sx/2;
382 const Slice s0(0,k-1), s1(k,2*k-1);
383// print("sx, tx",lx,lx_half,sx, tx,"off",s_off,t_off);
384
385 // this is the operator matrix in its actual level
386 R = rnlij(n,lx);
387
388 // this is the upsampled operator matrix
389 Rm = Tensor<Q>(2*k,2*k);
390 if (n>0) Rm(s0,s0)=rnlij(n-1,lx_half);
391 {
392 // PROFILE_BLOCK(Convolution1D_nstran); // Too fine grain for routine profiling
393 Rm = transform(Rm,hg);
394 }
395
396 {
397 // PROFILE_BLOCK(Convolution1D_nscopy); // Too fine grain for routine profiling
398 T=Tensor<Q>(k,k);
399 if (t_off==0 and s_off==0) T=copy(Rm(s0,s0));
400 if (t_off==0 and s_off==1) T=copy(Rm(s0,s1));
401 if (t_off==1 and s_off==0) T=copy(Rm(s1,s0));
402 if (t_off==1 and s_off==1) T=copy(Rm(s1,s1));
403// if (t_off==0 and s_off==0) T=copy(Rm(s0,s0));
404// if (t_off==1 and s_off==0) T=copy(Rm(s0,s1));
405// if (t_off==0 and s_off==1) T=copy(Rm(s1,s0));
406// if (t_off==1 and s_off==1) T=copy(Rm(s1,s1));
407 }
408
409 {
410 // PROFILE_BLOCK(Convolution1D_trans); // Too fine grain for routine profiling
411
412 Tensor<Q> RT(k,k), TT(k,k);
413 fast_transpose(k,k,R.ptr(), RT.ptr());
414 fast_transpose(k,k,T.ptr(), TT.ptr());
415 R = RT;
416 T = TT;
417 }
418
419// }
420
421 mod_ns_cache.set(cache_key,ConvolutionData1D<Q>(R,T,true));
422 return mod_ns_cache.getptr(cache_key);
423 }
424
425 /// Returns a pointer to the cached make_nonstandard form of the operator
427 const ConvolutionData1D<Q>* p = ns_cache.getptr(n,lx);
428 if (p) return p;
429
430 // PROFILE_MEMBER_FUNC(Convolution1D); // Too fine grain for routine profiling
431
432 Tensor<Q> R, T;
433 if (!get_issmall(n, lx)) {
434 Translation lx2 = lx*2;
435#if 0 // UNUSED VARIABLES
436 Slice s0(0,k-1), s1(k,2*k-1);
437#endif
438 const Tensor<Q> r0 = rnlij(n+1,lx2);
439 const Tensor<Q> rp = rnlij(n+1,lx2+1);
440 const Tensor<Q> rm = rnlij(n+1,lx2-1);
441
442 R = Tensor<Q>(2*k,2*k);
443
444// R(s0,s0) = r0;
445// R(s1,s1) = r0;
446// R(s1,s0) = rp;
447// R(s0,s1) = rm;
448
449 {
450 // PROFILE_BLOCK(Convolution1D_nscopy); // Too fine grain for routine profiling
451 copy_2d_patch(R.ptr(), 2*k, r0.ptr(), k, k, k);
452 copy_2d_patch(R.ptr()+2*k*k + k, 2*k, r0.ptr(), k, k, k);
453 copy_2d_patch(R.ptr()+2*k*k, 2*k, rp.ptr(), k, k, k);
454 copy_2d_patch(R.ptr() + k, 2*k, rm.ptr(), k, k, k);
455 }
456
457 //print("R ", n, lx, R.normf(), r0.normf(), rp.normf(), rm.normf());
458
459
460 {
461 // PROFILE_BLOCK(Convolution1D_nstran); // Too fine grain for routine profiling
462 R = transform(R,hgT);
463 }
464
465 //print("RX", n, lx, R.normf(), r0.normf(), rp.normf(), rm.normf());
466
467 {
468 // PROFILE_BLOCK(Convolution1D_trans); // Too fine grain for routine profiling
469
470 Tensor<Q> RT(2*k,2*k);
471 fast_transpose(2*k, 2*k, R.ptr(), RT.ptr());
472 R = RT;
473
474 //print("RT", n, lx, R.normf(), r0.normf(), rp.normf(), rm.normf());
475
476 //T = copy(R(s0,s0));
477 T = Tensor<Q>(k,k);
478 copy_2d_patch(T.ptr(), k, R.ptr(), 2*k, k, k);
479 }
480
481 //print("NS", n, lx, R.normf(), T.normf());
482 }
483
484 ns_cache.set(n,lx,ConvolutionData1D<Q>(R,T));
485
486 return ns_cache.getptr(n,lx);
487 };
488
489 Q phase(double R) const {
490 return 1.0;
491 }
492
494 return exp(double_complex(0.0,arg)*R);
495 }
496
497
498 const Tensor<Q>& get_rnlp(Level n, Translation lx) const {
499 const Tensor<Q>* p=rnlp_cache.getptr(n,lx);
500 if (p) return *p;
501
502 // PROFILE_MEMBER_FUNC(Convolution1D); // Too fine grain for routine profiling
503
504 long twok = 2*k;
505 Tensor<Q> r;
506
507 if (get_issmall(n, lx)) {
508 r = Tensor<Q>(twok);
509 }
510 else if (n < natural_level()) {
511 Tensor<Q> R(2*twok);
512 R(Slice(0,twok-1)) = get_rnlp(n+1,2*lx);
513 R(Slice(twok,2*twok-1)) = get_rnlp(n+1,2*lx+1);
514
515 R = transform(R, hgT2k);
516 r = copy(R(Slice(0,twok-1)));
517 }
518 else {
519 // PROFILE_BLOCK(Convolution1Drnlp); // Too fine grain for routine profiling
520
521 if (maxR > 0) {
522 Translation twon = Translation(1)<<n;
523 r = Tensor<Q>(2*k);
524 for (int R=-maxR; R<=maxR; ++R) {
525 r.gaxpy(1.0, rnlp(n,R*twon+lx), phase(Q(R)));
526 }
527 }
528 else {
529 r = rnlp(n, lx);
530 }
531 }
532
533 rnlp_cache.set(n, lx, r);
534 //print(" SET rnlp", n, lx, r);
535 return *rnlp_cache.getptr(n,lx);
536 }
537 };
538
539 /// Array of 1D convolutions (one / dimension)
540
541 /// data for 1 term and all dimensions
542 template <typename Q, int NDIM>
544 std::array<std::shared_ptr<Convolution1D<Q> >, NDIM> ops;
546
547 public:
548 ConvolutionND() : fac(1.0) {}
549
550 ConvolutionND(const ConvolutionND& other) : fac(other.fac)
551 {
552 ops = other.ops;
553 }
554
555 ConvolutionND(std::shared_ptr<Convolution1D<Q> > op, Q fac=1.0) : fac(fac)
556 {
557 std::fill(ops.begin(), ops.end(), op);
558 }
559
560 void setop(int dim, const std::shared_ptr<Convolution1D<Q> >& op) {
561 ops[dim] = op;
562 }
563
564 std::shared_ptr<Convolution1D<Q> > getop(int dim) const {
565 return ops[dim];
566 }
567
568 void setfac(Q value) {
569 fac = value;
570 }
571
572 Q getfac() const {
573 return fac;
574 }
575 };
576
577 // To test generic convolution by comparing with GaussianConvolution1D
578 template <typename Q>
580 private:
582 double exponent;
583 int m;
585
586 public:
587 // coeff * exp(-exponent*x^2) * x^m
590 natlev(Level(0.5*log(exponent)/log(2.0)+1)) {}
591
592 Q operator()(double x) const {
593 Q ee = coeff*exp(-exponent*x*x);
594 for (int mm=0; mm<m; ++mm) ee *= x;
595 return ee;
596 }
597 Level natural_level() const {return natlev;}
598 };
599
600
601 /// Generic 1D convolution using brute force (i.e., slow) adaptive quadrature for rnlp
602
603 /// Calls op(x) with x in *simulation coordinates* to evaluate the function.
604 template <typename Q, typename opT>
606 private:
608 long maxl; ///< At natural level is l beyond which operator is zero
609 public:
610
612
613 GenericConvolution1D(int k, const opT& op, int maxR, double arg = 0.0)
614 : Convolution1D<Q>(k, 20, maxR, arg), op(op), maxl(LONG_MAX-1) {
615 // PROFILE_MEMBER_FUNC(GenericConvolution1D); // Too fine grain for routine profiling
616
617 // For efficiency carefully compute outwards at the "natural" level
618 // until several successive boxes are determined to be zero. This
619 // then defines the future range of the operator and also serves
620 // to precompute the values used in the rnlp cache.
621
622 Level natl = natural_level();
623 int nzero = 0;
624 for (Translation lx=0; lx<(1L<<natl); ++lx) {
625 const Tensor<Q>& rp = this->get_rnlp(natl, lx);
626 const Tensor<Q>& rm = this->get_rnlp(natl,-lx);
627 if (rp.normf()<1e-12 && rm.normf()<1e-12) ++nzero;
628 if (nzero == 3) {
629 maxl = lx-2;
630 break;
631 }
632 }
633 }
634
635 virtual Level natural_level() const {return op.natural_level();}
636
637 struct Shmoo {
642
645
646 returnT operator()(double x) const {
647 int twok = q.k*2;
648 double fac = std::pow(0.5,n);
649 double phix[twok];
650 legendre_scaling_functions(x-lx,twok,phix);
651 Q f = q.op(fac*x)*sqrt(fac);
652 returnT v(twok);
653 for (long p=0; p<twok; ++p) v(p) += f*phix[p];
654 return v;
655 }
656 };
657
659 return adq1(lx, lx+1, Shmoo(n, lx, this), 1e-12,
660 this->npt, this->quad_x.ptr(), this->quad_w.ptr(), 0);
661 }
662
663 bool issmall(Level n, Translation lx) const {
664 if (lx < 0) lx = 1 - lx;
665 // Always compute contributions to nearest neighbor coupling
666 // ... we are two levels below so 0,1 --> 0,1,2,3 --> 0,...,7
667 if (lx <= 7) return false;
668
669 n = natural_level()-n;
670 if (n >= 0) lx = lx << n;
671 else lx = lx >> n;
672
673 return lx >= maxl;
674 }
675 };
676
677
678 /// 1D convolution with (derivative) Gaussian; coeff and expnt given in *simulation* coordinates [0,1]
679
680 /// Note that the derivative is computed in *simulation* coordinates so
681 /// you must be careful to scale the coefficients correctly.
682 template <typename Q>
684 // Returns range of Gaussian for periodic lattice sum in simulation coords
685 static int maxR(bool periodic, double expnt) {
686 if (periodic) {
687 return std::max(1,int(sqrt(16.0*2.3/expnt)+1));
688 }
689 else {
690 return 0;
691 }
692 }
693 public:
694 const Q coeff; ///< Coefficient
695 const double expnt; ///< Exponent
696 const Level natlev; ///< Level to evaluate
697 const int m; ///< Order of derivative (0, 1, or 2 only)
698
699 explicit GaussianConvolution1D(int k, Q coeff, double expnt,
700 int m, bool periodic, double arg = 0.0)
701 : Convolution1D<Q>(k,k+11,maxR(periodic,expnt),arg)
702 , coeff(coeff)
703 , expnt(expnt)
704 , natlev(Level(0.5*log(expnt)/log(2.0)+1))
705 , m(m)
706 {
707 MADNESS_ASSERT(m>=0 && m<=2);
708 // std::cout << "GC expnt=" << expnt << " coeff=" << coeff << " natlev=" << natlev << " maxR=" << maxR(periodic,expnt) << std::endl;
709 // for (Level n=0; n<5; n++) {
710 // for (Translation l=0; l<(1<<n); l++) {
711 // std::cout << "RNLP " << n << " " << l << " " << this->get_rnlp(n,l).normf() << std::endl;
712 // }
713 // std::cout << std::endl;
714 // }
715 }
716
718
719 virtual Level natural_level() const {
720 return natlev;
721 }
722
723 /// Compute the projection of the operator onto the double order polynomials
724
725 /// The returned reference is to a cached tensor ... if you want to
726 /// modify it, take a copy first.
727 ///
728 /// Return in \c v[p] \c p=0..2*k-1
729 /// \code
730 /// r(n,l,p) = 2^(-n) * int(K(2^(-n)*(z+l)) * phi(p,z), z=0..1)
731 /// \endcode
732 /// The kernel is coeff*exp(-expnt*z^2)*z^m (with m>0). This is equivalent to
733 /// \code
734 /// r(n,l,p) = 2^(-n*(m+1))*coeff * int( ((d/dz)^m exp(-beta*z^2)) * phi(p,z-l), z=l..l+1)
735 /// \endcode
736 /// where
737 /// \code
738 /// beta = alpha * 2^(-2*n)
739 /// \endcode
741 int twok = 2*this->k;
742 Tensor<Q> v(twok); // Can optimize this away by passing in
743
744 Translation lkeep = lx;
745 if (lx<0) lx = -lx-1;
746
747 /* Apply high-order Gauss Legendre onto subintervals
748
749 coeff*int(exp(-beta(x+l)**2) * z^m * phi[p](x),x=0..1);
750
751 The translations internally considered are all +ve, so
752 signficant pieces will be on the left. Finish after things
753 become insignificant.
754
755 The resulting coefficients are accurate to about 1e-20.
756 */
757
758 // Rescale expnt & coeff onto level n so integration range
759 // is [l,l+1]
760 Q scaledcoeff = coeff*pow(0.5,0.5*n*(2*m+1));
761
762 // Subdivide interval into nbox boxes of length h
763 // ... estimate appropriate size from the exponent. A
764 // Gaussian with real-part of the exponent beta falls in
765 // magnitude by a factor of 1/e at x=1/sqrt(beta), and by
766 // a factor of e^-49 ~ 5e-22 at x=7/sqrt(beta) (and with
767 // polyn of z^2 it is 1e-20). So, if we use a box of size
768 // 1/sqrt(beta) we will need at most 7 boxes. Incorporate
769 // the coefficient into the screening since it may be
770 // large. We can represent exp(-x^2) over [l,l+1] with a
771 // polynomial of order 21 to a relative
772 // precision of better than machine precision for
773 // l=0,1,2,3 and for l>3 the absolute error is less than
774 // 1e-23. We want to compute matrix elements with
775 // polynomials of order 2*k-1+m, so the total order is
776 // 2*k+20+m, which can be integrated with a quadrature rule
777 // of npt=k+11+(m+1)/2. npt is set in the constructor.
778
779 double fourn = std::pow(4.0,double(n));
780 double beta = expnt * pow(0.25,double(n));
781 double h = 1.0/sqrt(beta); // 2.0*sqrt(0.5/beta);
782 long nbox = long(1.0/h);
783 if (nbox < 1) nbox = 1;
784 h = 1.0/nbox;
785
786 // Find argmax such that h*scaledcoeff*exp(-argmax)=1e-22 ... if
787 // beta*xlo*xlo is already greater than argmax we can neglect this
788 // and subsequent boxes.
789
790 // The derivatives add a factor of expnt^m to the size of
791 // the function at long range.
792 double sch = std::abs(scaledcoeff*h);
793 if (m == 1) sch *= expnt;
794 else if (m == 2) sch *= expnt*expnt;
795 double argmax = std::abs(log(1e-22/sch)); // perhaps should be -log(1e-22/sch) ?
796
797 for (long box=0; box<nbox; ++box) {
798 double xlo = box*h + lx;
799 if (beta*xlo*xlo > argmax) break;
800 for (long i=0; i<this->npt; ++i) {
801#ifdef IBMXLC
802 double phix[80];
803#else
804 double phix[twok];
805#endif
806 double xx = xlo + h*this->quad_x(i);
807 Q ee = scaledcoeff*exp(-beta*xx*xx)*this->quad_w(i)*h;
808
809 // Differentiate as necessary
810 if (m == 1) {
811 ee *= -2.0*expnt*xx;
812 }
813 else if (m == 2) {
814 ee *= (4.0*xx*xx*expnt*expnt - 2.0*expnt*fourn);
815 }
816
817 legendre_scaling_functions(xx-lx,twok,phix);
818 for (long p=0; p<twok; ++p) v(p) += ee*phix[p];
819 }
820 }
821
822 if (lkeep < 0) {
823 /* phi[p](1-z) = (-1)^p phi[p](z) */
824 if (m == 1)
825 for (long p=0; p<twok; ++p) v(p) = -v(p);
826 for (long p=1; p<twok; p+=2) v(p) = -v(p);
827 }
828
829 return v;
830 };
831
832 /// Returns true if the block is expected to be small
833 bool issmall(Level n, Translation lx) const {
834 double beta = expnt * pow(0.25,double(n));
835 Translation ll;
836 if (lx > 0)
837 ll = lx - 1;
838 else if (lx < 0)
839 ll = -1 - lx;
840 else
841 ll = 0;
842
843 return (beta*ll*ll > 49.0); // 49 -> 5e-22 69 -> 1e-30
844 };
845 };
846
847
848 template <typename Q>
853
854 static std::shared_ptr< GaussianConvolution1D<Q> > get(int k, double expnt, int m, bool periodic) {
855 hashT key = hash_value(expnt);
856 hash_combine(key, k);
857 hash_combine(key, m);
858 hash_combine(key, int(periodic));
859
860 MADNESS_PRAGMA_CLANG(diagnostic push)
861 MADNESS_PRAGMA_CLANG(diagnostic ignored "-Wundefined-var-template")
862
863 iterator it = map.find(key);
864 if (it == map.end()) {
865 [[maybe_unused]] auto&& [tmpit, inserted] = map.insert(datumT(key, std::make_shared< GaussianConvolution1D<Q> >(k,
866 Q(sqrt(expnt/constants::pi)),
867 expnt,
868 m,
869 periodic
870 )));
871 MADNESS_ASSERT(inserted);
872 it = map.find(key);
873 //printf("conv1d: making %d %.8e\n",k,expnt);
874 }
875 else {
876 //printf("conv1d: reusing %d %.8e\n",k,expnt);
877 }
878 return it->second;
879
880 MADNESS_PRAGMA_CLANG(diagnostic pop)
881
882 }
883 };
884
885 // instantiated in mra1.cc
886 template <>
887 ConcurrentHashMap< hashT, std::shared_ptr< GaussianConvolution1D<double> > >
889
890 // instantiated in mra1.cc
891 template <>
894
895}
896
897#endif // MADNESS_MRA_CONVOLUTION1D_H__INCLUDED
Provides routines for internal use optimized for aligned data.
std::complex< double > double_complex
Definition cfft.h:14
long dim(int i) const
Returns the size of dimension i.
Definition basetensor.h:147
Definition worldhashmap.h:396
Provides the common functionality/interface of all 1D convolutions.
Definition convolution1d.h:257
Convolution1D(int k, int npt, int maxR, double arg=0.0)
Definition convolution1d.h:277
SimpleCache< Tensor< Q >, 1 > rnlp_cache
Definition convolution1d.h:270
Tensor< double > hgT2k
Definition convolution1d.h:267
virtual Level natural_level() const
Returns the level for projection.
Definition convolution1d.h:325
int maxR
Number of lattice translations for sum.
Definition convolution1d.h:262
Tensor< double > hg
Definition convolution1d.h:266
int k
Wavelet order.
Definition convolution1d.h:260
SimpleCache< ConvolutionData1D< Q >, 1 > ns_cache
Definition convolution1d.h:272
Tensor< double > hgT
Definition convolution1d.h:266
Tensor< double > c
Definition convolution1d.h:265
const Tensor< Q > & get_rnlp(Level n, Translation lx) const
Definition convolution1d.h:498
SimpleCache< Tensor< Q >, 1 > rnlij_cache
Definition convolution1d.h:271
virtual Tensor< Q > rnlp(Level n, Translation lx) const =0
Compute the projection of the operator onto the double order polynomials.
int npt
Number of quadrature points (is this used?)
Definition convolution1d.h:261
virtual ~Convolution1D()
Definition convolution1d.h:275
Tensor< double > quad_w
Definition convolution1d.h:264
Q phase(double R) const
Definition convolution1d.h:489
SimpleCache< ConvolutionData1D< Q >, 2 > mod_ns_cache
Definition convolution1d.h:273
bool get_issmall(Level n, Translation lx) const
Returns true if the block of rnlp is expected to be small including periodicity.
Definition convolution1d.h:308
Tensor< double > quad_x
Definition convolution1d.h:263
const Tensor< Q > & rnlij(Level n, Translation lx, bool do_transpose=false) const
Computes the transition matrix elements for the convolution for n,l.
Definition convolution1d.h:336
virtual bool issmall(Level n, Translation lx) const =0
Returns true if the block of rnlp is expected to be small.
Q phase(double_complex R) const
Definition convolution1d.h:493
const ConvolutionData1D< Q > * mod_nonstandard(const Key< 2 > &op_key) const
Returns a pointer to the cached modified make_nonstandard form of the operator.
Definition convolution1d.h:359
double arg
Definition convolution1d.h:268
Q opT
The apply function uses this to infer resultT=opT*inputT.
Definition convolution1d.h:259
const ConvolutionData1D< Q > * nonstandard(Level n, Translation lx) const
Returns a pointer to the cached make_nonstandard form of the operator.
Definition convolution1d.h:426
Array of 1D convolutions (one / dimension)
Definition convolution1d.h:543
std::shared_ptr< Convolution1D< Q > > getop(int dim) const
Definition convolution1d.h:564
void setop(int dim, const std::shared_ptr< Convolution1D< Q > > &op)
Definition convolution1d.h:560
ConvolutionND(const ConvolutionND &other)
Definition convolution1d.h:550
ConvolutionND()
Definition convolution1d.h:548
std::array< std::shared_ptr< Convolution1D< Q > >, NDIM > ops
Definition convolution1d.h:544
Q fac
Definition convolution1d.h:545
ConvolutionND(std::shared_ptr< Convolution1D< Q > > op, Q fac=1.0)
Definition convolution1d.h:555
Q getfac() const
Definition convolution1d.h:572
void setfac(Q value)
Definition convolution1d.h:568
1D convolution with (derivative) Gaussian; coeff and expnt given in simulation coordinates [0,...
Definition convolution1d.h:683
const int m
Order of derivative (0, 1, or 2 only)
Definition convolution1d.h:697
static int maxR(bool periodic, double expnt)
Definition convolution1d.h:685
virtual Level natural_level() const
Returns the level for projection.
Definition convolution1d.h:719
bool issmall(Level n, Translation lx) const
Returns true if the block is expected to be small.
Definition convolution1d.h:833
GaussianConvolution1D(int k, Q coeff, double expnt, int m, bool periodic, double arg=0.0)
Definition convolution1d.h:699
virtual ~GaussianConvolution1D()
Definition convolution1d.h:717
const double expnt
Exponent.
Definition convolution1d.h:695
const Level natlev
Level to evaluate.
Definition convolution1d.h:696
Tensor< Q > rnlp(Level n, Translation lx) const
Compute the projection of the operator onto the double order polynomials.
Definition convolution1d.h:740
const Q coeff
Coefficient.
Definition convolution1d.h:694
Definition convolution1d.h:579
Q coeff
Definition convolution1d.h:581
int m
Definition convolution1d.h:583
Level natural_level() const
Definition convolution1d.h:597
Level natlev
Definition convolution1d.h:584
GaussianGenericFunctor(Q coeff, double exponent, int m=0)
Definition convolution1d.h:588
Q operator()(double x) const
Definition convolution1d.h:592
double exponent
Definition convolution1d.h:582
Generic 1D convolution using brute force (i.e., slow) adaptive quadrature for rnlp.
Definition convolution1d.h:605
Tensor< Q > rnlp(Level n, Translation lx) const
Compute the projection of the operator onto the double order polynomials.
Definition convolution1d.h:658
opT op
Definition convolution1d.h:607
bool issmall(Level n, Translation lx) const
Returns true if the block of rnlp is expected to be small.
Definition convolution1d.h:663
long maxl
At natural level is l beyond which operator is zero.
Definition convolution1d.h:608
virtual Level natural_level() const
Returns the level for projection.
Definition convolution1d.h:635
GenericConvolution1D()
Definition convolution1d.h:611
GenericConvolution1D(int k, const opT &op, int maxR, double arg=0.0)
Definition convolution1d.h:613
iterator for hash
Definition worldhashmap.h:188
Key is the index for a node of the 2^NDIM-tree.
Definition key.h:66
Level level() const
Definition key.h:159
const Vector< Translation, NDIM > & translation() const
Definition key.h:164
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
A tensor is a multidimension array.
Definition tensor.h:317
float_scalar_type normf() const
Returns the Frobenius norm of the tensor.
Definition tensor.h:1726
TensorTypeData< T >::scalar_type scalar_type
C++ typename of the real type associated with a complex type.
Definition tensor.h:409
T * ptr()
Returns a pointer to the internal data.
Definition tensor.h:1824
Tensor< T > & gaxpy(T alpha, const Tensor< T > &t, T beta)
Inplace generalized saxpy ... this = this*alpha + other*beta.
Definition tensor.h:1804
A simple, fixed dimension vector.
Definition vector.h:64
Defines common mathematical and physical constants.
static const double R
Definition csqrt.cc:46
char * p(char *buf, const char *name, int k, int initial_level, double thresh, int order)
Definition derivatives.cc:72
auto T(World &world, response_space &f) -> response_space
Definition global_functions.cc:34
const double beta
Definition gygi_soltion.cc:62
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 MADNESS_PRAGMA_CLANG(x)
Definition madness_config.h:200
#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_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
const double pi
Mathematical constant .
Definition constants.h:48
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:10
bool two_scale_hg(int k, Tensor< double > *hg)
Definition twoscale.cc:151
void aligned_add(long n, double *MADNESS_RESTRICT a, const double *MADNESS_RESTRICT b)
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:69
void legendre_scaling_functions(double x, long k, double *p)
Evaluate the first k Legendre scaling functions.
Definition legendre.cc:85
std::vector< Function< TENSOR_RESULT_TYPE(T, R), NDIM > > transform(World &world, const std::vector< Function< T, NDIM > > &v, const Tensor< R > &c, bool fence=true)
Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i].
Definition vmra.h:689
response_space transpose(response_space &f)
Definition basic_operators.cc:10
void hash_combine(hashT &seed, const T &v)
Combine hash values.
Definition worldhash.h:260
int64_t Translation
Definition key.h:54
int Level
Definition key.h:55
static void copy_2d_patch(T *MADNESS_RESTRICT out, long ldout, const T *MADNESS_RESTRICT in, long ldin, long n, long m)
Definition convolution1d.h:59
bool autoc(int k, Tensor< double > *c)
Return the autocorrelation coefficients for scaling functions of given order.
Definition twoscale.cc:234
bool gauss_legendre(int n, double xlo, double xhi, double *x, double *w)
Definition legendre.cc:226
static double pop(std::vector< double > &v)
Definition SCF.cc:113
void svd(const Tensor< T > &a, Tensor< T > &U, Tensor< typename Tensor< T >::scalar_type > &s, Tensor< T > &VT)
Compute the singluar value decomposition of an n-by-m matrix using *gesvd.
Definition lapack.cc:739
NDIM & f
Definition mra.h:2416
std::size_t hashT
The hash value type.
Definition worldhash.h:145
double inner(response_space &a, response_space &b)
Definition response_functions.h:442
void aligned_sub(long n, double *MADNESS_RESTRICT a, const double *MADNESS_RESTRICT b)
funcT::returnT adq1(double lo, double hi, const funcT &func, double thresh, int n, const double *x, const double *w, int level)
Definition adquad.h:64
madness::hashT hash_value(const std::array< T, N > &a)
Hash std::array with madness hash.
Definition array_addons.h:78
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:2002
static long abs(long a)
Definition tensor.h:218
static const double b
Definition nonlinschro.cc:119
static const double a
Definition nonlinschro.cc:118
double Q(double a)
Definition relops.cc:20
static const double m
Definition relops.cc:9
static const long k
Definition rk.cc:44
!!! Note that if Rnormf is zero then ALL of the tensors are empty
Definition convolution1d.h:161
Tensor< Q > T
if NS: R=ns, T=T part of ns; if modified NS: T=\uparrow r^(n-1)
Definition convolution1d.h:164
double Rnorm
Definition convolution1d.h:169
Tensor< typename Tensor< Q >::scalar_type > Rs
Definition convolution1d.h:166
void make_approx(const Tensor< Q > &R, Tensor< Q > &RU, Tensor< typename Tensor< Q >::scalar_type > &Rs, Tensor< Q > &RVT, double &norm)
Definition convolution1d.h:228
double N_up
Definition convolution1d.h:172
double NSnormf
Definition convolution1d.h:169
double Rnormf
Definition convolution1d.h:169
Tensor< Q > TU
Definition convolution1d.h:165
ConvolutionData1D(const Tensor< Q > &R, const Tensor< Q > &T)
Definition convolution1d.h:179
double N_F
the norms according to Beylkin 2008, Eq. (21) ff
Definition convolution1d.h:172
double N_diff
Definition convolution1d.h:172
Tensor< Q > RU
Definition convolution1d.h:165
double Tnorm
Definition convolution1d.h:169
Tensor< typename Tensor< Q >::scalar_type > Ts
hold relative errors, NOT the singular values..
Definition convolution1d.h:166
ConvolutionData1D(const Tensor< Q > &R, const Tensor< Q > &T, const bool modified)
Definition convolution1d.h:207
double Tnormf
Definition convolution1d.h:169
Tensor< Q > R
Definition convolution1d.h:164
Tensor< Q > TVT
SVD approximations to R and T.
Definition convolution1d.h:165
Tensor< Q > RVT
Definition convolution1d.h:165
Definition convolution1d.h:849
ConcurrentHashMap< hashT, std::shared_ptr< GaussianConvolution1D< Q > > >::iterator iterator
Definition convolution1d.h:851
static ConcurrentHashMap< hashT, std::shared_ptr< GaussianConvolution1D< Q > > > map
Definition convolution1d.h:850
static std::shared_ptr< GaussianConvolution1D< Q > > get(int k, double expnt, int m, bool periodic)
Definition convolution1d.h:854
ConcurrentHashMap< hashT, std::shared_ptr< GaussianConvolution1D< Q > > >::datumT datumT
Definition convolution1d.h:852
Definition convolution1d.h:637
returnT operator()(double x) const
Definition convolution1d.h:646
Tensor< Q > returnT
Definition convolution1d.h:638
Translation lx
Definition convolution1d.h:640
Level n
Definition convolution1d.h:639
Shmoo(Level n, Translation lx, const GenericConvolution1D< Q, opT > *q)
Definition convolution1d.h:643
const GenericConvolution1D< Q, opT > & q
Definition convolution1d.h:641
static const double s0
Definition tdse4.cc:83
Defines and implements most of Tensor.
Prototypes for a partial interface from Tensor to LAPACK.
double norm(const T i1)
Definition test_cloud.cc:72
void e()
Definition test_sig.cc:75
double h(const coord_1d &r)
Definition testgconv.cc:68
static const std::size_t NDIM
Definition testpdiff.cc:42
Implement the madness:Vector class, an extension of std::array that supports some mathematical operat...
const double a2
Definition vnucso.cc:86
const double a1
Definition vnucso.cc:85