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 /// Header magic for Function::store/load; bump whenever FunctionNode::serialize changes.
138 /// 7776769 original (Mellow Mushroom Pizza tel.# in Knoxville, +1 for cell in header)
139 /// 7776770 FunctionNode gained _dnorm_tree
140 static constexpr long FUNCTION_ARCHIVE_MAGIC = 7776770;
141
142 /// A multiresolution adaptive numerical function
143 template <typename T, std::size_t NDIM>
145 // We make all of the content of Function and FunctionImpl
146 // public with the intent of avoiding the cumbersome forward
147 // and friend declarations. However, this open access should
148 // not be abused.
149
150 private:
151 std::shared_ptr< FunctionImpl<T,NDIM> > impl;
152
153 public:
154 bool impl_initialized()const{
155 if(impl==NULL) return false;
156 else return true;
157 }
161 typedef Vector<double,NDIM> coordT; ///< Type of vector holding coordinates
162 typedef T typeT;
163 static constexpr std::size_t dimT=NDIM;
164
165
166 /// Asserts that the function is initialized
167 inline void verify() const {
169 }
170
171 /// Returns true if the function is initialized
172 bool is_initialized() const {
173 return impl.get();
174 }
175
176 /// Default constructor makes uninitialized function. No communication.
177
178 /// An uninitialized function can only be assigned to. Any other operation will throw.
179 Function() : impl() {}
180
181
182 /// Constructor from FunctionFactory provides named parameter idiom. Possible non-blocking communication.
187
188
189 /// Copy constructor is \em shallow. No communication, works in either basis.
191 : impl(f.impl) {
192 }
193
194
195 /// Assignment is \em shallow. No communication, works in either basis.
198 if (this != &f) impl = f.impl;
199 return *this;
200 }
201
202 /// Destruction of any underlying implementation is deferred to next global fence.
204
205 /// implements swap algorithm
206 template <typename R, std::size_t MDIM>
208
209
210 /// Evaluates the function at a point in user coordinates. Possible non-blocking comm.
211
212 /// Only the invoking process will receive the result via the future
213 /// though other processes may be involved in the evaluation.
214 ///
215 /// Throws if function is not initialized.
216 Future<T> eval(const coordT& xuser) const {
218 const double eps=1e-15;
219 verify();
221 coordT xsim;
223 // If on the boundary, move the point just inside the
224 // volume so that the evaluation logic does not fail
225 for (std::size_t d=0; d<NDIM; ++d) {
226 if (xsim[d] < -eps) {
227 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
228 }
229 else if (xsim[d] < eps) {
230 xsim[d] = eps;
231 }
232
233 if (xsim[d] > 1.0+eps) {
234 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
235 }
236 else if (xsim[d] > 1.0-eps) {
237 xsim[d] = 1.0-eps;
238 }
239 }
240
241 Future<T> result;
242 impl->eval(xsim, impl->key0(), result.remote_ref(impl->world));
243 return result;
244 }
245
246 /// Evaluate function only if point is local returning (true,value); otherwise return (false,0.0)
247
248 /// maxlevel is the maximum depth to search down to --- the max local depth can be
249 /// computed with max_local_depth();
250 std::pair<bool,T> eval_local_only(const Vector<double,NDIM>& xuser, Level maxlevel) const {
251 const double eps=1e-15;
252 verify();
254 coordT xsim;
256 // If on the boundary, move the point just inside the
257 // volume so that the evaluation logic does not fail
258 for (std::size_t d=0; d<NDIM; ++d) {
259 if (xsim[d] < -eps) {
260 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
261 }
262 else if (xsim[d] < eps) {
263 xsim[d] = eps;
264 }
265
266 if (xsim[d] > 1.0+eps) {
267 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
268 }
269 else if (xsim[d] > 1.0-eps) {
270 xsim[d] = 1.0-eps;
271 }
272 }
273 return impl->eval_local_only(xsim,maxlevel);
274 }
275
276 /// Batched eval_local_only writing into a caller-provided buffer.
277
278 /// Resizes results to xuser.size() (reusing its capacity) and stores one
279 /// (local?,value) pair per input point, in input order: (true,value) if
280 /// the point is owned locally, otherwise (false,0.0).
281 /// Consecutive points that fall in the same leaf box share that box's
282 /// descent and coefficient fetch (last-box memoization), so spatially
283 /// coherent point streams (quadrature grids) amortise the per-point
284 /// tree descent. Results are bit-for-bit identical to calling the
285 /// single-point eval_local_only on each point. No communications, and
286 /// no per-call heap allocation once results has capacity.
287 ///
288 /// maxlevel is the maximum depth to search down to --- the max local depth can be
289 /// computed with max_local_depth();
290 void eval_local_only(const std::vector<coordT>& xuser, Level maxlevel,
291 std::vector<std::pair<bool,T>>& results) const {
292 const double eps=1e-15;
293 verify();
295 thread_local std::vector<coordT> xsim;
296 xsim.resize(xuser.size());
297 for (std::size_t ip=0; ip<xuser.size(); ++ip) {
298 coordT xs;
300 // If on the boundary, move the point just inside the volume so the
301 // evaluation logic does not fail (matches the single-point path).
302 for (std::size_t d=0; d<NDIM; ++d) {
303 if (xs[d] < -eps) {
304 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
305 }
306 else if (xs[d] < eps) {
307 xs[d] = eps;
308 }
309
310 if (xs[d] > 1.0+eps) {
311 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
312 }
313 else if (xs[d] > 1.0-eps) {
314 xs[d] = 1.0-eps;
315 }
316 }
317 xsim[ip] = xs;
318 }
319 results.resize(xuser.size());
320 impl->eval_local_only(xsim.data(), xsim.size(), maxlevel, results.data());
321 }
322
323 /// Batched eval_local_only returning a fresh vector (see the
324 /// output-parameter overload above for semantics).
325 std::vector<std::pair<bool,T>> eval_local_only(const std::vector<coordT>& xuser, Level maxlevel) const {
326 std::vector<std::pair<bool,T>> results;
327 eval_local_only(xuser, maxlevel, results);
328 return results;
329 }
330
331 /// Only the invoking process will receive the result via the future
332 /// though other processes may be involved in the evaluation.
333 ///
334 /// Throws if function is not initialized.
335 ///
336 /// This function is a minimally-modified version of eval()
339 const double eps=1e-15;
340 verify();
342 coordT xsim;
344 // If on the boundary, move the point just inside the
345 // volume so that the evaluation logic does not fail
346 for (std::size_t d=0; d<NDIM; ++d) {
347 if (xsim[d] < -eps) {
348 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
349 }
350 else if (xsim[d] < eps) {
351 xsim[d] = eps;
352 }
353
354 if (xsim[d] > 1.0+eps) {
355 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
356 }
357 else if (xsim[d] > 1.0-eps) {
358 xsim[d] = 1.0-eps;
359 }
360 }
361
362 Future<Level> result;
363 impl->evaldepthpt(xsim, impl->key0(), result.remote_ref(impl->world));
364 return result;
365 }
366
367
368 /// Evaluates the function rank at a point in user coordinates. Possible non-blocking comm.
369
370 /// Only the invoking process will receive the result via the future
371 /// though other processes may be involved in the evaluation.
372 ///
373 /// Throws if function is not initialized.
376 const double eps=1e-15;
377 verify();
379 coordT xsim;
381 // If on the boundary, move the point just inside the
382 // volume so that the evaluation logic does not fail
383 for (std::size_t d=0; d<NDIM; ++d) {
384 if (xsim[d] < -eps) {
385 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
386 }
387 else if (xsim[d] < eps) {
388 xsim[d] = eps;
389 }
390
391 if (xsim[d] > 1.0+eps) {
392 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
393 }
394 else if (xsim[d] > 1.0-eps) {
395 xsim[d] = 1.0-eps;
396 }
397 }
398
399 Future<long> result;
400 impl->evalR(xsim, impl->key0(), result.remote_ref(impl->world));
401 return result;
402 }
403
404 /// Evaluates a cube/slice of points (probably for plotting) ... collective but no fence necessary
405
406 /// All processes receive the entire result (which is a rather severe limit
407 /// on the size of the cube that is possible).
408
409 /// Set eval_refine=true to return the refinment levels of
410 /// the given function.
411
412 /// @param[in] cell A Tensor describe the cube where the function to be evaluated in
413 /// @param[in] npt How many points to evaluate in each dimension
414 /// @param[in] eval_refine Wether to return the refinment levels of the given function
416 const std::vector<long>& npt,
417 bool eval_refine = false) const {
418 MADNESS_ASSERT(static_cast<std::size_t>(cell.dim(0))>=NDIM && cell.dim(1)==2 && npt.size()>=NDIM);
420 const double eps=1e-14;
421 verify();
422 reconstruct();
424 for (std::size_t d=0; d<NDIM; ++d) {
425 simlo[d] = cell(d,0);
426 simhi[d] = cell(d,1);
427 }
430
431 // Move the bounding box infintesimally inside dyadic
432 // points so that the evaluation logic does not fail
433 for (std::size_t d=0; d<NDIM; ++d) {
435 MADNESS_ASSERT(simlo[d] >= 0.0);
436 MADNESS_ASSERT(simhi[d] <= 1.0);
437
438 double delta = eps*(simhi[d]-simlo[d]);
439 simlo[d] += delta;
440 simhi[d] -= 2*delta; // deliberate asymmetry
441 }
442 return impl->eval_plot_cube(simlo, simhi, npt, eval_refine);
443 }
444
445
446 /// Evaluates the function at a point in user coordinates. Collective operation.
447
448 /// Throws if function is not initialized.
449 ///
450 /// This function calls eval, blocks until the result is
451 /// available and then broadcasts the result to everyone.
452 /// Therefore, if you are evaluating many points in parallel
453 /// it is \em vastly less efficient than calling eval
454 /// directly, saving the futures, and then forcing all of the
455 /// results.
456 T operator()(const coordT& xuser) const {
458 verify();
460 T result;
461 if (impl->world.rank() == 0) result = eval(xuser).get();
462 impl->world.gop.broadcast(result);
463 //impl->world.gop.fence();
464 return result;
465 }
466
467 /// Evaluates the function at a point in user coordinates. Collective operation.
468
469 /// See "operator()(const coordT& xuser)" for more info
470 T operator()(double x, double y=0, double z=0, double xx=0, double yy=0, double zz=0) const {
471 coordT r;
472 r[0] = x;
473 if (NDIM>=2) r[1] = y;
474 if (NDIM>=3) r[2] = z;
475 if (NDIM>=4) r[3] = xx;
476 if (NDIM>=5) r[4] = yy;
477 if (NDIM>=6) r[5] = zz;
478 return (*this)(r);
479 }
480
481 /// Throws if function is not initialized.
482 ///
483 /// This function mimics operator() by going through the
484 /// tree looking for the depth of the tree at the point.
485 /// It blocks until the result is
486 /// available and then broadcasts the result to everyone.
487 /// Therefore, if you are evaluating many points in parallel
488 /// it is \em vastly less efficient than calling evaldepthpt
489 /// directly, saving the futures, and then forcing all of the
490 /// results.
491 Level depthpt(const coordT& xuser) const {
493 verify();
495 Level result;
496 if (impl->world.rank() == 0) result = evaldepthpt(xuser).get();
497 impl->world.gop.broadcast(result);
498 //impl->world.gop.fence();
499 return result;
500 }
501
502 /// Returns an estimate of the difference ||this-func||^2 from local data
503
504 /// No communication is performed. If the function is not
505 /// reconstructed, it throws an exception. To get the global
506 /// value either do a global sum of the local values or call
507 /// errsq
508 /// @param[in] func Templated interface to the a user specified function
509 template <typename funcT>
510 double errsq_local(const funcT& func) const {
512 verify();
513 if (!is_reconstructed()) MADNESS_EXCEPTION("Function:errsq_local:not reconstructed",0);
514 return impl->errsq_local(func);
515 }
516
517
518 /// Returns an estimate of the difference ||this-func|| ... global sum performed
519
520 /// If the function is compressed, it is reconstructed first. For efficient use
521 /// especially with many functions, reconstruct them all first, and use errsq_local
522 /// instead so you can perform a global sum on all at the same time.
523 /// @param[in] func Templated interface to the a user specified function
524 template <typename funcT>
525 double err(const funcT& func) const {
527 verify();
531 double local = impl->errsq_local(func);
532 impl->world.gop.sum(local);
533 impl->world.gop.fence();
534 return sqrt(local);
535 }
536
537 /// Verifies the tree data structure ... global sync implied
538 void verify_tree() const {
540 if (impl) impl->verify_tree();
541 }
542
543
544 /// Returns true if compressed, false otherwise. No communication.
545
546 /// If the function is not initialized, returns false.
547 bool is_compressed() const {
549 if (impl)
550 return impl->is_compressed();
551 else
552 return false;
553 }
554
555 /// Returns true if reconstructed, false otherwise. No communication.
556
557 /// If the function is not initialized, returns false.
558 bool is_reconstructed() const {
560 if (impl)
561 return impl->is_reconstructed();
562 else
563 return false;
564 }
565
566 /// Returns true if nonstandard-compressed, false otherwise. No communication.
567
568 /// If the function is not initialized, returns false.
569 bool is_nonstandard() const {
571 return impl ? impl->is_nonstandard() : false;
572 }
573
574 /// Returns true if redundant, false otherwise. No communication.
575
576 /// If the function is not initialized, returns false.
577 bool is_redundant() const {
579 return impl ? impl->is_redundant() : false;
580 }
581
582 /// Returns true if redundant_after_merge, false otherwise. No communication.
583
584 /// If the function is not initialized, returns false.
587 return impl ? impl->is_redundant_after_merge() : false;
588 }
589
590 /// Returns the number of nodes in the function tree ... collective global sum
591 std::size_t tree_size() const {
593 if (!impl) return 0;
594 return impl->tree_size();
595 }
596
597 /// print some info about this
598 void print_size(const std::string name) const {
599 if (!impl) {
600 print("function",name,"not assigned yet");
601 } else {
602 impl->print_size(name);
603 }
604 }
605
606 /// Returns the maximum depth of the function tree ... collective global sum
607 std::size_t max_depth() const {
609 if (!impl) return 0;
610 return impl->max_depth();
611 }
612
613
614 /// Returns the maximum local depth of the function tree ... no communications
615
616 /// This is the value to pass as \c maxlevel to eval_local_only: it bounds the
617 /// descent to the deepest leaf actually held on this rank. Passing a larger
618 /// bound (e.g. Level::max()) only makes a missing/remote point descend through
619 /// empty levels doing owner() checks that never match -- pure overhead.
620 std::size_t max_local_depth() const {
622 if (!impl) return 0;
623 return impl->max_local_depth();
624 }
625
626
627 /// Returns the max number of nodes on a processor
628 std::size_t max_nodes() const {
630 if (!impl) return 0;
631 return impl->max_nodes();
632 }
633
634 /// Returns the min number of nodes on a processor
635 std::size_t min_nodes() const {
637 if (!impl) return 0;
638 return impl->min_nodes();
639 }
640
641
642 /// Returns the number of coefficients in the function ... collective global sum
643 std::size_t size() const {
645 if (!impl) return 0;
646 return impl->size();
647 }
648
649 /// Return the number of coefficients in the function on this processor
650 std::size_t size_local() const {
652 if (!impl) return 0;
653 return impl->size_local();
654 }
655
656
657 /// Returns value of autorefine flag. No communication.
658 bool autorefine() const {
660 if (!impl) return true;
661 return impl->get_autorefine();
662 }
663
664
665 /// Sets the value of the autorefine flag. Optional global fence.
666
667 /// A fence is required to ensure consistent global state.
668 void set_autorefine(bool value, bool fence = true) {
670 verify();
671 impl->set_autorefine(value);
672 if (fence) impl->world.gop.fence();
673 }
674
675
676 /// Returns value of truncation threshold. No communication.
677 double thresh() const {
679 if (!impl) return 0.0;
680 return impl->get_thresh();
681 }
682
683
684 /// Sets the value of the truncation threshold. Optional global fence.
685
686 /// A fence is required to ensure consistent global state.
687 void set_thresh(double value, bool fence = true) {
689 verify();
690 impl->set_thresh(value);
691 if (fence) impl->world.gop.fence();
692 }
693
694
695 /// Returns the number of multiwavelets (k). No communication.
696 int k() const {
698 verify();
699 return impl->get_k();
700 }
701
702
703 /// Truncate the function with optional fence. Compresses with fence if not compressed.
704
705 /// If the truncation threshold is less than or equal to zero the default value
706 /// specified when the function was created is used.
707 /// If the function is not initialized, it just returns.
708 ///
709 /// Returns this for chaining.
710 /// @param[in] tol Tolerance for truncating the coefficients. Default 0.0 means use the implementation's member value \c thresh instead.
711 /// @param[in] fence Do fence
712 Function<T,NDIM>& truncate(double tol = 0.0, bool fence = true) {
714 if (!impl) return *this;
715 verify();
716// if (!is_compressed()) compress();
717 impl->truncate(tol,fence);
719 return *this;
720 }
721
722
723 /// Returns a shared-pointer to the implementation
724 const std::shared_ptr< FunctionImpl<T,NDIM> >& get_impl() const {
726 verify();
727 return impl;
728 }
729
730 /// Replace current FunctionImpl with provided new one
731 void set_impl(const std::shared_ptr< FunctionImpl<T,NDIM> >& impl) {
733 this->impl = impl;
734 }
735
736
737 /// Replace the current functor with the provided new one
738
739 /// presumably the new functor will be a CompositeFunctor, which will
740 /// change the behavior of the function: multiply the functor with the function
741 void set_functor(const std::shared_ptr<FunctionFunctorInterface<T, NDIM> > functor) {
742 this->impl->set_functor(functor);
743 print("set functor in mra.h");
744 }
745
746 bool is_on_demand() const {return this->impl->is_on_demand();}
747
748 /// Replace current FunctionImpl with a new one using the same parameters & map as f
749
750 /// If zero is true the function is initialized to zero, otherwise it is empty
751 template <typename R>
752 void set_impl(const Function<R,NDIM>& f, bool zero = true) {
753 impl = std::shared_ptr<implT>(new implT(*f.get_impl(), f.get_pmap(), zero));
754 if (zero) world().gop.fence();
755 }
756
757 /// Returns the world
758 World& world() const {
760 verify();
761 return impl->world;
762 }
763
764
765 /// Returns a shared pointer to the process map
766 const std::shared_ptr< WorldDCPmapInterface< Key<NDIM> > >& get_pmap() const {
768 verify();
769 return impl->get_pmap();
770 }
771
772 /// replicate this function according to type
773 ///
774 /// ** note that global operations will return unexpected results **
775 /// Be sure you know what you are doing!
776 void replicate(const DistributionType type, bool fence=true) const {
777 verify();
779 else if (type==DistributionType::NodeReplicated) impl->replicate_on_hosts(fence);
780 else MADNESS_EXCEPTION("Function::replicate: unknown DistributionType",type);
781 }
782
783 /// replicate this function, generating a unique pmap
784
785 /// ** note that global operations will return unexpected results **
786 /// Be sure you know what you are doing!
787 void replicate(bool fence=true) const {
788 verify();
789 impl->replicate(fence);
790 }
791
792 /// replicate this function, one copy per host
793
794 /// map will refer the to first rank on each host to avoid inter-node communication
795 /// ** note that global operations will return unexpected results **
796 /// Be sure you know what you are doing!
797 void replicate_on_hosts(bool fence=true) const {
798 verify();
799 impl->replicate_on_hosts(fence);
800 }
801
802
803 /// distribute this function according to newmap
804 void distribute(std::shared_ptr< WorldDCPmapInterface< Key<NDIM> > > newmap) const {
805 verify();
806 impl->distribute(newmap);
807 }
808
809
810 /// Returns the square of the norm of the local function ... no communication
811
812 /// Works in either basis
813 double norm2sq_local() const {
815 verify();
817 "function must be compressed or reconstructed for norm2sq_local");
818 return impl->norm2sq_local();
819 }
820
821
822 /// Returns the 2-norm of the function ... global sum ... works in either basis
823
824 /// See comments for err() w.r.t. applying to many functions.
825 double norm2() const {
827 verify();
829 double local = impl->norm2sq_local();
830
831 impl->world.gop.sum(local);
832 impl->world.gop.fence();
833 return sqrt(local);
834 }
835
836
837 /// Initializes information about the function norm at all length scales
838 void norm_tree(bool fence = true) const {
840 verify();
843 const_cast<Function<T,NDIM>*>(this)->impl->norm_tree(fence);
844 }
845
846
847 /// Compresses the function, transforming into wavelet basis. Possible non-blocking comm.
848
849 /// By default fence=true meaning that this operation completes before returning,
850 /// otherwise if fence=false it returns without fencing and the user must invoke
851 /// world.gop.fence() to assure global completion before using the function
852 /// for other purposes.
853 ///
854 /// Noop if already compressed or if not initialized.
855 ///
856 /// Since reconstruction/compression do not discard information we define them
857 /// as const ... "logical constness" not "bitwise constness".
858 const Function<T,NDIM>& compress(bool fence = true) const {
860 }
861
862
863 /// Compresses the function retaining scaling function coeffs. Possible non-blocking comm.
864
865 /// By default fence=true meaning that this operation completes before returning,
866 /// otherwise if fence=false it returns without fencing and the user must invoke
867 /// world.gop.fence() to assure global completion before using the function
868 /// for other purposes.
869 ///
870 /// Noop if already compressed or if not initialized.
876
877 /// Converts the function standard compressed form. Possible non-blocking comm.
878
879 /// By default fence=true meaning that this operation completes before returning,
880 /// otherwise if fence=false it returns without fencing and the user must invoke
881 /// world.gop.fence() to assure global completion before using the function
882 /// for other purposes.
883 ///
884 /// Must be already compressed.
885 void standard(bool fence = true) {
887 }
888
889 /// Converts the function to redundant form, i.e. sum coefficients on all levels
890
891 /// By default fence=true meaning that this operation completes before returning,
892 /// otherwise if fence=false it returns without fencing and the user must invoke
893 /// world.gop.fence() to assure global completion before using the function
894 /// for other purposes.
895 ///
896 /// Since the transformation does not discard information we define this
897 /// as const ... "logical constness" not "bitwise constness".
898 ///
899 /// Note redundant form stores sum coefficients at every level, so it is larger than
900 /// reconstructed form; a caller that keeps the function alive may want to convert back.
901 void make_redundant(bool fence = true) const {
903 }
904
905 /// Reconstructs the function, transforming into scaling function basis. Possible non-blocking comm.
906
907 /// By default fence=true meaning that this operation completes before returning,
908 /// otherwise if fence=false it returns without fencing and the user must invoke
909 /// world.gop.fence() to assure global completion before using the function
910 /// for other purposes.
911 ///
912 /// Noop if already reconstructed or if not initialized.
913 ///
914 /// Since reconstruction/compression do not discard information we define them
915 /// as const ... "logical constness" not "bitwise constness".
916 const Function<T,NDIM>& reconstruct(bool fence = true) const {
918 }
919
920 /// changes tree state to given state
921
922 /// Since reconstruction/compression do not discard information we define them
923 /// as const ... "logical constness" not "bitwise constness".
924 /// @param[in] finalstate The final state of the tree
925 /// @param[in] fence Fence after the operation (might not be respected!!!)
928 if (not impl) return *this;
929 TreeState current_state = impl->get_tree_state();
930 if (finalstate == current_state) return *this;
931 MADNESS_CHECK_THROW(current_state != TreeState::unknown, "unknown tree state");
932
933 impl->change_tree_state(finalstate, fence);
934 if (fence && VERIFY_TREE) verify_tree();
935 return *this;
936 }
937
938 /// Sums scaling coeffs down tree restoring state with coeffs only at leaves. Optional fence. Possible non-blocking comm.
939 void sum_down(bool fence = true) const {
941 verify();
942 MADNESS_CHECK_THROW(impl->get_tree_state()==redundant_after_merge, "sum_down requires a redundant_after_merge state");
943 const_cast<Function<T,NDIM>*>(this)->impl->sum_down(fence);
944 const_cast<Function<T,NDIM>*>(this)->impl->set_tree_state(reconstructed);
945
946 if (fence && VERIFY_TREE) verify_tree(); // Must be after in case nonstandard
947 }
948
949
950 /// Inplace autorefines the function. Optional fence. Possible non-blocking comm.
951 template <typename opT>
952 void refine_general(const opT& op, bool fence = true) const {
954 verify();
956 impl->refine(op, fence);
957 }
958
959
961 bool operator()(implT* impl, const Key<NDIM>& key, const nodeT& t) const {
962 return impl->autorefine_square_test(key, t);
963 }
964
965 template <typename Archive> void serialize (Archive& ar) {}
966 };
967
968 /// Inplace autorefines the function using same test as for squaring.
969
970 /// return this for chaining
971 const Function<T,NDIM>& refine(bool fence = true) const {
973 return *this;
974 }
975
976 /// Inplace broadens support in scaling function basis
978 bool fence = true) const {
979 verify();
980 reconstruct();
981 impl->broaden(bc.is_periodic(), fence);
982 }
983
984
985 /// Clears the function as if constructed uninitialized. Optional fence.
986
987 /// Any underlying data will not be freed until the next global fence.
988 void clear(bool fence = true) {
990 if (impl) {
991 World& world = impl->world;
992 impl.reset();
993 if (fence) world.gop.fence();
994 }
995 }
996
997 /// Process 0 prints a summary of all nodes in the tree (collective)
998 void print_tree(std::ostream& os = std::cout) const {
1000 if (impl) impl->print_tree(os);
1001 }
1002
1003 /// same as print_tree() but produces JSON-formatted string
1004 /// @warning enclose the result in braces to make it a valid JSON object
1005 void print_tree_json(std::ostream& os = std::cout) const {
1007 if (impl) impl->print_tree_json(os);
1008 }
1009
1010 /// Process 0 prints a graphviz-formatted output of all nodes in the tree (collective)
1011 void print_tree_graphviz(std::ostream& os = std::cout) const {
1013 os << "digraph G {" << std::endl;
1014 if (impl) impl->print_tree_graphviz(os);
1015 os << "}" << std::endl;
1016 }
1017
1018 /// Print a summary of the load balancing info
1019
1020 /// This is serial and VERY expensive
1021 void print_info() const {
1023 if (impl) impl->print_info();
1024 }
1025
1027 T (*f)(T);
1028 SimpleUnaryOpWrapper(T (*f)(T)) : f(f) {}
1029 void operator()(const Key<NDIM>& key, Tensor<T>& t) const {
1030 UNARY_OPTIMIZED_ITERATOR(T, t, *_p0 = f(*_p0));
1031 }
1032 template <typename Archive> void serialize(Archive& ar) {}
1033 };
1034
1035 /// Inplace unary operation on function values
1036 void unaryop(T (*f)(T)) {
1037 // Must fence here due to temporary object on stack
1038 // stopping us returning before complete
1040 }
1041
1042
1043 /// Inplace unary operation on function values
1044 template <typename opT>
1045 void unaryop(const opT& op, bool fence=true) {
1047 verify();
1048 reconstruct();
1049 impl->unary_op_value_inplace(op, fence);
1050 }
1051
1052
1053 /// Unary operation applied inplace to the coefficients
1054 template <typename opT>
1055 void unaryop_coeff(const opT& op,
1056 bool fence = true) {
1058 verify();
1059 impl->unary_op_coeff_inplace(op, fence);
1060 }
1061
1062
1063 /// Unary operation applied inplace to the nodes
1064 template <typename opT>
1065 void unaryop_node(const opT& op,
1066 bool fence = true) {
1068 verify();
1069 impl->unary_op_node_inplace(op, fence);
1070 }
1071
1072
1073
1074
1075 static void doconj(const Key<NDIM>, Tensor<T>& t) {
1077 t.conj();
1078 }
1079
1080 /// Inplace complex conjugate. No communication except for optional fence.
1081
1082 /// Returns this for chaining. Works in either basis.
1086 return *this;
1087 }
1088
1089
1090 /// Inplace, scale the function by a constant. No communication except for optional fence.
1091
1092 /// Works in either basis. Returns reference to this for chaining.
1093 template <typename Q>
1094 Function<T,NDIM>& scale(const Q q, bool fence=true) {
1096 verify();
1097 if (VERIFY_TREE) verify_tree();
1098 impl->scale_inplace(q,fence);
1099 return *this;
1100 }
1101
1102
1103 /// Inplace add scalar. No communication except for optional fence.
1106 verify();
1107 if (VERIFY_TREE) verify_tree();
1108 impl->add_scalar_inplace(t,fence);
1109 return *this;
1110 }
1111
1112
1113 /// Inplace, general bi-linear operation in wavelet basis. No communication except for optional fence.
1114
1115 /// If the functions are not in the wavelet basis an exception is thrown since this routine
1116 /// is intended to be fast and unexpected compression is assumed to be a performance bug.
1117 ///
1118 /// Returns this for chaining, can be in states compressed of redundant_after_merge.
1119 ///
1120 /// this and other may have different distributions and may even live in different worlds
1121 ///
1122 /// this <-- this*alpha + other*beta
1123 template <typename Q, typename R>
1125 const Function<Q,NDIM>& other, const R& beta, bool fence=true) {
1127 verify();
1128 other.verify();
1129
1130 // operation is done either in compressed or reconstructed state
1131 TreeState operating_state=this->get_impl()->get_tensor_type()==TT_FULL ? compressed : reconstructed;
1132
1133 TreeState thisstate=impl->get_tree_state();
1134 TreeState otherstate=other.get_impl()->get_tree_state();
1135
1137 MADNESS_CHECK_THROW(thisstate==compressed, "gaxpy: this must be compressed");
1138 MADNESS_CHECK_THROW(otherstate==compressed, "gaxpy: other must be compressed");
1139 impl->gaxpy_inplace(alpha, *other.get_impl(), beta, fence);
1140
1141 } else if (operating_state==reconstructed) {
1142 // this works both in reconstructed and redundant_after_merge states
1144 "gaxpy: this must be reconstructed or redundant_after_merge");
1146 "gaxpy: other must be reconstructed or redundant_after_merge");
1147
1148 impl->gaxpy_inplace_reconstructed(alpha,*other.get_impl(),beta,fence);
1149 } else {
1150 MADNESS_EXCEPTION("unknown tree state",1);
1151 }
1152 return *this;
1153 }
1154
1155
1156 /// Inplace addition of functions in the wavelet basis
1157
1158 /// Using operator notation forces a global fence after every operation.
1159 /// Functions don't need to be compressed, it's the caller's responsibility
1160 /// to choose an appropriate state with performance, usually compressed for 3d,
1161 /// reconstructed for 6d)
1162 template <typename Q>
1165
1166 // do this in reconstructed or compressed form
1168 this->change_tree_state(operating_state);
1170
1171 MADNESS_ASSERT(impl->get_tree_state() == other.get_impl()->get_tree_state());
1172 if (VERIFY_TREE) verify_tree();
1173 if (VERIFY_TREE) other.verify_tree();
1174 return gaxpy(T(1.0), other, Q(1.0), true);
1175 }
1176
1177
1178 /// Inplace subtraction of functions in the wavelet basis
1179
1180 /// Using operator notation forces a global fence after every operation
1181 template <typename Q>
1184 if (NDIM<=3) {
1185 compress();
1186 other.compress();
1187 } else {
1188 reconstruct();
1189 other.reconstruct();
1190 }
1191 MADNESS_ASSERT(impl->get_tree_state() == other.get_impl()->get_tree_state());
1192 if (VERIFY_TREE) verify_tree();
1193 if (VERIFY_TREE) other.verify_tree();
1194 return gaxpy(T(1.0), other, Q(-1.0), true);
1195 }
1196
1197
1198 /// Inplace scaling by a constant
1199
1200 /// Using operator notation forces a global fence after every operation
1201 template <typename Q>
1203 operator*=(const Q q) {
1205 scale(q,true);
1206 return *this;
1207 }
1208
1209
1210 /// Inplace squaring of function ... global comm only if not reconstructed
1211
1212 /// Returns *this for chaining.
1215 if (!is_reconstructed()) reconstruct();
1216 if (VERIFY_TREE) verify_tree();
1217 impl->square_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_inplace(fence);
1227 return *this;
1228 }
1229
1230 /// Returns *this for chaining.
1233 if (!is_reconstructed()) reconstruct();
1234 if (VERIFY_TREE) verify_tree();
1235 impl->abs_square_inplace(fence);
1236 return *this;
1237 }
1238
1239 /// Returns local contribution to \c int(f(x),x) ... no communication
1240
1241 /// In the wavelet basis this is just the coefficient of the first scaling
1242 /// function which is a constant. In the scaling function basis we
1243 /// must add up contributions from each box.
1244 T trace_local() const {
1246 if (!impl) return 0.0;
1247 if (VERIFY_TREE) verify_tree();
1248 return impl->trace_local();
1249 }
1250
1251
1252 /// Returns global value of \c int(f(x),x) ... global comm required
1253 T trace() const {
1255 if (!impl) return 0.0;
1256 T sum = impl->trace_local();
1257 impl->world.gop.sum(sum);
1258 impl->world.gop.fence();
1259 return sum;
1260 }
1261
1262
1263 /// Returns local part of inner product ... throws if both not compressed
1264 template <typename R>
1265 TENSOR_RESULT_TYPE(T,R) inner_local(const Function<R,NDIM>& g) const {
1272 return impl->inner_local(*(g.get_impl()));
1273 }
1274
1275 /// Returns local part of dot product ... throws if both not compressed
1277 TENSOR_RESULT_TYPE(T,R) dot_local(const Function<R,NDIM>& g) const {
1280 MADNESS_ASSERT(g.is_compressed());
1282 if (VERIFY_TREE) g.verify_tree();
1283 return impl->dot_local(*(g.get_impl()));
1284 }
1285
1286
1287 /// With this being an on-demand function, fill the MRA tree according to different criteria
1288
1289 /// @param[in] g the function after which the MRA structure is modeled (any basis works)
1290 template<typename R>
1292 MADNESS_ASSERT(g.is_initialized());
1294
1295 // clear what we have
1296 impl->get_coeffs().clear();
1297
1298 //leaf_op<T,NDIM> gnode_is_leaf(g.get_impl().get());
1299 Leaf_op_other<T,NDIM> gnode_is_leaf(g.get_impl().get());
1300 impl->make_Vphi(gnode_is_leaf,fence);
1301 return *this;
1302
1303 }
1304
1305 /// With this being an on-demand function, fill the MRA tree according to different criteria
1306
1307 /// @param[in] op the convolution operator for screening
1308 template<typename opT>
1309 Function<T,NDIM>& fill_tree(const opT& op, bool fence=true) {
1311 // clear what we have
1312 impl->get_coeffs().clear();
1315 impl ->make_Vphi(leaf_op,fence);
1316 return *this;
1317 }
1318
1319 /// With this being an on-demand function, fill the MRA tree according to different criteria
1322 // clear what we have
1323 impl->get_coeffs().clear();
1325 impl->make_Vphi(leaf_op,fence);
1326 return *this;
1327 }
1328
1329 /// Special refinement on 6D boxes where the electrons come close (meet)
1330 /// @param[in] op the convolution operator for screening
1331 template<typename opT>
1332 Function<T,NDIM>& fill_cuspy_tree(const opT& op,const bool fence=true){
1334 // clear what we have
1335 impl->get_coeffs().clear();
1337
1339 impl ->make_Vphi(leaf_op,fence);
1340
1341 return *this;
1342 }
1343
1344 /// Special refinement on 6D boxes where the electrons come close (meet)
1347 // clear what we have
1348 impl->get_coeffs().clear();
1350
1352 impl ->make_Vphi(leaf_op,fence);
1353
1354 return *this;
1355 }
1356
1357 /// Special refinement on 6D boxes for the nuclear potentials (regularized with cusp, non-regularized with singularity)
1358 /// @param[in] op the convolution operator for screening
1359 template<typename opT>
1360 Function<T,NDIM>& fill_nuclear_cuspy_tree(const opT& op,const size_t particle,const bool fence=true){
1362 // clear what we have
1363 impl->get_coeffs().clear();
1365
1367 impl ->make_Vphi(leaf_op,fence);
1368
1369 return *this;
1370 }
1371
1372 /// Special refinement on 6D boxes for the nuclear potentials (regularized with cusp, non-regularized with singularity)
1375 // clear what we have
1376 impl->get_coeffs().clear();
1378
1380 impl ->make_Vphi(leaf_op,fence);
1381
1382 return *this;
1383 }
1384
1385 /// perform the hartree product of f*g, invoked by result
1386 template<size_t LDIM, size_t KDIM, typename opT>
1387 void do_hartree_product(const std::vector<std::shared_ptr<FunctionImpl<T,LDIM>>> left,
1388 const std::vector<std::shared_ptr<FunctionImpl<T,KDIM>>> right,
1389 const opT* op) {
1390
1391 // get the right leaf operator
1393 impl->hartree_product(left,right,leaf_op,true);
1394 impl->finalize_sum();
1395// this->truncate();
1396
1397 }
1398
1399 /// perform the hartree product of f*g, invoked by result
1400 template<size_t LDIM, size_t KDIM>
1401 void do_hartree_product(const std::vector<std::shared_ptr<FunctionImpl<T,LDIM>>> left,
1402 const std::vector<std::shared_ptr<FunctionImpl<T,KDIM>>> right) {
1403
1404// hartree_leaf_op<T,KDIM+LDIM> leaf_op(impl.get(),cdata.s0);
1406 impl->hartree_product(left,right,leaf_op,true);
1407 impl->finalize_sum();
1408// this->truncate();
1409
1410 }
1411
1412 /// Returns the inner product
1413
1414 /// Not efficient for computing multiple inner products
1415 /// @param[in] g Function, optionally on-demand
1416 template <typename R>
1419
1420 // fast return if possible
1421 if (not this->is_initialized()) return 0.0;
1422 if (not g.is_initialized()) return 0.0;
1423
1424 // if this and g are the same, use norm2()
1425 if constexpr (std::is_same_v<T,R>) {
1426 if (this->get_impl() == g.get_impl()) {
1427 TreeState state = this->get_impl()->get_tree_state();
1428 if (not(state == reconstructed or state == compressed))
1430 double norm = this->norm2();
1431 return norm * norm;
1432 }
1433 }
1434
1435 // do it case-by-case
1436 if constexpr (std::is_same_v<R,T>) {
1437 if (this->is_on_demand())
1438 return g.inner_on_demand(*this);
1439 if (g.is_on_demand())
1440 return this->inner_on_demand(g);
1441 }
1442
1444 if (VERIFY_TREE) g.verify_tree();
1445
1446 // compute in compressed form if compression is fast, otherwise in redundant form
1448
1450 g.change_tree_state(operating_state,false);
1451 impl->world.gop.fence();
1452
1453 TENSOR_RESULT_TYPE(T,R) local = impl->inner_local(*g.get_impl());
1454 impl->world.gop.sum(local);
1455 impl->world.gop.fence();
1456
1457 // restore state -- no need for this
1458 // change_tree_state(state,false);
1459 // g.change_tree_state(gstate,false);
1460 // impl->world.gop.fence();
1461
1462 return local;
1463 }
1464
1465 /// Return the local part of inner product with external function ... no communication.
1466 /// If you are going to be doing a bunch of inner_ext calls, set
1467 /// keep_redundant to true and then manually undo_redundant when you
1468 /// are finished.
1469 /// @param[in] f Pointer to function of type T that take coordT arguments. This is the externally provided function
1470 /// @param[in] leaf_refine boolean switch to turn on/off refinement past leaf nodes
1471 /// @param[in] keep_redundant boolean switch to turn on/off undo_redundant
1472 /// @return Returns local part of the inner product, i.e. over the domain of all function nodes on this compute node.
1473 T inner_ext_local(const std::shared_ptr< FunctionFunctorInterface<T,NDIM> > f, const bool leaf_refine=true, const bool keep_redundant=false) const {
1476 T local = impl->inner_ext_local(f, leaf_refine);
1478 return local;
1479 }
1480
1481 /// Return the inner product with external function ... requires communication.
1482 /// If you are going to be doing a bunch of inner_ext calls, set
1483 /// keep_redundant to true and then manually undo_redundant when you
1484 /// are finished.
1485 /// @param[in] f Reference to FunctionFunctorInterface. This is the externally provided function
1486 /// @param[in] leaf_refine boolean switch to turn on/off refinement past leaf nodes
1487 /// @param[in] keep_redundant boolean switch to turn on/off undo_redundant
1488 /// @return Returns the inner product
1489 T inner_ext(const std::shared_ptr< FunctionFunctorInterface<T,NDIM> > f, const bool leaf_refine=true, const bool keep_redundant=false) const {
1492 T local = impl->inner_ext_local(f, leaf_refine);
1493 impl->world.gop.sum(local);
1494 impl->world.gop.fence();
1496 return local;
1497 }
1498
1499 /// Return the inner product with external function ... requires communication.
1500 /// If you are going to be doing a bunch of inner_ext calls, set
1501 /// keep_redundant to true and then manually undo_redundant when you
1502 /// are finished.
1503 /// @param[in] f Reference to FunctionFunctorInterface. This is the externally provided function
1504 /// @param[in] leaf_refine boolean switch to turn on/off refinement past leaf nodes
1505 /// @return Returns the inner product
1507 const bool leaf_refine=true) const {
1509 reconstruct();
1510 T local = impl->inner_adaptive_local(f, leaf_refine);
1511 impl->world.gop.sum(local);
1512 impl->world.gop.fence();
1513 return local;
1514 }
1515
1516 /// Return the local part of gaxpy with external function, this*alpha + f*beta ... no communication.
1517 /// @param[in] alpha prefactor for this Function
1518 /// @param[in] f Pointer to function of type T that take coordT arguments. This is the externally provided function
1519 /// @param[in] beta prefactor for f
1520 template <typename L>
1521 void gaxpy_ext(const Function<L,NDIM>& left, T (*f)(const coordT&), T alpha, T beta, double tol, bool fence=true) const {
1523 if (!left.is_reconstructed()) left.reconstruct();
1524 impl->gaxpy_ext(left.get_impl().get(), f, alpha, beta, tol, fence);
1525 }
1526
1527 /// Returns the inner product for one on-demand function
1528
1529 /// It does work, but it might not give you the precision you expect.
1530 /// The assumption is that the function g returns proper sum
1531 /// coefficients on the MRA tree of this. This might not be the case if
1532 /// g is constructed with an implicit multiplication, e.g.
1533 /// result = <this|g>, with g = 1/r12 | gg>
1534 /// @param[in] g on-demand function
1535 template<typename R>
1537 MADNESS_ASSERT(g.is_on_demand() and (not this->is_on_demand()));
1538
1539 constexpr std::size_t LDIM=std::max(NDIM/2,std::size_t(1));
1540 auto func=dynamic_cast<CompositeFunctorInterface<T,NDIM,LDIM>* >(g.get_impl()->get_functor().get());
1542 func->make_redundant(true);
1543 func->replicate_low_dim_functions(true);
1544 this->reconstruct(); // if this == &g we don't need g to be redundant
1545
1547
1548 TENSOR_RESULT_TYPE(T, R) local = impl->inner_local_on_demand(*g.get_impl());
1549 impl->world.gop.sum(local);
1550 impl->world.gop.fence();
1551
1552 return local;
1553 }
1554
1555 /// project this on the low-dim function g: h(x) = <f(x,y) | g(y)>
1556
1557 /// @param[in] g low-dim function
1558 /// @param[in] dim over which dimensions to be integrated: 0..LDIM-1 or LDIM..NDIM-1
1559 /// @return new function of dimension NDIM-LDIM
1560 template <typename R, size_t LDIM>
1562 if (NDIM<=LDIM) MADNESS_EXCEPTION("confused dimensions in project_out?",1);
1563 MADNESS_CHECK_THROW(dim==0 or dim==1,"dim must be 0 or 1 in project_out");
1564 verify();
1565 typedef TENSOR_RESULT_TYPE(T,R) resultT;
1566 static const size_t KDIM=NDIM-LDIM;
1567
1569 .k(g.k()).thresh(g.thresh());
1570 Function<resultT,KDIM> result=factory; // no empty() here!
1571
1573 g.change_tree_state(redundant,false);
1574 world().gop.fence();
1575 this->get_impl()->project_out(result.get_impl().get(),g.get_impl().get(),dim,true);
1576// result.get_impl()->project_out2(this->get_impl().get(),gimpl,dim);
1577 result.world().gop.fence();
1578 g.change_tree_state(reconstructed,false);
1579 result.get_impl()->trickle_down(false);
1580 result.get_impl()->set_tree_state(reconstructed);
1581 result.world().gop.fence();
1582 return result;
1583 }
1584
1585 Function<T,NDIM/2> dirac_convolution(const bool fence=true) const {
1586 constexpr std::size_t LDIM=NDIM/2;
1587 MADNESS_CHECK_THROW(NDIM==2*LDIM,"NDIM must be even");
1588// // this will be the result function
1591 if(!is_reconstructed()) this->reconstruct();
1592 this->get_impl()->do_dirac_convolution(f.get_impl().get(),fence);
1593 return f;
1594 }
1595
1596 /// Replaces this function with one loaded from an archive using the default processor map
1597
1598 /// Archive can be sequential or parallel.
1599 ///
1600 /// The & operator for serializing will only work with parallel archives.
1601 template <typename Archive>
1602 void load(World& world, Archive& ar) {
1604 // Type checking since we are probably circumventing the archive's own type checking
1605 long magic = 0l, id = 0l, ndim = 0l, k = 0l;
1606 Tensor<double> cell;
1607 ar & magic & id & ndim & k & cell;
1608 // CHECK not ASSERT: ASSERT is compiled out when ASSERTION_TYPE=disable
1610 "Function archive was written by an incompatible MADNESS version; regenerate it.");
1612 MADNESS_CHECK(ndim == NDIM);
1613
1614 // if simulation cell is set it must match the cell from function on file.
1615 // if simulation cell is not set set it to the one found on file
1616 // -- for the latter the only use case seems a python script for plotting
1618 if ((cell-FunctionDefaults<NDIM>::get_cell()).normf()>1.e-14) {
1619 std::ostringstream oss;
1620 oss << "simulation cells inconsistent: stored cell differs from FunctionDefaults cell.\n"
1621 << "Call FunctionDefaults<" << NDIM << ">::clear_cell() before reloading "
1622 << "(this will render all existing functions useless!)";
1623 MADNESS_EXCEPTION(oss.str().c_str(), 1);
1624 }
1625 } else { // no cell set in the defaults: use the one from file
1627 }
1628
1629 impl.reset(new implT(FunctionFactory<T,NDIM>(world).k(k).empty()));
1630 impl->load(ar);
1631 }
1632
1633
1634 /// Stores the function to an archive
1635
1636 /// Archive can be sequential or parallel.
1637 ///
1638 /// The & operator for serializing will only work with parallel archives.
1639 template <typename Archive>
1640 void store(Archive& ar) const {
1642 verify();
1643 // For type checking, etc.
1644 ar & long(FUNCTION_ARCHIVE_MAGIC) & long(TensorTypeData<T>::id) & long(NDIM) & long(k()) & impl->get_cell();
1645
1646 impl->store(ar);
1647 }
1648
1649 /// change the tensor type of the coefficients in the FunctionNode
1650
1651 /// @param[in] targs target tensor arguments (threshold and full/low rank)
1652 void change_tensor_type(const TensorArgs& targs, bool fence=true) {
1653 if (not impl) return;
1654 impl->change_tensor_type1(targs,fence);
1655 }
1656
1657
1658 /// This is replaced with left*right ... private
1659 template <typename Q, typename opT>
1661 const opT& op, bool fence) {
1663 func.verify();
1664 MADNESS_ASSERT(func.is_reconstructed());
1665 if (VERIFY_TREE) func.verify_tree();
1666 impl.reset(new implT(*func.get_impl(), func.get_pmap(), false));
1667 impl->unaryXX(func.get_impl().get(), op, fence);
1668 return *this;
1669 }
1670
1671 /// Returns vector of FunctionImpl pointers corresponding to vector of functions
1672 template <typename Q, std::size_t D>
1673 static std::vector< std::shared_ptr< FunctionImpl<Q,D> > > vimpl(const std::vector< Function<Q,D> >& v) {
1675 std::vector< std::shared_ptr< FunctionImpl<Q,D> > > r(v.size());
1676 for (unsigned int i=0; i<v.size(); ++i) r[i] = v[i].get_impl();
1677 return r;
1678 }
1679
1680 /// This is replaced with op(vector of functions) ... private
1681 template <typename opT>
1682 Function<T,NDIM>& multiop_values(const opT& op, const std::vector< Function<T,NDIM> >& vf) {
1683 std::vector<implT*> v(vf.size(),NULL);
1684 for (unsigned int i=0; i<v.size(); ++i) {
1685 if (vf[i].is_initialized()) v[i] = vf[i].get_impl().get();
1686 }
1687 impl->multiop_values(op, v);
1688 world().gop.fence();
1689 if (VERIFY_TREE) verify_tree();
1690
1691 return *this;
1692 }
1693
1694 /// apply op on the input vector yielding an output vector of functions
1695
1696 /// (*this) is just a dummy Function to be able to call internal methods in FuncImpl
1697 /// @param[in] op the operator working on vin
1698 /// @param[in] vin vector of input Functions
1699 /// @param[out] vout vector of output Functions vout = op(vin)
1700 template <typename opT>
1702 const std::vector< Function<T,NDIM> >& vin,
1703 std::vector< Function<T,NDIM> >& vout,
1704 const bool fence=true) {
1705 std::vector<implT*> vimplin(vin.size(),NULL);
1706 for (unsigned int i=0; i<vin.size(); ++i) {
1707 if (vin[i].is_initialized()) vimplin[i] = vin[i].get_impl().get();
1708 }
1709 std::vector<implT*> vimplout(vout.size(),NULL);
1710 for (unsigned int i=0; i<vout.size(); ++i) {
1711 if (vout[i].is_initialized()) vimplout[i] = vout[i].get_impl().get();
1712 }
1713
1714 impl->multi_to_multi_op_values(op, vimplin, vimplout, fence);
1715 if (VERIFY_TREE) verify_tree();
1716
1717 }
1718
1719
1720 /// Multiplication of function * vector of functions using recursive algorithm of mulxx
1721 template <typename L, typename R>
1722 void vmulXX(const Function<L,NDIM>& left,
1723 const std::vector< Function<R,NDIM> >& right,
1724 std::vector< Function<T,NDIM> >& result,
1725 double tol,
1726 bool fence) {
1728
1729 std::vector<FunctionImpl<T,NDIM>*> vresult(right.size());
1730 std::vector<const FunctionImpl<R,NDIM>*> vright(right.size());
1731 for (unsigned int i=0; i<right.size(); ++i) {
1732 result[i].set_impl(left,false);
1733 // set_impl copies left's state, which is redundant here, but the kernel builds
1734 // a reconstructed tree (interior nodes carry no coefficients)
1735 result[i].get_impl()->set_tree_state(reconstructed);
1736 vresult[i] = result[i].impl.get();
1737 vright[i] = right[i].get_impl().get();
1738 }
1739
1740 left.world().gop.fence(); // Is this still essential? Yes.
1741 vresult[0]->mulXXvec(left.get_impl().get(), vright, vresult, tol, fence);
1742 }
1743
1744 /// Same as \c operator* but with optional fence and no automatic reconstruction
1745
1746 /// f or g are on-demand functions
1747 template<typename L, typename R>
1748 void mul_on_demand(const Function<L,NDIM>& f, const Function<R,NDIM>& g, bool fence=true) {
1749 const FunctionImpl<L,NDIM>* fimpl=f.get_impl().get();
1750 const FunctionImpl<R,NDIM>* gimpl=g.get_impl().get();
1751 if (fimpl->is_on_demand() and gimpl->is_on_demand()) {
1752 MADNESS_EXCEPTION("can't multiply two on-demand functions",1);
1753 }
1754
1755 if (fimpl->is_on_demand()) {
1757 impl->multiply(leaf_op1,gimpl,fimpl,fence);
1758 } else {
1760 impl->multiply(leaf_op1,fimpl,gimpl,fence);
1761 }
1762 }
1763
1764 /// sparse transformation of a vector of functions ... private
1765 template <typename R, typename Q>
1766 void vtransform(const std::vector< Function<R,NDIM> >& v,
1767 const Tensor<Q>& c,
1768 std::vector< Function<T,NDIM> >& vresult,
1769 double tol,
1770 bool fence=true) {
1772 vresult[0].impl->vtransform(vimpl(v), c, vimpl(vresult), tol, fence);
1773 }
1774
1775 /// This is replaced with alpha*left + beta*right ... private
1776 template <typename L, typename R>
1778 T beta, const Function<R,NDIM>& right, bool fence) {
1780 left.verify();
1781 right.verify();
1782 MADNESS_ASSERT(left.is_compressed() && right.is_compressed());
1783 if (VERIFY_TREE) left.verify_tree();
1784 if (VERIFY_TREE) right.verify_tree();
1785 impl.reset(new implT(*left.get_impl(), left.get_pmap(), false));
1786 impl->gaxpy(alpha,*left.get_impl(),beta,*right.get_impl(),fence);
1787 return *this;
1788 }
1789
1790 /// This is replaced with mapdim(f) ... private
1791 Function<T,NDIM>& mapdim(const Function<T,NDIM>& f, const std::vector<long>& map, bool fence) {
1793 f.verify();
1794 if (VERIFY_TREE) f.verify_tree();
1795 for (std::size_t i=0; i<NDIM; ++i) MADNESS_ASSERT(map[i]>=0 && static_cast<std::size_t>(map[i])<NDIM);
1796 impl.reset(new implT(*f.impl, f.get_pmap(), false));
1797 impl->mapdim(*f.impl,map,fence);
1798 return *this;
1799 }
1800
1801 /// This is replaced with mirror(f) ... private
1802
1803 /// similar to mapdim, but maps from x to -x, y to -y, and so on
1804 /// Example: mirror a 3d function on the xy plane: mirror={1,1,-1}
1805 /// @param[in] mirror array of -1 and 1, corresponding to mirror or not
1806 Function<T,NDIM>& mirror(const Function<T,NDIM>& f, const std::vector<long>& mirrormap, bool fence) {
1808 f.verify();
1809 if (VERIFY_TREE) f.verify_tree();
1810 for (std::size_t i=0; i<NDIM; ++i) MADNESS_ASSERT((mirrormap[i]==1) or (mirrormap[i]==-1));
1811 impl.reset(new implT(*f.impl, f.get_pmap(), false));
1812 impl->mirror(*f.impl,mirrormap,fence);
1813 return *this;
1814 }
1815
1816 /// This is replaced with mirror(map(f)) ... private
1817
1818 /// first map then mirror!
1819 /// mirror is similar to mapdim, but maps from x to -x, y to -y, and so on
1820 /// Example: mirror a 3d function on the xy plane: mirror={1,1,-1}
1821 /// Example: c4 rotation of a 3d function around the z axis:
1822 /// x->y, y->-x, z->z: map(1,0,2); mirror(-1,1,1)
1823 /// @param[in] map array holding dimensions
1824 /// @param[in] mirror array of -1 and 1, corresponding to mirror or not
1826 const std::vector<long>& map, const std::vector<long>& mirror,
1827 bool fence) {
1829 f.verify();
1830 if (VERIFY_TREE) f.verify_tree();
1831 for (std::size_t i=0; i<mirror.size(); ++i) MADNESS_ASSERT((mirror[i]==1) or (mirror[i]==-1));
1832 for (std::size_t i=0; i<map.size(); ++i) MADNESS_ASSERT(map[i]>=0 && static_cast<std::size_t>(map[i])<NDIM);
1833
1834 impl.reset(new implT(*f.impl, f.get_pmap(), false));
1835 impl->map_and_mirror(*f.impl,map,mirror,fence);
1836 return *this;
1837 }
1838
1839
1840 /// check symmetry of a function by computing the 2nd derivative
1841 double check_symmetry() const {
1842
1844 if (VERIFY_TREE) verify_tree();
1845 double local = impl->check_symmetry_local();
1846 impl->world.gop.sum(local);
1847 impl->world.gop.fence();
1848 double asy=sqrt(local);
1849 if (this->world().rank()==0) print("asymmetry wrt particle",asy);
1851 return asy;
1852 }
1853
1854 /// reduce the rank of the coefficient tensors
1855 Function<T,NDIM>& reduce_rank(const double thresh=0.0, const bool fence=true) {
1856 verify();
1857 double thresh1= (thresh==0.0) ? impl->get_tensor_args().thresh : thresh;
1858 impl->reduce_rank(thresh1,fence);
1859 return *this;
1860 }
1861
1862 /// remove all nodes with level higher than n
1863 Function<T,NDIM>& chop_at_level(const int n, const bool fence=true) {
1864 verify();
1866 impl->chop_at_level(n,true);
1868 return *this;
1869 }
1870 };
1871
1872// template <typename T, typename opT, std::size_t NDIM>
1873 template <typename T, typename opT, std::size_t NDIM>
1874 Function<T,NDIM> multiop_values(const opT& op, const std::vector< Function<T,NDIM> >& vf) {
1876 r.set_impl(vf[0], false);
1877 r.multiop_values(op, vf);
1878 return r;
1879 }
1880
1881 /// Returns new function equal to alpha*f(x) with optional fence
1882 template <typename Q, typename T, std::size_t NDIM>
1884 mul(const Q alpha, const Function<T,NDIM>& f, bool fence=true) {
1886 f.verify();
1887 if (VERIFY_TREE) f.verify_tree();
1888 Function<TENSOR_RESULT_TYPE(Q,T),NDIM> result;
1889 result.set_impl(f, false);
1890 result.get_impl()->scale_oop(alpha,*f.get_impl(),fence);
1891 return result;
1892 }
1893
1894
1895 /// Returns new function equal to f(x)*alpha with optional fence
1896 template <typename Q, typename T, std::size_t NDIM>
1898 mul(const Function<T,NDIM>& f, const Q alpha, bool fence=true) {
1900 return mul(alpha,f,fence);
1901 }
1902
1903
1904 /// Returns new function equal to f(x)*alpha
1905
1906 /// Using operator notation forces a global fence after each operation
1907 template <typename Q, typename T, std::size_t NDIM>
1910 return mul(alpha, f, true);
1911 }
1912
1913 /// Returns new function equal to alpha*f(x)
1914
1915 /// Using operator notation forces a global fence after each operation
1916 template <typename Q, typename T, std::size_t NDIM>
1919 return mul(alpha, f, true);
1920 }
1921
1922 /// Sparse multiplication; the scalar interface redirects to the vector one in vmra.h
1923
1924 /// @param[in] tol target absolute accuracy of the product; see the vector mul_sparse in
1925 /// vmra.h for the semantics, including the internal safety margin and tol=0
1926 /// @param[in] do_make_redundant if false, both inputs must already be redundant
1927 template <typename L, typename R,std::size_t NDIM>
1929 mul_sparse(const Function<L,NDIM>& left, const Function<R,NDIM>& right, double tol,
1930 bool fence=true, bool do_make_redundant=true) {
1932 left.verify();
1933 right.verify();
1934 std::vector< Function<R,NDIM> > vright(1,right);
1935 return mul_sparse(left.get_impl()->world, left, vright, tol, fence, do_make_redundant)[0];
1936 }
1937
1938 /// Same as \c operator* but with optional fence
1939
1940 /// @param[in] tol 0 (the default) multiplies exactly; see mul_sparse to screen
1941 template <typename L, typename R,std::size_t NDIM>
1943 mul(const Function<L,NDIM>& left, const Function<R,NDIM>& right, bool fence=true,
1944 bool do_make_redundant=true, double tol=0.0) {
1945 return mul_sparse(left,right,tol,fence,do_make_redundant);
1946 }
1947
1948 /// Generate new function = op(left,right) where op acts on the function values
1949 template <typename L, typename R, typename opT, std::size_t NDIM>
1951 binary_op(const Function<L,NDIM>& left, const Function<R,NDIM>& right, const opT& op, bool fence=true) {
1953 if (!left.is_reconstructed()) left.reconstruct();
1954 if (!right.is_reconstructed()) right.reconstruct();
1955
1957 result.set_impl(left, false);
1958 result.get_impl()->binaryXX(left.get_impl().get(), right.get_impl().get(), op, fence);
1959 return result;
1960 }
1961
1962 /// Out of place application of unary operation to function values with optional fence
1963 template <typename Q, typename opT, std::size_t NDIM>
1965 unary_op(const Function<Q,NDIM>& func, const opT& op, bool fence=true) {
1966 if (!func.is_reconstructed()) func.reconstruct();
1969 result.set_impl(func, false);
1970 result.get_impl()->unaryXXvalues(func.get_impl().get(), op, fence);
1971 return result;
1972 }
1973
1974
1975 /// Out of place application of unary operation to scaling function coefficients with optional fence
1976 template <typename Q, typename opT, std::size_t NDIM>
1978 unary_op_coeffs(const Function<Q,NDIM>& func, const opT& op, bool fence=true) {
1979 if (!func.is_reconstructed()) func.reconstruct();
1981 return result.unary_op_coeffs(func,op,fence);
1982 }
1983
1984 /// Use the vmra/mul(...) interface instead
1985
1986 /// This so that we don't have to have friend functions in a different header.
1987 ///
1988 /// left and right must be in redundant state, with tree norms available.
1989 template <typename L, typename R, std::size_t D>
1990 std::vector< Function<TENSOR_RESULT_TYPE(L,R),D> >
1991 vmulXX(const Function<L,D>& left, const std::vector< Function<R,D> >& vright, double tol, bool fence=true) {
1992 if (vright.size() == 0) return std::vector< Function<TENSOR_RESULT_TYPE(L,R),D> >();
1993 std::vector< Function<TENSOR_RESULT_TYPE(L,R),D> > vresult(vright.size());
1994 vresult[0].vmulXX(left, vright, vresult, tol, fence);
1995 return vresult;
1996 }
1997
1998 /// Multiplies two functions with the new result being of type TensorResultType<L,R>
1999
2000 /// Using operator notation forces a global fence after each operation but also
2001 /// enables us to automatically reconstruct the input functions as required.
2002 template <typename L, typename R, std::size_t NDIM>
2004 operator*(const Function<L,NDIM>& left, const Function<R,NDIM>& right) {
2005 if (!left.is_reconstructed()) left.reconstruct();
2006 if (!right.is_reconstructed()) right.reconstruct();
2007 MADNESS_ASSERT(not (left.is_on_demand() or right.is_on_demand()));
2008 return mul(left,right,true);
2009 }
2010
2011 /// Performs a Hartree/outer product on the two given low-dimensional function vectors
2012
2013 /// @return result(x,y) = \sum_i f_i(x) g_i(y)
2014 template<typename T, std::size_t KDIM, std::size_t LDIM>
2016 hartree_product(const std::vector<Function<T,KDIM>>& left, const std::vector<Function<T,LDIM>>& right) {
2017
2018 MADNESS_CHECK_THROW(left.size()==right.size(), "hartree_product: left and right must have same size");
2019 if (left.size()==0) return Function<T,KDIM+LDIM>();
2020
2022
2024 .k(left.front().k()).thresh(thresh);
2025 Function<T,KDIM+LDIM> result=factory.empty();
2026
2027 // some prep work
2030 std::vector<std::shared_ptr<FunctionImpl<T,KDIM>>> vleft=get_impl(left);
2031 std::vector<std::shared_ptr<FunctionImpl<T,LDIM>>> vright=get_impl(right);
2032
2034
2035 return result;
2036
2037 }
2038
2039 /// Performs a Hartree product on the two given low-dimensional functions
2040 template<typename T, std::size_t KDIM, std::size_t LDIM>
2043 typedef std::vector<Function<T,KDIM>> vector;
2044 return hartree_product(vector({left2}),vector({right2}));
2045 }
2046
2047 /// Performs a Hartree product on the two given low-dimensional functions
2048 template<typename T, std::size_t KDIM, std::size_t LDIM, typename opT>
2051 const opT& op) {
2052
2053 // we need both sum and difference coeffs for error estimation
2054 Function<T,KDIM>& left = const_cast< Function<T,KDIM>& >(left2);
2055 Function<T,LDIM>& right = const_cast< Function<T,LDIM>& >(right2);
2056
2058
2060 .k(left.k()).thresh(thresh);
2061 Function<T,KDIM+LDIM> result=factory.empty();
2062
2063 if (result.world().rank()==0) {
2064 print("incomplete FunctionFactory in Function::hartree_product");
2065 print("thresh: ", thresh);
2066 }
2067 bool same=(left2.get_impl()==right2.get_impl());
2068
2069 // some prep work
2070 left.make_nonstandard(true, true);
2071 right.make_nonstandard(true, true);
2072
2073 std::vector<std::shared_ptr<FunctionImpl<T,KDIM>>> vleft;
2074 std::vector<std::shared_ptr<FunctionImpl<T,LDIM>>> vright;
2075 vleft.push_back(left.get_impl());
2076 vright.push_back(right.get_impl());
2077 result.do_hartree_product(vleft,right,&op);
2078
2079 left.standard(false);
2080 if (not same) right.standard(false);
2081 left2.world().gop.fence();
2082
2083 return result;
2084 }
2085
2086 /// adds beta*right only left: alpha*left + beta*right optional fence and no automatic compression
2087
2088 /// left and right might live in different worlds, the accumulation is non-blocking
2089 template <typename L, typename R,std::size_t NDIM>
2090 void
2092 TENSOR_RESULT_TYPE(L,R) beta, const Function<R,NDIM>& right, bool fence=true) {
2095 left.gaxpy(alpha, right, beta, fence);
2096 }
2097
2098 /// Returns new function alpha*left + beta*right optional fence and no automatic compression
2099 template <typename L, typename R,std::size_t NDIM>
2102 TENSOR_RESULT_TYPE(L,R) beta, const Function<R,NDIM>& right, bool fence=true) {
2105 return result.gaxpy_oop(alpha, left, beta, right, fence);
2106 }
2107
2108 /// Same as \c operator+ but with optional fence and no automatic compression
2109 template <typename L, typename R,std::size_t NDIM>
2111 add(const Function<L,NDIM>& left, const Function<R,NDIM>& right, bool fence=true) {
2112 return gaxpy_oop(TENSOR_RESULT_TYPE(L,R)(1.0), left,
2113 TENSOR_RESULT_TYPE(L,R)(1.0), right, fence);
2114 }
2115
2116
2117 /// Returns new function alpha*left + beta*right optional fence, having both addends reconstructed
2118 template<typename T, std::size_t NDIM>
2120 const double beta, const Function<T,NDIM>& right, const bool fence=true) {
2121 Function<T,NDIM> result;
2122 result.set_impl(right,false);
2123
2126 result.get_impl()->gaxpy_oop_reconstructed(alpha,*left.get_impl(),beta,*right.get_impl(),fence);
2127 return result;
2128
2129 }
2130
2131 /// Adds two functions with the new result being of type TensorResultType<L,R>
2132
2133 /// Using operator notation forces a global fence after each operation
2134 template <typename L, typename R, std::size_t NDIM>
2136 operator+(const Function<L,NDIM>& left, const Function<R,NDIM>& right) {
2137 if (VERIFY_TREE) left.verify_tree();
2138 if (VERIFY_TREE) right.verify_tree();
2139
2140 TreeState operating_state=left.get_impl()->get_tensor_type()==TT_FULL ? compressed : reconstructed;
2141 // no compression for high-dimensional functions
2143 left.reconstruct();
2144 right.reconstruct();
2145 return gaxpy_oop_reconstructed(1.0,left,1.0,right,true);
2146 } else {
2147 if (!left.is_compressed()) left.compress();
2148 if (!right.is_compressed()) right.compress();
2149 return add(left,right,true);
2150 }
2151 }
2152
2153 /// Same as \c operator- but with optional fence and no automatic compression
2154 template <typename L, typename R,std::size_t NDIM>
2156 sub(const Function<L,NDIM>& left, const Function<R,NDIM>& right, bool fence=true) {
2157 return gaxpy_oop(TENSOR_RESULT_TYPE(L,R)(1.0), left,
2158 TENSOR_RESULT_TYPE(L,R)(-1.0), right, fence);
2159 }
2160
2161
2162 /// Subtracts two functions with the new result being of type TensorResultType<L,R>
2163
2164 /// Using operator notation forces a global fence after each operation
2165 template <typename L, typename R, std::size_t NDIM>
2167 operator-(const Function<L,NDIM>& left, const Function<R,NDIM>& right) {
2169 // no compression for high-dimensional functions
2170 if (NDIM==6) {
2171 left.reconstruct();
2172 right.reconstruct();
2173 return gaxpy_oop_reconstructed(1.0,left,-1.0,right,true);
2174 } else {
2175 if (!left.is_compressed()) left.compress();
2176 if (!right.is_compressed()) right.compress();
2177 return sub(left,right,true);
2178 }
2179 }
2180
2181 /// Create a new copy of the function with different distribution and optional fence
2182
2183 /// Works in either basis. Different distributions imply
2184 /// asynchronous communication and the optional fence is
2185 /// collective.
2186 template <typename T, std::size_t NDIM>
2188 const std::shared_ptr< WorldDCPmapInterface< Key<NDIM> > >& pmap,
2189 bool fence = true) {
2191 f.verify();
2192 Function<T,NDIM> result;
2194 result.set_impl(std::shared_ptr<implT>(new implT(*f.get_impl(), pmap, false)));
2195 result.get_impl()->copy_coeffs(*f.get_impl(), fence);
2196 if (VERIFY_TREE) result.verify_tree();
2197 return result;
2198 }
2199
2200 /// Create a new copy of the function with the same distribution and optional fence
2201 template <typename T, std::size_t NDIM>
2204 return copy(f, f.get_pmap(), fence);
2205 }
2206
2207 /// Create a new copy of function f living in world (might differ from f.world)
2208
2209 /// uses the default processor map of world
2210 template <typename T, std::size_t NDIM>
2215
2216 // create a new function with pmap distribution, same parameters as f, but no coeffs
2217 Function<T,NDIM> result;
2218 result.set_impl(std::make_shared<implT>(world,*f.get_impl(), pmap, false));
2219 // copy f's coefficients to result
2220 result.get_impl()->copy_coeffs(*f.get_impl(), fence);
2221 return result;
2222 }
2223
2224 /// Type conversion implies a deep copy. No communication except for optional fence.
2225
2226 /// Works in either basis but any loss of precision may result in different errors
2227 /// in applied in a different basis.
2228 ///
2229 /// The new function is formed with the options from the default constructor.
2230 ///
2231 /// There is no automatic type conversion since this is generally a rather dangerous
2232 /// thing and because there would be no way to make the fence optional.
2233 template <typename T, typename Q, std::size_t NDIM>
2236 f.verify();
2237 Function<Q,NDIM> result;
2238 result.set_impl(f, false);
2239 result.get_impl()->copy_coeffs(*f.get_impl(), fence);
2240 return result;
2241 }
2242
2243
2244 /// Return the complex conjugate of the input function with the same distribution and optional fence
2245
2246 /// !!! The fence is actually not optional in the current implementation !!!
2247 template <typename T, std::size_t NDIM>
2250 Function<T,NDIM> result = copy(f,true);
2251 return result.conj(fence);
2252 }
2253
2254 /// Apply operator on a hartree product of two low-dimensional functions
2255
2256 /// Supposed to be something like result= G( f(1)*f(2))
2257 /// the hartree product is never constructed explicitly, but its coeffs are
2258 /// constructed on the fly and processed immediately.
2259 /// @param[in] op the operator
2260 /// @param[in] f1 function of particle 1
2261 /// @param[in] f2 function of particle 2
2262 /// @param[in] fence if we shall fence
2263 /// @return a function of dimension NDIM=LDIM+LDIM
2264 template <typename opT, typename T, std::size_t LDIM>
2265 Function<TENSOR_RESULT_TYPE(typename opT::opT,T), LDIM+LDIM>
2266 apply(const opT& op, const std::vector<Function<T,LDIM>>& f1, const std::vector<Function<T,LDIM>>& f2, bool fence=true) {
2267
2268 World& world=f1.front().world();
2269
2270 typedef TENSOR_RESULT_TYPE(T,typename opT::opT) resultT;
2271 typedef std::vector<Function<T,LDIM>> vecfuncL;
2272
2273 vecfuncL& ff1 = const_cast< vecfuncL& >(f1);
2274 vecfuncL& ff2 = const_cast< vecfuncL& >(f2);
2275
2276 bool same=(ff1[0].get_impl()==ff2[0].get_impl());
2277
2278 reconstruct(world,f1,false);
2279 reconstruct(world,f2,false);
2280 world.gop.fence();
2281 // keep the leaves! They are assumed to be there later
2282 // even for modified op we need NS form for the hartree_leaf_op
2283 for (auto& f : f1) f.make_nonstandard(true,false);
2284 for (auto& f : f2) f.make_nonstandard(true,false);
2285 world.gop.fence();
2286
2287
2290 Function<resultT,LDIM+LDIM> result=factory.empty().fence();
2291
2292 result.get_impl()->reset_timer();
2293 op.reset_timer();
2294
2295 // will fence here
2296 for (size_t i=0; i<f1.size(); ++i)
2297 result.get_impl()->recursive_apply(op, f1[i].get_impl().get(),f2[i].get_impl().get(),false);
2298 world.gop.fence();
2299
2300 if (op.print_timings) {
2301 result.get_impl()->print_timer();
2302 op.print_timer();
2303 }
2304
2305 result.get_impl()->finalize_apply(); // need fence before reconstruct
2306
2307 if (op.modified()) {
2308 result.get_impl()->trickle_down(true);
2309 } else {
2310 result.get_impl()->reconstruct(true);
2311 }
2312 standard(world,ff1,false);
2313 if (not same) standard(world,ff2,false);
2314
2315 return result;
2316 }
2317
2318
2319 /// Apply operator ONLY in non-standard form - required other steps missing !!
2320 template <typename opT, typename R, std::size_t NDIM>
2321 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM>
2322 apply_only(const opT& op, const Function<R,NDIM>& f, bool fence=true) {
2323 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM> result;
2324
2325 constexpr std::size_t OPDIM=opT::opdim;
2326 constexpr bool low_dim=(OPDIM*2==NDIM); // apply on some dimensions only
2327
2328 // specialized version for 3D
2329 if (NDIM <= 3 and (not low_dim)) {
2330 result.set_impl(f, false);
2331 result.get_impl()->apply(op, *f.get_impl(), fence);
2332
2333 } else { // general version for higher dimension
2334 //bool print_timings=false;
2335 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM> r1;
2336
2337 result.set_impl(f, false);
2338 r1.set_impl(f, false);
2339
2340 result.get_impl()->reset_timer();
2341 op.reset_timer();
2342
2343 result.get_impl()->apply_source_driven(op, *f.get_impl(), fence);
2344
2345 // recursive_apply is about 20% faster than apply_source_driven
2346 //result.get_impl()->recursive_apply(op, f.get_impl().get(),
2347 // r1.get_impl().get(),true); // will fence here
2348
2349 }
2350
2351 return result;
2352 }
2353
2354 /// Apply operator in non-standard form
2355
2356 /// Returns a new function with the same distribution
2357 ///
2358 /// !!! For the moment does NOT respect fence option ... always fences
2359 /// if the operator acts on one particle only the result will be sorted as
2360 /// g.particle=1: g(f) = \int g(x,x') f(x',y) dx' = result(x,y)
2361 /// g.particle=2: g(f) = \int g(y,y') f(x,y') dy' = result(x,y)
2362 /// for the second case it will notably *not* be as it is implemented in the partial inner product!
2363 /// g.particle=2 g(f) = result(x,y)
2364 /// inner(g(y,y'),f(x,y'),1,1) = result(y,x)
2365 /// also note the confusion with the counting of the particles/integration variables
2366 template <typename opT, typename R, std::size_t NDIM>
2367 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM>
2368 apply(const opT& op, const Function<R,NDIM>& f, bool fence=true) {
2369
2370 typedef TENSOR_RESULT_TYPE(typename opT::opT,R) resultT;
2371 Function<R,NDIM>& ff = const_cast< Function<R,NDIM>& >(f);
2373
2374 MADNESS_ASSERT(not f.is_on_demand());
2375 bool print_timings=op.print_timings;
2376
2377 if (VERIFY_TREE) ff.verify_tree();
2378 ff.reconstruct();
2379 if (print_timings) ff.print_size("ff in apply after reconstruct");
2380
2381 if (op.modified()) {
2382
2383 ff.change_tree_state(redundant);
2384// ff.get_impl()->make_redundant(true);
2385 result = apply_only(op, ff, fence);
2386 ff.get_impl()->undo_redundant(false);
2387 result.get_impl()->trickle_down(true);
2388
2389 } else {
2390
2391 // saves the standard() step, which is very expensive in 6D
2392// Function<R,NDIM> fff=copy(ff);
2394 fff.make_nonstandard(op.doleaves, true);
2395 if (print_timings) fff.print_size("ff in apply after make_nonstandard");
2396 if ((print_timings) and (f.world().rank()==0)) {
2397 fff.get_impl()->timer_filter.print("filter");
2398 fff.get_impl()->timer_compress_svd.print("compress_svd");
2399 }
2400 result = apply_only(op, fff, fence);
2401 result.get_impl()->set_tree_state(nonstandard_after_apply);
2402 ff.world().gop.fence();
2403 if (print_timings) result.print_size("result after apply_only");
2404
2405 // svd-tensors need some post-processing
2406 if (result.get_impl()->get_tensor_type()==TT_2D) {
2407 double elapsed=result.get_impl()->finalize_apply();
2408 if (print_timings) printf("time in finalize_apply %8.2f\n",elapsed);
2409 }
2410 if (print_timings) {
2411 result.get_impl()->print_timer();
2412 op.print_timer();
2413 }
2414
2415 result.get_impl()->reconstruct(true);
2416
2417// fff.clear();
2418 if (op.destructive()) {
2419 ff.world().gop.fence();
2420 ff.clear();
2421 } else {
2422 // ff.standard();
2423 ff.reconstruct();
2424 }
2425
2426 }
2427 if (print_timings) result.print_size("result after reconstruction");
2428 return result;
2429 }
2430
2431
2432 template <typename opT, typename R, std::size_t NDIM>
2433 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM>
2434 apply_1d_realspace_push(const opT& op, const Function<R,NDIM>& f, int axis, bool fence=true) {
2436 Function<R,NDIM>& ff = const_cast< Function<R,NDIM>& >(f);
2437 if (VERIFY_TREE) ff.verify_tree();
2438 ff.reconstruct();
2439
2440 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM> result;
2441
2442 result.set_impl(ff, false);
2443 result.get_impl()->apply_1d_realspace_push(op, ff.get_impl().get(), axis, fence);
2444 result.get_impl()->set_tree_state(redundant_after_merge);
2445 return result;
2446 }
2447
2448
2449 /// Generate a new function by reordering dimensions ... optional fence
2450
2451 /// You provide an array of dimension NDIM that maps old to new dimensions
2452 /// according to
2453 /// \code
2454 /// newdim = mapdim[olddim]
2455 /// \endcode
2456 /// Works in either scaling function or wavelet basis.
2457 ///
2458 /// Would be easy to modify this to also change the procmap here
2459 /// if desired but presently it uses the same procmap as f.
2460 template <typename T, std::size_t NDIM>
2462 mapdim(const Function<T,NDIM>& f, const std::vector<long>& map, bool fence=true) {
2464 Function<T,NDIM> result;
2465 return result.mapdim(f,map,fence);
2466 }
2467
2468 /// Generate a new function by mirroring within the dimensions .. optional fence
2469
2470 /// similar to mapdim
2471 /// @param[in] mirror array with -1 and 1, corresponding to mirror this dimension or not
2472 template <typename T, std::size_t NDIM>
2474 mirror(const Function<T,NDIM>& f, const std::vector<long>& mirrormap, bool fence=true) {
2476 Function<T,NDIM> result;
2477 return result.mirror(f,mirrormap,fence);
2478 }
2479
2480 /// This is replaced with mirror(map(f)), optional fence
2481
2482 /// first map then mirror!
2483 /// mirror is similar to mapdim, but maps from x to -x, y to -y, and so on
2484 /// Example: mirror a 3d function on the xy plane: mirror={1,1,-1}
2485 /// Example: c4 rotation of a 3d function around the z axis:
2486 /// x->y, y->-x, z->z: map(1,0,2); mirror(-1,1,1)
2487 /// @param[in] map array holding dimensions
2488 /// @param[in] mirror array of -1 and 1, corresponding to mirror or not
2489 template <typename T, std::size_t NDIM>
2491 map_and_mirror(const Function<T,NDIM>& f, const std::vector<long>& map,
2492 const std::vector<long>& mirror, bool fence=true) {
2494 Function<T,NDIM> result;
2495 return result.map_and_mirror(f,map,mirror,fence);
2496 }
2497
2498
2499 /// swap particles 1 and 2
2500
2501 /// param[in] f a function of 2 particles f(1,2)
2502 /// return the input function with particles swapped g(1,2) = f(2,1)
2503 template <typename T, std::size_t NDIM>
2504 typename std::enable_if_t<NDIM%2==0, Function<T,NDIM>>
2506 // this could be done more efficiently for SVD, but it works decently
2507 std::vector<long> map(NDIM);
2508 constexpr std::size_t LDIM=NDIM/2;
2509 static_assert(LDIM*2==NDIM);
2510 for (std::size_t d=0; d<LDIM; ++d) {
2511 map[d]=d+LDIM;
2512 map[d+LDIM]=d;
2513 }
2514// map[0]=3;
2515// map[1]=4;
2516// map[2]=5; // 2 -> 1
2517// map[3]=0;
2518// map[4]=1;
2519// map[5]=2; // 1 -> 2
2520 return mapdim(f,map);
2521 }
2522
2523 /// symmetrize a function
2524
2525 /// @param[in] symmetry possibilities are:
2526 /// (anti-) symmetric particle permutation ("sy_particle", "antisy_particle")
2527 /// symmetric mirror plane ("xy", "xz", "yz")
2528 /// @return a new function symmetrized according to the input parameter
2529 template <typename T, std::size_t NDIM>
2531 symmetrize(const Function<T,NDIM>& f, const std::string symmetry, bool fence=true) {
2532 Function<T,NDIM> result;
2533
2534 MADNESS_ASSERT(NDIM==6); // works only for pair functions
2535 std::vector<long> map(NDIM);
2536
2537 // symmetric particle permutation
2538 if (symmetry=="sy_particle") {
2539 map[0]=3; map[1]=4; map[2]=5;
2540 map[3]=0; map[4]=1; map[5]=2;
2541 } else if (symmetry=="cx") {
2542 map[0]=0; map[1]=2; map[2]=1;
2543 map[3]=3; map[4]=5; map[5]=4;
2544
2545 } else if (symmetry=="cy") {
2546 map[0]=2; map[1]=1; map[2]=0;
2547 map[3]=5; map[4]=4; map[5]=3;
2548
2549 } else if (symmetry=="cz") {
2550 map[0]=1; map[1]=0; map[2]=2;
2551 map[3]=4; map[4]=3; map[5]=5;
2552
2553 } else {
2554 if (f.world().rank()==0) {
2555 print("unknown parameter in symmetrize:",symmetry);
2556 }
2557 MADNESS_EXCEPTION("unknown parameter in symmetrize",1);
2558 }
2559
2560 result.mapdim(f,map,true); // need to fence here
2561 result.get_impl()->average(*f.get_impl());
2562
2563 return result;
2564 }
2565
2566
2567
2568 /// multiply a high-dimensional function with a low-dimensional function
2569
2570 /// @param[in] f NDIM function of 2 particles: f=f(1,2)
2571 /// @param[in] g LDIM function of 1 particle: g=g(1) or g=g(2)
2572 /// @param[in] particle if g=g(1) or g=g(2)
2573 /// @return h(1,2) = f(1,2) * g(p)
2574 template<typename T, std::size_t NDIM, std::size_t LDIM>
2575 Function<T,NDIM> multiply(const Function<T,NDIM> f, const Function<T,LDIM> g, const int particle, const bool fence=true) {
2576
2577 static_assert(LDIM+LDIM==NDIM);
2579
2580 Function<T,NDIM> result;
2581 result.set_impl(f, false);
2582
2583// Function<T,NDIM>& ff = const_cast< Function<T,NDIM>& >(f);
2584// Function<T,LDIM>& gg = const_cast< Function<T,LDIM>& >(g);
2585
2586 f.change_tree_state(redundant,false);
2587 g.change_tree_state(redundant,false);
2588 // neither call is fenced, and either may be a no-op if the function already is
2589 // redundant -- fence explicitly before the trees are traversed
2590 result.world().gop.fence();
2591 FunctionImpl<T,NDIM>* fimpl=f.get_impl().get();
2592 FunctionImpl<T,LDIM>* gimpl=g.get_impl().get();
2593
2594 result.get_impl()->multiply(fimpl,gimpl,particle);
2595 result.world().gop.fence();
2596
2597 f.change_tree_state(reconstructed,false);
2598 g.change_tree_state(reconstructed);
2599 return result;
2600 }
2601
2602
2603 template <typename T, std::size_t NDIM>
2608 bool fence=true)
2609 {
2611 Function<T,NDIM> result = FunctionFactory<T,NDIM>(other.world()).k(k).thresh(thresh).empty();
2612 other.reconstruct();
2613 result.get_impl()->project(*other.get_impl(),fence);
2614 return result;
2615 }
2616
2617
2618 /// Computes the scalar/inner product between two functions
2619
2620 /// In Maple this would be \c int(conjugate(f(x))*g(x),x=-infinity..infinity)
2621 template <typename T, typename R, std::size_t NDIM>
2624 return f.inner(g);
2625 }
2626
2627
2628 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2629
2630 /// syntax similar to the inner product in tensor.h
2631 /// e.g result=inner<3>(f,g),{0},{1}) : r(x,y) = int f(x1,x) g(y,x1) dx1
2632 /// @param[in] task 0: everything, 1; prepare only (fence), 2: work only (no fence), 3: finalize only (fence)
2633 template<std::size_t NDIM, typename T, std::size_t LDIM, typename R, std::size_t KDIM,
2634 std::size_t CDIM = (KDIM + LDIM - NDIM) / 2>
2635 std::vector<Function<TENSOR_RESULT_TYPE(T, R), NDIM>>
2636 innerXX(const Function<T, LDIM>& f, const std::vector<Function<R, KDIM>>& vg, const std::array<int, CDIM> v1,
2637 const std::array<int, CDIM> v2, int task=0) {
2638 bool prepare = ((task==0) or (task==1));
2639 bool work = ((task==0) or (task==2));
2640 bool finish = ((task==0) or (task==3));
2641
2642 static_assert((KDIM + LDIM - NDIM) % 2 == 0, "faulty dimensions in inner (partial version)");
2643 static_assert(KDIM + LDIM - 2 * CDIM == NDIM, "faulty dimensions in inner (partial version)");
2644
2645 // contraction indices must be contiguous and either in the beginning or at the end
2646 for (size_t i=0; i<CDIM-1; ++i) MADNESS_CHECK((v1[i]+1)==v1[i+1]);
2647 MADNESS_CHECK((v1[0]==0) or (v1[CDIM-1]==LDIM-1));
2648
2649 for (size_t i=0; i<CDIM-1; ++i) MADNESS_CHECK((v2[i]+1)==v2[i+1]);
2650 MADNESS_CHECK((v2[0]==0) or (v2[CDIM-1]==KDIM-1));
2651
2652 MADNESS_CHECK(f.is_initialized());
2654 MADNESS_CHECK(f.world().id() == vg[0].world().id());
2655 // this needs to be run in a single world, so that all coefficients are local.
2656 // Use macrotasks if run on multiple processes.
2657 World& world=f.world();
2658 MADNESS_CHECK(world.size() == 1);
2659
2660 if (prepare) {
2661 f.change_tree_state(nonstandard);
2663 world.gop.fence();
2664 f.get_impl()->compute_snorm_and_dnorm(false);
2665 for (auto& g : vg) g.get_impl()->compute_snorm_and_dnorm(false);
2666 world.gop.fence();
2667 }
2668
2669 typedef TENSOR_RESULT_TYPE(T, R) resultT;
2670 std::vector<Function<resultT,NDIM>> result(vg.size());
2671 if (work) {
2673 for (size_t i=0; i<vg.size(); ++i) {
2675 .k(f.k()).thresh(f.thresh()).empty().nofence();
2676 result[i].get_impl()->partial_inner(*f.get_impl(),*(vg[i]).get_impl(),v1,v2);
2677 result[i].get_impl()->set_tree_state(nonstandard_after_apply);
2678 }
2679 world.gop.set_forbid_fence(false);
2680 }
2681
2682 if (finish) {
2683
2684 world.gop.fence();
2685// result.get_impl()->reconstruct(true);
2686
2688// result.reconstruct();
2689 // restore initial state of g and h
2690 auto erase_list = [] (const auto& funcimpl) {
2691 typedef typename std::decay_t<decltype(funcimpl)>::keyT keyTT;
2692 std::list<keyTT> to_be_erased;
2693 for (auto it=funcimpl.get_coeffs().begin(); it!=funcimpl.get_coeffs().end(); ++it) {
2694 const auto& key=it->first;
2695 const auto& node=it->second;
2696 if (not node.has_children()) to_be_erased.push_back(key);
2697 }
2698 return to_be_erased;
2699 };
2700
2701 FunctionImpl<T,LDIM>& f_nc=const_cast<FunctionImpl<T,LDIM>&>(*f.get_impl());
2702 for (auto& key : erase_list(f_nc)) f_nc.get_coeffs().erase(key);
2703 for (auto& g : vg) {
2704 FunctionImpl<R,KDIM>& g_nc=const_cast<FunctionImpl<R,KDIM>&>(*g.get_impl());
2705 for (auto& key : erase_list(g_nc)) g_nc.get_coeffs().erase(key);
2706 }
2707 world.gop.fence();
2709 f_nc.reconstruct(false);
2710 world.gop.fence();
2711
2712 }
2713
2714 return result;
2715 }
2716
2717
2718 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2719
2720 /// syntax similar to the inner product in tensor.h
2721 /// e.g result=inner<3>(f,g),{0},{1}) : r(x,y) = int f(x1,x) g(y,x1) dx1
2722 /// @param[in] task 0: everything, 1; prepare only (fence), 2: work only (no fence), 3: finalize only (fence)
2723 template<std::size_t NDIM, typename T, std::size_t LDIM, typename R, std::size_t KDIM,
2724 std::size_t CDIM = (KDIM + LDIM - NDIM) / 2>
2726 innerXX(const Function<T, LDIM>& f, const Function<R, KDIM>& g, const std::array<int, CDIM> v1,
2727 const std::array<int, CDIM> v2, int task=0) {
2728 return innerXX<NDIM,T,LDIM,R,KDIM>(f,std::vector<Function<R,KDIM>>({g}),v1,v2,task)[0];
2729 }
2730
2731 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2732
2733 /// syntax similar to the inner product in tensor.h
2734 /// e.g result=inner<3>(f,g),{0},{1}) : r(x,y) = int f(x1,x) g(y,x1) dx1
2735 template <typename T, std::size_t LDIM, typename R, std::size_t KDIM>
2737 inner(const Function<T,LDIM>& f, const Function<R,KDIM>& g, const std::tuple<int> v1, const std::tuple<int> v2) {
2738 return innerXX<KDIM+LDIM-2>(f,g,
2739 std::array<int,1>({std::get<0>(v1)}),
2740 std::array<int,1>({std::get<0>(v2)}));
2741 }
2742
2743 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2744
2745 /// syntax similar to the inner product in tensor.h
2746 /// e.g result=inner<3>(f,g),{0,1},{1,2}) : r(y) = int f(x1,x2) g(y,x1,x2) dx1 dx2
2747 template <typename T, std::size_t LDIM, typename R, std::size_t KDIM>
2749 inner(const Function<T,LDIM>& f, const Function<R,KDIM>& g, const std::tuple<int,int> v1, const std::tuple<int,int> v2) {
2750 return innerXX<KDIM+LDIM-4>(f,g,
2751 std::array<int,2>({std::get<0>(v1),std::get<1>(v1)}),
2752 std::array<int,2>({std::get<0>(v2),std::get<1>(v2)}));
2753 }
2754
2755 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2756
2757 /// syntax similar to the inner product in tensor.h
2758 /// e.g result=inner<3>(f,g),{1},{2}) : r(x,y,z) = int f(x,x1) g(y,z,x1) dx1
2759 template <typename T, std::size_t LDIM, typename R, std::size_t KDIM>
2761 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) {
2762 return innerXX<KDIM+LDIM-6>(f,g,
2763 std::array<int,3>({std::get<0>(v1),std::get<1>(v1),std::get<2>(v1)}),
2764 std::array<int,3>({std::get<0>(v2),std::get<1>(v2),std::get<2>(v2)}));
2765 }
2766
2767
2768
2769 /// Computes the scalar/inner product between an MRA function and an external functor
2770
2771 /// Currently this defaults to inner_adaptive, which might be more expensive
2772 /// than inner_ext since it loops over all leaf nodes. If you feel inner_ext
2773 /// is more efficient you need to call it directly
2774 /// @param[in] f MRA function
2775 /// @param[in] g functor
2776 /// @result inner(f,g)
2777 template <typename T, typename opT, std::size_t NDIM>
2778 TENSOR_RESULT_TYPE(T,typename opT::value_type) inner(const Function<T,NDIM>& f, const opT& g) {
2780 std::shared_ptr< FunctionFunctorInterface<double,3> > func(new opT(g));
2781 return f.inner_adaptive(func);
2782 }
2783
2784 /// Computes the scalar/inner product between an MRA function and an external functor
2785
2786 /// Currently this defaults to inner_adaptive, which might be more expensive
2787 /// than inner_ext since it loops over all leaf nodes. If you feel inner_ext
2788 /// is more efficient you need to call it directly
2789 /// @param[in] g functor
2790 /// @param[in] f MRA function
2791 /// @result inner(f,g)
2792 template <typename T, typename opT, std::size_t NDIM>
2793 TENSOR_RESULT_TYPE(T,typename opT::value_type) inner(const opT& g, const Function<T,NDIM>& f) {
2794 return inner(f,g);
2795 }
2796
2797 template <typename T, typename R, std::size_t NDIM>
2800 return (f*R(1.0)).add_scalar(r);
2801 }
2802
2803 template <typename T, typename R, std::size_t NDIM>
2806 return (f*R(1.0)).add_scalar(r);
2807 }
2808
2809 template <typename T, typename R, std::size_t NDIM>
2812 return (f*R(1.0)).add_scalar(-r);
2813 }
2814
2815 template <typename T, typename R, std::size_t NDIM>
2818 return (f*R(-1.0)).add_scalar(r);
2819 }
2820
2821 namespace detail {
2822 template <std::size_t NDIM>
2823 struct realop {
2824 typedef double resultT;
2826 return real(t);
2827 }
2828
2829 template <typename Archive> void serialize (Archive& ar) {}
2830 };
2831
2832 template <std::size_t NDIM>
2833 struct imagop {
2834 typedef double resultT;
2836 return imag(t);
2837 }
2838
2839 template <typename Archive> void serialize (Archive& ar) {}
2840 };
2841
2842 template <std::size_t NDIM>
2843 struct abssqop {
2844 typedef double resultT;
2846 Tensor<double> r = abs(t);
2847 return r.emul(r);
2848 }
2849
2850 template <typename Archive> void serialize (Archive& ar) {}
2851 };
2852
2853 template <std::size_t NDIM>
2854 struct absop {
2855 typedef double resultT;
2857 Tensor<double> r = abs(t);
2858 return r;
2859 }
2860
2861 template <typename Archive> void serialize (Archive& ar) {}
2862 };
2863
2864 }
2865
2866 /// Returns a new function that is the real part of the input
2867 template <std::size_t NDIM>
2871
2872 /// Returns a new function that is the real part of the input
2873 template <std::size_t NDIM>
2875 return copy(z);
2876 }
2877
2878 /// Returns a new function that is the imaginary part of the input
2879 template <std::size_t NDIM>
2883
2884
2885 /// Create a new function that is the square of f - global comm only if not reconstructed
2886 template <typename T, std::size_t NDIM>
2889 Function<T,NDIM> result = copy(f,true); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2890 return result.square(true); //fence); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2891 }
2892
2893 /// Create a new function that is the abs of f - global comm only if not reconstructed
2894 template <typename T, std::size_t NDIM>
2895 Function<T,NDIM> abs(const Function<T,NDIM>& f, bool fence=true) {
2897 Function<T,NDIM> result = copy(f,true); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2898 return result.abs(true); //fence); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2899 }
2900
2901 /// Create a new function that is the abs_square of f - global comm only if not reconstructed
2902 template <typename T, std::size_t NDIM>
2903 typename std::enable_if<!TensorTypeData<T>::iscomplex, Function<T,NDIM> >::type
2904 abs_square(const Function<T,NDIM>& f, bool fence=true) {
2906 Function<T,NDIM> result = copy(f,true); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2907 return result.abs_square(true); //fence); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2908 }
2909
2910 /// Create a new function that is the abs_square of f - global comm only if not reconstructed
2911 template <typename T, std::size_t NDIM>
2912 typename std::enable_if<TensorTypeData<T>::iscomplex, Function<typename Tensor<T>::scalar_type,NDIM> >::type
2913 abs_square(const Function<T,NDIM>& f, bool fence=true) {
2915 }
2916
2917 /// Returns a new function that is the square of the absolute value of the input
2918 template <std::size_t NDIM>
2922
2923 /// Returns a new function that is the absolute value of the input
2924 template <std::size_t NDIM>
2928
2929 /// get tree state of a function
2930
2931 /// there is a corresponding function in vmra.h
2932 /// @param[in] f function
2933 /// @return TreeState::unknown if the function is not initialized
2934 template <typename T, std::size_t NDIM>
2936 if (f.is_initialized()) return f.get_impl()->get_tree_state();
2937 return TreeState::unknown;
2938 }
2939
2940 /// change tree state of a function
2941
2942 /// there is a corresponding function in vmra.h
2943 /// return this for chaining
2944 /// @param[in] f function
2945 /// @param[in] finalstate the new state
2946 /// @return this in the requested state
2947 template <typename T, std::size_t NDIM>
2952
2953 template <typename R, std::size_t MDIM>
2955 f1.impl.swap(f2.impl);
2956 }
2957
2958}
2959
2960#include <madness/mra/funcplot.h>
2961
2962namespace madness {
2963 namespace archive {
2964 template <class archiveT, class T, std::size_t NDIM>
2966 static inline void load(const ParallelInputArchive<archiveT>& ar, Function<T,NDIM>& f) {
2967 f.load(*ar.get_world(), ar);
2968 }
2969 };
2970
2971 template <class archiveT, class T, std::size_t NDIM>
2973 static inline void store(const ParallelOutputArchive<archiveT>& ar, const Function<T,NDIM>& f) {
2974 f.store(ar);
2975 }
2976 };
2977 }
2978
2979 template <class T, std::size_t NDIM>
2980 void save(const Function<T,NDIM>& f, const std::string name) {
2982 ar2 & f;
2983 }
2984
2985 template <class T, std::size_t NDIM>
2986 void load(Function<T,NDIM>& f, const std::string name) {
2988 ar2 & f;
2989 }
2990
2991}
2992
2993namespace madness {
2994 // type traits to check if a template parameter is a Function
2995 template<typename>
2996 struct is_madness_function : std::false_type {};
2997
2998 template<typename T, std::size_t NDIM>
2999 struct is_madness_function<madness::Function<T, NDIM>> : std::true_type {};
3000
3001}
3002
3003
3004/* @} */
3005
3006#include <madness/mra/derivative.h>
3007#include <madness/mra/operator.h>
3009#include <madness/mra/vmra.h>
3010// #include <madness/mra/mraimpl.h> !!!!!!!!!!!!! NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO !!!!!!!!!!!!!!!!!!
3011
3012#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:399
static void set_cell(const Tensor< double > &value)
Sets the user cell for the simulation.
Definition funcdefaults.h:364
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:968
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:136
A multiresolution adaptive numerical function.
Definition mra.h:144
void print_tree_json(std::ostream &os=std::cout) const
Definition mra.h:1005
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:415
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:1825
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:1521
T inner_adaptive(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > f, const bool leaf_refine=true) const
Definition mra.h:1506
void unaryop_coeff(const opT &op, bool fence=true)
Unary operation applied inplace to the coefficients.
Definition mra.h:1055
bool is_compressed() const
Returns true if compressed, false otherwise. No communication.
Definition mra.h:547
Function< T, NDIM/2 > dirac_convolution(const bool fence=true) const
Definition mra.h:1585
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:752
bool autorefine() const
Returns value of autorefine flag. No communication.
Definition mra.h:658
TreeState operating_state
Definition mra.h:1447
Function< T, NDIM > & add_scalar(T t, bool fence=true)
Inplace add scalar. No communication except for optional fence.
Definition mra.h:1104
void print_size(const std::string name) const
print some info about this
Definition mra.h:598
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:1291
void broaden(const BoundaryConditions< NDIM > &bc=FunctionDefaults< NDIM >::get_bc(), bool fence=true) const
Inplace broadens support in scaling function basis.
Definition mra.h:977
void print_info() const
Print a summary of the load balancing info.
Definition mra.h:1021
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:1094
void norm_tree(bool fence=true) const
Initializes information about the function norm at all length scales.
Definition mra.h:838
void load(World &world, Archive &ar)
Replaces this function with one loaded from an archive using the default processor map.
Definition mra.h:1602
Function< T, NDIM > & abs_square(bool fence=true)
Returns *this for chaining.
Definition mra.h:1231
void replicate(const DistributionType type, bool fence=true) const
Definition mra.h:776
double norm2sq_local() const
Returns the square of the norm of the local function ... no communication.
Definition mra.h:813
IsSupported< TensorTypeData< Q >, Function< T, NDIM > >::type & operator*=(const Q q)
Inplace scaling by a constant.
Definition mra.h:1203
void sum_down(bool fence=true) const
Sums scaling coeffs down tree restoring state with coeffs only at leaves. Optional fence....
Definition mra.h:939
Level depthpt(const coordT &xuser) const
Definition mra.h:491
bool is_redundant() const
Returns true if redundant, false otherwise. No communication.
Definition mra.h:577
Function< T, NDIM > & operator+=(const Function< Q, NDIM > &other)
Inplace addition of functions in the wavelet basis.
Definition mra.h:1163
Function< T, NDIM > & operator=(const Function< T, NDIM > &f)
Assignment is shallow. No communication, works in either basis.
Definition mra.h:196
void set_autorefine(bool value, bool fence=true)
Sets the value of the autorefine flag. Optional global fence.
Definition mra.h:668
World & world() const
Returns the world.
Definition mra.h:758
T trace() const
Returns global value of int(f(x),x) ... global comm required.
Definition mra.h:1253
T typeT
Definition mra.h:162
friend void swap(Function< R, MDIM > &f1, Function< R, MDIM > &f2)
implements swap algorithm
Definition mra.h:2954
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:1309
const Function< T, NDIM > & change_tree_state(const TreeState finalstate, bool fence=true) const
changes tree state to given state
Definition mra.h:926
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:1660
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:1011
double norm2() const
Returns the 2-norm of the function ... global sum ... works in either basis.
Definition mra.h:825
Function< T, NDIM > & fill_cuspy_tree(const opT &op, const bool fence=true)
Definition mra.h:1332
void change_tensor_type(const TensorArgs &targs, bool fence=true)
change the tensor type of the coefficients in the FunctionNode
Definition mra.h:1652
const Function< T, NDIM > & refine(bool fence=true) const
Inplace autorefines the function using same test as for squaring.
Definition mra.h:971
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:456
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:1213
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:1320
void verify_tree() const
Verifies the tree data structure ... global sync implied.
Definition mra.h:538
Future< Level > evaldepthpt(const coordT &xuser) const
Definition mra.h:337
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:1401
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:1791
impl world gop fence()
int k() const
Returns the number of multiwavelets (k). No communication.
Definition mra.h:696
const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > & get_pmap() const
Returns a shared pointer to the process map.
Definition mra.h:766
double thresh() const
Returns value of truncation threshold. No communication.
Definition mra.h:677
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:1777
void set_thresh(double value, bool fence=true)
Sets the value of the truncation threshold. Optional global fence.
Definition mra.h:687
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:1682
void distribute(std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > newmap) const
distribute this function according to newmap
Definition mra.h:804
void unaryop(const opT &op, bool fence=true)
Inplace unary operation on function values.
Definition mra.h:1045
const std::shared_ptr< FunctionImpl< T, NDIM > > & get_impl() const
Returns a shared-pointer to the implementation.
Definition mra.h:724
void standard(bool fence=true)
Converts the function standard compressed form. Possible non-blocking comm.
Definition mra.h:885
void unaryop_node(const opT &op, bool fence=true)
Unary operation applied inplace to the nodes.
Definition mra.h:1065
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:712
Function< T, NDIM > & fill_cuspy_tree(const bool fence=true)
Special refinement on 6D boxes where the electrons come close (meet)
Definition mra.h:1345
std::size_t size() const
Returns the number of coefficients in the function ... collective global sum.
Definition mra.h:643
bool is_on_demand() const
Definition mra.h:746
Function< T, NDIM > & operator-=(const Function< Q, NDIM > &other)
Inplace subtraction of functions in the wavelet basis.
Definition mra.h:1182
bool compressed
Definition mra.h:1267
const Function< T, NDIM > & reconstruct(bool fence=true) const
Reconstructs the function, transforming into scaling function basis. Possible non-blocking comm.
Definition mra.h:916
Function< T, NDIM > & abs(bool fence=true)
Returns *this for chaining.
Definition mra.h:1222
Function< T, NDIM > & reduce_rank(const double thresh=0.0, const bool fence=true)
reduce the rank of the coefficient tensors
Definition mra.h:1855
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:1806
std::size_t max_nodes() const
Returns the max number of nodes on a processor.
Definition mra.h:628
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:1387
std::shared_ptr< FunctionImpl< T, NDIM > > impl
Definition mra.h:151
void replicate_on_hosts(bool fence=true) const
replicate this function, one copy per host
Definition mra.h:797
void replicate(bool fence=true) const
replicate this function, generating a unique pmap
Definition mra.h:787
T trace_local() const
Returns local contribution to int(f(x),x) ... no communication.
Definition mra.h:1244
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:1748
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:1124
Vector< double, NDIM > coordT
Type of vector holding coordinates.
Definition mra.h:161
void store(Archive &ar) const
Stores the function to an archive.
Definition mra.h:1640
std::size_t max_local_depth() const
Returns the maximum local depth of the function tree ... no communications.
Definition mra.h:620
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:1766
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:607
Function()
Default constructor makes uninitialized function. No communication.
Definition mra.h:179
std::vector< std::pair< bool, T > > eval_local_only(const std::vector< coordT > &xuser, Level maxlevel) const
Definition mra.h:325
std::size_t tree_size() const
Returns the number of nodes in the function tree ... collective global sum.
Definition mra.h:591
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:1561
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:1673
FunctionImpl< T, NDIM > implT
Definition mra.h:158
void clear(bool fence=true)
Clears the function as if constructed uninitialized. Optional fence.
Definition mra.h:988
void refine_general(const opT &op, bool fence=true) const
Inplace autorefines the function. Optional fence. Possible non-blocking comm.
Definition mra.h:952
static void doconj(const Key< NDIM >, Tensor< T > &t)
Definition mra.h:1075
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:250
void set_functor(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > functor)
Replace the current functor with the provided new one.
Definition mra.h:741
bool impl_initialized() const
Definition mra.h:154
Function< T, NDIM > & fill_nuclear_cuspy_tree(const opT &op, const size_t particle, const bool fence=true)
Definition mra.h:1360
bool is_redundant_after_merge() const
Returns true if redundant_after_merge, false otherwise. No communication.
Definition mra.h:585
return local
Definition mra.h:1462
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:290
auto func
Definition mra.h:1540
~Function()
Destruction of any underlying implementation is deferred to next global fence.
Definition mra.h:203
Function(const Function< T, NDIM > &f)
Copy constructor is shallow. No communication, works in either basis.
Definition mra.h:190
void set_impl(const std::shared_ptr< FunctionImpl< T, NDIM > > &impl)
Replace current FunctionImpl with provided new one.
Definition mra.h:731
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:470
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:1473
std::size_t min_nodes() const
Returns the min number of nodes on a processor.
Definition mra.h:635
void make_redundant(bool fence=true) const
Converts the function to redundant form, i.e. sum coefficients on all levels.
Definition mra.h:901
constexpr std::size_t LDIM
Definition mra.h:1539
static constexpr std::size_t dimT
Definition mra.h:163
change_tree_state(operating_state, false)
bool is_nonstandard() const
Returns true if nonstandard-compressed, false otherwise. No communication.
Definition mra.h:569
void verify() const
Asserts that the function is initialized.
Definition mra.h:167
double err(const funcT &func) const
Returns an estimate of the difference ||this-func|| ... global sum performed.
Definition mra.h:525
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:1489
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:1373
double check_symmetry() const
check symmetry of a function by computing the 2nd derivative
Definition mra.h:1841
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:1701
FunctionFactory< T, NDIM > factoryT
Definition mra.h:160
std::size_t size_local() const
Return the number of coefficients in the function on this processor.
Definition mra.h:650
const Function< T, NDIM > & compress(bool fence=true) const
Compresses the function, transforming into wavelet basis. Possible non-blocking comm.
Definition mra.h:858
bool is_initialized() const
Returns true if the function is initialized.
Definition mra.h:172
bool is_reconstructed() const
Returns true if reconstructed, false otherwise. No communication.
Definition mra.h:558
Function< T, NDIM > & chop_at_level(const int n, const bool fence=true)
remove all nodes with level higher than n
Definition mra.h:1863
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:1722
double errsq_local(const funcT &func) const
Returns an estimate of the difference ||this-func||^2 from local data.
Definition mra.h:510
void make_nonstandard(bool keepleaves, bool fence=true) const
Compresses the function retaining scaling function coeffs. Possible non-blocking comm.
Definition mra.h:871
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:216
void print_tree(std::ostream &os=std::cout) const
Process 0 prints a summary of all nodes in the tree (collective)
Definition mra.h:998
FunctionNode< T, NDIM > nodeT
Definition mra.h:159
bool redundant
Definition mra.h:1268
Future< long > evalR(const coordT &xuser) const
Evaluates the function rank at a point in user coordinates. Possible non-blocking comm.
Definition mra.h:374
Function(const factoryT &factory)
Constructor from FunctionFactory provides named parameter idiom. Possible non-blocking communication.
Definition mra.h:183
NDIM &g const
Definition mra.h:1265
void unaryop(T(*f)(T))
Inplace unary operation on function values.
Definition mra.h:1036
Function< T, NDIM > conj(bool fence=true)
Inplace complex conjugate. No communication except for optional fence.
Definition mra.h:1083
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:134
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition world.h:344
ProcessID size() const
Returns the number of processes in this World (same as MPI_Comm_size()).
Definition world.h:354
WorldGopInterface & gop
Global operations.
Definition world.h:216
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.
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:2919
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:2434
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:2156
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:1951
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:2234
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:1884
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:2505
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:453
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:2636
static constexpr long FUNCTION_ARCHIVE_MAGIC
Definition mra.h:140
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:2935
std::vector< CCPairFunction< T, NDIM > > operator-(const std::vector< CCPairFunction< T, NDIM > > c1, const std::vector< CCPairFunction< T, NDIM > > &c2)
Definition ccpairfunction.h:1060
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:2119
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:227
@ TT_2D
Definition gentensor.h:120
@ TT_FULL
Definition gentensor.h:120
NDIM & f
Definition mra.h:2622
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:2111
Function< T, NDIM > symmetrize(const Function< T, NDIM > &f, const std::string symmetry, bool fence=true)
symmetrize a function
Definition mra.h:2531
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:2322
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:1965
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
CCPairFunction< T, NDIM > apply(const SeparatedConvolution< T, NDIM/2 > &op, const CCPairFunction< T, NDIM > &arg)
apply the operator to the argument
Definition ccpairfunction.h:896
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< TENSOR_RESULT_TYPE(L, R), NDIM > mul_sparse(const Function< L, NDIM > &left, const Function< R, NDIM > &right, double tol, bool fence=true, bool do_make_redundant=true)
Sparse multiplication; the scalar interface redirects to the vector one in vmra.h.
Definition mra.h:1929
Function< T, CCPairFunction< T, NDIM >::LDIM > inner(const CCPairFunction< T, NDIM > &c, const Function< T, CCPairFunction< T, NDIM >::LDIM > &f, const std::tuple< int, int, int > v1, const std::tuple< int, int, int > v2)
Definition ccpairfunction.h:993
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:2575
void load(Function< T, NDIM > &f, const std::string name)
Definition mra.h:2986
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:2605
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:2980
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:2016
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:2187
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:1032
T(* f)(T)
Definition mra.h:1027
void operator()(const Key< NDIM > &key, Tensor< T > &t) const
Definition mra.h:1029
SimpleUnaryOpWrapper(T(*f)(T))
Definition mra.h:1028
void serialize(Archive &ar)
Definition mra.h:965
bool operator()(implT *impl, const Key< NDIM > &key, const nodeT &t) const
Definition mra.h:961
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:2966
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:2973
Default store of an object via serialize(ar, t).
Definition archive.h:612
Definition mra.h:2854
Tensor< double > operator()(const Key< NDIM > &key, const Tensor< double_complex > &t) const
Definition mra.h:2856
double resultT
Definition mra.h:2855
void serialize(Archive &ar)
Definition mra.h:2861
Definition mra.h:2843
void serialize(Archive &ar)
Definition mra.h:2850
Tensor< double > operator()(const Key< NDIM > &key, const Tensor< double_complex > &t) const
Definition mra.h:2845
double resultT
Definition mra.h:2844
Definition mra.h:2833
Tensor< double > operator()(const Key< NDIM > &key, const Tensor< double_complex > &t) const
Definition mra.h:2835
void serialize(Archive &ar)
Definition mra.h:2839
double resultT
Definition mra.h:2834
Definition mra.h:2823
Tensor< double > operator()(const Key< NDIM > &key, const Tensor< double_complex > &t) const
Definition mra.h:2825
double resultT
Definition mra.h:2824
void serialize(Archive &ar)
Definition mra.h:2829
Definition mra.h:127
Definition funcimpl.h:633
returns true if the result of a hartree_product is a leaf node (compute norm & error)
Definition funcimpl.h:523
Definition mra.h:2996
Definition mra.h:112
Definition mra.h:115
Definition funcimpl.h:587
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