MADNESS 0.10.1
mra.h
Go to the documentation of this file.
1/*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30*/
31
32#ifndef MADNESS_MRA_MRA_H__INCLUDED
33#define MADNESS_MRA_MRA_H__INCLUDED
34
35/*!
36 \file mra/mra.h
37 \brief Main include file for MADNESS and defines \c Function interface
38
39 \addtogroup mra
40
41*/
42
43
45#include <madness/misc/misc.h>
47
48#define FUNCTION_INSTANTIATE_1
49#define FUNCTION_INSTANTIATE_2
50#define FUNCTION_INSTANTIATE_3
51#if !defined(HAVE_IBMBGP) || !defined(HAVE_IBMBGQ)
52#define FUNCTION_INSTANTIATE_4
53#define FUNCTION_INSTANTIATE_5
54#define FUNCTION_INSTANTIATE_6
55#endif
56
57static const bool VERIFY_TREE = false; //true
58
59
60namespace madness {
61 /// @brief initialize the internal state of the MADmra library
62 ///
63 /// Reads in (and broadcasts across \p world) the twoscale and autocorrelation coefficients,
64 /// Gauss-Legendre quadrature roots/weights, function defaults and operator displacement lists.
65 /// \warning By default this generates operator displacement lists (see Displacements) for up to 6-d free
66 /// and 3-d periodic boundary conditions. For optimal support for mixed boundary conditions
67 /// (periodic along some axes only) assign the desired boundary conditions
68 /// as default (e.g. `FunctionDefaults<3>::set_bc(BoundaryConditions<3>({BC_FREE, BC_FREE, BC_FREE, BC_FREE, BC_PERIODIC, BC_PERIODIC})`)
69 /// prior to calling this. This will make operator application with such boundary conditions
70 /// as efficient as possible, but will not allow the use of operators with
71 /// other boundary conditions that include periodic axes until Displacements::reset_periodic_axes is invoked.
72 /// By default efficiency is sacrificed for generality.
73 /// \param world broadcast data across this World
74 /// \param argc command-line parameter count
75 /// \param argv command-line parameters array
76 /// \param doprint if true, will log status to std::cout on rank 0 [default=false]
77 /// \param make_stdcout_nice_to_reals if true, will configure std::cout to print reals prettily, according to the MADNESS convention [default=true]
78 void startup(World& world, int argc, char** argv, bool doprint=false, bool make_stdcout_nice_to_reals = true);
79 std::string get_mra_data_dir();
80}
81
82#include <madness/mra/key.h>
85#include <madness/mra/indexit.h>
90#include <madness/mra/lbdeux.h>
92
93// some forward declarations
94namespace madness {
95
96 template<typename T, std::size_t NDIM>
97 class FunctionImpl;
98
99 template<typename T, std::size_t NDIM>
100 class Function;
101
102 template<typename T, std::size_t NDIM>
103 class FunctionNode;
104
105 template<typename T, std::size_t NDIM>
106 class FunctionFactory;
107
108 template<typename T, std::size_t NDIM>
109 class FunctionFunctorInterface;
110
111 template<typename T, std::size_t NDIM>
112 struct leaf_op;
113
114 template<typename T, std::size_t NDIM>
116
117 template<typename T, std::size_t NDIM>
118 struct hartree_leaf_op;
119
120 template<typename T, std::size_t NDIM, std::size_t LDIM, typename opT>
122
123 template<typename T, std::size_t NDIM, typename opT>
124 struct op_leaf_op;
125
126 template<typename T, std::size_t NDIM>
128
129}
130
131
132namespace madness {
133
134 /// \ingroup mra
135 /// \addtogroup function
136
137 /// A multiresolution adaptive numerical function
138 template <typename T, std::size_t NDIM>
140 // We make all of the content of Function and FunctionImpl
141 // public with the intent of avoiding the cumbersome forward
142 // and friend declarations. However, this open access should
143 // not be abused.
144
145 private:
146 std::shared_ptr< FunctionImpl<T,NDIM> > impl;
147
148 public:
149 bool impl_initialized()const{
150 if(impl==NULL) return false;
151 else return true;
152 }
156 typedef Vector<double,NDIM> coordT; ///< Type of vector holding coordinates
157 typedef T typeT;
158 static constexpr std::size_t dimT=NDIM;
159
160
161 /// Asserts that the function is initialized
162 inline void verify() const {
164 }
165
166 /// Returns true if the function is initialized
167 bool is_initialized() const {
168 return impl.get();
169 }
170
171 /// Default constructor makes uninitialized function. No communication.
172
173 /// An uninitialized function can only be assigned to. Any other operation will throw.
174 Function() : impl() {}
175
176
177 /// Constructor from FunctionFactory provides named parameter idiom. Possible non-blocking communication.
182
183
184 /// Copy constructor is \em shallow. No communication, works in either basis.
186 : impl(f.impl) {
187 }
188
189
190 /// Assignment is \em shallow. No communication, works in either basis.
193 if (this != &f) impl = f.impl;
194 return *this;
195 }
196
197 /// Destruction of any underlying implementation is deferred to next global fence.
199
200 /// implements swap algorithm
201 template <typename R, std::size_t MDIM>
203
204
205 /// Evaluates the function at a point in user coordinates. Possible non-blocking comm.
206
207 /// Only the invoking process will receive the result via the future
208 /// though other processes may be involved in the evaluation.
209 ///
210 /// Throws if function is not initialized.
211 Future<T> eval(const coordT& xuser) const {
213 const double eps=1e-15;
214 verify();
216 coordT xsim;
218 // If on the boundary, move the point just inside the
219 // volume so that the evaluation logic does not fail
220 for (std::size_t d=0; d<NDIM; ++d) {
221 if (xsim[d] < -eps) {
222 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
223 }
224 else if (xsim[d] < eps) {
225 xsim[d] = eps;
226 }
227
228 if (xsim[d] > 1.0+eps) {
229 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
230 }
231 else if (xsim[d] > 1.0-eps) {
232 xsim[d] = 1.0-eps;
233 }
234 }
235
236 Future<T> result;
237 impl->eval(xsim, impl->key0(), result.remote_ref(impl->world));
238 return result;
239 }
240
241 /// Evaluate function only if point is local returning (true,value); otherwise return (false,0.0)
242
243 /// maxlevel is the maximum depth to search down to --- the max local depth can be
244 /// computed with max_local_depth();
245 std::pair<bool,T> eval_local_only(const Vector<double,NDIM>& xuser, Level maxlevel) const {
246 const double eps=1e-15;
247 verify();
249 coordT xsim;
251 // If on the boundary, move the point just inside the
252 // volume so that the evaluation logic does not fail
253 for (std::size_t d=0; d<NDIM; ++d) {
254 if (xsim[d] < -eps) {
255 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
256 }
257 else if (xsim[d] < eps) {
258 xsim[d] = eps;
259 }
260
261 if (xsim[d] > 1.0+eps) {
262 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
263 }
264 else if (xsim[d] > 1.0-eps) {
265 xsim[d] = 1.0-eps;
266 }
267 }
268 return impl->eval_local_only(xsim,maxlevel);
269 }
270
271 /// Batched eval_local_only writing into a caller-provided buffer.
272
273 /// Resizes results to xuser.size() (reusing its capacity) and stores one
274 /// (local?,value) pair per input point, in input order: (true,value) if
275 /// the point is owned locally, otherwise (false,0.0).
276 /// Consecutive points that fall in the same leaf box share that box's
277 /// descent and coefficient fetch (last-box memoization), so spatially
278 /// coherent point streams (quadrature grids) amortise the per-point
279 /// tree descent. Results are bit-for-bit identical to calling the
280 /// single-point eval_local_only on each point. No communications, and
281 /// no per-call heap allocation once results has capacity.
282 ///
283 /// maxlevel is the maximum depth to search down to --- the max local depth can be
284 /// computed with max_local_depth();
285 void eval_local_only(const std::vector<coordT>& xuser, Level maxlevel,
286 std::vector<std::pair<bool,T>>& results) const {
287 const double eps=1e-15;
288 verify();
290 thread_local std::vector<coordT> xsim;
291 xsim.resize(xuser.size());
292 for (std::size_t ip=0; ip<xuser.size(); ++ip) {
293 coordT xs;
295 // If on the boundary, move the point just inside the volume so the
296 // evaluation logic does not fail (matches the single-point path).
297 for (std::size_t d=0; d<NDIM; ++d) {
298 if (xs[d] < -eps) {
299 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
300 }
301 else if (xs[d] < eps) {
302 xs[d] = eps;
303 }
304
305 if (xs[d] > 1.0+eps) {
306 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
307 }
308 else if (xs[d] > 1.0-eps) {
309 xs[d] = 1.0-eps;
310 }
311 }
312 xsim[ip] = xs;
313 }
314 results.resize(xuser.size());
315 impl->eval_local_only(xsim.data(), xsim.size(), maxlevel, results.data());
316 }
317
318 /// Batched eval_local_only returning a fresh vector (see the
319 /// output-parameter overload above for semantics).
320 std::vector<std::pair<bool,T>> eval_local_only(const std::vector<coordT>& xuser, Level maxlevel) const {
321 std::vector<std::pair<bool,T>> results;
322 eval_local_only(xuser, maxlevel, results);
323 return results;
324 }
325
326 /// Only the invoking process will receive the result via the future
327 /// though other processes may be involved in the evaluation.
328 ///
329 /// Throws if function is not initialized.
330 ///
331 /// This function is a minimally-modified version of eval()
334 const double eps=1e-15;
335 verify();
337 coordT xsim;
339 // If on the boundary, move the point just inside the
340 // volume so that the evaluation logic does not fail
341 for (std::size_t d=0; d<NDIM; ++d) {
342 if (xsim[d] < -eps) {
343 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
344 }
345 else if (xsim[d] < eps) {
346 xsim[d] = eps;
347 }
348
349 if (xsim[d] > 1.0+eps) {
350 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
351 }
352 else if (xsim[d] > 1.0-eps) {
353 xsim[d] = 1.0-eps;
354 }
355 }
356
357 Future<Level> result;
358 impl->evaldepthpt(xsim, impl->key0(), result.remote_ref(impl->world));
359 return result;
360 }
361
362
363 /// Evaluates the function rank at a point in user coordinates. Possible non-blocking comm.
364
365 /// Only the invoking process will receive the result via the future
366 /// though other processes may be involved in the evaluation.
367 ///
368 /// Throws if function is not initialized.
371 const double eps=1e-15;
372 verify();
374 coordT xsim;
376 // If on the boundary, move the point just inside the
377 // volume so that the evaluation logic does not fail
378 for (std::size_t d=0; d<NDIM; ++d) {
379 if (xsim[d] < -eps) {
380 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
381 }
382 else if (xsim[d] < eps) {
383 xsim[d] = eps;
384 }
385
386 if (xsim[d] > 1.0+eps) {
387 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
388 }
389 else if (xsim[d] > 1.0-eps) {
390 xsim[d] = 1.0-eps;
391 }
392 }
393
394 Future<long> result;
395 impl->evalR(xsim, impl->key0(), result.remote_ref(impl->world));
396 return result;
397 }
398
399 /// Evaluates a cube/slice of points (probably for plotting) ... collective but no fence necessary
400
401 /// All processes receive the entire result (which is a rather severe limit
402 /// on the size of the cube that is possible).
403
404 /// Set eval_refine=true to return the refinment levels of
405 /// the given function.
406
407 /// @param[in] cell A Tensor describe the cube where the function to be evaluated in
408 /// @param[in] npt How many points to evaluate in each dimension
409 /// @param[in] eval_refine Wether to return the refinment levels of the given function
411 const std::vector<long>& npt,
412 bool eval_refine = false) const {
413 MADNESS_ASSERT(static_cast<std::size_t>(cell.dim(0))>=NDIM && cell.dim(1)==2 && npt.size()>=NDIM);
415 const double eps=1e-14;
416 verify();
417 reconstruct();
419 for (std::size_t d=0; d<NDIM; ++d) {
420 simlo[d] = cell(d,0);
421 simhi[d] = cell(d,1);
422 }
425
426 // Move the bounding box infintesimally inside dyadic
427 // points so that the evaluation logic does not fail
428 for (std::size_t d=0; d<NDIM; ++d) {
430 MADNESS_ASSERT(simlo[d] >= 0.0);
431 MADNESS_ASSERT(simhi[d] <= 1.0);
432
433 double delta = eps*(simhi[d]-simlo[d]);
434 simlo[d] += delta;
435 simhi[d] -= 2*delta; // deliberate asymmetry
436 }
437 return impl->eval_plot_cube(simlo, simhi, npt, eval_refine);
438 }
439
440
441 /// Evaluates the function at a point in user coordinates. Collective operation.
442
443 /// Throws if function is not initialized.
444 ///
445 /// This function calls eval, blocks until the result is
446 /// available and then broadcasts the result to everyone.
447 /// Therefore, if you are evaluating many points in parallel
448 /// it is \em vastly less efficient than calling eval
449 /// directly, saving the futures, and then forcing all of the
450 /// results.
451 T operator()(const coordT& xuser) const {
453 verify();
455 T result;
456 if (impl->world.rank() == 0) result = eval(xuser).get();
457 impl->world.gop.broadcast(result);
458 //impl->world.gop.fence();
459 return result;
460 }
461
462 /// Evaluates the function at a point in user coordinates. Collective operation.
463
464 /// See "operator()(const coordT& xuser)" for more info
465 T operator()(double x, double y=0, double z=0, double xx=0, double yy=0, double zz=0) const {
466 coordT r;
467 r[0] = x;
468 if (NDIM>=2) r[1] = y;
469 if (NDIM>=3) r[2] = z;
470 if (NDIM>=4) r[3] = xx;
471 if (NDIM>=5) r[4] = yy;
472 if (NDIM>=6) r[5] = zz;
473 return (*this)(r);
474 }
475
476 /// Throws if function is not initialized.
477 ///
478 /// This function mimics operator() by going through the
479 /// tree looking for the depth of the tree at the point.
480 /// It blocks until the result is
481 /// available and then broadcasts the result to everyone.
482 /// Therefore, if you are evaluating many points in parallel
483 /// it is \em vastly less efficient than calling evaldepthpt
484 /// directly, saving the futures, and then forcing all of the
485 /// results.
486 Level depthpt(const coordT& xuser) const {
488 verify();
490 Level result;
491 if (impl->world.rank() == 0) result = evaldepthpt(xuser).get();
492 impl->world.gop.broadcast(result);
493 //impl->world.gop.fence();
494 return result;
495 }
496
497 /// Returns an estimate of the difference ||this-func||^2 from local data
498
499 /// No communication is performed. If the function is not
500 /// reconstructed, it throws an exception. To get the global
501 /// value either do a global sum of the local values or call
502 /// errsq
503 /// @param[in] func Templated interface to the a user specified function
504 template <typename funcT>
505 double errsq_local(const funcT& func) const {
507 verify();
508 if (!is_reconstructed()) MADNESS_EXCEPTION("Function:errsq_local:not reconstructed",0);
509 return impl->errsq_local(func);
510 }
511
512
513 /// Returns an estimate of the difference ||this-func|| ... global sum performed
514
515 /// If the function is compressed, it is reconstructed first. For efficient use
516 /// especially with many functions, reconstruct them all first, and use errsq_local
517 /// instead so you can perform a global sum on all at the same time.
518 /// @param[in] func Templated interface to the a user specified function
519 template <typename funcT>
520 double err(const funcT& func) const {
522 verify();
526 double local = impl->errsq_local(func);
527 impl->world.gop.sum(local);
528 impl->world.gop.fence();
529 return sqrt(local);
530 }
531
532 /// Verifies the tree data structure ... global sync implied
533 void verify_tree() const {
535 if (impl) impl->verify_tree();
536 }
537
538
539 /// Returns true if compressed, false otherwise. No communication.
540
541 /// If the function is not initialized, returns false.
542 bool is_compressed() const {
544 if (impl)
545 return impl->is_compressed();
546 else
547 return false;
548 }
549
550 /// Returns true if reconstructed, false otherwise. No communication.
551
552 /// If the function is not initialized, returns false.
553 bool is_reconstructed() const {
555 if (impl)
556 return impl->is_reconstructed();
557 else
558 return false;
559 }
560
561 /// Returns true if nonstandard-compressed, false otherwise. No communication.
562
563 /// If the function is not initialized, returns false.
564 bool is_nonstandard() const {
566 return impl ? impl->is_nonstandard() : false;
567 }
568
569 /// Returns true if redundant, false otherwise. No communication.
570
571 /// If the function is not initialized, returns false.
572 bool is_redundant() const {
574 return impl ? impl->is_redundant() : false;
575 }
576
577 /// Returns true if redundant_after_merge, false otherwise. No communication.
578
579 /// If the function is not initialized, returns false.
582 return impl ? impl->is_redundant_after_merge() : false;
583 }
584
585 /// Returns the number of nodes in the function tree ... collective global sum
586 std::size_t tree_size() const {
588 if (!impl) return 0;
589 return impl->tree_size();
590 }
591
592 /// print some info about this
593 void print_size(const std::string name) const {
594 if (!impl) {
595 print("function",name,"not assigned yet");
596 } else {
597 impl->print_size(name);
598 }
599 }
600
601 /// Returns the maximum depth of the function tree ... collective global sum
602 std::size_t max_depth() const {
604 if (!impl) return 0;
605 return impl->max_depth();
606 }
607
608
609 /// Returns the maximum local depth of the function tree ... no communications
610
611 /// This is the value to pass as \c maxlevel to eval_local_only: it bounds the
612 /// descent to the deepest leaf actually held on this rank. Passing a larger
613 /// bound (e.g. Level::max()) only makes a missing/remote point descend through
614 /// empty levels doing owner() checks that never match -- pure overhead.
615 std::size_t max_local_depth() const {
617 if (!impl) return 0;
618 return impl->max_local_depth();
619 }
620
621
622 /// Returns the max number of nodes on a processor
623 std::size_t max_nodes() const {
625 if (!impl) return 0;
626 return impl->max_nodes();
627 }
628
629 /// Returns the min number of nodes on a processor
630 std::size_t min_nodes() const {
632 if (!impl) return 0;
633 return impl->min_nodes();
634 }
635
636
637 /// Returns the number of coefficients in the function ... collective global sum
638 std::size_t size() const {
640 if (!impl) return 0;
641 return impl->size();
642 }
643
644 /// Return the number of coefficients in the function on this processor
645 std::size_t size_local() const {
647 if (!impl) return 0;
648 return impl->size_local();
649 }
650
651
652 /// Returns value of autorefine flag. No communication.
653 bool autorefine() const {
655 if (!impl) return true;
656 return impl->get_autorefine();
657 }
658
659
660 /// Sets the value of the autorefine flag. Optional global fence.
661
662 /// A fence is required to ensure consistent global state.
663 void set_autorefine(bool value, bool fence = true) {
665 verify();
666 impl->set_autorefine(value);
667 if (fence) impl->world.gop.fence();
668 }
669
670
671 /// Returns value of truncation threshold. No communication.
672 double thresh() const {
674 if (!impl) return 0.0;
675 return impl->get_thresh();
676 }
677
678
679 /// Sets the value of the truncation threshold. Optional global fence.
680
681 /// A fence is required to ensure consistent global state.
682 void set_thresh(double value, bool fence = true) {
684 verify();
685 impl->set_thresh(value);
686 if (fence) impl->world.gop.fence();
687 }
688
689
690 /// Returns the number of multiwavelets (k). No communication.
691 int k() const {
693 verify();
694 return impl->get_k();
695 }
696
697
698 /// Truncate the function with optional fence. Compresses with fence if not compressed.
699
700 /// If the truncation threshold is less than or equal to zero the default value
701 /// specified when the function was created is used.
702 /// If the function is not initialized, it just returns.
703 ///
704 /// Returns this for chaining.
705 /// @param[in] tol Tolerance for truncating the coefficients. Default 0.0 means use the implementation's member value \c thresh instead.
706 /// @param[in] fence Do fence
707 Function<T,NDIM>& truncate(double tol = 0.0, bool fence = true) {
709 if (!impl) return *this;
710 verify();
711// if (!is_compressed()) compress();
712 impl->truncate(tol,fence);
714 return *this;
715 }
716
717
718 /// Returns a shared-pointer to the implementation
719 const std::shared_ptr< FunctionImpl<T,NDIM> >& get_impl() const {
721 verify();
722 return impl;
723 }
724
725 /// Replace current FunctionImpl with provided new one
726 void set_impl(const std::shared_ptr< FunctionImpl<T,NDIM> >& impl) {
728 this->impl = impl;
729 }
730
731
732 /// Replace the current functor with the provided new one
733
734 /// presumably the new functor will be a CompositeFunctor, which will
735 /// change the behavior of the function: multiply the functor with the function
736 void set_functor(const std::shared_ptr<FunctionFunctorInterface<T, NDIM> > functor) {
737 this->impl->set_functor(functor);
738 print("set functor in mra.h");
739 }
740
741 bool is_on_demand() const {return this->impl->is_on_demand();}
742
743 /// Replace current FunctionImpl with a new one using the same parameters & map as f
744
745 /// If zero is true the function is initialized to zero, otherwise it is empty
746 template <typename R>
747 void set_impl(const Function<R,NDIM>& f, bool zero = true) {
748 impl = std::shared_ptr<implT>(new implT(*f.get_impl(), f.get_pmap(), zero));
749 if (zero) world().gop.fence();
750 }
751
752 /// Returns the world
753 World& world() const {
755 verify();
756 return impl->world;
757 }
758
759
760 /// Returns a shared pointer to the process map
761 const std::shared_ptr< WorldDCPmapInterface< Key<NDIM> > >& get_pmap() const {
763 verify();
764 return impl->get_pmap();
765 }
766
767 /// replicate this function according to type
768 ///
769 /// ** note that global operations will return unexpected results **
770 /// Be sure you know what you are doing!
771 void replicate(const DistributionType type, bool fence=true) const {
772 verify();
774 else if (type==DistributionType::NodeReplicated) impl->replicate_on_hosts(fence);
775 else MADNESS_EXCEPTION("Function::replicate: unknown DistributionType",type);
776 }
777
778 /// replicate this function, generating a unique pmap
779
780 /// ** note that global operations will return unexpected results **
781 /// Be sure you know what you are doing!
782 void replicate(bool fence=true) const {
783 verify();
784 impl->replicate(fence);
785 }
786
787 /// replicate this function, one copy per host
788
789 /// map will refer the to first rank on each host to avoid inter-node communication
790 /// ** note that global operations will return unexpected results **
791 /// Be sure you know what you are doing!
792 void replicate_on_hosts(bool fence=true) const {
793 verify();
794 impl->replicate_on_hosts(fence);
795 }
796
797
798 /// distribute this function according to newmap
799 void distribute(std::shared_ptr< WorldDCPmapInterface< Key<NDIM> > > newmap) const {
800 verify();
801 impl->distribute(newmap);
802 }
803
804
805 /// Returns the square of the norm of the local function ... no communication
806
807 /// Works in either basis
808 double norm2sq_local() const {
810 verify();
812 "function must be compressed or reconstructed for norm2sq_local");
813 return impl->norm2sq_local();
814 }
815
816
817 /// Returns the 2-norm of the function ... global sum ... works in either basis
818
819 /// See comments for err() w.r.t. applying to many functions.
820 double norm2() const {
822 verify();
824 double local = impl->norm2sq_local();
825
826 impl->world.gop.sum(local);
827 impl->world.gop.fence();
828 return sqrt(local);
829 }
830
831
832 /// Initializes information about the function norm at all length scales
833 void norm_tree(bool fence = true) const {
835 verify();
838 const_cast<Function<T,NDIM>*>(this)->impl->norm_tree(fence);
839 }
840
841
842 /// Compresses the function, transforming into wavelet basis. Possible non-blocking comm.
843
844 /// By default fence=true meaning that this operation completes before returning,
845 /// otherwise if fence=false it returns without fencing and the user must invoke
846 /// world.gop.fence() to assure global completion before using the function
847 /// for other purposes.
848 ///
849 /// Noop if already compressed or if not initialized.
850 ///
851 /// Since reconstruction/compression do not discard information we define them
852 /// as const ... "logical constness" not "bitwise constness".
853 const Function<T,NDIM>& compress(bool fence = true) const {
855 }
856
857
858 /// Compresses the function retaining scaling function coeffs. Possible non-blocking comm.
859
860 /// By default fence=true meaning that this operation completes before returning,
861 /// otherwise if fence=false it returns without fencing and the user must invoke
862 /// world.gop.fence() to assure global completion before using the function
863 /// for other purposes.
864 ///
865 /// Noop if already compressed or if not initialized.
871
872 /// Converts the function standard compressed form. Possible non-blocking comm.
873
874 /// By default fence=true meaning that this operation completes before returning,
875 /// otherwise if fence=false it returns without fencing and the user must invoke
876 /// world.gop.fence() to assure global completion before using the function
877 /// for other purposes.
878 ///
879 /// Must be already compressed.
880 void standard(bool fence = true) {
882 }
883
884 /// Converts the function to redundant form, i.e. sum coefficients on all levels
885
886 /// By default fence=true meaning that this operation completes before returning,
887 /// otherwise if fence=false it returns without fencing and the user must invoke
888 /// world.gop.fence() to assure global completion before using the function
889 /// for other purposes.
890 ///
891 /// Must be already compressed.
892 void make_redundant(bool fence = true) {
894 }
895
896 /// Reconstructs the function, transforming into scaling function basis. Possible non-blocking comm.
897
898 /// By default fence=true meaning that this operation completes before returning,
899 /// otherwise if fence=false it returns without fencing and the user must invoke
900 /// world.gop.fence() to assure global completion before using the function
901 /// for other purposes.
902 ///
903 /// Noop if already reconstructed or if not initialized.
904 ///
905 /// Since reconstruction/compression do not discard information we define them
906 /// as const ... "logical constness" not "bitwise constness".
907 const Function<T,NDIM>& reconstruct(bool fence = true) const {
909 }
910
911 /// changes tree state to given state
912
913 /// Since reconstruction/compression do not discard information we define them
914 /// as const ... "logical constness" not "bitwise constness".
915 /// @param[in] finalstate The final state of the tree
916 /// @param[in] fence Fence after the operation (might not be respected!!!)
919 if (not impl) return *this;
920 TreeState current_state = impl->get_tree_state();
921 if (finalstate == current_state) return *this;
922 MADNESS_CHECK_THROW(current_state != TreeState::unknown, "unknown tree state");
923
924 impl->change_tree_state(finalstate, fence);
925 if (fence && VERIFY_TREE) verify_tree();
926 return *this;
927 }
928
929 /// Sums scaling coeffs down tree restoring state with coeffs only at leaves. Optional fence. Possible non-blocking comm.
930 void sum_down(bool fence = true) const {
932 verify();
933 MADNESS_CHECK_THROW(impl->get_tree_state()==redundant_after_merge, "sum_down requires a redundant_after_merge state");
934 const_cast<Function<T,NDIM>*>(this)->impl->sum_down(fence);
935 const_cast<Function<T,NDIM>*>(this)->impl->set_tree_state(reconstructed);
936
937 if (fence && VERIFY_TREE) verify_tree(); // Must be after in case nonstandard
938 }
939
940
941 /// Inplace autorefines the function. Optional fence. Possible non-blocking comm.
942 template <typename opT>
943 void refine_general(const opT& op, bool fence = true) const {
945 verify();
947 impl->refine(op, fence);
948 }
949
950
952 bool operator()(implT* impl, const Key<NDIM>& key, const nodeT& t) const {
953 return impl->autorefine_square_test(key, t);
954 }
955
956 template <typename Archive> void serialize (Archive& ar) {}
957 };
958
959 /// Inplace autorefines the function using same test as for squaring.
960
961 /// return this for chaining
962 const Function<T,NDIM>& refine(bool fence = true) const {
964 return *this;
965 }
966
967 /// Inplace broadens support in scaling function basis
969 bool fence = true) const {
970 verify();
971 reconstruct();
972 impl->broaden(bc.is_periodic(), fence);
973 }
974
975
976 /// Clears the function as if constructed uninitialized. Optional fence.
977
978 /// Any underlying data will not be freed until the next global fence.
979 void clear(bool fence = true) {
981 if (impl) {
982 World& world = impl->world;
983 impl.reset();
984 if (fence) world.gop.fence();
985 }
986 }
987
988 /// Process 0 prints a summary of all nodes in the tree (collective)
989 void print_tree(std::ostream& os = std::cout) const {
991 if (impl) impl->print_tree(os);
992 }
993
994 /// same as print_tree() but produces JSON-formatted string
995 /// @warning enclose the result in braces to make it a valid JSON object
996 void print_tree_json(std::ostream& os = std::cout) const {
998 if (impl) impl->print_tree_json(os);
999 }
1000
1001 /// Process 0 prints a graphviz-formatted output of all nodes in the tree (collective)
1002 void print_tree_graphviz(std::ostream& os = std::cout) const {
1004 os << "digraph G {" << std::endl;
1005 if (impl) impl->print_tree_graphviz(os);
1006 os << "}" << std::endl;
1007 }
1008
1009 /// Print a summary of the load balancing info
1010
1011 /// This is serial and VERY expensive
1012 void print_info() const {
1014 if (impl) impl->print_info();
1015 }
1016
1018 T (*f)(T);
1020 void operator()(const Key<NDIM>& key, Tensor<T>& t) const {
1021 UNARY_OPTIMIZED_ITERATOR(T, t, *_p0 = f(*_p0));
1022 }
1023 template <typename Archive> void serialize(Archive& ar) {}
1024 };
1025
1026 /// Inplace unary operation on function values
1027 void unaryop(T (*f)(T)) {
1028 // Must fence here due to temporary object on stack
1029 // stopping us returning before complete
1031 }
1032
1033
1034 /// Inplace unary operation on function values
1035 template <typename opT>
1036 void unaryop(const opT& op, bool fence=true) {
1038 verify();
1039 reconstruct();
1040 impl->unary_op_value_inplace(op, fence);
1041 }
1042
1043
1044 /// Unary operation applied inplace to the coefficients
1045 template <typename opT>
1046 void unaryop_coeff(const opT& op,
1047 bool fence = true) {
1049 verify();
1050 impl->unary_op_coeff_inplace(op, fence);
1051 }
1052
1053
1054 /// Unary operation applied inplace to the nodes
1055 template <typename opT>
1056 void unaryop_node(const opT& op,
1057 bool fence = true) {
1059 verify();
1060 impl->unary_op_node_inplace(op, fence);
1061 }
1062
1063
1064
1065
1066 static void doconj(const Key<NDIM>, Tensor<T>& t) {
1068 t.conj();
1069 }
1070
1071 /// Inplace complex conjugate. No communication except for optional fence.
1072
1073 /// Returns this for chaining. Works in either basis.
1077 return *this;
1078 }
1079
1080
1081 /// Inplace, scale the function by a constant. No communication except for optional fence.
1082
1083 /// Works in either basis. Returns reference to this for chaining.
1084 template <typename Q>
1085 Function<T,NDIM>& scale(const Q q, bool fence=true) {
1087 verify();
1088 if (VERIFY_TREE) verify_tree();
1089 impl->scale_inplace(q,fence);
1090 return *this;
1091 }
1092
1093
1094 /// Inplace add scalar. No communication except for optional fence.
1097 verify();
1098 if (VERIFY_TREE) verify_tree();
1099 impl->add_scalar_inplace(t,fence);
1100 return *this;
1101 }
1102
1103
1104 /// Inplace, general bi-linear operation in wavelet basis. No communication except for optional fence.
1105
1106 /// If the functions are not in the wavelet basis an exception is thrown since this routine
1107 /// is intended to be fast and unexpected compression is assumed to be a performance bug.
1108 ///
1109 /// Returns this for chaining, can be in states compressed of redundant_after_merge.
1110 ///
1111 /// this and other may have different distributions and may even live in different worlds
1112 ///
1113 /// this <-- this*alpha + other*beta
1114 template <typename Q, typename R>
1116 const Function<Q,NDIM>& other, const R& beta, bool fence=true) {
1118 verify();
1119 other.verify();
1120
1121 // operation is done either in compressed or reconstructed state
1122 TreeState operating_state=this->get_impl()->get_tensor_type()==TT_FULL ? compressed : reconstructed;
1123
1124 TreeState thisstate=impl->get_tree_state();
1125 TreeState otherstate=other.get_impl()->get_tree_state();
1126
1128 MADNESS_CHECK_THROW(thisstate==compressed, "gaxpy: this must be compressed");
1129 MADNESS_CHECK_THROW(otherstate==compressed, "gaxpy: other must be compressed");
1130 impl->gaxpy_inplace(alpha, *other.get_impl(), beta, fence);
1131
1132 } else if (operating_state==reconstructed) {
1133 // this works both in reconstructed and redundant_after_merge states
1135 "gaxpy: this must be reconstructed or redundant_after_merge");
1137 "gaxpy: other must be reconstructed or redundant_after_merge");
1138
1139 impl->gaxpy_inplace_reconstructed(alpha,*other.get_impl(),beta,fence);
1140 } else {
1141 MADNESS_EXCEPTION("unknown tree state",1);
1142 }
1143 return *this;
1144 }
1145
1146
1147 /// Inplace addition of functions in the wavelet basis
1148
1149 /// Using operator notation forces a global fence after every operation.
1150 /// Functions don't need to be compressed, it's the caller's responsibility
1151 /// to choose an appropriate state with performance, usually compressed for 3d,
1152 /// reconstructed for 6d)
1153 template <typename Q>
1156
1157 // do this in reconstructed or compressed form
1159 this->change_tree_state(operating_state);
1161
1162 MADNESS_ASSERT(impl->get_tree_state() == other.get_impl()->get_tree_state());
1163 if (VERIFY_TREE) verify_tree();
1164 if (VERIFY_TREE) other.verify_tree();
1165 return gaxpy(T(1.0), other, Q(1.0), true);
1166 }
1167
1168
1169 /// Inplace subtraction of functions in the wavelet basis
1170
1171 /// Using operator notation forces a global fence after every operation
1172 template <typename Q>
1175 if (NDIM<=3) {
1176 compress();
1177 other.compress();
1178 } else {
1179 reconstruct();
1180 other.reconstruct();
1181 }
1182 MADNESS_ASSERT(impl->get_tree_state() == other.get_impl()->get_tree_state());
1183 if (VERIFY_TREE) verify_tree();
1184 if (VERIFY_TREE) other.verify_tree();
1185 return gaxpy(T(1.0), other, Q(-1.0), true);
1186 }
1187
1188
1189 /// Inplace scaling by a constant
1190
1191 /// Using operator notation forces a global fence after every operation
1192 template <typename Q>
1194 operator*=(const Q q) {
1196 scale(q,true);
1197 return *this;
1198 }
1199
1200
1201 /// Inplace squaring of function ... global comm only if not reconstructed
1202
1203 /// Returns *this for chaining.
1206 if (!is_reconstructed()) reconstruct();
1207 if (VERIFY_TREE) verify_tree();
1208 impl->square_inplace(fence);
1209 return *this;
1210 }
1211
1212 /// Returns *this for chaining.
1215 if (!is_reconstructed()) reconstruct();
1216 if (VERIFY_TREE) verify_tree();
1217 impl->abs_inplace(fence);
1218 return *this;
1219 }
1220
1221 /// Returns *this for chaining.
1224 if (!is_reconstructed()) reconstruct();
1225 if (VERIFY_TREE) verify_tree();
1226 impl->abs_square_inplace(fence);
1227 return *this;
1228 }
1229
1230 /// Returns local contribution to \c int(f(x),x) ... no communication
1231
1232 /// In the wavelet basis this is just the coefficient of the first scaling
1233 /// function which is a constant. In the scaling function basis we
1234 /// must add up contributions from each box.
1235 T trace_local() const {
1237 if (!impl) return 0.0;
1238 if (VERIFY_TREE) verify_tree();
1239 return impl->trace_local();
1240 }
1241
1242
1243 /// Returns global value of \c int(f(x),x) ... global comm required
1244 T trace() const {
1246 if (!impl) return 0.0;
1247 T sum = impl->trace_local();
1248 impl->world.gop.sum(sum);
1249 impl->world.gop.fence();
1250 return sum;
1251 }
1252
1253
1254 /// Returns local part of inner product ... throws if both not compressed
1255 template <typename R>
1256 TENSOR_RESULT_TYPE(T,R) inner_local(const Function<R,NDIM>& g) const {
1263 return impl->inner_local(*(g.get_impl()));
1264 }
1265
1266 /// Returns local part of dot product ... throws if both not compressed
1268 TENSOR_RESULT_TYPE(T,R) dot_local(const Function<R,NDIM>& g) const {
1271 MADNESS_ASSERT(g.is_compressed());
1273 if (VERIFY_TREE) g.verify_tree();
1274 return impl->dot_local(*(g.get_impl()));
1275 }
1276
1277
1278 /// With this being an on-demand function, fill the MRA tree according to different criteria
1279
1280 /// @param[in] g the function after which the MRA structure is modeled (any basis works)
1281 template<typename R>
1283 MADNESS_ASSERT(g.is_initialized());
1285
1286 // clear what we have
1287 impl->get_coeffs().clear();
1288
1289 //leaf_op<T,NDIM> gnode_is_leaf(g.get_impl().get());
1290 Leaf_op_other<T,NDIM> gnode_is_leaf(g.get_impl().get());
1291 impl->make_Vphi(gnode_is_leaf,fence);
1292 return *this;
1293
1294 }
1295
1296 /// With this being an on-demand function, fill the MRA tree according to different criteria
1297
1298 /// @param[in] op the convolution operator for screening
1299 template<typename opT>
1300 Function<T,NDIM>& fill_tree(const opT& op, bool fence=true) {
1302 // clear what we have
1303 impl->get_coeffs().clear();
1306 impl ->make_Vphi(leaf_op,fence);
1307 return *this;
1308 }
1309
1310 /// With this being an on-demand function, fill the MRA tree according to different criteria
1313 // clear what we have
1314 impl->get_coeffs().clear();
1316 impl->make_Vphi(leaf_op,fence);
1317 return *this;
1318 }
1319
1320 /// Special refinement on 6D boxes where the electrons come close (meet)
1321 /// @param[in] op the convolution operator for screening
1322 template<typename opT>
1323 Function<T,NDIM>& fill_cuspy_tree(const opT& op,const bool fence=true){
1325 // clear what we have
1326 impl->get_coeffs().clear();
1328
1330 impl ->make_Vphi(leaf_op,fence);
1331
1332 return *this;
1333 }
1334
1335 /// Special refinement on 6D boxes where the electrons come close (meet)
1338 // clear what we have
1339 impl->get_coeffs().clear();
1341
1343 impl ->make_Vphi(leaf_op,fence);
1344
1345 return *this;
1346 }
1347
1348 /// Special refinement on 6D boxes for the nuclear potentials (regularized with cusp, non-regularized with singularity)
1349 /// @param[in] op the convolution operator for screening
1350 template<typename opT>
1351 Function<T,NDIM>& fill_nuclear_cuspy_tree(const opT& op,const size_t particle,const bool fence=true){
1353 // clear what we have
1354 impl->get_coeffs().clear();
1356
1358 impl ->make_Vphi(leaf_op,fence);
1359
1360 return *this;
1361 }
1362
1363 /// Special refinement on 6D boxes for the nuclear potentials (regularized with cusp, non-regularized with singularity)
1366 // clear what we have
1367 impl->get_coeffs().clear();
1369
1371 impl ->make_Vphi(leaf_op,fence);
1372
1373 return *this;
1374 }
1375
1376 /// perform the hartree product of f*g, invoked by result
1377 template<size_t LDIM, size_t KDIM, typename opT>
1378 void do_hartree_product(const std::vector<std::shared_ptr<FunctionImpl<T,LDIM>>> left,
1379 const std::vector<std::shared_ptr<FunctionImpl<T,KDIM>>> right,
1380 const opT* op) {
1381
1382 // get the right leaf operator
1384 impl->hartree_product(left,right,leaf_op,true);
1385 impl->finalize_sum();
1386// this->truncate();
1387
1388 }
1389
1390 /// perform the hartree product of f*g, invoked by result
1391 template<size_t LDIM, size_t KDIM>
1392 void do_hartree_product(const std::vector<std::shared_ptr<FunctionImpl<T,LDIM>>> left,
1393 const std::vector<std::shared_ptr<FunctionImpl<T,KDIM>>> right) {
1394
1395// hartree_leaf_op<T,KDIM+LDIM> leaf_op(impl.get(),cdata.s0);
1397 impl->hartree_product(left,right,leaf_op,true);
1398 impl->finalize_sum();
1399// this->truncate();
1400
1401 }
1402
1403 /// Returns the inner product
1404
1405 /// Not efficient for computing multiple inner products
1406 /// @param[in] g Function, optionally on-demand
1407 template <typename R>
1410
1411 // fast return if possible
1412 if (not this->is_initialized()) return 0.0;
1413 if (not g.is_initialized()) return 0.0;
1414
1415 // if this and g are the same, use norm2()
1416 if constexpr (std::is_same_v<T,R>) {
1417 if (this->get_impl() == g.get_impl()) {
1418 TreeState state = this->get_impl()->get_tree_state();
1419 if (not(state == reconstructed or state == compressed))
1421 double norm = this->norm2();
1422 return norm * norm;
1423 }
1424 }
1425
1426 // do it case-by-case
1427 if constexpr (std::is_same_v<R,T>) {
1428 if (this->is_on_demand())
1429 return g.inner_on_demand(*this);
1430 if (g.is_on_demand())
1431 return this->inner_on_demand(g);
1432 }
1433
1435 if (VERIFY_TREE) g.verify_tree();
1436
1437 // compute in compressed form if compression is fast, otherwise in redundant form
1439
1441 g.change_tree_state(operating_state,false);
1442 impl->world.gop.fence();
1443
1444 TENSOR_RESULT_TYPE(T,R) local = impl->inner_local(*g.get_impl());
1445 impl->world.gop.sum(local);
1446 impl->world.gop.fence();
1447
1448 // restore state -- no need for this
1449 // change_tree_state(state,false);
1450 // g.change_tree_state(gstate,false);
1451 // impl->world.gop.fence();
1452
1453 return local;
1454 }
1455
1456 /// Return the local part of inner product with external function ... no communication.
1457 /// If you are going to be doing a bunch of inner_ext calls, set
1458 /// keep_redundant to true and then manually undo_redundant when you
1459 /// are finished.
1460 /// @param[in] f Pointer to function of type T that take coordT arguments. This is the externally provided function
1461 /// @param[in] leaf_refine boolean switch to turn on/off refinement past leaf nodes
1462 /// @param[in] keep_redundant boolean switch to turn on/off undo_redundant
1463 /// @return Returns local part of the inner product, i.e. over the domain of all function nodes on this compute node.
1464 T inner_ext_local(const std::shared_ptr< FunctionFunctorInterface<T,NDIM> > f, const bool leaf_refine=true, const bool keep_redundant=false) const {
1467 T local = impl->inner_ext_local(f, leaf_refine);
1469 return local;
1470 }
1471
1472 /// Return the inner product with external function ... requires communication.
1473 /// If you are going to be doing a bunch of inner_ext calls, set
1474 /// keep_redundant to true and then manually undo_redundant when you
1475 /// are finished.
1476 /// @param[in] f Reference to FunctionFunctorInterface. This is the externally provided function
1477 /// @param[in] leaf_refine boolean switch to turn on/off refinement past leaf nodes
1478 /// @param[in] keep_redundant boolean switch to turn on/off undo_redundant
1479 /// @return Returns the inner product
1480 T inner_ext(const std::shared_ptr< FunctionFunctorInterface<T,NDIM> > f, const bool leaf_refine=true, const bool keep_redundant=false) const {
1483 T local = impl->inner_ext_local(f, leaf_refine);
1484 impl->world.gop.sum(local);
1485 impl->world.gop.fence();
1487 return local;
1488 }
1489
1490 /// Return the inner product with external function ... requires communication.
1491 /// If you are going to be doing a bunch of inner_ext calls, set
1492 /// keep_redundant to true and then manually undo_redundant when you
1493 /// are finished.
1494 /// @param[in] f Reference to FunctionFunctorInterface. This is the externally provided function
1495 /// @param[in] leaf_refine boolean switch to turn on/off refinement past leaf nodes
1496 /// @return Returns the inner product
1498 const bool leaf_refine=true) const {
1500 reconstruct();
1501 T local = impl->inner_adaptive_local(f, leaf_refine);
1502 impl->world.gop.sum(local);
1503 impl->world.gop.fence();
1504 return local;
1505 }
1506
1507 /// Return the local part of gaxpy with external function, this*alpha + f*beta ... no communication.
1508 /// @param[in] alpha prefactor for this Function
1509 /// @param[in] f Pointer to function of type T that take coordT arguments. This is the externally provided function
1510 /// @param[in] beta prefactor for f
1511 template <typename L>
1512 void gaxpy_ext(const Function<L,NDIM>& left, T (*f)(const coordT&), T alpha, T beta, double tol, bool fence=true) const {
1514 if (!left.is_reconstructed()) left.reconstruct();
1515 impl->gaxpy_ext(left.get_impl().get(), f, alpha, beta, tol, fence);
1516 }
1517
1518 /// Returns the inner product for one on-demand function
1519
1520 /// It does work, but it might not give you the precision you expect.
1521 /// The assumption is that the function g returns proper sum
1522 /// coefficients on the MRA tree of this. This might not be the case if
1523 /// g is constructed with an implicit multiplication, e.g.
1524 /// result = <this|g>, with g = 1/r12 | gg>
1525 /// @param[in] g on-demand function
1526 template<typename R>
1528 MADNESS_ASSERT(g.is_on_demand() and (not this->is_on_demand()));
1529
1530 constexpr std::size_t LDIM=std::max(NDIM/2,std::size_t(1));
1531 auto func=dynamic_cast<CompositeFunctorInterface<T,NDIM,LDIM>* >(g.get_impl()->get_functor().get());
1533 func->make_redundant(true);
1534 func->replicate_low_dim_functions(true);
1535 this->reconstruct(); // if this == &g we don't need g to be redundant
1536
1538
1539 TENSOR_RESULT_TYPE(T, R) local = impl->inner_local_on_demand(*g.get_impl());
1540 impl->world.gop.sum(local);
1541 impl->world.gop.fence();
1542
1543 return local;
1544 }
1545
1546 /// project this on the low-dim function g: h(x) = <f(x,y) | g(y)>
1547
1548 /// @param[in] g low-dim function
1549 /// @param[in] dim over which dimensions to be integrated: 0..LDIM-1 or LDIM..NDIM-1
1550 /// @return new function of dimension NDIM-LDIM
1551 template <typename R, size_t LDIM>
1553 if (NDIM<=LDIM) MADNESS_EXCEPTION("confused dimensions in project_out?",1);
1554 MADNESS_CHECK_THROW(dim==0 or dim==1,"dim must be 0 or 1 in project_out");
1555 verify();
1556 typedef TENSOR_RESULT_TYPE(T,R) resultT;
1557 static const size_t KDIM=NDIM-LDIM;
1558
1560 .k(g.k()).thresh(g.thresh());
1561 Function<resultT,KDIM> result=factory; // no empty() here!
1562
1564 g.change_tree_state(redundant,false);
1565 world().gop.fence();
1566 this->get_impl()->project_out(result.get_impl().get(),g.get_impl().get(),dim,true);
1567// result.get_impl()->project_out2(this->get_impl().get(),gimpl,dim);
1568 result.world().gop.fence();
1569 g.change_tree_state(reconstructed,false);
1570 result.get_impl()->trickle_down(false);
1571 result.get_impl()->set_tree_state(reconstructed);
1572 result.world().gop.fence();
1573 return result;
1574 }
1575
1576 Function<T,NDIM/2> dirac_convolution(const bool fence=true) const {
1577 constexpr std::size_t LDIM=NDIM/2;
1578 MADNESS_CHECK_THROW(NDIM==2*LDIM,"NDIM must be even");
1579// // this will be the result function
1582 if(!is_reconstructed()) this->reconstruct();
1583 this->get_impl()->do_dirac_convolution(f.get_impl().get(),fence);
1584 return f;
1585 }
1586
1587 /// Replaces this function with one loaded from an archive using the default processor map
1588
1589 /// Archive can be sequential or parallel.
1590 ///
1591 /// The & operator for serializing will only work with parallel archives.
1592 template <typename Archive>
1593 void load(World& world, Archive& ar) {
1595 // Type checking since we are probably circumventing the archive's own type checking
1596 long magic = 0l, id = 0l, ndim = 0l, k = 0l;
1597 Tensor<double> cell;
1598 ar & magic & id & ndim & k & cell;
1599 MADNESS_ASSERT(magic == 7776769); // Mellow Mushroom Pizza tel.# in Knoxville (+1 for cell in header)
1601 MADNESS_ASSERT(ndim == NDIM);
1602
1603 // if simulation cell is set it must match the cell from function on file.
1604 // if simulation cell is not set set it to the one found on file
1605 // -- for the latter the only use case seems a python script for plotting
1607 if ((cell-FunctionDefaults<NDIM>::get_cell()).normf()>1.e-14) {
1608 std::ostringstream oss;
1609 oss << "simulation cells inconsistent: stored cell differs from FunctionDefaults cell.\n"
1610 << "Call FunctionDefaults<" << NDIM << ">::clear_cell() before reloading "
1611 << "(this will render all existing functions useless!)";
1612 MADNESS_EXCEPTION(oss.str().c_str(), 1);
1613 }
1614 } else { // no cell set in the defaults: use the one from file
1616 }
1617
1618 impl.reset(new implT(FunctionFactory<T,NDIM>(world).k(k).empty()));
1619 impl->load(ar);
1620 }
1621
1622
1623 /// Stores the function to an archive
1624
1625 /// Archive can be sequential or parallel.
1626 ///
1627 /// The & operator for serializing will only work with parallel archives.
1628 template <typename Archive>
1629 void store(Archive& ar) const {
1631 verify();
1632 // For type checking, etc.
1633 ar & long(7776769) & long(TensorTypeData<T>::id) & long(NDIM) & long(k()) & impl->get_cell();
1634
1635 impl->store(ar);
1636 }
1637
1638 /// change the tensor type of the coefficients in the FunctionNode
1639
1640 /// @param[in] targs target tensor arguments (threshold and full/low rank)
1641 void change_tensor_type(const TensorArgs& targs, bool fence=true) {
1642 if (not impl) return;
1643 impl->change_tensor_type1(targs,fence);
1644 }
1645
1646
1647 /// This is replaced with left*right ... private
1648 template <typename Q, typename opT>
1650 const opT& op, bool fence) {
1652 func.verify();
1653 MADNESS_ASSERT(func.is_reconstructed());
1654 if (VERIFY_TREE) func.verify_tree();
1655 impl.reset(new implT(*func.get_impl(), func.get_pmap(), false));
1656 impl->unaryXX(func.get_impl().get(), op, fence);
1657 return *this;
1658 }
1659
1660 /// Returns vector of FunctionImpl pointers corresponding to vector of functions
1661 template <typename Q, std::size_t D>
1662 static std::vector< std::shared_ptr< FunctionImpl<Q,D> > > vimpl(const std::vector< Function<Q,D> >& v) {
1664 std::vector< std::shared_ptr< FunctionImpl<Q,D> > > r(v.size());
1665 for (unsigned int i=0; i<v.size(); ++i) r[i] = v[i].get_impl();
1666 return r;
1667 }
1668
1669 /// This is replaced with op(vector of functions) ... private
1670 template <typename opT>
1671 Function<T,NDIM>& multiop_values(const opT& op, const std::vector< Function<T,NDIM> >& vf) {
1672 std::vector<implT*> v(vf.size(),NULL);
1673 for (unsigned int i=0; i<v.size(); ++i) {
1674 if (vf[i].is_initialized()) v[i] = vf[i].get_impl().get();
1675 }
1676 impl->multiop_values(op, v);
1677 world().gop.fence();
1678 if (VERIFY_TREE) verify_tree();
1679
1680 return *this;
1681 }
1682
1683 /// apply op on the input vector yielding an output vector of functions
1684
1685 /// (*this) is just a dummy Function to be able to call internal methods in FuncImpl
1686 /// @param[in] op the operator working on vin
1687 /// @param[in] vin vector of input Functions
1688 /// @param[out] vout vector of output Functions vout = op(vin)
1689 template <typename opT>
1691 const std::vector< Function<T,NDIM> >& vin,
1692 std::vector< Function<T,NDIM> >& vout,
1693 const bool fence=true) {
1694 std::vector<implT*> vimplin(vin.size(),NULL);
1695 for (unsigned int i=0; i<vin.size(); ++i) {
1696 if (vin[i].is_initialized()) vimplin[i] = vin[i].get_impl().get();
1697 }
1698 std::vector<implT*> vimplout(vout.size(),NULL);
1699 for (unsigned int i=0; i<vout.size(); ++i) {
1700 if (vout[i].is_initialized()) vimplout[i] = vout[i].get_impl().get();
1701 }
1702
1703 impl->multi_to_multi_op_values(op, vimplin, vimplout, fence);
1704 if (VERIFY_TREE) verify_tree();
1705
1706 }
1707
1708
1709 /// Multiplication of function * vector of functions using recursive algorithm of mulxx
1710 template <typename L, typename R>
1711 void vmulXX(const Function<L,NDIM>& left,
1712 const std::vector< Function<R,NDIM> >& right,
1713 std::vector< Function<T,NDIM> >& result,
1714 double tol,
1715 bool fence) {
1717
1718 std::vector<FunctionImpl<T,NDIM>*> vresult(right.size());
1719 std::vector<const FunctionImpl<R,NDIM>*> vright(right.size());
1720 for (unsigned int i=0; i<right.size(); ++i) {
1721 result[i].set_impl(left,false);
1722 vresult[i] = result[i].impl.get();
1723 vright[i] = right[i].get_impl().get();
1724 }
1725
1726 left.world().gop.fence(); // Is this still essential? Yes.
1727 vresult[0]->mulXXvec(left.get_impl().get(), vright, vresult, tol, fence);
1728 }
1729
1730 /// Same as \c operator* but with optional fence and no automatic reconstruction
1731
1732 /// f or g are on-demand functions
1733 template<typename L, typename R>
1734 void mul_on_demand(const Function<L,NDIM>& f, const Function<R,NDIM>& g, bool fence=true) {
1735 const FunctionImpl<L,NDIM>* fimpl=f.get_impl().get();
1736 const FunctionImpl<R,NDIM>* gimpl=g.get_impl().get();
1737 if (fimpl->is_on_demand() and gimpl->is_on_demand()) {
1738 MADNESS_EXCEPTION("can't multiply two on-demand functions",1);
1739 }
1740
1741 if (fimpl->is_on_demand()) {
1743 impl->multiply(leaf_op1,gimpl,fimpl,fence);
1744 } else {
1746 impl->multiply(leaf_op1,fimpl,gimpl,fence);
1747 }
1748 }
1749
1750 /// sparse transformation of a vector of functions ... private
1751 template <typename R, typename Q>
1752 void vtransform(const std::vector< Function<R,NDIM> >& v,
1753 const Tensor<Q>& c,
1754 std::vector< Function<T,NDIM> >& vresult,
1755 double tol,
1756 bool fence=true) {
1758 vresult[0].impl->vtransform(vimpl(v), c, vimpl(vresult), tol, fence);
1759 }
1760
1761 /// This is replaced with alpha*left + beta*right ... private
1762 template <typename L, typename R>
1764 T beta, const Function<R,NDIM>& right, bool fence) {
1766 left.verify();
1767 right.verify();
1768 MADNESS_ASSERT(left.is_compressed() && right.is_compressed());
1769 if (VERIFY_TREE) left.verify_tree();
1770 if (VERIFY_TREE) right.verify_tree();
1771 impl.reset(new implT(*left.get_impl(), left.get_pmap(), false));
1772 impl->gaxpy(alpha,*left.get_impl(),beta,*right.get_impl(),fence);
1773 return *this;
1774 }
1775
1776 /// This is replaced with mapdim(f) ... private
1777 Function<T,NDIM>& mapdim(const Function<T,NDIM>& f, const std::vector<long>& map, bool fence) {
1779 f.verify();
1780 if (VERIFY_TREE) f.verify_tree();
1781 for (std::size_t i=0; i<NDIM; ++i) MADNESS_ASSERT(map[i]>=0 && static_cast<std::size_t>(map[i])<NDIM);
1782 impl.reset(new implT(*f.impl, f.get_pmap(), false));
1783 impl->mapdim(*f.impl,map,fence);
1784 return *this;
1785 }
1786
1787 /// This is replaced with mirror(f) ... private
1788
1789 /// similar to mapdim, but maps from x to -x, y to -y, and so on
1790 /// Example: mirror a 3d function on the xy plane: mirror={1,1,-1}
1791 /// @param[in] mirror array of -1 and 1, corresponding to mirror or not
1792 Function<T,NDIM>& mirror(const Function<T,NDIM>& f, const std::vector<long>& mirrormap, bool fence) {
1794 f.verify();
1795 if (VERIFY_TREE) f.verify_tree();
1796 for (std::size_t i=0; i<NDIM; ++i) MADNESS_ASSERT((mirrormap[i]==1) or (mirrormap[i]==-1));
1797 impl.reset(new implT(*f.impl, f.get_pmap(), false));
1798 impl->mirror(*f.impl,mirrormap,fence);
1799 return *this;
1800 }
1801
1802 /// This is replaced with mirror(map(f)) ... private
1803
1804 /// first map then mirror!
1805 /// mirror is similar to mapdim, but maps from x to -x, y to -y, and so on
1806 /// Example: mirror a 3d function on the xy plane: mirror={1,1,-1}
1807 /// Example: c4 rotation of a 3d function around the z axis:
1808 /// x->y, y->-x, z->z: map(1,0,2); mirror(-1,1,1)
1809 /// @param[in] map array holding dimensions
1810 /// @param[in] mirror array of -1 and 1, corresponding to mirror or not
1812 const std::vector<long>& map, const std::vector<long>& mirror,
1813 bool fence) {
1815 f.verify();
1816 if (VERIFY_TREE) f.verify_tree();
1817 for (std::size_t i=0; i<mirror.size(); ++i) MADNESS_ASSERT((mirror[i]==1) or (mirror[i]==-1));
1818 for (std::size_t i=0; i<map.size(); ++i) MADNESS_ASSERT(map[i]>=0 && static_cast<std::size_t>(map[i])<NDIM);
1819
1820 impl.reset(new implT(*f.impl, f.get_pmap(), false));
1821 impl->map_and_mirror(*f.impl,map,mirror,fence);
1822 return *this;
1823 }
1824
1825
1826 /// check symmetry of a function by computing the 2nd derivative
1827 double check_symmetry() const {
1828
1830 if (VERIFY_TREE) verify_tree();
1831 double local = impl->check_symmetry_local();
1832 impl->world.gop.sum(local);
1833 impl->world.gop.fence();
1834 double asy=sqrt(local);
1835 if (this->world().rank()==0) print("asymmetry wrt particle",asy);
1837 return asy;
1838 }
1839
1840 /// reduce the rank of the coefficient tensors
1841 Function<T,NDIM>& reduce_rank(const double thresh=0.0, const bool fence=true) {
1842 verify();
1843 double thresh1= (thresh==0.0) ? impl->get_tensor_args().thresh : thresh;
1844 impl->reduce_rank(thresh1,fence);
1845 return *this;
1846 }
1847
1848 /// remove all nodes with level higher than n
1849 Function<T,NDIM>& chop_at_level(const int n, const bool fence=true) {
1850 verify();
1852 impl->chop_at_level(n,true);
1854 return *this;
1855 }
1856 };
1857
1858// template <typename T, typename opT, std::size_t NDIM>
1859 template <typename T, typename opT, std::size_t NDIM>
1860 Function<T,NDIM> multiop_values(const opT& op, const std::vector< Function<T,NDIM> >& vf) {
1862 r.set_impl(vf[0], false);
1863 r.multiop_values(op, vf);
1864 return r;
1865 }
1866
1867 /// Returns new function equal to alpha*f(x) with optional fence
1868 template <typename Q, typename T, std::size_t NDIM>
1870 mul(const Q alpha, const Function<T,NDIM>& f, bool fence=true) {
1872 f.verify();
1873 if (VERIFY_TREE) f.verify_tree();
1875 result.set_impl(f, false);
1876 result.get_impl()->scale_oop(alpha,*f.get_impl(),fence);
1877 return result;
1878 }
1879
1880
1881 /// Returns new function equal to f(x)*alpha with optional fence
1882 template <typename Q, typename T, std::size_t NDIM>
1884 mul(const Function<T,NDIM>& f, const Q alpha, bool fence=true) {
1886 return mul(alpha,f,fence);
1887 }
1888
1889
1890 /// Returns new function equal to f(x)*alpha
1891
1892 /// Using operator notation forces a global fence after each operation
1893 template <typename Q, typename T, std::size_t NDIM>
1896 return mul(alpha, f, true);
1897 }
1898
1899 /// Returns new function equal to alpha*f(x)
1900
1901 /// Using operator notation forces a global fence after each operation
1902 template <typename Q, typename T, std::size_t NDIM>
1905 return mul(alpha, f, true);
1906 }
1907
1908 /// Sparse multiplication --- left and right must be reconstructed and if tol!=0 have tree of norms already created
1909 template <typename L, typename R,std::size_t NDIM>
1911 mul_sparse(const Function<L,NDIM>& left, const Function<R,NDIM>& right, double tol, bool fence=true) {
1913 left.verify();
1914 right.verify();
1916 if (VERIFY_TREE) left.verify_tree();
1917 if (VERIFY_TREE) right.verify_tree();
1918
1920 result.set_impl(left, false);
1921 result.get_impl()->mulXX(left.get_impl().get(), right.get_impl().get(), tol, fence);
1922 return result;
1923 }
1924
1925 /// Same as \c operator* but with optional fence and no automatic reconstruction
1926 template <typename L, typename R,std::size_t NDIM>
1928 mul(const Function<L,NDIM>& left, const Function<R,NDIM>& right, bool fence=true) {
1929 return mul_sparse(left,right,0.0,fence);
1930 }
1931
1932 /// Generate new function = op(left,right) where op acts on the function values
1933 template <typename L, typename R, typename opT, std::size_t NDIM>
1935 binary_op(const Function<L,NDIM>& left, const Function<R,NDIM>& right, const opT& op, bool fence=true) {
1937 if (!left.is_reconstructed()) left.reconstruct();
1938 if (!right.is_reconstructed()) right.reconstruct();
1939
1941 result.set_impl(left, false);
1942 result.get_impl()->binaryXX(left.get_impl().get(), right.get_impl().get(), op, fence);
1943 return result;
1944 }
1945
1946 /// Out of place application of unary operation to function values with optional fence
1947 template <typename Q, typename opT, std::size_t NDIM>
1949 unary_op(const Function<Q,NDIM>& func, const opT& op, bool fence=true) {
1950 if (!func.is_reconstructed()) func.reconstruct();
1953 result.set_impl(func, false);
1954 result.get_impl()->unaryXXvalues(func.get_impl().get(), op, fence);
1955 return result;
1956 }
1957
1958
1959 /// Out of place application of unary operation to scaling function coefficients with optional fence
1960 template <typename Q, typename opT, std::size_t NDIM>
1962 unary_op_coeffs(const Function<Q,NDIM>& func, const opT& op, bool fence=true) {
1963 if (!func.is_reconstructed()) func.reconstruct();
1965 return result.unary_op_coeffs(func,op,fence);
1966 }
1967
1968 /// Use the vmra/mul(...) interface instead
1969
1970 /// This so that we don't have to have friend functions in a different header.
1971 ///
1972 /// If using sparsity (tol != 0) you must have created the tree of norms
1973 /// already for both left and right.
1974 template <typename L, typename R, std::size_t D>
1975 std::vector< Function<TENSOR_RESULT_TYPE(L,R),D> >
1976 vmulXX(const Function<L,D>& left, const std::vector< Function<R,D> >& vright, double tol, bool fence=true) {
1977 if (vright.size() == 0) return std::vector< Function<TENSOR_RESULT_TYPE(L,R),D> >();
1978 std::vector< Function<TENSOR_RESULT_TYPE(L,R),D> > vresult(vright.size());
1979 vresult[0].vmulXX(left, vright, vresult, tol, fence);
1980 return vresult;
1981 }
1982
1983 /// Multiplies two functions with the new result being of type TensorResultType<L,R>
1984
1985 /// Using operator notation forces a global fence after each operation but also
1986 /// enables us to automatically reconstruct the input functions as required.
1987 template <typename L, typename R, std::size_t NDIM>
1989 operator*(const Function<L,NDIM>& left, const Function<R,NDIM>& right) {
1990 if (!left.is_reconstructed()) left.reconstruct();
1991 if (!right.is_reconstructed()) right.reconstruct();
1992 MADNESS_ASSERT(not (left.is_on_demand() or right.is_on_demand()));
1993 return mul(left,right,true);
1994 }
1995
1996 /// Performs a Hartree/outer product on the two given low-dimensional function vectors
1997
1998 /// @return result(x,y) = \sum_i f_i(x) g_i(y)
1999 template<typename T, std::size_t KDIM, std::size_t LDIM>
2001 hartree_product(const std::vector<Function<T,KDIM>>& left, const std::vector<Function<T,LDIM>>& right) {
2002
2003 MADNESS_CHECK_THROW(left.size()==right.size(), "hartree_product: left and right must have same size");
2004 if (left.size()==0) return Function<T,KDIM+LDIM>();
2005
2007
2009 .k(left.front().k()).thresh(thresh);
2010 Function<T,KDIM+LDIM> result=factory.empty();
2011
2012 // some prep work
2015 std::vector<std::shared_ptr<FunctionImpl<T,KDIM>>> vleft=get_impl(left);
2016 std::vector<std::shared_ptr<FunctionImpl<T,LDIM>>> vright=get_impl(right);
2017
2019
2020 return result;
2021
2022 }
2023
2024 /// Performs a Hartree product on the two given low-dimensional functions
2025 template<typename T, std::size_t KDIM, std::size_t LDIM>
2028 typedef std::vector<Function<T,KDIM>> vector;
2029 return hartree_product(vector({left2}),vector({right2}));
2030 }
2031
2032 /// Performs a Hartree product on the two given low-dimensional functions
2033 template<typename T, std::size_t KDIM, std::size_t LDIM, typename opT>
2036 const opT& op) {
2037
2038 // we need both sum and difference coeffs for error estimation
2039 Function<T,KDIM>& left = const_cast< Function<T,KDIM>& >(left2);
2040 Function<T,LDIM>& right = const_cast< Function<T,LDIM>& >(right2);
2041
2043
2045 .k(left.k()).thresh(thresh);
2046 Function<T,KDIM+LDIM> result=factory.empty();
2047
2048 if (result.world().rank()==0) {
2049 print("incomplete FunctionFactory in Function::hartree_product");
2050 print("thresh: ", thresh);
2051 }
2052 bool same=(left2.get_impl()==right2.get_impl());
2053
2054 // some prep work
2055 left.make_nonstandard(true, true);
2056 right.make_nonstandard(true, true);
2057
2058 std::vector<std::shared_ptr<FunctionImpl<T,KDIM>>> vleft;
2059 std::vector<std::shared_ptr<FunctionImpl<T,LDIM>>> vright;
2060 vleft.push_back(left.get_impl());
2061 vright.push_back(right.get_impl());
2062 result.do_hartree_product(vleft,right,&op);
2063
2064 left.standard(false);
2065 if (not same) right.standard(false);
2066 left2.world().gop.fence();
2067
2068 return result;
2069 }
2070
2071 /// adds beta*right only left: alpha*left + beta*right optional fence and no automatic compression
2072
2073 /// left and right might live in different worlds, the accumulation is non-blocking
2074 template <typename L, typename R,std::size_t NDIM>
2075 void
2077 TENSOR_RESULT_TYPE(L,R) beta, const Function<R,NDIM>& right, bool fence=true) {
2080 left.gaxpy(alpha, right, beta, fence);
2081 }
2082
2083 /// Returns new function alpha*left + beta*right optional fence and no automatic compression
2084 template <typename L, typename R,std::size_t NDIM>
2087 TENSOR_RESULT_TYPE(L,R) beta, const Function<R,NDIM>& right, bool fence=true) {
2090 return result.gaxpy_oop(alpha, left, beta, right, fence);
2091 }
2092
2093 /// Same as \c operator+ but with optional fence and no automatic compression
2094 template <typename L, typename R,std::size_t NDIM>
2096 add(const Function<L,NDIM>& left, const Function<R,NDIM>& right, bool fence=true) {
2097 return gaxpy_oop(TENSOR_RESULT_TYPE(L,R)(1.0), left,
2098 TENSOR_RESULT_TYPE(L,R)(1.0), right, fence);
2099 }
2100
2101
2102 /// Returns new function alpha*left + beta*right optional fence, having both addends reconstructed
2103 template<typename T, std::size_t NDIM>
2105 const double beta, const Function<T,NDIM>& right, const bool fence=true) {
2106 Function<T,NDIM> result;
2107 result.set_impl(right,false);
2108
2111 result.get_impl()->gaxpy_oop_reconstructed(alpha,*left.get_impl(),beta,*right.get_impl(),fence);
2112 return result;
2113
2114 }
2115
2116 /// Adds two functions with the new result being of type TensorResultType<L,R>
2117
2118 /// Using operator notation forces a global fence after each operation
2119 template <typename L, typename R, std::size_t NDIM>
2121 operator+(const Function<L,NDIM>& left, const Function<R,NDIM>& right) {
2122 if (VERIFY_TREE) left.verify_tree();
2123 if (VERIFY_TREE) right.verify_tree();
2124
2125 TreeState operating_state=left.get_impl()->get_tensor_type()==TT_FULL ? compressed : reconstructed;
2126 // no compression for high-dimensional functions
2128 left.reconstruct();
2129 right.reconstruct();
2130 return gaxpy_oop_reconstructed(1.0,left,1.0,right,true);
2131 } else {
2132 if (!left.is_compressed()) left.compress();
2133 if (!right.is_compressed()) right.compress();
2134 return add(left,right,true);
2135 }
2136 }
2137
2138 /// Same as \c operator- but with optional fence and no automatic compression
2139 template <typename L, typename R,std::size_t NDIM>
2141 sub(const Function<L,NDIM>& left, const Function<R,NDIM>& right, bool fence=true) {
2142 return gaxpy_oop(TENSOR_RESULT_TYPE(L,R)(1.0), left,
2143 TENSOR_RESULT_TYPE(L,R)(-1.0), right, fence);
2144 }
2145
2146
2147 /// Subtracts two functions with the new result being of type TensorResultType<L,R>
2148
2149 /// Using operator notation forces a global fence after each operation
2150 template <typename L, typename R, std::size_t NDIM>
2152 operator-(const Function<L,NDIM>& left, const Function<R,NDIM>& right) {
2154 // no compression for high-dimensional functions
2155 if (NDIM==6) {
2156 left.reconstruct();
2157 right.reconstruct();
2158 return gaxpy_oop_reconstructed(1.0,left,-1.0,right,true);
2159 } else {
2160 if (!left.is_compressed()) left.compress();
2161 if (!right.is_compressed()) right.compress();
2162 return sub(left,right,true);
2163 }
2164 }
2165
2166 /// Create a new copy of the function with different distribution and optional fence
2167
2168 /// Works in either basis. Different distributions imply
2169 /// asynchronous communication and the optional fence is
2170 /// collective.
2171 template <typename T, std::size_t NDIM>
2173 const std::shared_ptr< WorldDCPmapInterface< Key<NDIM> > >& pmap,
2174 bool fence = true) {
2176 f.verify();
2177 Function<T,NDIM> result;
2179 result.set_impl(std::shared_ptr<implT>(new implT(*f.get_impl(), pmap, false)));
2180 result.get_impl()->copy_coeffs(*f.get_impl(), fence);
2181 if (VERIFY_TREE) result.verify_tree();
2182 return result;
2183 }
2184
2185 /// Create a new copy of the function with the same distribution and optional fence
2186 template <typename T, std::size_t NDIM>
2189 return copy(f, f.get_pmap(), fence);
2190 }
2191
2192 /// Create a new copy of function f living in world (might differ from f.world)
2193
2194 /// uses the default processor map of world
2195 template <typename T, std::size_t NDIM>
2200
2201 // create a new function with pmap distribution, same parameters as f, but no coeffs
2202 Function<T,NDIM> result;
2203 result.set_impl(std::make_shared<implT>(world,*f.get_impl(), pmap, false));
2204 // copy f's coefficients to result
2205 result.get_impl()->copy_coeffs(*f.get_impl(), fence);
2206 return result;
2207 }
2208
2209 /// Type conversion implies a deep copy. No communication except for optional fence.
2210
2211 /// Works in either basis but any loss of precision may result in different errors
2212 /// in applied in a different basis.
2213 ///
2214 /// The new function is formed with the options from the default constructor.
2215 ///
2216 /// There is no automatic type conversion since this is generally a rather dangerous
2217 /// thing and because there would be no way to make the fence optional.
2218 template <typename T, typename Q, std::size_t NDIM>
2221 f.verify();
2222 Function<Q,NDIM> result;
2223 result.set_impl(f, false);
2224 result.get_impl()->copy_coeffs(*f.get_impl(), fence);
2225 return result;
2226 }
2227
2228
2229 /// Return the complex conjugate of the input function with the same distribution and optional fence
2230
2231 /// !!! The fence is actually not optional in the current implementation !!!
2232 template <typename T, std::size_t NDIM>
2235 Function<T,NDIM> result = copy(f,true);
2236 return result.conj(fence);
2237 }
2238
2239 /// Apply operator on a hartree product of two low-dimensional functions
2240
2241 /// Supposed to be something like result= G( f(1)*f(2))
2242 /// the hartree product is never constructed explicitly, but its coeffs are
2243 /// constructed on the fly and processed immediately.
2244 /// @param[in] op the operator
2245 /// @param[in] f1 function of particle 1
2246 /// @param[in] f2 function of particle 2
2247 /// @param[in] fence if we shall fence
2248 /// @return a function of dimension NDIM=LDIM+LDIM
2249 template <typename opT, typename T, std::size_t LDIM>
2250 Function<TENSOR_RESULT_TYPE(typename opT::opT,T), LDIM+LDIM>
2251 apply(const opT& op, const std::vector<Function<T,LDIM>>& f1, const std::vector<Function<T,LDIM>>& f2, bool fence=true) {
2252
2253 World& world=f1.front().world();
2254
2255 typedef TENSOR_RESULT_TYPE(T,typename opT::opT) resultT;
2256 typedef std::vector<Function<T,LDIM>> vecfuncL;
2257
2258 vecfuncL& ff1 = const_cast< vecfuncL& >(f1);
2259 vecfuncL& ff2 = const_cast< vecfuncL& >(f2);
2260
2261 bool same=(ff1[0].get_impl()==ff2[0].get_impl());
2262
2263 reconstruct(world,f1,false);
2264 reconstruct(world,f2,false);
2265 world.gop.fence();
2266 // keep the leaves! They are assumed to be there later
2267 // even for modified op we need NS form for the hartree_leaf_op
2268 for (auto& f : f1) f.make_nonstandard(true,false);
2269 for (auto& f : f2) f.make_nonstandard(true,false);
2270 world.gop.fence();
2271
2272
2275 Function<resultT,LDIM+LDIM> result=factory.empty().fence();
2276
2277 result.get_impl()->reset_timer();
2278 op.reset_timer();
2279
2280 // will fence here
2281 for (size_t i=0; i<f1.size(); ++i)
2282 result.get_impl()->recursive_apply(op, f1[i].get_impl().get(),f2[i].get_impl().get(),false);
2283 world.gop.fence();
2284
2285 if (op.print_timings) {
2286 result.get_impl()->print_timer();
2287 op.print_timer();
2288 }
2289
2290 result.get_impl()->finalize_apply(); // need fence before reconstruct
2291
2292 if (op.modified()) {
2293 result.get_impl()->trickle_down(true);
2294 } else {
2295 result.get_impl()->reconstruct(true);
2296 }
2297 standard(world,ff1,false);
2298 if (not same) standard(world,ff2,false);
2299
2300 return result;
2301 }
2302
2303
2304 /// Apply operator ONLY in non-standard form - required other steps missing !!
2305 template <typename opT, typename R, std::size_t NDIM>
2306 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM>
2307 apply_only(const opT& op, const Function<R,NDIM>& f, bool fence=true) {
2308 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM> result;
2309
2310 constexpr std::size_t OPDIM=opT::opdim;
2311 constexpr bool low_dim=(OPDIM*2==NDIM); // apply on some dimensions only
2312
2313 // specialized version for 3D
2314 if (NDIM <= 3 and (not low_dim)) {
2315 result.set_impl(f, false);
2316 result.get_impl()->apply(op, *f.get_impl(), fence);
2317
2318 } else { // general version for higher dimension
2319 //bool print_timings=false;
2320 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM> r1;
2321
2322 result.set_impl(f, false);
2323 r1.set_impl(f, false);
2324
2325 result.get_impl()->reset_timer();
2326 op.reset_timer();
2327
2328 result.get_impl()->apply_source_driven(op, *f.get_impl(), fence);
2329
2330 // recursive_apply is about 20% faster than apply_source_driven
2331 //result.get_impl()->recursive_apply(op, f.get_impl().get(),
2332 // r1.get_impl().get(),true); // will fence here
2333
2334 }
2335
2336 return result;
2337 }
2338
2339 /// Apply operator in non-standard form
2340
2341 /// Returns a new function with the same distribution
2342 ///
2343 /// !!! For the moment does NOT respect fence option ... always fences
2344 /// if the operator acts on one particle only the result will be sorted as
2345 /// g.particle=1: g(f) = \int g(x,x') f(x',y) dx' = result(x,y)
2346 /// g.particle=2: g(f) = \int g(y,y') f(x,y') dy' = result(x,y)
2347 /// for the second case it will notably *not* be as it is implemented in the partial inner product!
2348 /// g.particle=2 g(f) = result(x,y)
2349 /// inner(g(y,y'),f(x,y'),1,1) = result(y,x)
2350 /// also note the confusion with the counting of the particles/integration variables
2351 template <typename opT, typename R, std::size_t NDIM>
2352 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM>
2353 apply(const opT& op, const Function<R,NDIM>& f, bool fence=true) {
2354
2355 typedef TENSOR_RESULT_TYPE(typename opT::opT,R) resultT;
2356 Function<R,NDIM>& ff = const_cast< Function<R,NDIM>& >(f);
2358
2359 MADNESS_ASSERT(not f.is_on_demand());
2360 bool print_timings=op.print_timings;
2361
2362 if (VERIFY_TREE) ff.verify_tree();
2363 ff.reconstruct();
2364 if (print_timings) ff.print_size("ff in apply after reconstruct");
2365
2366 if (op.modified()) {
2367
2368 ff.change_tree_state(redundant);
2369// ff.get_impl()->make_redundant(true);
2370 result = apply_only(op, ff, fence);
2371 ff.get_impl()->undo_redundant(false);
2372 result.get_impl()->trickle_down(true);
2373
2374 } else {
2375
2376 // saves the standard() step, which is very expensive in 6D
2377// Function<R,NDIM> fff=copy(ff);
2379 fff.make_nonstandard(op.doleaves, true);
2380 if (print_timings) fff.print_size("ff in apply after make_nonstandard");
2381 if ((print_timings) and (f.world().rank()==0)) {
2382 fff.get_impl()->timer_filter.print("filter");
2383 fff.get_impl()->timer_compress_svd.print("compress_svd");
2384 }
2385 result = apply_only(op, fff, fence);
2386 result.get_impl()->set_tree_state(nonstandard_after_apply);
2387 ff.world().gop.fence();
2388 if (print_timings) result.print_size("result after apply_only");
2389
2390 // svd-tensors need some post-processing
2391 if (result.get_impl()->get_tensor_type()==TT_2D) {
2392 double elapsed=result.get_impl()->finalize_apply();
2393 if (print_timings) printf("time in finalize_apply %8.2f\n",elapsed);
2394 }
2395 if (print_timings) {
2396 result.get_impl()->print_timer();
2397 op.print_timer();
2398 }
2399
2400 result.get_impl()->reconstruct(true);
2401
2402// fff.clear();
2403 if (op.destructive()) {
2404 ff.world().gop.fence();
2405 ff.clear();
2406 } else {
2407 // ff.standard();
2408 ff.reconstruct();
2409 }
2410
2411 }
2412 if (print_timings) result.print_size("result after reconstruction");
2413 return result;
2414 }
2415
2416
2417 template <typename opT, typename R, std::size_t NDIM>
2418 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM>
2419 apply_1d_realspace_push(const opT& op, const Function<R,NDIM>& f, int axis, bool fence=true) {
2421 Function<R,NDIM>& ff = const_cast< Function<R,NDIM>& >(f);
2422 if (VERIFY_TREE) ff.verify_tree();
2423 ff.reconstruct();
2424
2425 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM> result;
2426
2427 result.set_impl(ff, false);
2428 result.get_impl()->apply_1d_realspace_push(op, ff.get_impl().get(), axis, fence);
2429 result.get_impl()->set_tree_state(redundant_after_merge);
2430 return result;
2431 }
2432
2433
2434 /// Generate a new function by reordering dimensions ... optional fence
2435
2436 /// You provide an array of dimension NDIM that maps old to new dimensions
2437 /// according to
2438 /// \code
2439 /// newdim = mapdim[olddim]
2440 /// \endcode
2441 /// Works in either scaling function or wavelet basis.
2442 ///
2443 /// Would be easy to modify this to also change the procmap here
2444 /// if desired but presently it uses the same procmap as f.
2445 template <typename T, std::size_t NDIM>
2447 mapdim(const Function<T,NDIM>& f, const std::vector<long>& map, bool fence=true) {
2449 Function<T,NDIM> result;
2450 return result.mapdim(f,map,fence);
2451 }
2452
2453 /// Generate a new function by mirroring within the dimensions .. optional fence
2454
2455 /// similar to mapdim
2456 /// @param[in] mirror array with -1 and 1, corresponding to mirror this dimension or not
2457 template <typename T, std::size_t NDIM>
2459 mirror(const Function<T,NDIM>& f, const std::vector<long>& mirrormap, bool fence=true) {
2461 Function<T,NDIM> result;
2462 return result.mirror(f,mirrormap,fence);
2463 }
2464
2465 /// This is replaced with mirror(map(f)), optional fence
2466
2467 /// first map then mirror!
2468 /// mirror is similar to mapdim, but maps from x to -x, y to -y, and so on
2469 /// Example: mirror a 3d function on the xy plane: mirror={1,1,-1}
2470 /// Example: c4 rotation of a 3d function around the z axis:
2471 /// x->y, y->-x, z->z: map(1,0,2); mirror(-1,1,1)
2472 /// @param[in] map array holding dimensions
2473 /// @param[in] mirror array of -1 and 1, corresponding to mirror or not
2474 template <typename T, std::size_t NDIM>
2476 map_and_mirror(const Function<T,NDIM>& f, const std::vector<long>& map,
2477 const std::vector<long>& mirror, bool fence=true) {
2479 Function<T,NDIM> result;
2480 return result.map_and_mirror(f,map,mirror,fence);
2481 }
2482
2483
2484 /// swap particles 1 and 2
2485
2486 /// param[in] f a function of 2 particles f(1,2)
2487 /// return the input function with particles swapped g(1,2) = f(2,1)
2488 template <typename T, std::size_t NDIM>
2489 typename std::enable_if_t<NDIM%2==0, Function<T,NDIM>>
2491 // this could be done more efficiently for SVD, but it works decently
2492 std::vector<long> map(NDIM);
2493 constexpr std::size_t LDIM=NDIM/2;
2494 static_assert(LDIM*2==NDIM);
2495 for (std::size_t d=0; d<LDIM; ++d) {
2496 map[d]=d+LDIM;
2497 map[d+LDIM]=d;
2498 }
2499// map[0]=3;
2500// map[1]=4;
2501// map[2]=5; // 2 -> 1
2502// map[3]=0;
2503// map[4]=1;
2504// map[5]=2; // 1 -> 2
2505 return mapdim(f,map);
2506 }
2507
2508 /// symmetrize a function
2509
2510 /// @param[in] symmetry possibilities are:
2511 /// (anti-) symmetric particle permutation ("sy_particle", "antisy_particle")
2512 /// symmetric mirror plane ("xy", "xz", "yz")
2513 /// @return a new function symmetrized according to the input parameter
2514 template <typename T, std::size_t NDIM>
2516 symmetrize(const Function<T,NDIM>& f, const std::string symmetry, bool fence=true) {
2517 Function<T,NDIM> result;
2518
2519 MADNESS_ASSERT(NDIM==6); // works only for pair functions
2520 std::vector<long> map(NDIM);
2521
2522 // symmetric particle permutation
2523 if (symmetry=="sy_particle") {
2524 map[0]=3; map[1]=4; map[2]=5;
2525 map[3]=0; map[4]=1; map[5]=2;
2526 } else if (symmetry=="cx") {
2527 map[0]=0; map[1]=2; map[2]=1;
2528 map[3]=3; map[4]=5; map[5]=4;
2529
2530 } else if (symmetry=="cy") {
2531 map[0]=2; map[1]=1; map[2]=0;
2532 map[3]=5; map[4]=4; map[5]=3;
2533
2534 } else if (symmetry=="cz") {
2535 map[0]=1; map[1]=0; map[2]=2;
2536 map[3]=4; map[4]=3; map[5]=5;
2537
2538 } else {
2539 if (f.world().rank()==0) {
2540 print("unknown parameter in symmetrize:",symmetry);
2541 }
2542 MADNESS_EXCEPTION("unknown parameter in symmetrize",1);
2543 }
2544
2545 result.mapdim(f,map,true); // need to fence here
2546 result.get_impl()->average(*f.get_impl());
2547
2548 return result;
2549 }
2550
2551
2552
2553 /// multiply a high-dimensional function with a low-dimensional function
2554
2555 /// @param[in] f NDIM function of 2 particles: f=f(1,2)
2556 /// @param[in] g LDIM function of 1 particle: g=g(1) or g=g(2)
2557 /// @param[in] particle if g=g(1) or g=g(2)
2558 /// @return h(1,2) = f(1,2) * g(p)
2559 template<typename T, std::size_t NDIM, std::size_t LDIM>
2560 Function<T,NDIM> multiply(const Function<T,NDIM> f, const Function<T,LDIM> g, const int particle, const bool fence=true) {
2561
2562 static_assert(LDIM+LDIM==NDIM);
2564
2565 Function<T,NDIM> result;
2566 result.set_impl(f, false);
2567
2568// Function<T,NDIM>& ff = const_cast< Function<T,NDIM>& >(f);
2569// Function<T,LDIM>& gg = const_cast< Function<T,LDIM>& >(g);
2570
2571 f.change_tree_state(redundant,false);
2572 g.change_tree_state(redundant);
2573 FunctionImpl<T,NDIM>* fimpl=f.get_impl().get();
2574 FunctionImpl<T,LDIM>* gimpl=g.get_impl().get();
2575
2576 result.get_impl()->multiply(fimpl,gimpl,particle);
2577 result.world().gop.fence();
2578
2579 f.change_tree_state(reconstructed,false);
2580 g.change_tree_state(reconstructed);
2581 return result;
2582 }
2583
2584
2585 template <typename T, std::size_t NDIM>
2590 bool fence=true)
2591 {
2593 Function<T,NDIM> result = FunctionFactory<T,NDIM>(other.world()).k(k).thresh(thresh).empty();
2594 other.reconstruct();
2595 result.get_impl()->project(*other.get_impl(),fence);
2596 return result;
2597 }
2598
2599
2600 /// Computes the scalar/inner product between two functions
2601
2602 /// In Maple this would be \c int(conjugate(f(x))*g(x),x=-infinity..infinity)
2603 template <typename T, typename R, std::size_t NDIM>
2606 return f.inner(g);
2607 }
2608
2609
2610 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2611
2612 /// syntax similar to the inner product in tensor.h
2613 /// e.g result=inner<3>(f,g),{0},{1}) : r(x,y) = int f(x1,x) g(y,x1) dx1
2614 /// @param[in] task 0: everything, 1; prepare only (fence), 2: work only (no fence), 3: finalize only (fence)
2615 template<std::size_t NDIM, typename T, std::size_t LDIM, typename R, std::size_t KDIM,
2616 std::size_t CDIM = (KDIM + LDIM - NDIM) / 2>
2617 std::vector<Function<TENSOR_RESULT_TYPE(T, R), NDIM>>
2618 innerXX(const Function<T, LDIM>& f, const std::vector<Function<R, KDIM>>& vg, const std::array<int, CDIM> v1,
2619 const std::array<int, CDIM> v2, int task=0) {
2620 bool prepare = ((task==0) or (task==1));
2621 bool work = ((task==0) or (task==2));
2622 bool finish = ((task==0) or (task==3));
2623
2624 static_assert((KDIM + LDIM - NDIM) % 2 == 0, "faulty dimensions in inner (partial version)");
2625 static_assert(KDIM + LDIM - 2 * CDIM == NDIM, "faulty dimensions in inner (partial version)");
2626
2627 // contraction indices must be contiguous and either in the beginning or at the end
2628 for (size_t i=0; i<CDIM-1; ++i) MADNESS_CHECK((v1[i]+1)==v1[i+1]);
2629 MADNESS_CHECK((v1[0]==0) or (v1[CDIM-1]==LDIM-1));
2630
2631 for (size_t i=0; i<CDIM-1; ++i) MADNESS_CHECK((v2[i]+1)==v2[i+1]);
2632 MADNESS_CHECK((v2[0]==0) or (v2[CDIM-1]==KDIM-1));
2633
2634 MADNESS_CHECK(f.is_initialized());
2636 MADNESS_CHECK(f.world().id() == vg[0].world().id());
2637 // this needs to be run in a single world, so that all coefficients are local.
2638 // Use macrotasks if run on multiple processes.
2639 World& world=f.world();
2640 MADNESS_CHECK(world.size() == 1);
2641
2642 if (prepare) {
2643 f.change_tree_state(nonstandard);
2645 world.gop.fence();
2646 f.get_impl()->compute_snorm_and_dnorm(false);
2647 for (auto& g : vg) g.get_impl()->compute_snorm_and_dnorm(false);
2648 world.gop.fence();
2649 }
2650
2651 typedef TENSOR_RESULT_TYPE(T, R) resultT;
2652 std::vector<Function<resultT,NDIM>> result(vg.size());
2653 if (work) {
2655 for (size_t i=0; i<vg.size(); ++i) {
2657 .k(f.k()).thresh(f.thresh()).empty().nofence();
2658 result[i].get_impl()->partial_inner(*f.get_impl(),*(vg[i]).get_impl(),v1,v2);
2659 result[i].get_impl()->set_tree_state(nonstandard_after_apply);
2660 }
2661 world.gop.set_forbid_fence(false);
2662 }
2663
2664 if (finish) {
2665
2666 world.gop.fence();
2667// result.get_impl()->reconstruct(true);
2668
2670// result.reconstruct();
2671 // restore initial state of g and h
2672 auto erase_list = [] (const auto& funcimpl) {
2673 typedef typename std::decay_t<decltype(funcimpl)>::keyT keyTT;
2674 std::list<keyTT> to_be_erased;
2675 for (auto it=funcimpl.get_coeffs().begin(); it!=funcimpl.get_coeffs().end(); ++it) {
2676 const auto& key=it->first;
2677 const auto& node=it->second;
2678 if (not node.has_children()) to_be_erased.push_back(key);
2679 }
2680 return to_be_erased;
2681 };
2682
2683 FunctionImpl<T,LDIM>& f_nc=const_cast<FunctionImpl<T,LDIM>&>(*f.get_impl());
2684 for (auto& key : erase_list(f_nc)) f_nc.get_coeffs().erase(key);
2685 for (auto& g : vg) {
2686 FunctionImpl<R,KDIM>& g_nc=const_cast<FunctionImpl<R,KDIM>&>(*g.get_impl());
2687 for (auto& key : erase_list(g_nc)) g_nc.get_coeffs().erase(key);
2688 }
2689 world.gop.fence();
2691 f_nc.reconstruct(false);
2692 world.gop.fence();
2693
2694 }
2695
2696 return result;
2697 }
2698
2699
2700 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2701
2702 /// syntax similar to the inner product in tensor.h
2703 /// e.g result=inner<3>(f,g),{0},{1}) : r(x,y) = int f(x1,x) g(y,x1) dx1
2704 /// @param[in] task 0: everything, 1; prepare only (fence), 2: work only (no fence), 3: finalize only (fence)
2705 template<std::size_t NDIM, typename T, std::size_t LDIM, typename R, std::size_t KDIM,
2706 std::size_t CDIM = (KDIM + LDIM - NDIM) / 2>
2708 innerXX(const Function<T, LDIM>& f, const Function<R, KDIM>& g, const std::array<int, CDIM> v1,
2709 const std::array<int, CDIM> v2, int task=0) {
2710 return innerXX<NDIM,T,LDIM,R,KDIM>(f,std::vector<Function<R,KDIM>>({g}),v1,v2,task)[0];
2711 }
2712
2713 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2714
2715 /// syntax similar to the inner product in tensor.h
2716 /// e.g result=inner<3>(f,g),{0},{1}) : r(x,y) = int f(x1,x) g(y,x1) dx1
2717 template <typename T, std::size_t LDIM, typename R, std::size_t KDIM>
2719 inner(const Function<T,LDIM>& f, const Function<R,KDIM>& g, const std::tuple<int> v1, const std::tuple<int> v2) {
2720 return innerXX<KDIM+LDIM-2>(f,g,
2721 std::array<int,1>({std::get<0>(v1)}),
2722 std::array<int,1>({std::get<0>(v2)}));
2723 }
2724
2725 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2726
2727 /// syntax similar to the inner product in tensor.h
2728 /// e.g result=inner<3>(f,g),{0,1},{1,2}) : r(y) = int f(x1,x2) g(y,x1,x2) dx1 dx2
2729 template <typename T, std::size_t LDIM, typename R, std::size_t KDIM>
2731 inner(const Function<T,LDIM>& f, const Function<R,KDIM>& g, const std::tuple<int,int> v1, const std::tuple<int,int> v2) {
2732 return innerXX<KDIM+LDIM-4>(f,g,
2733 std::array<int,2>({std::get<0>(v1),std::get<1>(v1)}),
2734 std::array<int,2>({std::get<0>(v2),std::get<1>(v2)}));
2735 }
2736
2737 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2738
2739 /// syntax similar to the inner product in tensor.h
2740 /// e.g result=inner<3>(f,g),{1},{2}) : r(x,y,z) = int f(x,x1) g(y,z,x1) dx1
2741 template <typename T, std::size_t LDIM, typename R, std::size_t KDIM>
2743 inner(const Function<T,LDIM>& f, const Function<R,KDIM>& g, const std::tuple<int,int,int> v1, const std::tuple<int,int,int> v2) {
2744 return innerXX<KDIM+LDIM-6>(f,g,
2745 std::array<int,3>({std::get<0>(v1),std::get<1>(v1),std::get<2>(v1)}),
2746 std::array<int,3>({std::get<0>(v2),std::get<1>(v2),std::get<2>(v2)}));
2747 }
2748
2749
2750
2751 /// Computes the scalar/inner product between an MRA function and an external functor
2752
2753 /// Currently this defaults to inner_adaptive, which might be more expensive
2754 /// than inner_ext since it loops over all leaf nodes. If you feel inner_ext
2755 /// is more efficient you need to call it directly
2756 /// @param[in] f MRA function
2757 /// @param[in] g functor
2758 /// @result inner(f,g)
2759 template <typename T, typename opT, std::size_t NDIM>
2760 TENSOR_RESULT_TYPE(T,typename opT::value_type) inner(const Function<T,NDIM>& f, const opT& g) {
2762 std::shared_ptr< FunctionFunctorInterface<double,3> > func(new opT(g));
2763 return f.inner_adaptive(func);
2764 }
2765
2766 /// Computes the scalar/inner product between an MRA function and an external functor
2767
2768 /// Currently this defaults to inner_adaptive, which might be more expensive
2769 /// than inner_ext since it loops over all leaf nodes. If you feel inner_ext
2770 /// is more efficient you need to call it directly
2771 /// @param[in] g functor
2772 /// @param[in] f MRA function
2773 /// @result inner(f,g)
2774 template <typename T, typename opT, std::size_t NDIM>
2775 TENSOR_RESULT_TYPE(T,typename opT::value_type) inner(const opT& g, const Function<T,NDIM>& f) {
2776 return inner(f,g);
2777 }
2778
2779 template <typename T, typename R, std::size_t NDIM>
2782 return (f*R(1.0)).add_scalar(r);
2783 }
2784
2785 template <typename T, typename R, std::size_t NDIM>
2788 return (f*R(1.0)).add_scalar(r);
2789 }
2790
2791 template <typename T, typename R, std::size_t NDIM>
2794 return (f*R(1.0)).add_scalar(-r);
2795 }
2796
2797 template <typename T, typename R, std::size_t NDIM>
2800 return (f*R(-1.0)).add_scalar(r);
2801 }
2802
2803 namespace detail {
2804 template <std::size_t NDIM>
2805 struct realop {
2806 typedef double resultT;
2808 return real(t);
2809 }
2810
2811 template <typename Archive> void serialize (Archive& ar) {}
2812 };
2813
2814 template <std::size_t NDIM>
2815 struct imagop {
2816 typedef double resultT;
2818 return imag(t);
2819 }
2820
2821 template <typename Archive> void serialize (Archive& ar) {}
2822 };
2823
2824 template <std::size_t NDIM>
2825 struct abssqop {
2826 typedef double resultT;
2828 Tensor<double> r = abs(t);
2829 return r.emul(r);
2830 }
2831
2832 template <typename Archive> void serialize (Archive& ar) {}
2833 };
2834
2835 template <std::size_t NDIM>
2836 struct absop {
2837 typedef double resultT;
2839 Tensor<double> r = abs(t);
2840 return r;
2841 }
2842
2843 template <typename Archive> void serialize (Archive& ar) {}
2844 };
2845
2846 }
2847
2848 /// Returns a new function that is the real part of the input
2849 template <std::size_t NDIM>
2853
2854 /// Returns a new function that is the real part of the input
2855 template <std::size_t NDIM>
2857 return copy(z);
2858 }
2859
2860 /// Returns a new function that is the imaginary part of the input
2861 template <std::size_t NDIM>
2865
2866
2867 /// Create a new function that is the square of f - global comm only if not reconstructed
2868 template <typename T, std::size_t NDIM>
2871 Function<T,NDIM> result = copy(f,true); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2872 return result.square(true); //fence); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2873 }
2874
2875 /// Create a new function that is the abs of f - global comm only if not reconstructed
2876 template <typename T, std::size_t NDIM>
2877 Function<T,NDIM> abs(const Function<T,NDIM>& f, bool fence=true) {
2879 Function<T,NDIM> result = copy(f,true); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2880 return result.abs(true); //fence); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2881 }
2882
2883 /// Create a new function that is the abs_square of f - global comm only if not reconstructed
2884 template <typename T, std::size_t NDIM>
2885 typename std::enable_if<!TensorTypeData<T>::iscomplex, Function<T,NDIM> >::type
2886 abs_square(const Function<T,NDIM>& f, bool fence=true) {
2888 Function<T,NDIM> result = copy(f,true); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2889 return result.abs_square(true); //fence); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2890 }
2891
2892 /// Create a new function that is the abs_square of f - global comm only if not reconstructed
2893 template <typename T, std::size_t NDIM>
2894 typename std::enable_if<TensorTypeData<T>::iscomplex, Function<typename Tensor<T>::scalar_type,NDIM> >::type
2895 abs_square(const Function<T,NDIM>& f, bool fence=true) {
2897 }
2898
2899 /// Returns a new function that is the square of the absolute value of the input
2900 template <std::size_t NDIM>
2904
2905 /// Returns a new function that is the absolute value of the input
2906 template <std::size_t NDIM>
2910
2911 /// get tree state of a function
2912
2913 /// there is a corresponding function in vmra.h
2914 /// @param[in] f function
2915 /// @return TreeState::unknown if the function is not initialized
2916 template <typename T, std::size_t NDIM>
2918 if (f.is_initialized()) return f.get_impl()->get_tree_state();
2919 return TreeState::unknown;
2920 }
2921
2922 /// change tree state of a function
2923
2924 /// there is a corresponding function in vmra.h
2925 /// return this for chaining
2926 /// @param[in] f function
2927 /// @param[in] finalstate the new state
2928 /// @return this in the requested state
2929 template <typename T, std::size_t NDIM>
2934
2935 template <typename R, std::size_t MDIM>
2937 f1.impl.swap(f2.impl);
2938 }
2939
2940}
2941
2942#include <madness/mra/funcplot.h>
2943
2944namespace madness {
2945 namespace archive {
2946 template <class archiveT, class T, std::size_t NDIM>
2948 static inline void load(const ParallelInputArchive<archiveT>& ar, Function<T,NDIM>& f) {
2949 f.load(*ar.get_world(), ar);
2950 }
2951 };
2952
2953 template <class archiveT, class T, std::size_t NDIM>
2955 static inline void store(const ParallelOutputArchive<archiveT>& ar, const Function<T,NDIM>& f) {
2956 f.store(ar);
2957 }
2958 };
2959 }
2960
2961 template <class T, std::size_t NDIM>
2962 void save(const Function<T,NDIM>& f, const std::string name) {
2964 ar2 & f;
2965 }
2966
2967 template <class T, std::size_t NDIM>
2968 void load(Function<T,NDIM>& f, const std::string name) {
2970 ar2 & f;
2971 }
2972
2973}
2974
2975namespace madness {
2976 // type traits to check if a template parameter is a Function
2977 template<typename>
2978 struct is_madness_function : std::false_type {};
2979
2980 template<typename T, std::size_t NDIM>
2981 struct is_madness_function<madness::Function<T, NDIM>> : std::true_type {};
2982
2983}
2984
2985
2986/* @} */
2987
2988#include <madness/mra/derivative.h>
2989#include <madness/mra/operator.h>
2991#include <madness/mra/vmra.h>
2992// #include <madness/mra/mraimpl.h> !!!!!!!!!!!!! NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO !!!!!!!!!!!!!!!!!!
2993
2994#endif // MADNESS_MRA_MRA_H__INCLUDED
double q(double t)
Definition DKops.h:18
This header should include pretty much everything needed for the parallel runtime.
long dim(int i) const
Returns the size of dimension i.
Definition basetensor.h:147
This class is used to specify boundary conditions for all operators.
Definition bc.h:72
CompositeFunctorInterface implements a wrapper of holding several functions and functors.
Definition function_interface.h:172
FunctionDefaults holds default paramaters as static class members.
Definition funcdefaults.h:100
static const double & get_thresh()
Returns the default threshold.
Definition funcdefaults.h:177
static std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > & get_pmap()
Returns the default process map that was last initialized via set_default_pmap()
Definition funcdefaults.h:401
static void set_cell(const Tensor< double > &value)
Sets the user cell for the simulation.
Definition funcdefaults.h:366
FunctionFactory implements the named-parameter idiom for Function.
Definition function_factory.h:86
virtual FunctionFactory & thresh(double thresh)
Definition function_factory.h:198
virtual FunctionFactory & k(int k)
Definition function_factory.h:193
Abstract base class interface required for functors used as input to Functions.
Definition function_interface.h:68
FunctionImpl holds all Function state to facilitate shallow copy semantics.
Definition funcimpl.h:945
const dcT & get_coeffs() const
Definition mraimpl.h:343
bool is_on_demand() const
Definition mraimpl.h:283
FunctionNode holds the coefficients, etc., at each node of the 2^NDIM-tree.
Definition funcimpl.h:127
A multiresolution adaptive numerical function.
Definition mra.h:139
void print_tree_json(std::ostream &os=std::cout) const
Definition mra.h:996
Tensor< T > eval_cube(const Tensor< double > &cell, const std::vector< long > &npt, bool eval_refine=false) const
Evaluates a cube/slice of points (probably for plotting) ... collective but no fence necessary.
Definition mra.h:410
TENSOR_RESULT_TYPE(T, R) inner(const Function< R
Returns the inner product.
Function< T, NDIM > & map_and_mirror(const Function< T, NDIM > &f, const std::vector< long > &map, const std::vector< long > &mirror, bool fence)
This is replaced with mirror(map(f)) ... private.
Definition mra.h:1811
void gaxpy_ext(const Function< L, NDIM > &left, T(*f)(const coordT &), T alpha, T beta, double tol, bool fence=true) const
Definition mra.h:1512
T inner_adaptive(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > f, const bool leaf_refine=true) const
Definition mra.h:1497
void unaryop_coeff(const opT &op, bool fence=true)
Unary operation applied inplace to the coefficients.
Definition mra.h:1046
bool is_compressed() const
Returns true if compressed, false otherwise. No communication.
Definition mra.h:542
Function< T, NDIM/2 > dirac_convolution(const bool fence=true) const
Definition mra.h:1576
return impl inner_local * g())
void set_impl(const Function< R, NDIM > &f, bool zero=true)
Replace current FunctionImpl with a new one using the same parameters & map as f.
Definition mra.h:747
bool autorefine() const
Returns value of autorefine flag. No communication.
Definition mra.h:653
TreeState operating_state
Definition mra.h:1438
Function< T, NDIM > & add_scalar(T t, bool fence=true)
Inplace add scalar. No communication except for optional fence.
Definition mra.h:1095
void print_size(const std::string name) const
print some info about this
Definition mra.h:593
Function< T, NDIM > & fill_tree(const Function< R, NDIM > &g, bool fence=true)
With this being an on-demand function, fill the MRA tree according to different criteria.
Definition mra.h:1282
void broaden(const BoundaryConditions< NDIM > &bc=FunctionDefaults< NDIM >::get_bc(), bool fence=true) const
Inplace broadens support in scaling function basis.
Definition mra.h:968
void print_info() const
Print a summary of the load balancing info.
Definition mra.h:1012
Function< T, NDIM > & scale(const Q q, bool fence=true)
Inplace, scale the function by a constant. No communication except for optional fence.
Definition mra.h:1085
void norm_tree(bool fence=true) const
Initializes information about the function norm at all length scales.
Definition mra.h:833
void load(World &world, Archive &ar)
Replaces this function with one loaded from an archive using the default processor map.
Definition mra.h:1593
Function< T, NDIM > & abs_square(bool fence=true)
Returns *this for chaining.
Definition mra.h:1222
void replicate(const DistributionType type, bool fence=true) const
Definition mra.h:771
double norm2sq_local() const
Returns the square of the norm of the local function ... no communication.
Definition mra.h:808
IsSupported< TensorTypeData< Q >, Function< T, NDIM > >::type & operator*=(const Q q)
Inplace scaling by a constant.
Definition mra.h:1194
void sum_down(bool fence=true) const
Sums scaling coeffs down tree restoring state with coeffs only at leaves. Optional fence....
Definition mra.h:930
Level depthpt(const coordT &xuser) const
Definition mra.h:486
bool is_redundant() const
Returns true if redundant, false otherwise. No communication.
Definition mra.h:572
Function< T, NDIM > & operator+=(const Function< Q, NDIM > &other)
Inplace addition of functions in the wavelet basis.
Definition mra.h:1154
Function< T, NDIM > & operator=(const Function< T, NDIM > &f)
Assignment is shallow. No communication, works in either basis.
Definition mra.h:191
void set_autorefine(bool value, bool fence=true)
Sets the value of the autorefine flag. Optional global fence.
Definition mra.h:663
World & world() const
Returns the world.
Definition mra.h:753
T trace() const
Returns global value of int(f(x),x) ... global comm required.
Definition mra.h:1244
T typeT
Definition mra.h:157
friend void swap(Function< R, MDIM > &f1, Function< R, MDIM > &f2)
implements swap algorithm
Definition mra.h:2936
Function< T, NDIM > & fill_tree(const opT &op, bool fence=true)
With this being an on-demand function, fill the MRA tree according to different criteria.
Definition mra.h:1300
const Function< T, NDIM > & change_tree_state(const TreeState finalstate, bool fence=true) const
changes tree state to given state
Definition mra.h:917
Function< typename opT::resultT, NDIM > & unary_op_coeffs(const Function< Q, NDIM > &func, const opT &op, bool fence)
This is replaced with left*right ... private.
Definition mra.h:1649
void print_tree_graphviz(std::ostream &os=std::cout) const
Process 0 prints a graphviz-formatted output of all nodes in the tree (collective)
Definition mra.h:1002
double norm2() const
Returns the 2-norm of the function ... global sum ... works in either basis.
Definition mra.h:820
Function< T, NDIM > & fill_cuspy_tree(const opT &op, const bool fence=true)
Definition mra.h:1323
void change_tensor_type(const TensorArgs &targs, bool fence=true)
change the tensor type of the coefficients in the FunctionNode
Definition mra.h:1641
const Function< T, NDIM > & refine(bool fence=true) const
Inplace autorefines the function using same test as for squaring.
Definition mra.h:962
TENSOR_RESULT_TYPE(T, R) inner_on_demand(const Function< R
Returns the inner product for one on-demand function.
T operator()(const coordT &xuser) const
Evaluates the function at a point in user coordinates. Collective operation.
Definition mra.h:451
MADNESS_ASSERT(g.is_compressed())
Function< T, NDIM > & square(bool fence=true)
Inplace squaring of function ... global comm only if not reconstructed.
Definition mra.h:1204
Function< T, NDIM > & fill_tree(bool fence=true)
With this being an on-demand function, fill the MRA tree according to different criteria.
Definition mra.h:1311
void verify_tree() const
Verifies the tree data structure ... global sync implied.
Definition mra.h:533
Future< Level > evaldepthpt(const coordT &xuser) const
Definition mra.h:332
void do_hartree_product(const std::vector< std::shared_ptr< FunctionImpl< T, LDIM > > > left, const std::vector< std::shared_ptr< FunctionImpl< T, KDIM > > > right)
perform the hartree product of f*g, invoked by result
Definition mra.h:1392
Function< T, NDIM > & mapdim(const Function< T, NDIM > &f, const std::vector< long > &map, bool fence)
This is replaced with mapdim(f) ... private.
Definition mra.h:1777
impl world gop fence()
int k() const
Returns the number of multiwavelets (k). No communication.
Definition mra.h:691
const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > & get_pmap() const
Returns a shared pointer to the process map.
Definition mra.h:761
double thresh() const
Returns value of truncation threshold. No communication.
Definition mra.h:672
Function< T, NDIM > & gaxpy_oop(T alpha, const Function< L, NDIM > &left, T beta, const Function< R, NDIM > &right, bool fence)
This is replaced with alpha*left + beta*right ... private.
Definition mra.h:1763
void set_thresh(double value, bool fence=true)
Sets the value of the truncation threshold. Optional global fence.
Definition mra.h:682
Function< T, NDIM > & multiop_values(const opT &op, const std::vector< Function< T, NDIM > > &vf)
This is replaced with op(vector of functions) ... private.
Definition mra.h:1671
void distribute(std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > newmap) const
distribute this function according to newmap
Definition mra.h:799
void unaryop(const opT &op, bool fence=true)
Inplace unary operation on function values.
Definition mra.h:1036
const std::shared_ptr< FunctionImpl< T, NDIM > > & get_impl() const
Returns a shared-pointer to the implementation.
Definition mra.h:719
void standard(bool fence=true)
Converts the function standard compressed form. Possible non-blocking comm.
Definition mra.h:880
void unaryop_node(const opT &op, bool fence=true)
Unary operation applied inplace to the nodes.
Definition mra.h:1056
Function< T, NDIM > & truncate(double tol=0.0, bool fence=true)
Truncate the function with optional fence. Compresses with fence if not compressed.
Definition mra.h:707
Function< T, NDIM > & fill_cuspy_tree(const bool fence=true)
Special refinement on 6D boxes where the electrons come close (meet)
Definition mra.h:1336
std::size_t size() const
Returns the number of coefficients in the function ... collective global sum.
Definition mra.h:638
bool is_on_demand() const
Definition mra.h:741
Function< T, NDIM > & operator-=(const Function< Q, NDIM > &other)
Inplace subtraction of functions in the wavelet basis.
Definition mra.h:1173
bool compressed
Definition mra.h:1258
const Function< T, NDIM > & reconstruct(bool fence=true) const
Reconstructs the function, transforming into scaling function basis. Possible non-blocking comm.
Definition mra.h:907
Function< T, NDIM > & abs(bool fence=true)
Returns *this for chaining.
Definition mra.h:1213
Function< T, NDIM > & reduce_rank(const double thresh=0.0, const bool fence=true)
reduce the rank of the coefficient tensors
Definition mra.h:1841
Function< T, NDIM > & mirror(const Function< T, NDIM > &f, const std::vector< long > &mirrormap, bool fence)
This is replaced with mirror(f) ... private.
Definition mra.h:1792
std::size_t max_nodes() const
Returns the max number of nodes on a processor.
Definition mra.h:623
void do_hartree_product(const std::vector< std::shared_ptr< FunctionImpl< T, LDIM > > > left, const std::vector< std::shared_ptr< FunctionImpl< T, KDIM > > > right, const opT *op)
perform the hartree product of f*g, invoked by result
Definition mra.h:1378
std::shared_ptr< FunctionImpl< T, NDIM > > impl
Definition mra.h:146
void replicate_on_hosts(bool fence=true) const
replicate this function, one copy per host
Definition mra.h:792
void replicate(bool fence=true) const
replicate this function, generating a unique pmap
Definition mra.h:782
T trace_local() const
Returns local contribution to int(f(x),x) ... no communication.
Definition mra.h:1235
void mul_on_demand(const Function< L, NDIM > &f, const Function< R, NDIM > &g, bool fence=true)
Same as operator* but with optional fence and no automatic reconstruction.
Definition mra.h:1734
Function< T, NDIM > & gaxpy(const T &alpha, const Function< Q, NDIM > &other, const R &beta, bool fence=true)
Inplace, general bi-linear operation in wavelet basis. No communication except for optional fence.
Definition mra.h:1115
Vector< double, NDIM > coordT
Type of vector holding coordinates.
Definition mra.h:156
void store(Archive &ar) const
Stores the function to an archive.
Definition mra.h:1629
std::size_t max_local_depth() const
Returns the maximum local depth of the function tree ... no communications.
Definition mra.h:615
void vtransform(const std::vector< Function< R, NDIM > > &v, const Tensor< Q > &c, std::vector< Function< T, NDIM > > &vresult, double tol, bool fence=true)
sparse transformation of a vector of functions ... private
Definition mra.h:1752
TENSOR_RESULT_TYPE(T, R) local
std::size_t max_depth() const
Returns the maximum depth of the function tree ... collective global sum.
Definition mra.h:602
Function()
Default constructor makes uninitialized function. No communication.
Definition mra.h:174
std::vector< std::pair< bool, T > > eval_local_only(const std::vector< coordT > &xuser, Level maxlevel) const
Definition mra.h:320
std::size_t tree_size() const
Returns the number of nodes in the function tree ... collective global sum.
Definition mra.h:586
Function< TENSOR_RESULT_TYPE(T, R), NDIM-LDIM > project_out(const Function< R, LDIM > &g, const int dim) const
project this on the low-dim function g: h(x) = <f(x,y) | g(y)>
Definition mra.h:1552
static std::vector< std::shared_ptr< FunctionImpl< Q, D > > > vimpl(const std::vector< Function< Q, D > > &v)
Returns vector of FunctionImpl pointers corresponding to vector of functions.
Definition mra.h:1662
FunctionImpl< T, NDIM > implT
Definition mra.h:153
void clear(bool fence=true)
Clears the function as if constructed uninitialized. Optional fence.
Definition mra.h:979
void refine_general(const opT &op, bool fence=true) const
Inplace autorefines the function. Optional fence. Possible non-blocking comm.
Definition mra.h:943
static void doconj(const Key< NDIM >, Tensor< T > &t)
Definition mra.h:1066
std::pair< bool, T > eval_local_only(const Vector< double, NDIM > &xuser, Level maxlevel) const
Evaluate function only if point is local returning (true,value); otherwise return (false,...
Definition mra.h:245
void set_functor(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > functor)
Replace the current functor with the provided new one.
Definition mra.h:736
bool impl_initialized() const
Definition mra.h:149
Function< T, NDIM > & fill_nuclear_cuspy_tree(const opT &op, const size_t particle, const bool fence=true)
Definition mra.h:1351
bool is_redundant_after_merge() const
Returns true if redundant_after_merge, false otherwise. No communication.
Definition mra.h:580
return local
Definition mra.h:1453
void eval_local_only(const std::vector< coordT > &xuser, Level maxlevel, std::vector< std::pair< bool, T > > &results) const
Batched eval_local_only writing into a caller-provided buffer.
Definition mra.h:285
auto func
Definition mra.h:1531
~Function()
Destruction of any underlying implementation is deferred to next global fence.
Definition mra.h:198
Function(const Function< T, NDIM > &f)
Copy constructor is shallow. No communication, works in either basis.
Definition mra.h:185
void set_impl(const std::shared_ptr< FunctionImpl< T, NDIM > > &impl)
Replace current FunctionImpl with provided new one.
Definition mra.h:726
T operator()(double x, double y=0, double z=0, double xx=0, double yy=0, double zz=0) const
Evaluates the function at a point in user coordinates. Collective operation.
Definition mra.h:465
T inner_ext_local(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > f, const bool leaf_refine=true, const bool keep_redundant=false) const
Definition mra.h:1464
std::size_t min_nodes() const
Returns the min number of nodes on a processor.
Definition mra.h:630
constexpr std::size_t LDIM
Definition mra.h:1530
static constexpr std::size_t dimT
Definition mra.h:158
change_tree_state(operating_state, false)
bool is_nonstandard() const
Returns true if nonstandard-compressed, false otherwise. No communication.
Definition mra.h:564
void verify() const
Asserts that the function is initialized.
Definition mra.h:162
double err(const funcT &func) const
Returns an estimate of the difference ||this-func|| ... global sum performed.
Definition mra.h:520
T inner_ext(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > f, const bool leaf_refine=true, const bool keep_redundant=false) const
Definition mra.h:1480
void make_redundant(bool fence=true)
Converts the function to redundant form, i.e. sum coefficients on all levels.
Definition mra.h:892
Function< T, NDIM > & fill_nuclear_cuspy_tree(const size_t particle, const bool fence=true)
Special refinement on 6D boxes for the nuclear potentials (regularized with cusp, non-regularized wit...
Definition mra.h:1364
double check_symmetry() const
check symmetry of a function by computing the 2nd derivative
Definition mra.h:1827
void multi_to_multi_op_values(const opT &op, const std::vector< Function< T, NDIM > > &vin, std::vector< Function< T, NDIM > > &vout, const bool fence=true)
apply op on the input vector yielding an output vector of functions
Definition mra.h:1690
FunctionFactory< T, NDIM > factoryT
Definition mra.h:155
std::size_t size_local() const
Return the number of coefficients in the function on this processor.
Definition mra.h:645
const Function< T, NDIM > & compress(bool fence=true) const
Compresses the function, transforming into wavelet basis. Possible non-blocking comm.
Definition mra.h:853
bool is_initialized() const
Returns true if the function is initialized.
Definition mra.h:167
bool is_reconstructed() const
Returns true if reconstructed, false otherwise. No communication.
Definition mra.h:553
Function< T, NDIM > & chop_at_level(const int n, const bool fence=true)
remove all nodes with level higher than n
Definition mra.h:1849
MADNESS_ASSERT(is_compressed())
void vmulXX(const Function< L, NDIM > &left, const std::vector< Function< R, NDIM > > &right, std::vector< Function< T, NDIM > > &result, double tol, bool fence)
Multiplication of function * vector of functions using recursive algorithm of mulxx.
Definition mra.h:1711
double errsq_local(const funcT &func) const
Returns an estimate of the difference ||this-func||^2 from local data.
Definition mra.h:505
void make_nonstandard(bool keepleaves, bool fence=true) const
Compresses the function retaining scaling function coeffs. Possible non-blocking comm.
Definition mra.h:866
if(VERIFY_TREE) verify_tree()
Future< T > eval(const coordT &xuser) const
Evaluates the function at a point in user coordinates. Possible non-blocking comm.
Definition mra.h:211
void print_tree(std::ostream &os=std::cout) const
Process 0 prints a summary of all nodes in the tree (collective)
Definition mra.h:989
FunctionNode< T, NDIM > nodeT
Definition mra.h:154
bool redundant
Definition mra.h:1259
Future< long > evalR(const coordT &xuser) const
Evaluates the function rank at a point in user coordinates. Possible non-blocking comm.
Definition mra.h:369
Function(const factoryT &factory)
Constructor from FunctionFactory provides named parameter idiom. Possible non-blocking communication.
Definition mra.h:178
NDIM &g const
Definition mra.h:1256
void unaryop(T(*f)(T))
Inplace unary operation on function values.
Definition mra.h:1027
Function< T, NDIM > conj(bool fence=true)
Inplace complex conjugate. No communication except for optional fence.
Definition mra.h:1074
A future is a possibly yet unevaluated value.
Definition future.h:370
remote_refT remote_ref(World &world) const
Returns a structure used to pass references to another process.
Definition future.h:672
Key is the index for a node of the 2^NDIM-tree.
Definition key.h:70
Definition leafop.h:391
Definition leafop.h:261
Traits class to specify support of numeric types.
Definition type_data.h:56
A tensor is a multidimensional array.
Definition tensor.h:318
Tensor< T > & emul(const Tensor< T > &t)
Inplace multiply by corresponding elements of argument Tensor.
Definition tensor.h:1800
Tensor< T > & conj()
Inplace complex conjugate.
Definition tensor.h:717
A simple, fixed dimension vector.
Definition vector.h:64
void erase(const keyT &key)
Erases entry from container (non-blocking comm if remote)
Definition worlddc.h:1392
Interface to be provided by any process map.
Definition worlddc.h:122
void fence(bool debug=false)
Synchronizes all processes in communicator AND globally ensures no pending AM or tasks.
Definition worldgop.cc:176
bool set_forbid_fence(bool value)
Set forbid_fence flag to new value and return old value.
Definition worldgop.h:677
A parallel world class.
Definition world.h:132
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition world.h:320
ProcessID size() const
Returns the number of processes in this World (same as MPI_Comm_size()).
Definition world.h:330
WorldGopInterface & gop
Global operations.
Definition world.h:207
World * get_world() const
Returns a pointer to the world.
Definition parallel_archive.h:130
An archive for storing local or parallel data, wrapping a BinaryFstreamInputArchive.
Definition parallel_archive.h:366
An archive for storing local or parallel data wrapping a BinaryFstreamOutputArchive.
Definition parallel_archive.h:321
Objects that implement their own parallel archive interface should derive from this class.
Definition parallel_archive.h:58
static const double R
Definition csqrt.cc:46
Declaration and initialization of tree traversal functions and generic derivative.
double(* f1)(const coord_3d &)
Definition derivatives.cc:55
double(* f2)(const coord_3d &)
Definition derivatives.cc:56
const double delta
Definition dielectric_external_field.cc:119
Provides FunctionDefaults and utilities for coordinate transformation.
Provides FunctionCommonData, FunctionImpl and FunctionFactory.
Defines/implements plotting interface for functions.
Provides typedefs to hide use of templates and to increase interoperability.
auto T(World &world, response_space &f) -> response_space
Definition global_functions.cc:28
const double beta
Definition gygi_soltion.cc:62
static const double v
Definition hatom_sf_dirac.cc:20
Provides IndexIterator.
Tensor< double > op(const Tensor< double > &x)
Definition kain.cc:508
Multidimension Key for MRA tree and associated iterators.
Implements (2nd generation) static load/data balancing for functions.
#define MADNESS_CHECK(condition)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:182
#define MADNESS_EXCEPTION(msg, value)
Macro for throwing a MADNESS exception.
Definition madness_exception.h:119
#define MADNESS_ASSERT(condition)
Assert a condition that should be free of side-effects since in release builds this might be a no-op.
Definition madness_exception.h:134
#define MADNESS_CHECK_THROW(condition, msg)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:207
Header to declare stuff which has not yet found a home.
static const bool VERIFY_TREE
Definition mra.h:57
Definition potentialmanager.cc:41
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:10
double abs(double x)
Definition complexfun.h:48
Function< double, NDIM > abssq(const Function< double_complex, NDIM > &z, bool fence=true)
Returns a new function that is the square of the absolute value of the input.
Definition mra.h:2901
DistributionType
some introspection of how data is distributed
Definition worlddc.h:81
@ NodeReplicated
even if there are several ranks per node
Definition worlddc.h:84
@ RankReplicated
replicate the container over all world ranks
Definition worlddc.h:83
Function< TENSOR_RESULT_TYPE(typename opT::opT, R), NDIM > apply_1d_realspace_push(const opT &op, const Function< R, NDIM > &f, int axis, bool fence=true)
Definition mra.h:2419
Function< TENSOR_RESULT_TYPE(L, R), NDIM > sub(const Function< L, NDIM > &left, const Function< R, NDIM > &right, bool fence=true)
Same as operator- but with optional fence and no automatic compression.
Definition mra.h:2141
Function< TENSOR_RESULT_TYPE(L, R), NDIM > binary_op(const Function< L, NDIM > &left, const Function< R, NDIM > &right, const opT &op, bool fence=true)
Generate new function = op(left,right) where op acts on the function values.
Definition mra.h:1935
Function< Q, NDIM > convert(const Function< T, NDIM > &f, bool fence=true)
Type conversion implies a deep copy. No communication except for optional fence.
Definition mra.h:2219
Function< TENSOR_RESULT_TYPE(Q, T), NDIM > mul(const Q alpha, const Function< T, NDIM > &f, bool fence=true)
Returns new function equal to alpha*f(x) with optional fence.
Definition mra.h:1870
std::enable_if_t< NDIM%2==0, Function< T, NDIM > > swap_particles(const Function< T, NDIM > &f)
swap particles 1 and 2
Definition mra.h:2490
TreeState
Definition funcdefaults.h:59
@ nonstandard_after_apply
s and d coeffs, state after operator application
Definition funcdefaults.h:64
@ redundant_after_merge
s coeffs everywhere, must be summed up to yield the result
Definition funcdefaults.h:66
@ reconstructed
s coeffs at the leaves only
Definition funcdefaults.h:60
@ nonstandard
s and d coeffs in internal nodes
Definition funcdefaults.h:62
@ unknown
Definition funcdefaults.h:68
@ nonstandard_with_leaves
like nonstandard, with s coeffs at the leaves
Definition funcdefaults.h:63
static void user_to_sim(const Vector< double, NDIM > &xuser, Vector< double, NDIM > &xsim)
Convert user coords (cell[][]) to simulation coords ([0,1]^ndim)
Definition funcdefaults.h:455
std::vector< Function< TENSOR_RESULT_TYPE(T, R), NDIM > > innerXX(const Function< T, LDIM > &f, const std::vector< Function< R, KDIM > > &vg, const std::array< int, CDIM > v1, const std::array< int, CDIM > v2, int task=0)
Computes the partial scalar/inner product between two functions, returns a low-dim function.
Definition mra.h:2618
std::vector< CCPairFunction< T, NDIM > > operator*(const double fac, const std::vector< CCPairFunction< T, NDIM > > &arg)
Definition ccpairfunction.h:1089
int Level
Definition key.h:59
TreeState get_tree_state(const Function< T, NDIM > &f)
get tree state of a function
Definition mra.h:2917
std::vector< CCPairFunction< T, NDIM > > operator-(const std::vector< CCPairFunction< T, NDIM > > c1, const std::vector< CCPairFunction< T, NDIM > > &c2)
Definition ccpairfunction.h:1060
Function< TENSOR_RESULT_TYPE(L, R), NDIM > mul_sparse(const Function< L, NDIM > &left, const Function< R, NDIM > &right, double tol, bool fence=true)
Sparse multiplication — left and right must be reconstructed and if tol!=0 have tree of norms already...
Definition mra.h:1911
std::string get_mra_data_dir()
Definition startup.cc:209
Function< T, NDIM > gaxpy_oop_reconstructed(const double alpha, const Function< T, NDIM > &left, const double beta, const Function< T, NDIM > &right, const bool fence=true)
Returns new function alpha*left + beta*right optional fence, having both addends reconstructed.
Definition mra.h:2104
void print(const T &t, const Ts &... ts)
Print items to std::cout (items separated by spaces) and terminate with a new line.
Definition print.h:226
response_space apply(World &world, std::vector< std::vector< std::shared_ptr< real_convolution_3d > > > &op, response_space &f)
Definition basic_operators.cc:43
@ TT_2D
Definition gentensor.h:120
@ TT_FULL
Definition gentensor.h:120
NDIM & f
Definition mra.h:2604
Function< TENSOR_RESULT_TYPE(L, R), NDIM > add(const Function< L, NDIM > &left, const Function< R, NDIM > &right, bool fence=true)
Same as operator+ but with optional fence and no automatic compression.
Definition mra.h:2096
Function< T, NDIM > symmetrize(const Function< T, NDIM > &f, const std::string symmetry, bool fence=true)
symmetrize a function
Definition mra.h:2516
Function< TENSOR_RESULT_TYPE(typename opT::opT, R), NDIM > apply_only(const opT &op, const Function< R, NDIM > &f, bool fence=true)
Apply operator ONLY in non-standard form - required other steps missing !!
Definition mra.h:2307
double inner(response_space &a, response_space &b)
Definition response_functions.h:639
double imag(double x)
Definition complexfun.h:56
Function< typename opT::resultT, NDIM > unary_op(const Function< Q, NDIM > &func, const opT &op, bool fence=true)
Out of place application of unary operation to function values with optional fence.
Definition mra.h:1949
void startup(World &world, int argc, char **argv, bool doprint=false, bool make_stdcout_nice_to_reals=true)
initialize the internal state of the MADmra library
Definition startup.cc:64
std::string type(const PairType &n)
Definition PNOParameters.h:18
static bool print_timings
Definition SCF.cc:106
std::vector< CCPairFunction< T, NDIM > > operator+(const std::vector< CCPairFunction< T, NDIM > > c1, const std::vector< CCPairFunction< T, NDIM > > &c2)
Definition ccpairfunction.h:1052
Function< T, NDIM > multiply(const Function< T, NDIM > f, const Function< T, LDIM > g, const int particle, const bool fence=true)
multiply a high-dimensional function with a low-dimensional function
Definition mra.h:2560
void load(Function< T, NDIM > &f, const std::string name)
Definition mra.h:2968
Function< T, NDIM > project(const Function< T, NDIM > &other, int k=FunctionDefaults< NDIM >::get_k(), double thresh=FunctionDefaults< NDIM >::get_thresh(), bool fence=true)
Definition mra.h:2587
double real(double x)
Definition complexfun.h:52
static XNonlinearSolver< std::vector< Function< T, NDIM > >, T, vector_function_allocator< T, NDIM > > nonlinear_vector_solver(World &world, const long nvec)
Definition nonlinsol.h:371
std::string name(const FuncType &type, const int ex=-1)
Definition ccpairfunction.h:28
void save(const Function< T, NDIM > &f, const std::string name)
Definition mra.h:2962
Function< T, KDIM+LDIM > hartree_product(const std::vector< Function< T, KDIM > > &left, const std::vector< Function< T, LDIM > > &right)
Performs a Hartree/outer product on the two given low-dimensional function vectors.
Definition mra.h:2001
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:2172
static const double d
Definition nonlinschro.cc:121
Implements most functionality of separated operators.
Implements ParallelInputArchive and ParallelOutputArchive for parallel serialization of data.
double Q(double a)
Definition relops.cc:20
static const double c
Definition relops.cc:10
static const double L
Definition rk.cc:46
Definition test_ar.cc:204
Definition test_dc.cc:47
Definition leafop.h:133
void serialize(Archive &ar)
Definition mra.h:1023
T(* f)(T)
Definition mra.h:1018
void operator()(const Key< NDIM > &key, Tensor< T > &t) const
Definition mra.h:1020
SimpleUnaryOpWrapper(T(*f)(T))
Definition mra.h:1019
void serialize(Archive &ar)
Definition mra.h:956
bool operator()(implT *impl, const Key< NDIM > &key, const nodeT &t) const
Definition mra.h:952
Definition type_data.h:146
Definition leafop.h:185
Definition leafop.h:62
TensorArgs holds the arguments for creating a LowRankTensor.
Definition gentensor.h:134
static void load(const ParallelInputArchive< archiveT > &ar, Function< T, NDIM > &f)
Definition mra.h:2948
Default load of an object via serialize(ar, t).
Definition archive.h:667
static void store(const ParallelOutputArchive< archiveT > &ar, const Function< T, NDIM > &f)
Definition mra.h:2955
Default store of an object via serialize(ar, t).
Definition archive.h:612
Definition mra.h:2836
Tensor< double > operator()(const Key< NDIM > &key, const Tensor< double_complex > &t) const
Definition mra.h:2838
double resultT
Definition mra.h:2837
void serialize(Archive &ar)
Definition mra.h:2843
Definition mra.h:2825
void serialize(Archive &ar)
Definition mra.h:2832
Tensor< double > operator()(const Key< NDIM > &key, const Tensor< double_complex > &t) const
Definition mra.h:2827
double resultT
Definition mra.h:2826
Definition mra.h:2815
Tensor< double > operator()(const Key< NDIM > &key, const Tensor< double_complex > &t) const
Definition mra.h:2817
void serialize(Archive &ar)
Definition mra.h:2821
double resultT
Definition mra.h:2816
Definition mra.h:2805
Tensor< double > operator()(const Key< NDIM > &key, const Tensor< double_complex > &t) const
Definition mra.h:2807
double resultT
Definition mra.h:2806
void serialize(Archive &ar)
Definition mra.h:2811
Definition mra.h:127
Definition funcimpl.h:610
returns true if the result of a hartree_product is a leaf node (compute norm & error)
Definition funcimpl.h:500
Definition mra.h:2978
Definition mra.h:112
Definition mra.h:115
Definition funcimpl.h:564
Definition lowrankfunction.h:336
double real(double a)
Definition tdse4.cc:78
Defines and implements most of Tensor.
#define UNARY_OPTIMIZED_ITERATOR(X, x, exp)
Definition tensor_macros.h:658
AtomicInt sum
Definition test_atomicint.cc:46
double norm(const T i1)
Definition test_cloud.cc:85
int task(int i)
Definition test_runtime.cpp:4
void e()
Definition test_sig.cc:75
static const double alpha
Definition testcosine.cc:10
constexpr std::size_t NDIM
Definition testgconv.cc:54
std::size_t axis
Definition testpdiff.cc:59
#define TENSOR_RESULT_TYPE(L, R)
This macro simplifies access to TensorResultType.
Definition type_data.h:205
Defines operations on vectors of Functions.
Implements WorldContainer.
#define PROFILE_FUNC
Definition worldprofile.h:209
#define PROFILE_MEMBER_FUNC(classname)
Definition worldprofile.h:210