MADNESS  version 0.9
funcimpl.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  $Id$
33 */
34 
35 #ifndef MADNESS_MRA_FUNCIMPL_H__INCLUDED
36 #define MADNESS_MRA_FUNCIMPL_H__INCLUDED
37 
40 
41 #include <iostream>
42 #include <madness/world/world.h>
43 #include <madness/world/print.h>
46 #include <madness/misc/misc.h>
47 #include <madness/tensor/tensor.h>
49 
51 #include <madness/mra/indexit.h>
52 #include <madness/mra/key.h>
55 
56 namespace madness {
57  template <typename T, std::size_t NDIM>
58  class DerivativeBase;
59 
60  template<typename T, std::size_t NDIM>
61  class FunctionImpl;
62 
63  template<typename T, std::size_t NDIM>
64  class FunctionNode;
65 
66  template<typename T, std::size_t NDIM>
67  class Function;
68 
69  template<typename T, std::size_t NDIM>
71 
72  template<typename T, std::size_t NDIM, std::size_t MDIM>
74 
75  template<int D>
76  class LoadBalImpl;
77 
78 }
79 
80 namespace madness {
81 
82 
84  template<typename keyT>
85  class SimplePmap : public WorldDCPmapInterface<keyT> {
86  private:
87  const int nproc;
88  const ProcessID me;
89 
90  public:
91  SimplePmap(World& world) : nproc(world.nproc()), me(world.rank())
92  { }
93 
94  ProcessID owner(const keyT& key) const {
95  if (key.level() == 0)
96  return 0;
97  else
98  return key.hash() % nproc;
99  }
100  };
101 
103  template <typename keyT>
104  class LevelPmap : public WorldDCPmapInterface<keyT> {
105  private:
106  const int nproc;
107  public:
108  LevelPmap() : nproc(0) {};
109 
110  LevelPmap(World& world) : nproc(world.nproc()) {}
111 
113  ProcessID owner(const keyT& key) const {
114  Level n = key.level();
115  if (n == 0) return 0;
116  hashT hash;
117  if (n <= 3 || (n&0x1)) hash = key.hash();
118  else hash = key.parent().hash();
119  return hash%nproc;
120  }
121  };
122 
123 
125  template<typename T, std::size_t NDIM>
126  class FunctionNode {
127  public:
129  typedef Tensor<T> tensorT;
130  private:
131  // Should compile OK with these volatile but there should
132  // be no need to set as volatile since the container internally
133  // stores the entire entry as volatile
134 
135  coeffT _coeffs;
136  double _norm_tree;
137  bool _has_children;
138  coeffT buffer;
139 
140  public:
142  FunctionNode() :
144  _coeffs(), _norm_tree(1e300), _has_children(false) {
145  }
146 
148 
152  explicit
153  FunctionNode(const coeffT& coeff, bool has_children = false) :
154  _coeffs(coeff), _norm_tree(1e300), _has_children(has_children) {
155  }
156 
157  explicit
158  FunctionNode(const coeffT& coeff, double norm_tree, bool has_children) :
159  _coeffs(coeff), _norm_tree(norm_tree), _has_children(has_children) {
160  }
161 
163  *this = other;
164  }
165 
168  if (this != &other) {
169  coeff() = copy(other.coeff());
170  _norm_tree = other._norm_tree;
171  _has_children = other._has_children;
172  }
173  return *this;
174  }
175 
177 
180  template<typename Q>
182  convert() const {
183  return FunctionNode<Q, NDIM> (copy(coeff()), _has_children);
184  }
185 
187  bool
188  has_coeff() const {
189  return _coeffs.has_data();
190  }
191 
192  bool exists() const {return this->has_data();}
193 
195  bool
196  has_children() const {
197  return _has_children;
198  }
199 
201  bool
202  is_leaf() const {
203  return !_has_children;
204  }
205 
207  bool
208  is_invalid() const {
209  return !(has_coeff() || has_children());
210  }
211 
213 
215  coeffT&
216  coeff() {
217  MADNESS_ASSERT(_coeffs.ndim() == -1 || (_coeffs.dim(0) <= 2
218  * MAXK && _coeffs.dim(0) >= 0));
219  return const_cast<coeffT&>(_coeffs);
220  }
221 
223 
225  const coeffT&
226  coeff() const {
227  return const_cast<const coeffT&>(_coeffs);
228  }
229 
231  size_t size() const {
232  return _coeffs.size();
233  }
234 
235  public:
236 
238  void reduceRank(const double& eps) {
239  _coeffs.reduce_rank(eps);
240  }
241 
243  Void
244  set_has_children(bool flag) {
245  _has_children = flag;
246  return None;
247  }
248 
250  Void
252  //madness::print(" set_chi_recu: ", key, *this);
254  if (!(has_children() || has_coeff() || key.level()==0)) {
255  // If node already knows it has children or it has
256  // coefficients then it must already be connected to
257  // its parent. If not, the node was probably just
258  // created for this operation and must be connected to
259  // its parent.
260  Key<NDIM> parent = key.parent();
261  const_cast<dcT&>(c).task(parent, &FunctionNode<T,NDIM>::set_has_children_recursive, c, parent, TaskAttributes::hipri());
262  //madness::print(" set_chi_recu: forwarding",key,parent);
263  }
264  _has_children = true;
265  return None;
266  }
267 
269  void set_is_leaf(bool flag) {
270  _has_children = !flag;
271  }
272 
274  void set_coeff(const coeffT& coeffs) {
275  coeff() = coeffs;
276  if ((_coeffs.has_data()) and ((_coeffs.dim(0) < 0) || (_coeffs.dim(0)>2*MAXK))) {
277  print("set_coeff: may have a problem");
278  print("set_coeff: coeff.dim[0] =", coeffs.dim(0), ", 2* MAXK =", 2*MAXK);
279  }
280  MADNESS_ASSERT(coeffs.dim(0)<=2*MAXK && coeffs.dim(0)>=0);
281  }
282 
284  void clear_coeff() {
285  coeff()=coeffT();
286  }
287 
289  template <typename Q>
290  void scale(Q a) {
291  _coeffs.scale(a);
292  }
293 
296  _norm_tree = norm_tree;
297  return None;
298  }
299 
301  double get_norm_tree() const {
302  return _norm_tree;
303  }
304 
305 
307 
310  template <typename Q, typename R>
311  Void gaxpy_inplace(const T& alpha, const FunctionNode<Q,NDIM>& other, const R& beta) {
312  PROFILE_MEMBER_FUNC(FuncNode);
313  if (other.has_children())
314  _has_children = true;
315  if (has_coeff()) {
316  if (other.has_coeff()) {
317  coeff().gaxpy(alpha,other.coeff(),beta);
318  }
319  else {
320  coeff().scale(alpha);
321  }
322  }
323  else if (other.has_coeff()) {
324  coeff() = other.coeff()*beta; //? Is this the correct type conversion?
325  }
326  return None;
327  }
328 
330  double accumulate2(const tensorT& t, const typename FunctionNode<T,NDIM>::dcT& c,
331  const Key<NDIM>& key) {
332  double cpu0=cpu_time();
333  if (has_coeff()) {
334  MADNESS_ASSERT(coeff().tensor_type()==TT_FULL);
335  // if (coeff().type==TT_FULL) {
336  coeff() += coeffT(t,-1.0,TT_FULL);
337  // } else {
338  // tensorT cc=coeff().full_tensor_copy();;
339  // cc += t;
340  // coeff()=coeffT(cc,args);
341  // }
342  }
343  else {
344  // No coeff and no children means the node is newly
345  // created for this operation and therefore we must
346  // tell its parent that it exists.
347  coeff() = coeffT(t,-1.0,TT_FULL);
348  // coeff() = copy(t);
349  // coeff() = coeffT(t,args);
350  if ((!_has_children) && key.level()> 0) {
351  Key<NDIM> parent = key.parent();
352  const_cast<dcT&>(c).task(parent, &FunctionNode<T,NDIM>::set_has_children_recursive, c, parent);
353  }
354  }
355  double cpu1=cpu_time();
356  return cpu1-cpu0;
357  }
358 
359 
361  double accumulate(const coeffT& t, const typename FunctionNode<T,NDIM>::dcT& c,
362  const Key<NDIM>& key, const TensorArgs& args) {
363  double cpu0=cpu_time();
364  if (has_coeff()) {
365 
366 #if 1
367  coeff().add_SVD(t,args.thresh);
368  if (buffer.rank()<coeff().rank()) {
369  if (buffer.has_data()) {
370  buffer.add_SVD(coeff(),args.thresh);
371  } else {
372  buffer=copy(coeff());
373  }
374  coeff()=coeffT();
375  }
376 
377 #else
378  // always do low rank
379  coeff().add_SVD(t,args.thresh);
380 
381 #endif
382 
383  } else {
384  // No coeff and no children means the node is newly
385  // created for this operation and therefore we must
386  // tell its parent that it exists.
387  coeff() = copy(t);
388  if ((!_has_children) && key.level()> 0) {
389  Key<NDIM> parent = key.parent();
390  const_cast<dcT&>(c).task(parent, &FunctionNode<T,NDIM>::set_has_children_recursive, c, parent);
391  }
392  }
393  double cpu1=cpu_time();
394  return cpu1-cpu0;
395  }
396 
398  if ((coeff().has_data()) and (buffer.has_data())) {
399  coeff().add_SVD(buffer,args.thresh);
400  } else if (buffer.has_data()) {
401  coeff()=buffer;
402  }
403  buffer=coeffT();
404  return None;
405  }
406 
407  T trace_conj(const FunctionNode<T,NDIM>& rhs) const {
408  return this->_coeffs.trace_conj((rhs._coeffs));
409  }
410 
411  template <typename Archive>
412  void serialize(Archive& ar) {
413  ar & coeff() & _has_children & _norm_tree;
414  }
415 
416  };
417 
418  template <typename T, std::size_t NDIM>
419  std::ostream& operator<<(std::ostream& s, const FunctionNode<T,NDIM>& node) {
420  s << "(has_coeff=" << node.has_coeff() << ", has_children=" << node.has_children() << ", norm=";
421  double norm = node.has_coeff() ? node.coeff().normf() : 0.0;
422  if (norm < 1e-12)
423  norm = 0.0;
424  double nt = node.get_norm_tree();
425  if (nt == 1e300) nt = 0.0;
426  s << norm << ", norm_tree=" << nt << "), rank="<< node.coeff().rank()<<")";
427  return s;
428  }
429 
430 
431 
433  template<typename T, std::size_t NDIM>
434  struct leaf_op {
436  const implT* f;
437  bool do_error_leaf_op() const {return false;}
438 
439  leaf_op() {}
440  leaf_op(const implT* f) : f(f) {}
441 
443  bool operator()(const Key<NDIM>& key, const GenTensor<T>& coeff=GenTensor<T>()) const {
444  MADNESS_ASSERT(f->get_coeffs().is_local(key));
445  return (not f->get_coeffs().find(key).get()->second.has_children());
446  }
447 
448  template <typename Archive> void serialize (Archive& ar) {
449  ar & f;
450  }
451  };
452 
453 
455  template<typename T, std::size_t NDIM>
456  struct error_leaf_op {
459  const implT* f;
460 
461  bool do_error_leaf_op() const {return true;} // no double call
463  error_leaf_op(const implT* f) : f(f) {}
464 
466  bool operator()(const Key<NDIM>& key) const {return true;}
467 
469  bool operator()(const Key<NDIM>& key, const GenTensor<T>& coeff) const {return false;}
470 
472 
477  bool operator()(const Key<NDIM>& key, const coeffT& coeff, const coeffT& parent) const {
478  if (parent.has_no_data()) return false;
479  if (key.level()<2) return false;
480  coeffT upsampled=f->upsample(key,parent);
481  upsampled.scale(-1.0);
482  upsampled+=coeff;
483  const double dnorm=upsampled.normf();
484  const bool is_leaf=(dnorm<f->truncate_tol(f->get_thresh(),key.level()));
485  return is_leaf;
486  }
487 
488  template <typename Archive> void serialize (Archive& ar) {ar & f;}
489  };
490 
492  template<typename T, size_t NDIM>
494 
497  long k;
498  bool do_error_leaf_op() const {return false;}
499 
501  hartree_leaf_op(const implT* f, const long& k) : f(f), k(k) {}
502 
504  bool operator()(const Key<NDIM>& key) const {return false;}
505 
507  bool operator()(const Key<NDIM>& key, const GenTensor<T>& coeff) const {
508  MADNESS_EXCEPTION("no post-determination in hartree_leaf_op",1);
509  return true;
510  }
511 
513 
517  bool operator()(const Key<NDIM>& key, const Tensor<T>& fcoeff, const Tensor<T>& gcoeff) const {
518 
519  if (key.level()<2) return false;
520  Slice s = Slice(0,k-1);
521  std::vector<Slice> s0(NDIM/2,s);
522 
523  const double tol=f->get_thresh();
524  const double thresh=f->truncate_tol(tol, key);
525  // include the wavelets in the norm, makes it much more accurate
526  const double fnorm=fcoeff.normf();
527  const double gnorm=gcoeff.normf();
528 
529  // if the final norm is small, perform the hartree product and return
530  const double norm=fnorm*gnorm; // computing the outer product
531  if (norm < thresh) return true;
532 
533  // norm of the scaling function coefficients
534  const double sfnorm=fcoeff(s0).normf();
535  const double sgnorm=gcoeff(s0).normf();
536 
537  // get the error of both functions and of the pair function;
538  // need the abs for numerics: sfnorm might be equal fnorm.
539  const double ferror=sqrt(std::abs(fnorm*fnorm-sfnorm*sfnorm));
540  const double gerror=sqrt(std::abs(gnorm*gnorm-sgnorm*sgnorm));
541 
542  // if the expected error is small, perform the hartree product and return
543  const double error=fnorm*gerror + ferror*gnorm + ferror*gerror;
544  // const double error=sqrt(fnorm*fnorm*gnorm*gnorm - sfnorm*sfnorm*sgnorm*sgnorm);
545 
546  if (error < thresh) return true;
547  return false;
548  }
549  template <typename Archive> void serialize (Archive& ar) {
550  ar & f & k;
551  }
552  };
553 
556  template<typename T, size_t NDIM, typename opT>
557  struct op_leaf_op {
559 
560  const opT* op;
561  const implT* f;
562  bool do_error_leaf_op() const {return true;}
563 
565  op_leaf_op(const opT* op, const implT* f) : op(op), f(f) {}
566 
568  bool operator()(const Key<NDIM>& key) const {return true;}
569 
571  bool operator()(const Key<NDIM>& key, const GenTensor<T>& coeff) const {
572  if (key.level()<2) return false;
573  const double cnorm=coeff.normf();
574  return this->operator()(key,cnorm);
575  }
576 
578  bool operator()(const Key<NDIM>& key, const double& cnorm) const {
579  if (key.level()<2) return false;
580 
581  typedef Key<opT::opdim> opkeyT;
582  const opkeyT source=op->get_source_key(key);
583 
584  const double thresh=f->truncate_tol(f->get_thresh(),key);
585  const std::vector<opkeyT>& disp = op->get_disp(key.level());
586  const opkeyT& d = *disp.begin(); // use the zero-displacement for screening
587  const double opnorm = op->norm(key.level(), d, source);
588  const double norm=opnorm*cnorm;
589  return norm<thresh;
590 
591  }
592 
593  template <typename Archive> void serialize (Archive& ar) {
594  ar & op & f;
595  }
596 
597  };
598 
599 
602  template<typename T, size_t NDIM, size_t LDIM, typename opT>
604 
607 
609  const implL* g; // for use of its cdata only
610  const opT* op;
611  bool do_error_leaf_op() const {return false;}
612 
614  hartree_convolute_leaf_op(const implT* f, const implL* g, const opT* op)
615  : f(f), g(g), op(op) {}
616 
618  bool operator()(const Key<NDIM>& key) const {return true;}
619 
621  bool operator()(const Key<NDIM>& key, const GenTensor<T>& coeff) const {
622  MADNESS_EXCEPTION("no post-determination in hartree_convolute_leaf_op",1);
623  return true;
624  }
625 
627 
631  bool operator()(const Key<NDIM>& key, const Tensor<T>& fcoeff, const Tensor<T>& gcoeff) const {
632  // bool operator()(const Key<NDIM>& key, const GenTensor<T>& coeff) const {
633 
634  if (key.level()<2) return false;
635 
636  const double tol=f->get_thresh();
637  const double thresh=f->truncate_tol(tol, key);
638  // include the wavelets in the norm, makes it much more accurate
639  const double fnorm=fcoeff.normf();
640  const double gnorm=gcoeff.normf();
641 
642  // norm of the scaling function coefficients
643  const double sfnorm=fcoeff(g->get_cdata().s0).normf();
644  const double sgnorm=gcoeff(g->get_cdata().s0).normf();
645 
646  // if the final norm is small, perform the hartree product and return
647  const double norm=fnorm*gnorm; // computing the outer product
648  if (norm < thresh) return true;
649 
650  // get the error of both functions and of the pair function
651  const double ferror=sqrt(fnorm*fnorm-sfnorm*sfnorm);
652  const double gerror=sqrt(gnorm*gnorm-sgnorm*sgnorm);
653 
654  // if the expected error is small, perform the hartree product and return
655  const double error=fnorm*gerror + ferror*gnorm + ferror*gerror;
656  if (error < thresh) return true;
657 
658  // now check if the norm of this and the norm of the operator are significant
659  const std::vector<Key<NDIM> >& disp = op->get_disp(key.level());
660  const Key<NDIM>& d = *disp.begin(); // use the zero-displacement for screening
661  const double opnorm = op->norm(key.level(), d, key);
662  const double final_norm=opnorm*sfnorm*sgnorm;
663  if (final_norm < thresh) return true;
664 
665  return false;
666  }
667  template <typename Archive> void serialize (Archive& ar) {
668  ar & f & op;
669  }
670  };
671 
672  template<typename T, size_t NDIM>
673  struct noop {
674  void operator()(const Key<NDIM>& key, const GenTensor<T>& coeff, const bool& is_leaf) const {}
675  bool operator()(const Key<NDIM>& key, const GenTensor<T>& fcoeff, const GenTensor<T>& gcoeff) const {
676  MADNESS_EXCEPTION("in noop::operator()",1);
677  return true;
678  }
679  template <typename Archive> void serialize (Archive& ar) {}
680 
681  };
682 
683  template<typename T, std::size_t NDIM>
684  struct insert_op {
686  typedef Key<NDIM> keyT;
689 
690  implT* impl;
691  insert_op() : impl() {}
692  insert_op(implT* f) : impl(f) {}
693  insert_op(const insert_op& other) : impl(other.impl) {}
694  void operator()(const keyT& key, const coeffT& coeff, const bool& is_leaf) const {
695  impl->get_coeffs().replace(key,nodeT(coeff,not is_leaf));
696  }
697  template <typename Archive> void serialize (Archive& ar) {
698  ar & impl;
699  }
700 
701  };
702 
703  template<size_t NDIM>
704  struct true_op {
705 
706  template<typename T>
707  bool operator()(const Key<NDIM>& key, const T& t) const {return true;}
708 
709  template<typename T, typename R>
710  bool operator()(const Key<NDIM>& key, const T& t, const R& r) const {return true;}
711  template <typename Archive> void serialize (Archive& ar) {}
712 
713  };
714 
716  template<typename T, std::size_t NDIM>
717  struct ShallowNode {
719  coeffT _coeffs;
721  ShallowNode() : _coeffs(), _has_children(false) {}
723  : _coeffs(node.coeff()), _has_children(node.has_children()) {}
725  : _coeffs(node.coeff()), _has_children(node._has_children) {}
726 
727  const coeffT& coeff() const {return _coeffs;}
728  coeffT& coeff() {return _coeffs;}
729  bool has_children() const {return _has_children;}
730  bool is_leaf() const {return not _has_children;}
731  template <typename Archive>
732  void serialize(Archive& ar) {
733  ar & coeff() & _has_children;
734  }
735  };
736 
737 
739 
755  template<typename T, size_t NDIM>
756  class CoeffTracker {
757 
758  typedef FunctionImpl<T,NDIM> implT;
759  typedef Key<NDIM> keyT;
760  typedef GenTensor<T> coeffT;
761  typedef std::pair<Key<NDIM>,ShallowNode<T,NDIM> > datumT;
762  enum LeafStatus {no, yes, unknown};
763 
765  const implT* impl;
767  keyT key_;
769  LeafStatus is_leaf_;
771  coeffT coeff_;
772  public:
773 
775  CoeffTracker() : impl(), key_(), is_leaf_(unknown), coeff_() {}
776 
778  CoeffTracker(const implT* impl) : impl(impl), is_leaf_(no) {
779  if (impl) key_=impl->get_cdata().key0;
780  }
781 
783  explicit CoeffTracker(const CoeffTracker& other, const datumT& datum) : impl(other.impl), key_(other.key_),
784  coeff_(datum.second.coeff()) {
785  if (datum.second.is_leaf()) is_leaf_=yes;
786  else is_leaf_=no;
787  }
788 
790  CoeffTracker(const CoeffTracker& other) : impl(other.impl), key_(other.key_),
791  is_leaf_(other.is_leaf_), coeff_(other.coeff_) {}
792 
794  const implT* get_impl() const {return impl;}
795 
797  const coeffT& coeff() const {return coeff_;}
798 
800  const keyT& key() const {return key_;}
801 
803 
808  coeffT coeff(const keyT& key) const {
809  MADNESS_ASSERT(impl);
810  if (impl->is_compressed() or impl->is_nonstandard())
811  return impl->parent_to_child_NS(key,key_,coeff_);
812  return impl->parent_to_child(coeff_,key_,key);
813  }
814 
816  const LeafStatus& is_leaf() const {return is_leaf_;}
817 
819  CoeffTracker make_child(const keyT& child) const {
820 
821  // fast return
822  if ((not impl) or impl->is_on_demand()) return CoeffTracker(*this);
823 
824  // can't make a child without knowing if this is a leaf -- activate first
825  MADNESS_ASSERT((is_leaf_==yes) or (is_leaf_==no));
826 
827  CoeffTracker result;
828  if (impl) {
829  result.impl=impl;
830  if (is_leaf_==yes) result.key_=key_;
831  if (is_leaf_==no) {
832  result.key_=child;
833  // check if child is direct descendent of this, but root node is special case
834  if (child.level()>0) MADNESS_ASSERT(result.key().level()==key().level()+1);
835  }
836  result.is_leaf_=unknown;
837  }
838  return result;
839  }
840 
842 
846 
847  // fast return
848  if (not impl) return Future<CoeffTracker>(CoeffTracker());
849  if (impl->is_on_demand()) return Future<CoeffTracker>(CoeffTracker(impl));
850 
851  // this will return a <keyT,nodeT> from a remote node
852  ProcessID p=impl->get_coeffs().owner(key());
853  Future<datumT> datum1=impl->task(p, &implT::find_datum,key_,TaskAttributes::hipri());
854 
855  // construct a new CoeffTracker locally
856  return impl->world.taskq.add(*const_cast<CoeffTracker*> (this),
857  &CoeffTracker::forward_ctor,*this,datum1);
858  }
859 
860  private:
862  CoeffTracker forward_ctor(const CoeffTracker& other, const datumT& datum) const {
863  return CoeffTracker(other,datum);
864  }
865 
866  public:
868  template <typename Archive> void serialize(const Archive& ar) {
869  int il=int(is_leaf_);
870  ar & impl & key_ & il & coeff_;
871  is_leaf_=LeafStatus(il);
872  }
873  };
874 
875  template<typename T, std::size_t NDIM>
876  std::ostream&
877  operator<<(std::ostream& s, const CoeffTracker<T,NDIM>& ct) {
878  s << ct.key() << ct.is_leaf() << " " << ct.get_impl();
879  return s;
880  }
881 
883 
897  template <typename T, std::size_t NDIM>
898  class FunctionImpl : public WorldObject< FunctionImpl<T,NDIM> > {
899  private:
900  typedef WorldObject< FunctionImpl<T,NDIM> > woT;
901  public:
904  typedef Tensor<T> tensorT;
906  typedef Key<NDIM> keyT;
910  typedef std::pair<const keyT,nodeT> datumT;
912 
913  //template <typename Q, int D> friend class Function;
914  template <typename Q, std::size_t D> friend class FunctionImpl;
915 
917 
918  private:
919  int k;
920  double thresh;
921  int initial_level;
922  int max_refine_level;
923  int truncate_mode;
924  bool autorefine;
925  bool truncate_on_project;
926  bool nonstandard;
927  TensorArgs targs;
928 
929  const FunctionCommonData<T,NDIM>& cdata;
930 
932 
933  bool on_demand;
934  bool compressed;
935  bool redundant;
936 
937  dcT coeffs;
938 
939  // Disable the default copy constructor
941 
942  public:
948  bool do_new;
951 
954  : WorldObject<implT>(factory._world)
955  , world(factory._world)
956  , k(factory._k)
957  , thresh(factory._thresh)
958  , initial_level(factory._initial_level)
959  , max_refine_level(factory._max_refine_level)
960  , truncate_mode(factory._truncate_mode)
961  , autorefine(factory._autorefine)
962  , truncate_on_project(factory._truncate_on_project)
963  , nonstandard(false)
964  , targs(factory._thresh,FunctionDefaults<NDIM>::get_tensor_type())
965  , cdata(FunctionCommonData<T,NDIM>::get(k))
966  , functor(factory.get_functor())
967  , on_demand(factory._is_on_demand)
968  , compressed(false)
969  , redundant(false)
970  , coeffs(world,factory._pmap,false)
971  //, bc(factory._bc)
972  {
974  // !!! Ensure that all local state is correctly formed
975  // before invoking process_pending for the coeffs and
976  // for this. Otherwise, there is a race condition.
977  MADNESS_ASSERT(k>0 && k<=MAXK);
978 
979  bool empty = (factory._empty or is_on_demand());
980  bool do_refine = factory._refine;
981 
982  if (do_refine)
983  initial_level = std::max(0,initial_level - 1);
984 
985  if (empty) { // Do not set any coefficients at all
986  // additional functors are only evaluated on-demand
987  } else if (functor) { // Project function and optionally refine
989  typename dcT::const_iterator end = coeffs.end();
990  for (typename dcT::const_iterator it=coeffs.begin(); it!=end; ++it) {
991  if (it->second.is_leaf())
992  woT::task(coeffs.owner(it->first), &implT::project_refine_op, it->first, do_refine,
993  functor->special_points());
994  }
995  }
996  else { // Set as if a zero function
997  initial_level = 1;
999  }
1000 
1001  coeffs.process_pending();
1002  this->process_pending();
1003  if (factory._fence && functor)
1004  world.gop.fence();
1005  }
1006 
1008 
1013  template <typename Q>
1016  bool dozero)
1017  : WorldObject<implT>(other.world)
1018  , world(other.world)
1019  , k(other.k)
1020  , thresh(other.thresh)
1021  , initial_level(other.initial_level)
1022  , max_refine_level(other.max_refine_level)
1023  , truncate_mode(other.truncate_mode)
1024  , autorefine(other.autorefine)
1025  , truncate_on_project(other.truncate_on_project)
1026  , nonstandard(other.nonstandard)
1027  , targs(other.targs)
1028  , cdata(FunctionCommonData<T,NDIM>::get(k))
1029  , functor()
1030  , on_demand(false) // since functor() is an default ctor
1031  , compressed(other.compressed)
1032  , redundant(other.redundant)
1033  , coeffs(world, pmap ? pmap : other.coeffs.get_pmap())
1034  //, bc(other.bc)
1035  {
1036  if (dozero) {
1037  initial_level = 1;
1039  }
1040  coeffs.process_pending();
1041  this->process_pending();
1042  }
1043 
1044  virtual ~FunctionImpl() { }
1045 
1047 
1049  template <typename Q>
1050  void copy_coeffs(const FunctionImpl<Q,NDIM>& other, bool fence) {
1051  typename FunctionImpl<Q,NDIM>::dcT::const_iterator end = other.coeffs.end();
1052  for (typename FunctionImpl<Q,NDIM>::dcT::const_iterator it=other.coeffs.begin();
1053  it!=end; ++it) {
1054  const keyT& key = it->first;
1055  const typename FunctionImpl<Q,NDIM>::nodeT& node = it->second;
1056  coeffs.replace(key,node. template convert<Q>());
1057  }
1058  if (fence)
1059  world.gop.fence();
1060  }
1061 
1063  template<typename Q, typename R>
1064  void gaxpy_inplace_reconstructed(const T& alpha, const FunctionImpl<Q,NDIM>& g, const R& beta, const bool fence) {
1065  // merge g's tree into this' tree
1066  this->merge_trees(beta,g,alpha,true);
1067 
1068  // sum down the sum coeffs into the leafs
1069  if (world.rank() == coeffs.owner(cdata.key0)) sum_down_spawn(cdata.key0, coeffT());
1070  if (fence) world.gop.fence();
1071  }
1072 
1074 
1081  template<typename Q, typename R>
1082  void merge_trees(const T alpha, const FunctionImpl<Q,NDIM>& other, const R beta, const bool fence=true) {
1083  MADNESS_ASSERT(get_pmap() == other.get_pmap());
1084  other.flo_unary_op_node_inplace(do_merge_trees<Q,R>(alpha,beta,*this),fence);
1085  if (fence) world.gop.fence();
1086  }
1087 
1088 
1090 
1099  void gaxpy_oop_reconstructed(const double alpha, const implT& f,
1100  const double beta, const implT& g, const bool fence);
1101 
1102  template <typename Q, typename R>
1109  do_gaxpy_inplace(FunctionImpl<T,NDIM>* f, T alpha, R beta) : f(f), alpha(alpha), beta(beta) {}
1110  bool operator()(typename rangeT::iterator& it) const {
1111  const keyT& key = it->first;
1112  const FunctionNode<Q,NDIM>& other_node = it->second;
1113  // Use send to get write accessor and automated construction if missing
1114  f->coeffs.send(key, &nodeT:: template gaxpy_inplace<Q,R>, alpha, other_node, beta);
1115  return true;
1116  }
1117  template <typename Archive>
1118  void serialize(Archive& ar) {}
1119  };
1120 
1122  template <typename Q, typename R>
1123  void gaxpy_inplace(const T& alpha,const FunctionImpl<Q,NDIM>& other, const R& beta, bool fence) {
1124  MADNESS_ASSERT(get_pmap() == other.get_pmap());
1125  if (alpha != T(1.0)) scale_inplace(alpha,false);
1127  typedef do_gaxpy_inplace<Q,R> opT;
1128  world.taskq.for_each<rangeT,opT>(rangeT(other.coeffs.begin(), other.coeffs.end()), opT(this, T(1.0), beta));
1129  if (fence)
1130  world.gop.fence();
1131  }
1132 
1133  template <typename Archive>
1134  void load(Archive& ar) {
1135  // WE RELY ON K BEING STORED FIRST
1136  int kk = 0;
1137  ar & kk;
1138 
1139  MADNESS_ASSERT(kk==k);
1140 
1141  // note that functor should not be (re)stored
1142  ar & thresh & initial_level & max_refine_level & truncate_mode
1143  & autorefine & truncate_on_project & nonstandard & compressed ; //& bc;
1144 
1145  ar & coeffs;
1146  world.gop.fence();
1147  }
1148 
1149  template <typename Archive>
1150  void store(Archive& ar) {
1151  // WE RELY ON K BEING STORED FIRST
1152 
1153  // note that functor should not be (re)stored
1154  ar & k & thresh & initial_level & max_refine_level & truncate_mode
1155  & autorefine & truncate_on_project & nonstandard & compressed ; //& bc;
1156 
1157  ar & coeffs;
1158  world.gop.fence();
1159  }
1160 
1162  bool is_compressed() const;
1163 
1165  bool is_redundant() const;
1166 
1167  bool is_nonstandard() const;
1168 
1170 
1172 
1174 
1175  void unset_functor();
1176 
1177  bool& is_on_demand(); // ???????????????????? why returning reference
1178 
1179  const bool& is_on_demand() const; // ?????????????????????
1180 
1181  TensorType get_tensor_type() const;
1182 
1183  TensorArgs get_tensor_args() const;
1184 
1185  double get_thresh() const;
1186 
1187  void set_thresh(double value);
1188 
1189  bool get_autorefine() const;
1190 
1191  void set_autorefine(bool value);
1192 
1193  int get_k() const;
1194 
1195  const dcT& get_coeffs() const;
1196 
1197  dcT& get_coeffs();
1198 
1199  const FunctionCommonData<T,NDIM>& get_cdata() const;
1200 
1201  Void accumulate_timer(const double time) const; // !!!!!!!!!!!! REDUNDANT !!!!!!!!!!!!!!!
1202 
1203  void print_timer() const;
1204 
1205  void reset_timer();
1206 
1208 
1212  void add_scalar_inplace(T t, bool fence);
1213 
1215 
1217  void insert_zero_down_to_initial_level(const keyT& key);
1218 
1220 
1222  void truncate(double tol, bool fence);
1223 
1225 
1228  Future<bool> truncate_spawn(const keyT& key, double tol);
1229 
1231  bool truncate_op(const keyT& key, double tol, const std::vector< Future<bool> >& v);
1232 
1234  void fcube(const keyT& key, const FunctionFunctorInterface<T,NDIM>& f, const Tensor<double>& qx, tensorT& fval) const;
1235 
1236  void fcube(const keyT& key, T (*f)(const coordT&), const Tensor<double>& qx, tensorT& fval) const;
1237 
1238  const keyT& key0() const;
1239 
1240  void print_tree(std::ostream& os = std::cout, Level maxlevel = 10000) const;
1241 
1242  void do_print_tree(const keyT& key, std::ostream& os, Level maxlevel) const;
1243 
1244  void print_tree_graphviz(std::ostream& os = std::cout, Level maxlevel = 10000) const;
1245 
1246  void do_print_tree_graphviz(const keyT& key, std::ostream& os, Level maxlevel) const;
1247 
1251  double limit;
1252  bool log;
1253  static double lower() {return 1.e-10;};
1255  do_convert_to_color(const double limit, const bool log) : limit(limit), log(log) {}
1256  double operator()(double val) const {
1257  double color=0.0;
1258 
1259  if (log) {
1260  double val2=log10(val) - log10(lower()); // will yield >0.0
1261  double upper=log10(limit) -log10(lower());
1262  val2=0.7-(0.7/upper)*val2;
1263  color= std::max(0.0,val2);
1264  color= std::min(0.7,color);
1265  } else {
1266  double hue=0.7-(0.7/limit)*(val);
1267  color= std::max(0.0,hue);
1268  }
1269  return color;
1270  }
1271  };
1272 
1273 
1275 
1278  void print_plane(const std::string filename, const int xaxis, const int yaxis, const coordT& el2);
1279 
1281 
1285  Tensor<double> print_plane_local(const int xaxis, const int yaxis, const coordT& el2);
1286 
1288  Void do_print_plane(const std::string filename, std::vector<Tensor<double> > plotinfo,
1289  const int xaxis, const int yaxis, const coordT el2);
1290 
1293  void print_grid(const std::string filename) const;
1294 
1296  std::vector<keyT> local_leaf_keys() const;
1297 
1299 
1303  void do_print_grid(const std::string filename, const std::vector<keyT>& keys) const;
1304 
1306 
1310  template<size_t FDIM>
1312  read_grid(const std::string keyfile, const std::string gridfile,
1314 
1315  std::ifstream kfile(keyfile.c_str());
1316  std::ifstream gfile(gridfile.c_str());
1317  std::string line;
1318 
1319  long ndata,ndata1;
1320  if (not (std::getline(kfile,line))) MADNESS_EXCEPTION("failed reading 1st line of key data",0);
1321  if (not (std::istringstream(line) >> ndata)) MADNESS_EXCEPTION("failed reading k",0);
1322  if (not (std::getline(gfile,line))) MADNESS_EXCEPTION("failed reading 1st line of grid data",0);
1323  if (not (std::istringstream(line) >> ndata1)) MADNESS_EXCEPTION("failed reading k",0);
1324  MADNESS_ASSERT(ndata==ndata1);
1325  if (not (std::getline(kfile,line))) MADNESS_EXCEPTION("failed reading 2nd line of key data",0);
1326  if (not (std::getline(gfile,line))) MADNESS_EXCEPTION("failed reading 2nd line of grid data",0);
1327 
1328  // the quadrature points in simulation coordinates of the root node
1329  const Tensor<double> qx=cdata.quad_x;
1330  const size_t npt = qx.dim(0);
1331 
1332  // the number of coordinates (grid point tuples) per box ({x1},{x2},{x3},..,{xNDIM})
1333  long npoints=power<NDIM>(npt);
1334  // the number of boxes
1335  long nboxes=ndata/npoints;
1336  MADNESS_ASSERT(nboxes*npoints==ndata);
1337  print("reading ",nboxes,"boxes from file",gridfile,keyfile);
1338 
1339  // these will be the data
1340  Tensor<T> values(cdata.vk,false);
1341 
1342  int ii=0;
1343  std::string gline,kline;
1344  // while (1) {
1345  while (std::getline(kfile,kline)) {
1346 
1347  double x,y,z,x1,y1,z1,val;
1348 
1349  // get the key
1350  // MADNESS_ASSERT(std::getline(kfile,kline));
1351  long nn;
1352  Translation l1,l2,l3;
1353  // line looks like: # key: n l1 l2 l3
1354  kline.erase(0,7);
1355  std::stringstream(kline) >> nn >> l1 >> l2 >> l3;
1356  // kfile >> s >> nn >> l1 >> l2 >> l3;
1357  const Vector<Translation,3> ll=vec(l1,l2,l3);
1358  Key<3> key(nn,ll);
1359 
1360  // this is borrowed from fcube
1361  const Vector<Translation,3>& l = key.translation();
1362  const Level n = key.level();
1363  const double h = std::pow(0.5,double(n));
1364  coordT c; // will hold the point in user coordinates
1365  const Tensor<double>& cell_width = FunctionDefaults<NDIM>::get_cell_width();
1366  const Tensor<double>& cell = FunctionDefaults<NDIM>::get_cell();
1367 
1368 
1369  if (NDIM == 3) {
1370  for (int i=0; i<npt; ++i) {
1371  c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
1372  for (int j=0; j<npt; ++j) {
1373  c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
1374  for (int k=0; k<npt; ++k) {
1375  c[2] = cell(2,0) + h*cell_width[2]*(l[2] + qx(k)); // z
1376  // fprintf(pFile,"%18.12f %18.12f %18.12f\n",c[0],c[1],c[2]);
1377  MADNESS_ASSERT(std::getline(gfile,gline));
1378  MADNESS_ASSERT(std::getline(kfile,kline));
1379  std::istringstream(gline) >> x >> y >> z >> val;
1380  std::istringstream(kline) >> x1 >> y1 >> z1;
1381  MADNESS_ASSERT(std::fabs(x-c[0])<1.e-4);
1382  MADNESS_ASSERT(std::fabs(x1-c[0])<1.e-4);
1383  MADNESS_ASSERT(std::fabs(y-c[1])<1.e-4);
1384  MADNESS_ASSERT(std::fabs(y1-c[1])<1.e-4);
1385  MADNESS_ASSERT(std::fabs(z-c[2])<1.e-4);
1386  MADNESS_ASSERT(std::fabs(z1-c[2])<1.e-4);
1387 
1388  // regularize if a functor is given
1389  if (vnuc_functor) val-=(*vnuc_functor)(c);
1390  values(i,j,k)=val;
1391  }
1392  }
1393  }
1394  } else {
1395  MADNESS_EXCEPTION("only NDIM=3 in print_grid",0);
1396  }
1397 
1398  // insert the new leaf node
1399  const bool has_children=false;
1400  coeffT coeff=coeffT(this->values2coeffs(key,values),targs);
1401  nodeT node(coeff,has_children);
1402  coeffs.replace(key,node);
1403  const_cast<dcT&>(coeffs).task(key.parent(), &FunctionNode<T,NDIM>::set_has_children_recursive, coeffs, key.parent());
1404  ii++;
1405  }
1406 
1407  kfile.close();
1408  gfile.close();
1409  MADNESS_ASSERT(ii==nboxes);
1410 
1411  }
1412 
1413 
1415 
1418  template<size_t FDIM>
1420  read_grid2(const std::string gridfile,
1422 
1423  std::ifstream gfile(gridfile.c_str());
1424  std::string line;
1425 
1426  long ndata;
1427  if (not (std::getline(gfile,line))) MADNESS_EXCEPTION("failed reading 1st line of grid data",0);
1428  if (not (std::istringstream(line) >> ndata)) MADNESS_EXCEPTION("failed reading k",0);
1429  if (not (std::getline(gfile,line))) MADNESS_EXCEPTION("failed reading 2nd line of grid data",0);
1430 
1431  // the quadrature points in simulation coordinates of the root node
1432  const Tensor<double> qx=cdata.quad_x;
1433  const size_t npt = qx.dim(0);
1434 
1435  // the number of coordinates (grid point tuples) per box ({x1},{x2},{x3},..,{xNDIM})
1436  long npoints=power<NDIM>(npt);
1437  // the number of boxes
1438  long nboxes=ndata/npoints;
1439  MADNESS_ASSERT(nboxes*npoints==ndata);
1440  print("reading ",nboxes,"boxes from file",gridfile);
1441 
1442  // these will be the data
1443  Tensor<T> values(cdata.vk,false);
1444 
1445  int ii=0;
1446  std::string gline;
1447  // while (1) {
1448  while (std::getline(gfile,gline)) {
1449 
1450  double x1,y1,z1,val;
1451 
1452  // get the key
1453  long nn;
1454  Translation l1,l2,l3;
1455  // line looks like: # key: n l1 l2 l3
1456  gline.erase(0,7);
1457  std::stringstream(gline) >> nn >> l1 >> l2 >> l3;
1458  const Vector<Translation,3> ll=vec(l1,l2,l3);
1459  Key<3> key(nn,ll);
1460 
1461  // this is borrowed from fcube
1462  const Vector<Translation,3>& l = key.translation();
1463  const Level n = key.level();
1464  const double h = std::pow(0.5,double(n));
1465  coordT c; // will hold the point in user coordinates
1466  const Tensor<double>& cell_width = FunctionDefaults<NDIM>::get_cell_width();
1467  const Tensor<double>& cell = FunctionDefaults<NDIM>::get_cell();
1468 
1469 
1470  if (NDIM == 3) {
1471  for (int i=0; i<npt; ++i) {
1472  c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
1473  for (int j=0; j<npt; ++j) {
1474  c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
1475  for (int k=0; k<npt; ++k) {
1476  c[2] = cell(2,0) + h*cell_width[2]*(l[2] + qx(k)); // z
1477 
1478  MADNESS_ASSERT(std::getline(gfile,gline));
1479  std::istringstream(gline) >> x1 >> y1 >> z1 >> val;
1480  MADNESS_ASSERT(std::fabs(x1-c[0])<1.e-4);
1481  MADNESS_ASSERT(std::fabs(y1-c[1])<1.e-4);
1482  MADNESS_ASSERT(std::fabs(z1-c[2])<1.e-4);
1483 
1484  // regularize if a functor is given
1485  if (vnuc_functor) val-=(*vnuc_functor)(c);
1486  values(i,j,k)=val;
1487  }
1488  }
1489  }
1490  } else {
1491  MADNESS_EXCEPTION("only NDIM=3 in print_grid",0);
1492  }
1493 
1494  // insert the new leaf node
1495  const bool has_children=false;
1496  coeffT coeff=coeffT(this->values2coeffs(key,values),targs);
1497  nodeT node(coeff,has_children);
1498  coeffs.replace(key,node);
1499  const_cast<dcT&>(coeffs).task(key.parent(),
1501  coeffs, key.parent());
1502  ii++;
1503  }
1504 
1505  gfile.close();
1506  MADNESS_ASSERT(ii==nboxes);
1507 
1508  }
1509 
1510 
1512  tensorT project(const keyT& key) const;
1513 
1515 
1522  double truncate_tol(double tol, const keyT& key) const;
1523 
1524 
1526  std::vector<Slice> child_patch(const keyT& child) const;
1527 
1529  Void project_refine_op(const keyT& key, bool do_refine,
1530  const std::vector<Vector<double,NDIM> >& specialpts);
1531 
1533 
1537  void phi_for_mul(Level np, Translation lp, Level nc, Translation lc, Tensor<double>& phi) const;
1538 
1540 
1542  const coeffT parent_to_child(const coeffT& s, const keyT& parent, const keyT& child) const;
1543 
1545 
1552  coeffT parent_to_child_NS(const keyT& child, const keyT& parent,
1553  const coeffT& coeff) const;
1554 
1556  Key<NDIM> simpt2key(const coordT& pt, Level n) const;
1557 
1559  // N=2^n, M=N/q, q must be power of 2
1560  // q=0 return coeffs [N,k] for direct sum
1561  // q>0 return coeffs [k,q,M] for fft sum
1562  tensorT coeffs_for_jun(Level n, long q=0);
1563 
1564  template <typename Q>
1565  GenTensor<Q> coeffs2values(const keyT& key, const GenTensor<Q>& coeff) const {
1567  double scale = pow(2.0,0.5*NDIM*key.level())/sqrt(FunctionDefaults<NDIM>::get_cell_volume());
1568  return transform(coeff,cdata.quad_phit).scale(scale);
1569  }
1570 
1572 
1580  template <typename Q>
1581  GenTensor<Q> NScoeffs2values(const keyT& key, const GenTensor<Q>& coeff,
1582  const bool s_only) const {
1584 
1585  // sanity checks
1586  MADNESS_ASSERT((coeff.dim(0)==this->get_k()) == s_only);
1587  MADNESS_ASSERT((coeff.dim(0)==this->get_k()) or (coeff.dim(0)==2*this->get_k()));
1588 
1589  // this is a block-diagonal matrix with the quadrature points on the diagonal
1590  Tensor<double> quad_phit_2k(2*cdata.k,2*cdata.npt);
1591  quad_phit_2k(cdata.s[0],cdata.s[0])=cdata.quad_phit;
1592  quad_phit_2k(cdata.s[1],cdata.s[1])=cdata.quad_phit;
1593 
1594  // the transformation matrix unfilters (cdata.hg) and transforms to values in one step
1595  const Tensor<double> transf = (s_only)
1596  ? inner(cdata.hg(Slice(0,k-1),_),quad_phit_2k) // S coeffs
1597  : inner(cdata.hg,quad_phit_2k); // NS coeffs
1598 
1599  // increment the level since the coeffs2values part happens on level n+1
1600  const double scale = pow(2.0,0.5*NDIM*(key.level()+1))/
1602 
1603  return transform(coeff,transf).scale(scale);
1604  }
1605 
1607 
1616  template <typename Q>
1617  GenTensor<Q> NS_fcube_for_mul(const keyT& child, const keyT& parent,
1618  const GenTensor<Q>& coeff, const bool s_only) const {
1620 
1621  // sanity checks
1622  MADNESS_ASSERT((coeff.dim(0)==this->get_k()) == s_only);
1623  MADNESS_ASSERT((coeff.dim(0)==this->get_k()) or (coeff.dim(0)==2*this->get_k()));
1624 
1625  // fast return if possible
1626  // if (child.level()==parent.level()) return NScoeffs2values(child,coeff,s_only);
1627 
1628  if (s_only) {
1629 
1630  Tensor<double> quad_phi[NDIM];
1631  // tmp tensor
1632  Tensor<double> phi1(cdata.k,cdata.npt);
1633 
1634  for (std::size_t d=0; d<NDIM; ++d) {
1635 
1636  // input is S coeffs (dimension k), output is values on 2*npt grid points
1637  quad_phi[d]=Tensor<double>(cdata.k,2*cdata.npt);
1638 
1639  // for both children of "child" evaluate the Legendre polynomials
1640  // first the left child on level n+1 and translations 2l
1641  phi_for_mul(parent.level(),parent.translation()[d],
1642  child.level()+1, 2*child.translation()[d], phi1);
1643  quad_phi[d](_,Slice(0,k-1))=phi1;
1644 
1645  // next the right child on level n+1 and translations 2l+1
1646  phi_for_mul(parent.level(),parent.translation()[d],
1647  child.level()+1, 2*child.translation()[d]+1, phi1);
1648  quad_phi[d](_,Slice(k,2*k-1))=phi1;
1649  }
1650 
1651  const double scale = 1.0/sqrt(FunctionDefaults<NDIM>::get_cell_volume());
1652  return general_transform(coeff,quad_phi).scale(scale);
1653  }
1654  MADNESS_EXCEPTION("you should not be here in NS_fcube_for_mul",1);
1655  return GenTensor<Q>();
1656  }
1657 
1659 
1665  template <typename Q>
1666  GenTensor<Q> values2NScoeffs(const keyT& key, const GenTensor<Q>& values) const {
1668 
1669  // sanity checks
1670  MADNESS_ASSERT(values.dim(0)==2*this->get_k());
1671 
1672  // this is a block-diagonal matrix with the quadrature points on the diagonal
1673  Tensor<double> quad_phit_2k(2*cdata.npt,2*cdata.k);
1674  quad_phit_2k(cdata.s[0],cdata.s[0])=cdata.quad_phiw;
1675  quad_phit_2k(cdata.s[1],cdata.s[1])=cdata.quad_phiw;
1676 
1677  // the transformation matrix unfilters (cdata.hg) and transforms to values in one step
1678  const Tensor<double> transf=inner(quad_phit_2k,cdata.hgT);
1679 
1680  // increment the level since the values2coeffs part happens on level n+1
1681  const double scale = pow(0.5,0.5*NDIM*(key.level()+1))
1683 
1684  return transform(values,transf).scale(scale);
1685  }
1686 
1687  template <typename Q>
1688  Tensor<Q> coeffs2values(const keyT& key, const Tensor<Q>& coeff) const {
1690  double scale = pow(2.0,0.5*NDIM*key.level())/sqrt(FunctionDefaults<NDIM>::get_cell_volume());
1691  return transform(coeff,cdata.quad_phit).scale(scale);
1692  }
1693 
1694  template <typename Q>
1695  GenTensor<Q> values2coeffs(const keyT& key, const GenTensor<Q>& values) const {
1697  double scale = pow(0.5,0.5*NDIM*key.level())*sqrt(FunctionDefaults<NDIM>::get_cell_volume());
1698  return transform(values,cdata.quad_phiw).scale(scale);
1699  }
1700 
1701  template <typename Q>
1702  Tensor<Q> values2coeffs(const keyT& key, const Tensor<Q>& values) const {
1704  double scale = pow(0.5,0.5*NDIM*key.level())*sqrt(FunctionDefaults<NDIM>::get_cell_volume());
1705  return transform(values,cdata.quad_phiw).scale(scale);
1706  }
1707 
1709 
1712  template <typename Q>
1713  Tensor<Q> fcube_for_mul(const keyT& child, const keyT& parent, const Tensor<Q>& coeff) const {
1715  if (child.level() == parent.level()) {
1716  return coeffs2values(parent, coeff);
1717  }
1718  else if (child.level() < parent.level()) {
1719  MADNESS_EXCEPTION("FunctionImpl: fcube_for_mul: child-parent relationship bad?",0);
1720  }
1721  else {
1722  Tensor<double> phi[NDIM];
1723  for (std::size_t d=0; d<NDIM; ++d) {
1724  phi[d] = Tensor<double>(cdata.k,cdata.npt);
1725  phi_for_mul(parent.level(),parent.translation()[d],
1726  child.level(), child.translation()[d], phi[d]);
1727  }
1728  return general_transform(coeff,phi).scale(1.0/sqrt(FunctionDefaults<NDIM>::get_cell_volume()));;
1729  }
1730  }
1731 
1732 
1734 
1737  template <typename Q>
1738  GenTensor<Q> fcube_for_mul(const keyT& child, const keyT& parent, const GenTensor<Q>& coeff) const {
1740  if (child.level() == parent.level()) {
1741  return coeffs2values(parent, coeff);
1742  }
1743  else if (child.level() < parent.level()) {
1744  MADNESS_EXCEPTION("FunctionImpl: fcube_for_mul: child-parent relationship bad?",0);
1745  }
1746  else {
1747  Tensor<double> phi[NDIM];
1748  for (size_t d=0; d<NDIM; d++) {
1749  phi[d] = Tensor<double>(cdata.k,cdata.npt);
1750  phi_for_mul(parent.level(),parent.translation()[d],
1751  child.level(), child.translation()[d], phi[d]);
1752  }
1753  return general_transform(coeff,phi).scale(1.0/sqrt(FunctionDefaults<NDIM>::get_cell_volume()));
1754  }
1755  }
1756 
1757 
1759  template <typename L, typename R>
1760  Void do_mul(const keyT& key, const Tensor<L>& left, const std::pair< keyT, Tensor<R> >& arg) {
1762  const keyT& rkey = arg.first;
1763  const Tensor<R>& rcoeff = arg.second;
1764  //madness::print("do_mul: r", rkey, rcoeff.size());
1765  Tensor<R> rcube = fcube_for_mul(key, rkey, rcoeff);
1766  //madness::print("do_mul: l", key, left.size());
1767  Tensor<L> lcube = fcube_for_mul(key, key, left);
1768 
1769  Tensor<T> tcube(cdata.vk,false);
1770  TERNARY_OPTIMIZED_ITERATOR(T, tcube, L, lcube, R, rcube, *_p0 = *_p1 * *_p2;);
1771  double scale = pow(0.5,0.5*NDIM*key.level())*sqrt(FunctionDefaults<NDIM>::get_cell_volume());
1772  tcube = transform(tcube,cdata.quad_phiw).scale(scale);
1773  coeffs.replace(key, nodeT(coeffT(tcube,targs),false));
1774  return None;
1775  }
1776 
1777 
1779 
1785  template<typename R>
1786  Tensor<TENSOR_RESULT_TYPE(T,R)> mul(const Tensor<T>& c1, const Tensor<R>& c2,
1787  const int npt, const keyT& key) const {
1788  typedef TENSOR_RESULT_TYPE(T,R) resultT;
1789 
1791 
1792  // construct a tensor with the npt coeffs
1793  Tensor<T> c11(cdata2.vk), c22(cdata2.vk);
1794  c11(this->cdata.s0)=c1;
1795  c22(this->cdata.s0)=c2;
1796 
1797  // it's sufficient to scale once
1798  double scale = pow(2.0,0.5*NDIM*key.level())/sqrt(FunctionDefaults<NDIM>::get_cell_volume());
1799  Tensor<T> c1value=transform(c11,cdata2.quad_phit).scale(scale);
1800  Tensor<R> c2value=transform(c22,cdata2.quad_phit);
1801  Tensor<resultT> resultvalue(cdata2.vk,false);
1802  TERNARY_OPTIMIZED_ITERATOR(resultT, resultvalue, T, c1value, R, c2value, *_p0 = *_p1 * *_p2;);
1803 
1804  Tensor<resultT> result=transform(resultvalue,cdata2.quad_phiw);
1805 
1806  // return a copy of the slice to have the tensor contiguous
1807  return copy(result(this->cdata.s0));
1808  }
1809 
1810 
1812  template <typename L, typename R, typename opT>
1813  Void do_binary_op(const keyT& key, const Tensor<L>& left,
1814  const std::pair< keyT, Tensor<R> >& arg,
1815  const opT& op) {
1817  const keyT& rkey = arg.first;
1818  const Tensor<R>& rcoeff = arg.second;
1819  Tensor<R> rcube = fcube_for_mul(key, rkey, rcoeff);
1820  Tensor<L> lcube = fcube_for_mul(key, key, left);
1821 
1822  Tensor<T> tcube(cdata.vk,false);
1823  op(key, tcube, lcube, rcube);
1824  double scale = pow(0.5,0.5*NDIM*key.level())*sqrt(FunctionDefaults<NDIM>::get_cell_volume());
1825  tcube = transform(tcube,cdata.quad_phiw).scale(scale);
1826  coeffs.replace(key, nodeT(coeffT(tcube,targs),false));
1827  return None;
1828  }
1829 
1831 
1836  template <typename L, typename R>
1837  void gaxpy(T alpha, const FunctionImpl<L,NDIM>& left,
1838  T beta, const FunctionImpl<R,NDIM>& right, bool fence) {
1839  // Loop over local nodes in both functions. Add in left and subtract right.
1840  // Not that efficient in terms of memory bandwidth but ensures we do
1841  // not miss any nodes.
1842  typename FunctionImpl<L,NDIM>::dcT::const_iterator left_end = left.coeffs.end();
1843  for (typename FunctionImpl<L,NDIM>::dcT::const_iterator it=left.coeffs.begin();
1844  it!=left_end;
1845  ++it) {
1846  const keyT& key = it->first;
1847  const typename FunctionImpl<L,NDIM>::nodeT& other_node = it->second;
1848  coeffs.send(key, &nodeT:: template gaxpy_inplace<T,L>, 1.0, other_node, alpha);
1849  }
1850  typename FunctionImpl<R,NDIM>::dcT::const_iterator right_end = right.coeffs.end();
1851  for (typename FunctionImpl<R,NDIM>::dcT::const_iterator it=right.coeffs.begin();
1852  it!=right_end;
1853  ++it) {
1854  const keyT& key = it->first;
1855  const typename FunctionImpl<L,NDIM>::nodeT& other_node = it->second;
1856  coeffs.send(key, &nodeT:: template gaxpy_inplace<T,R>, 1.0, other_node, beta);
1857  }
1858  if (fence)
1859  world.gop.fence();
1860  }
1861 
1863  template <typename opT>
1864  void unary_op_coeff_inplace(const opT& op, bool fence) {
1865  typename dcT::iterator end = coeffs.end();
1866  for (typename dcT::iterator it=coeffs.begin(); it!=end; ++it) {
1867  const keyT& parent = it->first;
1868  nodeT& node = it->second;
1869  if (node.has_coeff()) {
1870  // op(parent, node.coeff());
1871  TensorArgs full(-1.0,TT_FULL);
1872  change_tensor_type(node.coeff(),full);
1873  op(parent, node.coeff().full_tensor());
1874  change_tensor_type(node.coeff(),targs);
1875  // op(parent,node);
1876  }
1877  }
1878  if (fence)
1879  world.gop.fence();
1880  }
1881 
1883  template <typename opT>
1884  void unary_op_node_inplace(const opT& op, bool fence) {
1885  typename dcT::iterator end = coeffs.end();
1886  for (typename dcT::iterator it=coeffs.begin(); it!=end; ++it) {
1887  const keyT& parent = it->first;
1888  nodeT& node = it->second;
1889  op(parent, node);
1890  }
1891  if (fence)
1892  world.gop.fence();
1893  }
1894 
1896  template <typename opT>
1897  void flo_unary_op_node_inplace(const opT& op, bool fence) {
1899  typedef do_unary_op_value_inplace<opT> xopT;
1900  world.taskq.for_each<rangeT,opT>(rangeT(coeffs.begin(), coeffs.end()), op);
1901  if (fence)
1902  world.gop.fence();
1903  }
1904 
1906  template <typename opT>
1907  void flo_unary_op_node_inplace(const opT& op, bool fence) const {
1909  typedef do_unary_op_value_inplace<opT> xopT;
1910  world.taskq.for_each<rangeT,opT>(rangeT(coeffs.begin(), coeffs.end()), op);
1911  if (fence)
1912  world.gop.fence();
1913  }
1914 
1916  Void erase(const Level& max_level);
1917 
1919  double check_symmetry_local() const;
1920 
1924  const implT* f; // for calling its member functions
1925 
1926  do_truncate_NS_leafs(const implT* f) : f(f) {}
1927 
1928  bool operator()(typename rangeT::iterator& it) const {
1929 
1930  const keyT& key = it->first;
1931  nodeT& node = it->second;
1932 
1933  if (node.is_leaf() and node.coeff().has_data()) {
1934  coeffT d = copy(node.coeff());
1935  d(f->cdata.s0)=0.0;
1936  const double error=d.normf();
1937  const double tol=f->truncate_tol(f->get_thresh(),key);
1938  if (error<tol) node.coeff()=copy(node.coeff()(f->cdata.s0));
1939  }
1940  return true;
1941  }
1942  template <typename Archive> void serialize(const Archive& ar) {}
1943 
1944  };
1945 
1950 
1953 
1954  bool operator()(typename rangeT::iterator& it) const {
1955 
1956  nodeT& node = it->second;
1957  if (node.has_children()) node.clear_coeff();
1958  return true;
1959  }
1960  template <typename Archive> void serialize(const Archive& ar) {}
1961 
1962  };
1963 
1964 
1968  implT* impl;
1969 
1971  do_keep_sum_coeffs(implT* impl) :impl(impl) {}
1972 
1973  bool operator()(typename rangeT::iterator& it) const {
1974 
1975  nodeT& node = it->second;
1976  coeffT s=copy(node.coeff()(impl->cdata.s0));
1977  node.coeff()=s;
1978  return true;
1979  }
1980  template <typename Archive> void serialize(const Archive& ar) {}
1981 
1982  };
1983 
1984 
1988 
1989  // threshold for rank reduction / SVD truncation
1991 
1992  // constructor takes target precision
1994  do_reduce_rank(const TensorArgs& targs) : args(targs) {}
1995  do_reduce_rank(const double& thresh) {
1996  args.thresh=thresh;
1997  }
1998 
1999  //
2000  bool operator()(typename rangeT::iterator& it) const {
2001 
2002  nodeT& node = it->second;
2003  node.reduceRank(args.thresh);
2004  return true;
2005  }
2006  template <typename Archive> void serialize(const Archive& ar) {}
2007  };
2008 
2009 
2010 
2014  const implT* f;
2016  do_check_symmetry_local(const implT& f) : f(&f) {}
2017 
2019  double operator()(typename rangeT::iterator& it) const {
2020 
2021  const keyT& key = it->first;
2022  const nodeT& fnode = it->second;
2023 
2024  // skip internal nodes
2025  if (fnode.has_children()) return 0.0;
2026 
2027  if (f->world.size()>1) return 0.0;
2028 
2029  // exchange particles
2030  std::vector<long> map(NDIM);
2031  map[0]=3; map[1]=4; map[2]=5;
2032  map[3]=0; map[4]=1; map[5]=2;
2033 
2034  // make mapped key
2036  for (std::size_t i=0; i<NDIM; ++i) l[map[i]] = key.translation()[i];
2037  const keyT mapkey(key.level(),l);
2038 
2039  double norm=0.0;
2040 
2041 
2042  // hope it's local
2043  if (f->get_coeffs().probe(mapkey)) {
2044  MADNESS_ASSERT(f->get_coeffs().probe(mapkey));
2045  const nodeT& mapnode=f->get_coeffs().find(mapkey).get()->second;
2046 
2047  bool have_c1=fnode.coeff().has_data() and fnode.coeff().config().has_data();
2048  bool have_c2=mapnode.coeff().has_data() and mapnode.coeff().config().has_data();
2049 
2050  if (have_c1 and have_c2) {
2051  tensorT c1=fnode.coeff().full_tensor_copy();
2052  tensorT c2=mapnode.coeff().full_tensor_copy();
2053  c2 = copy(c2.mapdim(map));
2054  norm=(c1-c2).normf();
2055  } else if (have_c1) {
2056  tensorT c1=fnode.coeff().full_tensor_copy();
2057  norm=c1.normf();
2058  } else if (have_c2) {
2059  tensorT c2=mapnode.coeff().full_tensor_copy();
2060  norm=c2.normf();
2061  } else {
2062  norm=0.0;
2063  }
2064  } else {
2065  norm=fnode.coeff().normf();
2066  }
2067  return norm*norm;
2068  }
2069 
2070  double operator()(double a, double b) const {
2071  return (a+b);
2072  }
2073 
2074  template <typename Archive> void serialize(const Archive& ar) {
2075  MADNESS_EXCEPTION("no serialization of do_check_symmetry yet",1);
2076  }
2077 
2078 
2079  };
2080 
2082 
2085  template<typename Q, typename R>
2092  do_merge_trees(const T alpha, const R beta, FunctionImpl<Q,NDIM>& other)
2093  : other(&other), alpha(alpha), beta(beta) {}
2094 
2096  bool operator()(typename rangeT::iterator& it) const {
2097 
2098  const keyT& key = it->first;
2099  const nodeT& fnode = it->second;
2100 
2101  // if other's node exists: add this' coeffs to it
2102  // otherwise insert this' node into other's tree
2103  typename dcT::accessor acc;
2104  if (other->get_coeffs().find(acc,key)) {
2105  nodeT& gnode=acc->second;
2106  gnode.gaxpy_inplace(beta,fnode,alpha);
2107  } else {
2108  nodeT gnode=fnode;
2109  gnode.scale(alpha);
2110  other->get_coeffs().replace(key,gnode);
2111  }
2112  return true;
2113  }
2114 
2115  template <typename Archive> void serialize(const Archive& ar) {
2116  MADNESS_EXCEPTION("no serialization of do_merge_trees",1);
2117  }
2118  };
2119 
2120 
2122  struct do_mapdim {
2124 
2125  std::vector<long> map;
2126  implT* f;
2127 
2128  do_mapdim() : f(0) {};
2129  do_mapdim(const std::vector<long> map, implT& f) : map(map), f(&f) {}
2130 
2131  bool operator()(typename rangeT::iterator& it) const {
2132 
2133  const keyT& key = it->first;
2134  const nodeT& node = it->second;
2135 
2137  for (std::size_t i=0; i<NDIM; ++i) l[map[i]] = key.translation()[i];
2138  tensorT c = node.coeff().full_tensor_copy();
2139  if (c.size()) c = copy(c.mapdim(map));
2140  coeffT cc(c,f->get_tensor_args());
2141  f->get_coeffs().replace(keyT(key.level(),l), nodeT(cc,node.has_children()));
2142 
2143  return true;
2144  }
2145  template <typename Archive> void serialize(const Archive& ar) {
2146  MADNESS_EXCEPTION("no serialization of do_mapdim",1);
2147  }
2148 
2149  };
2150 
2152  struct do_average {
2154 
2155  implT* g;
2156 
2158  do_average(implT& g) : g(&g) {}
2159 
2161  bool operator()(typename rangeT::iterator& it) const {
2162 
2163  const keyT& key = it->first;
2164  const nodeT& fnode = it->second;
2165 
2166  // fast return if rhs has no coeff here
2167  if (fnode.has_coeff()) {
2168 
2169  // check if there is a node already existing
2170  typename dcT::accessor acc;
2171  if (g->get_coeffs().find(acc,key)) {
2172  nodeT& gnode=acc->second;
2173  if (gnode.has_coeff()) gnode.coeff()+=fnode.coeff();
2174  } else {
2175  g->get_coeffs().replace(key,fnode);
2176  }
2177  }
2178 
2179  return true;
2180  }
2181  template <typename Archive> void serialize(const Archive& ar) {}
2182  };
2183 
2187 
2188  // threshold for rank reduction / SVD truncation
2190 
2191  // constructor takes target precision
2193  do_change_tensor_type(const TensorArgs& targs) : targs(targs) {}
2194 
2195  //
2196  bool operator()(typename rangeT::iterator& it) const {
2197 
2198  nodeT& node = it->second;
2199  change_tensor_type(node.coeff(),targs);
2200  return true;
2201 
2202  }
2203  template <typename Archive> void serialize(const Archive& ar) {}
2204  };
2205 
2208 
2209  // threshold for rank reduction / SVD truncation
2211 
2212  // constructor takes target precision
2214  do_consolidate_buffer(const TensorArgs& targs) : targs(targs) {}
2215  bool operator()(typename rangeT::iterator& it) const {
2216  it->second.consolidate_buffer(targs);
2217  return true;
2218  }
2219  template <typename Archive> void serialize(const Archive& ar) {}
2220  };
2221 
2222 
2223 
2224  template <typename opT>
2227  implT* impl;
2228  opT op;
2229  do_unary_op_value_inplace(implT* impl, const opT& op) : impl(impl), op(op) {}
2230  bool operator()(typename rangeT::iterator& it) const {
2231  const keyT& key = it->first;
2232  nodeT& node = it->second;
2233  if (node.has_coeff()) {
2234  const TensorArgs full_args(-1.0,TT_FULL);
2235  change_tensor_type(node.coeff(),full_args);
2236  tensorT& t= node.coeff().full_tensor();
2237  //double before = t.normf();
2238  tensorT values = impl->fcube_for_mul(key, key, t);
2239  op(key, values);
2240  double scale = pow(0.5,0.5*NDIM*key.level())*sqrt(FunctionDefaults<NDIM>::get_cell_volume());
2241  t = transform(values,impl->cdata.quad_phiw).scale(scale);
2242  node.coeff()=coeffT(t,impl->get_tensor_args());
2243  //double after = t.normf();
2244  //madness::print("XOP:", key, before, after);
2245  }
2246  return true;
2247  }
2248  template <typename Archive> void serialize(const Archive& ar) {}
2249  };
2250 
2251  template <typename Q, typename R>
2253  const Tensor<Q>& c,
2254  const std::vector< std::shared_ptr< FunctionImpl<T,NDIM> > >& vleft,
2255  double tol) {
2256  // To reduce crunch on vectors being transformed each task
2257  // does them in a random order
2258  std::vector<unsigned int> ind(vleft.size());
2259  for (unsigned int i=0; i<vleft.size(); ++i) {
2260  ind[i] = i;
2261  }
2262  for (unsigned int i=0; i<vleft.size(); ++i) {
2263  unsigned int j = RandomValue<int>()%vleft.size();
2264  std::swap(ind[i],ind[j]);
2265  }
2266 
2267  typename FunctionImpl<R,NDIM>::dcT::const_iterator end = right->coeffs.end();
2268  for (typename FunctionImpl<R,NDIM>::dcT::const_iterator it=right->coeffs.begin(); it != end; ++it) {
2269  if (it->second.has_coeff()) {
2270  const Key<NDIM>& key = it->first;
2271  const GenTensor<R>& r = it->second.coeff();
2272  double norm = r.normf();
2273  double keytol = truncate_tol(tol,key);
2274 
2275  for (unsigned int j=0; j<vleft.size(); ++j) {
2276  unsigned int i = ind[j]; // Random permutation
2277  if (std::abs(norm*c(i)) > keytol) {
2278  implT* left = vleft[i].get();
2279  typename dcT::accessor acc;
2280  bool newnode = left->coeffs.insert(acc,key);
2281  if (newnode && key.level()>0) {
2282  Key<NDIM> parent = key.parent();
2283  left->coeffs.task(parent, &nodeT::set_has_children_recursive, left->coeffs, parent);
2284  }
2285  nodeT& node = acc->second;
2286  if (!node.has_coeff())
2287  node.set_coeff(coeffT(cdata.v2k,targs));
2288  coeffT& t = node.coeff();
2289  t.gaxpy(1.0, r, c(i));
2290  }
2291  }
2292  }
2293  }
2294  return None;
2295  }
2296 
2298 
2302  Void refine_to_common_level(const std::vector<FunctionImpl<T,NDIM>*>& v,
2303  const std::vector<tensorT>& c,
2304  const keyT key);
2305 
2306  template <typename opT>
2307  Void multiop_values_doit(const keyT& key, const opT& op, const std::vector<implT*>& v) {
2308  std::vector<tensorT> c(v.size());
2309  for (unsigned int i=0; i<v.size(); i++) {
2310  c[i] = coeffs2values(key, v[i]->coeffs.find(key).get()->second.coeff().full_tensor_copy()); // !!!!! gack
2311  }
2312  tensorT r = op(key, c);
2313  coeffs.replace(key, nodeT(coeffT(values2coeffs(key, r),targs),false));
2314  return None;
2315  }
2316 
2317  // assumes all functions have been refined down to the same level
2318  template <typename opT>
2319  void multiop_values(const opT& op, const std::vector<implT*>& v) {
2320  typename dcT::iterator end = v[0]->coeffs.end();
2321  for (typename dcT::iterator it=v[0]->coeffs.begin(); it!=end; ++it) {
2322  const keyT& key = it->first;
2323  if (it->second.has_coeff())
2324  world.taskq.add(*this, &implT:: template multiop_values_doit<opT>, key, op, v);
2325  else
2326  coeffs.replace(key, nodeT(coeffT(),true));
2327  }
2328  world.gop.fence();
2329  }
2330 
2332  template <typename Q, typename R>
2333  void vtransform(const std::vector< std::shared_ptr< FunctionImpl<R,NDIM> > >& vright,
2334  const Tensor<Q>& c,
2335  const std::vector< std::shared_ptr< FunctionImpl<T,NDIM> > >& vleft,
2336  double tol,
2337  bool fence) {
2338  for (unsigned int j=0; j<vright.size(); ++j) {
2339  world.taskq.add(*this, &implT:: template vtransform_doit<Q,R>, vright[j], copy(c(j,_)), vleft, tol);
2340  }
2341  if (fence)
2342  world.gop.fence();
2343  }
2344 
2346  template <typename opT>
2347  void unary_op_value_inplace(const opT& op, bool fence) {
2349  typedef do_unary_op_value_inplace<opT> xopT;
2350  world.taskq.for_each<rangeT,xopT>(rangeT(coeffs.begin(), coeffs.end()), xopT(this,op));
2351  if (fence)
2352  world.gop.fence();
2353  }
2354 
2355  // Multiplication assuming same distribution and recursive descent
2356  template <typename L, typename R>
2357  Void mulXXveca(const keyT& key,
2358  const FunctionImpl<L,NDIM>* left, const Tensor<L>& lcin,
2359  const std::vector<const FunctionImpl<R,NDIM>*> vrightin,
2360  const std::vector< Tensor<R> >& vrcin,
2361  const std::vector<FunctionImpl<T,NDIM>*> vresultin,
2362  double tol) {
2363  typedef typename FunctionImpl<L,NDIM>::dcT::const_iterator literT;
2364  typedef typename FunctionImpl<R,NDIM>::dcT::const_iterator riterT;
2365 
2366  double lnorm = 1e99;
2367  Tensor<L> lc = lcin;
2368  if (lc.size() == 0) {
2369  literT it = left->coeffs.find(key).get();
2370  MADNESS_ASSERT(it != left->coeffs.end());
2371  lnorm = it->second.get_norm_tree();
2372  if (it->second.has_coeff())
2373  lc = it->second.coeff().full_tensor_copy();
2374  }
2375 
2376  // Loop thru RHS functions seeing if anything can be multiplied
2377  std::vector<FunctionImpl<T,NDIM>*> vresult;
2378  std::vector<const FunctionImpl<R,NDIM>*> vright;
2379  std::vector< Tensor<R> > vrc;
2380  vresult.reserve(vrightin.size());
2381  vright.reserve(vrightin.size());
2382  vrc.reserve(vrightin.size());
2383 
2384  for (unsigned int i=0; i<vrightin.size(); ++i) {
2385  FunctionImpl<T,NDIM>* result = vresultin[i];
2386  const FunctionImpl<R,NDIM>* right = vrightin[i];
2387  Tensor<R> rc = vrcin[i];
2388  double rnorm;
2389  if (rc.size() == 0) {
2390  riterT it = right->coeffs.find(key).get();
2391  MADNESS_ASSERT(it != right->coeffs.end());
2392  rnorm = it->second.get_norm_tree();
2393  if (it->second.has_coeff())
2394  rc = it->second.coeff().full_tensor_copy();
2395  }
2396  else {
2397  rnorm = rc.normf();
2398  }
2399 
2400  if (rc.size() && lc.size()) { // Yipee!
2401  result->task(world.rank(), &implT:: template do_mul<L,R>, key, lc, std::make_pair(key,rc));
2402  }
2403  else if (tol && lnorm*rnorm < truncate_tol(tol, key)) {
2404  result->coeffs.replace(key, nodeT(coeffT(cdata.vk,targs),false)); // Zero leaf
2405  }
2406  else { // Interior node
2407  result->coeffs.replace(key, nodeT(coeffT(),true));
2408  vresult.push_back(result);
2409  vright.push_back(right);
2410  vrc.push_back(rc);
2411  }
2412  }
2413 
2414  if (vresult.size()) {
2415  Tensor<L> lss;
2416  if (lc.size()) {
2417  Tensor<L> ld(cdata.v2k);
2418  ld(cdata.s0) = lc(___);
2419  lss = left->unfilter(ld);
2420  }
2421 
2422  std::vector< Tensor<R> > vrss(vresult.size());
2423  for (unsigned int i=0; i<vresult.size(); ++i) {
2424  if (vrc[i].size()) {
2425  Tensor<R> rd(cdata.v2k);
2426  rd(cdata.s0) = vrc[i](___);
2427  vrss[i] = vright[i]->unfilter(rd);
2428  }
2429  }
2430 
2431  for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
2432  const keyT& child = kit.key();
2433  Tensor<L> ll;
2434 
2435  std::vector<Slice> cp = child_patch(child);
2436 
2437  if (lc.size())
2438  ll = copy(lss(cp));
2439 
2440  std::vector< Tensor<R> > vv(vresult.size());
2441  for (unsigned int i=0; i<vresult.size(); ++i) {
2442  if (vrc[i].size())
2443  vv[i] = copy(vrss[i](cp));
2444  }
2445 
2446  woT::task(coeffs.owner(child), &implT:: template mulXXveca<L,R>, child, left, ll, vright, vv, vresult, tol);
2447  }
2448  }
2449  return None;
2450  }
2451 
2452  // Multiplication using recursive descent and assuming same distribution
2453  template <typename L, typename R>
2454  Void mulXXa(const keyT& key,
2455  const FunctionImpl<L,NDIM>* left, const Tensor<L>& lcin,
2456  const FunctionImpl<R,NDIM>* right,const Tensor<R>& rcin,
2457  double tol) {
2458  typedef typename FunctionImpl<L,NDIM>::dcT::const_iterator literT;
2459  typedef typename FunctionImpl<R,NDIM>::dcT::const_iterator riterT;
2460 
2461  double lnorm=1e99, rnorm=1e99;
2462 
2463  Tensor<L> lc = lcin;
2464  if (lc.size() == 0) {
2465  literT it = left->coeffs.find(key).get();
2466  MADNESS_ASSERT(it != left->coeffs.end());
2467  lnorm = it->second.get_norm_tree();
2468  if (it->second.has_coeff())
2469  lc = it->second.coeff().full_tensor_copy();
2470  }
2471 
2472  Tensor<R> rc = rcin;
2473  if (rc.size() == 0) {
2474  riterT it = right->coeffs.find(key).get();
2475  MADNESS_ASSERT(it != right->coeffs.end());
2476  rnorm = it->second.get_norm_tree();
2477  if (it->second.has_coeff())
2478  rc = it->second.coeff().full_tensor_copy();
2479  }
2480 
2481  // both nodes are leaf nodes: multiply and return
2482  if (rc.size() && lc.size()) { // Yipee!
2483  do_mul<L,R>(key, lc, std::make_pair(key,rc));
2484  return None;
2485  }
2486 
2487  if (tol) {
2488  if (lc.size())
2489  lnorm = lc.normf(); // Otherwise got from norm tree above
2490  if (rc.size())
2491  rnorm = rc.normf();
2492  if (lnorm*rnorm < truncate_tol(tol, key)) {
2493  coeffs.replace(key, nodeT(coeffT(cdata.vk,targs),false)); // Zero leaf node
2494  return None;
2495  }
2496  }
2497 
2498  // Recur down
2499  coeffs.replace(key, nodeT(coeffT(),true)); // Interior node
2500 
2501  Tensor<L> lss;
2502  if (lc.size()) {
2503  Tensor<L> ld(cdata.v2k);
2504  ld(cdata.s0) = lc(___);
2505  lss = left->unfilter(ld);
2506  }
2507 
2508  Tensor<R> rss;
2509  if (rc.size()) {
2510  Tensor<R> rd(cdata.v2k);
2511  rd(cdata.s0) = rc(___);
2512  rss = right->unfilter(rd);
2513  }
2514 
2515  for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
2516  const keyT& child = kit.key();
2517  Tensor<L> ll;
2518  Tensor<R> rr;
2519  if (lc.size())
2520  ll = copy(lss(child_patch(child)));
2521  if (rc.size())
2522  rr = copy(rss(child_patch(child)));
2523 
2524  woT::task(coeffs.owner(child), &implT:: template mulXXa<L,R>, child, left, ll, right, rr, tol);
2525  }
2526 
2527  return None;
2528  }
2529 
2530 
2531  // Binary operation on values using recursive descent and assuming same distribution
2532  template <typename L, typename R, typename opT>
2533  Void binaryXXa(const keyT& key,
2534  const FunctionImpl<L,NDIM>* left, const Tensor<L>& lcin,
2535  const FunctionImpl<R,NDIM>* right,const Tensor<R>& rcin,
2536  const opT& op) {
2537  typedef typename FunctionImpl<L,NDIM>::dcT::const_iterator literT;
2538  typedef typename FunctionImpl<R,NDIM>::dcT::const_iterator riterT;
2539 
2540  Tensor<L> lc = lcin;
2541  if (lc.size() == 0) {
2542  literT it = left->coeffs.find(key).get();
2543  MADNESS_ASSERT(it != left->coeffs.end());
2544  if (it->second.has_coeff())
2545  lc = it->second.coeff().full_tensor_copy();
2546  }
2547 
2548  Tensor<R> rc = rcin;
2549  if (rc.size() == 0) {
2550  riterT it = right->coeffs.find(key).get();
2551  MADNESS_ASSERT(it != right->coeffs.end());
2552  if (it->second.has_coeff())
2553  rc = it->second.coeff().full_tensor_copy();
2554  }
2555 
2556  if (rc.size() && lc.size()) { // Yipee!
2557  do_binary_op<L,R>(key, lc, std::make_pair(key,rc), op);
2558  return None;
2559  }
2560 
2561  // Recur down
2562  coeffs.replace(key, nodeT(coeffT(),true)); // Interior node
2563 
2564  Tensor<L> lss;
2565  if (lc.size()) {
2566  Tensor<L> ld(cdata.v2k);
2567  ld(cdata.s0) = lc(___);
2568  lss = left->unfilter(ld);
2569  }
2570 
2571  Tensor<R> rss;
2572  if (rc.size()) {
2573  Tensor<R> rd(cdata.v2k);
2574  rd(cdata.s0) = rc(___);
2575  rss = right->unfilter(rd);
2576  }
2577 
2578  for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
2579  const keyT& child = kit.key();
2580  Tensor<L> ll;
2581  Tensor<R> rr;
2582  if (lc.size())
2583  ll = copy(lss(child_patch(child)));
2584  if (rc.size())
2585  rr = copy(rss(child_patch(child)));
2586 
2587  woT::task(coeffs.owner(child), &implT:: template binaryXXa<L,R,opT>, child, left, ll, right, rr, op);
2588  }
2589 
2590  return None;
2591  }
2592 
2593  template <typename Q, typename opT>
2595  typedef typename opT::resultT resultT;
2597  opT op;
2598 
2601  const opT& op)
2602  : impl_func(impl_func), op(op) {}
2603 
2604  Tensor<resultT> operator()(const Key<NDIM>& key, const Tensor<Q>& t) const {
2605  Tensor<Q> invalues = impl_func->coeffs2values(key, t);
2606 
2607  Tensor<resultT> outvalues = op(key, invalues);
2608 
2609  return impl_func->values2coeffs(key, outvalues);
2610  }
2611 
2612  template <typename Archive>
2613  void serialize(Archive& ar) {
2614  ar & impl_func & op;
2615  }
2616  };
2617 
2618  // Multiplication using recursive descent and assuming same distribution
2619  template <typename Q, typename opT>
2620  Void unaryXXa(const keyT& key,
2621  const FunctionImpl<Q,NDIM>* func, const opT& op) {
2622 
2623  // const Tensor<Q>& fc = func->coeffs.find(key).get()->second.full_tensor_copy();
2624  const Tensor<Q> fc = func->coeffs.find(key).get()->second.coeff().full_tensor_copy();
2625 
2626  if (fc.size() == 0) {
2627  // Recur down
2628  coeffs.replace(key, nodeT(coeffT(),true)); // Interior node
2629  for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
2630  const keyT& child = kit.key();
2631  woT::task(coeffs.owner(child), &implT:: template unaryXXa<Q,opT>, child, func, op);
2632  }
2633  }
2634  else {
2635  tensorT t=op(key,fc);
2636  coeffs.replace(key, nodeT(coeffT(t,targs),false)); // Leaf node
2637  }
2638 
2639  return None;
2640  }
2641 
2642  template <typename L, typename R>
2643  void mulXX(const FunctionImpl<L,NDIM>* left, const FunctionImpl<R,NDIM>* right, double tol, bool fence) {
2644  if (world.rank() == coeffs.owner(cdata.key0))
2645  mulXXa(cdata.key0, left, Tensor<L>(), right, Tensor<R>(), tol);
2646  if (fence)
2647  world.gop.fence();
2648 
2649  //verify_tree();
2650  }
2651 
2652  template <typename L, typename R, typename opT>
2653  void binaryXX(const FunctionImpl<L,NDIM>* left, const FunctionImpl<R,NDIM>* right,
2654  const opT& op, bool fence) {
2655  if (world.rank() == coeffs.owner(cdata.key0))
2656  binaryXXa(cdata.key0, left, Tensor<L>(), right, Tensor<R>(), op);
2657  if (fence)
2658  world.gop.fence();
2659 
2660  //verify_tree();
2661  }
2662 
2663  template <typename Q, typename opT>
2664  void unaryXX(const FunctionImpl<Q,NDIM>* func, const opT& op, bool fence) {
2665  if (world.rank() == coeffs.owner(cdata.key0))
2666  unaryXXa(cdata.key0, func, op);
2667  if (fence)
2668  world.gop.fence();
2669 
2670  //verify_tree();
2671  }
2672 
2673  template <typename Q, typename opT>
2674  void unaryXXvalues(const FunctionImpl<Q,NDIM>* func, const opT& op, bool fence) {
2675  if (world.rank() == coeffs.owner(cdata.key0))
2676  unaryXXa(cdata.key0, func, coeff_value_adaptor<Q,opT>(func,op));
2677  if (fence)
2678  world.gop.fence();
2679 
2680  //verify_tree();
2681  }
2682 
2683  template <typename L, typename R>
2684  void mulXXvec(const FunctionImpl<L,NDIM>* left,
2685  const std::vector<const FunctionImpl<R,NDIM>*>& vright,
2686  const std::vector<FunctionImpl<T,NDIM>*>& vresult,
2687  double tol,
2688  bool fence) {
2689  std::vector< Tensor<R> > vr(vright.size());
2690  if (world.rank() == coeffs.owner(cdata.key0))
2691  mulXXveca(cdata.key0, left, Tensor<L>(), vright, vr, vresult, tol);
2692  if (fence)
2693  world.gop.fence();
2694  }
2695 
2696  Future<double> get_norm_tree_recursive(const keyT& key) const;
2697 
2698  mutable long box_leaf[1000];
2699  mutable long box_interior[1000];
2700 
2701  // horrifically non-scalable
2702  Void put_in_box(ProcessID from, long nl, long ni) const;
2703 
2705  void print_info() const;
2706 
2708 
2714  void verify_tree() const;
2715 
2717 
2733  Void sock_it_to_me(const keyT& key,
2734  const RemoteReference< FutureImpl< std::pair<keyT,coeffT> > >& ref) const;
2737  Void sock_it_to_me_too(const keyT& key,
2738  const RemoteReference< FutureImpl< std::pair<keyT,coeffT> > >& ref) const;
2739 
2740  Void plot_cube_kernel(archive::archive_ptr< Tensor<T> > ptr,
2741  const keyT& key,
2742  const coordT& plotlo, const coordT& plothi, const std::vector<long>& npt,
2743  bool eval_refine) const;
2744 
2745 
2747 
2749  Tensor<T> eval_plot_cube(const coordT& plotlo,
2750  const coordT& plothi,
2751  const std::vector<long>& npt,
2752  const bool eval_refine = false) const;
2753 
2754 
2756 
2759  std::pair<bool,T> eval_local_only(const Vector<double,NDIM>& xin, Level maxlevel) ;
2760 
2761 
2763 
2767  Void eval(const Vector<double,NDIM>& xin,
2768  const keyT& keyin,
2769  const typename Future<T>::remote_refT& ref);
2770 
2772 
2779  const keyT& keyin,
2780  const typename Future<Level>::remote_refT& ref);
2781 
2783 
2789  Void evalR(const Vector<double,NDIM>& xin,
2790  const keyT& keyin,
2791  const typename Future<long>::remote_refT& ref);
2792 
2793 
2795 
2806  void tnorm(const tensorT& t, double* lo, double* hi) const;
2807 
2808  // This invoked if node has not been autorefined
2809  Void do_square_inplace(const keyT& key);
2810 
2811  // This invoked if node has been autorefined
2812  Void do_square_inplace2(const keyT& parent, const keyT& child, const tensorT& parent_coeff);
2813 
2815  bool noautorefine(const keyT& key, const tensorT& t) const;
2816 
2818  bool autorefine_square_test(const keyT& key, const nodeT& t) const;
2819 
2821 
2824  void square_inplace(bool fence);
2825  void abs_inplace(bool fence);
2826  void abs_square_inplace(bool fence);
2827 
2829  Void sum_down_spawn(const keyT& key, const coeffT& s);
2830 
2832  void sum_down(bool fence);
2833 
2835  template<size_t LDIM>
2836  struct multiply_op {
2837 
2838  static bool randomize() {return false;}
2842 
2843  implT* h;
2844  ctT f;
2845  ctL g;
2846  int particle;
2847 
2848  multiply_op() : particle(1) {}
2849 
2850  multiply_op(implT* h, const ctT& f, const ctL& g, const int particle)
2851  : h(h), f(f), g(g), particle(particle) {};
2852 
2854 
2856  bool screen(const coeffT& fcoeff, const coeffT& gcoeff, const keyT& key) const {
2857  double glo=0.0, ghi=0.0, flo=0.0, fhi=0.0;
2858  MADNESS_ASSERT(gcoeff.tensor_type()==TT_FULL);
2859  g.get_impl()->tnorm(gcoeff.full_tensor(), &glo, &ghi);
2860 
2861  // this assumes intimate knowledge of how a GenTensor is organized!
2862  MADNESS_ASSERT(fcoeff.tensor_type()==TT_2D);
2863  const long rank=fcoeff.rank();
2864  const long maxk=fcoeff.dim(0);
2865  tensorT vec=fcoeff.config().ref_vector(particle-1).reshape(rank,maxk,maxk,maxk);
2866  for (long i=0; i<rank; ++i) {
2867  double lo,hi;
2868  tensorT c=vec(Slice(i,i),_,_,_).reshape(maxk,maxk,maxk);
2869  g.get_impl()->tnorm(c, &lo, &hi); // note we use g instead of h, since g is 3D
2870  flo+=lo*fcoeff.config().weights(i);
2871  fhi+=hi*fcoeff.config().weights(i);
2872  }
2873  double total_hi=glo*fhi + ghi*flo + fhi*ghi;
2874  return (total_hi<h->truncate_tol(h->get_thresh(),key));
2875 
2876  }
2877 
2879 
2882  std::pair<bool,coeffT> operator()(const Key<NDIM>& key) const {
2883 
2884  // bool is_leaf=(not fdatum.second.has_children());
2885  // if (not is_leaf) return std::pair<bool,coeffT> (is_leaf,coeffT());
2886 
2887  // break key into particles (these are the child keys, with f/gdatum come the parent keys)
2888  Key<LDIM> key1,key2;
2889  key.break_apart(key1,key2);
2890  const Key<LDIM> gkey= (particle==1) ? key1 : key2;
2891 
2892  // get coefficients of the actual FunctionNode
2893  coeffT coeff1=f.get_impl()->parent_to_child(f.coeff(),f.key(),key);
2894  coeff1.normalize();
2895  const coeffT coeff2=g.get_impl()->parent_to_child(g.coeff(),g.key(),gkey);
2896 
2897  coeffT hcoeff;
2898 
2899  bool is_leaf=screen(coeff1,coeff2,key);
2900  if (key.level()<2) is_leaf=false;
2901 
2902  if (is_leaf) {
2903 
2904  // convert coefficients to values
2905  coeffT hvalues=f.get_impl()->coeffs2values(key,coeff1);
2906  coeffT gvalues=g.get_impl()->coeffs2values(gkey,coeff2);
2907 
2908  // multiply one of the two vectors of f with g
2909  // note shallow copy of Tensor<T>
2910  MADNESS_ASSERT(hvalues.tensor_type()==TT_2D);
2911  MADNESS_ASSERT(gvalues.tensor_type()==TT_FULL);
2912  const long rank=hvalues.rank();
2913  const long maxk=h->get_k();
2914  MADNESS_ASSERT(maxk==coeff1.dim(0));
2915  tensorT vec=hvalues.config().ref_vector(particle-1).reshape(rank,maxk,maxk,maxk);
2916  for (long i=0; i<rank; ++i) {
2917  tensorT c=vec(Slice(i,i),_,_,_);
2918  c.emul(gvalues.full_tensor());
2919  }
2920 
2921  // convert values back to coefficients
2922  hcoeff=h->values2coeffs(key,hvalues);
2923  }
2924 
2925  return std::pair<bool,coeffT> (is_leaf,hcoeff);
2926  }
2927 
2928  this_type make_child(const keyT& child) const {
2929 
2930  // break key into particles
2931  Key<LDIM> key1, key2;
2932  child.break_apart(key1,key2);
2933  const Key<LDIM> gkey= (particle==1) ? key1 : key2;
2934 
2935  return this_type(h,f.make_child(child),g.make_child(gkey),particle);
2936  }
2937 
2939  Future<ctT> f1=f.activate();
2940  Future<ctL> g1=g.activate();
2941  return h->world.taskq.add(*const_cast<this_type *> (this),
2942  &this_type::forward_ctor,h,f1,g1,particle);
2943  }
2944 
2945  this_type forward_ctor(implT* h1, const ctT& f1, const ctL& g1, const int particle) {
2946  return this_type(h1,f1,g1,particle);
2947  }
2948 
2949  template <typename Archive> void serialize(const Archive& ar) {
2950  ar & h & f & g;
2951  }
2952  };
2953 
2954 
2956  struct add_op {
2957 
2960 
2961  bool randomize() const {return false;}
2962 
2964  ctT f,g;
2966  double alpha, beta;
2967 
2968  add_op() {};
2969  add_op(const ctT& f, const ctT& g, const double alpha, const double beta)
2970  : f(f), g(g), alpha(alpha), beta(beta){}
2971 
2973  std::pair<bool,coeffT> operator()(const keyT& key) const {
2974 
2975  bool is_leaf=(f.is_leaf() and g.is_leaf());
2976  if (not is_leaf) return std::pair<bool,coeffT> (is_leaf,coeffT());
2977 
2978  coeffT fcoeff=f.get_impl()->parent_to_child(f.coeff(),f.key(),key);
2979  coeffT gcoeff=g.get_impl()->parent_to_child(g.coeff(),g.key(),key);
2980  coeffT hcoeff=copy(fcoeff);
2981  hcoeff.gaxpy(alpha,gcoeff,beta);
2982  hcoeff.reduce_rank(f.get_impl()->get_tensor_args().thresh);
2983  return std::pair<bool,coeffT> (is_leaf,hcoeff);
2984  }
2985 
2986  this_type make_child(const keyT& child) const {
2987  return this_type(f.make_child(child),g.make_child(child),alpha,beta);
2988  }
2989 
2992  Future<ctT> f1=f.activate();
2993  Future<ctT> g1=g.activate();
2994  return f.get_impl()->world.taskq.add(*const_cast<this_type *> (this),
2995  &this_type::forward_ctor,f1,g1,alpha,beta);
2996  }
2997 
2999  this_type forward_ctor(const ctT& f1, const ctT& g1, const double alpha, const double beta) {
3000  return this_type(f1,g1,alpha,beta);
3001  }
3002 
3003  template <typename Archive> void serialize(const Archive& ar) {
3004  ar & f & g & alpha & beta;
3005  }
3006 
3007  };
3008 
3010 
3017  template<size_t LDIM>
3018  Void multiply(const implT* f, const FunctionImpl<T,LDIM>* g, const int particle) {
3019 
3020  keyT key0=f->cdata.key0;
3021 
3022  if (world.rank() == coeffs.owner(key0)) {
3023 
3024  CoeffTracker<T,NDIM> ff(f);
3025  CoeffTracker<T,LDIM> gg(g);
3026 
3027  typedef multiply_op<LDIM> coeff_opT;
3028  coeff_opT coeff_op(this,ff,gg,particle);
3029 
3030  typedef insert_op<T,NDIM> apply_opT;
3031  apply_opT apply_op(this);
3032 
3033  ProcessID p= coeffs.owner(key0);
3034  woT::task(p, &implT:: template forward_traverse<coeff_opT,apply_opT>, coeff_op, apply_op, key0);
3035  }
3036 
3037  this->compressed=false;
3038  return None;
3039 
3040  }
3041 
3043  template<size_t LDIM, typename leaf_opT>
3044  struct hartree_op {
3045  bool randomize() const {return false;}
3046 
3049 
3050  implT* result;
3051  ctL p1, p2;
3052  leaf_opT leaf_op;
3053 
3054  // ctor
3056  hartree_op(implT* result, const ctL& p11, const ctL& p22, const leaf_opT& leaf_op)
3057  : result(result), p1(p11), p2(p22), leaf_op(leaf_op) {
3058  MADNESS_ASSERT(LDIM+LDIM==NDIM);
3059  }
3060 
3061  std::pair<bool,coeffT> operator()(const Key<NDIM>& key) const {
3062 
3063  // break key into particles (these are the child keys, with datum1/2 come the parent keys)
3064  Key<LDIM> key1,key2;
3065  key.break_apart(key1,key2);
3066 
3067  // this returns the appropriate NS coeffs for key1 and key2 resp.
3068  const coeffT fcoeff=p1.coeff(key1);
3069  const coeffT gcoeff=p2.coeff(key2);
3070  bool is_leaf=leaf_op(key,fcoeff.full_tensor(),gcoeff.full_tensor());
3071  if (not is_leaf) return std::pair<bool,coeffT> (is_leaf,coeffT());
3072 
3073  // extract the sum coeffs from the NS coeffs
3074  const coeffT s1=fcoeff(p1.get_impl()->cdata.s0);
3075  const coeffT s2=gcoeff(p2.get_impl()->cdata.s0);
3076 
3077  // new coeffs are simply the hartree/kronecker/outer product --
3078  coeffT coeff=outer(s1,s2);
3079  change_tensor_type(coeff,result->get_tensor_args());
3080  // no post-determination
3081  // is_leaf=leaf_op(key,coeff);
3082  return std::pair<bool,coeffT>(is_leaf,coeff);
3083  }
3084 
3085  this_type make_child(const keyT& child) const {
3086 
3087  // break key into particles
3088  Key<LDIM> key1, key2;
3089  child.break_apart(key1,key2);
3090 
3091  return this_type(result,p1.make_child(key1),p2.make_child(key2),leaf_op);
3092  }
3093 
3095  Future<ctL> p11=p1.activate();
3096  Future<ctL> p22=p2.activate();
3097  return result->world.taskq.add(*const_cast<this_type *> (this),
3098  &this_type::forward_ctor,result,p11,p22,leaf_op);
3099  }
3100 
3101  this_type forward_ctor(implT* result1, const ctL& p11, const ctL& p22, const leaf_opT& leaf_op) {
3102  return this_type(result1,p11,p22,leaf_op);
3103  }
3104 
3105  template <typename Archive> void serialize(const Archive& ar) {
3106  ar & result & p1 & p2 & leaf_op;
3107  }
3108  };
3109 
3111 
3117  template<typename coeff_opT, typename apply_opT>
3118  Void forward_traverse(const coeff_opT& coeff_op, const apply_opT& apply_op, const keyT& key) const {
3119  MADNESS_ASSERT(coeffs.is_local(key));
3120  Future<coeff_opT> active_coeff=coeff_op.activate();
3121  woT::task(world.rank(), &implT:: template traverse_tree<coeff_opT,apply_opT>, active_coeff, apply_op, key);
3122  return None;
3123  }
3124 
3125 
3127 
3133  template<typename coeff_opT, typename apply_opT>
3134  Void traverse_tree(const coeff_opT& coeff_op, const apply_opT& apply_op, const keyT& key) const {
3135  MADNESS_ASSERT(coeffs.is_local(key));
3136 
3137  typedef typename std::pair<bool,coeffT> argT;
3138  const argT arg=coeff_op(key);
3139  apply_op.operator()(key,arg.second,arg.first);
3140 
3141  const bool has_children=(not arg.first);
3142  if (has_children) {
3143  for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
3144  const keyT& child=kit.key();
3145  coeff_opT child_op=coeff_op.make_child(child);
3146  // spawn activation where child is local
3147  ProcessID p=coeffs.owner(child);
3148 
3149  madness::Void (implT::*ft)(const coeff_opT&, const apply_opT&, const keyT&) const = &implT::forward_traverse<coeff_opT,apply_opT>;
3150 
3151  woT::task(p, ft, child_op, apply_op, child);
3152  }
3153  }
3154  return None;
3155  }
3156 
3157 
3159 
3164  template<std::size_t LDIM, typename leaf_opT>
3166  const leaf_opT& leaf_op, bool fence) {
3167  MADNESS_ASSERT(p1->is_nonstandard());
3168  MADNESS_ASSERT(p2->is_nonstandard());
3169 
3170  const keyT key0=cdata.key0;
3171 
3172  if (world.rank() == this->get_coeffs().owner(key0)) {
3173 
3174  // prepare the CoeffTracker
3175  CoeffTracker<T,LDIM> iap1(p1);
3176  CoeffTracker<T,LDIM> iap2(p2);
3177 
3178  // the operator making the coefficients
3179  typedef hartree_op<LDIM,leaf_opT> coeff_opT;
3180  coeff_opT coeff_op(this,iap1,iap2,leaf_op);
3181 
3182  // this operator simply inserts the coeffs into this' tree
3183  typedef insert_op<T,NDIM> apply_opT;
3184  apply_opT apply_op(this);
3185 
3186  woT::task(world.rank(), &implT:: template forward_traverse<coeff_opT,apply_opT>,
3187  coeff_op, apply_op, cdata.key0);
3188 
3189  }
3190 
3191  this->compressed=false;
3192  if (fence) world.gop.fence();
3193  return None;
3194  }
3195 
3196 
3197  template <typename opT, typename R>
3198  Void
3199  apply_1d_realspace_push_op(const archive::archive_ptr<const opT>& pop, int axis, const keyT& key, const Tensor<R>& c) {
3200  const opT* op = pop.ptr;
3201  const Level n = key.level();
3202  const double cnorm = c.normf();
3203  const double tol = truncate_tol(thresh, key)*0.1; // ??? why this value????
3204 
3206  const Translation lold = lnew[axis];
3207  const Translation maxs = Translation(1)<<n;
3208 
3209  int nsmall = 0; // Counts neglected blocks to terminate s loop
3210  for (Translation s=0; s<maxs; ++s) {
3211  int maxdir = s ? 1 : -1;
3212  for (int direction=-1; direction<=maxdir; direction+=2) {
3213  lnew[axis] = lold + direction*s;
3214  if (lnew[axis] >= 0 && lnew[axis] < maxs) { // NON-ZERO BOUNDARY CONDITIONS IGNORED HERE !!!!!!!!!!!!!!!!!!!!
3215  const Tensor<typename opT::opT>& r = op->rnlij(n, s*direction, true);
3216  double Rnorm = r.normf();
3217 
3218  if (Rnorm == 0.0) {
3219  return None; // Hard zero means finished!
3220  }
3221 
3222  if (s <= 1 || r.normf()*cnorm > tol) { // Always do kernel and neighbor
3223  nsmall = 0;
3224  tensorT result = transform_dir(c,r,axis);
3225 
3226  if (result.normf() > tol*0.3) {
3227  Key<NDIM> dest(n,lnew);
3228  coeffs.task(dest, &nodeT::accumulate2, result, coeffs, dest, TaskAttributes::hipri());
3229  }
3230  }
3231  else {
3232  ++nsmall;
3233  }
3234  }
3235  else {
3236  ++nsmall;
3237  }
3238  }
3239  if (nsmall >= 4) {
3240  // If have two negligble blocks in
3241  // succession in each direction interpret
3242  // this as the operator being zero beyond
3243  break;
3244  }
3245  }
3246  return None;
3247  }
3248 
3249  template <typename opT, typename R>
3250  void
3251  apply_1d_realspace_push(const opT& op, const FunctionImpl<R,NDIM>* f, int axis, bool fence) {
3253 
3254  typedef typename FunctionImpl<R,NDIM>::dcT::const_iterator fiterT;
3255  typedef FunctionNode<R,NDIM> fnodeT;
3256  fiterT end = f->coeffs.end();
3257  ProcessID me = world.rank();
3258  for (fiterT it=f->coeffs.begin(); it!=end; ++it) {
3259  const fnodeT& node = it->second;
3260  if (node.has_coeff()) {
3261  const keyT& key = it->first;
3262  const Tensor<R>& c = node.coeff().full_tensor_copy();
3263  woT::task(me, &implT:: template apply_1d_realspace_push_op<opT,R>,
3264  archive::archive_ptr<const opT>(&op), axis, key, c);
3265  }
3266  }
3267  if (fence) world.gop.fence();
3268  }
3269 
3271  const implT* f,
3272  const keyT& key,
3273  const std::pair<keyT,coeffT>& left,
3274  const std::pair<keyT,coeffT>& center,
3275  const std::pair<keyT,coeffT>& right);
3276 
3278  const implT* f,
3279  const keyT& key,
3280  const std::pair<keyT,coeffT>& left,
3281  const std::pair<keyT,coeffT>& center,
3282  const std::pair<keyT,coeffT>& right);
3283 
3284  // Called by result function to differentiate f
3285  void diff(const DerivativeBase<T,NDIM>* D, const implT* f, bool fence);
3286 
3288 
3292  keyT neighbor(const keyT& key, const keyT& disp, const std::vector<bool>& is_periodic) const;
3293 
3295  Future< std::pair<keyT,coeffT> > find_me(const keyT& key) const;
3296 
3298  std::pair<Key<NDIM>,ShallowNode<T,NDIM> > find_datum(keyT key) const;
3299 
3301 
3306  coeffT multiply(const coeffT& val_ket, const coeffT& val_pot, int particle) const;
3307 
3308 
3310 
3320  coeffT assemble_coefficients(const keyT& key, const coeffT& coeff_ket,
3321  const coeffT& vpotential1, const coeffT& vpotential2,
3322  const tensorT& veri) const;
3323 
3325 
3330  template<typename opT, size_t LDIM>
3331  struct Vphi_op_NS {
3332 
3333  bool randomize() const {return true;}
3334 
3338 
3339  implT* result;
3340  opT leaf_op;
3341  ctT iaket;
3342  ctL iap1, iap2;
3343  ctL iav1, iav2;
3344  const implT* eri;
3345 
3346  // ctor
3348  Vphi_op_NS(implT* result, const opT& leaf_op, const ctT& iaket,
3349  const ctL& iap1, const ctL& iap2, const ctL& iav1, const ctL& iav2,
3350  const implT* eri)
3351  : result(result), leaf_op(leaf_op), iaket(iaket), iap1(iap1), iap2(iap2)
3352  , iav1(iav1), iav2(iav2), eri(eri) {
3353 
3354  // 2-particle potential must be on-demand
3355  if (eri) MADNESS_ASSERT(eri->is_on_demand());
3356  }
3357 
3359  std::pair<bool,coeffT> operator()(const Key<NDIM>& key) const {
3360 
3361  // use an error measure to determine if a box is a leaf
3362  const bool do_error_measure=leaf_op.do_error_leaf_op();
3363 
3364  // pre-determination: insert empty node and continue recursion on all children
3365  bool is_leaf=leaf_op(key);
3366  if (not is_leaf) {
3367  result->get_coeffs().replace(key,nodeT(coeffT(),not is_leaf));
3368  return continue_recursion(std::vector<bool>(1<<NDIM,false),tensorT(),key);
3369  }
3370 
3371  // make the sum coeffs for this box (the parent box)
3372  coeffT sum_coeff=make_sum_coeffs(key);
3373 
3374  // post-determination: insert s-coeffs and stop recursion
3375  is_leaf=leaf_op(key,sum_coeff);
3376  if (is_leaf) {
3377  result->get_coeffs().replace(key,nodeT(sum_coeff,not is_leaf));
3378  return std::pair<bool,coeffT> (true,coeffT());
3379  }
3380 
3381  if (do_error_measure) {
3382  // make the sum coeffs for all children, accumulated on s_coeffs
3383  tensorT s_coeffs=make_childrens_sum_coeffs(key);
3384 
3385  // now check if sum coeffs are leaves according to the d coefficient norm
3386  tensorT d=result->filter(s_coeffs);
3387  sum_coeff=coeffT(copy(d(result->get_cdata().s0)),result->get_tensor_args());
3388 
3389  d(result->get_cdata().s0)=0.0;
3390  double error=d.normf();
3391  is_leaf=(error<result->truncate_tol(result->get_thresh(),key));
3392 
3393  // if this is a leaf insert sum coeffs and stop recursion
3394  if (is_leaf) {
3395  result->get_coeffs().replace(key,nodeT(sum_coeff,not is_leaf));
3396  result->large++;
3397  // print("is leaf acc to d coeffs",key);
3398  return std::pair<bool,coeffT> (true,coeffT());
3399  } else {
3400 
3401  // determine for each child if it is a leaf by comparing to the sum coeffs
3402  std::vector<bool> child_is_leaf(1<<NDIM);
3403  std::size_t i=0;
3404  for (KeyChildIterator<NDIM> kit(key); kit; ++kit, ++i) {
3405  // post-determination for this child's coeffs
3406  coeffT child_coeff=coeffT(copy(s_coeffs(result->child_patch(kit.key()))),
3407  result->get_tensor_args());
3408  child_is_leaf[i]=leaf_op(kit.key(),child_coeff);
3409 
3410  // compare to parent sum coeffs
3411  error_leaf_op<T,NDIM> elop(result);
3412  child_is_leaf[i]=child_is_leaf[i] or elop(kit.key(),child_coeff,sum_coeff);
3413  if (child_is_leaf[i]) result->small++;
3414  // else result->large++;
3415  }
3416  // insert empty sum coeffs for this box and
3417  // send off the tasks for those children that might not be leaves;
3418  result->get_coeffs().replace(key,nodeT(coeffT(),not is_leaf));
3419  if (not is_leaf) return continue_recursion(child_is_leaf,s_coeffs,key);
3420  }
3421  } else {
3422  return continue_recursion(std::vector<bool>(1<<NDIM,false),tensorT(),key);
3423  }
3424  MADNESS_EXCEPTION("you should not be here",1);
3425  return std::pair<bool,coeffT> (true,coeffT());
3426  }
3427 
3428 
3430 
3435  std::pair<bool,coeffT> continue_recursion(const std::vector<bool> child_is_leaf,
3436  const tensorT& coeffs, const keyT& key) const {
3437  std::size_t i=0;
3438  for (KeyChildIterator<NDIM> kit(key); kit; ++kit, ++i) {
3439  keyT child=kit.key();
3440  bool is_leaf=child_is_leaf[i];
3441 
3442  if (is_leaf) {
3443  // insert the sum coeffs
3444  insert_op<T,NDIM> iop(result);
3445  iop(child,coeffT(copy(coeffs(result->child_patch(child))),result->get_tensor_args()),is_leaf);
3446  } else {
3447  this_type child_op=this->make_child(child);
3448  noop<T,NDIM> no;
3449  // spawn activation where child is local
3450  ProcessID p=result->get_coeffs().owner(child);
3451 
3452  madness::Void (implT::*ft)(const Vphi_op_NS<opT,LDIM>&, const noop<T,NDIM>&, const keyT&) const = &implT:: template forward_traverse< Vphi_op_NS<opT,LDIM>, noop<T,NDIM> >;
3453  result->task(p, ft, child_op, no, child);
3454  }
3455  }
3456  // return e sum coeffs; also return always is_leaf=true:
3457  // the recursion is continued within this struct, not outside in traverse_tree!
3458  return std::pair<bool,coeffT> (true,coeffT());
3459  }
3460 
3462 
3465  tensorT eri_values(const keyT& key) const {
3466  tensorT val_eri;
3467  if (eri and eri->is_on_demand()) {
3468  if (eri->get_functor()->provides_coeff()) {
3469  val_eri=eri->coeffs2values(
3470  key,eri->get_functor()->coeff(key).full_tensor());
3471  } else {
3472  val_eri=tensorT(eri->cdata.vk);
3473  eri->fcube(key,*(eri->get_functor()),eri->cdata.quad_x,val_eri);
3474  }
3475  }
3476  return val_eri;
3477  }
3478 
3480  coeffT make_sum_coeffs(const keyT& key) const {
3481  // break key into particles
3482  Key<LDIM> key1, key2;
3483  key.break_apart(key1,key2);
3484 
3485  // use the ket coeffs if they are there, or make them by hartree product
3486  const coeffT coeff_ket_NS = (iaket.get_impl())
3487  ? iaket.coeff(key)
3488  : outer(iap1.coeff(key1),iap2.coeff(key2));
3489 
3490  coeffT val_potential1, val_potential2;
3491  if (iav1.get_impl()) {
3492  coeffT tmp=iav1.coeff(key1)(iav1.get_impl()->get_cdata().s0);
3493  val_potential1=iav1.get_impl()->coeffs2values(key1,tmp);
3494  }
3495  if (iav2.get_impl()) {
3496  coeffT tmp=iav2.coeff(key2)(iav2.get_impl()->get_cdata().s0);
3497  val_potential2=iav2.get_impl()->coeffs2values(key2,tmp);
3498  }
3499  coeffT tmp=coeff_ket_NS(result->get_cdata().s0);
3500 
3501  return result->assemble_coefficients(key,tmp,
3502  val_potential1,val_potential2,eri_values(key));
3503  }
3504 
3506  tensorT make_childrens_sum_coeffs(const keyT& key) const {
3507  // break key into particles
3508  Key<LDIM> key1, key2;
3509  key.break_apart(key1,key2);
3510 
3511  // use the ket coeffs if they are there, or make them by hartree product
3512  const coeffT coeff_ket_NS = (iaket.get_impl())
3513  ? iaket.coeff(key)
3514  : outer(iap1.coeff(key1),iap2.coeff(key2));
3515 
3516  // get the sum coeffs for all children
3517  const coeffT coeff_ket_unfiltered=result->unfilter(coeff_ket_NS);
3518  const coeffT coeff_v1_unfiltered=(iav1.get_impl())
3519  ? iav1.get_impl()->unfilter(iav1.coeff(key1)) : coeffT();
3520  const coeffT coeff_v2_unfiltered=(iav2.get_impl())
3521  ? iav2.get_impl()->unfilter(iav2.coeff(key2)) : coeffT();
3522 
3523  // result sum coeffs of all children
3524  tensorT s_coeffs(result->cdata.v2k);
3525  for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
3526 
3527  // break key into particles
3528  Key<LDIM> child1, child2;
3529  kit.key().break_apart(child1,child2);
3530 
3531  // make the values of the potentials for each child
3532  // transform the child patch of s coeffs to values
3533  coeffT val_potential1, val_potential2;
3534  if (iav1.get_impl()) {
3535  coeffT tmp=coeff_v1_unfiltered(iav1.get_impl()->child_patch(child1));
3536  val_potential1=iav1.get_impl()->coeffs2values(child1,tmp);
3537  }
3538  if (iav2.get_impl()) {
3539  coeffT tmp=coeff_v2_unfiltered(iav2.get_impl()->child_patch(child2));
3540  val_potential2=iav2.get_impl()->coeffs2values(child2,tmp);
3541  }
3542  const coeffT coeff_ket=coeff_ket_unfiltered(result->child_patch(kit.key()));
3543 
3544  // the sum coeffs for this child
3545  const tensorT val_eri=eri_values(kit.key());
3546  const coeffT coeff_result=result->assemble_coefficients(kit.key(),coeff_ket,
3547  val_potential1,val_potential2,val_eri);
3548 
3549  // accumulate the sum coeffs of the children here
3550  s_coeffs(result->child_patch(kit.key()))+=coeff_result.full_tensor_copy();
3551  }
3552  return s_coeffs;
3553 
3554  }
3555 
3556  this_type make_child(const keyT& child) const {
3557 
3558  // break key into particles
3559  Key<LDIM> key1, key2;
3560  child.break_apart(key1,key2);
3561 
3562  return this_type(result,leaf_op,iaket.make_child(child),
3563  iap1.make_child(key1),iap2.make_child(key2),
3564  iav1.make_child(key1),iav2.make_child(key2),eri);
3565  }
3566 
3568  Future<ctT> iaket1=iaket.activate();
3569  Future<ctL> iap11=iap1.activate();
3570  Future<ctL> iap21=iap2.activate();
3571  Future<ctL> iav11=iav1.activate();
3572  Future<ctL> iav21=iav2.activate();
3573  return result->world.taskq.add(*const_cast<this_type *> (this),
3574  &this_type::forward_ctor,result,leaf_op,
3575  iaket1,iap11,iap21,iav11,iav21,eri);
3576  }
3577 
3578  this_type forward_ctor(implT* result1, const opT& leaf_op, const ctT& iaket1,
3579  const ctL& iap11, const ctL& iap21, const ctL& iav11, const ctL& iav21,
3580  const implT* eri1) {
3581  return this_type(result1,leaf_op,iaket1,iap11,iap21,iav11,iav21,eri1);
3582  }
3583 
3585  template <typename Archive> void serialize(const Archive& ar) {
3586  ar & iaket & eri & result & leaf_op & iap1 & iap2 & iav1 & iav2;
3587  }
3588  };
3589 
3591 
3597  template<typename opT>
3598  void make_Vphi(const opT& leaf_op, const bool fence=true) {
3599 
3600  const size_t LDIM=3;
3601 
3602  // keep the functor available, but remove it from the result
3603  // result will return false upon is_on_demand(), which is necessary for the
3604  // CoeffTracker to track the parent coeffs correctly for error_leaf_op
3606  this->unset_functor();
3607 
3609  dynamic_cast<CompositeFunctorInterface<T,NDIM,LDIM>* >(&(*func2));
3610  MADNESS_ASSERT(func);
3611 
3612  coeffs.clear();
3613  const keyT& key0=cdata.key0;
3614 
3615 
3616  FunctionImpl<T,NDIM>* ket=func->impl_ket.get();
3617  const FunctionImpl<T,NDIM>* eri=func->impl_eri.get();
3618  FunctionImpl<T,LDIM>* v1=func->impl_m1.get();
3619  FunctionImpl<T,LDIM>* v2=func->impl_m2.get();
3620  FunctionImpl<T,LDIM>* p1=func->impl_p1.get();
3621  FunctionImpl<T,LDIM>* p2=func->impl_p2.get();
3622 
3623  if (ket) ket->undo_redundant(false);
3624  if (v1) v1->undo_redundant(false);
3625  if (v2) v2->undo_redundant(false);
3626  if (p1) p1->undo_redundant(false);
3627  if (p2) p2->undo_redundant(false); // fence here
3628  world.gop.fence();
3629 
3630  if (ket) ket->compress(true,true,false,false);
3631  if (v1) v1->compress(true,true,false,false);
3632  if (v2) v2->compress(true,true,false,false);
3633  if (p1) p1->compress(true,true,false,false);
3634  if (p2) p2->compress(true,true,false,false); // fence here
3635  world.gop.fence();
3636  small=0;
3637  large=0;
3638 
3639  if (world.rank() == coeffs.owner(key0)) {
3640 
3641  // insert an empty internal node for comparison
3642  this->coeffs.replace(key0,nodeT(coeffT(),true));
3643 
3644  // prepare the CoeffTracker
3645  CoeffTracker<T,NDIM> iaket(ket);
3646  CoeffTracker<T,LDIM> iap1(p1);
3647  CoeffTracker<T,LDIM> iap2(p2);
3648  CoeffTracker<T,LDIM> iav1(v1);
3649  CoeffTracker<T,LDIM> iav2(v2);
3650 
3651  // the operator making the coefficients
3652  typedef Vphi_op_NS<opT,LDIM> coeff_opT;
3653  coeff_opT coeff_op(this,leaf_op,iaket,iap1,iap2,iav1,iav2,eri);
3654 
3655  // this operator simply inserts the coeffs into this' tree
3656  typedef noop<T,NDIM> apply_opT;
3657  apply_opT apply_op;
3658 
3659  woT::task(world.rank(), &implT:: template forward_traverse<coeff_opT,apply_opT>,
3660  coeff_op, apply_op, cdata.key0);
3661  }
3662 
3663  world.gop.fence();
3664 
3665  // remove internal coefficients
3666  this->redundant=true;
3667  this->undo_redundant(false);
3668 
3669  // set right state
3670  this->compressed=false;
3671  this->on_demand=false;
3672  this->redundant=false;
3673  this->nonstandard=false;
3674  if (fence) world.gop.fence();
3675 
3676  }
3677 
3678 
3680  void mapdim(const implT& f, const std::vector<long>& map, bool fence);
3681 
3682 
3684 
3686  void average(const implT& rhs);
3687 
3689 
3691  void change_tensor_type1(const TensorArgs& targs, bool fence);
3692 
3694 
3696  void reduce_rank(const TensorArgs& targs, bool fence);
3697 
3698  T eval_cube(Level n, coordT& x, const tensorT& c) const;
3699 
3701 
3708  // \endcode
3713  tensorT filter(const tensorT& s) const;
3714 
3715  coeffT filter(const coeffT& s) const;
3716 
3718 
3732  tensorT unfilter(const tensorT& s) const;
3733 
3734  coeffT unfilter(const coeffT& s) const;
3735 
3737 
3743  tensorT downsample(const keyT& key, const std::vector< Future<coeffT > >& v) const;
3744 
3746 
3752  coeffT upsample(const keyT& key, const coeffT& coeff) const;
3753 
3755  void project(const implT& old, bool fence);
3756 
3758  bool operator()(const implT* f, const keyT& key, const nodeT& t) const {
3759  return true;
3760  }
3761  template <typename Archive> void serialize(Archive& ar) {}
3762  };
3763 
3764  template <typename opT>
3765  Void refine_op(const opT& op, const keyT& key) {
3766  // Must allow for someone already having autorefined the coeffs
3767  // and we get a write accessor just in case they are already executing
3768  typename dcT::accessor acc;
3769  MADNESS_ASSERT(coeffs.find(acc,key));
3770  nodeT& node = acc->second;
3771  if (node.has_coeff() && key.level() < max_refine_level && op(this, key, node)) {
3772  coeffT d(cdata.v2k,targs);
3773  d(cdata.s0) += copy(node.coeff());
3774  d = unfilter(d);
3775  node.clear_coeff();
3776  node.set_has_children(true);
3777  for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
3778  const keyT& child = kit.key();
3779  coeffT ss = copy(d(child_patch(child)));
3780  ss.reduce_rank(targs.thresh);
3781  // coeffs.replace(child,nodeT(ss,-1.0,false).node_to_low_rank());
3782  coeffs.replace(child,nodeT(ss,-1.0,false));
3783  // Note value -1.0 for norm tree to indicate result of refinement
3784  }
3785  }
3786  return None;
3787  }
3788 
3789  template <typename opT>
3790  Void refine_spawn(const opT& op, const keyT& key) {
3791  nodeT& node = coeffs.find(key).get()->second;
3792  if (node.has_children()) {
3793  for (KeyChildIterator<NDIM> kit(key); kit; ++kit)
3794  woT::task(coeffs.owner(kit.key()), &implT:: template refine_spawn<opT>, op, kit.key(), TaskAttributes::hipri());
3795  }
3796  else {
3797  woT::task(coeffs.owner(key), &implT:: template refine_op<opT>, op, key);
3798  }
3799  return None;
3800  }
3801 
3802  // Refine in real space according to local user-defined criterion
3803  template <typename opT>
3804  void refine(const opT& op, bool fence) {
3805  if (world.rank() == coeffs.owner(cdata.key0))
3806  woT::task(coeffs.owner(cdata.key0), &implT:: template refine_spawn<opT>, op, cdata.key0, TaskAttributes::hipri());
3807  if (fence)
3808  world.gop.fence();
3809  }
3810 
3811  bool exists_and_has_children(const keyT& key) const;
3812 
3813  bool exists_and_is_leaf(const keyT& key) const;
3814 
3815 
3816  Void broaden_op(const keyT& key, const std::vector< Future <bool> >& v);
3817 
3818  // For each local node sets value of norm tree to 0.0
3819  void zero_norm_tree();
3820 
3821  // Broaden tree
3822  void broaden(std::vector<bool> is_periodic, bool fence);
3823 
3825  void trickle_down(bool fence);
3826 
3828 
3830  Void trickle_down_op(const keyT& key, const coeffT& s);
3831 
3832  void reconstruct(bool fence);
3833 
3834  // Invoked on node where key is local
3835  // Void reconstruct_op(const keyT& key, const tensorT& s);
3836  Void reconstruct_op(const keyT& key, const coeffT& s);
3837 
3839 
3845  void compress(bool nonstandard, bool keepleaves, bool redundant, bool fence);
3846 
3847  // Invoked on node where key is local
3848  Future<coeffT > compress_spawn(const keyT& key, bool nonstandard, bool keepleaves, bool redundant);
3849 
3851  void make_redundant(const bool fence);
3852 
3854  void undo_redundant(const bool fence);
3855 
3856 
3858  void norm_tree(bool fence);
3859 
3860  double norm_tree_op(const keyT& key, const std::vector< Future<double> >& v);
3861 
3862  Future<double> norm_tree_spawn(const keyT& key);
3863 
3865 
3867  Future<coeffT> truncate_reconstructed_spawn(const keyT& key, const double tol);
3868 
3870 
3872  coeffT truncate_reconstructed_op(const keyT& key, const std::vector< Future<coeffT > >& v, const double tol);
3873 
3875 
3881  coeffT compress_op(const keyT& key, const std::vector< Future<coeffT > >& v, bool nonstandard, bool redundant);
3882 
3883 
3885 
3889  coeffT make_redundant_op(const keyT& key, const std::vector< Future<coeffT > >& v);
3890 
3892  void standard(bool fence);
3893 
3895  struct do_standard {
3897 
3898  // threshold for rank reduction / SVD truncation
3899  implT* impl;
3900 
3901  // constructor takes target precision
3903  do_standard(implT* impl) : impl(impl) {}
3904 
3905  //
3906  bool operator()(typename rangeT::iterator& it) const {
3907 
3908  const keyT& key = it->first;
3909  nodeT& node = it->second;
3910  if (key.level()> 0 && node.has_coeff()) {
3911  if (node.has_children()) {
3912  // Zero out scaling coeffs
3913  node.coeff()(impl->cdata.s0)=0.0;
3914  node.reduceRank(impl->targs.thresh);
3915  } else {
3916  // Deleting both scaling and wavelet coeffs
3917  node.clear_coeff();
3918  }
3919  }
3920  return true;
3921  }
3922  template <typename Archive> void serialize(const Archive& ar) {
3923  MADNESS_EXCEPTION("no serialization of do_standard",1);
3924  }
3925  };
3926 
3927 
3929  template<size_t OPDIM>
3930  struct do_op_args {
3932  keyT dest;
3933  double tol, fac, cnorm;
3935  do_op_args(const Key<OPDIM>& key, const Key<OPDIM>& d, const keyT& dest, double tol, double fac, double cnorm)
3936  : key(key), d(d), dest(dest), tol(tol), fac(fac), cnorm(cnorm) {}
3937  template <class Archive>
3938  void serialize(Archive& ar) {
3939  ar & archive::wrap_opaque(this,1);
3940  }
3941  };
3942 
3944 
3949  template <typename opT, typename R, size_t OPDIM>
3950  Void do_apply_kernel(const opT* op, const Tensor<R>& c, const do_op_args<OPDIM>& args) {
3951 
3952  tensorT result = op->apply(args.key, args.d, c, args.tol/args.fac/args.cnorm);
3953 
3954  // Screen here to reduce communication cost of negligible data
3955  // and also to ensure we don't needlessly widen the tree when
3956  // applying the operator
3957  if (result.normf()> 0.3*args.tol/args.fac) {
3958  // OPTIMIZATION NEEDED HERE ... CHANGING THIS TO TASK NOT SEND REMOVED
3959  // BUILTIN OPTIMIZATION TO SHORTCIRCUIT MSG IF DATA IS LOCAL
3960  Future<double> time=coeffs.task(args.dest, &nodeT::accumulate2, result, coeffs, args.dest, TaskAttributes::hipri());
3962  // //
3963  // // UGLY BUT ADDED THE OPTIMIZATION BACK IN HERE EXPLICITLY/
3964  // if (args.dest == world.rank()) {
3965  // coeffs.send(args.dest, &nodeT::accumulate, result, coeffs, args.dest);
3966  // }
3967  // else {
3968  // coeffs.task(args.dest, &nodeT::accumulate, result, coeffs, args.dest, TaskAttributes::hipri());
3969  // }
3970  }
3971 
3972  return None;
3973  }
3974 
3976 
3982  template <typename opT, typename R, size_t OPDIM>
3983  double do_apply_kernel2(const opT* op, const Tensor<R>& c, const do_op_args<OPDIM>& args,
3984  const TensorArgs& apply_targs) {
3985 
3986  tensorT result_full = op->apply(args.key, args.d, c, args.tol/args.fac/args.cnorm);
3987  const double norm=result_full.normf();
3988 
3989  // Screen here to reduce communication cost of negligible data
3990  // and also to ensure we don't needlessly widen the tree when
3991  // applying the operator
3992  // OPTIMIZATION NEEDED HERE ... CHANGING THIS TO TASK NOT SEND REMOVED
3993  // BUILTIN OPTIMIZATION TO SHORTCIRCUIT MSG IF DATA IS LOCAL
3994  if (norm > 0.3*args.tol/args.fac) {
3995 
3996  small++;
3997  double cpu0=cpu_time();
3998  coeffT result=coeffT(result_full,apply_targs);
3999  MADNESS_ASSERT(result.tensor_type()==TT_FULL or result.tensor_type()==TT_2D);
4000  double cpu1=cpu_time();
4001  timer_lr_result.accumulate(cpu1-cpu0);
4002 
4003  Future<double> time=coeffs.task(args.dest, &nodeT::accumulate, result, coeffs, args.dest, apply_targs,
4006  }
4007  return norm;
4008  }
4009 
4010 
4011 
4013 
4019  template <typename opT, typename R, size_t OPDIM>
4020  double do_apply_kernel3(const opT* op, const GenTensor<R>& coeff, const do_op_args<OPDIM>& args,
4021  const TensorArgs& apply_targs) {
4022 
4023  coeffT result;
4024  if (2*OPDIM==NDIM) result= op->apply2_lowdim(args.key, args.d, coeff, args.tol/args.fac/args.cnorm, args.tol/args.fac);
4025  if (OPDIM==NDIM) result = op->apply2(args.key, args.d, coeff, args.tol/args.fac/args.cnorm, args.tol/args.fac);
4026  // double result_norm=-1.0;
4027  // if (result.tensor_type()==TT_2D) result_norm=result.config().svd_normf();
4028  // if (result.tensor_type()==TT_FULL) result_norm=result.normf();
4029  // MADNESS_ASSERT(result_norm>-0.5);
4030 
4031  const double result_norm=result.svd_normf();
4032 
4033  if (result_norm> 0.3*args.tol/args.fac) {
4034  small++;
4035 
4036  // accumulate also expects result in SVD form
4037  Future<double> time=coeffs.task(args.dest, &nodeT::accumulate, result, coeffs, args.dest, apply_targs,
4040 
4041  }
4042  return result_norm;
4043 
4044  }
4045 
4047 
4053  template <typename opT, typename R>
4054  Void do_apply(const opT* op, const keyT& key, const Tensor<R>& c) {
4056 
4057  typedef typename opT::keyT opkeyT;
4058  static const size_t opdim=opT::opdim;
4059 
4060  const opkeyT source=op->get_source_key(key);
4061 
4062  // insert timer here
4063  double fac = 10.0; //3.0; // 10.0 seems good for qmprop ... 3.0 OK for others
4064  double cnorm = c.normf();
4065  //const long lmax = 1L << (key.level()-1);
4066 
4067  const std::vector<opkeyT>& disp = op->get_disp(key.level());
4068 
4069  // use to have static in front, but this is not thread-safe
4070  const std::vector<bool> is_periodic(NDIM,false); // Periodic sum is already done when making rnlp
4071 
4072  for (typename std::vector<opkeyT>::const_iterator it=disp.begin(); it != disp.end(); ++it) {
4073  // const opkeyT& d = *it;
4074 
4075  keyT d;
4076  Key<NDIM-opdim> nullkey(key.level());
4077  if (op->particle()==1) d=it->merge_with(nullkey);
4078  if (op->particle()==2) d=nullkey.merge_with(*it);
4079 
4080  keyT dest = neighbor(key, d, is_periodic);
4081 
4082  if (dest.is_valid()) {
4083  double opnorm = op->norm(key.level(), *it, source);
4084  // working assumption here is that the operator is isotropic and
4085  // montonically decreasing with distance
4086  double tol = truncate_tol(thresh, key);
4087 
4088  //print("APP", key, dest, cnorm, opnorm, (cnorm*opnorm> tol/fac));
4089 
4090  if (cnorm*opnorm> tol/fac) {
4091 
4092  // Most expensive part is the kernel ... do it in a separate task
4093  if (d.distsq()==0) {
4094  // This introduces finer grain parallelism
4095  ProcessID where = world.rank();
4096  do_op_args<opdim> args(source, *it, dest, tol, fac, cnorm);
4097  woT::task(where, &implT:: template do_apply_kernel<opT,R,opdim>, op, c, args);
4098  } else {
4099  tensorT result = op->apply(source,*it, c, tol/fac/cnorm);
4100  if (result.normf()> 0.3*tol/fac) {
4101  coeffs.task(dest, &nodeT::accumulate2, result, coeffs, dest, TaskAttributes::hipri());
4102  }
4103  }
4104  } else if (d.distsq() >= 1)
4105  break; // Assumes monotonic decay beyond nearest neighbor
4106  }
4107  }
4108  return None;
4109  }
4110 
4111 
4113  template <typename opT, typename R>
4114  void apply(opT& op, const FunctionImpl<R,NDIM>& f, bool fence) {
4116  MADNESS_ASSERT(!op.modified());
4117  typename dcT::const_iterator end = f.coeffs.end();
4118  for (typename dcT::const_iterator it=f.coeffs.begin(); it!=end; ++it) {
4119  // looping through all the coefficients in the source
4120  const keyT& key = it->first;
4121  const FunctionNode<R,NDIM>& node = it->second;
4122  if (node.has_coeff()) {
4123  if (node.coeff().dim(0) != k || op.doleaves) {
4125  woT::task(p, &implT:: template do_apply<opT,R>, &op, key, node.coeff().full_tensor_copy());
4126  }
4127  }
4128  }
4129  if (fence)
4130  world.gop.fence();
4131 
4132  this->compressed=true;
4133  this->nonstandard=true;
4134  this->redundant=false;
4135 
4136  }
4137 
4139 
4146  template <typename opT, typename R>
4147  double do_apply_directed_screening(const opT* op, const keyT& key, const coeffT& coeff,
4148  const bool& do_kernel) {
4150  // insert timer here
4151  typedef typename opT::keyT opkeyT;
4152 
4153  // screening: contains all displacement keys that had small result norms
4154  std::list<opkeyT> blacklist;
4155 
4156  static const size_t opdim=opT::opdim;
4157  Key<NDIM-opdim> nullkey(key.level());
4158 
4159  // source is that part of key that corresponds to those dimensions being processed
4160  const opkeyT source=op->get_source_key(key);
4161 
4162  const double tol = truncate_tol(thresh, key);
4163 
4164  // fac is the root of the number of contributing neighbors (1st shell)
4165  double fac=std::pow(3,NDIM*0.5);
4166  double cnorm = coeff.normf();
4167 
4168  // for accumulation: keep slightly tighter TensorArgs
4169  TensorArgs apply_targs(targs);
4170  apply_targs.thresh=tol/fac*0.03;
4171 
4172  double maxnorm=0.0;
4173  // for the kernel it may be more efficient to do the convolution in full rank
4174  tensorT coeff_full;
4175 
4176  const std::vector<opkeyT>& disp = op->get_disp(key.level());
4177  const std::vector<bool> is_periodic(NDIM,false); // Periodic sum is already done when making rnlp
4178 
4179  for (typename std::vector<opkeyT>::const_iterator it=disp.begin(); it != disp.end(); ++it) {
4180  const opkeyT& d = *it;
4181 
4182  const int shell=d.distsq();
4183  if (do_kernel and (shell>0)) break;
4184  if ((not do_kernel) and (shell==0)) continue;
4185 
4186  keyT disp1;
4187  if (op->particle()==1) disp1=it->merge_with(nullkey);
4188  else if (op->particle()==2) disp1=nullkey.merge_with(*it);
4189  else {
4190  MADNESS_EXCEPTION("confused particle in operato??",1);
4191  }
4192 
4193  keyT dest = neighbor(key, disp1, is_periodic);
4194 
4195  if (not dest.is_valid()) continue;
4196 
4197  // directed screening
4198  // working assumption here is that the operator is isotropic and
4199  // monotonically decreasing with distance
4200  bool screened=false;
4201  typename std::list<opkeyT>::const_iterator it2;
4202  for (it2=blacklist.begin(); it2!=blacklist.end(); it2++) {
4203  if (d.is_farther_out_than(*it2)) {
4204  screened=true;
4205  break;
4206  }
4207  }
4208  if (not screened) {
4209 
4210  double opnorm = op->norm(key.level(), d, source);
4211  double norm=0.0;
4212 
4213  if (cnorm*opnorm> tol/fac) {
4214 
4215  double cost_ratio=op->estimate_costs(source, d, coeff, tol/fac/cnorm, tol/fac);
4216  // cost_ratio=1.5; // force low rank
4217  // cost_ratio=0.5; // force full rank
4218 
4219  if (cost_ratio>0.0) {
4220 
4221  do_op_args<opdim> args(source, d, dest, tol, fac, cnorm);
4222  norm=0.0;
4223  if (cost_ratio<1.0) {
4224  if (not coeff_full.has_data()) coeff_full=coeff.full_tensor_copy();
4225  norm=do_apply_kernel2(op, coeff_full,args,apply_targs);
4226  } else {
4227  norm=do_apply_kernel3(op,coeff,args,apply_targs);
4228  }
4229  maxnorm=std::max(norm,maxnorm);
4230  }
4231 
4232  } else if (shell >= 12) {
4233  break; // Assumes monotonic decay beyond nearest neighbor
4234  }
4235  if (norm<0.3*tol/fac) blacklist.push_back(d);
4236  }
4237  }
4238  return maxnorm;
4239  }
4240 
4241 
4243  template <typename opT, typename R>
4244  void apply_source_driven(opT& op, const FunctionImpl<R,NDIM>& f, bool fence) {
4246 
4247  MADNESS_ASSERT(not op.modified());
4248  // looping through all the coefficients of the source f
4249  typename dcT::const_iterator end = f.get_coeffs().end();
4250  for (typename dcT::const_iterator it=f.get_coeffs().begin(); it!=end; ++it) {
4251 
4252  const keyT& key = it->first;
4253  const coeffT& coeff = it->second.coeff();
4254 
4255  if (coeff.has_data() and (coeff.rank()!=0)) {
4257  woT::task(p, &implT:: template do_apply_directed_screening<opT,R>, &op, key, coeff, true);
4258  woT::task(p, &implT:: template do_apply_directed_screening<opT,R>, &op, key, coeff, false);
4259  }
4260  }
4261  if (fence) world.gop.fence();
4262  }
4263 
4265  double finalize_apply(const bool fence=true);
4266 
4268 
4276  template<typename opT, std::size_t LDIM>
4277  void recursive_apply(opT& apply_op, const FunctionImpl<T,LDIM>* fimpl,
4278  const FunctionImpl<T,LDIM>* gimpl, const bool fence) {
4279 
4280  const keyT& key0=cdata.key0;
4281 
4282  if (world.rank() == coeffs.owner(key0)) {
4283 
4284  CoeffTracker<T,LDIM> ff(fimpl);
4285  CoeffTracker<T,LDIM> gg(gimpl);
4286 
4287  typedef recursive_apply_op<opT,LDIM> coeff_opT;
4288  coeff_opT coeff_op(this,ff,gg,&apply_op);
4289 
4290  typedef noop<T,NDIM> apply_opT;
4291  apply_opT apply_op;
4292 
4293  ProcessID p= coeffs.owner(key0);
4294  woT::task(p, &implT:: template forward_traverse<coeff_opT,apply_opT>, coeff_op, apply_op, key0);
4295 
4296  }
4297  if (fence) world.gop.fence();
4298  }
4299 
4301  template<typename opT, std::size_t LDIM>
4303  bool randomize() const {return true;}
4304 
4306 
4307  implT* result;
4310  opT* apply_op;
4311 
4312  // ctor
4314  recursive_apply_op(implT* result,
4315  const CoeffTracker<T,LDIM>& iaf, const CoeffTracker<T,LDIM>& iag,
4316  const opT* apply_op) : result(result), iaf(iaf), iag(iag), apply_op(apply_op)
4317  {
4318  MADNESS_ASSERT(LDIM+LDIM==NDIM);
4319  }
4320  recursive_apply_op(const recursive_apply_op& other) : result(other.result), iaf(other.iaf),
4321  iag(other.iag), apply_op(other.apply_op) {}
4322 
4323 
4325 
4327  std::pair<bool,coeffT> operator()(const Key<NDIM>& key) const {
4328 
4329  // World& world=result->world;
4330  // break key into particles (these are the child keys, with datum1/2 come the parent keys)
4331  Key<LDIM> key1,key2;
4332  key.break_apart(key1,key2);
4333 
4334  // the lo-dim functions should be in full tensor form
4335  const tensorT fcoeff=iaf.coeff(key1).full_tensor();
4336  const tensorT gcoeff=iag.coeff(key2).full_tensor();
4337 
4338  // would this be a leaf node? If so, then its sum coeffs have already been
4339  // processed by the parent node's wavelet coeffs. Therefore we won't
4340  // process it any more.
4341  hartree_leaf_op<T,NDIM> leaf_op(result,result->get_k());
4342  bool is_leaf=leaf_op(key,fcoeff,gcoeff);
4343 
4344  if (not is_leaf) {
4345  // new coeffs are simply the hartree/kronecker/outer product --
4346  const std::vector<Slice>& s0=iaf.get_impl()->cdata.s0;
4347  const coeffT coeff = (apply_op->modified())
4348  ? outer_low_rank(copy(fcoeff(s0)),copy(gcoeff(s0)))
4349  : outer_low_rank(fcoeff,gcoeff);
4350 
4351  // now send off the application
4352  tensorT coeff_full;
4353  ProcessID p=result->world.rank();
4354  double norm0=result->do_apply_directed_screening<opT,T>(apply_op, key, coeff, true);
4355 
4356  result->task(p,&implT:: template do_apply_directed_screening<opT,T>,
4357  apply_op,key,coeff,false);
4358 
4359  return finalize(norm0,key,coeff);
4360 
4361  } else {
4362  return std::pair<bool,coeffT> (is_leaf,coeffT());
4363  }
4364  }
4365 
4367  std::pair<bool,coeffT> finalize(const double kernel_norm, const keyT& key,
4368  const coeffT& coeff) const {
4369  const double thresh=result->get_thresh()*0.1;
4370  bool is_leaf=(kernel_norm<result->truncate_tol(thresh,key));
4371  if (key.level()<2) is_leaf=false;
4372  return std::pair<bool,coeffT> (is_leaf,coeff);
4373  }
4374 
4375 
4376  this_type make_child(const keyT& child) const {
4377 
4378  // break key into particles
4379  Key<LDIM> key1, key2;
4380  child.break_apart(key1,key2);
4381 
4382  return this_type(result,iaf.make_child(key1),iag.make_child(key2),apply_op);
4383  }
4384 
4388  return result->world.taskq.add(*const_cast<this_type *> (this),
4389  &this_type::forward_ctor,result,f1,g1,apply_op);
4390  }
4391 
4392  this_type forward_ctor(implT* r, const CoeffTracker<T,LDIM>& f1, const CoeffTracker<T,LDIM>& g1,
4393  const opT* apply_op1) {
4394  return this_type(r,f1,g1,apply_op1);
4395  }
4396 
4397  template <typename Archive> void serialize(const Archive& ar) {
4398  ar & result & iaf & iag & apply_op;
4399  }
4400  };
4401 
4403 
4408  template<typename opT>
4409  void recursive_apply(opT& apply_op, const implT* fimpl, implT* rimpl, const bool fence) {
4410 
4411  const keyT& key0=cdata.key0;
4412 
4413  if (world.rank() == coeffs.owner(key0)) {
4414 
4415  typedef recursive_apply_op2<opT> coeff_opT;
4416  coeff_opT coeff_op(this,fimpl,&apply_op);
4417 
4418  typedef noop<T,NDIM> apply_opT;
4419  apply_opT apply_op;
4420 
4421  woT::task(world.rank(), &implT:: template forward_traverse<coeff_opT,apply_opT>,
4422  coeff_op, apply_op, cdata.key0);
4423 
4424  }
4425  if (fence) world.gop.fence();
4426  }
4427 
4429  template<typename opT>
4431  bool randomize() const {return true;}
4432 
4435  typedef std::pair<bool,coeffT> argT;
4436 
4437  mutable implT* result;
4438  ctT iaf;
4439  const opT* apply_op;
4440 
4441  // ctor
4443  recursive_apply_op2(implT* result, const ctT& iaf, const opT* apply_op)
4444  : result(result), iaf(iaf), apply_op(apply_op) {}
4445 
4446  recursive_apply_op2(const recursive_apply_op2& other) : result(other.result),
4447  iaf(other.iaf), apply_op(other.apply_op) {}
4448 
4449 
4451 
4455  argT operator()(const Key<NDIM>& key) const {
4456 
4457  const coeffT& coeff=iaf.coeff();
4458 
4459  if (coeff.has_data()) {
4460 
4461  // now send off the application for all neighbor boxes
4462  ProcessID p=result->world.rank();
4463  result->task(p,&implT:: template do_apply_directed_screening<opT,T>,
4464  apply_op, key, coeff, false);
4465 
4466  // process the core box
4467  double norm0=result->do_apply_directed_screening<opT,T>(apply_op,key,coeff,true);
4468 
4469  if (iaf.is_leaf()) return argT(true,coeff);
4470  return finalize(norm0,key,coeff,result);
4471 
4472  } else {
4473  const bool is_leaf=true;
4474  return argT(is_leaf,coeffT());
4475  }
4476  }
4477 
4479  argT finalize(const double kernel_norm, const keyT& key,
4480  const coeffT& coeff, const implT* r) const {
4481  const double thresh=r->get_thresh()*0.1;
4482  bool is_leaf=(kernel_norm<r->truncate_tol(thresh,key));
4483  if (key.level()<2) is_leaf=false;
4484  return argT(is_leaf,coeff);
4485  }
4486 
4487 
4488  this_type make_child(const keyT& child) const {
4489  return this_type(result,iaf.make_child(child),apply_op);
4490  }
4491 
4494  Future<ctT> f1=iaf.activate();
4495  return result->world.taskq.add(*const_cast<this_type *> (this),
4496  &this_type::forward_ctor,result,f1,apply_op);
4497  }
4498 
4500  this_type forward_ctor(implT* result1, const ctT& iaf1, const opT* apply_op1) {
4501  return this_type(result1,iaf1,apply_op1);
4502  }
4503 
4504  template <typename Archive> void serialize(const Archive& ar) {
4505  ar & result & iaf & apply_op;
4506  }
4507  };
4508 
4510 
4513  template <typename opT>
4514  double err_box(const keyT& key, const nodeT& node, const opT& func,
4515  int npt, const Tensor<double>& qx, const Tensor<double>& quad_phit,
4516  const Tensor<double>& quad_phiw) const {
4517 
4518  std::vector<long> vq(NDIM);
4519  for (std::size_t i=0; i<NDIM; ++i)
4520  vq[i] = npt;
4521  tensorT fval(vq,false), work(vq,false), result(vq,false);
4522 
4523  // Compute the "exact" function in this volume at npt points
4524  // where npt is usually this->npt+1.
4525  fcube(key, func, qx, fval);
4526 
4527  // Transform into the scaling function basis of order npt
4528  double scale = pow(0.5,0.5*NDIM*key.level())*sqrt(FunctionDefaults<NDIM>::get_cell_volume());
4529  fval = fast_transform(fval,quad_phiw,result,work).scale(scale);
4530 
4531  // Subtract to get the error ... the original coeffs are in the order k
4532  // basis but we just computed the coeffs in the order npt(=k+1) basis
4533  // so we can either use slices or an iterator macro.
4534  const tensorT coeff = node.coeff().full_tensor_copy();
4535  ITERATOR(coeff,fval(IND)-=coeff(IND););
4536  // flo note: we do want to keep a full tensor here!
4537 
4538  // Compute the norm of what remains
4539  double err = fval.normf();
4540  return err*err;
4541  }
4542 
4543  template <typename opT>
4544  class do_err_box {
4545  const implT* impl;
4546  const opT* func;
4547  int npt;
4548  Tensor<double> qx;
4549  Tensor<double> quad_phit;
4550  Tensor<double> quad_phiw;
4551  public:
4553 
4554  do_err_box(const implT* impl, const opT* func, int npt, const Tensor<double>& qx,
4555  const Tensor<double>& quad_phit, const Tensor<double>& quad_phiw)
4556  : impl(impl), func(func), npt(npt), qx(qx), quad_phit(quad_phit), quad_phiw(quad_phiw) {}
4557 
4559  : impl(e.impl), func(e.func), npt(e.npt), qx(e.qx), quad_phit(e.quad_phit), quad_phiw(e.quad_phiw) {}
4560 
4561  double operator()(typename dcT::const_iterator& it) const {
4562  const keyT& key = it->first;
4563  const nodeT& node = it->second;
4564  if (node.has_coeff())
4565  return impl->err_box(key, node, *func, npt, qx, quad_phit, quad_phiw);
4566  else
4567  return 0.0;
4568  }
4569 
4570  double operator()(double a, double b) const {
4571  return a+b;
4572  }
4573 
4574  template <typename Archive>
4575  void serialize(const Archive& ar) {
4576  throw "not yet";
4577  }
4578  };
4579 
4581  template <typename opT>
4582  double errsq_local(const opT& func) const {
4584  // Make quadrature rule of higher order
4585  const int npt = cdata.npt + 1;
4586  Tensor<double> qx, qw, quad_phi, quad_phiw, quad_phit;
4587  FunctionCommonData<T,NDIM>::_init_quadrature(k+1, npt, qx, qw, quad_phi, quad_phiw, quad_phit);
4588 
4590  rangeT range(coeffs.begin(), coeffs.end());
4591  return world.taskq.reduce< double,rangeT,do_err_box<opT> >(range,
4592  do_err_box<opT>(this, &func, npt, qx, quad_phit, quad_phiw));
4593  }
4594 
4596  T trace_local() const;
4597 
4599  double operator()(typename dcT::const_iterator& it) const {
4600  const nodeT& node = it->second;
4601  if (node.has_coeff()) {
4602  double norm = node.coeff().normf();
4603  return norm*norm;
4604  }
4605  else {
4606  return 0.0;
4607  }
4608  }
4609 
4610  double operator()(double a, double b) const {
4611  return (a+b);
4612  }
4613 
4614  template <typename Archive> void serialize(const Archive& ar) {
4615  throw "NOT IMPLEMENTED";
4616  }
4617  };
4618 
4619 
4621  double norm2sq_local() const;
4622 
4624  template<typename R>
4628  typedef TENSOR_RESULT_TYPE(T,R) resultT;
4629 
4630  do_inner_local(const FunctionImpl<R,NDIM>* other, const bool leaves_only)
4631  : other(other), leaves_only(leaves_only) {}
4632  resultT operator()(typename dcT::const_iterator& it) const {
4633 
4634  TENSOR_RESULT_TYPE(T,R) sum=0.0;
4635  const keyT& key=it->first;
4636  const nodeT& fnode = it->second;
4637  if (fnode.has_coeff()) {
4638  if (other->coeffs.probe(it->first)) {
4639  const FunctionNode<R,NDIM>& gnode = other->coeffs.find(key).get()->second;
4640  if (gnode.has_coeff()) {
4641  if (gnode.coeff().dim(0) != fnode.coeff().dim(0)) {
4642  madness::print("INNER", it->first, gnode.coeff().dim(0),fnode.coeff().dim(0));
4643  MADNESS_EXCEPTION("functions have different k or compress/reconstruct error", 0);
4644  }
4645  if (leaves_only) {
4646  if (gnode.is_leaf() or fnode.is_leaf()) {
4647  sum += fnode.coeff().trace_conj(gnode.coeff());
4648  }
4649  } else {
4650  sum += fnode.coeff().trace_conj(gnode.coeff());
4651  }
4652  }
4653  }
4654  }
4655  return sum;
4656  }
4657 
4658  resultT operator()(resultT a, resultT b) const {
4659  return (a+b);
4660  }
4661 
4662  template <typename Archive> void serialize(const Archive& ar) {
4663  throw "NOT IMPLEMENTED";
4664  }
4665  };
4666 
4668 
4670  template <typename R>
4671  TENSOR_RESULT_TYPE(T,R) inner_local(const FunctionImpl<R,NDIM>& g) const {
4674  typedef TENSOR_RESULT_TYPE(T,R) resultT;
4675 
4676  // make sure the states of the trees are consistent
4678  bool leaves_only=(this->is_redundant());
4679  return world.taskq.reduce<resultT,rangeT,do_inner_local<R> >
4680  (rangeT(coeffs.begin(),coeffs.end()),do_inner_local<R>(&g, leaves_only));
4681  }
4682 
4688  T inner_ext_node(keyT key, tensorT c, T (*f)(const coordT&)) const {
4689  tensorT fvals = tensorT(this->cdata.vk);
4690  // Compute the value of the external function at the quadrature points.
4691  fvals = madness::fcube(key, f, this->cdata.quad_x);
4692  // Convert quadrature point values to scaling coefficients.
4693  tensorT fc = tensorT(values2coeffs(key, fvals));
4694  // Return the inner product of the two functions' scaling coefficients.
4695  return c.trace_conj(fc);
4696  }
4697 
4703  T inner_ext_node(keyT key, tensorT c, const std::shared_ptr< FunctionFunctorInterface<T,NDIM> > f) const {
4704  tensorT fvals = tensorT(this->cdata.vk);
4705  // Compute the value of the external function at the quadrature points.
4706  fcube(key, *(f), cdata.quad_x, fvals);
4707  // Convert quadrature point values to scaling coefficients.
4708  tensorT fc = tensorT(values2coeffs(key, fvals));
4709  // Return the inner product of the two functions' scaling coefficients.
4710  return c.trace_conj(fc);
4711  }
4712 
4720  T inner_ext_recursive(keyT key, tensorT c, T (*f)(const coordT&), const bool leaf_refine, T old_inner=T(0)) const {
4721  int i = 0;
4722  tensorT c_child, inner_child;
4723  T new_inner, result = 0.0;
4724 
4725  c_child = tensorT(cdata.v2k); // tensor of child coeffs
4726  inner_child = Tensor<double>(pow(2, NDIM)); // child inner products
4727 
4728  // If old_inner is default value, assume this is the first call
4729  // and compute inner product on this node.
4730  if (old_inner == T(0)) {
4731  old_inner = inner_ext_node(key, c, f);
4732  }
4733 
4734  if (coeffs.find(key).get()->second.has_children()) {
4735  // Since the key has children and we know the func is redundant,
4736  // Iterate over all children of this compute node, computing
4737  // the inner product on each child node. new_inner will store
4738  // the sum of these, yielding a more accurate inner product.
4739  for (KeyChildIterator<NDIM> it(key); it; ++it, ++i) {
4740  const keyT& child = it.key();
4741  tensorT cc = coeffs.find(child).get()->second.coeff().full_tensor_copy();
4742  inner_child(i) = inner_ext_node(child, cc, f);
4743  }
4744  new_inner = inner_child.sum();
4745  } else if (leaf_refine) {
4746  // We need the scaling coefficients of the numerical function
4747  // at each of the children nodes. We can't use project because
4748  // there is no guarantee that the numerical function will have
4749  // a functor. Instead, since we know we are at or below the
4750  // leaf nodes, the wavelet coefficients are zero (to within the
4751  // truncate tolerance). Thus, we can use unfilter() to
4752  // get the scaling coefficients at the next level.
4753  tensorT d = tensorT(cdata.v2k);
4754  d = T(0);
4755  d(cdata.s0) = copy(c);
4756  c_child = unfilter(d);
4757 
4758  // Iterate over all children of this compute node, computing
4759  // the inner product on each child node. new_inner will store
4760  // the sum of these, yielding a more accurate inner product.
4761  for (KeyChildIterator<NDIM> it(key); it; ++it, ++i) {
4762  const keyT& child = it.key();
4763  tensorT cc = tensorT(c_child(child_patch(child)));
4764  inner_child(i) = inner_ext_node(child, cc, f);
4765  }
4766  new_inner = inner_child.sum();
4767  } else {
4768  // If we get to here, we are at the leaf nodes and the user has
4769  // specified that they do not want refinement past leaf nodes.
4770  new_inner = old_inner;
4771  }
4772 
4773  // Check for convergence. If converged...yay, we're done. If not,
4774  // call inner_ext_node_recursive on each child node and accumulate
4775  // the inner product in result.
4776  // if (std::abs(new_inner - old_inner) <= truncate_tol(thresh, key)) {
4777  if (std::abs(new_inner - old_inner) <= thresh) {
4778  result = new_inner;
4779  } else {
4780  i = 0;
4781  for (KeyChildIterator<NDIM> it(key); it; ++it, ++i) {
4782  const keyT& child = it.key();
4783  tensorT cc = tensorT(c_child(child_patch(child)));
4784  result += inner_ext_recursive(child, cc, f, leaf_refine, inner_child(i));
4785  }
4786  }
4787 
4788  return result;
4789  }
4790 
4798  T inner_ext_recursive(keyT key, tensorT c, const std::shared_ptr< FunctionFunctorInterface<T,NDIM> > f, const bool leaf_refine, T old_inner=T(0)) const {
4799  int i = 0;
4800  tensorT c_child, inner_child;
4801  T new_inner, result = 0.0;
4802 
4803  c_child = tensorT(cdata.v2k); // tensor of child coeffs
4804  inner_child = Tensor<double>(pow(2, NDIM)); // child inner products
4805 
4806  // If old_inner is default value, assume this is the first call
4807  // and compute inner product on this node.
4808  if (old_inner == T(0)) {
4809  old_inner = inner_ext_node(key, c, f);
4810  }
4811 
4812  if (coeffs.find(key).get()->second.has_children()) {
4813  // Since the key has children and we know the func is redundant,
4814  // Iterate over all children of this compute node, computing
4815  // the inner product on each child node. new_inner will store
4816  // the sum of these, yielding a more accurate inner product.
4817  for (KeyChildIterator<NDIM> it(key); it; ++it, ++i) {
4818  const keyT& child = it.key();
4819  tensorT cc = coeffs.find(child).get()->second.coeff().full_tensor_copy();
4820  inner_child(i) = inner_ext_node(child, cc, f);
4821  }
4822  new_inner = inner_child.sum();
4823  } else if (leaf_refine) {
4824  // We need the scaling coefficients of the numerical function
4825  // at each of the children nodes. We can't use project because
4826  // there is no guarantee that the numerical function will have
4827  // a functor. Instead, since we know we are at or below the
4828  // leaf nodes, the wavelet coefficients are zero (to within the
4829  // truncate tolerance). Thus, we can use unfilter() to
4830  // get the scaling coefficients at the next level.
4831  tensorT d = tensorT(cdata.v2k);
4832  d = T(0);
4833  d(cdata.s0) = copy(c);
4834  c_child = unfilter(d);
4835 
4836  // Iterate over all children of this compute node, computing
4837  // the inner product on each child node. new_inner will store
4838  // the sum of these, yielding a more accurate inner product.
4839  for (KeyChildIterator<NDIM> it(key); it; ++it, ++i) {
4840  const keyT& child = it.key();
4841  tensorT cc = tensorT(c_child(child_patch(child)));
4842  inner_child(i) = inner_ext_node(child, cc, f);
4843  }
4844  new_inner = inner_child.sum();
4845  } else {
4846  // If we get to here, we are at the leaf nodes and the user has
4847  // specified that they do not want refinement past leaf nodes.
4848  new_inner = old_inner;
4849  }
4850 
4851  // Check for convergence. If converged...yay, we're done. If not,
4852  // call inner_ext_node_recursive on each child node and accumulate
4853  // the inner product in result.
4854  // if (std::abs(new_inner - old_inner) <= truncate_tol(thresh, key)) {
4855  if (std::abs(new_inner - old_inner) <= thresh) {
4856  result = new_inner;
4857  } else {
4858  i = 0;
4859  for (KeyChildIterator<NDIM> it(key); it; ++it, ++i) {
4860  const keyT& child = it.key();
4861  tensorT cc = tensorT(c_child(child_patch(child)));
4862  result += inner_ext_recursive(child, cc, f, leaf_refine, inner_child(i));
4863  }
4864  }
4865 
4866  return result;
4867  }
4868 
4870  T (*fptr)(const coordT&);
4871  const implT * impl;
4872  const bool leaf_refine;
4873 
4874  do_inner_ext_local(T (*f)(const coordT&), const implT * impl, const bool leaf_refine) : fptr(f), impl(impl), leaf_refine(leaf_refine) {};
4875 
4876  T operator()(typename dcT::const_iterator& it) const {
4877  /* if (it->second.is_leaf()) { */
4878  if (it->first.level() == impl->initial_level) {
4879  tensorT cc = it->second.coeff().full_tensor_copy();
4880  return impl->inner_ext_recursive(it->first, cc, fptr, leaf_refine, T(0));
4881  } else {
4882  return 0.0;
4883  }
4884  }
4885 
4886  T operator()(T a, T b) const {
4887  return (a + b);
4888  }
4889 
4890  template <typename Archive> void serialize(const Archive& ar) {
4891  throw "NOT IMPLEMENTED";
4892  }
4893  };
4894 
4897  const implT * impl;
4898  const bool leaf_refine;
4899 
4900  do_inner_ext_local_ffi(const std::shared_ptr< FunctionFunctorInterface<T,NDIM> > f, const implT * impl, const bool leaf_refine) : fref(f), impl(impl), leaf_refine(leaf_refine) {};
4901 
4902  T operator()(typename dcT::const_iterator& it) const {
4903  /* if (it->second.is_leaf()) { */
4904  if (it->first.level() == impl->initial_level) {
4905  tensorT cc = it->second.coeff().full_tensor_copy();
4906  return impl->inner_ext_recursive(it->first, cc, fref, leaf_refine, T(0));
4907  } else {
4908  return 0.0;
4909  }
4910  }
4911 
4912  T operator()(T a, T b) const {
4913  return (a + b);
4914  }
4915 
4916  template <typename Archive> void serialize(const Archive& ar) {
4917  throw "NOT IMPLEMENTED";
4918  }
4919  };
4920 
4925  T inner_ext_local(T (*f)(const coordT&), const bool leaf_refine) const {
4927 
4928  return world.taskq.reduce<T, rangeT, do_inner_ext_local>(rangeT(coeffs.begin(),coeffs.end()),
4929  do_inner_ext_local(f, this, leaf_refine));
4930  }
4931 
4936  T inner_ext_local(const std::shared_ptr< FunctionFunctorInterface<T,NDIM> > f, const bool leaf_refine) const {
4938 
4939  return world.taskq.reduce<T, rangeT, do_inner_ext_local_ffi>(rangeT(coeffs.begin(),coeffs.end()),
4940  do_inner_ext_local_ffi(f, this, leaf_refine));
4941  }
4942 
4955  template <typename L>
4956  tensorT gaxpy_ext_node(keyT key, Tensor<L> lc, T (*f)(const coordT&), T alpha, T beta) const {
4957  // Compute the value of external function at the quadrature points.
4958  tensorT fvals = madness::fcube(key, f, cdata.quad_x);
4959  // Convert quadrature point values to scaling coefficients.
4960  tensorT fcoeffs = values2coeffs(key, fvals);
4961  // Return the inner product of the two functions' scaling coeffs.
4962  tensorT c2 = copy(lc);
4963  c2.gaxpy(alpha, fcoeffs, beta);
4964  return c2;
4965  }
4966 
4980  template <typename L>
4981  Void gaxpy_ext_recursive(const keyT& key, const FunctionImpl<L,NDIM>* left,
4982  Tensor<L> lcin, tensorT c, T (*f)(const coordT&),
4983  T alpha, T beta, double tol, bool below_leaf) {
4984  typedef typename FunctionImpl<L,NDIM>::dcT::const_iterator literT;
4985 
4986  // If we haven't yet reached the leaf level, check whether the
4987  // current key is a leaf node of left. If so, set below_leaf to true
4988  // and continue. If not, make this a parent, recur down, return.
4989  if (not below_leaf) {
4990  bool left_leaf = left->coeffs.find(key).get()->second.is_leaf();
4991  if (left_leaf) {
4992  below_leaf = true;
4993  } else {
4994  this->coeffs.replace(key, nodeT(coeffT(), true));
4995  for (KeyChildIterator<NDIM> it(key); it; ++it) {
4996  const keyT& child = it.key();
4997  woT::task(left->coeffs.owner(child), &implT:: template gaxpy_ext_recursive<L>,
4998  child, left, Tensor<L>(), tensorT(), f, alpha, beta, tol, below_leaf);
4999  }
5000  return None;
5001  }
5002  }
5003 
5004  // Compute left's coefficients if not provided
5005  Tensor<L> lc = lcin;
5006  if (lc.size() == 0) {
5007  literT it = left->coeffs.find(key).get();
5008  MADNESS_ASSERT(it != left->coeffs.end());
5009  if (it->second.has_coeff())
5010  lc = it->second.coeff().full_tensor_copy();
5011  }
5012 
5013  // Compute this node's coefficients if not provided in function call
5014  if (c.size() == 0) {
5015  c = gaxpy_ext_node(key, lc, f, alpha, beta);
5016  }
5017 
5018  // We need the scaling coefficients of the numerical function at
5019  // each of the children nodes. We can't use project because there
5020  // is no guarantee that the numerical function will have a functor.
5021  // Instead, since we know we are at or below the leaf nodes, the
5022  // wavelet coefficients are zero (to within the truncate tolerance).
5023  // Thus, we can use unfilter() to get the scaling coefficients at
5024  // the next level.
5025  Tensor<L> lc_child = Tensor<L>(cdata.v2k); // left's child coeffs
5026  Tensor<L> ld = Tensor<L>(cdata.v2k);
5027  ld = L(0);
5028  ld(cdata.s0) = copy(lc);
5029  lc_child = unfilter(ld);
5030 
5031  // Iterate over children of this node,
5032  // storing the gaxpy coeffs in c_child
5033  tensorT c_child = tensorT(cdata.v2k); // tensor of child coeffs
5034  for (KeyChildIterator<NDIM> it(key); it; ++it) {
5035  const keyT& child = it.key();
5036  tensorT lcoeff = tensorT(lc_child(child_patch(child)));
5037  c_child(child_patch(child)) = gaxpy_ext_node(child, lcoeff, f, alpha, beta);
5038  }
5039 
5040  // Compute the difference coefficients to test for convergence.
5041  tensorT d = tensorT(cdata.v2k);
5042  d = filter(c_child);
5043  // Filter returns both s and d coefficients, so set scaling
5044  // coefficient part of d to 0 so that we take only the
5045  // norm of the difference coefficients.
5046  d(cdata.s0) = T(0);
5047  double dnorm = d.normf();
5048 
5049  // Small d.normf means we've reached a good level of resolution
5050  // Store the coefficients and return.
5051  if (dnorm <= truncate_tol(tol,key)) {
5052  this->coeffs.replace(key, nodeT(coeffT(c,targs), false));
5053  } else {
5054  // Otherwise, make this a parent node and recur down
5055  this->coeffs.replace(key, nodeT(coeffT(), true)); // Interior node
5056 
5057  for (KeyChildIterator<NDIM> it(key); it; ++it) {
5058  const keyT& child = it.key();
5059  tensorT child_coeff = tensorT(c_child(child_patch(child)));
5060  tensorT left_coeff = tensorT(lc_child(child_patch(child)));
5061  woT::task(left->coeffs.owner(child), &implT:: template gaxpy_ext_recursive<L>,
5062  child, left, left_coeff, child_coeff, f, alpha, beta, tol, below_leaf);
5063  }
5064  }
5065  return None;
5066  }
5067 
5068  template <typename L>
5069  void gaxpy_ext(const FunctionImpl<L,NDIM>* left, T (*f)(const coordT&), T alpha, T beta, double tol, bool fence) {
5070  if (world.rank() == coeffs.owner(cdata.key0))
5071  gaxpy_ext_recursive<L> (cdata.key0, left, Tensor<L>(), tensorT(), f, alpha, beta, tol, false);
5072  if (fence)
5073  world.gop.fence();
5074  }
5075 
5077 
5083  template<size_t LDIM>
5085  const int dim, const bool fence) {
5086 
5087  const keyT& key0=cdata.key0;
5088 
5089  if (world.rank() == coeffs.owner(key0)) {
5090 
5091  // coeff_op will accumulate the result
5092  typedef project_out_op<LDIM> coeff_opT;
5093  coeff_opT coeff_op(this,result,CoeffTracker<T,LDIM>(gimpl),dim);
5094 
5095  // don't do anything on this -- coeff_op will accumulate into result
5096  typedef noop<T,NDIM> apply_opT;
5097  apply_opT apply_op;
5098 
5099  woT::task(world.rank(), &implT:: template forward_traverse<coeff_opT,apply_opT>,
5100  coeff_op, apply_op, cdata.key0);
5101 
5102  }
5103  if (fence) world.gop.fence();
5104 
5105  }
5106 
5107 
5109  template<size_t LDIM>
5111  bool randomize() const {return false;}
5112 
5115  typedef FunctionImpl<T,NDIM-LDIM> implL1;
5116  typedef std::pair<bool,coeffT> argT;
5117 
5118  const implT* fimpl; //< the hi dim function f
5119  mutable implL1* result; //< the low dim result function
5120  ctL iag; //< the low dim function g
5121  int dim; //< 0: project 0..LDIM-1, 1: project LDIM..NDIM-1
5122 
5123  // ctor
5125  project_out_op(const implT* fimpl, implL1* result, const ctL& iag, const int dim)
5126  : fimpl(fimpl), result(result), iag(iag), dim(dim) {}
5128  : fimpl(other.fimpl), result(other.result), iag(other.iag), dim(other.dim) {}
5129 
5130 
5132  Future<argT> operator()(const Key<NDIM>& key) const {
5133 
5134  Key<LDIM> key1,key2,dest;
5135  key.break_apart(key1,key2);
5136 
5137  // make the right coefficients
5138  coeffT gcoeff;
5139  if (dim==0) {
5140  gcoeff=iag.get_impl()->parent_to_child(iag.coeff(),iag.key(),key1);
5141  dest=key2;
5142  }
5143  if (dim==1) {
5144  gcoeff=iag.get_impl()->parent_to_child(iag.coeff(),iag.key(),key2);
5145  dest=key1;
5146  }
5147 
5148  MADNESS_ASSERT(fimpl->get_coeffs().probe(key)); // must be local!
5149  const nodeT& fnode=fimpl->get_coeffs().find(key).get()->second;
5150  const coeffT& fcoeff=fnode.coeff();
5151 
5152  // fast return if possible
5153  if (fcoeff.has_no_data() or gcoeff.has_no_data())
5154  return Future<argT> (argT(fnode.is_leaf(),coeffT()));;
5155 
5156  // let's specialize for the time being on SVD tensors for f and full tensors of half dim for g
5157  MADNESS_ASSERT(gcoeff.tensor_type()==TT_FULL);
5158  MADNESS_ASSERT(fcoeff.tensor_type()==TT_2D);
5159  const tensorT gtensor=gcoeff.full_tensor();
5160  tensorT final(result->cdata.vk);
5161 
5162  const int otherdim=(dim+1)%2;
5163  const int k=fcoeff.dim(0);
5164  std::vector<Slice> s(fcoeff.config().dim_per_vector()+1,_);
5165 
5166  // do the actual contraction
5167  for (int r=0; r<fcoeff.rank(); ++r) {
5168  s[0]=Slice(r,r);
5169  const tensorT contracted_tensor=fcoeff.config().ref_vector(dim)(s).reshape(k,k,k);
5170  const tensorT other_tensor=fcoeff.config().ref_vector(otherdim)(s).reshape(k,k,k);
5171  const double ovlp= gtensor.trace_conj(contracted_tensor);
5172  const double fac=ovlp * fcoeff.config().weights(r);
5173  final+=fac*other_tensor;
5174  }
5175 
5176  // accumulate the result
5177  result->coeffs.task(dest, &FunctionNode<T,LDIM>::accumulate2, final, result->coeffs, dest, TaskAttributes::hipri());
5178 
5179  return Future<argT> (argT(fnode.is_leaf(),coeffT()));
5180  }
5181 
5182  this_type make_child(const keyT& child) const {
5183  Key<LDIM> key1,key2;
5184  child.break_apart(key1,key2);
5185  const Key<LDIM> gkey = (dim==0) ? key1 : key2;
5186 
5187  return this_type(fimpl,result,iag.make_child(gkey),dim);
5188  }
5189 
5192  Future<ctL> g1=iag.activate();
5193  return result->world.taskq.add(*const_cast<this_type *> (this),
5194  &this_type::forward_ctor,fimpl,result,g1,dim);
5195  }
5196 
5198  this_type forward_ctor(const implT* fimpl1, implL1* result1, const ctL& iag1, const int dim1) {
5199  return this_type(fimpl1,result1,iag1,dim1);
5200  }
5201 
5202  template <typename Archive> void serialize(const Archive& ar) {
5203  ar & result & iag & fimpl & dim;
5204  }
5205 
5206  };
5207 
5208 
5210 
5216  template<size_t LDIM>
5217  void project_out2(const FunctionImpl<T,LDIM+NDIM>* f, const FunctionImpl<T,LDIM>* g, const int dim) {
5218 
5219  typedef std::pair< keyT,coeffT > pairT;
5220  typedef typename FunctionImpl<T,NDIM+LDIM>::dcT::const_iterator fiterator;
5221 
5222  // loop over all nodes of hi-dim f, compute the inner products with all
5223  // appropriate nodes of g, and accumulate in result
5224  fiterator end = f->get_coeffs().end();
5225  for (fiterator it=f->get_coeffs().begin(); it!=end; ++it) {
5226  const Key<LDIM+NDIM> key=it->first;
5227  const FunctionNode<T,LDIM+NDIM> fnode=it->second;
5228  const coeffT& fcoeff=fnode.coeff();
5229 
5230  if (fnode.is_leaf() and fcoeff.has_data()) {
5231 
5232  // break key into particle: over key1 will be summed, over key2 will be
5233  // accumulated, or vice versa, depending on dim
5234  if (dim==0) {
5235  Key<NDIM> key1;
5236  Key<LDIM> key2;
5237  key.break_apart(key1,key2);
5238 
5239  Future<pairT> result;
5240  // sock_it_to_me(key1, result.remote_ref(world));
5241  g->task(coeffs.owner(key1), &implT::sock_it_to_me, key1, result.remote_ref(world), TaskAttributes::hipri());
5242  woT::task(world.rank(),&implT:: template do_project_out<LDIM>,fcoeff,result,key1,key2,dim);
5243 
5244  } else if (dim==1) {
5245  Key<LDIM> key1;
5246  Key<NDIM> key2;
5247  key.break_apart(key1,key2);
5248 
5249  Future<pairT> result;
5250  // sock_it_to_me(key2, result.remote_ref(world));
5251  g->task(coeffs.owner(key2), &implT::sock_it_to_me, key2, result.remote_ref(world), TaskAttributes::hipri());
5252  woT::task(world.rank(),&implT:: template do_project_out<LDIM>,fcoeff,result,key2,key1,dim);
5253 
5254  } else {
5255  MADNESS_EXCEPTION("confused dim in project_out",1);
5256  }
5257  }
5258  }
5259  this->compressed=false;
5260  this->nonstandard=false;
5261  this->redundant=true;
5262  }
5263 
5264 
5266 
5273  template<size_t LDIM>
5274  Void do_project_out(const coeffT& fcoeff, const std::pair<keyT,coeffT> gpair, const keyT& gkey,
5275  const Key<NDIM>& dest, const int dim) const {
5276 
5277  const coeffT gcoeff=parent_to_child(gpair.second,gpair.first,gkey);
5278 
5279  // fast return if possible
5280  if (fcoeff.has_no_data() or gcoeff.has_no_data()) return None;
5281 
5282  // let's specialize for the time being on SVD tensors for f and full tensors of half dim for g
5283  MADNESS_ASSERT(gcoeff.tensor_type()==TT_FULL);
5284  MADNESS_ASSERT(fcoeff.tensor_type()==TT_2D);
5285  const tensorT gtensor=gcoeff.full_tensor();
5286  tensorT result(cdata.vk);
5287 
5288  const int otherdim=(dim+1)%2;
5289  const int k=fcoeff.dim(0);
5290  std::vector<Slice> s(fcoeff.config().dim_per_vector()+1,_);
5291 
5292  // do the actual contraction
5293  for (int r=0; r<fcoeff.rank(); ++r) {
5294  s[0]=Slice(r,r);
5295  const tensorT contracted_tensor=fcoeff.config().ref_vector(dim)(s).reshape(k,k,k);
5296  const tensorT other_tensor=fcoeff.config().ref_vector(otherdim)(s).reshape(k,k,k);
5297  const double ovlp= gtensor.trace_conj(contracted_tensor);
5298  const double fac=ovlp * fcoeff.config().weights(r);
5299  result+=fac*other_tensor;
5300  }
5301 
5302  // accumulate the result
5303  coeffs.task(dest, &nodeT::accumulate2, result, coeffs, dest, TaskAttributes::hipri());
5304  return None;
5305  }
5306 
5307 
5308 
5309 
5311  std::size_t max_local_depth() const;
5312 
5313 
5315  std::size_t max_depth() const;
5316 
5318  std::size_t max_nodes() const;
5319 
5321  std::size_t min_nodes() const;
5322 
5324  std::size_t tree_size() const;
5325 
5327  std::size_t size() const;
5328 
5330  std::size_t real_size() const;
5331 
5333  void print_size(const std::string name) const;
5334 
5336  void print_stats() const;
5337 
5339  void scale_inplace(const T q, bool fence);
5340 
5342  template <typename Q, typename F>
5343  void scale_oop(const Q q, const FunctionImpl<F,NDIM>& f, bool fence) {
5344  typedef typename FunctionImpl<F,NDIM>::nodeT fnodeT;
5345  typedef typename FunctionImpl<F,NDIM>::dcT fdcT;
5346  typename fdcT::const_iterator end = f.coeffs.end();
5347  for (typename fdcT::const_iterator it=f.coeffs.begin(); it!=end; ++it) {
5348  const keyT& key = it->first;
5349  const fnodeT& node = it->second;
5350 
5351  if (node.has_coeff()) {
5352  coeffs.replace(key,nodeT(node.coeff()*q,node.has_children()));
5353  }
5354  else {
5355  coeffs.replace(key,nodeT(coeffT(),node.has_children()));
5356  }
5357  }
5358  if (fence)
5359  world.gop.fence();
5360  }
5361  };
5362 
5363  namespace archive {
5364  template <class Archive, class T, std::size_t NDIM>
5366  static void load(const Archive& ar, const FunctionImpl<T,NDIM>*& ptr) {
5367  bool exists=false;
5368  ar & exists;
5369  if (exists) {
5370  uniqueidT id;
5371  ar & id;
5372  World* world = World::world_from_id(id.get_world_id());
5373  MADNESS_ASSERT(world);
5374  ptr = static_cast< const FunctionImpl<T,NDIM>*>(world->ptr_from_id< WorldObject< FunctionImpl<T,NDIM> > >(id));
5375  if (!ptr)
5376  MADNESS_EXCEPTION("FunctionImpl: remote operation attempting to use a locally uninitialized object",0);
5377  } else {
5378  ptr=NULL;
5379  }
5380  }
5381  };
5382 
5383  template <class Archive, class T, std::size_t NDIM>
5385  static void store(const Archive& ar, const FunctionImpl<T,NDIM>*const& ptr) {
5386  bool exists=(ptr) ? true : false;
5387  ar & exists;
5388  if (exists) ar & ptr->id();
5389  }
5390  };
5391 
5392  template <class Archive, class T, std::size_t NDIM>
5393  struct ArchiveLoadImpl<Archive, FunctionImpl<T,NDIM>*> {
5394  static void load(const Archive& ar, FunctionImpl<T,NDIM>*& ptr) {
5395  bool exists=false;
5396  ar & exists;
5397  if (exists) {
5398  uniqueidT id;
5399  ar & id;
5400  World* world = World::world_from_id(id.get_world_id());
5401  MADNESS_ASSERT(world);
5402  ptr = static_cast< FunctionImpl<T,NDIM>*>(world->ptr_from_id< WorldObject< FunctionImpl<T,NDIM> > >(id));
5403  if (!ptr)
5404  MADNESS_EXCEPTION("FunctionImpl: remote operation attempting to use a locally uninitialized object",0);
5405  } else {
5406  ptr=NULL;
5407  }
5408  }
5409  };
5410 
5411  template <class Archive, class T, std::size_t NDIM>
5412  struct ArchiveStoreImpl<Archive, FunctionImpl<T,NDIM>*> {
5413  static void store(const Archive& ar, FunctionImpl<T,NDIM>*const& ptr) {
5414  bool exists=(ptr) ? true : false;
5415  ar & exists;
5416  if (exists) ar & ptr->id();
5417  // ar & ptr->id();
5418  }
5419  };
5420 
5421  template <class Archive, class T, std::size_t NDIM>
5422  struct ArchiveLoadImpl<Archive, std::shared_ptr<const FunctionImpl<T,NDIM> > > {
5423  static void load(const Archive& ar, std::shared_ptr<const FunctionImpl<T,NDIM> >& ptr) {
5424  const FunctionImpl<T,NDIM>* f = NULL;
5426  ptr.reset(f, & madness::detail::no_delete<const FunctionImpl<T,NDIM> >);
5427  }
5428  };
5429 
5430  template <class Archive, class T, std::size_t NDIM>
5431  struct ArchiveStoreImpl<Archive, std::shared_ptr<const FunctionImpl<T,NDIM> > > {
5432  static void store(const Archive& ar, const std::shared_ptr<const FunctionImpl<T,NDIM> >& ptr) {
5434  }
5435  };
5436 
5437  template <class Archive, class T, std::size_t NDIM>
5438  struct ArchiveLoadImpl<Archive, std::shared_ptr<FunctionImpl<T,NDIM> > > {
5439  static void load(const Archive& ar, std::shared_ptr<FunctionImpl<T,NDIM> >& ptr) {
5440  FunctionImpl<T,NDIM>* f = NULL;
5443  }
5444  };
5445 
5446  template <class Archive, class T, std::size_t NDIM>
5447  struct ArchiveStoreImpl<Archive, std::shared_ptr<FunctionImpl<T,NDIM> > > {
5448  static void store(const Archive& ar, const std::shared_ptr<FunctionImpl<T,NDIM> >& ptr) {
5450  }
5451  };
5452  }
5453 
5454 }
5455 
5456 #endif // MADNESS_MRA_FUNCIMPL_H__INCLUDED
int np
Definition: tdse1d.cc:166
bool is_leaf() const
Returns true if this does not have children.
Definition: funcimpl.h:202
bool do_error_leaf_op() const
Definition: funcimpl.h:461
bool do_error_leaf_op() const
Definition: funcimpl.h:498
void serialize(const Archive &ar)
Definition: funcimpl.h:3922
double fac
Definition: funcimpl.h:3933
double tol
Definition: funcimpl.h:3933
Vphi_op_NS()
Definition: funcimpl.h:3347
keyT dest
Definition: funcimpl.h:3932
recursive_apply_op2(implT *result, const ctT &iaf, const opT *apply_op)
Definition: funcimpl.h:4443
bool do_error_leaf_op() const
Definition: funcimpl.h:437
Void do_binary_op(const keyT &key, const Tensor< L > &left, const std::pair< keyT, Tensor< R > > &arg, const opT &op)
Invoked as a task by do_binary_op with the actual coefficients.
Definition: funcimpl.h:1813
FunctionNode()
Default constructor makes node without coeff or children.
Definition: funcimpl.h:143
bool operator()(typename rangeT::iterator &it) const
Definition: funcimpl.h:2196
const double thresh
Definition: dielectric.cc:185
const implL * g
Definition: funcimpl.h:609
hartree_leaf_op(const implT *f, const long &k)
Definition: funcimpl.h:501
bool operator()(typename rangeT::iterator &it) const
Definition: funcimpl.h:2215
this_type make_child(const keyT &child) const
Definition: funcimpl.h:3085
void error(const char *msg)
Definition: world.cc:128
#define ITERATOR(t, exp)
Definition: tensor_macros.h:249
WorldGopInterface & gop
Global operations.
Definition: worldfwd.h:462
SRConf< T > config() const
Definition: gentensor.h:201
std::vector< long > map
Definition: funcimpl.h:2125
leaf_opT leaf_op
determine if a given node will be a leaf node
Definition: funcimpl.h:3052
void mulXXvec(const FunctionImpl< L, NDIM > *left, const std::vector< const FunctionImpl< R, NDIM > * > &vright, const std::vector< FunctionImpl< T, NDIM > * > &vresult, double tol, bool fence)
Definition: funcimpl.h:2684
insert_op()
Definition: funcimpl.h:691
do_check_symmetry_local(const implT &f)
Definition: funcimpl.h:2016
this_type forward_ctor(implT *h1, const ctT &f1, const ctL &g1, const int particle)
Definition: funcimpl.h:2945
Void hartree_product(const FunctionImpl< T, LDIM > *p1, const FunctionImpl< T, LDIM > *p2, const leaf_opT &leaf_op, bool fence)
given two functions of LDIM, perform the Hartree/Kronecker/outer product
Definition: funcimpl.h:3165
void process_pending()
To be called from derived constructor to process pending messages.
Definition: worldobj.h:330
void process_pending()
Process pending messages.
Definition: worlddc.h:903
Void sum_down_spawn(const keyT &key, const coeffT &s)
is this the same as trickle_down() ?
Definition: mraimpl.h:964
Definition: shared_ptr_bits.h:38
std::shared_ptr< implL > impl_m2
supposedly 1/r2
Definition: function_interface.h:154
size_t size() const
Returns the number of coefficients in this node.
Definition: funcimpl.h:231
this_type forward_ctor(implT *result1, const ctT &iaf1, const opT *apply_op1)
taskq-compatible ctor
Definition: funcimpl.h:4500
Makes a distributed container with specified attributes.
Definition: worlddc.h:55
Tensor< Q > fcube_for_mul(const keyT &child, const keyT &parent, const Tensor< Q > &coeff) const
Compute the function values for multiplication.
Definition: funcimpl.h:1713
implT * impl
Definition: funcimpl.h:1968
NDIM const Function< R, NDIM > & g
Definition: mra.h:2179
do_reduce_rank()
Definition: funcimpl.h:1993
Tensor< double > hgT
The full twoscale coeff (2k,2k) and transpose.
Definition: function_common_data.h:107
void set_coeff(const coeffT &coeffs)
Takes a shallow copy of the coeff — same as this->coeff()=coeff.
Definition: funcimpl.h:274
bool leaves_only
Definition: funcimpl.h:4678
CoeffTracker< T, LDIM > ctL
Definition: funcimpl.h:5114
ctT iaket
the ket of a pair function (exclusive with p1, p2)
Definition: funcimpl.h:3341
Void mulXXa(const keyT &key, const FunctionImpl< L, NDIM > *left, const Tensor< L > &lcin, const FunctionImpl< R, NDIM > *right, const Tensor< R > &rcin, double tol)
Definition: funcimpl.h:2454
CoeffTracker(const implT *impl)
the initial ctor making the root key
Definition: funcimpl.h:778
hartree_op(implT *result, const ctL &p11, const ctL &p22, const leaf_opT &leaf_op)
Definition: funcimpl.h:3056
GenTensor< T > coeffT
Definition: funcimpl.h:458
void scale(Q a)
Scale the coefficients of this node.
Definition: funcimpl.h:290
Void sock_it_to_me_too(const keyT &key, const RemoteReference< FutureImpl< std::pair< keyT, coeffT > > > &ref) const
Definition: mraimpl.h:2704
do_check_symmetry_local()
Definition: funcimpl.h:2015
std::pair< bool, coeffT > continue_recursion(const std::vector< bool > child_is_leaf, const tensorT &coeffs, const keyT &key) const
loop over all children and either insert their sum coeffs or continue the recursion ...
Definition: funcimpl.h:3435
T norm(Vector< T, N > v)
Compute norm of a Vector.
Definition: array.h:447
const implT * eri
2-particle potential, must be on-demand
Definition: funcimpl.h:3344
const double R
Definition: dielectric.cc:191
static void _init_quadrature(int k, int npt, Tensor< double > &quad_x, Tensor< double > &quad_w, Tensor< double > &quad_phi, Tensor< double > &quad_phiw, Tensor< double > &quad_phit)
Initialize the quadrature information.
Definition: mraimpl.h:83
AtomicInt small
Definition: funcimpl.h:949
double operator()(double val) const
Definition: funcimpl.h:1256
std::complex< double > func(int n, int t1, int t2, int t3, double xx, double yy, double zz)
Definition: wannier.cc:98
A pmap that locates children on odd levels with their even level parents.
Definition: funcimpl.h:104
GenTensor< T > full_tensor_copy() const
Definition: gentensor.h:184
do_inner_ext_local_ffi(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > f, const implT *impl, const bool leaf_refine)
Definition: funcimpl.h:4900
bool operator()(typename rangeT::iterator &it) const
Definition: funcimpl.h:1928
Key< OPDIM > d
Definition: funcimpl.h:3931
double get_thresh() const
Definition: mraimpl.h:281
void print_plane(const std::string filename, const int xaxis, const int yaxis, const coordT &el2)
Print a plane ("xy", "xz", or "yz") containing the point x to file.
Definition: mraimpl.h:357
this_type forward_ctor(const ctT &f1, const ctT &g1, const double alpha, const double beta)
taskq-compatible ctor
Definition: funcimpl.h:2999
void do_print_tree(const keyT &key, std::ostream &os, Level maxlevel) const
Definition: mraimpl.h:2592
#define IND
Definition: tensor_macros.h:204
static TaskAttributes hipri()
Definition: worldthread.h:277
Header to declare stuff which has not yet found a home.
FunctionDefaults holds default paramaters as static class members.
Definition: funcdefaults.h:175
Void apply_1d_realspace_push_op(const archive::archive_ptr< const opT > &pop, int axis, const keyT &key, const Tensor< R > &c)
Definition: funcimpl.h:3199
compute the inner product of this range with other
Definition: funcimpl.h:4625
const opT * op
the convolution operator
Definition: funcimpl.h:560
const FunctionImpl< T, NDIM > * f
Definition: funcimpl.h:608
Range< typename dcT::iterator > rangeT
Definition: funcimpl.h:1923
Range< typename FunctionImpl< Q, NDIM >::dcT::const_iterator > rangeT
Definition: funcimpl.h:1104
double get_norm_tree() const
Gets the value of norm_tree.
Definition: funcimpl.h:301
coeffT compress_op(const keyT &key, const std::vector< Future< coeffT > > &v, bool nonstandard, bool redundant)
calculate the wavelet coefficients using the sum coefficients of all child nodes
Definition: mraimpl.h:1650
double operator()(double a, double b) const
Definition: funcimpl.h:4610
bool operator()(typename rangeT::iterator &it) const
Definition: funcimpl.h:2230
Void plot_cube_kernel(archive::archive_ptr< Tensor< T > > ptr, const keyT &key, const coordT &plotlo, const coordT &plothi, const std::vector< long > &npt, bool eval_refine) const
Definition: mraimpl.h:3097
Range< typename dcT::iterator > rangeT
Definition: funcimpl.h:1987
CoeffTracker< T, LDIM > ctL
Definition: funcimpl.h:3337
do_merge_trees()
Definition: funcimpl.h:2091
bool find(accessor &acc, const keyT &key)
Write access to LOCAL value by key. Returns true if found, false otherwise (always false for remote)...
Definition: worlddc.h:740
Void multiply(const implT *f, const FunctionImpl< T, LDIM > *g, const int particle)
multiply f (a pair function of NDIM) with an orbital g (LDIM=NDIM/2)
Definition: funcimpl.h:3018
int dim
Definition: funcimpl.h:5121
do_consolidate_buffer(const TensorArgs &targs)
Definition: funcimpl.h:2214
error_leaf_op()
Definition: funcimpl.h:462
void apply_source_driven(opT &op, const FunctionImpl< R, NDIM > &f, bool fence)
similar to apply, but for low rank coeffs
Definition: funcimpl.h:4244
TensorType
low rank representations of tensors (see gentensor.h)
Definition: tensor.h:275
do_unary_op_value_inplace(implT *impl, const opT &op)
Definition: funcimpl.h:2229
std::pair< bool, coeffT > operator()(const keyT &key) const
if we are at the bottom of the trees, return the sum of the coeffs
Definition: funcimpl.h:2973
void insert_zero_down_to_initial_level(const keyT &key)
Initialize nodes to zero function at initial_level of refinement.
Definition: mraimpl.h:2488
const implT * f
Definition: funcimpl.h:1924
recursive_apply_op2()
Definition: funcimpl.h:4442
add_op(const ctT &f, const ctT &g, const double alpha, const double beta)
Definition: funcimpl.h:2969
bool has_children() const
Returns true if this node has children.
Definition: funcimpl.h:196
double operator()(double a, double b) const
Definition: funcimpl.h:4570
bool _fence
Definition: function_factory.h:93
bool operator()(const Key< NDIM > &key, const T &t) const
Definition: funcimpl.h:707
void serialize(const Archive &ar)
Definition: funcimpl.h:4397
long ndim() const
Returns the number of dimensions in the tensor.
Definition: basetensor.h:144
std::size_t size() const
Returns the number of coefficients in the function ... collective global sum.
Definition: mraimpl.h:1829
const Vector< Translation, NDIM > & translation() const
Definition: key.h:225
void abs_inplace(bool fence)
Definition: mraimpl.h:2958
static void store(const Archive &ar, const std::shared_ptr< const FunctionImpl< T, NDIM > > &ptr)
Definition: funcimpl.h:5432
void serialize(const Archive &ar)
Definition: funcimpl.h:1980
void serialize(const Archive &ar)
serialization
Definition: funcimpl.h:868
this_type make_child(const keyT &child) const
Definition: funcimpl.h:5182
Definition: worldhashmap.h:332
const int NDIM
Definition: tdse1.cc:44
void serialize(const Archive &ar)
Definition: funcimpl.h:5202
std::vector< long > v2k
(2k,...) used to initialize Tensors
Definition: function_common_data.h:94
coeff_value_adaptor(const FunctionImpl< Q, NDIM > *impl_func, const opT &op)
Definition: funcimpl.h:2600
do_inner_ext_local(T(*f)(const coordT &), const implT *impl, const bool leaf_refine)
Definition: funcimpl.h:4874
void refine(const opT &op, bool fence)
Definition: funcimpl.h:3804
CoeffTracker< T, NDIM > ctT
Definition: funcimpl.h:3336
FunctionNode(const coeffT &coeff, bool has_children=false)
Constructor from given coefficients with optional children.
Definition: funcimpl.h:153
static double lower()
Definition: funcimpl.h:1253
static void load(const Archive &ar, std::shared_ptr< FunctionImpl< T, NDIM > > &ptr)
Definition: funcimpl.h:5439
void serialize(Archive &ar)
Definition: funcimpl.h:412
Key< NDIM+LDIM > merge_with(const Key< LDIM > &rhs) const
merge with other key (ie concatenate), use level of rhs, not of this
Definition: key.h:348
const opT * apply_op
need this for randomization
Definition: funcimpl.h:4439
TensorArgs args
Definition: funcimpl.h:1990
Definition: funcimpl.h:4544
GenTensor< T > coeffT
Type of tensor used to hold coeffs.
Definition: funcimpl.h:908
void unary_op_coeff_inplace(const opT &op, bool fence)
Unary operation applied inplace to the coefficients WITHOUT refinement, optional fence.
Definition: funcimpl.h:1864
resultT operator()(typename dcT::const_iterator &it) const
Definition: funcimpl.h:4632
Range< typename dcT::const_iterator > rangeT
Definition: funcimpl.h:2153
bool has_no_data() const
Definition: gentensor.h:188
bool operator()(const Key< NDIM > &key, const GenTensor< T > &coeff) const
no post-determination
Definition: funcimpl.h:621
bool operator()(const Key< NDIM > &key, const GenTensor< T > &coeff) const
post-determination: return true if operator and coefficient norms are small
Definition: funcimpl.h:571
T inner_ext_node(keyT key, tensorT c, T(*f)(const coordT &)) const
Definition: funcimpl.h:4688
bool screen(const coeffT &fcoeff, const coeffT &gcoeff, const keyT &key) const
return true if this will be a leaf node
Definition: funcimpl.h:2856
remove_internal_coeffs()
constructor need impl for cdata
Definition: funcimpl.h:1952
void square_inplace(bool fence)
Pointwise squaring of function with optional global fence.
Definition: mraimpl.h:2952
CoeffTracker< T, NDIM > ctT
Definition: funcimpl.h:2839
#define TERNARY_OPTIMIZED_ITERATOR(X, x, Y, y, Z, z, exp)
Definition: tensor_macros.h:719
void serialize(const Archive &ar)
Definition: funcimpl.h:2248
do_convert_to_color(const double limit, const bool log)
Definition: funcimpl.h:1255
const LeafStatus & is_leaf() const
const reference to is_leaf flag
Definition: funcimpl.h:816
const mpreal dim(const mpreal &a, const mpreal &b, mp_rnd_t rnd_mode)
Definition: mpreal.h:2201
void merge_trees(const T alpha, const FunctionImpl< Q, NDIM > &other, const R beta, const bool fence=true)
merge the trees of this and other, while multiplying them with the alpha or beta, resp ...
Definition: funcimpl.h:1082
coeffT & coeff()
Returns a non-const reference to the tensor containing the coeffs.
Definition: funcimpl.h:216
Future< bool > for_each(const rangeT &range, const opT &op)
Apply op(item) for all items in range.
Definition: worldtask.h:556
Future< this_type > activate() const
retrieve the coefficients (parent coeffs might be remote)
Definition: funcimpl.h:5191
ShallowNode()
Definition: funcimpl.h:721
bool is_invalid() const
Returns true if this node is invalid (no coeffs and no children)
Definition: funcimpl.h:208
bool operator()(typename rangeT::iterator &it) const
Definition: funcimpl.h:2131
Tensor< Q > values2coeffs(const keyT &key, const Tensor< Q > &values) const
Definition: funcimpl.h:1702
CoeffTracker< T, NDIM > ctT
Definition: funcimpl.h:2958
GenTensor< T > outer(const GenTensor< T > &left, const GenTensor< T > &right)
Outer product ... result(i,j,...,p,q,...) = left(i,k,...)*right(p,q,...)
Definition: gentensor.h:230
coeffT parent_to_child_NS(const keyT &child, const keyT &parent, const coeffT &coeff) const
Directly project parent NS coeffs to child NS coeffs.
Definition: mraimpl.h:658
ctT iaf
Definition: funcimpl.h:4438
double svd_normf() const
Definition: gentensor.h:190
void copy_coeffs(const FunctionImpl< Q, NDIM > &other, bool fence)
Copy coeffs from other into self.
Definition: funcimpl.h:1050
bool is_compressed() const
Returns true if the function is compressed.
Definition: mraimpl.h:231
bool operator()(const Key< NDIM > &key, const coeffT &coeff, const coeffT &parent) const
post-determination
Definition: funcimpl.h:477
Provides a tensor with taking advantage of possibly low rank.
const implT * fimpl
Definition: funcimpl.h:5118
GenTensor< Q > NScoeffs2values(const keyT &key, const GenTensor< Q > &coeff, const bool s_only) const
convert S or NS coeffs to values on a 2k grid of the children
Definition: funcimpl.h:1581
CoeffTracker make_child(const keyT &child) const
make a child of this, ignoring the coeffs
Definition: funcimpl.h:819
const double L
Definition: 3dharmonic.cc:123
void phi_for_mul(Level np, Translation lp, Level nc, Translation lc, Tensor< double > &phi) const
Compute the Legendre scaling functions for multiplication.
Definition: mraimpl.h:2968
std::size_t max_nodes() const
Returns the max number of nodes on a processor.
Definition: mraimpl.h:1802
detail::ReferenceWrapper< T > const ref(T &t)
Reference wrapper factory function.
Definition: ref.h:132
add_op this_type
Definition: funcimpl.h:2959
void serialize(Archive &ar)
Definition: funcimpl.h:3938
implL1 * result
Definition: funcimpl.h:5119
std::size_t max_depth() const
Returns the maximum depth of the tree ... collective ... global sum/broadcast.
Definition: mraimpl.h:1794
::std::string string
Definition: gtest-port.h:872
FunctionImpl(const FunctionFactory< T, NDIM > &factory)
Initialize function impl from data in factory.
Definition: funcimpl.h:953
Void do_square_inplace2(const keyT &parent, const keyT &child, const tensorT &parent_coeff)
FunctionNode(const coeffT &coeff, double norm_tree, bool has_children)
Definition: funcimpl.h:158
do_reduce_rank(const TensorArgs &targs)
Definition: funcimpl.h:1994
do_gaxpy_inplace(FunctionImpl< T, NDIM > *f, T alpha, R beta)
Definition: funcimpl.h:1109
Void vtransform_doit(const std::shared_ptr< FunctionImpl< R, NDIM > > &right, const Tensor< Q > &c, const std::vector< std::shared_ptr< FunctionImpl< T, NDIM > > > &vleft, double tol)
Definition: funcimpl.h:2252
returns true if the result of a hartree_product is a leaf node (compute norm & error) ...
Definition: funcimpl.h:493
void no_delete(T *)
Use this function with shared_ptr to do nothing for the pointer cleanup.
Definition: boost_checked_delete_bits.h:47
bool randomize() const
Definition: funcimpl.h:2961
Iterator for distributed container wraps the local iterator.
Definition: worlddc.h:159
Range< typename dcT::iterator > rangeT
Definition: funcimpl.h:2186
void reduceRank(const double &eps)
reduces the rank of the coefficients (if applicable)
Definition: funcimpl.h:238
FunctionImpl< T, NDIM > implT
Definition: funcimpl.h:685
void abs_square_inplace(bool fence)
Definition: mraimpl.h:2963
recursive part of recursive_apply
Definition: funcimpl.h:4302
T alpha
Definition: funcimpl.h:1106
virtual ~FunctionImpl()
Definition: funcimpl.h:1044
double cnorm
Definition: funcimpl.h:3933
std::shared_ptr< implL > impl_p2
supposedly orbital 2
Definition: function_interface.h:156
Definition: uniqueid.h:46
const implT * f
Definition: funcimpl.h:459
void serialize(const Archive &ar)
Definition: funcimpl.h:3003
error_leaf_op(const implT *f)
Definition: funcimpl.h:463
ctT g
Definition: funcimpl.h:2964
do_mapdim(const std::vector< long > map, implT &f)
Definition: funcimpl.h:2129
hartree_convolute_leaf_op(const implT *f, const implL *g, const opT *op)
Definition: funcimpl.h:614
Void do_diff1(const DerivativeBase< T, NDIM > *D, const implT *f, const keyT &key, const std::pair< keyT, coeffT > &left, const std::pair< keyT, coeffT > &center, const std::pair< keyT, coeffT > &right)
Definition: mraimpl.h:1023
LevelPmap(World &world)
Definition: funcimpl.h:110
bool operator()(const Key< NDIM > &key) const
no pre-determination
Definition: funcimpl.h:618
void clear()
Clears all local data (no communication)
Definition: worlddc.h:875
Grossly simplified Boost-like type traits and templates.
WorldContainer< keyT, nodeT > dcT
Type of container holding the coefficients.
Definition: funcimpl.h:909
void compress(bool nonstandard, bool keepleaves, bool redundant, bool fence)
compress the wave function
Definition: mraimpl.h:1462
bool randomize() const
Definition: funcimpl.h:3333
bool has_coeff() const
Returns true if there are coefficients in this node.
Definition: funcimpl.h:188
tensorT gaxpy_ext_node(keyT key, Tensor< L > lc, T(*f)(const coordT &), T alpha, T beta) const
Definition: funcimpl.h:4956
GenTensor< T > coeffT
Definition: funcimpl.h:128
Definition: mpreal.h:3066
double accumulate(const coeffT &t, const typename FunctionNode< T, NDIM >::dcT &c, const Key< NDIM > &key, const TensorArgs &args)
Accumulate inplace and if necessary connect node to parent.
Definition: funcimpl.h:361
multiply_op< LDIM > this_type
Definition: funcimpl.h:2841
friend class FunctionImpl
Definition: funcimpl.h:914
this_type forward_ctor(const implT *fimpl1, implL1 *result1, const ctL &iag1, const int dim1)
taskq-compatible ctor
Definition: funcimpl.h:5198
tensorT downsample(const keyT &key, const std::vector< Future< coeffT > > &v) const
downsample the sum coefficients of level n+1 to sum coeffs on level n
Definition: mraimpl.h:1237
void set_functor(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > functor1)
Definition: mraimpl.h:245
ShallowNode(const FunctionNode< T, NDIM > &node)
Definition: funcimpl.h:722
FunctionImpl< T, NDIM > implT
Definition: funcimpl.h:495
char(& no)[2]
Definition: type_traits_bits.h:172
project_out_op(const implT *fimpl, implL1 *result, const ctL &iag, const int dim)
Definition: funcimpl.h:5125
coeffT truncate_reconstructed_op(const keyT &key, const std::vector< Future< coeffT > > &v, const double tol)
given the sum coefficients of all children, truncate or not
Definition: mraimpl.h:1584
double norm_tree_op(const keyT &key, const std::vector< Future< double > > &v)
Definition: mraimpl.h:1522
void add_scalar_inplace(T t, bool fence)
Adds a constant to the function. Local operation, optional fence.
Definition: mraimpl.h:2447
recursive_apply_op2(const recursive_apply_op2 &other)
Definition: funcimpl.h:4446
void apply_1d_realspace_push(const opT &op, const FunctionImpl< R, NDIM > *f, int axis, bool fence)
Definition: funcimpl.h:3251
void nonstandard(World &world, std::vector< Function< T, NDIM > > &v, bool fence=true)
Generates non-standard form of a vector of functions.
Definition: vmra.h:167
std::size_t real_size() const
Returns the number of coefficients in the function ... collective global sum.
Definition: mraimpl.h:1860
const uniqueidT & id() const
Returns the globally unique object ID.
Definition: worldobj.h:377
Future< this_type > activate() const
Definition: funcimpl.h:3094
double operator()(typename dcT::const_iterator &it) const
Definition: funcimpl.h:4599
Future< double > get_norm_tree_recursive(const keyT &key) const
Definition: mraimpl.h:2667
std::vector< keyT > local_leaf_keys() const
return the keys of the local leaf boxes
Definition: mraimpl.h:515
recursive part of recursive_apply
Definition: funcimpl.h:4430
Void forward_traverse(const coeff_opT &coeff_op, const apply_opT &apply_op, const keyT &key) const
traverse a non-existing tree
Definition: funcimpl.h:3118
Definition: funcimpl.h:684
returns true if the function has a leaf node at key (works only locally)
Definition: funcimpl.h:434
bool operator()(const Key< NDIM > &key, const GenTensor< T > &coeff) const
no post-determination
Definition: funcimpl.h:507
Tensor< TENSOR_RESULT_TYPE(T, R)> mul(const Tensor< T > &c1, const Tensor< R > &c2, const int npt, const keyT &key) const
multiply the values of two coefficient tensors using a custom number of grid points ...
Definition: funcimpl.h:1786
void serialize(Archive &ar)
Definition: funcimpl.h:732
void gaxpy_ext(const FunctionImpl< L, NDIM > *left, T(*f)(const coordT &), T alpha, T beta, double tol, bool fence)
Definition: funcimpl.h:5069
void trickle_down(bool fence)
sum all the contributions from all scales after applying an operator in mod-NS form ...
Definition: mraimpl.h:1388
NDIM & f
Definition: mra.h:2179
bool operator()(const Key< NDIM > &key) const
pre-determination: we can't know if this will be a leaf node before we got the final coeffs ...
Definition: funcimpl.h:568
given a ket and the 1- and 2-electron potentials, construct the function V phi
Definition: funcimpl.h:3331
long dim(int i) const
Returns the size of dmension i.
Definition: basetensor.h:147
void serialize(const Archive &ar)
Definition: funcimpl.h:4662
void serialize(Archive &ar)
Definition: funcimpl.h:593
std::size_t min_nodes() const
Returns the min number of nodes on a processor.
Definition: mraimpl.h:1811
do_err_box()
Definition: funcimpl.h:4552
bool has_data() const
Definition: gentensor.h:187
do_err_box(const do_err_box &e)
Definition: funcimpl.h:4558
void add_SVD(const GenTensor< T > &rhs, const double &eps)
Definition: gentensor.h:199
void serialize(const Archive &ar)
Definition: funcimpl.h:2145
iterator end()
Returns an iterator past the end of the local data (no communication)
Definition: worlddc.h:835
ProcessID size() const
Returns the number of processes in this world (same as MPI_Comm_size())
Definition: worldfwd.h:533
do_consolidate_buffer()
Definition: funcimpl.h:2213
double do_apply_kernel2(const opT *op, const Tensor< R > &c, const do_op_args< OPDIM > &args, const TensorArgs &apply_targs)
same as do_apply_kernel, but use full rank tensors as input and low rank tensors as output ...
Definition: funcimpl.h:3983
Provides FunctionDefaults and utilities for coordinate transformation.
do_merge_trees(const T alpha, const R beta, FunctionImpl< Q, NDIM > &other)
Definition: funcimpl.h:2092
FunctionImpl< T, NDIM > implT
Definition: funcimpl.h:605
Tensor< T > fcube(const Key< NDIM > &, T(*f)(const Vector< double, NDIM > &), const Tensor< double > &)
Definition: mraimpl.h:2047
"put" this on g
Definition: funcimpl.h:2152
Void gaxpy_inplace(const T &alpha, const FunctionNode< Q, NDIM > &other, const R &beta)
General bi-linear operation — this = this*alpha + other*beta.
Definition: funcimpl.h:311
int RandomValue< int >()
Random int.
Definition: ran.cc:250
Future< this_type > activate() const
retrieve the coefficients (parent coeffs might be remote)
Definition: funcimpl.h:4493
Wrapper for opaque pointer ... bitwise copy of the pointer ... no remapping performed.
Definition: archive.h:788
implT * f
Definition: funcimpl.h:2126
const FunctionCommonData< T, NDIM > & get_cdata() const
Definition: mraimpl.h:302
void recursive_apply(opT &apply_op, const FunctionImpl< T, LDIM > *fimpl, const FunctionImpl< T, LDIM > *gimpl, const bool fence)
traverse a non-existing tree, make its coeffs and apply an operator
Definition: funcimpl.h:4277
std::pair< bool, coeffT > operator()(const Key< NDIM > &key) const
make and insert the coefficients into result's tree
Definition: funcimpl.h:3359
hartree_op()
Definition: funcimpl.h:3055
Void traverse_tree(const coeff_opT &coeff_op, const apply_opT &apply_op, const keyT &key) const
traverse a non-existing tree
Definition: funcimpl.h:3134
void average(const implT &rhs)
take the average of two functions, similar to: this=0.5*(this+rhs)
Definition: mraimpl.h:1150
double beta
Definition: funcimpl.h:2966
do_keep_sum_coeffs(implT *impl)
constructor need impl for cdata
Definition: funcimpl.h:1971
CoeffTracker< T, LDIM > ctL
Definition: funcimpl.h:2840
std::pair< bool, coeffT > operator()(const Key< NDIM > &key) const
apply this on a FunctionNode of f and g of Key key
Definition: funcimpl.h:2882
Tensor< T > tensorT
Type of tensor for anything but to hold coeffs.
Definition: funcimpl.h:904
const keyT & key() const
const reference to the key
Definition: funcimpl.h:800
const implT * impl
Definition: funcimpl.h:4897
ctL iap1
Definition: funcimpl.h:3342
FunctionImpl< T, NDIM > * f
Definition: funcimpl.h:1105
void recursive_apply(opT &apply_op, const implT *fimpl, implT *rimpl, const bool fence)
traverse an existing tree and apply an operator
Definition: funcimpl.h:4409
Default store of a thingy via serialize(ar,t)
Definition: archive.h:708
void unaryXX(const FunctionImpl< Q, NDIM > *func, const opT &op, bool fence)
Definition: funcimpl.h:2664
int get_k() const
Definition: mraimpl.h:293
void norm_tree(World &world, const std::vector< Function< T, NDIM > > &v, bool fence=true)
Makes the norm tree for all functions in a vector.
Definition: vmra.h:506
std::vector< Slice > child_patch(const keyT &child) const
Returns patch referring to coeffs of child in parent box.
Definition: mraimpl.h:641
void change_tensor_type1(const TensorArgs &targs, bool fence)
change the tensor type of the coefficients in the FunctionNode
Definition: mraimpl.h:1161
const coeffT parent_to_child(const coeffT &s, const keyT &parent, const keyT &child) const
Directly project parent coeffs to child coeffs.
Definition: mraimpl.h:2983
Key< NDIM > keyT
Type of key.
Definition: funcimpl.h:906
uint64_t distsq() const
Definition: key.h:230
void serialize(const Archive &ar)
Definition: funcimpl.h:2006
static bool get_apply_randomize()
Gets the random load balancing for integral operators flag.
Definition: funcdefaults.h:324
FunctionImpl< T, NDIM > implT
Definition: funcimpl.h:457
TensorArgs targs
Definition: funcimpl.h:2189
opT op
Definition: funcimpl.h:2597
int k
order of the wavelet
Definition: function_common_data.h:88
void break_apart(Key< LDIM > &key1, Key< KDIM > &key2) const
break key into two low-dimensional keys
Definition: key.h:330
double errsq_local(const opT &func) const
Returns the sum of squares of errors from local info ... no comms.
Definition: funcimpl.h:4582
const double beta
Definition: gygi_soltion.cc:63
Tensor< typename Tensor< T >::scalar_type > arg(const Tensor< T > &t)
Return a new tensor holding the argument of each element of t (complex types only) ...
Definition: tensor.h:2429
void binaryXX(const FunctionImpl< L, NDIM > *left, const FunctionImpl< R, NDIM > *right, const opT &op, bool fence)
Definition: funcimpl.h:2653
FunctionImpl holds all Function state to facilitate shallow copy semantics.
Definition: funcdefaults.h:48
static const Tensor< double > & get_cell()
Gets the user cell for the simulation.
Definition: funcdefaults.h:369
This header should include pretty much everything needed for the parallel runtime.
T inner(const vecfunc< T, NDIM > &a, const vecfunc< T, NDIM > &b)
the non-linear solver requires an inner product
Definition: nemo.h:112
#define PROFILE_MEMBER_FUNC(classname)
Definition: worldprofile.h:199
iterator begin()
Returns an iterator to the beginning of the local data (no communication)
Definition: worlddc.h:822
T inner_ext_local(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > f, const bool leaf_refine) const
Definition: funcimpl.h:4936
Tensor< resultT > operator()(const Key< NDIM > &key, const Tensor< Q > &t) const
Definition: funcimpl.h:2604
SimplePmap(World &world)
Definition: funcimpl.h:91
Changes non-standard compressed form to standard compressed form.
Definition: funcimpl.h:3895
bool exists() const
Definition: funcimpl.h:192
op_leaf_op(const opT *op, const implT *f)
Definition: funcimpl.h:565
FunctionImpl< T, NDIM > implT
Definition: funcimpl.h:558
implT * g
Definition: funcimpl.h:2155
ctL p2
tracking coeffs of the two lo-dim functions
Definition: funcimpl.h:3051
FunctionImpl< T, NDIM > implT
Definition: funcimpl.h:435
Future< std::pair< keyT, coeffT > > find_me(const keyT &key) const
find_me. Called by diff_bdry to get coefficients of boundary function
Definition: mraimpl.h:3059
Void trickle_down_op(const keyT &key, const coeffT &s)
sum all the contributions from all scales after applying an operator in mod-NS form ...
Definition: mraimpl.h:1402
std::vector< long > vk
(k,...) used to initialize Tensors
Definition: function_common_data.h:93
static World * world_from_id(unsigned long id)
Convert world id to world pointer.
Definition: worldfwd.h:628
void multiop_values(const opT &op, const std::vector< implT * > &v)
Definition: funcimpl.h:2319
ctL iap2
the particles 1 and 2 (exclusive with ket)
Definition: funcimpl.h:3342
this_type make_child(const keyT &child) const
Definition: funcimpl.h:3556
merge the coefficent boxes of this into other's tree
Definition: funcimpl.h:2086
Void set_norm_tree(double norm_tree)
Sets the value of norm_tree.
Definition: funcimpl.h:295
FunctionImpl< T, NDIM > implT
Type of this class (implementation)
Definition: funcimpl.h:902
returnT type
Definition: enable_if.h:47
Defines and implements most of Tensor.
std::shared_ptr< implT > impl_ket
various MRA functions of NDIM dimensionality
Definition: function_interface.h:149
leaf_op(const implT *f)
Definition: funcimpl.h:440
bool leaves_only
Definition: funcimpl.h:4627
TensorType get_tensor_type() const
Definition: mraimpl.h:275
static void load(const Archive &ar, FunctionImpl< T, NDIM > *&ptr)
Definition: funcimpl.h:5394
T inner_ext_recursive(keyT key, tensorT c, const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > f, const bool leaf_refine, T old_inner=T(0)) const
Definition: funcimpl.h:4798
implT * result
Definition: funcimpl.h:4437
void scale_inplace(const T q, bool fence)
In-place scale by a constant.
Definition: mraimpl.h:2946
Void mulXXveca(const keyT &key, const FunctionImpl< L, NDIM > *left, const Tensor< L > &lcin, const std::vector< const FunctionImpl< R, NDIM > * > vrightin, const std::vector< Tensor< R > > &vrcin, const std::vector< FunctionImpl< T, NDIM > * > vresultin, double tol)
Definition: funcimpl.h:2357
bool is_valid() const
Checks if a key is valid.
Definition: key.h:158
void unary_op_node_inplace(const opT &op, bool fence)
Unary operation applied inplace to the coefficients WITHOUT refinement, optional fence.
Definition: funcimpl.h:1884
bool noautorefine(const keyT &key, const tensorT &t) const
Always returns false (for when autorefine is not wanted)
Definition: mraimpl.h:947
Range< typename dcT::iterator > rangeT
Definition: funcimpl.h:2207
this_type make_child(const keyT &child) const
Definition: funcimpl.h:4488
CompositeFunctorInterface implements a wrapper of holding several functions and functors.
Definition: funcimpl.h:73
Timer timer_target_driven
Definition: funcimpl.h:947
do_op_args()
Definition: funcimpl.h:3934
Void unaryXXa(const keyT &key, const FunctionImpl< Q, NDIM > *func, const opT &op)
Definition: funcimpl.h:2620
void serialize(const Archive &ar)
Definition: funcimpl.h:4614
void set_autorefine(bool value)
Definition: mraimpl.h:290
a class to track where relevant (parent) coeffs are
Definition: funcimpl.h:756
std::size_t max_local_depth() const
Returns the maximum local depth of the tree ... no communications.
Definition: mraimpl.h:1780
Timer timer_accumulate
Definition: funcimpl.h:943
T inner_ext_recursive(keyT key, tensorT c, T(*f)(const coordT &), const bool leaf_refine, T old_inner=T(0)) const
Definition: funcimpl.h:4720
Void erase(const Level &max_level)
truncate tree at a certain level
Definition: mraimpl.h:823
do_average(implT &g)
Definition: funcimpl.h:2158
bool is_leaf() const
Definition: funcimpl.h:730
const bool leaf_refine
Definition: funcimpl.h:4898
Range< typename dcT::iterator > rangeT
Definition: funcimpl.h:1967
Void do_apply(const opT *op, const keyT &key, const Tensor< R > &c)
apply an operator on the coeffs c (at node key)
Definition: funcimpl.h:4054
void do_print_tree_graphviz(const keyT &key, std::ostream &os, Level maxlevel) const
Definition: mraimpl.h:2620
double thresh
Definition: gentensor.h:128
Simple structure used to manage references/pointers to remote instances.
Definition: worldref.h:59
T operator()(T a, T b) const
Definition: funcimpl.h:4912
given an NS tree resulting from a convolution, truncate leafs if appropriate
Definition: funcimpl.h:1922
Void sock_it_to_me(const keyT &key, const RemoteReference< FutureImpl< std::pair< keyT, coeffT > > > &ref) const
Walk up the tree returning pair(key,node) for first node with coefficients.
Definition: mraimpl.h:2678
bool operator()(const Key< NDIM > &key, const Tensor< T > &fcoeff, const Tensor< T > &gcoeff) const
post-determination: true if f is a leaf and the result is well-represented
Definition: funcimpl.h:517
Tensor< double > quad_x
quadrature points
Definition: function_common_data.h:99
Void evaldepthpt(const Vector< double, NDIM > &xin, const keyT &keyin, const typename Future< Level >::remote_refT &ref)
Get the depth of the tree at a point in simulation coordinates.
Definition: mraimpl.h:2800
insert_op(const insert_op &other)
Definition: funcimpl.h:693
implT * impl
Definition: funcimpl.h:690
void zero_norm_tree()
Definition: mraimpl.h:1329
Void set_has_children_recursive(const typename FunctionNode< T, NDIM >::dcT &c, const Key< NDIM > &key)
Sets has_children attribute to true recurring up to ensure connected.
Definition: funcimpl.h:251
bool is_local(const keyT &key) const
Returns true if the key maps to the local processor (no communication)
Definition: worlddc.h:793
Future< coeffT > truncate_reconstructed_spawn(const keyT &key, const double tol)
truncate using a tree in reconstructed form
Definition: mraimpl.h:1560
double operator()(double a, double b) const
Definition: funcimpl.h:2070
T trace_conj(const FunctionNode< T, NDIM > &rhs) const
Definition: funcimpl.h:407
void print_tree_graphviz(std::ostream &os=std::cout, Level maxlevel=10000) const
Definition: mraimpl.h:2612
recursive_apply_op2< opT > this_type
Definition: funcimpl.h:4433
CoeffTracker< T, LDIM > iag
Definition: funcimpl.h:4309
void do_print_grid(const std::string filename, const std::vector< keyT > &keys) const
print the grid in xyz format
Definition: mraimpl.h:541
const T1 &f1 return GTEST_2_TUPLE_() T(f0, f1)
std::pair< Key< NDIM >, ShallowNode< T, NDIM > > find_datum(keyT key) const
return the a std::pair, which MUST exist
Definition: mraimpl.h:1057
Vector< double, NDIM > coordT
Type of vector holding coordinates.
Definition: funcimpl.h:911
T(* fptr)(const coordT &)
Definition: funcimpl.h:4870
void verify_tree() const
Verify tree is properly constructed ... global synchronization involved.
Definition: mraimpl.h:104
implT * result
where to construct the pair function
Definition: funcimpl.h:3050
static bool randomize()
Definition: funcimpl.h:2838
#define max(a, b)
Definition: lda.h:53
T inner_ext_node(keyT key, tensorT c, const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > f) const
Definition: funcimpl.h:4703
bool operator()(const Key< NDIM > &key) const
no pre-determination
Definition: funcimpl.h:466
bool operator()(const Key< NDIM > &key, const Tensor< T > &fcoeff, const Tensor< T > &gcoeff) const
post-determination: true if f is a leaf and the result is well-represented
Definition: funcimpl.h:631
ctL g
Definition: funcimpl.h:2845
void unary_op_value_inplace(const opT &op, bool fence)
Unary operation applied inplace to the values with optional refinement and fence. ...
Definition: funcimpl.h:2347
T * ptr
Definition: archive.h:790
void serialize(const Archive &ar)
Definition: funcimpl.h:2074
Vector< T, 1 > vec(T x)
Your friendly neighborhood factory function.
Definition: array.h:456
Tensor< double > print_plane_local(const int xaxis, const int yaxis, const coordT &el2)
collect the data for a plot of the MRA structure locally on each node
Definition: mraimpl.h:378
Key parent(int generation=1) const
Returns the key of the parent.
Definition: key.h:248
std::vector< Slice > s0
s[0] in each dimension to get scaling coeff
Definition: function_common_data.h:91
void scale(World &world, std::vector< Function< T, NDIM > > &v, const std::vector< Q > &factors, bool fence=true)
Scales inplace a vector of functions by distinct values.
Definition: vmra.h:290
const bool leaf_refine
Definition: funcimpl.h:4872
Future< this_type > activate() const
Definition: funcimpl.h:4385
void serialize(const Archive &ar)
Definition: funcimpl.h:4916
Future< argT > operator()(const Key< NDIM > &key) const
do the actual contraction
Definition: funcimpl.h:5132
WorldContainer< Key< NDIM >, FunctionNode< T, NDIM > > dcT
Definition: funcimpl.h:141
void scale_oop(const Q q, const FunctionImpl< F, NDIM > &f, bool fence)
Out-of-place scale by a constant.
Definition: funcimpl.h:5343
Definition: funcimpl.h:557
void serialize(Archive &ar)
Definition: funcimpl.h:697
detail::task_result_type< memfnT >::futureT task(ProcessID dest, memfnT memfn, const TaskAttributes &attr=TaskAttributes()) const
Sends task to derived class method "returnT (this->*memfn)(a1,a2,a3,a4,a5,a6,a7,a8,a9)".
Definition: worldobj.h:493
void change_tensor_type(GenTensor< T > &t, const TensorArgs &targs)
change representation to targ.tt
Definition: gentensor.h:1309
Void do_square_inplace(const keyT &key)
void vtransform(const std::vector< std::shared_ptr< FunctionImpl< R, NDIM > > > &vright, const Tensor< Q > &c, const std::vector< std::shared_ptr< FunctionImpl< T, NDIM > > > &vleft, double tol, bool fence)
Transforms a vector of functions left[i] = sum[j] right[j]*c[j,i] using sparsity. ...
Definition: funcimpl.h:2333
Definition: funcimpl.h:1103
T operator()(T a, T b) const
Definition: funcimpl.h:4886
hartree_leaf_op()
Definition: funcimpl.h:500
std::pair< bool, T > eval_local_only(const Vector< double, NDIM > &xin, Level maxlevel)
Evaluate function only if point is local returning (true,value); otherwise return (false...
Definition: mraimpl.h:2771
const keyT & key0() const
Definition: mraimpl.h:348
bool operator()(typename rangeT::iterator &it) const
iterator it points to this
Definition: funcimpl.h:2161
const FunctionImpl< T, NDIM > * f
Definition: funcimpl.h:496
Definition: function_common_data.h:127
opT leaf_op
deciding if a given FunctionNode will be a leaf node
Definition: funcimpl.h:3340
ctT f
tracking coeffs of first and second addend
Definition: funcimpl.h:2964
bool has_children() const
Definition: funcimpl.h:729
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
void gaxpy_oop_reconstructed(const double alpha, const implT &f, const double beta, const implT &g, const bool fence)
perform: this= alpha*f + beta*g, invoked by result
Definition: mraimpl.h:203
T operator()(typename dcT::const_iterator &it) const
Definition: funcimpl.h:4902
void serialize(const Archive &ar)
Definition: funcimpl.h:1942
this_type make_child(const keyT &child) const
Definition: funcimpl.h:2986
Key< OPDIM > key
Definition: funcimpl.h:3931
T alpha
Definition: funcimpl.h:2089
const mpreal log10(const mpreal &v, mp_rnd_t rnd_mode)
Definition: mpreal.h:2227
Range< typename dcT::iterator > rangeT
Definition: funcimpl.h:1949
const mpreal min(const mpreal &x, const mpreal &y)
Definition: mpreal.h:2675
Tensor< TENSOR_RESULT_TYPE(T, Q)> transform_dir(const Tensor< T > &t, const Tensor< Q > &c, int axis)
Transforms one dimension of the tensor t by the matrix c, returns new contiguous tensor.
Definition: tensor.h:1929
std::pair< bool, coeffT > operator()(const Key< NDIM > &key) const
make the NS-coefficients and send off the application of the operator
Definition: funcimpl.h:4327
Definition: funcimpl.h:76
Range< typename dcT::const_iterator > rangeT
Definition: funcimpl.h:4673
void store(Archive &ar)
Definition: funcimpl.h:1150
double alpha
prefactor for f, g
Definition: funcimpl.h:2966
change representation of nodes' coeffs to low rank, optional fence
Definition: funcimpl.h:2185
do_average()
Definition: funcimpl.h:2157
CoeffTracker< T, LDIM > ctL
Definition: funcimpl.h:3048
hartree_op< LDIM, leaf_opT > this_type
Definition: funcimpl.h:3047
FunctionNode< T, NDIM > nodeT
Definition: funcimpl.h:688
do_gaxpy_inplace()
Definition: funcimpl.h:1108
recursive_apply_op()
Definition: funcimpl.h:4313
TENSOR_RESULT_TYPE(T, R) inner_local(const FunctionImpl<R
Returns the inner product ASSUMING same distribution.
coeffT make_redundant_op(const keyT &key, const std::vector< Future< coeffT > > &v)
similar to compress_op, but insert only the sum coefficients in the tree
Definition: mraimpl.h:1714
FLOAT a(int j, FLOAT z)
Definition: y1.cc:86
void accumulate(const double time) const
accumulate timer
Definition: function_common_data.h:141
void project_out(FunctionImpl< T, NDIM-LDIM > *result, const FunctionImpl< T, LDIM > *gimpl, const int dim, const bool fence)
project the low-dim function g on the hi-dim function f: result(x) = ...
Definition: funcimpl.h:5084
void replace(const pairT &datum)
Inserts/replaces key+value pair (non-blocking communication if key not local)
Definition: worlddc.h:727
multiply_op()
Definition: funcimpl.h:2848
Void do_project_out(const coeffT &fcoeff, const std::pair< keyT, coeffT > gpair, const keyT &gkey, const Key< NDIM > &dest, const int dim) const
compute the inner product of two nodes of only some dimensions and accumulate on result ...
Definition: funcimpl.h:5274
std::shared_ptr< implL > impl_p1
supposedly orbital 1
Definition: function_interface.h:155
double do_apply_kernel3(const opT *op, const GenTensor< R > &coeff, const do_op_args< OPDIM > &args, const TensorArgs &apply_targs)
same as do_apply_kernel2, but use low rank tensors as input and low rank tensors as output ...
Definition: funcimpl.h:4020
void serialize(const Archive &ar)
Definition: funcimpl.h:2219
void reset_timer()
Definition: mraimpl.h:320
void serialize(Archive &ar)
Definition: funcimpl.h:679
Provides IndexIterator.
void print_grid(const std::string filename) const
Definition: mraimpl.h:499
do_change_tensor_type()
Definition: funcimpl.h:2192
bool operator()(typename rangeT::iterator &it) const
return the norm of the difference of this node and its "mirror" node
Definition: funcimpl.h:2096
recursive_apply_op< opT, LDIM > this_type
Definition: funcimpl.h:4305
Level level() const
Definition: key.h:220
Void binaryXXa(const keyT &key, const FunctionImpl< L, NDIM > *left, const Tensor< L > &lcin, const FunctionImpl< R, NDIM > *right, const Tensor< R > &rcin, const opT &op)
Definition: funcimpl.h:2533
void reduce_rank(const double &eps)
Definition: gentensor.h:193
do_reduce_rank(const double &thresh)
Definition: funcimpl.h:1995
Default load of a thingy via serialize(ar,t)
Definition: archive.h:718
Void do_apply_kernel(const opT *op, const Tensor< R > &c, const do_op_args< OPDIM > &args)
for fine-grain parallelism: call the apply method of an operator in a separate task ...
Definition: funcimpl.h:3950
CoeffTracker< T, LDIM > iaf
Definition: funcimpl.h:4308
static const FunctionCommonData< T, NDIM > & get(int k)
Definition: function_common_data.h:111
ProcessID random_proc()
Returns a random process number [0,world.size())
Definition: worldfwd.h:690
coeffT upsample(const keyT &key, const coeffT &coeff) const
upsample the sum coefficients of level 1 to sum coeffs on level n+1
Definition: mraimpl.h:1267
void print_tree(std::ostream &os=std::cout, Level maxlevel=10000) const
Definition: mraimpl.h:2583
bool log
Definition: funcimpl.h:1252
void truncate(double tol, bool fence)
Truncate according to the threshold with optional global fence.
Definition: mraimpl.h:332
TensorArgs holds the arguments for creating a LowRankTensor.
Definition: gentensor.h:127
ctL iav1
Definition: funcimpl.h:3343
Void reconstruct_op(const keyT &key, const coeffT &s)
Definition: mraimpl.h:1992
bool _empty
Definition: function_factory.h:90
Future< this_type > activate() const
Definition: funcimpl.h:2938
enable_if_c< NDIM==FDIM >::type read_grid(const std::string keyfile, const std::string gridfile, std::shared_ptr< FunctionFunctorInterface< double, NDIM > > vnuc_functor)
read data from a grid
Definition: funcimpl.h:1312
FunctionNode< T, NDIM > & operator=(const FunctionNode< T, NDIM > &other)
Definition: funcimpl.h:167
resultT operator()(resultT a, resultT b) const
Definition: funcimpl.h:4658
void operator()(const keyT &key, const coeffT &coeff, const bool &is_leaf) const
Definition: funcimpl.h:694
project_out_op(const project_out_op &other)
Definition: funcimpl.h:5127
double check_symmetry_local() const
Returns some asymmetry measure ... no comms.
Definition: mraimpl.h:840
coeff_value_adaptor()
Definition: funcimpl.h:2599
ctL p1
Definition: funcimpl.h:3051
Void evalR(const Vector< double, NDIM > &xin, const keyT &keyin, const typename Future< long >::remote_refT &ref)
Get the rank of leaf box of the tree at a point in simulation coordinates.
Definition: mraimpl.h:2842
Definition: tensor.h:275
shallow-copy, pared-down version of FunctionNode, for special purpose only
Definition: funcimpl.h:717
void broaden(std::vector< bool > is_periodic, bool fence)
Definition: mraimpl.h:1338
laziness
Definition: funcimpl.h:3930
LevelPmap()
Definition: funcimpl.h:108
FunctionImpl< Q, NDIM > * other
Definition: funcimpl.h:2088
Implements the functionality of Futures.
Definition: worldfut.h:157
void flo_unary_op_node_inplace(const opT &op, bool fence)
Unary operation applied inplace to the coefficients WITHOUT refinement, optional fence.
Definition: funcimpl.h:1897
map this on f
Definition: funcimpl.h:2122
do_truncate_NS_leafs(const implT *f)
Definition: funcimpl.h:1926
this_type make_child(const keyT &child) const
Definition: funcimpl.h:4376
return world taskq reduce(rangeT(coeffs.begin(), coeffs.end()), do_inner_local< R >(&g, leaves_only))
An integer with atomic set, get, read+inc, read+dec, dec+test operations.
Definition: atomicint.h:73
double operator()(typename dcT::const_iterator &it) const
Definition: funcimpl.h:4561
const implT * get_impl() const
const reference to impl
Definition: funcimpl.h:794
bool truncate_op(const keyT &key, double tol, const std::vector< Future< bool > > &v)
Actually do the truncate operation.
Definition: mraimpl.h:2555
const FunctionImpl< R, NDIM > * other
Definition: funcimpl.h:4626
Range< typename dcT::iterator > rangeT
Definition: funcimpl.h:2123
bool operator()(const implT *f, const keyT &key, const nodeT &t) const
Definition: funcimpl.h:3758
bool operator()(const Key< NDIM > &key, const double &cnorm) const
post-determination: return true if operator and coefficient norms are small
Definition: funcimpl.h:578
this_type forward_ctor(implT *result1, const opT &leaf_op, const ctT &iaket1, const ctL &iap11, const ctL &iap21, const ctL &iav11, const ctL &iav21, const implT *eri1)
Definition: funcimpl.h:3578
bool & is_on_demand()
Definition: mraimpl.h:269
static void load(const Archive &ar, std::shared_ptr< const FunctionImpl< T, NDIM > > &ptr)
Definition: funcimpl.h:5423
Implements most parts of a globally addressable object (via unique ID)
Definition: worldam.h:74
GenTensor< Q > values2NScoeffs(const keyT &key, const GenTensor< Q > &values) const
convert function values of the a child generation directly to NS coeffs
Definition: funcimpl.h:1666
opT * apply_op
Definition: funcimpl.h:4310
int particle
if g is g(1) or g(2)
Definition: funcimpl.h:2846
const implT * impl
Definition: funcimpl.h:4871
void set_thresh(double value)
Definition: mraimpl.h:284
bool is_nonstandard() const
Definition: mraimpl.h:242
tensorT sqrt(const tensorT &s, double tol=1e-8)
Computes matrix square root (not used any more?)
Definition: DFcode/moldft.cc:446
Void gaxpy_ext_recursive(const keyT &key, const FunctionImpl< L, NDIM > *left, Tensor< L > lcin, tensorT c, T(*f)(const coordT &), T alpha, T beta, double tol, bool below_leaf)
Definition: funcimpl.h:4981
bool operator()(typename rangeT::iterator &it) const
Definition: funcimpl.h:1973
A parallel world with full functionality wrapping an MPI communicator.
Definition: worldfwd.h:416
void fence()
Synchronizes all processes in communicator AND globally ensures no pending AM or tasks.
Definition: worldgop.cc:52
TensorType tensor_type() const
Definition: gentensor.h:197
do_convert_to_color()
Definition: funcimpl.h:1254
Timer timer_filter
Definition: funcimpl.h:945
leaf_op()
Definition: funcimpl.h:439
std::shared_ptr< FunctionFunctorInterface< T, NDIM > > get_functor()
Definition: mraimpl.h:251
hartree_convolute_leaf_op()
Definition: funcimpl.h:613
std::shared_ptr< FunctionImpl< T, NDIM > > pimplT
pointer to this class
Definition: funcimpl.h:903
keep only the sum coefficients in each node
Definition: funcimpl.h:1966
Hartree product of two LDIM functions to yield a NDIM = 2*LDIM function.
Definition: funcimpl.h:3044
void reduce_rank(const TensorArgs &targs, bool fence)
reduce the rank of the coefficients tensors
Definition: mraimpl.h:1169
void reconstruct(bool fence)
Definition: mraimpl.h:1444
std::size_t hashT
The hash value type.
Definition: worldhash.h:148
T inner_ext_local(T(*f)(const coordT &), const bool leaf_refine) const
Definition: funcimpl.h:4925
Void project_refine_op(const keyT &key, bool do_refine, const std::vector< Vector< double, NDIM > > &specialpts)
Projection with optional refinement.
Definition: mraimpl.h:2368
Void refine_spawn(const opT &op, const keyT &key)
Definition: funcimpl.h:3790
argT finalize(const double kernel_norm, const keyT &key, const coeffT &coeff, const implT *r) const
sole purpose is to wait for the kernel norm, wrap it and send it back to caller
Definition: funcimpl.h:4479
implT * result
where to construct Vphi, no need to track parents
Definition: funcimpl.h:3339
bool insert(accessor &acc, const keyT &key)
Write access to LOCAL value by key. Returns true if inserted, false if already exists (throws if remo...
Definition: worlddc.h:754
perform this multiplication: h(1,2) = f(1,2) * g(1)
Definition: funcimpl.h:2836
Void consolidate_buffer(const TensorArgs &args)
Definition: funcimpl.h:397
void serialize(const Archive &ar)
Definition: funcimpl.h:4890
void load(Archive &ar)
Definition: funcimpl.h:1134
bool randomize() const
Definition: funcimpl.h:4303
int Level
Definition: key.h:58
GenTensor< Q > NS_fcube_for_mul(const keyT &child, const keyT &parent, const GenTensor< Q > &coeff, const bool s_only) const
Compute the function values for multiplication.
Definition: funcimpl.h:1617
Void multiop_values_doit(const keyT &key, const opT &op, const std::vector< implT * > &v)
Definition: funcimpl.h:2307
World & world
Definition: funcimpl.h:916
typedef TENSOR_RESULT_TYPE(T, R) resultT
int ProcessID
Used to clearly identify process number/rank.
Definition: worldtypes.h:37
const implT * f
the source or result function, needed for truncate_tol
Definition: funcimpl.h:561
GenTensor< T > coeffT
Definition: funcimpl.h:718
implT * impl
Definition: funcimpl.h:2227
Future< MEMFUN_RETURNT(memfunT) > send(const keyT &key, memfunT memfun)
Sends message "resultT memfun()" to item (non-blocking comm if remote)
Definition: worlddc.h:919
T trace_local() const
Returns int(f(x),x) in local volume.
Definition: mraimpl.h:3000
FunctionImpl< T, NDIM-LDIM > implL1
Definition: funcimpl.h:5115
Definition: funcimpl.h:3757
project_out_op()
Definition: funcimpl.h:5124
std::pair< bool, coeffT > argT
Definition: funcimpl.h:4435
tensorT eri_values(const keyT &key) const
return the values of the 2-particle potential
Definition: funcimpl.h:3465
void print_size(const std::string name) const
print tree size and size
Definition: mraimpl.h:1874
const mpreal sum(const mpreal tab[], unsigned long int n, mp_rnd_t rnd_mode)
Definition: mpreal.cc:241
FunctionNode holds the coefficients, etc., at each node of the 2^NDIM-tree.
Definition: derivative.h:58
Tri-diagonal operator traversing tree primarily for derivative operator.
Definition: derivative.h:73
std::shared_ptr< implT > impl_eri
supposedly 1/r12
Definition: function_interface.h:150
Abstract base class interface required for functors used as input to Functions.
Definition: function_interface.h:58
R beta
Definition: funcimpl.h:2090
Tensor< T > eval_plot_cube(const coordT &plotlo, const coordT &plothi, const std::vector< long > &npt, const bool eval_refine=false) const
Evaluate a cube/slice of points ... plotlo and plothi are already in simulation coordinates.
Definition: mraimpl.h:3192
ProcessID rank() const
Returns the process rank in this world (same as MPI_Comm_rank()))
Definition: worldfwd.h:526
Void accumulate_timer(const double time) const
Definition: mraimpl.h:305
void serialize(Archive &ar)
Definition: funcimpl.h:2613
check symmetry wrt particle exchange
Definition: funcimpl.h:2012
Void refine_op(const opT &op, const keyT &key)
Definition: funcimpl.h:3765
archive_array< unsigned char > wrap_opaque(const T *, unsigned int)
Factory function to wrap pointer to contiguous data as opaque (uchar) archive_array.
Definition: archive.h:827
double finalize_apply(const bool fence=true)
after apply we need to do some cleanup;
Definition: mraimpl.h:1741
project the low-dim function g on the hi-dim function f: result(x) = ...
Definition: funcimpl.h:5110
static void store(const Archive &ar, const FunctionImpl< T, NDIM > *const &ptr)
Definition: funcimpl.h:5385
project_out_op< LDIM > this_type
Definition: funcimpl.h:5113
void norm_tree(bool fence)
compute for each FunctionNode the norm of the function inside that node
Definition: mraimpl.h:1514
Void set_has_children(bool flag)
Sets has_children attribute to value of flag.
Definition: funcimpl.h:244
bool operator()(const Key< NDIM > &key) const
no pre-determination
Definition: funcimpl.h:504
ProcessID owner(const keyT &key) const
Returns processor that logically owns key (no communication)
Definition: worlddc.h:786
static void store(const Archive &ar, const std::shared_ptr< FunctionImpl< T, NDIM > > &ptr)
Definition: funcimpl.h:5448
bool randomize() const
Definition: funcimpl.h:3045
bool operator()(const Key< NDIM > &key, const T &t, const R &r) const
Definition: funcimpl.h:710
void serialize(Archive &ar)
Definition: funcimpl.h:448
void print_stats() const
print the number of configurations per node
Definition: mraimpl.h:1898
void add(TaskInterface *t)
Add a new local task taking ownership of the pointer.
Definition: worldtask.h:473
GenTensor< T > full_tensor() const
Definition: gentensor.h:182
recursive_apply_op(const recursive_apply_op &other)
Definition: funcimpl.h:4320
recursive_apply_op(implT *result, const CoeffTracker< T, LDIM > &iaf, const CoeffTracker< T, LDIM > &iag, const opT *apply_op)
Definition: funcimpl.h:4314
void unaryXXvalues(const FunctionImpl< Q, NDIM > *func, const opT &op, bool fence)
Definition: funcimpl.h:2674
WorldTaskQueue & taskq
Task queue.
Definition: worldfwd.h:461
Void broaden_op(const keyT &key, const std::vector< Future< bool > > &v)
Definition: mraimpl.h:1317
GenTensor< T > outer_low_rank(const Tensor< T > &left, const Tensor< T > &right)
Outer product ... result(i,j,...,p,q,...) = left(i,k,...)*right(p,q,...)
Definition: gentensor.h:238
ctT f
Definition: funcimpl.h:2844
bool is_redundant() const
Returns true if the function is redundant.
Definition: mraimpl.h:237
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
long box_leaf[1000]
Definition: funcimpl.h:2698
iteratorT iterator
Definition: worldrange.h:55
Definition: funcimpl.h:603
std::size_t tree_size() const
Returns the size of the tree structure of the function ... collective global sum. ...
Definition: mraimpl.h:1820
const implT * f
Definition: funcimpl.h:436
Vphi_op_NS< opT, LDIM > this_type
Definition: funcimpl.h:3335
Timer timer_compress_svd
Definition: funcimpl.h:946
remote_refT remote_ref(World &world) const
Returns a structure used to pass references to another process.
Definition: worldfut.h:552
std::pair< bool, coeffT > argT
Definition: funcimpl.h:5116
Range vaguely a la Intel TBB encapsulates random-access STL-like start and end iterators with chunksi...
Definition: worldrange.h:49
ProcessID owner(const keyT &key) const
Find the owner of a given key.
Definition: funcimpl.h:113
implT * h
the result function h(1,2) = f(1,2) * g(1)
Definition: funcimpl.h:2843
void serialize(Archive &ar)
Definition: funcimpl.h:488
const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > & get_pmap() const
Definition: mraimpl.h:187
void clear_coeff()
Clears the coefficients (has_coeff() will subsequently return false)
Definition: funcimpl.h:284
long size() const
Returns the number of elements in the tensor.
Definition: basetensor.h:138
bool do_error_leaf_op() const
Definition: funcimpl.h:562
T operator()(typename dcT::const_iterator &it) const
Definition: funcimpl.h:4876
bool randomize() const
Definition: funcimpl.h:5111
void diff(const DerivativeBase< T, NDIM > *D, const implT *f, bool fence)
Definition: mraimpl.h:1035
void operator()(const Key< NDIM > &key, const GenTensor< T > &coeff, const bool &is_leaf) const
Definition: funcimpl.h:674
Future< bool > truncate_spawn(const keyT &key, double tol)
Returns true if after truncation this node has coefficients.
Definition: mraimpl.h:2519
bool operator()(const Key< NDIM > &key, const GenTensor< T > &coeff=GenTensor< T >()) const
pre/post-determination is the same here
Definition: funcimpl.h:443
void serialize(const Archive &ar)
Definition: funcimpl.h:2949
do_err_box(const implT *impl, const opT *func, int npt, const Tensor< double > &qx, const Tensor< double > &quad_phit, const Tensor< double > &quad_phiw)
Definition: funcimpl.h:4554
Future< resultT > reduce(const rangeT &range, const opT &op)
Reduce op(item) for all items in range using op(sum,op(item))
Definition: worldtask.h:516
void normalize()
Definition: gentensor.h:194
A simple process map.
Definition: funcimpl.h:85
bool do_error_leaf_op() const
Definition: funcimpl.h:611
void serialize(Archive &ar)
Definition: funcimpl.h:1118
Definition: funcimpl.h:704
enable_if_c< NDIM==FDIM >::type read_grid2(const std::string gridfile, std::shared_ptr< FunctionFunctorInterface< double, NDIM > > vnuc_functor)
read data from a grid
Definition: funcimpl.h:1420
void serialize(const Archive &ar)
Definition: funcimpl.h:2181
Range< typename dcT::const_iterator > rangeT
Definition: funcimpl.h:2087
T * ptr_from_id(uniqueidT id) const
Look up local pointer from world-wide unique id.
Definition: worldfwd.h:597
double err_box(const keyT &key, const nodeT &node, const opT &func, int npt, const Tensor< double > &qx, const Tensor< double > &quad_phit, const Tensor< double > &quad_phiw) const
Returns the square of the error norm in the box labeled by key.
Definition: funcimpl.h:4514
static const Tensor< double > & get_cell_width()
Returns the width of each user cell dimension.
Definition: funcdefaults.h:391
void standard(bool fence)
Changes non-standard compressed form to standard compressed form.
Definition: mraimpl.h:1732
CoeffTracker()
default ctor
Definition: funcimpl.h:775
Future< this_type > activate() const
Definition: funcimpl.h:3567
Vphi_op_NS(implT *result, const opT &leaf_op, const ctT &iaket, const ctL &iap1, const ctL &iap2, const ctL &iav1, const ctL &iav2, const implT *eri)
Definition: funcimpl.h:3348
opT::resultT resultT
Definition: funcimpl.h:2595
Key< NDIM > simpt2key(const coordT &pt, Level n) const
Returns the box at level n that contains the given point in simulation coordinates.
Definition: mraimpl.h:694
TensorArgs targs
Definition: funcimpl.h:2210
GenTensor< Q > values2coeffs(const keyT &key, const GenTensor< Q > &values) const
Definition: funcimpl.h:1695
NDIM &g const
Definition: funcimpl.h:4671
A future is a possibly yet unevaluated value.
Definition: ref.h:210
void set_is_leaf(bool flag)
Sets has_children attribute to value of !flag.
Definition: funcimpl.h:269
A type you can return when you want to return void ... use "return None".
Definition: typestuff.h:154
void serialize(Archive &ar)
Definition: funcimpl.h:667
Tensor< double > hg
Definition: function_common_data.h:107
void fcube(const keyT &key, const FunctionFunctorInterface< T, NDIM > &f, const Tensor< double > &qx, tensorT &fval) const
Evaluate function at quadrature points in the specified box.
Definition: mraimpl.h:2356
double do_apply_directed_screening(const opT *op, const keyT &key, const coeffT &coeff, const bool &do_kernel)
apply an operator on the coeffs c (at node key)
Definition: funcimpl.h:4147
bool exists_and_has_children(const keyT &key) const
Definition: mraimpl.h:1306
tensorT coeffs_for_jun(Level n, long q=0)
Get the scaling function coeffs at level n starting from NS form.
Definition: mraimpl.h:708
const FunctionImpl< Q, NDIM > * impl_func
Definition: funcimpl.h:2596
void serialize(const Archive &ar)
Definition: funcimpl.h:4504
this_type make_child(const keyT &child) const
Definition: funcimpl.h:2928
Tensor< TENSOR_RESULT_TYPE(T, Q) > & fast_transform(const Tensor< T > &t, const Tensor< Q > &c, Tensor< TENSOR_RESULT_TYPE(T, Q) > &result, Tensor< TENSOR_RESULT_TYPE(T, Q) > &workspace)
Restricted but heavily optimized form of transform()
Definition: tensor.h:2351
bool operator()(const Key< NDIM > &key, const GenTensor< T > &coeff) const
no post-determination
Definition: funcimpl.h:469
std::pair< const keyT, nodeT > datumT
Type of entry in container.
Definition: funcimpl.h:910
coeffT coeff(const keyT &key) const
return the coefficients belonging to the passed-in key
Definition: funcimpl.h:808
Tensor< double > op(const Tensor< double > &x)
Definition: kain.cc:508
Slice s[4]
s[0]=Slice(0,k-1), s[1]=Slice(k,2*k-1), etc.
Definition: function_common_data.h:90
Interface to be provided by any process map.
Definition: worlddc.h:64
Future< REMFUTURE(MEMFUN_RETURNT(memfunT)) > task(const keyT &key, memfunT memfun, const TaskAttributes &attr=TaskAttributes())
Adds task "resultT memfun()" in process owning item (non-blocking comm if remote) ...
Definition: worlddc.h:1148
bool operator()(typename rangeT::iterator &it) const
Definition: funcimpl.h:1954
CoeffTracker(const CoeffTracker &other)
copy ctor
Definition: funcimpl.h:790
void serialize(const Archive &ar)
serialize this (needed for use in recursive_op)
Definition: funcimpl.h:3585
implT * result
Definition: funcimpl.h:4307
const T1 & f1
Definition: gtest-tuple.h:680
GenTensor< Q > coeffs2values(const keyT &key, const GenTensor< Q > &coeff) const
Definition: funcimpl.h:1565
double limit
Definition: funcimpl.h:1251
tensorT make_childrens_sum_coeffs(const keyT &key) const
make the sum coeffs for all children of key
Definition: funcimpl.h:3506
coeffT make_sum_coeffs(const keyT &key) const
make the sum coeffs for key
Definition: funcimpl.h:3480
void print(const A &a)
Print a single item to std::cout terminating with new line.
Definition: print.h:122
FunctionCommonData holds all Function data common for given k.
Definition: function_common_data.h:52
int npt
no. of quadrature points
Definition: function_common_data.h:89
Key< NDIM > keyT
Definition: funcimpl.h:686
coeffT assemble_coefficients(const keyT &key, const coeffT &coeff_ket, const coeffT &vpotential1, const coeffT &vpotential2, const tensorT &veri) const
given several coefficient tensors, assemble a result tensor
Definition: mraimpl.h:1099
R beta
Definition: funcimpl.h:1107
long box_interior[1000]
Definition: funcimpl.h:2699
void project_out2(const FunctionImpl< T, LDIM+NDIM > *f, const FunctionImpl< T, LDIM > *g, const int dim)
project the low-dim function g on the hi-dim function f: this(x) = ...
Definition: funcimpl.h:5217
void gaxpy_inplace_reconstructed(const T &alpha, const FunctionImpl< Q, NDIM > &g, const R &beta, const bool fence)
perform inplace gaxpy: this = alpha*this + beta*other
Definition: funcimpl.h:1064
bool _has_children
Definition: funcimpl.h:720
#define MADNESS_EXCEPTION(msg, value)
Definition: worldexc.h:88
GenTensor< T > coeffT
Definition: funcimpl.h:687
tensorT filter(const tensorT &s) const
Transform sum coefficients at level n to sums+differences at level n-1.
Definition: mraimpl.h:1188
void print_info() const
Prints summary of data distribution.
Definition: mraimpl.h:921
Tensor< Q > coeffs2values(const keyT &key, const Tensor< Q > &coeff) const
Definition: funcimpl.h:1688
A slice defines a sub-range or patch of a dimension.
Definition: slice.h:103
Future< coeffT > compress_spawn(const keyT &key, bool nonstandard, bool keepleaves, bool redundant)
Definition: mraimpl.h:3070
bool operator()(typename rangeT::iterator &it) const
Definition: funcimpl.h:1110
const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > fref
Definition: funcimpl.h:4896
bool exists_and_is_leaf(const keyT &key) const
Definition: mraimpl.h:1311
FunctionNode< Q, NDIM > convert() const
Copy with possible type conversion of coefficients, copying all other state.
Definition: funcimpl.h:182
Void do_print_plane(const std::string filename, std::vector< Tensor< double > > plotinfo, const int xaxis, const int yaxis, const coordT el2)
print the MRA structure
Definition: mraimpl.h:454
FunctionImpl(const FunctionImpl< Q, NDIM > &other, const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > &pmap, bool dozero)
Copy constructor.
Definition: funcimpl.h:1014
Multidimension Key for MRA tree and associated iterators.
Tensor< T > tensorT
Definition: funcimpl.h:129
long k
Definition: funcimpl.h:497
void serialize(Archive &ar)
Definition: funcimpl.h:549
void serialize(const Archive &ar)
Definition: funcimpl.h:3105
do_op_args(const Key< OPDIM > &key, const Key< OPDIM > &d, const keyT &dest, double tol, double fac, double cnorm)
Definition: funcimpl.h:3935
Definition: gentensor.h:123
multiply_op(implT *h, const ctT &f, const ctL &g, const int particle)
Definition: funcimpl.h:2850
double operator()(typename rangeT::iterator &it) const
return the norm of the difference of this node and its "mirror" node
Definition: funcimpl.h:2019
Future< double > norm_tree_spawn(const keyT &key)
Definition: mraimpl.h:1537
coeffT _coeffs
Definition: funcimpl.h:719
FunctionNode(const FunctionNode< T, NDIM > &other)
Definition: funcimpl.h:162
FunctionNode< T, NDIM > nodeT
Type of node.
Definition: funcimpl.h:907
bool get_autorefine() const
Definition: mraimpl.h:287
Vector< Translation, NDIM > tranT
Type of array holding translation.
Definition: funcimpl.h:905
static void store(const Archive &ar, FunctionImpl< T, NDIM > *const &ptr)
Definition: funcimpl.h:5413
void gaxpy_inplace(const T &alpha, const FunctionImpl< Q, NDIM > &other, const R &beta, bool fence)
Inplace general bilinear operation.
Definition: funcimpl.h:1123
FunctionFactory implements the named-parameter idiom for Function.
Definition: funcimpl.h:70
FunctionImpl< T, LDIM > implL
Definition: funcimpl.h:606
const coeffT & coeff() const
Returns a const reference to the tensor containing the coeffs.
Definition: funcimpl.h:226
bool autorefine_square_test(const keyT &key, const nodeT &t) const
Returns true if this block of coeffs needs autorefining.
Definition: mraimpl.h:953
const opT * op
Definition: funcimpl.h:610
Definition: tensor.h:275
void undo_redundant(const bool fence)
convert this from redundant to standard reconstructed form
Definition: mraimpl.h:1504
Void eval(const Vector< double, NDIM > &xin, const keyT &keyin, const typename Future< T >::remote_refT &ref)
Evaluate the function at a point in simulation coordinates.
Definition: mraimpl.h:2727
double norm2sq_local() const
Returns the square of the local norm ... no comms.
Definition: mraimpl.h:1768
ctL iag
Definition: funcimpl.h:5120
int64_t Translation
Definition: key.h:57
Definition: funcimpl.h:673
reduce the rank of the nodes, optional fence
Definition: funcimpl.h:1986
void make_Vphi(const opT &leaf_op, const bool fence=true)
assemble the function V*phi using V and phi given from the functor
Definition: funcimpl.h:3598
do_standard()
Definition: funcimpl.h:3902
add two functions f and g: result=alpha * f + beta * g
Definition: funcimpl.h:2956
const mpreal fabs(const mpreal &v, mp_rnd_t rnd_mode)
Definition: mpreal.h:2187
returns true if the node is well represented compared to its parent
Definition: funcimpl.h:456
void gaxpy(T alpha, const FunctionImpl< L, NDIM > &left, T beta, const FunctionImpl< R, NDIM > &right, bool fence)
Invoked by result to perform result += alpha*left+beta*right in wavelet basis.
Definition: funcimpl.h:1837
Holds machinery to set up Functions/FuncImpls using various Factories and Interfaces.
Definition: chem/atomutil.cc:45
const dcT & get_coeffs() const
Definition: mraimpl.h:296
coeffT & coeff()
Definition: funcimpl.h:728
Key< NDIM > key0
Key for root node.
Definition: function_common_data.h:97
CoeffTracker(const CoeffTracker &other, const datumT &datum)
ctor with a pair
Definition: funcimpl.h:783
const double c
Definition: gfit.cc:200
std::shared_ptr< implL > impl_m1
various MRA functions of MDIM dimensionality (e.g. 3, if NDIM==6)
Definition: function_interface.h:153
std::pair< bool, coeffT > finalize(const double kernel_norm, const keyT &key, const coeffT &coeff) const
sole purpose is to wait for the kernel norm, wrap it and send it back to caller
Definition: funcimpl.h:4367
void serialize(const Archive &ar)
Definition: funcimpl.h:1960
bool _refine
Definition: function_factory.h:89
std::vector< Function< TENSOR_RESULT_TYPE(T, R), NDIM > > transform(World &world, const std::vector< Function< T, NDIM > > &v, const DistributedMatrix< R > &c, bool fence=true)
Definition: chem/SCF.cc:86
op_leaf_op()
Definition: funcimpl.h:564
Range< typename dcT::const_iterator > rangeT
Definition: funcimpl.h:2013
Future< this_type > activate() const
retrieve the coefficients (parent coeffs might be remote)
Definition: funcimpl.h:2991
FLOAT b(int j, FLOAT z)
Definition: y1.cc:79
double accumulate2(const tensorT &t, const typename FunctionNode< T, NDIM >::dcT &c, const Key< NDIM > &key)
Accumulate inplace and if necessary connect node to parent.
Definition: funcimpl.h:330
Tensor< double > quad_phit
transpose of quad_phi
Definition: function_common_data.h:102
void print_timer() const
Definition: mraimpl.h:311
std::pair< bool, coeffT > operator()(const Key< NDIM > &key) const
Definition: funcimpl.h:3061
Tensor< double > quad_phiw
quad_phiw(i,j) = at x[i] value of w[i]*phi[j]
Definition: function_common_data.h:103
void swap(mpfr::mpreal &x, mpfr::mpreal &y)
Definition: mpreal.h:3069
this_type forward_ctor(implT *r, const CoeffTracker< T, LDIM > &f1, const CoeffTracker< T, LDIM > &g1, const opT *apply_op1)
Definition: funcimpl.h:4392
void apply(opT &op, const FunctionImpl< R, NDIM > &f, bool fence)
apply an operator on f to return this
Definition: funcimpl.h:4114
Timer timer_lr_result
Definition: funcimpl.h:944
Void do_mul(const keyT &key, const Tensor< L > &left, const std::pair< keyT, Tensor< R > > &arg)
Invoked as a task by mul with the actual coefficients.
Definition: funcimpl.h:1760
Definition: funcimpl.h:4598
Key is the index for a node of the 2^NDIM-tree.
Definition: key.h:69
tensorT unfilter(const tensorT &s) const
Transform sums+differences at level n to sum coefficients at level n+1.
Definition: mraimpl.h:1217
AtomicInt large
Definition: funcimpl.h:950
argT operator()(const Key< NDIM > &key) const
send off the application of the operator
Definition: funcimpl.h:4455
static void load(const Archive &ar, const FunctionImpl< T, NDIM > *&ptr)
Definition: funcimpl.h:5366
ProcessID owner(const keyT &key) const
Maps key to processor.
Definition: funcimpl.h:94
const coeffT & coeff() const
const reference to the coeffs
Definition: funcimpl.h:797
tensorT project(const keyT &key) const
Compute by projection the scaling function coeffs in specified box.
Definition: mraimpl.h:2646
MADNESS_ASSERT(this->is_redundant()==g.is_redundant())
insert_op(implT *f)
Definition: funcimpl.h:692
Future< CoeffTracker > activate() const
find the coefficients
Definition: funcimpl.h:845
bool do_new
Definition: funcimpl.h:948
double truncate_tol(double tol, const keyT &key) const
Returns the truncation threshold according to truncate_method.
Definition: mraimpl.h:613
const coeffT & coeff() const
Definition: funcimpl.h:727
void unset_functor()
Definition: mraimpl.h:263
TensorArgs get_tensor_args() const
Definition: mraimpl.h:278
bool operator()(const Key< NDIM > &key, const GenTensor< T > &fcoeff, const GenTensor< T > &gcoeff) const
Definition: funcimpl.h:675
keyT neighbor(const keyT &key, const keyT &disp, const std::vector< bool > &is_periodic) const
Returns key of general neighbor enforcing BC.
Definition: mraimpl.h:3042
do_mapdim()
Definition: funcimpl.h:2128
void mulXX(const FunctionImpl< L, NDIM > *left, const FunctionImpl< R, NDIM > *right, double tol, bool fence)
Definition: funcimpl.h:2643
void serialize(const Archive &ar)
Definition: funcimpl.h:4575
do_standard(implT *impl)
Definition: funcimpl.h:3903
CoeffTracker< T, NDIM > ctT
Definition: funcimpl.h:4434
implT * impl
Definition: funcimpl.h:3899
do_change_tensor_type(const TensorArgs &targs)
Definition: funcimpl.h:2193
add_op()
Definition: funcimpl.h:2968
void serialize(const Archive &ar)
Definition: funcimpl.h:2115
bool randomize() const
Definition: funcimpl.h:4431
ShallowNode(const ShallowNode< T, NDIM > &node)
Definition: funcimpl.h:724
T eval_cube(Level n, coordT &x, const tensorT &c) const
Definition: mraimpl.h:1938
Void forward_do_diff1(const DerivativeBase< T, NDIM > *D, const implT *f, const keyT &key, const std::pair< keyT, coeffT > &left, const std::pair< keyT, coeffT > &center, const std::pair< keyT, coeffT > &right)
Definition: mraimpl.h:1012
Range< typename dcT::iterator > rangeT
Definition: funcimpl.h:3896
void tnorm(const tensorT &t, double *lo, double *hi) const
Computes norm of low/high-order polyn. coeffs for autorefinement test.
Definition: mraimpl.h:2885
bool operator()(typename rangeT::iterator &it) const
Definition: funcimpl.h:3906
this_type forward_ctor(implT *result1, const ctL &p11, const ctL &p22, const leaf_opT &leaf_op)
Definition: funcimpl.h:3101
void sum_down(bool fence)
After 1d push operator must sum coeffs down the tree to restore correct scaling function coefficients...
Definition: mraimpl.h:1004
void flo_unary_op_node_inplace(const opT &op, bool fence) const
Unary operation applied inplace to the coefficients WITHOUT refinement, optional fence.
Definition: funcimpl.h:1907
void make_redundant(const bool fence)
convert this to redundant, i.e. have sum coefficients on all levels
Definition: mraimpl.h:1485
Void refine_to_common_level(const std::vector< FunctionImpl< T, NDIM > * > &v, const std::vector< tensorT > &c, const keyT key)
Refine multiple functions down to the same finest level.
Definition: mraimpl.h:854
void mapdim(const implT &f, const std::vector< long > &map, bool fence)
Permute the dimensions of f according to map, result on this.
Definition: mraimpl.h:1138
ctL iav2
potentials for particles 1 and 2
Definition: funcimpl.h:3343
long rank() const
Definition: gentensor.h:189
void serialize(const Archive &ar)
Definition: funcimpl.h:2203
Range< typename dcT::iterator > rangeT
Definition: funcimpl.h:2226
Iterates in lexical order thru all children of a key.
Definition: key.h:61
GenTensor< Q > fcube_for_mul(const keyT &child, const keyT &parent, const GenTensor< Q > &coeff) const
Compute the function values for multiplication.
Definition: funcimpl.h:1738
void serialize(Archive &ar)
Definition: funcimpl.h:3761
void serialize(Archive &ar)
Definition: funcimpl.h:711
bool operator()(typename rangeT::iterator &it) const
Definition: funcimpl.h:2000
const implT * f
Definition: funcimpl.h:2014
Void put_in_box(ProcessID from, long nl, long ni) const
Definition: mraimpl.h:911
bool probe(const keyT &key) const
Returns true if local data is immediately available (no communication)
Definition: worlddc.h:776