MADNESS  version 0.9
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  $Id$
32 */
33 #ifndef MADNESS_MRA_OPERATOR_H__INCLUDED
34 #define MADNESS_MRA_OPERATOR_H__INCLUDED
35 
38 
40 
41 #include <limits.h>
42 #include <madness/mra/adquad.h>
43 #include <madness/tensor/mtxmq.h>
44 #include <madness/tensor/aligned.h>
46 #include <madness/constants.h>
47 
52 #include <madness/mra/gfit.h>
53 
54 namespace madness {
55 
56 
59  template <typename Q, std::size_t NDIM>
61  double norm;
63  };
64 
66 
68  template <typename Q, std::size_t NDIM>
70  std::vector< SeparatedConvolutionInternal<Q,NDIM> > muops;
71  double norm;
72 
73  SeparatedConvolutionData(int rank) : muops(rank), norm(0.0) {}
75  muops = q.muops;
76  norm = q.norm;
77  }
78  };
79 
80 
82 
83  /* this stuff is very confusing, poorly commented, and extremely poorly named!
84 
85  I think it works like this:
86  We try to apply transition matrices to the compressed form of function coefficients.
87  Most of the code is about caching these transition matrices. They are cached (key of the map is the displacement)
88  in the SimpleCache "data", which is of type SeparatedConvolutionData, which keeps the matrices
89  for all separated terms and dimensions. These SeparatedConvolutionData are constructed using
90  ConvolutionND "ops", which is constructed at the construction of the SeparatedConvolution.
91 
92  SeparatedConvolution (all terms, all dim, all displacements)
93 
94  construction storage
95 
96  SimpleCache<SeparatedConvolutionData>
97  (all terms, all dim) / (all disp)
98  vector<ConvolutionND>
99  (1 term, all dim) / (all terms)
100  vector<SeparatedConvolutionInternal>
101  (1 term, all dim) / (all terms)
102 
103 
104  vector<ConvolutionData1D>
105  (1 term, 1 dim) / (all dim)
106 
107  ConvolutionND and SeparatedConvolutionInternal both point to the same data in ConvolutionData1D.
108  Why we need SeparatedConvolutionInternal in the first place I have no idea. ConvolutionND has the global
109  factor, and SeparatedConvolutionInternal has a norm.
110 
111 
112  */
113 
114 
115 
116  template <typename Q, std::size_t NDIM>
117  class SeparatedConvolution : public WorldObject< SeparatedConvolution<Q,NDIM> > {
118  public:
119  typedef Q opT;
120  bool doleaves;
122  bool modified_;
126 
127  typedef Key<NDIM> keyT;
128  const static size_t opdim=NDIM;
132 
133  // if this is a Slater-type convolution kernel: 1-exp(-mu r12)/(2 mu)
135  double mu_;
136 
137  private:
138 
139 
140  mutable std::vector< ConvolutionND<Q,NDIM> > ops;
141  const BoundaryConditions<NDIM> bc;
142  const int k;
143  const FunctionCommonData<Q,NDIM>& cdata;
144  const int rank;
145  const std::vector<long> vk;
146  const std::vector<long> v2k;
147  const std::vector<Slice> s0;
148 
149  // SeparatedConvolutionData keeps data for all terms and all dimensions and 1 displacement
152 
153  public:
154 
155  bool& modified() {return modified_;}
156  const bool& modified() const {return modified_;}
157 
158  int& particle() {return particle_;}
159  const int& particle() const {return particle_;}
160 
161  bool& destructive() {return destructive_;}
162  const bool& destructive() const {return destructive_;}
163 
164  const double& gamma() const {return mu_;}
165  const double& mu() const {return mu_;}
166 
167  private:
168 
170  struct ApplyTerms {
171  ApplyTerms() : r_term(false), t_term(false) {}
172  bool r_term;
173  bool t_term;
174  bool any_terms() const {return r_term or t_term;}
175  };
176 
178  struct Transformation {
179  long r; // Effective rank of transformation
180  const Q* U; // Ptr to matrix
181  const Q* VT;
182  };
183 
184 // /// return the right block of the upsampled operator (modified NS only)
185 //
186 // /// unlike the operator matrices on the natural level the upsampled operator
187 // /// matrices are not Toeplitz, so we need more information than just the displacement
188 // ///.@param[in] source the source key
189 // /// @param[in] disp the displacement
190 // /// @param[in] upop the unfiltered operator matrix from scale n-1
191 // /// @return (k,k) patch of the upop(2k,2k) matrix
192 // static Tensor<Q> operator_patch(const Translation& source, const Translation& disp, const Tensor<Q>& upop) {
193 //
194 // // which of the 4 upsampled matrices do we need?
195 // Translation sx=source%2; // source offset
196 // Translation tx=(source+disp)%2; // target offset
197 //
198 // Tensor<Q> rij(k,k);
199 // // those two are equivalent:
201 // if (sx==0 and tx==0) copy_2d_patch(rij.ptr(), k, upop.ptr(), 2*k, k, k);
202 // if (sx==1 and tx==0) copy_2d_patch(rij.ptr() + k, k, upop.ptr(), 2*k, k, k);
203 // if (sx==0 and tx==1) copy_2d_patch(rij.ptr() + 2*k*k, k, upop.ptr(), 2*k, k, k);
204 // if (sx==1 and tx==1) copy_2d_patch(rij.ptr() + 2*k*k + k, k, upop.ptr(), 2*k, k, k);
205 //*/
206 // Slice s0(0,k-1), s1(k,2*k-1);
207 // if (sx==0 and tx==0) rij=Rm(s0,s0);
208 // if (sx==1 and tx==0) rij=Rm(s1,s0);
209 // if (sx==0 and tx==1) rij=Rm(s0,s1);
210 // if (sx==1 and tx==1) rij=Rm(s1,s1);
211 //
212 // return rij;
213 // }
214 
215 
216 
218  template <typename T, typename R>
219  void apply_transformation(long dimk,
220  const Transformation trans[NDIM],
221  const Tensor<T>& f,
222  Tensor<R>& work1,
223  Tensor<R>& work2,
224  Tensor<Q>& work3,
225  const Q mufac,
226  Tensor<R>& result) const {
227 
229  long size = 1;
230  for (std::size_t i=0; i<NDIM; ++i) size *= dimk;
231  long dimi = size/dimk;
232 
233  R* restrict w1=work1.ptr();
234  R* restrict w2=work2.ptr();
235 #ifndef HAVE_IBMBGQ
236  Q* restrict w3=work3.ptr();
237  const Q* U;
238 #endif
239 
240 #ifdef HAVE_IBMBGQ
241  mTxmq_padding(dimi, trans[0].r, dimk, dimk, w1, f.ptr(), trans[0].U);
242 #else
243  U = (trans[0].r == dimk) ? trans[0].U : shrink(dimk,dimk,trans[0].r,trans[0].U,w3);
244  mTxmq(dimi, trans[0].r, dimk, w1, f.ptr(), U);
245 #endif
246 
247  size = trans[0].r * size / dimk;
248  dimi = size/dimk;
249  for (std::size_t d=1; d<NDIM; ++d) {
250 #ifdef HAVE_IBMBGQ
251  mTxmq_padding(dimi, trans[d].r, dimk, dimk, w2, w1, trans[d].U);
252 #else
253  U = (trans[d].r == dimk) ? trans[d].U : shrink(dimk,dimk,trans[d].r,trans[d].U,w3);
254  mTxmq(dimi, trans[d].r, dimk, w2, w1, U);
255 #endif
256  size = trans[d].r * size / dimk;
257  dimi = size/dimk;
258  std::swap(w1,w2);
259  }
260 
261  // If all blocks are full rank we can skip the transposes
262  bool doit = false;
263  for (std::size_t d=0; d<NDIM; ++d) doit = doit || trans[d].VT;
264 
265  if (doit) {
266  for (std::size_t d=0; d<NDIM; ++d) {
267  if (trans[d].VT) {
268  dimi = size/trans[d].r;
269 #ifdef HAVE_IBMBGQ
270  mTxmq_padding(dimi, dimk, trans[d].r, dimk, w2, w1, trans[d].VT);
271 #else
272  mTxmq(dimi, dimk, trans[d].r, w2, w1, trans[d].VT);
273 #endif
274  size = dimk*size/trans[d].r;
275  }
276  else {
277  fast_transpose(dimk, dimi, w1, w2);
278  }
279  std::swap(w1,w2);
280  }
281  }
282  // Assuming here that result is contiguous and aligned
283  aligned_axpy(size, result.ptr(), w1, mufac);
284  }
285 
286 
288  template <typename T, typename R>
289  void apply_transformation3(const Tensor<T> trans2[NDIM],
290  const Tensor<T>& f,
291  const Q mufac,
292  Tensor<R>& result) const {
293 
295 
296  Tensor<R> result2=general_transform(f,trans2);
297  result2.scale(mufac);
298  result+=result2;
299 
300  }
301 
302 
303 
305  template <typename T, typename R>
306  void apply_transformation2(Level n, long dimk, double tol,
307  const Tensor<T> trans2[NDIM],
308  const GenTensor<T>& f,
309  GenTensor<R>& work1,
310  GenTensor<R>& work2,
311  GenTensor<Q>& work3,
312  const Q mufac,
313  GenTensor<R>& result) const {
314 
316 
317 #if 1
318  result=general_transform(f,trans2);
319  result.scale(mufac);
320 
321 #else
322 
323  long size = 1;
324  for (std::size_t i=0; i<NDIM; ++i) size *= dimk;
325  long dimi = size/dimk;
326 
327  R* restrict w1=work1.ptr();
328  R* restrict w2=work2.ptr();
329  Q* restrict w3=work3.ptr();
330 
331  const Q* U;
332 
333  U = (trans[0].r == dimk) ? trans[0].U : shrink(dimk,dimk,trans[0].r,trans[0].U,w3);
334  mTxmq(dimi, trans[0].r, dimk, w1, f.ptr(), U);
335  size = trans[0].r * size / dimk;
336  dimi = size/dimk;
337  for (std::size_t d=1; d<NDIM; ++d) {
338  U = (trans[d].r == dimk) ? trans[d].U : shrink(dimk,dimk,trans[d].r,trans[d].U,w3);
339  mTxmq(dimi, trans[d].r, dimk, w2, w1, U);
340  size = trans[d].r * size / dimk;
341  dimi = size/dimk;
342  std::swap(w1,w2);
343  }
344 
345  // If all blocks are full rank we can skip the transposes
346  bool doit = false;
347  for (std::size_t d=0; d<NDIM; ++d) doit = doit || trans[d].VT;
348 
349  if (doit) {
350  for (std::size_t d=0; d<NDIM; ++d) {
351  if (trans[d].VT) {
352  dimi = size/trans[d].r;
353  mTxmq(dimi, dimk, trans[d].r, w2, w1, trans[d].VT);
354  size = dimk*size/trans[d].r;
355  }
356  else {
357  fast_transpose(dimk, dimi, w1, w2);
358  }
359  std::swap(w1,w2);
360  }
361  }
362  // Assuming here that result is contiguous and aligned
363  aligned_axpy(size, result.ptr(), w1, mufac);
364  // long one = 1;
365  //daxpy_(&size, &mufac, w1, &one, result.ptr(), &one);
366 #endif
367  }
368 
369 
371  template <typename T>
372  void muopxv_fast(ApplyTerms at,
373  const ConvolutionData1D<Q>* const ops_1d[NDIM],
374  const Tensor<T>& f, const Tensor<T>& f0,
375  Tensor<TENSOR_RESULT_TYPE(T,Q)>& result,
376  Tensor<TENSOR_RESULT_TYPE(T,Q)>& result0,
377  double tol,
378  const Q mufac,
379  Tensor<TENSOR_RESULT_TYPE(T,Q)>& work1,
380  Tensor<TENSOR_RESULT_TYPE(T,Q)>& work2,
381  Tensor<Q>& work5) const {
382 
384  Transformation trans[NDIM];
385  Tensor<T> trans2[NDIM];
386 
387  double Rnorm = 1.0;
388  for (std::size_t d=0; d<NDIM; ++d) Rnorm *= ops_1d[d]->Rnorm;
389 
390  if (at.r_term and (Rnorm > 1.e-20)) {
391 
392  tol = tol/(Rnorm*NDIM); // Errors are relative within here
393 
394  // Determine rank of SVD to use or if to use the full matrix
395  long twok = 2*k;
396  if (modified()) twok=k;
397 
398  long break_even;
399  if (NDIM==1) break_even = long(0.5*twok);
400  else if (NDIM==2) break_even = long(0.6*twok);
401  else if (NDIM==3) break_even=long(0.65*twok);
402  else break_even=long(0.7*twok);
403  for (std::size_t d=0; d<NDIM; ++d) {
404  long r;
405  for (r=0; r<twok; ++r) {
406  if (ops_1d[d]->Rs[r] < tol) break;
407  }
408  if (r >= break_even) {
409  trans[d].r = twok;
410  trans[d].U = ops_1d[d]->R.ptr();
411  trans[d].VT = 0;
412  }
413  else {
414  r += (r&1L);
415  trans[d].r = std::max(2L,r);
416  trans[d].U = ops_1d[d]->RU.ptr();
417  trans[d].VT = ops_1d[d]->RVT.ptr();
418  }
419  trans2[d]=ops_1d[d]->R;
420  }
421  apply_transformation(twok, trans, f, work1, work2, work5, mufac, result);
422  // apply_transformation2(n, twok, tol, trans2, f, work1, work2, work5, mufac, result);
423 // apply_transformation3(trans2, f, mufac, result);
424  }
425 
426  double Tnorm = 1.0;
427  for (std::size_t d=0; d<NDIM; ++d) Tnorm *= ops_1d[d]->Tnorm;
428 
429  if (at.t_term and (Tnorm>0.0)) {
430  tol = tol/(Tnorm*NDIM); // Errors are relative within here
431 
432  long break_even;
433  if (NDIM==1) break_even = long(0.5*k);
434  else if (NDIM==2) break_even = long(0.6*k);
435  else if (NDIM==3) break_even=long(0.65*k);
436  else break_even=long(0.7*k);
437  for (std::size_t d=0; d<NDIM; ++d) {
438  long r;
439  for (r=0; r<k; ++r) {
440  if (ops_1d[d]->Ts[r] < tol) break;
441  }
442  if (r >= break_even) {
443  trans[d].r = k;
444  trans[d].U = ops_1d[d]->T.ptr();
445  trans[d].VT = 0;
446  }
447  else {
448  r += (r&1L);
449  trans[d].r = std::max(2L,r);
450  trans[d].U = ops_1d[d]->TU.ptr();
451  trans[d].VT = ops_1d[d]->TVT.ptr();
452  }
453  trans2[d]=ops_1d[d]->T;
454  }
455  apply_transformation(k, trans, f0, work1, work2, work5, -mufac, result0);
456 // apply_transformation2(n, k, tol, trans2, f0, work1, work2, work5, -mufac, result0);
457 // apply_transformation3(trans2, f0, -mufac, result0);
458  }
459  }
460 
461 
463  template <typename T>
464  void muopxv_fast2(Level n,
465  const ConvolutionData1D<Q>* const ops_1d[NDIM],
466  const GenTensor<T>& f, const GenTensor<T>& f0,
467  GenTensor<TENSOR_RESULT_TYPE(T,Q)>& result,
468  GenTensor<TENSOR_RESULT_TYPE(T,Q)>& result0,
469  double tol,
470  const Q mufac,
471  GenTensor<TENSOR_RESULT_TYPE(T,Q)>& work1,
472  GenTensor<TENSOR_RESULT_TYPE(T,Q)>& work2,
473  GenTensor<Q>& work5) const {
474 
476 // Transformation trans[NDIM];
477  Tensor<T> trans2[NDIM];
478 // MADNESS_EXCEPTION("no muopxv_fast2",1);
479 
480  double Rnorm = 1.0;
481  for (std::size_t d=0; d<NDIM; ++d) Rnorm *= ops_1d[d]->Rnorm;
482  if (Rnorm == 0.0) return;
483 
484  if (Rnorm > 1.e-20) {
485 
486  tol = tol/(Rnorm*NDIM); // Errors are relative within here
487 
488  // Determine rank of SVD to use or if to use the full matrix
489  long twok = 2*k;
490  if (modified()) twok=k;
491 // long break_even;
492 // if (NDIM==1) break_even = long(0.5*twok);
493 // else if (NDIM==2) break_even = long(0.6*twok);
494 // else if (NDIM==3) break_even=long(0.65*twok);
495 // else break_even=long(0.7*twok);
496  for (std::size_t d=0; d<NDIM; ++d) {
497  long r;
498  for (r=0; r<twok; ++r) {
499  if (ops_1d[d]->Rs[r] < tol) break;
500  }
501 // if (r >= break_even) {
502 // trans[d].r = twok;
503 // trans[d].U = ops_1d[d]->R.ptr();
504 // trans[d].VT = 0;
505 // }
506 // else {
507 // r += (r&1L);
508 // trans[d].r = std::max(2L,r);
509 // trans[d].U = ops_1d[d]->RU.ptr();
510 // trans[d].VT = ops_1d[d]->RVT.ptr();
511 // }
512  trans2[d]=ops_1d[d]->R;
513  }
514  apply_transformation2(n, twok, tol, trans2, f, work1, work2, work5, mufac, result);
515  }
516 
517  double Tnorm = 1.0;
518  for (std::size_t d=0; d<NDIM; ++d) Tnorm *= ops_1d[d]->Tnorm;
519 
520  if (n > 0 and (Tnorm>1.e-20)) {
521 // long break_even;
522 //
523 // if (NDIM==1) break_even = long(0.5*k);
524 // else if (NDIM==2) break_even = long(0.6*k);
525 // else if (NDIM==3) break_even=long(0.65*k);
526 // else break_even=long(0.7*k);
527  for (std::size_t d=0; d<NDIM; ++d) {
528  long r;
529  for (r=0; r<k; ++r) {
530  if (ops_1d[d]->Ts[r] < tol) break;
531  }
532 // if (r >= break_even) {
533 // trans[d].r = k;
534 // trans[d].U = ops_1d[d]->T.ptr();
535 // trans[d].VT = 0;
536 // }
537 // else {
538 // r += (r&1L);
539 // trans[d].r = std::max(2L,r);
540 // trans[d].U = ops_1d[d]->TU.ptr();
541 // trans[d].VT = ops_1d[d]->TVT.ptr();
542 // }
543  trans2[d]=ops_1d[d]->T;
544  }
545  apply_transformation2(n, k, tol, trans2, f0, work1, work2, work5, -mufac, result0);
546  }
547  }
548 
549 
552  double munorm2(Level n, const ConvolutionData1D<Q>* ops[]) const {
553  if (modified()) return munorm2_modified(n,ops);
554  return munorm2_ns(n,ops);
555  }
556 
560  double munorm2_ns(Level n, const ConvolutionData1D<Q>* ops[]) const {
562 
563  double prodR=1.0, prodT=1.0;
564  for (std::size_t d=0; d<NDIM; ++d) {
565  prodR *= ops[d]->Rnormf;
566  prodT *= ops[d]->Tnormf;
567 
568  }
569  if (n) prodR = sqrt(std::max(prodR*prodR - prodT*prodT,0.0));
570 
571  // this kicks in if the line above has no numerically significant digits.
572  if (prodR < 1e-8*prodT) {
573  double prod=1.0, sum=0.0;
574  for (std::size_t d=0; d<NDIM; ++d) {
575  double a = ops[d]->NSnormf;
576  double b = ops[d]->Tnormf;
577  double aa = std::min(a,b);
578  double bb = std::max(a,b);
579  prod *= bb;
580  if (bb > 0.0) sum +=(aa/bb);
581  }
582  if (n) prod *= sum;
583  prodR = prod;
584  }
585 
586  return prodR;
587  }
588 
589 
593  double munorm2_modified(Level n, const ConvolutionData1D<Q>* ops_1d[]) const {
595 
596  // follows Eq. (21) ff of Beylkin 2008 (Beylkin Appl. Comput. Harmon. Anal. 24, pp 354)
597 
598  // we have all combinations of difference, upsampled, F terms (d, u, f),
599  // with the constraint that d is in each term exactly once. In the mixed terms (udf)
600  // we just get all possible combinations, in the pure terms (dff, duu) we have
601  // to multiply each term (dff, fdf, ffd) with (NDIM-1)!, to get the right number.
602 
603  double dff = 0.0;
604  double duu = 0.0;
605  double udf = 0.0;
606 
607  // loop over d shifting over the dimensions dxx, xdx, xxd,
608  for (size_t d=0; d<NDIM; ++d) {
609  double dff_tmp = ops_1d[d]->N_diff;
610  double duu_tmp = ops_1d[d]->N_diff;
611  double udf_tmp = ops_1d[d]->N_diff;
612 
613 
614  for (size_t dd=0; dd<NDIM; ++dd) {
615  if (dd!=d) {
616  dff_tmp *= ops_1d[dd]->N_F;
617  duu_tmp *= ops_1d[dd]->N_up;
618 
619  udf_tmp *= ops_1d[dd]->N_F;
620  for (size_t ddd=0; ddd<NDIM; ++ddd) {
621  if (ddd!=dd) udf += udf_tmp * ops_1d[ddd]->N_up;
622  }
623  }
624  }
625 
626  dff+=dff_tmp;
627  duu+=duu_tmp;
628  }
629 
630  // finalize with the factorial
631  double factorial=1.0;
632  for (int i=1; i<static_cast<int>(NDIM)-1; ++i) factorial*=double(i);
633  dff*=factorial;
634  duu*=factorial;
635 
636  // Eq. (23) of Beylkin 2008, for one separated term WITHOUT the factor
637  double norm=(dff + udf + duu) /(factorial * double(NDIM));
638 
639 // // double check
640 // if (NDIM==3) {
641 // Tensor<Q> R_full=outer(ops_1d[0]->R,outer(ops_1d[1]->R,ops_1d[2]->R));
642 // Tensor<Q> T_full=outer(ops_1d[0]->T,outer(ops_1d[1]->T,ops_1d[2]->T));
643 // double n2=(R_full-T_full).normf();
645 // norm=n2;
646 // }
647 
648  return norm;
649 
650  }
651 
652 
654 
656  const SeparatedConvolutionInternal<Q,NDIM> getmuop(int mu, Level n, const Key<NDIM>& disp) const {
658  SeparatedConvolutionInternal<Q,NDIM> op;
659  for (std::size_t d=0; d<NDIM; ++d) {
660  op.ops[d] = ops[mu].getop(d)->nonstandard(n, disp.translation()[d]);
661  }
662  op.norm = munorm2(n, op.ops)*std::abs(ops[mu].getfac());
663 
664 // double newnorm = munorm2(n, op.ops);
665 // // This rescaling empirically based upon BSH separated expansion
666 // // ... needs more testing. OK also for TDSE.
667 // // All is good except for some 000 blocks which are up to sqrt(k^d) off.
668 // for (int d=0; d<NDIM; ++d) {
669 // if (disp[d] == 0) newnorm *= 0.5;
670 // else if (std::abs(disp[d]) == 1) newnorm *= 0.8;
671 // }
672 // double oldnorm = munorm(n, op.ops);
673 // if (oldnorm > 1e-13 && (newnorm < 0.5*oldnorm || newnorm > 2.0*oldnorm) )
674 // print("munorm", n, disp, mu, newnorm, oldnorm, newnorm/oldnorm);
675 
676  return op;
677  }
678 
679 
680 
682 
685  const SeparatedConvolutionInternal<Q,NDIM>
686  getmuop_modified(int mu, Level n, const Key<NDIM>& disp, const Key<NDIM>& source) const {
688 
689 
690  // SeparatedConvolutionInternal keeps data for 1 term and all dimensions
691  SeparatedConvolutionInternal<Q,NDIM> op;
692 
693  // in the modified NS form we need not only the displacement, but also the source Translation
694  // for correctly constructing the operator, b/c the operator is not Toeplitz
695 
696  // op.ops is of type ConvolutionData1D (1 term, 1 dim, 1 disp)
697  // ops[mu] is of type ConvolutionND (1 term, all dim, 1 disp)
698  for (std::size_t d=0; d<NDIM; ++d) {
699  Translation sx=source.translation()[d]; // source translation
700  Translation tx=source.translation()[d]+disp.translation()[d]; // target translation
701 
702  Key<2> op_key(n,Vector<Translation,2>(vec(sx,tx)));
703  op.ops[d] = ops[mu].getop(d)->mod_nonstandard(op_key);
704  }
705 
706  // works for both modified and not modified NS form
707  op.norm = munorm2(n, op.ops)*std::abs(ops[mu].getfac());
708 // op.norm=1.0;
709  return op;
710  }
711 
713  const SeparatedConvolutionData<Q,NDIM>* getop(Level n, const Key<NDIM>& d, const Key<NDIM>& source) const {
714 
715  // in the NS form the operator depends only on the displacement
716  if (not modified()) return getop_ns(n,d);
717  return getop_modified(n, d, source);
718  }
719 
720 
722 
727  const SeparatedConvolutionData<Q,NDIM>* getop_ns(Level n, const Key<NDIM>& d) const {
729  const SeparatedConvolutionData<Q,NDIM>* p = data.getptr(n,d);
730  if (p) return p;
731 
732  // get the data for each term
733  SeparatedConvolutionData<Q,NDIM> op(rank);
734  for (int mu=0; mu<rank; ++mu) {
735  // op.muops is of type SeparatedConvolutionInternal (1 term, all dim, 1 disp)
736  // getmuop uses ConvolutionND
737  op.muops[mu] = getmuop(mu, n, d);
738  }
739 
740  double norm = 0.0;
741  for (int mu=0; mu<rank; ++mu) {
742  const double munorm = op.muops[mu].norm;
743  norm += munorm*munorm;
744  }
745  //print("getop", n, d, norm);
746  op.norm = sqrt(norm);
747  data.set(n, d, op);
748  return data.getptr(n,d);
749  }
750 
751 
752 
754 
761  const SeparatedConvolutionData<Q,NDIM>* getop_modified(Level n, const Key<NDIM>& disp, const Key<NDIM>& source) const {
763 
764  // in the modified NS form the upsampled part of the operator depends on the modulus of the source
765  Vector<Translation,NDIM> t=source.translation();
766  for (size_t i=0; i<NDIM; ++i) t[i]=t[i]%2;
767  Key<2*NDIM> key=disp.merge_with(Key<NDIM>(source.level(),t));
768 
769  const SeparatedConvolutionData<Q,NDIM>* p = mod_data.getptr(n,key);
770  if (p) return p;
771 
772  // get the data for each term
773  // op.muops is of type SeparatedConvolutionInternal (1 term, all dim, 1 disp)
774  // getmuop uses ConvolutionND
775  SeparatedConvolutionData<Q,NDIM> op(rank);
776  for (int mu=0; mu<rank; ++mu) op.muops[mu] = getmuop_modified(mu, n, disp, source);
777 
778  double norm = 0.0;
779  for (int mu=0; mu<rank; ++mu) {
780  const double munorm = op.muops[mu].norm;
781  norm += munorm*munorm;
782  }
783 
784  op.norm = sqrt(norm);
785  mod_data.set(n, key, op);
786  return mod_data.getptr(n,key);
787  }
788 
789 
790  void check_cubic() {
791  // !!! NB ... cell volume obtained from global defaults
792  const Tensor<double>& cell_width = FunctionDefaults<NDIM>::get_cell_width();
793  // Check that the cell is cubic since currently is assumed
794  for (std::size_t d=1; d<NDIM; ++d) {
795  MADNESS_ASSERT(fabs(cell_width(d)-cell_width(0L)) < 1e-14*cell_width(0L));
796  }
797  }
798 
799 
801 
807  template<typename T, size_t FDIM>
808  GenTensor<T> partial_upsample(const Key<FDIM>& key, const GenTensor<T>& coeff, const int particle) const {
809 
810  if (coeff.rank()==0) return GenTensor<T>();
811  MADNESS_ASSERT(coeff.dim(0)==k);
812  if (NDIM==coeff.ndim()) {
813  MADNESS_ASSERT(particle==1); // other particle, leave this particle unchanged
814  return coeff;
815  }
816 
817  MADNESS_ASSERT(coeff.ndim()==FDIM);
818  MADNESS_ASSERT(particle==0 or (2*NDIM==FDIM));
819 
820  // the twoscale coefficients: for upsampling use h0/h1; see Alpert Eq (3.35a/b)
821  // handle the spectator dimensions with the identity matrix
822  const Tensor<T> h[2] = {cdata.h0, cdata.h1};
823  Tensor<T> identity(k,k);
824  for (int i=0; i<k; ++i) identity(i,i)=1.0;
825  Tensor<T> matrices[2*NDIM];
826 
827  // get the appropriate twoscale coefficients for each dimension
828  if (particle==0) {
829  for (size_t ii=0; ii<NDIM; ++ii) matrices[ii]=h[key.translation()[ii]%2];
830  for (size_t ii=0; ii<NDIM; ++ii) matrices[ii+NDIM]=identity;
831  } else if (particle==1) {
832  for (size_t ii=0; ii<NDIM; ++ii) matrices[ii]=identity;
833  for (size_t ii=0; ii<NDIM; ++ii) matrices[ii+NDIM]=h[key.translation()[ii+NDIM]%2];
834  } else {
835  MADNESS_EXCEPTION("unknown particle",1);
836  }
837 
838  // transform and accumulate on the result
839  const GenTensor<T> result=general_transform(coeff,matrices);
840  return result;
841  }
842 
843 
845 
850  template<typename T, size_t FDIM>
851  GenTensor<T> upsample(const Key<FDIM>& key, const GenTensor<T>& coeff) const {
852 
853  // the twoscale coefficients: for upsampling use h0/h1; see Alpert Eq (3.35a/b)
854  // note there are no difference coefficients; if you want that use unfilter
855  const Tensor<T> h[2] = {cdata.h0, cdata.h1};
856  Tensor<T> matrices[FDIM];
857 
858  // get the appropriate twoscale coefficients for each dimension
859  for (size_t ii=0; ii<FDIM; ++ii) matrices[ii]=h[key.translation()[ii]%2];
860 
861  // transform and accumulate on the result
862  const GenTensor<T> result=general_transform(coeff,matrices);
863  return result;
864  }
865 
866 
867  public:
868 
869  // For separated convolutions with same operator in each direction (isotropic)
871  std::vector< std::shared_ptr< Convolution1D<Q> > >& argops,
874  bool doleaves = false)
875  : WorldObject< SeparatedConvolution<Q,NDIM> >(world)
876  , doleaves(doleaves)
877  , isperiodicsum(bc(0,0)==BC_PERIODIC)
878  , modified_(false)
879  , particle_(1)
880  , destructive_(false)
881  , is_slaterf12(false)
882  , mu_(0.0)
883  , bc(bc)
884  , k(k)
885  , cdata(FunctionCommonData<Q,NDIM>::get(k))
886  , rank(argops.size())
887  , vk(NDIM,k)
888  , v2k(NDIM,2*k)
889  , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1))
890  {
891  // Presently we must have periodic or non-periodic in all dimensions.
892  for (std::size_t d=1; d<NDIM; ++d) {
893  MADNESS_ASSERT(bc(d,0)==bc(0,0));
894  }
895  check_cubic();
896 
897  for (unsigned int mu=0; mu < argops.size(); ++mu) {
898  this->ops.push_back(ConvolutionND<Q,NDIM>(argops[mu]));
899  }
900 
901  this->process_pending();
902  }
903 
904  // For general convolutions
906  std::vector< ConvolutionND<Q,NDIM> >& argops,
909  bool doleaves = false)
910  : WorldObject< SeparatedConvolution<Q,NDIM> >(world)
911  , doleaves(doleaves)
912  , isperiodicsum(bc(0,0)==BC_PERIODIC)
913  , modified_(false)
914  , particle_(1)
915  , destructive_(false)
916  , is_slaterf12(false)
917  , mu_(0.0)
918  , ops(argops)
919  , bc(bc)
920  , k(k)
921  , cdata(FunctionCommonData<Q,NDIM>::get(k))
922  , rank(argops.size())
923  , vk(NDIM,k)
924  , v2k(NDIM,2*k)
925  , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1))
926  {
927  // Presently we must have periodic or non-periodic in all dimensions.
928  for (std::size_t d=1; d<NDIM; ++d) {
929  MADNESS_ASSERT(bc(d,0)==bc(0,0));
930  }
931  this->process_pending();
932  }
933 
936  const Tensor<Q>& coeff, const Tensor<double>& expnt,
939  bool doleaves = false,
940  double mu=0.0)
941  : WorldObject< SeparatedConvolution<Q,NDIM> >(world)
942  , doleaves(doleaves)
943  , isperiodicsum(bc(0,0)==BC_PERIODIC)
944  , modified_(false)
945  , particle_(1)
946  , destructive_(false)
947  , is_slaterf12(mu>0.0)
948  , mu_(mu)
949  , ops(coeff.dim(0))
950  , bc(bc)
951  , k(k)
952  , cdata(FunctionCommonData<Q,NDIM>::get(k))
953  , rank(coeff.dim(0))
954  , vk(NDIM,k)
955  , v2k(NDIM,2*k)
956  , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1))
957  {
958  // Presently we must have periodic or non-periodic in all dimensions.
959  for (std::size_t d=1; d<NDIM; ++d) {
960  MADNESS_ASSERT(bc(d,0)==bc(0,0));
961  }
962 
963  const Tensor<double>& width = FunctionDefaults<NDIM>::get_cell_width();
964  const double pi = constants::pi;
965 
966  for (int mu=0; mu<rank; ++mu) {
967  Q c = std::pow(sqrt(expnt(mu)/pi),static_cast<int>(NDIM)); // Normalization coeff
968 
969  // We cache the normalized operator so the factor is the value we must multiply
970  // by to recover the coeff we want.
971  ops[mu].setfac(coeff(mu)/c);
972 
973  for (std::size_t d=0; d<NDIM; ++d) {
974  ops[mu].setop(d,GaussianConvolution1DCache<Q>::get(k, expnt(mu)*width[d]*width[d], 0, isperiodicsum));
975  }
976  }
977  }
978 
981  Vector<double,NDIM> args,
982  const Tensor<Q>& coeff, const Tensor<double>& expnt,
985  bool doleaves=false)
986  : WorldObject< SeparatedConvolution<Q,NDIM> >(world)
987  , doleaves(doleaves)
988  , isperiodicsum(bc(0,0)==BC_PERIODIC)
989  , modified_(false)
990  , particle_(1)
991  , destructive_(false)
992  , is_slaterf12(false)
993  , mu_(0.0)
994  , ops(coeff.dim(0))
995  , bc(bc)
996  , k(k)
997  , cdata(FunctionCommonData<Q,NDIM>::get(k))
998  , rank(coeff.dim(0))
999  , vk(NDIM,k)
1000  , v2k(NDIM,2*k)
1001  , s0(std::max<std::size_t>(2,NDIM),Slice(0,k-1))
1002  {
1003  // Presently we must have periodic or non-periodic in all dimensions.
1004  for (std::size_t d=1; d<NDIM; ++d) {
1005  MADNESS_ASSERT(bc(d,0)==bc(0,0));
1006  }
1007 
1008  const Tensor<double>& width = FunctionDefaults<NDIM>::get_cell_width();
1009 
1010  for (int mu=0; mu<rank; ++mu) {
1011  for (std::size_t d=0; d<NDIM; ++d) {
1012  Q c = pow(coeff[mu],1.0/NDIM);
1014  gcptr(new GaussianConvolution1D<Q>(k, c*width[d], expnt(mu)*width[d]*width[d],
1015  0, isperiodicsum, args[d]));
1016  ops[mu].setop(d,gcptr);
1017  }
1018  }
1019  }
1020 
1022 
1023  void print_timer() const {
1024  if (this->world.rank()==0) {
1025  timer_full.print("op full tensor ");
1026  timer_low_transf.print("op low rank transform");
1027  timer_low_accumulate.print("op low rank addition ");
1028  }
1029  }
1030 
1031  void reset_timer() const {
1032  if (this->world.rank()==0) {
1033  timer_full.reset();
1034  timer_low_transf.reset();
1035  timer_low_accumulate.reset();
1036  }
1037  }
1038 
1039  const BoundaryConditions<NDIM>& get_bc() const {return bc;}
1040 
1041  const std::vector< Key<NDIM> >& get_disp(Level n) const {
1042  return Displacements<NDIM>().get_disp(n, isperiodicsum);
1043  }
1044 
1046  double norm(Level n, const Key<NDIM>& d, const Key<NDIM>& source_key) const {
1047  // SeparatedConvolutionData keeps data for all terms and all dimensions and 1 displacement
1048 // return 1.0;
1049  return getop(n, d, source_key)->norm;
1050  }
1051 
1053 
1059  template<size_t FDIM>
1060  typename disable_if_c<FDIM==NDIM, Key<NDIM> >::type
1061  get_source_key(const Key<FDIM> key) const {
1062  Key<NDIM> source;
1063  Key<FDIM-NDIM> dummykey;
1064  if (particle()==1) key.break_apart(source,dummykey);
1065  if (particle()==2) key.break_apart(dummykey,source);
1066  return source;
1067  }
1068 
1070 
1076  template<size_t FDIM>
1077  typename enable_if_c<FDIM==NDIM, Key<NDIM> >::type
1078  get_source_key(const Key<FDIM> key) const {
1079  return key;
1080  }
1081 
1083 
1089  template <typename T, size_t FDIM>
1091  return madness::apply(*this, f);
1092  }
1093 
1095 
1099  template <typename T, size_t LDIM>
1102  MADNESS_ASSERT(not is_slaterf12);
1103  return madness::apply(*this, f1, f2);
1104  }
1105 
1106 
1108 
1114  template <typename T>
1115  Tensor<TENSOR_RESULT_TYPE(T,Q)> apply(const Key<NDIM>& source,
1116  const Key<NDIM>& shift,
1117  const Tensor<T>& coeff,
1118  double tol) const {
1120  MADNESS_ASSERT(coeff.ndim()==NDIM);
1121 
1122  double cpu0=cpu_time();
1123 
1124  typedef TENSOR_RESULT_TYPE(T,Q) resultT;
1125  const Tensor<T>* input = &coeff;
1126  Tensor<T> dummy;
1127 
1128  if (not modified()) {
1129  if (coeff.dim(0) == k) {
1130  // This processes leaf nodes with only scaling
1131  // coefficients ... FuncImpl::apply by default does not
1132  // apply the operator to these since for smoothing operators
1133  // it is not necessary. It is necessary for operators such
1134  // as differentiation and time evolution and will also occur
1135  // if the application of the operator widens the tree.
1136  dummy = Tensor<T>(v2k);
1137  dummy(s0) = coeff;
1138  input = &dummy;
1139  }
1140  else {
1141  MADNESS_ASSERT(coeff.dim(0)==2*k);
1142  }
1143  }
1144 
1145  tol = tol/rank; // Error is per separated term
1146  ApplyTerms at;
1147  at.r_term=true;
1148  at.t_term=(source.level()>0);
1149 
1151  const SeparatedConvolutionData<Q,NDIM>* op = getop(source.level(), shift, source);
1152 
1153  //print("sepop",source,shift,op->norm,tol);
1154 
1155  Tensor<resultT> r(v2k), r0(vk);
1156  Tensor<resultT> work1(v2k,false), work2(v2k,false);
1157  Tensor<Q> work5(2*k,2*k);
1158 
1159  if (modified()) {
1160  r=Tensor<resultT>(vk);
1161  work1=Tensor<resultT>(vk,false);
1162  work2=Tensor<resultT>(vk,false);
1163  work5=Tensor<Q>(k,k);
1164  }
1165 
1166  const Tensor<T> f0 = copy(coeff(s0));
1167  for (int mu=0; mu<rank; ++mu) {
1168  // SeparatedConvolutionInternal keeps data for 1 term and all dimensions and 1 displacement
1169  const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1170  if (muop.norm > tol) {
1171  // ops is of ConvolutionND, returns data for 1 term and all dimensions
1172  Q fac = ops[mu].getfac();
1173  muopxv_fast(at, muop.ops, *input, f0, r, r0, tol/std::abs(fac), fac,
1174  work1, work2, work5);
1175  }
1176  }
1177 
1178  r(s0).gaxpy(1.0,r0,1.0);
1179  double cpu1=cpu_time();
1180  timer_full.accumulate(cpu1-cpu0);
1181 
1182  return r;
1183  }
1184 
1185 
1187 
1198  template<typename T>
1200  const Key<NDIM>& shift, const GenTensor<T>& coeff, double tol, double tol2) const {
1201 
1202  typedef TENSOR_RESULT_TYPE(T,Q) resultT;
1203 
1204  // some checks
1205  MADNESS_ASSERT(coeff.tensor_type()==TT_2D); // for now
1206  MADNESS_ASSERT(not modified());
1207  MADNESS_ASSERT(not doleaves);
1208  MADNESS_ASSERT(coeff.dim(0)==2*k);
1209  MADNESS_ASSERT(2*NDIM==coeff.ndim());
1210 
1211  const SeparatedConvolutionData<Q,NDIM>* op = getop(source.level(), shift, source);
1212 
1213  // prepare access to the singular vectors
1214  std::vector<Slice> s(coeff.config().dim_per_vector()+1,_);
1215  // can't use predefined slices and vectors -- they have the wrong dimension
1216  const std::vector<Slice> s00(coeff.ndim(),Slice(0,k-1));
1217 
1218  // some workspace
1219  Tensor<resultT> work1(v2k,false), work2(v2k,false);
1220  Tensor<Q> work5(2*k,2*k);
1221 
1222  // sliced input and final result
1223  const GenTensor<T> f0 = copy(coeff(s00));
1224  GenTensor<resultT> final=copy(coeff);
1225  GenTensor<resultT> final0=copy(f0);
1226 
1227  tol = tol/rank*0.01; // Error is per separated term
1228  tol2= tol2/rank;
1229 
1230  for (int r=0; r<coeff.rank(); ++r) {
1231 
1232  // get the appropriate singular vector (left or right depends on particle)
1233  // and apply the full tensor muopxv_fast on it, term by term
1234  s[0]=Slice(r,r);
1235  const Tensor<T> chunk=coeff.config().ref_vector(particle()-1)(s).reshape(2*k,2*k,2*k);
1236  const Tensor<T> chunk0=f0.config().ref_vector(particle()-1)(s).reshape(k,k,k);
1237 // const double weight=coeff.config().weights(r);
1238 
1239  // accumulate all terms of the operator for a specific term of the function
1240  Tensor<resultT> result(v2k), result0(vk);
1241 
1242  ApplyTerms at;
1243  at.r_term=true;
1244  at.t_term=source.level()>0;
1245 
1246  // this loop will return on result and result0 the terms [(P+Q) G (P+Q)]_1,
1247  // and [P Q P]_1, respectively
1248  for (int mu=0; mu<rank; ++mu) {
1249  const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1250 
1251 // if (muop.norm > tol2*std::abs(weight)) {
1252 
1253  Q fac = ops[mu].getfac();
1254  muopxv_fast(at, muop.ops, chunk, chunk0, result, result0,
1255  tol/std::abs(fac), fac, work1, work2, work5);
1256 
1257 // }
1258  }
1259 
1260 
1261  // reinsert the transformed terms into result, leaving the other particle unchanged
1262  MADNESS_ASSERT(final.config().has_structure());
1263  final.config().ref_vector(particle()-1)(s)=result;
1264 
1265  if (source.level()>0) {
1266  final0.config().ref_vector(particle()-1)(s)=result0;
1267  } else {
1268  final0.config().ref_vector(0)(s)=0.0;
1269  final0.config().ref_vector(1)(s)=0.0;
1270  }
1271 
1272  }
1273 
1274  final(s00)+=final0;
1275  final.reduce_rank(tol2);
1276 
1277  return final;
1278  }
1279 
1280 
1282 
1286  template <typename T>
1288  const Key<NDIM>& shift,
1289  const GenTensor<T>& coeff,
1290  double tol, double tol2) const {
1292  typedef TENSOR_RESULT_TYPE(T,Q) resultT;
1293 
1294  MADNESS_ASSERT(coeff.ndim()==NDIM);
1295  MADNESS_ASSERT(coeff.tensor_type()==TT_2D); // we use the rank below
1296 // MADNESS_EXCEPTION("no apply2",1);
1297  const TensorType tt=coeff.tensor_type();
1298 
1299  const GenTensor<T>* input = &coeff;
1300  GenTensor<T> dummy;
1301 
1302  if (not modified()) {
1303  if (coeff.dim(0) == k) {
1304  // This processes leaf nodes with only scaling
1305  // coefficients ... FuncImpl::apply by default does not
1306  // apply the operator to these since for smoothing operators
1307  // it is not necessary. It is necessary for operators such
1308  // as differentiation and time evolution and will also occur
1309  // if the application of the operator widens the tree.
1310  dummy = GenTensor<T>(v2k,coeff.tensor_type());
1311  dummy(s0) += coeff;
1312  input = &dummy;
1313  }
1314  else {
1315  MADNESS_ASSERT(coeff.dim(0)==2*k);
1316  }
1317  }
1318 
1319  tol = tol/rank; // Error is per separated term
1320  tol2= tol2/rank;
1321 
1322  const SeparatedConvolutionData<Q,NDIM>* op = getop(source.level(), shift, source);
1323 
1324  GenTensor<resultT> r, r0, result, result0;
1325  GenTensor<resultT> work1(v2k,tt), work2(v2k,tt);
1326  GenTensor<Q> work5(v2k,tt);
1327 
1328  if (modified()) {
1329  r=GenTensor<resultT>(vk,tt);
1330  work1=GenTensor<resultT>(vk,tt);
1331  work2=GenTensor<resultT>(vk,tt);
1332  work5=GenTensor<Q>();
1333 
1334  }
1335 
1336  // collect the results of the individual operator terms
1337  std::list<GenTensor<T> > r_list;
1338  std::list<GenTensor<T> > r0_list;
1339 
1340 // const GenTensor<T> f0 = copy(coeff(s0));
1341  const GenTensor<T> f0 = copy((*input)(s0));
1342  for (int mu=0; mu<rank; ++mu) {
1343  const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1344  //print("muop",source, shift, mu, muop.norm);
1345 
1346  // delta(g) < delta(T) * || f ||
1347  if (muop.norm > tol) {
1348 
1349  // get maximum rank of coeff to contribute:
1350  // delta(g) < eps < || T || * delta(f)
1351  // delta(coeff) * || T || < tol2
1352  const int r_max=SRConf<T>::max_sigma(tol2/muop.norm,coeff.rank(),coeff.config().weights_);
1353  // print("r_max",coeff.config().weights(r_max));
1354 
1355  // note that max_sigma is inclusive!
1356  if (r_max>=0) {
1357  const GenTensor<resultT> chunk=input->get_configs(0,r_max);
1358  const GenTensor<resultT> chunk0=f0.get_configs(0,r_max);
1359 
1360  double cpu0=cpu_time();
1361 
1362  Q fac = ops[mu].getfac();
1363  muopxv_fast2(source.level(), muop.ops, chunk, chunk0, r, r0,
1364  tol/std::abs(fac), fac, work1, work2, work5);
1365  double cpu1=cpu_time();
1366  timer_low_transf.accumulate(cpu1-cpu0);
1367 
1368  r_list.push_back(r);
1369  r0_list.push_back(r0);
1370  }
1371  }
1372  }
1373 
1374  // finally accumulate all the resultant terms into one tensor
1375  double cpu0=cpu_time();
1376 
1377  result0=reduce(r0_list,tol2*rank);
1378  if (r_list.size()>0) r_list.front()(s0)+=result0;
1379  result=reduce(r_list,tol2*rank);
1380  result.reduce_rank(tol2*rank);
1381 
1382  double cpu1=cpu_time();
1383  timer_low_accumulate.accumulate(cpu1-cpu0);
1384  return result;
1385  }
1386 
1388 
1396  template<typename T>
1397  double estimate_costs(const Key<NDIM>& source,
1398  const Key<NDIM>& shift,
1399  const GenTensor<T>& coeff,
1400  double tol, double tol2) const {
1401 
1402  if (coeff.tensor_type()==TT_FULL) return 0.5;
1403  if (2*NDIM==coeff.ndim()) return 1.5;
1404  MADNESS_ASSERT(NDIM==coeff.ndim());
1405  MADNESS_ASSERT(coeff.tensor_type()==TT_2D);
1406 
1407  const SeparatedConvolutionData<Q,NDIM>* op = getop(source.level(), shift, source);
1408 
1409  tol = tol/rank; // Error is per separated term
1410  tol2= tol2/rank;
1411 
1412  const double full_operator_cost=pow(coeff.dim(0),NDIM+1);
1413  const double low_operator_cost=pow(coeff.dim(0),NDIM/2+1);
1414  const double low_reduction_cost=pow(coeff.dim(0),NDIM/2);
1415 
1416  double full_cost=0.0;
1417  double low_cost=0.0;
1418 
1419  for (int mu=0; mu<rank; ++mu) {
1420  const SeparatedConvolutionInternal<Q,NDIM>& muop = op->muops[mu];
1421 
1422  // delta(g) < delta(T) * || f ||
1423  if (muop.norm > tol) {
1424  // note that max_sigma is inclusive: it returns a slice w(Slice(0,i))
1425  long nterms=SRConf<T>::max_sigma(tol2/muop.norm,coeff.rank(),coeff.config().weights_)+1;
1426 
1427  // take only the first overlap computation of rank reduction into account
1428  low_cost+=nterms*low_operator_cost + 2.0*nterms*nterms*low_reduction_cost;
1429 
1430  full_cost+=full_operator_cost;
1431  }
1432  }
1433 
1434  // include random empirical factor of 2
1435  double ratio=-1.0;
1436  if (low_cost>0.0) ratio=full_cost/low_cost;
1437 // print("nterms, full, low, full/low", full_cost, low_cost,shift.distsq(), ratio);
1438  return ratio;
1439 
1440  }
1441 
1442  };
1443 
1444 
1445 
1447  static
1448  inline
1449  SeparatedConvolution<double_complex,3> PeriodicHFExchangeOperator(World& world,
1450  Vector<double,3> args,
1451  double lo,
1452  double eps,
1453  const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(),
1454  int k=FunctionDefaults<3>::get_k())
1455  {
1456  const Tensor<double>& cell_width = FunctionDefaults<3>::get_cell_width();
1457  double hi = cell_width.normf(); // Diagonal width of cell
1458  if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation
1459 
1460  GFit<double,3> fit=GFit<double,3>::CoulombFit(lo,hi,eps,false);
1461  Tensor<double> coeff=fit.coeffs();
1462  Tensor<double> expnt=fit.exponents();
1463 
1464  if (bc(0,0) == BC_PERIODIC) {
1465  fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), true);
1466  }
1467 
1468  return SeparatedConvolution<double_complex,3>(world, args, coeff, expnt, bc, k, false);
1469 // return SeparatedConvolution<double_complex,3>(world, coeff, expnt, bc, k);
1470 
1471  }
1472 
1474  static
1475  inline
1476  SeparatedConvolution<double,3> CoulombOperator(World& world,
1477  double lo,
1478  double eps,
1479  const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(),
1480  int k=FunctionDefaults<3>::get_k())
1481  {
1482  const Tensor<double>& cell_width = FunctionDefaults<3>::get_cell_width();
1483  double hi = cell_width.normf(); // Diagonal width of cell
1484  if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation
1485 
1486  GFit<double,3> fit=GFit<double,3>::CoulombFit(lo,hi,eps,false);
1487  Tensor<double> coeff=fit.coeffs();
1488  Tensor<double> expnt=fit.exponents();
1489 
1490 
1491  if (bc(0,0) == BC_PERIODIC) {
1492  fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), true);
1493  }
1494  return SeparatedConvolution<double,3>(world, coeff, expnt, bc, k);
1495  }
1496 
1497 
1499  static
1500  inline
1501  SeparatedConvolution<double,3>* CoulombOperatorPtr(World& world,
1502  double lo,
1503  double eps,
1504  const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(),
1505  int k=FunctionDefaults<3>::get_k())
1506  {
1507  const Tensor<double>& cell_width = FunctionDefaults<3>::get_cell_width();
1508  double hi = cell_width.normf(); // Diagonal width of cell
1509  if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation
1510  GFit<double,3> fit=GFit<double,3>::CoulombFit(lo,hi,eps,false);
1511  Tensor<double> coeff=fit.coeffs();
1512  Tensor<double> expnt=fit.exponents();
1513 
1514  if (bc(0,0) == BC_PERIODIC) {
1515  fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), true);
1516  }
1517  return new SeparatedConvolution<double,3>(world, coeff, expnt, bc, k);
1518  }
1519 
1520 
1522  template <std::size_t NDIM>
1523  static
1524  inline
1525  SeparatedConvolution<double,NDIM> BSHOperator(World& world,
1526  double mu,
1527  double lo,
1528  double eps,
1529  const BoundaryConditions<NDIM>& bc=FunctionDefaults<NDIM>::get_bc(),
1530  int k=FunctionDefaults<NDIM>::get_k())
1531  {
1532  if (eps>1.e-4) {
1533  if (world.rank()==0) print("the accuracy in BSHOperator is too small, tighten the threshold",eps);
1534  MADNESS_EXCEPTION("0",1);
1535  }
1536  const Tensor<double>& cell_width = FunctionDefaults<NDIM>::get_cell_width();
1537  double hi = cell_width.normf(); // Diagonal width of cell
1538  if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation
1539 
1540  GFit<double,NDIM> fit=GFit<double,NDIM>::BSHFit(mu,lo,hi,eps,false);
1541  Tensor<double> coeff=fit.coeffs();
1542  Tensor<double> expnt=fit.exponents();
1543 
1544  if (bc(0,0) == BC_PERIODIC) {
1545  fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false);
1546  }
1547 
1548  return SeparatedConvolution<double,NDIM>(world, coeff, expnt, bc, k);
1549  }
1550 
1551 
1553  static
1554  inline
1555  SeparatedConvolution<double,3> BSHOperator3D(World& world,
1556  double mu,
1557  double lo,
1558  double eps,
1559  const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(),
1560  int k=FunctionDefaults<3>::get_k())
1561 
1562  {
1563  const Tensor<double>& cell_width = FunctionDefaults<3>::get_cell_width();
1564  double hi = cell_width.normf(); // Diagonal width of cell
1565  if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation
1566 
1567  GFit<double,3> fit=GFit<double,3>::BSHFit(mu,lo,hi,eps,false);
1568  Tensor<double> coeff=fit.coeffs();
1569  Tensor<double> expnt=fit.exponents();
1570 
1571  if (bc(0,0) == BC_PERIODIC) {
1572  fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false);
1573  }
1574  return SeparatedConvolution<double,3>(world, coeff, expnt, bc, k);
1575  }
1576 
1578  static inline SeparatedConvolution<double,3> SlaterF12Operator(World& world,
1579  double mu, double lo, double eps,
1580  const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(),
1581  int k=FunctionDefaults<3>::get_k()) {
1582 
1583  const Tensor<double>& cell_width = FunctionDefaults<3>::get_cell_width();
1584  double hi = cell_width.normf(); // Diagonal width of cell
1585  if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation
1586 
1587  GFit<double,3> fit=GFit<double,3>::SlaterFit(mu,lo,hi,eps,false);
1588  Tensor<double> coeff=fit.coeffs();
1589  Tensor<double> expnt=fit.exponents();
1590 
1591  if (bc(0,0) == BC_PERIODIC) {
1592  fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false);
1593  }
1594  return SeparatedConvolution<double,3>(world, coeff, expnt, bc, k, false, mu);
1595  }
1596 
1597 
1599  static
1600  inline
1601  SeparatedConvolution<double,3>* BSHOperatorPtr3D(World& world,
1602  double mu,
1603  double lo,
1604  double eps,
1605  const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(),
1606  int k=FunctionDefaults<3>::get_k())
1607  {
1608  const Tensor<double>& cell_width = FunctionDefaults<3>::get_cell_width();
1609  double hi = cell_width.normf(); // Diagonal width of cell
1610  if (bc(0,0) == BC_PERIODIC) hi *= 100; // Extend range for periodic summation
1611 
1612  GFit<double,3> fit=GFit<double,3>::BSHFit(mu,lo,hi,eps,false);
1613  Tensor<double> coeff=fit.coeffs();
1614  Tensor<double> expnt=fit.exponents();
1615 
1616  if (bc(0,0) == BC_PERIODIC) {
1617  fit.truncate_periodic_expansion(coeff, expnt, cell_width.max(), false);
1618  }
1619  return new SeparatedConvolution<double,3>(world, coeff, expnt, bc, k);
1620  }
1621 
1622 
1624 
1627  static
1628  inline
1629  std::vector< std::shared_ptr< SeparatedConvolution<double,3> > >
1630  GradCoulombOperator(World& world,
1631  double lo,
1632  double eps,
1633  const BoundaryConditions<3>& bc=FunctionDefaults<3>::get_bc(),
1634  int k=FunctionDefaults<3>::get_k())
1635  {
1636  typedef SeparatedConvolution<double,3> real_convolution_3d;
1638  const double pi = constants::pi;
1639  const Tensor<double> width = FunctionDefaults<3>::get_cell_width();
1640  double hi = width.normf(); // Diagonal width of cell
1641  const bool isperiodicsum = (bc(0,0)==BC_PERIODIC);
1642  if (isperiodicsum) hi *= 100; // Extend range for periodic summation
1643 
1644  GFit<double,3> fit=GFit<double,3>::CoulombFit(lo,hi,eps,false);
1645  Tensor<double> coeff=fit.coeffs();
1646  Tensor<double> expnt=fit.exponents();
1647 
1648  if (bc(0,0) == BC_PERIODIC) {
1649  fit.truncate_periodic_expansion(coeff, expnt, width.max(), true);
1650  }
1651 
1652  int rank = coeff.dim(0);
1653 
1654  std::vector<real_convolution_3d_ptr> gradG(3);
1655 
1656  for (int dir=0; dir<3; dir++) {
1657  std::vector< ConvolutionND<double,3> > ops(rank);
1658  for (int mu=0; mu<rank; mu++) {
1659  // We cache the normalized operator so the factor is the value we must multiply
1660  // by to recover the coeff we want.
1661  double c = std::pow(sqrt(expnt(mu)/pi),3); // Normalization coeff
1662  ops[mu].setfac(coeff(mu)/c/width[dir]);
1663 
1664  for (int d=0; d<3; d++) {
1665  if (d != dir)
1666  ops[mu].setop(d,GaussianConvolution1DCache<double>::get(k, expnt(mu)*width[d]*width[d], 0, isperiodicsum));
1667  }
1668  ops[mu].setop(dir,GaussianConvolution1DCache<double>::get(k, expnt(mu)*width[dir]*width[dir], 1, isperiodicsum));
1669  }
1670  gradG[dir] = real_convolution_3d_ptr(new SeparatedConvolution<double,3>(world, ops));
1671  }
1672 
1673  return gradG;
1674  }
1675 
1676  namespace archive {
1677  template <class Archive, class T, std::size_t NDIM>
1678  struct ArchiveLoadImpl<Archive,const SeparatedConvolution<T,NDIM>*> {
1679  static inline void load(const Archive& ar, const SeparatedConvolution<T,NDIM>*& ptr) {
1681  ar & p;
1682  ptr = static_cast< const SeparatedConvolution<T,NDIM>* >(p);
1683  }
1684  };
1685 
1686  template <class Archive, class T, std::size_t NDIM>
1687  struct ArchiveStoreImpl<Archive,const SeparatedConvolution<T,NDIM>*> {
1688  static inline void store(const Archive& ar, const SeparatedConvolution<T,NDIM>*const& ptr) {
1689  ar & static_cast< const WorldObject< SeparatedConvolution<T,NDIM> >* >(ptr);
1690  }
1691  };
1692  }
1693 
1694 }
1695 
1696 
1697 
1698 
1699 #endif // MADNESS_MRA_OPERATOR_H__INCLUDED
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:1199
SRConf< T > config() const
Definition: gentensor.h:201
void process_pending()
To be called from derived constructor to process pending messages.
Definition: worldobj.h:330
Definition: shared_ptr_bits.h:38
SRConf< T > get_configs(const int &start, const int &end) const
Definition: gentensor.h:202
Tensor< double > h1
Definition: function_common_data.h:105
const double pi
Mathematical constant pi.
Definition: constants.h:44
const double R
Definition: dielectric.cc:191
1D convolution with (derivative) Gaussian; coeff and expnt given in simulation coordinates [0...
Definition: convolution1d.h:671
SeparatedConvolution(World &world, Vector< double, NDIM > args, const Tensor< Q > &coeff, const Tensor< double > &expnt, const BoundaryConditions< NDIM > &bc=FunctionDefaults< NDIM >::get_bc(), int k=FunctionDefaults< NDIM >::get_k(), bool doleaves=false)
WSTHORNTON Constructor for Gaussian Convolutions (mostly for backward compatability) ...
Definition: operator.h:980
FunctionDefaults holds default paramaters as static class members.
Definition: funcdefaults.h:175
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:1046
TensorType
low rank representations of tensors (see gentensor.h)
Definition: tensor.h:275
static const size_t opdim
Definition: operator.h:128
static GFit SlaterFit(double gamma, double lo, double hi, double eps, bool prnt=false)
return a fit for the Slater function
Definition: gfit.h:86
long ndim() const
Returns the number of dimensions in the tensor.
Definition: basetensor.h:144
const int NDIM
Definition: tdse1.cc:44
Timer timer_low_accumulate
Definition: operator.h:131
bool isperiodicsum
Definition: operator.h:121
bool destructive_
destroy the argument or restore it (expensive for 6d functions)
Definition: operator.h:125
const mpreal dim(const mpreal &a, const mpreal &b, mp_rnd_t rnd_mode)
Definition: mpreal.h:2201
double norm
Definition: operator.h:71
const double L
Definition: 3dharmonic.cc:123
void print_timer() const
Definition: operator.h:1023
Defines common mathematical and physical constants.
Convolutions in separated form (including Gaussian)
Definition: operator.h:117
const BoundaryConditions< NDIM > & get_bc() const
Definition: operator.h:1039
Definition: mpreal.h:3066
Provides the common functionality/interface of all 1D convolutions.
Definition: convolution1d.h:247
void mTxmq_padding(long dimi, long dimj, long dimk, long ext_b, cT *c, const aT *a, const bT *b)
Definition: mtxmq.h:74
std::shared_ptr< real_convolution_3d > real_convolution_3d_ptr
Definition: functypedefs.h:135
Provides routines for internal use optimized for aligned data.
NDIM & f
Definition: mra.h:2179
long dim(int i) const
Returns the size of dmension i.
Definition: basetensor.h:147
enable_if_c< 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:1078
Definition: funcdefaults.h:56
bool modified_
use modified NS form
Definition: operator.h:123
TENSOR_RESULT_TYPE(T, R) inner(const Function<T
Computes the scalar/inner product between two functions.
Default store of a thingy via serialize(ar,t)
Definition: archive.h:708
void print(std::string line="") const
print timer
Definition: function_common_data.h:174
Timer timer_low_transf
Definition: operator.h:130
int particle_
Definition: operator.h:124
void break_apart(Key< LDIM > &key1, Key< KDIM > &key2) const
break key into two low-dimensional keys
Definition: key.h:330
#define PROFILE_MEMBER_FUNC(classname)
Definition: worldprofile.h:199
!!! Note that if Rnormf is zero then ***ALL*** of the tensors are empty
Definition: convolution1d.h:150
FLOAT fit(const FLOAT &x, const vector< FLOAT > &p)
Definition: y.cc:326
void reset_timer() const
Definition: operator.h:1031
bool is_slaterf12
Definition: operator.h:134
const int & particle() const
Definition: operator.h:159
static int max_sigma(const double &thresh, const int &rank, const Tensor< double > &w)
Definition: srconf.h:125
GenTensor< T > reduce(std::list< GenTensor< T > > &addends, double eps, bool are_optimal=false)
Definition: gentensor.h:217
const T1 &f1 return GTEST_2_TUPLE_() T(f0, f1)
#define max(a, b)
Definition: lda.h:53
Vector< T, 1 > vec(T x)
Your friendly neighborhood factory function.
Definition: array.h:456
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:70
Simplified interface around hash_map to cache stuff for 1D.
Definition: simplecache.h:45
const Q * getptr(const Key< NDIM > &key) const
If key is present return pointer to cached value, otherwise return NULL.
Definition: simplecache.h:65
SeparatedConvolutionData keeps data for all terms, all dimensions.
Definition: operator.h:69
Definition: function_common_data.h:127
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:1835
Holds displacements for applying operators to avoid replicating for all operators.
Definition: displacements.h:39
void fast_transpose(long n, long m, const T *a, T *restrict b)
a(n,m) –> b(m,n) ... optimized for smallish matrices
Definition: convolution1d.h:71
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:1101
const mpreal min(const mpreal &x, const mpreal &y)
Definition: mpreal.h:2675
Prototypes for a partial interface from Tensor to LAPACK.
FLOAT a(int j, FLOAT z)
Definition: y1.cc:86
void accumulate(const double time) const
accumulate timer
Definition: function_common_data.h:141
SeparatedConvolution(World &world, std::vector< ConvolutionND< Q, NDIM > > &argops, const BoundaryConditions< NDIM > &bc=FunctionDefaults< NDIM >::get_bc(), long k=FunctionDefaults< NDIM >::get_k(), bool doleaves=false)
Definition: operator.h:905
bool doleaves
If should be applied to leaf coefficients ... false by default.
Definition: operator.h:120
Key< NDIM > keyT
Definition: operator.h:127
This class is used to specify boundary conditions for all operatorsExterior boundary conditions (i...
Definition: funcdefaults.h:72
Level level() const
Definition: key.h:220
void reduce_rank(const double &eps)
Definition: gentensor.h:193
Default load of a thingy via serialize(ar,t)
Definition: archive.h:718
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:1115
SeparatedConvolution(World &world, const Tensor< Q > &coeff, const Tensor< double > &expnt, const BoundaryConditions< NDIM > &bc=FunctionDefaults< NDIM >::get_bc(), int k=FunctionDefaults< NDIM >::get_k(), bool doleaves=false, double mu=0.0)
Constructor for Gaussian Convolutions (mostly for backward compatability)
Definition: operator.h:935
Array of 1D convolutions (one / dimension)
Definition: convolution1d.h:531
Namespace for mathematical applications.
Definition: muParser.cpp:47
SeparatedConvolution< double, 3 > real_convolution_3d
Definition: functypedefs.h:121
Definition: tensor.h:275
Implements most parts of a globally addressable object (via unique ID)
Definition: worldam.h:74
enable_if_c from Boost for conditionally instantiating templates based on type
Definition: enable_if.h:46
static void store(const Archive &ar, const SeparatedConvolution< T, NDIM > *const &ptr)
Definition: operator.h:1688
tensorT sqrt(const tensorT &s, double tol=1e-8)
Computes matrix square root (not used any more?)
Definition: DFcode/moldft.cc:446
static void load(const Archive &ar, const SeparatedConvolution< T, NDIM > *&ptr)
Definition: operator.h:1679
A parallel world with full functionality wrapping an MPI communicator.
Definition: worldfwd.h:416
TensorType tensor_type() const
Definition: gentensor.h:197
void mTxmq(long dimi, long dimj, long dimk, cT *restrict c, const aT *a, const bT *b)
Definition: mtxmq.h:50
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:1397
bool & modified()
Definition: operator.h:155
A multiresolution adaptive numerical function.
Definition: derivative.h:61
int Level
Definition: key.h:58
const std::vector< Key< NDIM > > & get_disp(Level n) const
Definition: operator.h:1041
const mpreal sum(const mpreal tab[], unsigned long int n, mp_rnd_t rnd_mode)
Definition: mpreal.cc:241
SeparatedConvolutionData(int rank)
Definition: operator.h:73
ProcessID rank() const
Returns the process rank in this world (same as MPI_Comm_rank()))
Definition: worldfwd.h:526
fit isotropic functions to a set of Gaussians with controlled precision
Q opT
The apply function uses this to infer resultT=opT*inputT.
Definition: operator.h:119
static GFit CoulombFit(double lo, double hi, double eps, bool prnt=false)
return a fit for the Coulomb function
Definition: gfit.h:55
GenTensor< TENSOR_RESULT_TYPE(T, Q)> general_transform(const GenTensor< T > &t, const Tensor< Q > c[])
Transform all dimensions of the tensor t by distinct matrices c.
Definition: gentensor.h:1342
bool & destructive()
Definition: operator.h:161
Definition: convolution1d.h:837
void set(const Key< NDIM > &key, const Q &val)
Set value associated with key ... gives ownership of a new copy to the container. ...
Definition: simplecache.h:91
int & particle()
Definition: operator.h:158
T * shrink(long n, long m, long r, const T *a, T *restrict b)
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).
Definition: convolution1d.h:117
const double & gamma() const
Definition: operator.h:164
static const Tensor< double > & get_cell_width()
Returns the width of each user cell dimension.
Definition: funcdefaults.h:391
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:1287
const bool & modified() const
Definition: operator.h:156
Function< TENSOR_RESULT_TYPE(T, Q), FDIM > operator()(const Function< T, FDIM > &f) const
apply this operator on a function f
Definition: operator.h:1090
disable_if from Boost for conditionally instantiating templates based on type
Definition: enable_if.h:68
void reset() const
Definition: function_common_data.h:168
Tensor< double > op(const Tensor< double > &x)
Definition: kain.cc:508
const T1 & f1
Definition: gtest-tuple.h:680
void doit(World &world)
Definition: tdse1.cc:753
void print(const A &a)
Print a single item to std::cout terminating with new line.
Definition: print.h:122
#define MADNESS_EXCEPTION(msg, value)
Definition: worldexc.h:88
A slice defines a sub-range or patch of a dimension.
Definition: slice.h:103
const T1 const T2 & f2
Definition: gtest-tuple.h:680
Definition: gentensor.h:123
SeparatedConvolution(World &world, std::vector< std::shared_ptr< Convolution1D< Q > > > &argops, const BoundaryConditions< NDIM > &bc=FunctionDefaults< NDIM >::get_bc(), long k=FunctionDefaults< NDIM >::get_k(), bool doleaves=false)
Definition: operator.h:870
Timer timer_full
Definition: operator.h:129
double mu_
Definition: operator.h:135
Definition: operator.h:60
const double & mu() const
Definition: operator.h:165
Definition: tensor.h:275
#define restrict
Definition: config.h:403
int64_t Translation
Definition: key.h:57
const mpreal fabs(const mpreal &v, mp_rnd_t rnd_mode)
Definition: mpreal.h:2187
disable_if_c< 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:1061
Holds machinery to set up Functions/FuncImpls using various Factories and Interfaces.
Definition: chem/atomutil.cc:45
Function< T, NDIM > apply(const Derivative< T, NDIM > &D, const Function< T, NDIM > &f, bool fence=true)
Applies derivative operator to function (for syntactic equivalence to integral operator apply) ...
Definition: derivative.h:613
const double c
Definition: gfit.cc:200
FLOAT b(int j, FLOAT z)
Definition: y1.cc:79
void swap(mpfr::mpreal &x, mpfr::mpreal &y)
Definition: mpreal.h:3069
SeparatedConvolutionData(const SeparatedConvolutionData< Q, NDIM > &q)
Definition: operator.h:74
double norm
Definition: operator.h:61
Key is the index for a node of the 2^NDIM-tree.
Definition: key.h:69
const ConvolutionData1D< Q > * ops[NDIM]
Definition: operator.h:62
Compuates most matrix elements over 1D operators (including Gaussians)
World & world
Think globally act locally.
Definition: worldobj.h:171
virtual ~SeparatedConvolution()
Definition: operator.h:1021
long rank() const
Definition: gentensor.h:189
const bool & destructive() const
Definition: operator.h:162
Tensor< double > h0
Definition: function_common_data.h:105
std::vector< SeparatedConvolutionInternal< Q, NDIM > > muops
Definition: operator.h:70