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 /// \note This generates the operator displacement lists (see Displacements) for free boundary conditions
66 /// in up to 6 dimensions and, if the default boundary conditions have periodic axes, for kernels
67 /// lattice-summed along those axes. Lists for any other set of lattice-summed axes are built when an
68 /// operator summed along them is first constructed.
69 /// \param world broadcast data across this World
70 /// \param argc command-line parameter count
71 /// \param argv command-line parameters array
72 /// \param doprint if true, will log status to std::cout on rank 0 [default=false]
73 /// \param make_stdcout_nice_to_reals if true, will configure std::cout to print reals prettily, according to the MADNESS convention [default=true]
74 void startup(World& world, int argc, char** argv, bool doprint=false, bool make_stdcout_nice_to_reals = true);
75 std::string get_mra_data_dir();
76}
77
78#include <madness/mra/key.h>
81#include <madness/mra/indexit.h>
86#include <madness/mra/lbdeux.h>
89
90// some forward declarations
91namespace madness {
92
93 template<typename T, std::size_t NDIM>
94 class FunctionImpl;
95
96 template<typename T, std::size_t NDIM>
97 class Function;
98
99 template<typename T, std::size_t NDIM>
100 class FunctionNode;
101
102 template<typename T, std::size_t NDIM>
103 class FunctionFactory;
104
105 template<typename T, std::size_t NDIM>
107
108 template<typename T, std::size_t NDIM>
109 struct leaf_op;
110
111 template<typename T, std::size_t NDIM>
113
114 template<typename T, std::size_t NDIM>
115 struct hartree_leaf_op;
116
117 template<typename T, std::size_t NDIM, std::size_t LDIM, typename opT>
119
120 template<typename T, std::size_t NDIM, typename opT>
121 struct op_leaf_op;
122
123 template<typename T, std::size_t NDIM>
125
126}
127
128
129namespace madness {
130
131 /// \ingroup mra
132 /// \addtogroup function
133
134 /// Header magic for Function::store/load; bump whenever FunctionNode::serialize changes.
135 /// 7776769 original (Mellow Mushroom Pizza tel.# in Knoxville, +1 for cell in header)
136 /// 7776770 FunctionNode gained _dnorm_tree
137 static constexpr long FUNCTION_ARCHIVE_MAGIC = 7776770;
138
139 /// A multiresolution adaptive numerical function
140 template <typename T, std::size_t NDIM>
142 // We make all of the content of Function and FunctionImpl
143 // public with the intent of avoiding the cumbersome forward
144 // and friend declarations. However, this open access should
145 // not be abused.
146
147 private:
148 std::shared_ptr< FunctionImpl<T,NDIM> > impl;
149
150 public:
151 bool impl_initialized()const{
152 if(impl==NULL) return false;
153 else return true;
154 }
158 typedef Vector<double,NDIM> coordT; ///< Type of vector holding coordinates
159 typedef T typeT;
160 static constexpr std::size_t dimT=NDIM;
161
162
163 /// Asserts that the function is initialized
164 inline void verify() const {
166 }
167
168 /// Returns true if the function is initialized
169 bool is_initialized() const {
170 return impl.get();
171 }
172
173 /// Default constructor makes uninitialized function. No communication.
174
175 /// An uninitialized function can only be assigned to. Any other operation will throw.
176 Function() : impl() {}
177
178
179 /// Constructor from FunctionFactory provides named parameter idiom. Possible non-blocking communication.
180 Function(const factoryT& factory)
181 : impl(new FunctionImpl<T,NDIM>(factory)) {
183 }
184
185
186 /// Copy constructor is \em shallow. No communication, works in either basis.
188 : impl(f.impl) {
189 }
190
191
192 /// Assignment is \em shallow. No communication, works in either basis.
195 if (this != &f) impl = f.impl;
196 return *this;
197 }
198
199 /// Destruction of any underlying implementation is deferred to next global fence.
201
202 /// implements swap algorithm
203 template <typename R, std::size_t MDIM>
205
206
207 /// Evaluates the function at a point in user coordinates. Possible non-blocking comm.
208
209 /// Only the invoking process will receive the result via the future
210 /// though other processes may be involved in the evaluation.
211 ///
212 /// Throws if function is not initialized.
213 Future<T> eval(const coordT& xuser) const {
215 const double eps=1e-15;
216 verify();
218 coordT xsim;
219 user_to_sim(xuser,xsim);
220 // If on the boundary, move the point just inside the
221 // volume so that the evaluation logic does not fail
222 for (std::size_t d=0; d<NDIM; ++d) {
223 if (xsim[d] < -eps) {
224 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
225 }
226 else if (xsim[d] < eps) {
227 xsim[d] = eps;
228 }
229
230 if (xsim[d] > 1.0+eps) {
231 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
232 }
233 else if (xsim[d] > 1.0-eps) {
234 xsim[d] = 1.0-eps;
235 }
236 }
237
238 Future<T> result;
239 impl->eval(xsim, impl->key0(), result.remote_ref(impl->world));
240 return result;
241 }
242
243 /// Evaluate function only if point is local returning (true,value); otherwise return (false,0.0)
244
245 /// maxlevel is the maximum depth to search down to --- the max local depth can be
246 /// computed with max_local_depth();
247 std::pair<bool,T> eval_local_only(const Vector<double,NDIM>& xuser, Level maxlevel) const {
248 const double eps=1e-15;
249 verify();
251 coordT xsim;
252 user_to_sim(xuser,xsim);
253 // If on the boundary, move the point just inside the
254 // volume so that the evaluation logic does not fail
255 for (std::size_t d=0; d<NDIM; ++d) {
256 if (xsim[d] < -eps) {
257 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
258 }
259 else if (xsim[d] < eps) {
260 xsim[d] = eps;
261 }
262
263 if (xsim[d] > 1.0+eps) {
264 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
265 }
266 else if (xsim[d] > 1.0-eps) {
267 xsim[d] = 1.0-eps;
268 }
269 }
270 return impl->eval_local_only(xsim,maxlevel);
271 }
272
273 /// Batched eval_local_only writing into a caller-provided buffer.
274
275 /// Resizes results to xuser.size() (reusing its capacity) and stores one
276 /// (local?,value) pair per input point, in input order: (true,value) if
277 /// the point is owned locally, otherwise (false,0.0).
278 /// Consecutive points that fall in the same leaf box share that box's
279 /// descent and coefficient fetch (last-box memoization), so spatially
280 /// coherent point streams (quadrature grids) amortise the per-point
281 /// tree descent. Results are bit-for-bit identical to calling the
282 /// single-point eval_local_only on each point. No communications, and
283 /// no per-call heap allocation once results has capacity.
284 ///
285 /// maxlevel is the maximum depth to search down to --- the max local depth can be
286 /// computed with max_local_depth();
287 void eval_local_only(const std::vector<coordT>& xuser, Level maxlevel,
288 std::vector<std::pair<bool,T>>& results) const {
289 const double eps=1e-15;
290 verify();
292 thread_local std::vector<coordT> xsim;
293 xsim.resize(xuser.size());
294 for (std::size_t ip=0; ip<xuser.size(); ++ip) {
295 coordT xs;
296 user_to_sim(xuser[ip],xs);
297 // If on the boundary, move the point just inside the volume so the
298 // evaluation logic does not fail (matches the single-point path).
299 for (std::size_t d=0; d<NDIM; ++d) {
300 if (xs[d] < -eps) {
301 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
302 }
303 else if (xs[d] < eps) {
304 xs[d] = eps;
305 }
306
307 if (xs[d] > 1.0+eps) {
308 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
309 }
310 else if (xs[d] > 1.0-eps) {
311 xs[d] = 1.0-eps;
312 }
313 }
314 xsim[ip] = xs;
315 }
316 results.resize(xuser.size());
317 impl->eval_local_only(xsim.data(), xsim.size(), maxlevel, results.data());
318 }
319
320 /// Batched eval_local_only returning a fresh vector (see the
321 /// output-parameter overload above for semantics).
322 std::vector<std::pair<bool,T>> eval_local_only(const std::vector<coordT>& xuser, Level maxlevel) const {
323 std::vector<std::pair<bool,T>> results;
324 eval_local_only(xuser, maxlevel, results);
325 return results;
326 }
327
328 /// Only the invoking process will receive the result via the future
329 /// though other processes may be involved in the evaluation.
330 ///
331 /// Throws if function is not initialized.
332 ///
333 /// This function is a minimally-modified version of eval()
334 Future<Level> evaldepthpt(const coordT& xuser) const {
336 const double eps=1e-15;
337 verify();
339 coordT xsim;
340 user_to_sim(xuser,xsim);
341 // If on the boundary, move the point just inside the
342 // volume so that the evaluation logic does not fail
343 for (std::size_t d=0; d<NDIM; ++d) {
344 if (xsim[d] < -eps) {
345 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
346 }
347 else if (xsim[d] < eps) {
348 xsim[d] = eps;
349 }
350
351 if (xsim[d] > 1.0+eps) {
352 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
353 }
354 else if (xsim[d] > 1.0-eps) {
355 xsim[d] = 1.0-eps;
356 }
357 }
358
359 Future<Level> result;
360 impl->evaldepthpt(xsim, impl->key0(), result.remote_ref(impl->world));
361 return result;
362 }
363
364
365 /// Evaluates the function rank at a point in user coordinates. Possible non-blocking comm.
366
367 /// Only the invoking process will receive the result via the future
368 /// though other processes may be involved in the evaluation.
369 ///
370 /// Throws if function is not initialized.
371 Future<long> evalR(const coordT& xuser) const {
373 const double eps=1e-15;
374 verify();
376 coordT xsim;
377 user_to_sim(xuser,xsim);
378 // If on the boundary, move the point just inside the
379 // volume so that the evaluation logic does not fail
380 for (std::size_t d=0; d<NDIM; ++d) {
381 if (xsim[d] < -eps) {
382 MADNESS_EXCEPTION("eval: coordinate lower-bound error in dimension", d);
383 }
384 else if (xsim[d] < eps) {
385 xsim[d] = eps;
386 }
387
388 if (xsim[d] > 1.0+eps) {
389 MADNESS_EXCEPTION("eval: coordinate upper-bound error in dimension", d);
390 }
391 else if (xsim[d] > 1.0-eps) {
392 xsim[d] = 1.0-eps;
393 }
394 }
395
396 Future<long> result;
397 impl->evalR(xsim, impl->key0(), result.remote_ref(impl->world));
398 return result;
399 }
400
401 /// Evaluates a cube/slice of points (probably for plotting) ... collective but no fence necessary
402
403 /// All processes receive the entire result (which is a rather severe limit
404 /// on the size of the cube that is possible).
405
406 /// Set eval_refine=true to return the refinment levels of
407 /// the given function.
408
409 /// @param[in] cell A Tensor describe the cube where the function to be evaluated in
410 /// @param[in] npt How many points to evaluate in each dimension
411 /// @param[in] eval_refine Wether to return the refinment levels of the given function
413 const std::vector<long>& npt,
414 bool eval_refine = false) const {
415 MADNESS_ASSERT(static_cast<std::size_t>(cell.dim(0))>=NDIM && cell.dim(1)==2 && npt.size()>=NDIM);
417 const double eps=1e-14;
418 verify();
419 reconstruct();
420 coordT simlo, simhi;
421 for (std::size_t d=0; d<NDIM; ++d) {
422 simlo[d] = cell(d,0);
423 simhi[d] = cell(d,1);
424 }
425 user_to_sim(simlo, simlo);
426 user_to_sim(simhi, simhi);
427
428 // Move the bounding box infintesimally inside dyadic
429 // points so that the evaluation logic does not fail
430 for (std::size_t d=0; d<NDIM; ++d) {
431 MADNESS_ASSERT(simhi[d] >= simlo[d]);
432 MADNESS_ASSERT(simlo[d] >= 0.0);
433 MADNESS_ASSERT(simhi[d] <= 1.0);
434
435 double delta = eps*(simhi[d]-simlo[d]);
436 simlo[d] += delta;
437 simhi[d] -= 2*delta; // deliberate asymmetry
438 }
439 return impl->eval_plot_cube(simlo, simhi, npt, eval_refine);
440 }
441
442
443 /// Evaluates the function at a point in user coordinates. Collective operation.
444
445 /// Throws if function is not initialized.
446 ///
447 /// This function calls eval, blocks until the result is
448 /// available and then broadcasts the result to everyone.
449 /// Therefore, if you are evaluating many points in parallel
450 /// it is \em vastly less efficient than calling eval
451 /// directly, saving the futures, and then forcing all of the
452 /// results.
453 T operator()(const coordT& xuser) const {
455 verify();
457 T result;
458 if (impl->world.rank() == 0) result = eval(xuser).get();
459 impl->world.gop.broadcast(result);
460 //impl->world.gop.fence();
461 return result;
462 }
463
464 /// Evaluates the function at a point in user coordinates. Collective operation.
465
466 /// See "operator()(const coordT& xuser)" for more info
467 T operator()(double x, double y=0, double z=0, double xx=0, double yy=0, double zz=0) const {
468 coordT r;
469 r[0] = x;
470 if (NDIM>=2) r[1] = y;
471 if (NDIM>=3) r[2] = z;
472 if (NDIM>=4) r[3] = xx;
473 if (NDIM>=5) r[4] = yy;
474 if (NDIM>=6) r[5] = zz;
475 return (*this)(r);
476 }
477
478 /// Throws if function is not initialized.
479 ///
480 /// This function mimics operator() by going through the
481 /// tree looking for the depth of the tree at the point.
482 /// It blocks until the result is
483 /// available and then broadcasts the result to everyone.
484 /// Therefore, if you are evaluating many points in parallel
485 /// it is \em vastly less efficient than calling evaldepthpt
486 /// directly, saving the futures, and then forcing all of the
487 /// results.
488 Level depthpt(const coordT& xuser) const {
490 verify();
492 Level result;
493 if (impl->world.rank() == 0) result = evaldepthpt(xuser).get();
494 impl->world.gop.broadcast(result);
495 //impl->world.gop.fence();
496 return result;
497 }
498
499 /// Returns an estimate of the difference ||this-func||^2 from local data
500
501 /// No communication is performed. If the function is not
502 /// reconstructed, it throws an exception. To get the global
503 /// value either do a global sum of the local values or call
504 /// errsq
505 /// @param[in] func Templated interface to the a user specified function
506 template <typename funcT>
507 double errsq_local(const funcT& func) const {
509 verify();
510 if (!is_reconstructed()) MADNESS_EXCEPTION("Function:errsq_local:not reconstructed",0);
511 return impl->errsq_local(func);
512 }
513
514
515 /// Returns an estimate of the difference ||this-func|| ... global sum performed
516
517 /// If the function is compressed, it is reconstructed first. For efficient use
518 /// especially with many functions, reconstruct them all first, and use errsq_local
519 /// instead so you can perform a global sum on all at the same time.
520 /// @param[in] func Templated interface to the a user specified function
521 template <typename funcT>
522 double err(const funcT& func) const {
524 verify();
528 double local = impl->errsq_local(func);
529 impl->world.gop.sum(local);
530 impl->world.gop.fence();
531 return sqrt(local);
532 }
533
534 /// Verifies the tree data structure ... global sync implied
535 void verify_tree() const {
537 if (impl) impl->verify_tree();
538 }
539
540
541 /// Returns true if compressed, false otherwise. No communication.
542
543 /// If the function is not initialized, returns false.
544 bool is_compressed() const {
546 if (impl)
547 return impl->is_compressed();
548 else
549 return false;
550 }
551
552 /// Returns true if reconstructed, false otherwise. No communication.
553
554 /// If the function is not initialized, returns false.
555 bool is_reconstructed() const {
557 if (impl)
558 return impl->is_reconstructed();
559 else
560 return false;
561 }
562
563 /// Returns true if nonstandard-compressed, false otherwise. No communication.
564
565 /// If the function is not initialized, returns false.
566 bool is_nonstandard() const {
568 return impl ? impl->is_nonstandard() : false;
569 }
570
571 /// Returns true if redundant, false otherwise. No communication.
572
573 /// If the function is not initialized, returns false.
574 bool is_redundant() const {
576 return impl ? impl->is_redundant() : false;
577 }
578
579 /// Returns true if redundant_after_merge, false otherwise. No communication.
580
581 /// If the function is not initialized, returns false.
584 return impl ? impl->is_redundant_after_merge() : false;
585 }
586
587 /// Returns the number of nodes in the function tree ... collective global sum
588 std::size_t tree_size() const {
590 if (!impl) return 0;
591 return impl->tree_size();
592 }
593
594 /// print some info about this
595 void print_size(const std::string name) const {
596 if (!impl) {
597 print("function",name,"not assigned yet");
598 } else {
599 impl->print_size(name);
600 }
601 }
602
603 /// Returns the maximum depth of the function tree ... collective global sum
604 std::size_t max_depth() const {
606 if (!impl) return 0;
607 return impl->max_depth();
608 }
609
610
611 /// Returns the maximum local depth of the function tree ... no communications
612
613 /// This is the value to pass as \c maxlevel to eval_local_only: it bounds the
614 /// descent to the deepest leaf actually held on this rank. Passing a larger
615 /// bound (e.g. Level::max()) only makes a missing/remote point descend through
616 /// empty levels doing owner() checks that never match -- pure overhead.
617 std::size_t max_local_depth() const {
619 if (!impl) return 0;
620 return impl->max_local_depth();
621 }
622
623
624 /// Returns the max number of nodes on a processor
625 std::size_t max_nodes() const {
627 if (!impl) return 0;
628 return impl->max_nodes();
629 }
630
631 /// Returns the min number of nodes on a processor
632 std::size_t min_nodes() const {
634 if (!impl) return 0;
635 return impl->min_nodes();
636 }
637
638
639 /// Returns the number of coefficients in the function ... collective global sum
640 std::size_t size() const {
642 if (!impl) return 0;
643 return impl->size();
644 }
645
646 /// Return the number of coefficients in the function on this processor
647 std::size_t size_local() const {
649 if (!impl) return 0;
650 return impl->size_local();
651 }
652
653
654 /// Returns value of autorefine flag. No communication.
655 bool autorefine() const {
657 if (!impl) return true;
658 return impl->get_autorefine();
659 }
660
661
662 /// Sets the value of the autorefine flag. Optional global fence.
663
664 /// A fence is required to ensure consistent global state.
665 void set_autorefine(bool value, bool fence = true) {
667 verify();
668 impl->set_autorefine(value);
669 if (fence) impl->world.gop.fence();
670 }
671
672
673 /// Returns value of truncation threshold. No communication.
674 double thresh() const {
676 if (!impl) return 0.0;
677 return impl->get_thresh();
678 }
679
680
681 /// Sets the value of the truncation threshold. Optional global fence.
682
683 /// A fence is required to ensure consistent global state.
684 void set_thresh(double value, bool fence = true) {
686 verify();
687 impl->set_thresh(value);
688 if (fence) impl->world.gop.fence();
689 }
690
691
692 /// Sets the truncate_mode (-2,-1,0,1,2,3,4) on this Function's impl. No fence is
693 /// issued — truncate_mode is a local per-impl integer with no global state.
696 verify();
697 impl->set_truncate_mode(value);
698 }
699
700
701 /// Returns the number of multiwavelets (k). No communication.
702 int k() const {
704 verify();
705 return impl->get_k();
706 }
707
708
709 /// Truncate the function with optional fence. Compresses with fence if not compressed.
710
711 /// If the truncation threshold is less than or equal to zero the default value
712 /// specified when the function was created is used.
713 /// If the function is not initialized, it just returns.
714 ///
715 /// Returns this for chaining.
716 /// @param[in] tol Tolerance for truncating the coefficients. Default 0.0 means use the implementation's member value \c thresh instead.
717 /// @param[in] fence Do fence
718 Function<T,NDIM>& truncate(double tol = 0.0, bool fence = true) {
720 if (!impl) return *this;
721 verify();
722// if (!is_compressed()) compress();
723 impl->truncate(tol,fence);
725 return *this;
726 }
727
728
729 /// Returns a shared-pointer to the implementation
730 const std::shared_ptr< FunctionImpl<T,NDIM> >& get_impl() const {
732 verify();
733 return impl;
734 }
735
736 /// Replace current FunctionImpl with provided new one
737 void set_impl(const std::shared_ptr< FunctionImpl<T,NDIM> >& impl) {
739 this->impl = impl;
740 }
741
742
743 /// Replace the current functor with the provided new one
744
745 /// presumably the new functor will be a CompositeFunctor, which will
746 /// change the behavior of the function: multiply the functor with the function
747 void set_functor(const std::shared_ptr<FunctionFunctorInterface<T, NDIM> > functor) {
748 this->impl->set_functor(functor);
749 print("set functor in mra.h");
750 }
751
752 bool is_on_demand() const {return this->impl->is_on_demand();}
753
754 /// Replace current FunctionImpl with a new one using the same parameters & map as f
755
756 /// If zero is true the function is initialized to zero, otherwise it is empty
757 template <typename R>
758 void set_impl(const Function<R,NDIM>& f, bool zero = true) {
759 impl = std::shared_ptr<implT>(new implT(*f.get_impl(), f.get_pmap(), zero));
760 if (zero) world().gop.fence();
761 }
762
763 /// Returns the world
764 World& world() const {
766 verify();
767 return impl->world;
768 }
769
770
771 /// Returns a shared pointer to the process map
772 const std::shared_ptr< WorldDCPmapInterface< Key<NDIM> > >& get_pmap() const {
774 verify();
775 return impl->get_pmap();
776 }
777
778 /// Replicates this function according to its distribution type.
779 ///
780 /// RankReplicated gives every rank every coefficient node. NodeReplicated
781 /// gives one copy per host, and the lowest rank on that host owns it. The
782 /// two methods below give the ownership rules and the limits of each policy.
783 /// NodeReplicated requires fence=true.
784 void replicate(const DistributionType type, bool fence=true) const {
785 verify();
787 else if (type==DistributionType::NodeReplicated) impl->replicate_on_hosts(fence);
788 else MADNESS_EXCEPTION("Function::replicate: unknown DistributionType",type);
789 }
790
791 /// Replicates this function on every rank.
792 ///
793 /// Every rank owns every coefficient node, so rank-local operations such as
794 /// eval_local_only work on every rank. Global reductions count the data more
795 /// than once. Queued tasks must not change the coefficients until the call
796 /// returns.
797 void replicate(bool fence=true) const {
798 verify();
799 impl->replicate(fence);
800 }
801
802 /// Replicates this function once per host.
803 ///
804 /// The lowest rank on each host owns all coefficient nodes. Other ranks route
805 /// ordinary container access, such as find, to that rank. eval_local_only does
806 /// no communication, so it returns false on those ranks. Global reductions
807 /// count one copy per host. If every rank needs local coefficient access,
808 /// replicate() is the correct policy. fence must be true.
809 void replicate_on_hosts(bool fence=true) const {
810 verify();
811 impl->replicate_on_hosts(fence);
812 }
813
814
815 /// distribute this function according to newmap
816 void distribute(std::shared_ptr< WorldDCPmapInterface< Key<NDIM> > > newmap) const {
817 verify();
818 impl->distribute(newmap);
819 }
820
821
822 /// Returns the square of the norm of the local function ... no communication
823
824 /// Works in any state that holds its coefficients once, cf.
825 /// FunctionImpl::has_summable_coefficients()
826 double norm2sq_local() const {
828 verify();
829 MADNESS_CHECK_THROW(impl->has_summable_coefficients(),
830 "norm2sq_local needs a tree that holds its coefficients once");
831 return impl->norm2sq_local();
832 }
833
834
835 /// Returns the 2-norm of the function ... global sum ... works in either basis
836
837 /// Works in any state whose coefficients norm2sq_local() can sum, which
838 /// includes the redundant and nonstandard-with-leaves trees left behind
839 /// by mul_sparse() and friends; the remaining states are reconstructed
840 /// first. See comments for err() w.r.t. applying to many functions.
841 ///
842 /// Throws if the function is on-demand: it carries no coefficients, so
843 /// its norm is not defined until it is materialized.
844 ///
845 /// N.B. that reconstruction is a mutation -- it discards the interior
846 /// coefficients -- so this (logically const) method fences before it
847 /// changes state: any task still reading those coefficients, e.g. a
848 /// mul_sparse() invoked with fence=false, must be done with them before
849 /// they are removed.
850 ///
851 /// The branch is taken on the tree state, which is replicated, so all
852 /// ranks take the same branch and the global ops stay collective.
853 double norm2() const {
855 verify();
857 if (!impl->has_summable_coefficients()) {
859 "norm2 is not defined for an on-demand function; materialize it first");
860 impl->world.gop.fence();
861 reconstruct();
862 }
863 double local = impl->norm2sq_local();
864
865 impl->world.gop.sum(local);
866 impl->world.gop.fence();
867 return sqrt(local);
868 }
869
870
871 /// Initializes information about the function norm at all length scales
872 void norm_tree(bool fence = true) const {
874 verify();
877 const_cast<Function<T,NDIM>*>(this)->impl->norm_tree(fence);
878 }
879
880
881 /// Compresses the function, transforming into wavelet basis. Possible non-blocking comm.
882
883 /// By default fence=true meaning that this operation completes before returning,
884 /// otherwise if fence=false it returns without fencing and the user must invoke
885 /// world.gop.fence() to assure global completion before using the function
886 /// for other purposes.
887 ///
888 /// Noop if already compressed or if not initialized.
889 ///
890 /// Since reconstruction/compression do not discard information we define them
891 /// as const ... "logical constness" not "bitwise constness".
892 const Function<T,NDIM>& compress(bool fence = true) const {
894 }
895
896
897 /// Compresses the function retaining scaling function coeffs. Possible non-blocking comm.
898
899 /// By default fence=true meaning that this operation completes before returning,
900 /// otherwise if fence=false it returns without fencing and the user must invoke
901 /// world.gop.fence() to assure global completion before using the function
902 /// for other purposes.
903 ///
904 /// Noop if already compressed or if not initialized.
905 void make_nonstandard(bool keepleaves, bool fence=true) const {
907 if (keepleaves) newstate=nonstandard_with_leaves;
908 change_tree_state(newstate,fence);
909 }
910
911 /// Converts the function standard compressed form. Possible non-blocking comm.
912
913 /// By default fence=true meaning that this operation completes before returning,
914 /// otherwise if fence=false it returns without fencing and the user must invoke
915 /// world.gop.fence() to assure global completion before using the function
916 /// for other purposes.
917 ///
918 /// Must be already compressed.
919 void standard(bool fence = true) {
921 }
922
923 /// Converts the function to redundant form, i.e. sum coefficients on all levels
924
925 /// By default fence=true meaning that this operation completes before returning,
926 /// otherwise if fence=false it returns without fencing and the user must invoke
927 /// world.gop.fence() to assure global completion before using the function
928 /// for other purposes.
929 ///
930 /// Since the transformation does not discard information we define this
931 /// as const ... "logical constness" not "bitwise constness".
932 ///
933 /// Note redundant form stores sum coefficients at every level, so it is larger than
934 /// reconstructed form; a caller that keeps the function alive may want to convert back.
935 void make_redundant(bool fence = true) const {
937 }
938
939 /// Reconstructs the function, transforming into scaling function basis. Possible non-blocking comm.
940
941 /// By default fence=true meaning that this operation completes before returning,
942 /// otherwise if fence=false it returns without fencing and the user must invoke
943 /// world.gop.fence() to assure global completion before using the function
944 /// for other purposes.
945 ///
946 /// Noop if already reconstructed or if not initialized.
947 ///
948 /// Since reconstruction/compression do not discard information we define them
949 /// as const ... "logical constness" not "bitwise constness".
950 const Function<T,NDIM>& reconstruct(bool fence = true) const {
952 }
953
954 /// changes tree state to given state
955
956 /// Since reconstruction/compression do not discard information we define them
957 /// as const ... "logical constness" not "bitwise constness".
958 /// @param[in] finalstate The final state of the tree
959 /// @param[in] fence Fence after the operation (might not be respected!!!)
960 const Function<T,NDIM>& change_tree_state(const TreeState finalstate, bool fence = true) const {
962 if (not impl) return *this;
963 TreeState current_state = impl->get_tree_state();
964 if (finalstate == current_state) return *this;
965 MADNESS_CHECK_THROW(current_state != TreeState::unknown, "unknown tree state");
966
967 impl->change_tree_state(finalstate, fence);
968 if (fence && VERIFY_TREE) verify_tree();
969 return *this;
970 }
971
972 /// Sums scaling coeffs down tree restoring state with coeffs only at leaves. Optional fence. Possible non-blocking comm.
973 void sum_down(bool fence = true) const {
975 verify();
976 MADNESS_CHECK_THROW(impl->get_tree_state()==redundant_after_merge, "sum_down requires a redundant_after_merge state");
977 const_cast<Function<T,NDIM>*>(this)->impl->sum_down(fence);
978 const_cast<Function<T,NDIM>*>(this)->impl->set_tree_state(reconstructed);
979
980 if (fence && VERIFY_TREE) verify_tree(); // Must be after in case nonstandard
981 }
982
983
984 /// Inplace autorefines the function. Optional fence. Possible non-blocking comm.
985 template <typename opT>
986 void refine_general(const opT& op, bool fence = true) const {
988 verify();
990 impl->refine(op, fence);
991 }
992
993
995 bool operator()(implT* impl, const Key<NDIM>& key, const nodeT& t) const {
996 return impl->autorefine_square_test(key, t);
997 }
998
999 template <typename Archive> void serialize (Archive& ar) {}
1000 };
1001
1002 /// Inplace autorefines the function using same test as for squaring.
1003
1004 /// return this for chaining
1005 const Function<T,NDIM>& refine(bool fence = true) const {
1006 refine_general(autorefine_square_op(), fence);
1007 return *this;
1008 }
1009
1010 /// Inplace broadens support in scaling function basis
1011
1012 /// N.B. with fence=false the per-node norm reset is skipped: norm_tree
1013 /// keeps the -1.0 broadened marker and dnorm_tree its previous value,
1014 /// so broadening cannot be repeated until the norms are recomputed.
1016 bool fence = true) const {
1017 verify();
1018 reconstruct();
1019 impl->broaden(bc.is_periodic(), fence);
1020 }
1021
1022
1023 /// Clears the function as if constructed uninitialized. Optional fence.
1024
1025 /// Any underlying data will not be freed until the next global fence.
1026 void clear(bool fence = true) {
1028 if (impl) {
1029 World& world = impl->world;
1030 impl.reset();
1031 if (fence) world.gop.fence();
1032 }
1033 }
1034
1035 /// Process 0 prints a summary of all nodes in the tree (collective)
1036 void print_tree(std::ostream& os = std::cout) const {
1038 if (impl) impl->print_tree(os);
1039 }
1040
1041 /// same as print_tree() but produces JSON-formatted string
1042 /// @warning enclose the result in braces to make it a valid JSON object
1043 void print_tree_json(std::ostream& os = std::cout) const {
1045 if (impl) impl->print_tree_json(os);
1046 }
1047
1048 /// Process 0 prints a graphviz-formatted output of all nodes in the tree (collective)
1049 void print_tree_graphviz(std::ostream& os = std::cout) const {
1051 os << "digraph G {" << std::endl;
1052 if (impl) impl->print_tree_graphviz(os);
1053 os << "}" << std::endl;
1054 }
1055
1056 /// Print a summary of the load balancing info
1057
1058 /// This is serial and VERY expensive
1059 void print_info() const {
1061 if (impl) impl->print_info();
1062 }
1063
1065 T (*f)(T);
1066 SimpleUnaryOpWrapper(T (*f)(T)) : f(f) {}
1067 void operator()(const Key<NDIM>& key, Tensor<T>& t) const {
1068 UNARY_OPTIMIZED_ITERATOR(T, t, *_p0 = f(*_p0));
1069 }
1070 template <typename Archive> void serialize(Archive& ar) {}
1071 };
1072
1073 /// Inplace unary operation on function values
1074 void unaryop(T (*f)(T)) {
1075 // Must fence here due to temporary object on stack
1076 // stopping us returning before complete
1077 this->unaryop(SimpleUnaryOpWrapper(f));
1078 }
1079
1080
1081 /// Inplace unary operation on function values
1082 template <typename opT>
1083 void unaryop(const opT& op, bool fence=true) {
1085 verify();
1086 reconstruct();
1087 impl->unary_op_value_inplace(op, fence);
1088 }
1089
1090
1091 /// Unary operation applied inplace to the coefficients
1092 template <typename opT>
1093 void unaryop_coeff(const opT& op,
1094 bool fence = true) {
1096 verify();
1097 impl->unary_op_coeff_inplace(op, fence);
1098 }
1099
1100
1101 /// Unary operation applied inplace to the nodes
1102 template <typename opT>
1103 void unaryop_node(const opT& op,
1104 bool fence = true) {
1106 verify();
1107 impl->unary_op_node_inplace(op, fence);
1108 }
1109
1110
1111
1112
1113 static void doconj(const Key<NDIM>, Tensor<T>& t) {
1115 t.conj();
1116 }
1117
1118 /// Inplace complex conjugate. No communication except for optional fence.
1119
1120 /// Returns this for chaining. Works in either basis.
1124 return *this;
1125 }
1126
1127
1128 /// Inplace, scale the function by a constant. No communication except for optional fence.
1129
1130 /// Works in either basis. Returns reference to this for chaining.
1131 template <typename Q>
1132 Function<T,NDIM>& scale(const Q q, bool fence=true) {
1134 verify();
1135 if (VERIFY_TREE) verify_tree();
1136 impl->scale_inplace(q,fence);
1137 return *this;
1138 }
1139
1140
1141 /// Inplace add scalar. No communication except for optional fence.
1144 verify();
1145 if (VERIFY_TREE) verify_tree();
1146 impl->add_scalar_inplace(t,fence);
1147 return *this;
1148 }
1149
1150
1151 /// Inplace, general bi-linear operation in wavelet basis. No communication except for optional fence.
1152
1153 /// If the functions are not in the wavelet basis an exception is thrown since this routine
1154 /// is intended to be fast and unexpected compression is assumed to be a performance bug.
1155 ///
1156 /// Returns this for chaining, can be in states compressed of redundant_after_merge.
1157 ///
1158 /// this and other may have different distributions and may even live in different worlds
1159 ///
1160 /// this <-- this*alpha + other*beta
1161 template <typename Q, typename R>
1163 const Function<Q,NDIM>& other, const R& beta, bool fence=true) {
1165 verify();
1166 other.verify();
1167
1168 // operation is done either in compressed or reconstructed state
1169 TreeState operating_state=this->get_impl()->get_tensor_type()==TT_FULL ? compressed : reconstructed;
1170
1171 TreeState thisstate=impl->get_tree_state();
1172 TreeState otherstate=other.get_impl()->get_tree_state();
1173
1175 MADNESS_CHECK_THROW(thisstate==compressed, "gaxpy: this must be compressed");
1176 MADNESS_CHECK_THROW(otherstate==compressed, "gaxpy: other must be compressed");
1177 impl->gaxpy_inplace(alpha, *other.get_impl(), beta, fence);
1178
1179 } else if (operating_state==reconstructed) {
1180 // this works both in reconstructed and redundant_after_merge states
1182 "gaxpy: this must be reconstructed or redundant_after_merge");
1183 MADNESS_CHECK_THROW(otherstate==reconstructed or otherstate==redundant_after_merge,
1184 "gaxpy: other must be reconstructed or redundant_after_merge");
1185
1186 impl->gaxpy_inplace_reconstructed(alpha,*other.get_impl(),beta,fence);
1187 } else {
1188 MADNESS_EXCEPTION("unknown tree state",1);
1189 }
1190 return *this;
1191 }
1192
1193
1194 /// Inplace addition of functions in the wavelet basis
1195
1196 /// Using operator notation forces a global fence after every operation.
1197 /// Functions don't need to be compressed, it's the caller's responsibility
1198 /// to choose an appropriate state with performance, usually compressed for 3d,
1199 /// reconstructed for 6d)
1200 template <typename Q>
1203
1204 // do this in reconstructed or compressed form
1206 this->change_tree_state(operating_state);
1208
1209 MADNESS_ASSERT(impl->get_tree_state() == other.get_impl()->get_tree_state());
1210 if (VERIFY_TREE) verify_tree();
1211 if (VERIFY_TREE) other.verify_tree();
1212 return gaxpy(T(1.0), other, Q(1.0), true);
1213 }
1214
1215
1216 /// Inplace subtraction of functions in the wavelet basis
1217
1218 /// Using operator notation forces a global fence after every operation
1219 template <typename Q>
1222 if (NDIM<=3) {
1223 compress();
1224 other.compress();
1225 } else {
1226 reconstruct();
1227 other.reconstruct();
1228 }
1229 MADNESS_ASSERT(impl->get_tree_state() == other.get_impl()->get_tree_state());
1230 if (VERIFY_TREE) verify_tree();
1231 if (VERIFY_TREE) other.verify_tree();
1232 return gaxpy(T(1.0), other, Q(-1.0), true);
1233 }
1234
1235
1236 /// Inplace scaling by a constant
1237
1238 /// Using operator notation forces a global fence after every operation
1239 template <typename Q>
1241 operator*=(const Q q) {
1243 scale(q,true);
1244 return *this;
1245 }
1246
1247
1248 /// Inplace squaring of function ... global comm only if not reconstructed
1249
1250 /// Returns *this for chaining.
1253 if (!is_reconstructed()) reconstruct();
1254 if (VERIFY_TREE) verify_tree();
1255 impl->square_inplace(fence);
1256 return *this;
1257 }
1258
1259 /// Returns *this for chaining.
1262 if (!is_reconstructed()) reconstruct();
1263 if (VERIFY_TREE) verify_tree();
1264 impl->abs_inplace(fence);
1265 return *this;
1266 }
1267
1268 /// Returns *this for chaining.
1271 if (!is_reconstructed()) reconstruct();
1272 if (VERIFY_TREE) verify_tree();
1273 impl->abs_square_inplace(fence);
1274 return *this;
1275 }
1276
1277 /// Returns local contribution to \c int(f(x),x) ... no communication
1278
1279 /// In the wavelet basis this is just the coefficient of the first scaling
1280 /// function which is a constant. In the scaling function basis we
1281 /// must add up contributions from each box.
1282 T trace_local() const {
1284 if (!impl) return 0.0;
1285 MADNESS_CHECK_THROW(impl->has_summable_coefficients(),
1286 "trace_local needs a tree that holds its coefficients once");
1287 if (VERIFY_TREE) verify_tree();
1288 return impl->trace_local();
1289 }
1290
1291
1292 /// Returns global value of \c int(f(x),x) ... global comm required
1293
1294 /// Works in any state whose coefficients trace_local() can sum; the
1295 /// remaining states are reconstructed first. For efficient use
1296 /// especially with many functions, reconstruct them all first and use
1297 /// trace_local instead, so you can perform a global sum on all at the
1298 /// same time.
1299 ///
1300 /// Throws if the function is on-demand, and fences before reconstructing;
1301 /// see norm2() for both, including why the branch stays collective.
1302 T trace() const {
1304 if (!impl) return 0.0;
1305 if (!impl->has_summable_coefficients()) {
1307 "trace is not defined for an on-demand function; materialize it first");
1308 impl->world.gop.fence();
1309 reconstruct();
1310 }
1311 if (VERIFY_TREE) verify_tree();
1312 T sum = impl->trace_local();
1313 impl->world.gop.sum(sum);
1314 impl->world.gop.fence();
1315 return sum;
1316 }
1317
1318
1319 /// Returns local part of inner product ... throws if both not compressed
1320 template <typename R>
1321 TENSOR_RESULT_TYPE(T,R) inner_local(const Function<R,NDIM>& g) const {
1325 MADNESS_CHECK_THROW(compressed or redundant,"functions must be compressed or redundant in inner");
1328 return impl->inner_local(*(g.get_impl()));
1329 }
1330
1331 /// Returns local part of dot product ... throws if both not compressed
1332 template <typename R>
1333 TENSOR_RESULT_TYPE(T,R) dot_local(const Function<R,NDIM>& g) const {
1336 MADNESS_ASSERT(g.is_compressed());
1338 if (VERIFY_TREE) g.verify_tree();
1339 return impl->dot_local(*(g.get_impl()));
1340 }
1341
1342
1343 /// With this being an on-demand function, fill the MRA tree according to different criteria
1344
1345 /// @param[in] g the function after which the MRA structure is modeled (any basis works)
1346 template<typename R>
1348 MADNESS_ASSERT(g.is_initialized());
1350
1351 // clear what we have
1352 impl->get_coeffs().clear();
1353
1354 //leaf_op<T,NDIM> gnode_is_leaf(g.get_impl().get());
1355 Leaf_op_other<T,NDIM> gnode_is_leaf(g.get_impl().get());
1356 impl->make_Vphi(gnode_is_leaf,fence);
1357 return *this;
1358
1359 }
1360
1361 /// With this being an on-demand function, fill the MRA tree according to different criteria
1362
1363 /// @param[in] op the convolution operator for screening
1364 template<typename opT>
1365 Function<T,NDIM>& fill_tree(const opT& op, bool fence=true) {
1367 // clear what we have
1368 impl->get_coeffs().clear();
1371 impl ->make_Vphi(leaf_op,fence);
1372 return *this;
1373 }
1374
1375 /// With this being an on-demand function, fill the MRA tree according to different criteria
1378 // clear what we have
1379 impl->get_coeffs().clear();
1381 impl->make_Vphi(leaf_op,fence);
1382 return *this;
1383 }
1384
1385 /// Special refinement on 6D boxes where the electrons come close (meet)
1386 /// @param[in] op the convolution operator for screening
1387 template<typename opT>
1388 Function<T,NDIM>& fill_cuspy_tree(const opT& op,const bool fence=true){
1390 // clear what we have
1391 impl->get_coeffs().clear();
1393
1395 impl ->make_Vphi(leaf_op,fence);
1396
1397 return *this;
1398 }
1399
1400 /// Special refinement on 6D boxes where the electrons come close (meet)
1403 // clear what we have
1404 impl->get_coeffs().clear();
1406
1408 impl ->make_Vphi(leaf_op,fence);
1409
1410 return *this;
1411 }
1412
1413 /// Special refinement on 6D boxes for the nuclear potentials (regularized with cusp, non-regularized with singularity)
1414 /// @param[in] op the convolution operator for screening
1415 template<typename opT>
1416 Function<T,NDIM>& fill_nuclear_cuspy_tree(const opT& op,const size_t particle,const bool fence=true){
1418 // clear what we have
1419 impl->get_coeffs().clear();
1421
1423 impl ->make_Vphi(leaf_op,fence);
1424
1425 return *this;
1426 }
1427
1428 /// Special refinement on 6D boxes for the nuclear potentials (regularized with cusp, non-regularized with singularity)
1431 // clear what we have
1432 impl->get_coeffs().clear();
1434
1436 impl ->make_Vphi(leaf_op,fence);
1437
1438 return *this;
1439 }
1440
1441 /// perform the hartree product of f*g, invoked by result
1442 template<size_t LDIM, size_t KDIM, typename opT>
1443 void do_hartree_product(const std::vector<std::shared_ptr<FunctionImpl<T,LDIM>>> left,
1444 const std::vector<std::shared_ptr<FunctionImpl<T,KDIM>>> right,
1445 const opT* op) {
1446
1447 // get the right leaf operator
1449 impl->hartree_product(left,right,leaf_op,true);
1450 impl->finalize_sum();
1451// this->truncate();
1452
1453 }
1454
1455 /// perform the hartree product of f*g, invoked by result
1456 template<size_t LDIM, size_t KDIM>
1457 void do_hartree_product(const std::vector<std::shared_ptr<FunctionImpl<T,LDIM>>> left,
1458 const std::vector<std::shared_ptr<FunctionImpl<T,KDIM>>> right) {
1459
1460// hartree_leaf_op<T,KDIM+LDIM> leaf_op(impl.get(),cdata.s0);
1462 impl->hartree_product(left,right,leaf_op,true);
1463 impl->finalize_sum();
1464// this->truncate();
1465
1466 }
1467
1468 /// Returns the inner product
1469
1470 /// Not efficient for computing multiple inner products
1471 /// @param[in] g Function, optionally on-demand
1472 template <typename R>
1475
1476 // fast return if possible
1477 if (not this->is_initialized()) return 0.0;
1478 if (not g.is_initialized()) return 0.0;
1479
1480 // if this and g are the same, use norm2()
1481 if constexpr (std::is_same_v<T,R>) {
1482 if (this->get_impl() == g.get_impl()) {
1483 // let norm2() handle tree state
1484 double norm = this->norm2();
1485 return norm * norm;
1486 }
1487 }
1488
1489 // do it case-by-case
1490 if constexpr (std::is_same_v<R,T>) {
1491 if (this->is_on_demand())
1492 return g.inner_on_demand(*this);
1493 if (g.is_on_demand())
1494 return this->inner_on_demand(g);
1495 }
1496
1498 if (VERIFY_TREE) g.verify_tree();
1499
1500 // compute in compressed form if compression is fast, otherwise in redundant form
1502
1504 g.change_tree_state(operating_state,false);
1505 impl->world.gop.fence();
1506
1507 TENSOR_RESULT_TYPE(T,R) local = impl->inner_local(*g.get_impl());
1508 impl->world.gop.sum(local);
1509 impl->world.gop.fence();
1510
1511 // restore state -- no need for this
1512 // change_tree_state(state,false);
1513 // g.change_tree_state(gstate,false);
1514 // impl->world.gop.fence();
1515
1516 return local;
1517 }
1518
1519 /// Return the local part of inner product with external function ... no communication.
1520 /// If you are going to be doing a bunch of inner_ext calls, set
1521 /// keep_redundant to true and then manually undo_redundant when you
1522 /// are finished.
1523 /// @param[in] f Pointer to function of type T that take coordT arguments. This is the externally provided function
1524 /// @param[in] leaf_refine boolean switch to turn on/off refinement past leaf nodes
1525 /// @param[in] keep_redundant boolean switch to turn on/off undo_redundant
1526 /// @return Returns local part of the inner product, i.e. over the domain of all function nodes on this compute node.
1527 T inner_ext_local(const std::shared_ptr< FunctionFunctorInterface<T,NDIM> > f, const bool leaf_refine=true, const bool keep_redundant=false) const {
1530 T local = impl->inner_ext_local(f, leaf_refine);
1531 if (not keep_redundant) change_tree_state(reconstructed);
1532 return local;
1533 }
1534
1535 /// Return the inner product with external function ... requires communication.
1536 /// If you are going to be doing a bunch of inner_ext calls, set
1537 /// keep_redundant to true and then manually undo_redundant when you
1538 /// are finished.
1539 /// @param[in] f Reference to FunctionFunctorInterface. This is the externally provided function
1540 /// @param[in] leaf_refine boolean switch to turn on/off refinement past leaf nodes
1541 /// @param[in] keep_redundant boolean switch to turn on/off undo_redundant
1542 /// @return Returns the inner product
1543 T inner_ext(const std::shared_ptr< FunctionFunctorInterface<T,NDIM> > f, const bool leaf_refine=true, const bool keep_redundant=false) const {
1546 T local = impl->inner_ext_local(f, leaf_refine);
1547 impl->world.gop.sum(local);
1548 impl->world.gop.fence();
1549 if (not keep_redundant) change_tree_state(reconstructed);
1550 return local;
1551 }
1552
1553 /// Return the inner product with external function ... requires communication.
1554 /// If you are going to be doing a bunch of inner_ext calls, set
1555 /// keep_redundant to true and then manually undo_redundant when you
1556 /// are finished.
1557 /// @param[in] f Reference to FunctionFunctorInterface. This is the externally provided function
1558 /// @param[in] leaf_refine boolean switch to turn on/off refinement past leaf nodes
1559 /// @return Returns the inner product
1561 const bool leaf_refine=true) const {
1563 reconstruct();
1564 T local = impl->inner_adaptive_local(f, leaf_refine);
1565 impl->world.gop.sum(local);
1566 impl->world.gop.fence();
1567 return local;
1568 }
1569
1570 /// Return the local part of gaxpy with external function, this*alpha + f*beta ... no communication.
1571 /// @param[in] alpha prefactor for this Function
1572 /// @param[in] f Pointer to function of type T that take coordT arguments. This is the externally provided function
1573 /// @param[in] beta prefactor for f
1574 template <typename L>
1575 void gaxpy_ext(const Function<L,NDIM>& left, T (*f)(const coordT&), T alpha, T beta, double tol, bool fence=true) const {
1577 if (!left.is_reconstructed()) left.reconstruct();
1578 impl->gaxpy_ext(left.get_impl().get(), f, alpha, beta, tol, fence);
1579 }
1580
1581 /// Returns the inner product for one on-demand function
1582
1583 /// It does work, but it might not give you the precision you expect.
1584 /// The assumption is that the function g returns proper sum
1585 /// coefficients on the MRA tree of this. This might not be the case if
1586 /// g is constructed with an implicit multiplication, e.g.
1587 /// result = <this|g>, with g = 1/r12 | gg>
1588 /// @param[in] g on-demand function
1589 template<typename R>
1590 TENSOR_RESULT_TYPE(T, R) inner_on_demand(const Function<R, NDIM>& g) const {
1591 MADNESS_ASSERT(g.is_on_demand() and (not this->is_on_demand()));
1592
1593 constexpr std::size_t LDIM=std::max(NDIM/2,std::size_t(1));
1594 auto func=dynamic_cast<CompositeFunctorInterface<T,NDIM,LDIM>* >(g.get_impl()->get_functor().get());
1596 func->make_redundant(true);
1597 func->replicate_low_dim_functions(true);
1598 this->reconstruct(); // if this == &g we don't need g to be redundant
1599
1601
1602 TENSOR_RESULT_TYPE(T, R) local = impl->inner_local_on_demand(*g.get_impl());
1603 impl->world.gop.sum(local);
1604 impl->world.gop.fence();
1605
1606 return local;
1607 }
1608
1609 /// project this on the low-dim function g: h(x) = <f(x,y) | g(y)>
1610
1611 /// @param[in] g low-dim function
1612 /// @param[in] dim over which dimensions to be integrated: 0..LDIM-1 or LDIM..NDIM-1
1613 /// @return new function of dimension NDIM-LDIM
1614 template <typename R, size_t LDIM>
1616 if (NDIM<=LDIM) MADNESS_EXCEPTION("confused dimensions in project_out?",1);
1617 MADNESS_CHECK_THROW(dim==0 or dim==1,"dim must be 0 or 1 in project_out");
1618 verify();
1619 typedef TENSOR_RESULT_TYPE(T,R) resultT;
1620 static const size_t KDIM=NDIM-LDIM;
1621
1623 .k(g.k()).thresh(g.thresh());
1624 Function<resultT,KDIM> result=factory; // no empty() here!
1625
1627 g.change_tree_state(redundant,false);
1628 world().gop.fence();
1629 this->get_impl()->project_out(result.get_impl().get(),g.get_impl().get(),dim,true);
1630// result.get_impl()->project_out2(this->get_impl().get(),gimpl,dim);
1631 result.world().gop.fence();
1632 g.change_tree_state(reconstructed,false);
1633 result.get_impl()->trickle_down(false);
1634 result.get_impl()->set_tree_state(reconstructed);
1635 result.world().gop.fence();
1636 return result;
1637 }
1638
1639 Function<T,NDIM/2> dirac_convolution(const bool fence=true) const {
1640 constexpr std::size_t LDIM=NDIM/2;
1641 MADNESS_CHECK_THROW(NDIM==2*LDIM,"NDIM must be even");
1642// // this will be the result function
1644 Function<T,LDIM> f = factory;
1645 if(!is_reconstructed()) this->reconstruct();
1646 this->get_impl()->do_dirac_convolution(f.get_impl().get(),fence);
1647 return f;
1648 }
1649
1650 /// Replaces this function with one loaded from an archive using the default processor map
1651
1652 /// Archive can be sequential or parallel.
1653 ///
1654 /// The & operator for serializing will only work with parallel archives.
1655 template <typename Archive>
1656 void load(World& world, Archive& ar) {
1658 // Type checking since we are probably circumventing the archive's own type checking
1659 long magic = 0l, id = 0l, ndim = 0l, k = 0l;
1661 ar & magic & id & ndim & k & cell;
1662 // CHECK not ASSERT: ASSERT is compiled out when ASSERTION_TYPE=disable
1664 "Function archive was written by an incompatible MADNESS version; regenerate it.");
1666 MADNESS_CHECK(ndim == NDIM);
1667
1668 // if simulation cell is set it must match the cell from function on file.
1669 // if simulation cell is not set set it to the one found on file
1670 // -- for the latter the only use case seems a python script for plotting
1672 if ((cell-FunctionDefaults<NDIM>::get_cell()).normf()>1.e-14) {
1673 std::ostringstream oss;
1674 oss << "simulation cells inconsistent: stored cell differs from FunctionDefaults cell.\n"
1675 << "Call FunctionDefaults<" << NDIM << ">::clear_cell() before reloading "
1676 << "(this will render all existing functions useless!)";
1677 MADNESS_EXCEPTION(oss.str().c_str(), 1);
1678 }
1679 } else { // no cell set in the defaults: use the one from file
1681 }
1682
1683 impl.reset(new implT(FunctionFactory<T,NDIM>(world).k(k).empty()));
1684 impl->load(ar);
1685 }
1686
1687
1688 /// Stores the function to an archive
1689
1690 /// Archive can be sequential or parallel.
1691 ///
1692 /// The & operator for serializing will only work with parallel archives.
1693 template <typename Archive>
1694 void store(Archive& ar) const {
1696 verify();
1697 // For type checking, etc.
1698 ar & long(FUNCTION_ARCHIVE_MAGIC) & long(TensorTypeData<T>::id) & long(NDIM) & long(k()) & impl->get_cell();
1699
1700 impl->store(ar);
1701 }
1702
1703 /// change the tensor type of the coefficients in the FunctionNode
1704
1705 /// @param[in] targs target tensor arguments (threshold and full/low rank)
1706 void change_tensor_type(const TensorArgs& targs, bool fence=true) {
1707 if (not impl) return;
1708 impl->change_tensor_type1(targs,fence);
1709 }
1710
1711
1712 /// This is replaced with left*right ... private
1713 template <typename Q, typename opT>
1715 const opT& op, bool fence) {
1717 func.verify();
1718 MADNESS_ASSERT(func.is_reconstructed());
1719 if (VERIFY_TREE) func.verify_tree();
1720 impl.reset(new implT(*func.get_impl(), func.get_pmap(), false));
1721 impl->unaryXX(func.get_impl().get(), op, fence);
1722 return *this;
1723 }
1724
1725 /// Returns vector of FunctionImpl pointers corresponding to vector of functions
1726 template <typename Q, std::size_t D>
1727 static std::vector< std::shared_ptr< FunctionImpl<Q,D> > > vimpl(const std::vector< Function<Q,D> >& v) {
1729 std::vector< std::shared_ptr< FunctionImpl<Q,D> > > r(v.size());
1730 for (unsigned int i=0; i<v.size(); ++i) r[i] = v[i].get_impl();
1731 return r;
1732 }
1733
1734 /// This is replaced with op(vector of functions) ... private
1735 template <typename opT>
1736 Function<T,NDIM>& multiop_values(const opT& op, const std::vector< Function<T,NDIM> >& vf) {
1737 std::vector<implT*> v(vf.size(),NULL);
1738 for (unsigned int i=0; i<v.size(); ++i) {
1739 if (vf[i].is_initialized()) v[i] = vf[i].get_impl().get();
1740 }
1741 impl->multiop_values(op, v);
1742 world().gop.fence();
1743 if (VERIFY_TREE) verify_tree();
1744
1745 return *this;
1746 }
1747
1748 /// apply op on the input vector yielding an output vector of functions
1749
1750 /// (*this) is just a dummy Function to be able to call internal methods in FuncImpl
1751 /// @param[in] op the operator working on vin
1752 /// @param[in] vin vector of input Functions
1753 /// @param[out] vout vector of output Functions vout = op(vin)
1754 template <typename opT>
1756 const std::vector< Function<T,NDIM> >& vin,
1757 std::vector< Function<T,NDIM> >& vout,
1758 const bool fence=true) {
1759 std::vector<implT*> vimplin(vin.size(),NULL);
1760 for (unsigned int i=0; i<vin.size(); ++i) {
1761 if (vin[i].is_initialized()) vimplin[i] = vin[i].get_impl().get();
1762 }
1763 std::vector<implT*> vimplout(vout.size(),NULL);
1764 for (unsigned int i=0; i<vout.size(); ++i) {
1765 if (vout[i].is_initialized()) vimplout[i] = vout[i].get_impl().get();
1766 }
1767
1768 impl->multi_to_multi_op_values(op, vimplin, vimplout, fence);
1769 if (VERIFY_TREE) verify_tree();
1770
1771 }
1772
1773
1774 /// Multiplication of function * vector of functions using recursive algorithm of mulxx
1775 template <typename L, typename R>
1776 void vmulXX(const Function<L,NDIM>& left,
1777 const std::vector< Function<R,NDIM> >& right,
1778 std::vector< Function<T,NDIM> >& result,
1779 double tol,
1780 bool fence) {
1782
1783 std::vector<FunctionImpl<T,NDIM>*> vresult(right.size());
1784 std::vector<const FunctionImpl<R,NDIM>*> vright(right.size());
1785 for (unsigned int i=0; i<right.size(); ++i) {
1786 result[i].set_impl(left,false);
1787 // set_impl copies left's state, which is redundant here, but the kernel builds
1788 // a reconstructed tree (interior nodes carry no coefficients)
1789 result[i].get_impl()->set_tree_state(reconstructed);
1790 vresult[i] = result[i].impl.get();
1791 vright[i] = right[i].get_impl().get();
1792 }
1793
1794 left.world().gop.fence(); // Is this still essential? Yes.
1795 vresult[0]->mulXXvec(left.get_impl().get(), vright, vresult, tol, fence);
1796 }
1797
1798 /// Same as \c operator* but with optional fence and no automatic reconstruction
1799
1800 /// f or g are on-demand functions
1801 template<typename L, typename R>
1802 void mul_on_demand(const Function<L,NDIM>& f, const Function<R,NDIM>& g, bool fence=true) {
1803 const FunctionImpl<L,NDIM>* fimpl=f.get_impl().get();
1804 const FunctionImpl<R,NDIM>* gimpl=g.get_impl().get();
1805 if (fimpl->is_on_demand() and gimpl->is_on_demand()) {
1806 MADNESS_EXCEPTION("can't multiply two on-demand functions",1);
1807 }
1808
1809 if (fimpl->is_on_demand()) {
1810 leaf_op<R,NDIM> leaf_op1(gimpl);
1811 impl->multiply(leaf_op1,gimpl,fimpl,fence);
1812 } else {
1813 leaf_op<L,NDIM> leaf_op1(fimpl);
1814 impl->multiply(leaf_op1,fimpl,gimpl,fence);
1815 }
1816 }
1817
1818 /// sparse transformation of a vector of functions ... private
1819 template <typename R, typename Q>
1820 void vtransform(const std::vector< Function<R,NDIM> >& v,
1821 const Tensor<Q>& c,
1822 std::vector< Function<T,NDIM> >& vresult,
1823 double tol,
1824 bool fence=true) {
1826 vresult[0].impl->vtransform(vimpl(v), c, vimpl(vresult), tol, fence);
1827 }
1828
1829 /// This is replaced with alpha*left + beta*right ... private
1830 template <typename L, typename R>
1832 T beta, const Function<R,NDIM>& right, bool fence) {
1834 left.verify();
1835 right.verify();
1836 MADNESS_ASSERT(left.is_compressed() && right.is_compressed());
1837 if (VERIFY_TREE) left.verify_tree();
1838 if (VERIFY_TREE) right.verify_tree();
1839 impl.reset(new implT(*left.get_impl(), left.get_pmap(), false));
1840 impl->gaxpy(alpha,*left.get_impl(),beta,*right.get_impl(),fence);
1841 return *this;
1842 }
1843
1844 /// This is replaced with mapdim(f) ... private
1845 Function<T,NDIM>& mapdim(const Function<T,NDIM>& f, const std::vector<long>& map, bool fence) {
1847 f.verify();
1848 if (VERIFY_TREE) f.verify_tree();
1849 for (std::size_t i=0; i<NDIM; ++i) MADNESS_ASSERT(map[i]>=0 && static_cast<std::size_t>(map[i])<NDIM);
1850 impl.reset(new implT(*f.impl, f.get_pmap(), false));
1851 impl->mapdim(*f.impl,map,fence);
1852 return *this;
1853 }
1854
1855 /// This is replaced with mirror(f) ... private
1856
1857 /// similar to mapdim, but maps from x to -x, y to -y, and so on
1858 /// Example: mirror a 3d function on the xy plane: mirror={1,1,-1}
1859 /// @param[in] mirror array of -1 and 1, corresponding to mirror or not
1860 Function<T,NDIM>& mirror(const Function<T,NDIM>& f, const std::vector<long>& mirrormap, bool fence) {
1862 f.verify();
1863 if (VERIFY_TREE) f.verify_tree();
1864 for (std::size_t i=0; i<NDIM; ++i) MADNESS_ASSERT((mirrormap[i]==1) or (mirrormap[i]==-1));
1865 impl.reset(new implT(*f.impl, f.get_pmap(), false));
1866 impl->mirror(*f.impl,mirrormap,fence);
1867 return *this;
1868 }
1869
1870 /// This is replaced with mirror(map(f)) ... private
1871
1872 /// first map then mirror!
1873 /// mirror is similar to mapdim, but maps from x to -x, y to -y, and so on
1874 /// Example: mirror a 3d function on the xy plane: mirror={1,1,-1}
1875 /// Example: c4 rotation of a 3d function around the z axis:
1876 /// x->y, y->-x, z->z: map(1,0,2); mirror(-1,1,1)
1877 /// @param[in] map array holding dimensions
1878 /// @param[in] mirror array of -1 and 1, corresponding to mirror or not
1880 const std::vector<long>& map, const std::vector<long>& mirror,
1881 bool fence) {
1883 f.verify();
1884 if (VERIFY_TREE) f.verify_tree();
1885 for (std::size_t i=0; i<mirror.size(); ++i) MADNESS_ASSERT((mirror[i]==1) or (mirror[i]==-1));
1886 for (std::size_t i=0; i<map.size(); ++i) MADNESS_ASSERT(map[i]>=0 && static_cast<std::size_t>(map[i])<NDIM);
1887
1888 impl.reset(new implT(*f.impl, f.get_pmap(), false));
1889 impl->map_and_mirror(*f.impl,map,mirror,fence);
1890 return *this;
1891 }
1892
1893
1894 /// check symmetry of a function by computing the 2nd derivative
1895 double check_symmetry() const {
1896
1898 if (VERIFY_TREE) verify_tree();
1899 double local = impl->check_symmetry_local();
1900 impl->world.gop.sum(local);
1901 impl->world.gop.fence();
1902 double asy=sqrt(local);
1903 if (this->world().rank()==0) print("asymmetry wrt particle",asy);
1905 return asy;
1906 }
1907
1908 /// reduce the rank of the coefficient tensors
1909 Function<T,NDIM>& reduce_rank(const double thresh=0.0, const bool fence=true) {
1910 verify();
1911 double thresh1= (thresh==0.0) ? impl->get_tensor_args().thresh : thresh;
1912 impl->reduce_rank(thresh1,fence);
1913 return *this;
1914 }
1915
1916 /// remove all nodes with level higher than n
1917 Function<T,NDIM>& chop_at_level(const int n, const bool fence=true) {
1918 verify();
1920 impl->chop_at_level(n,true);
1922 return *this;
1923 }
1924 };
1925
1926// template <typename T, typename opT, std::size_t NDIM>
1927 template <typename T, typename opT, std::size_t NDIM>
1928 Function<T,NDIM> multiop_values(const opT& op, const std::vector< Function<T,NDIM> >& vf) {
1930 r.set_impl(vf[0], false);
1931 r.multiop_values(op, vf);
1932 return r;
1933 }
1934
1935 /// Returns new function equal to alpha*f(x) with optional fence
1936 template <typename Q, typename T, std::size_t NDIM>
1938 mul(const Q alpha, const Function<T,NDIM>& f, bool fence=true) {
1940 f.verify();
1941 if (VERIFY_TREE) f.verify_tree();
1942 Function<TENSOR_RESULT_TYPE(Q,T),NDIM> result;
1943 result.set_impl(f, false);
1944 result.get_impl()->scale_oop(alpha,*f.get_impl(),fence);
1945 return result;
1946 }
1947
1948
1949 /// Returns new function equal to f(x)*alpha with optional fence
1950 template <typename Q, typename T, std::size_t NDIM>
1952 mul(const Function<T,NDIM>& f, const Q alpha, bool fence=true) {
1954 return mul(alpha,f,fence);
1955 }
1956
1957
1958 /// Returns new function equal to f(x)*alpha
1959
1960 /// Using operator notation forces a global fence after each operation
1961 template <typename Q, typename T, std::size_t NDIM>
1964 return mul(alpha, f, true);
1965 }
1966
1967 /// Returns new function equal to alpha*f(x)
1968
1969 /// Using operator notation forces a global fence after each operation
1970 template <typename Q, typename T, std::size_t NDIM>
1973 return mul(alpha, f, true);
1974 }
1975
1976 /// Sparse multiplication; the scalar interface redirects to the vector one in vmra.h
1977
1978 /// @param[in] tol target absolute accuracy of the product; see the vector mul_sparse in
1979 /// vmra.h for the semantics, including the internal safety margin and tol=0
1980 /// @param[in] do_make_redundant if false, both inputs must already be redundant
1981 template <typename L, typename R,std::size_t NDIM>
1983 mul_sparse(const Function<L,NDIM>& left, const Function<R,NDIM>& right, double tol,
1984 bool fence=true, bool do_make_redundant=true) {
1986 left.verify();
1987 right.verify();
1988 std::vector< Function<R,NDIM> > vright(1,right);
1989 return mul_sparse(left.get_impl()->world, left, vright, tol, fence, do_make_redundant)[0];
1990 }
1991
1992 /// Same as \c operator* but with optional fence; see mul_sparse to screen
1993 template <typename L, typename R,std::size_t NDIM>
1995 mul(const Function<L,NDIM>& left, const Function<R,NDIM>& right, bool fence=true,
1996 bool do_make_redundant=true) {
1997 return mul_sparse(left,right,/*tol=*/0.0,fence,do_make_redundant);
1998 }
1999
2000 /// Generate new function = op(left,right) where op acts on the function values
2001 template <typename L, typename R, typename opT, std::size_t NDIM>
2003 binary_op(const Function<L,NDIM>& left, const Function<R,NDIM>& right, const opT& op, bool fence=true) {
2005 if (!left.is_reconstructed()) left.reconstruct();
2006 if (!right.is_reconstructed()) right.reconstruct();
2007
2009 result.set_impl(left, false);
2010 result.get_impl()->binaryXX(left.get_impl().get(), right.get_impl().get(), op, fence);
2011 return result;
2012 }
2013
2014 /// Out of place application of unary operation to function values with optional fence
2015 template <typename Q, typename opT, std::size_t NDIM>
2017 unary_op(const Function<Q,NDIM>& func, const opT& op, bool fence=true) {
2018 if (!func.is_reconstructed()) func.reconstruct();
2020 if (VERIFY_TREE) func.verify_tree();
2021 result.set_impl(func, false);
2022 result.get_impl()->unaryXXvalues(func.get_impl().get(), op, fence);
2023 return result;
2024 }
2025
2026
2027 /// Out of place application of unary operation to scaling function coefficients with optional fence
2028 template <typename Q, typename opT, std::size_t NDIM>
2030 unary_op_coeffs(const Function<Q,NDIM>& func, const opT& op, bool fence=true) {
2031 if (!func.is_reconstructed()) func.reconstruct();
2033 return result.unary_op_coeffs(func,op,fence);
2034 }
2035
2036 /// Use the vmra/mul(...) interface instead
2037
2038 /// This so that we don't have to have friend functions in a different header.
2039 ///
2040 /// left and right must be in redundant state, with tree norms available.
2041 template <typename L, typename R, std::size_t D>
2042 std::vector< Function<TENSOR_RESULT_TYPE(L,R),D> >
2043 vmulXX(const Function<L,D>& left, const std::vector< Function<R,D> >& vright, double tol, bool fence=true) {
2044 if (vright.size() == 0) return std::vector< Function<TENSOR_RESULT_TYPE(L,R),D> >();
2045 std::vector< Function<TENSOR_RESULT_TYPE(L,R),D> > vresult(vright.size());
2046 vresult[0].vmulXX(left, vright, vresult, tol, fence);
2047 return vresult;
2048 }
2049
2050 /// Multiplies two functions with the new result being of type TensorResultType<L,R>
2051
2052 /// Using operator notation forces a global fence after each operation but also
2053 /// enables us to automatically reconstruct the input functions as required.
2054 template <typename L, typename R, std::size_t NDIM>
2056 operator*(const Function<L,NDIM>& left, const Function<R,NDIM>& right) {
2057 if (!left.is_reconstructed()) left.reconstruct();
2058 if (!right.is_reconstructed()) right.reconstruct();
2059 MADNESS_ASSERT(not (left.is_on_demand() or right.is_on_demand()));
2060 return mul(left,right,true);
2061 }
2062
2063 /// Performs a Hartree/outer product on the two given low-dimensional function vectors
2064
2065 /// @return result(x,y) = \sum_i f_i(x) g_i(y)
2066 template<typename T, std::size_t KDIM, std::size_t LDIM>
2068 hartree_product(const std::vector<Function<T,KDIM>>& left, const std::vector<Function<T,LDIM>>& right) {
2069
2070 MADNESS_CHECK_THROW(left.size()==right.size(), "hartree_product: left and right must have same size");
2071 if (left.size()==0) return Function<T,KDIM+LDIM>();
2072
2074
2076 .k(left.front().k()).thresh(thresh);
2077 Function<T,KDIM+LDIM> result=factory.empty();
2078
2079 // some prep work
2082 std::vector<std::shared_ptr<FunctionImpl<T,KDIM>>> vleft=get_impl(left);
2083 std::vector<std::shared_ptr<FunctionImpl<T,LDIM>>> vright=get_impl(right);
2084
2085 result.do_hartree_product(vleft,vright);
2086
2087 return result;
2088
2089 }
2090
2091 /// Performs a Hartree product on the two given low-dimensional functions
2092 template<typename T, std::size_t KDIM, std::size_t LDIM>
2095 typedef std::vector<Function<T,KDIM>> vector;
2096 return hartree_product(vector({left2}),vector({right2}));
2097 }
2098
2099 /// Performs a Hartree product on the two given low-dimensional functions
2100 template<typename T, std::size_t KDIM, std::size_t LDIM, typename opT>
2103 const opT& op) {
2104
2105 // we need both sum and difference coeffs for error estimation
2106 Function<T,KDIM>& left = const_cast< Function<T,KDIM>& >(left2);
2107 Function<T,LDIM>& right = const_cast< Function<T,LDIM>& >(right2);
2108
2110
2112 .k(left.k()).thresh(thresh);
2113 Function<T,KDIM+LDIM> result=factory.empty();
2114
2115 if (result.world().rank()==0) {
2116 print("incomplete FunctionFactory in Function::hartree_product");
2117 print("thresh: ", thresh);
2118 }
2119 bool same=(left2.get_impl()==right2.get_impl());
2120
2121 // some prep work
2122 left.make_nonstandard(true, true);
2123 right.make_nonstandard(true, true);
2124
2125 std::vector<std::shared_ptr<FunctionImpl<T,KDIM>>> vleft;
2126 std::vector<std::shared_ptr<FunctionImpl<T,LDIM>>> vright;
2127 vleft.push_back(left.get_impl());
2128 vright.push_back(right.get_impl());
2129 result.do_hartree_product(vleft,right,&op);
2130
2131 left.standard(false);
2132 if (not same) right.standard(false);
2133 left2.world().gop.fence();
2134
2135 return result;
2136 }
2137
2138 /// adds beta*right only left: alpha*left + beta*right optional fence and no automatic compression
2139
2140 /// left and right might live in different worlds, the accumulation is non-blocking
2141 template <typename L, typename R,std::size_t NDIM>
2142 void
2144 TENSOR_RESULT_TYPE(L,R) beta, const Function<R,NDIM>& right, bool fence=true) {
2147 left.gaxpy(alpha, right, beta, fence);
2148 }
2149
2150 /// Returns new function alpha*left + beta*right optional fence and no automatic compression
2151 template <typename L, typename R,std::size_t NDIM>
2154 TENSOR_RESULT_TYPE(L,R) beta, const Function<R,NDIM>& right, bool fence=true) {
2157 return result.gaxpy_oop(alpha, left, beta, right, fence);
2158 }
2159
2160 /// Same as \c operator+ but with optional fence and no automatic compression
2161 template <typename L, typename R,std::size_t NDIM>
2163 add(const Function<L,NDIM>& left, const Function<R,NDIM>& right, bool fence=true) {
2164 return gaxpy_oop(TENSOR_RESULT_TYPE(L,R)(1.0), left,
2165 TENSOR_RESULT_TYPE(L,R)(1.0), right, fence);
2166 }
2167
2168
2169 /// Returns new function alpha*left + beta*right optional fence, having both addends reconstructed
2170 template<typename T, std::size_t NDIM>
2172 const double beta, const Function<T,NDIM>& right, const bool fence=true) {
2173 Function<T,NDIM> result;
2174 result.set_impl(right,false);
2175
2178 result.get_impl()->gaxpy_oop_reconstructed(alpha,*left.get_impl(),beta,*right.get_impl(),fence);
2179 return result;
2180
2181 }
2182
2183 /// Adds two functions with the new result being of type TensorResultType<L,R>
2184
2185 /// Using operator notation forces a global fence after each operation
2186 template <typename L, typename R, std::size_t NDIM>
2188 operator+(const Function<L,NDIM>& left, const Function<R,NDIM>& right) {
2189 if (VERIFY_TREE) left.verify_tree();
2190 if (VERIFY_TREE) right.verify_tree();
2191
2192 TreeState operating_state=left.get_impl()->get_tensor_type()==TT_FULL ? compressed : reconstructed;
2193 // no compression for high-dimensional functions
2195 left.reconstruct();
2196 right.reconstruct();
2197 return gaxpy_oop_reconstructed(1.0,left,1.0,right,true);
2198 } else {
2199 if (!left.is_compressed()) left.compress();
2200 if (!right.is_compressed()) right.compress();
2201 return add(left,right,true);
2202 }
2203 }
2204
2205 /// Same as \c operator- but with optional fence and no automatic compression
2206 template <typename L, typename R,std::size_t NDIM>
2208 sub(const Function<L,NDIM>& left, const Function<R,NDIM>& right, bool fence=true) {
2209 return gaxpy_oop(TENSOR_RESULT_TYPE(L,R)(1.0), left,
2210 TENSOR_RESULT_TYPE(L,R)(-1.0), right, fence);
2211 }
2212
2213
2214 /// Subtracts two functions with the new result being of type TensorResultType<L,R>
2215
2216 /// Using operator notation forces a global fence after each operation
2217 template <typename L, typename R, std::size_t NDIM>
2219 operator-(const Function<L,NDIM>& left, const Function<R,NDIM>& right) {
2221 // no compression for high-dimensional functions
2222 if (NDIM==6) {
2223 left.reconstruct();
2224 right.reconstruct();
2225 return gaxpy_oop_reconstructed(1.0,left,-1.0,right,true);
2226 } else {
2227 if (!left.is_compressed()) left.compress();
2228 if (!right.is_compressed()) right.compress();
2229 return sub(left,right,true);
2230 }
2231 }
2232
2233 /// Create a new copy of the function with different distribution and optional fence
2234
2235 /// Works in either basis. Different distributions imply
2236 /// asynchronous communication and the optional fence is
2237 /// collective.
2238 template <typename T, std::size_t NDIM>
2240 const std::shared_ptr< WorldDCPmapInterface< Key<NDIM> > >& pmap,
2241 bool fence = true) {
2243 f.verify();
2244 Function<T,NDIM> result;
2246 result.set_impl(std::shared_ptr<implT>(new implT(*f.get_impl(), pmap, false)));
2247 result.get_impl()->copy_coeffs(*f.get_impl(), fence);
2248 if (VERIFY_TREE) result.verify_tree();
2249 return result;
2250 }
2251
2252 /// Create a new copy of the function with the same distribution and optional fence
2253 template <typename T, std::size_t NDIM>
2256 return copy(f, f.get_pmap(), fence);
2257 }
2258
2259 /// Create a new copy of function f living in world (might differ from f.world)
2260
2261 /// uses the default processor map of world
2262 template <typename T, std::size_t NDIM>
2267
2268 // create a new function with pmap distribution, same parameters as f, but no coeffs
2269 Function<T,NDIM> result;
2270 result.set_impl(std::make_shared<implT>(world,*f.get_impl(), pmap, false));
2271 // copy f's coefficients to result
2272 result.get_impl()->copy_coeffs(*f.get_impl(), fence);
2273 return result;
2274 }
2275
2276 /// Type conversion implies a deep copy. No communication except for optional fence.
2277
2278 /// Works in either basis but any loss of precision may result in different errors
2279 /// in applied in a different basis.
2280 ///
2281 /// The new function is formed with the options from the default constructor.
2282 ///
2283 /// There is no automatic type conversion since this is generally a rather dangerous
2284 /// thing and because there would be no way to make the fence optional.
2285 template <typename T, typename Q, std::size_t NDIM>
2288 f.verify();
2289 Function<Q,NDIM> result;
2290 result.set_impl(f, false);
2291 result.get_impl()->copy_coeffs(*f.get_impl(), fence);
2292 return result;
2293 }
2294
2295
2296 /// Return the complex conjugate of the input function with the same distribution and optional fence
2297
2298 /// !!! The fence is actually not optional in the current implementation !!!
2299 template <typename T, std::size_t NDIM>
2302 Function<T,NDIM> result = copy(f,true);
2303 return result.conj(fence);
2304 }
2305
2306 /// Apply operator on a hartree product of two low-dimensional functions
2307
2308 /// Supposed to be something like result= G( f(1)*f(2))
2309 /// the hartree product is never constructed explicitly, but its coeffs are
2310 /// constructed on the fly and processed immediately.
2311 /// @param[in] op the operator
2312 /// @param[in] f1 function of particle 1
2313 /// @param[in] f2 function of particle 2
2314 /// @param[in] fence if we shall fence
2315 /// @return a function of dimension NDIM=LDIM+LDIM
2316 template <typename opT, typename T, std::size_t LDIM>
2317 Function<TENSOR_RESULT_TYPE(typename opT::opT,T), LDIM+LDIM>
2318 apply(const opT& op, const std::vector<Function<T,LDIM>>& f1, const std::vector<Function<T,LDIM>>& f2, bool fence=true) {
2319
2320 World& world=f1.front().world();
2321
2322 typedef TENSOR_RESULT_TYPE(T,typename opT::opT) resultT;
2323 typedef std::vector<Function<T,LDIM>> vecfuncL;
2324
2325 vecfuncL& ff1 = const_cast< vecfuncL& >(f1);
2326 vecfuncL& ff2 = const_cast< vecfuncL& >(f2);
2327
2328 bool same=(ff1[0].get_impl()==ff2[0].get_impl());
2329
2330 reconstruct(world,f1,false);
2331 reconstruct(world,f2,false);
2332 world.gop.fence();
2333 // keep the leaves! They are assumed to be there later
2334 // even for modified op we need NS form for the hartree_leaf_op
2335 for (auto& f : f1) f.make_nonstandard(true,false);
2336 for (auto& f : f2) f.make_nonstandard(true,false);
2337 world.gop.fence();
2338
2339
2342 Function<resultT,LDIM+LDIM> result=factory.empty().fence();
2343
2344 result.get_impl()->reset_timer();
2345 op.reset_timer();
2346
2347 // fuse all pairs into a single tree traversal
2348 {
2349 std::vector<const FunctionImpl<T,LDIM>*> fimpls(f1.size()), gimpls(f2.size());
2350 for (size_t i=0; i<f1.size(); ++i) {
2351 fimpls[i]=f1[i].get_impl().get();
2352 gimpls[i]=f2[i].get_impl().get();
2353 }
2354 result.get_impl()->recursive_apply(op, fimpls, gimpls, false);
2355 }
2356 world.gop.fence();
2357
2358 if (op.print_timings) {
2359 result.get_impl()->print_timer();
2360 op.print_timer();
2361 }
2362
2363 result.get_impl()->finalize_apply(); // need fence before reconstruct
2364
2365 if (op.modified()) {
2366 result.get_impl()->trickle_down(true);
2367 } else {
2368 result.get_impl()->reconstruct(true);
2369 }
2370 standard(world,ff1,false);
2371 if (not same) standard(world,ff2,false);
2372
2373 return result;
2374 }
2375
2376
2377 /// Apply operator ONLY in non-standard form - required other steps missing !!
2378 template <typename opT, typename R, std::size_t NDIM>
2379 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM>
2380 apply_only(const opT& op, const Function<R,NDIM>& f, bool fence=true) {
2381 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM> result;
2382
2383 constexpr std::size_t OPDIM=opT::opdim;
2384 constexpr bool low_dim=(OPDIM*2==NDIM); // apply on some dimensions only
2385
2386 // specialized version for 3D
2387 if (NDIM <= 3 and (not low_dim)) {
2388 result.set_impl(f, false);
2389 result.get_impl()->apply(op, *f.get_impl(), fence);
2390
2391 } else { // general version for higher dimension
2392 //bool print_timings=false;
2393 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM> r1;
2394
2395 result.set_impl(f, false);
2396 r1.set_impl(f, false);
2397
2398 result.get_impl()->reset_timer();
2399 op.reset_timer();
2400
2401 result.get_impl()->apply_source_driven(op, *f.get_impl(), fence);
2402
2403 // recursive_apply is about 20% faster than apply_source_driven
2404 //result.get_impl()->recursive_apply(op, f.get_impl().get(),
2405 // r1.get_impl().get(),true); // will fence here
2406
2407 }
2408
2409 return result;
2410 }
2411
2412 /// Apply operator in non-standard form
2413
2414 /// Returns a new function with the same distribution
2415 ///
2416 /// !!! For the moment does NOT respect fence option ... always fences
2417 /// if the operator acts on one particle only the result will be sorted as
2418 /// g.particle=1: g(f) = \int g(x,x') f(x',y) dx' = result(x,y)
2419 /// g.particle=2: g(f) = \int g(y,y') f(x,y') dy' = result(x,y)
2420 /// for the second case it will notably *not* be as it is implemented in the partial inner product!
2421 /// g.particle=2 g(f) = result(x,y)
2422 /// inner(g(y,y'),f(x,y'),1,1) = result(y,x)
2423 /// also note the confusion with the counting of the particles/integration variables
2424 template <typename opT, typename R, std::size_t NDIM>
2425 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM>
2426 apply(const opT& op, const Function<R,NDIM>& f, bool fence=true) {
2427
2428 typedef TENSOR_RESULT_TYPE(typename opT::opT,R) resultT;
2429 Function<R,NDIM>& ff = const_cast< Function<R,NDIM>& >(f);
2431
2432 MADNESS_ASSERT(not f.is_on_demand());
2433 bool print_timings=op.print_timings;
2434
2435 if (VERIFY_TREE) ff.verify_tree();
2436 ff.reconstruct();
2437 if (print_timings) ff.print_size("ff in apply after reconstruct");
2438
2439 if (op.modified()) {
2440
2442// ff.get_impl()->make_redundant(true);
2443 result = apply_only(op, ff, fence);
2444 ff.get_impl()->undo_redundant(false);
2445 result.get_impl()->trickle_down(true);
2446
2447 } else {
2448
2449 // saves the standard() step, which is very expensive in 6D
2450// Function<R,NDIM> fff=copy(ff);
2451 Function<R,NDIM> fff=(ff);
2452 fff.make_nonstandard(op.doleaves, true);
2453 if (print_timings) fff.print_size("ff in apply after make_nonstandard");
2454 if ((print_timings) and (f.world().rank()==0)) {
2455 fff.get_impl()->timer_filter.print("filter");
2456 fff.get_impl()->timer_compress_svd.print("compress_svd");
2457 }
2458 result = apply_only(op, fff, fence);
2459 result.get_impl()->set_tree_state(nonstandard_after_apply);
2460 ff.world().gop.fence();
2461 if (print_timings) result.print_size("result after apply_only");
2462
2463 // svd-tensors need some post-processing
2464 if (result.get_impl()->get_tensor_type()==TT_2D) {
2465 double elapsed=result.get_impl()->finalize_apply();
2466 if (print_timings) printf("time in finalize_apply %8.2f\n",elapsed);
2467 }
2468 if (print_timings) {
2469 result.get_impl()->print_timer();
2470 op.print_timer();
2471 }
2472
2473 result.get_impl()->reconstruct(true);
2474
2475// fff.clear();
2476 if (op.destructive()) {
2477 ff.world().gop.fence();
2478 ff.clear();
2479 } else {
2480 // ff.standard();
2481 ff.reconstruct();
2482 }
2483
2484 }
2485 if (print_timings) result.print_size("result after reconstruction");
2486 return result;
2487 }
2488
2489
2490 template <typename opT, typename R, std::size_t NDIM>
2491 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM>
2492 apply_1d_realspace_push(const opT& op, const Function<R,NDIM>& f, int axis, bool fence=true) {
2494 Function<R,NDIM>& ff = const_cast< Function<R,NDIM>& >(f);
2495 if (VERIFY_TREE) ff.verify_tree();
2496 ff.reconstruct();
2497
2498 Function<TENSOR_RESULT_TYPE(typename opT::opT,R), NDIM> result;
2499
2500 result.set_impl(ff, false);
2501 result.get_impl()->apply_1d_realspace_push(op, ff.get_impl().get(), axis, fence);
2502 result.get_impl()->set_tree_state(redundant_after_merge);
2503 return result;
2504 }
2505
2506
2507 /// Generate a new function by reordering dimensions ... optional fence
2508
2509 /// You provide an array of dimension NDIM that maps old to new dimensions
2510 /// according to
2511 /// \code
2512 /// newdim = mapdim[olddim]
2513 /// \endcode
2514 /// Works in either scaling function or wavelet basis.
2515 ///
2516 /// Would be easy to modify this to also change the procmap here
2517 /// if desired but presently it uses the same procmap as f.
2518 template <typename T, std::size_t NDIM>
2520 mapdim(const Function<T,NDIM>& f, const std::vector<long>& map, bool fence=true) {
2522 Function<T,NDIM> result;
2523 return result.mapdim(f,map,fence);
2524 }
2525
2526 /// Generate a new function by mirroring within the dimensions .. optional fence
2527
2528 /// similar to mapdim
2529 /// @param[in] mirror array with -1 and 1, corresponding to mirror this dimension or not
2530 template <typename T, std::size_t NDIM>
2532 mirror(const Function<T,NDIM>& f, const std::vector<long>& mirrormap, bool fence=true) {
2534 Function<T,NDIM> result;
2535 return result.mirror(f,mirrormap,fence);
2536 }
2537
2538 /// This is replaced with mirror(map(f)), optional fence
2539
2540 /// first map then mirror!
2541 /// mirror is similar to mapdim, but maps from x to -x, y to -y, and so on
2542 /// Example: mirror a 3d function on the xy plane: mirror={1,1,-1}
2543 /// Example: c4 rotation of a 3d function around the z axis:
2544 /// x->y, y->-x, z->z: map(1,0,2); mirror(-1,1,1)
2545 /// @param[in] map array holding dimensions
2546 /// @param[in] mirror array of -1 and 1, corresponding to mirror or not
2547 template <typename T, std::size_t NDIM>
2549 map_and_mirror(const Function<T,NDIM>& f, const std::vector<long>& map,
2550 const std::vector<long>& mirror, bool fence=true) {
2552 Function<T,NDIM> result;
2553 return result.map_and_mirror(f,map,mirror,fence);
2554 }
2555
2556
2557 /// swap particles 1 and 2
2558
2559 /// param[in] f a function of 2 particles f(1,2)
2560 /// return the input function with particles swapped g(1,2) = f(2,1)
2561 template <typename T, std::size_t NDIM>
2562 typename std::enable_if_t<NDIM%2==0, Function<T,NDIM>>
2564 // this could be done more efficiently for SVD, but it works decently
2565 std::vector<long> map(NDIM);
2566 constexpr std::size_t LDIM=NDIM/2;
2567 static_assert(LDIM*2==NDIM);
2568 for (std::size_t d=0; d<LDIM; ++d) {
2569 map[d]=d+LDIM;
2570 map[d+LDIM]=d;
2571 }
2572// map[0]=3;
2573// map[1]=4;
2574// map[2]=5; // 2 -> 1
2575// map[3]=0;
2576// map[4]=1;
2577// map[5]=2; // 1 -> 2
2578 return mapdim(f,map);
2579 }
2580
2581 /// symmetrize a function
2582
2583 /// @param[in] symmetry possibilities are:
2584 /// (anti-) symmetric particle permutation ("sy_particle", "antisy_particle")
2585 /// symmetric mirror plane ("xy", "xz", "yz")
2586 /// @return a new function symmetrized according to the input parameter
2587 template <typename T, std::size_t NDIM>
2589 symmetrize(const Function<T,NDIM>& f, const std::string symmetry, bool fence=true) {
2590 Function<T,NDIM> result;
2591
2592 MADNESS_ASSERT(NDIM==6); // works only for pair functions
2593 std::vector<long> map(NDIM);
2594
2595 // symmetric particle permutation
2596 if (symmetry=="sy_particle") {
2597 map[0]=3; map[1]=4; map[2]=5;
2598 map[3]=0; map[4]=1; map[5]=2;
2599 } else if (symmetry=="cx") {
2600 map[0]=0; map[1]=2; map[2]=1;
2601 map[3]=3; map[4]=5; map[5]=4;
2602
2603 } else if (symmetry=="cy") {
2604 map[0]=2; map[1]=1; map[2]=0;
2605 map[3]=5; map[4]=4; map[5]=3;
2606
2607 } else if (symmetry=="cz") {
2608 map[0]=1; map[1]=0; map[2]=2;
2609 map[3]=4; map[4]=3; map[5]=5;
2610
2611 } else {
2612 if (f.world().rank()==0) {
2613 print("unknown parameter in symmetrize:",symmetry);
2614 }
2615 MADNESS_EXCEPTION("unknown parameter in symmetrize",1);
2616 }
2617
2618 result.mapdim(f,map,true); // need to fence here
2619 result.get_impl()->average(*f.get_impl());
2620
2621 return result;
2622 }
2623
2624
2625
2626 /// multiply a high-dimensional function with a low-dimensional function
2627
2628 /// @param[in] f NDIM function of 2 particles: f=f(1,2)
2629 /// @param[in] g LDIM function of 1 particle: g=g(1) or g=g(2)
2630 /// @param[in] particle if g=g(1) or g=g(2)
2631 /// @return h(1,2) = f(1,2) * g(p)
2632 template<typename T, std::size_t NDIM, std::size_t LDIM>
2633 Function<T,NDIM> multiply(const Function<T,NDIM> f, const Function<T,LDIM> g, const int particle, const bool fence=true) {
2634
2635 static_assert(LDIM+LDIM==NDIM);
2637
2638 Function<T,NDIM> result;
2639 result.set_impl(f, false);
2640
2641// Function<T,NDIM>& ff = const_cast< Function<T,NDIM>& >(f);
2642// Function<T,LDIM>& gg = const_cast< Function<T,LDIM>& >(g);
2643
2644 f.change_tree_state(redundant,false);
2645 g.change_tree_state(redundant,false);
2646 // neither call is fenced, and either may be a no-op if the function already is
2647 // redundant -- fence explicitly before the trees are traversed
2648 result.world().gop.fence();
2649 FunctionImpl<T,NDIM>* fimpl=f.get_impl().get();
2650 FunctionImpl<T,LDIM>* gimpl=g.get_impl().get();
2651
2652 result.get_impl()->multiply(fimpl,gimpl,particle);
2653 result.world().gop.fence();
2654
2655 f.change_tree_state(reconstructed,false);
2656 g.change_tree_state(reconstructed);
2657 return result;
2658 }
2659
2660
2661 /// build result = Σ_t (ket_t · factor1_t(1) · factor2_t(2) · extra_t(1,2)) adaptively
2662 ///
2663 /// Each term's ket is either an explicit NDIM Function (`term.ket`) or a sum of
2664 /// hartree products ket_t(1,2) = Σ_k p1[k](1) ⊗ p2[k](2). factor1 / factor2 are
2665 /// optional single LDIM factors; extra is an optional NDIM factor (typically an
2666 /// on-demand ERI).
2667 ///
2668 /// Subsumes:
2669 /// - multiply(f,g,particle) : one term, factor1 or factor2
2670 /// - make_Vphi(...) : sum of three terms with shared ket
2671 /// - make_Vphi_ij_u(...) : one term, factor1=i, factor2=j
2672 ///
2673 /// Inputs are brought into redundant state internally; the result is reconstructed.
2674 /// `target_precision`: error threshold; 0 → use the result's thresh.
2675 /// `oversampling`: additional quadrature points for pointwise_multiplier.
2676 template <typename T, std::size_t NDIM>
2678 std::vector<composite_term<T,NDIM>> terms,
2679 double target_precision = 0.0,
2680 int oversampling = 1,
2681 bool fence = true) {
2682 MADNESS_ASSERT(!terms.empty());
2683
2684 // model the result tree shape on the first available NDIM impl, or fall back
2685 // to constructing an empty Function from defaults when only hartree pairs are given.
2686 Function<T,NDIM> result;
2687 if (terms.front().ket.is_initialized()) {
2688 result.set_impl(terms.front().ket, false);
2689 } else {
2690 MADNESS_ASSERT(!terms.front().p1.empty());
2692 }
2693
2695 Leaf leaf_op(result.get_impl().get());
2696
2698 target_precision, oversampling, fence);
2699 return result;
2700 }
2701
2702 /// Overload taking a polymorphic LeafOpBase for fine-grained tree-structure control.
2703 ///
2704 /// The caller-provided `leaf_op` lets you drive a cuspy box (ElectronCuspyBox_op,
2705 /// NuclearCuspyBox_op), a custom Specialbox_op, or a screening operator through
2706 /// the composite product's per-key refinement decisions.
2707 ///
2708 /// Lifetime: `leaf_op` must outlive this call.
2709 template <typename T, std::size_t NDIM>
2711 std::vector<composite_term<T,NDIM>> terms,
2713 double target_precision = 0.0,
2714 int oversampling = 1,
2715 bool fence = true) {
2716 MADNESS_ASSERT(!terms.empty());
2717
2718 Function<T,NDIM> result;
2719 if (terms.front().ket.is_initialized()) {
2720 result.set_impl(terms.front().ket, false);
2721 } else {
2722 MADNESS_ASSERT(!terms.front().p1.empty());
2724 }
2725
2726 LeafOpRef<T,NDIM> leaf_ref(leaf_op);
2728 result.get_impl().get(), leaf_ref, terms,
2729 target_precision, oversampling, fence);
2730 return result;
2731 }
2732
2733 /// compute <bra | Σ_t (ket_t · factor1_t · factor2_t)> adaptively
2734 ///
2735 /// `bra` may be on-demand (e.g., an ERI functor) or a regular tree-resident NDIM
2736 /// Function. Per-term `extra` is not allowed in inner mode (route extras through
2737 /// the bra instead).
2738 template <typename T, std::size_t NDIM>
2740 std::vector<composite_term<T,NDIM>> terms,
2741 Function<T,NDIM> bra,
2742 double target_precision = 0.0,
2743 int oversampling = 1) {
2744 MADNESS_CHECK_THROW(!terms.empty(),
2745 "composite_inner: terms list must not be empty");
2747 "composite_inner: bra Function must be initialised");
2748
2749 // pick a sibling impl to model the accumulator's pmap / thresh / k
2750 const FunctionImpl<T,NDIM>* like = nullptr;
2751 if (terms.front().ket.is_initialized()) {
2752 like = terms.front().ket.get_impl().get();
2753 } else if (bra.is_initialized() && !bra.is_on_demand()) {
2754 like = bra.get_impl().get();
2755 }
2757 "composite_inner: cannot model accumulator — provide a ket in the first term, "
2758 "or a non-on-demand bra");
2759
2761 Leaf leaf_op(const_cast<FunctionImpl<T,NDIM>*>(like));
2762
2764 bra,
2765 target_precision, oversampling);
2766 }
2767
2768 /// Overload taking a polymorphic LeafOpBase for fine-grained refinement control.
2769 template <typename T, std::size_t NDIM>
2771 std::vector<composite_term<T,NDIM>> terms,
2772 Function<T,NDIM> bra,
2774 double target_precision = 0.0,
2775 int oversampling = 1) {
2776 MADNESS_CHECK_THROW(!terms.empty(),
2777 "composite_inner: terms list must not be empty");
2779 "composite_inner: bra Function must be initialised");
2780
2781 const FunctionImpl<T,NDIM>* like = nullptr;
2782 if (terms.front().ket.is_initialized()) {
2783 like = terms.front().ket.get_impl().get();
2784 } else if (bra.is_initialized() && !bra.is_on_demand()) {
2785 like = bra.get_impl().get();
2786 }
2788 "composite_inner: cannot model accumulator — provide a ket in the first term, "
2789 "or a non-on-demand bra");
2790
2791 LeafOpRef<T,NDIM> leaf_ref(leaf_op);
2793 world, like, leaf_ref, terms, bra,
2794 target_precision, oversampling);
2795 }
2796
2797
2798 template <typename T, std::size_t NDIM>
2803 bool fence=true)
2804 {
2807 other.reconstruct();
2808 result.get_impl()->project(*other.get_impl(),fence);
2809 return result;
2810 }
2811
2812
2813 /// Computes the scalar/inner product between two functions
2814
2815 /// In Maple this would be \c int(conjugate(f(x))*g(x),x=-infinity..infinity)
2816 template <typename T, typename R, std::size_t NDIM>
2819 return f.inner(g);
2820 }
2821
2822
2823 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2824
2825 /// syntax similar to the inner product in tensor.h
2826 /// e.g result=inner<3>(f,g),{0},{1}) : r(x,y) = int f(x1,x) g(y,x1) dx1
2827 /// @param[in] task 0: everything, 1; prepare only (fence), 2: work only (no fence), 3: finalize only (fence)
2828 template<std::size_t NDIM, typename T, std::size_t LDIM, typename R, std::size_t KDIM,
2829 std::size_t CDIM = (KDIM + LDIM - NDIM) / 2>
2830 std::vector<Function<TENSOR_RESULT_TYPE(T, R), NDIM>>
2831 innerXX(const Function<T, LDIM>& f, const std::vector<Function<R, KDIM>>& vg, const std::array<int, CDIM> v1,
2832 const std::array<int, CDIM> v2, int task=0) {
2833 bool prepare = ((task==0) or (task==1));
2834 bool work = ((task==0) or (task==2));
2835 bool finish = ((task==0) or (task==3));
2836
2837 static_assert((KDIM + LDIM - NDIM) % 2 == 0, "faulty dimensions in inner (partial version)");
2838 static_assert(KDIM + LDIM - 2 * CDIM == NDIM, "faulty dimensions in inner (partial version)");
2839
2840 // contraction indices must be contiguous and either in the beginning or at the end
2841 for (size_t i=0; i<CDIM-1; ++i) MADNESS_CHECK((v1[i]+1)==v1[i+1]);
2842 MADNESS_CHECK((v1[0]==0) or (v1[CDIM-1]==LDIM-1));
2843
2844 for (size_t i=0; i<CDIM-1; ++i) MADNESS_CHECK((v2[i]+1)==v2[i+1]);
2845 MADNESS_CHECK((v2[0]==0) or (v2[CDIM-1]==KDIM-1));
2846
2847 MADNESS_CHECK(f.is_initialized());
2849 MADNESS_CHECK(f.world().id() == vg[0].world().id());
2850 // this needs to be run in a single world, so that all coefficients are local.
2851 // Use macrotasks if run on multiple processes.
2852 World& world=f.world();
2853 MADNESS_CHECK(world.size() == 1);
2854
2855 if (prepare) {
2856 f.change_tree_state(nonstandard);
2858 world.gop.fence();
2859 f.get_impl()->compute_snorm_and_dnorm(false);
2860 for (auto& g : vg) g.get_impl()->compute_snorm_and_dnorm(false);
2861 world.gop.fence();
2862 }
2863
2864 typedef TENSOR_RESULT_TYPE(T, R) resultT;
2865 std::vector<Function<resultT,NDIM>> result(vg.size());
2866 if (work) {
2868 for (size_t i=0; i<vg.size(); ++i) {
2870 .k(f.k()).thresh(f.thresh()).empty().nofence();
2871 result[i].get_impl()->partial_inner(*f.get_impl(),*(vg[i]).get_impl(),v1,v2);
2872 result[i].get_impl()->set_tree_state(nonstandard_after_apply);
2873 }
2874 world.gop.set_forbid_fence(false);
2875 }
2876
2877 if (finish) {
2878
2879 world.gop.fence();
2880// result.get_impl()->reconstruct(true);
2881
2883// result.reconstruct();
2884 // restore initial state of g and h
2885 auto erase_list = [] (const auto& funcimpl) {
2886 typedef typename std::decay_t<decltype(funcimpl)>::keyT keyTT;
2887 std::list<keyTT> to_be_erased;
2888 for (auto it=funcimpl.get_coeffs().begin(); it!=funcimpl.get_coeffs().end(); ++it) {
2889 const auto& key=it->first;
2890 const auto& node=it->second;
2891 if (not node.has_children()) to_be_erased.push_back(key);
2892 }
2893 return to_be_erased;
2894 };
2895
2896 FunctionImpl<T,LDIM>& f_nc=const_cast<FunctionImpl<T,LDIM>&>(*f.get_impl());
2897 for (auto& key : erase_list(f_nc)) f_nc.get_coeffs().erase(key);
2898 for (auto& g : vg) {
2899 FunctionImpl<R,KDIM>& g_nc=const_cast<FunctionImpl<R,KDIM>&>(*g.get_impl());
2900 for (auto& key : erase_list(g_nc)) g_nc.get_coeffs().erase(key);
2901 }
2902 world.gop.fence();
2904 f_nc.reconstruct(false);
2905 world.gop.fence();
2906
2907 }
2908
2909 return result;
2910 }
2911
2912
2913 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2914
2915 /// syntax similar to the inner product in tensor.h
2916 /// e.g result=inner<3>(f,g),{0},{1}) : r(x,y) = int f(x1,x) g(y,x1) dx1
2917 /// @param[in] task 0: everything, 1; prepare only (fence), 2: work only (no fence), 3: finalize only (fence)
2918 template<std::size_t NDIM, typename T, std::size_t LDIM, typename R, std::size_t KDIM,
2919 std::size_t CDIM = (KDIM + LDIM - NDIM) / 2>
2921 innerXX(const Function<T, LDIM>& f, const Function<R, KDIM>& g, const std::array<int, CDIM> v1,
2922 const std::array<int, CDIM> v2, int task=0) {
2923 return innerXX<NDIM,T,LDIM,R,KDIM>(f,std::vector<Function<R,KDIM>>({g}),v1,v2,task)[0];
2924 }
2925
2926 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2927
2928 /// syntax similar to the inner product in tensor.h
2929 /// e.g result=inner<3>(f,g),{0},{1}) : r(x,y) = int f(x1,x) g(y,x1) dx1
2930 template <typename T, std::size_t LDIM, typename R, std::size_t KDIM>
2932 inner(const Function<T,LDIM>& f, const Function<R,KDIM>& g, const std::tuple<int> v1, const std::tuple<int> v2) {
2933 return innerXX<KDIM+LDIM-2>(f,g,
2934 std::array<int,1>({std::get<0>(v1)}),
2935 std::array<int,1>({std::get<0>(v2)}));
2936 }
2937
2938 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2939
2940 /// syntax similar to the inner product in tensor.h
2941 /// e.g result=inner<3>(f,g),{0,1},{1,2}) : r(y) = int f(x1,x2) g(y,x1,x2) dx1 dx2
2942 template <typename T, std::size_t LDIM, typename R, std::size_t KDIM>
2944 inner(const Function<T,LDIM>& f, const Function<R,KDIM>& g, const std::tuple<int,int> v1, const std::tuple<int,int> v2) {
2945 return innerXX<KDIM+LDIM-4>(f,g,
2946 std::array<int,2>({std::get<0>(v1),std::get<1>(v1)}),
2947 std::array<int,2>({std::get<0>(v2),std::get<1>(v2)}));
2948 }
2949
2950 /// Computes the partial scalar/inner product between two functions, returns a low-dim function
2951
2952 /// syntax similar to the inner product in tensor.h
2953 /// e.g result=inner<3>(f,g),{1},{2}) : r(x,y,z) = int f(x,x1) g(y,z,x1) dx1
2954 template <typename T, std::size_t LDIM, typename R, std::size_t KDIM>
2956 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) {
2957 return innerXX<KDIM+LDIM-6>(f,g,
2958 std::array<int,3>({std::get<0>(v1),std::get<1>(v1),std::get<2>(v1)}),
2959 std::array<int,3>({std::get<0>(v2),std::get<1>(v2),std::get<2>(v2)}));
2960 }
2961
2962
2963
2964 /// Computes the scalar/inner product between an MRA function and an external functor
2965
2966 /// Currently this defaults to inner_adaptive, which might be more expensive
2967 /// than inner_ext since it loops over all leaf nodes. If you feel inner_ext
2968 /// is more efficient you need to call it directly
2969 /// @param[in] f MRA function
2970 /// @param[in] g functor
2971 /// @result inner(f,g)
2972 template <typename T, typename opT, std::size_t NDIM>
2973 TENSOR_RESULT_TYPE(T,typename opT::value_type) inner(const Function<T,NDIM>& f, const opT& g) {
2975 std::shared_ptr< FunctionFunctorInterface<double,3> > func(new opT(g));
2976 return f.inner_adaptive(func);
2977 }
2978
2979 /// Computes the scalar/inner product between an MRA function and an external functor
2980
2981 /// Currently this defaults to inner_adaptive, which might be more expensive
2982 /// than inner_ext since it loops over all leaf nodes. If you feel inner_ext
2983 /// is more efficient you need to call it directly
2984 /// @param[in] g functor
2985 /// @param[in] f MRA function
2986 /// @result inner(f,g)
2987 template <typename T, typename opT, std::size_t NDIM>
2988 TENSOR_RESULT_TYPE(T,typename opT::value_type) inner(const opT& g, const Function<T,NDIM>& f) {
2989 return inner(f,g);
2990 }
2991
2992 template <typename T, typename R, std::size_t NDIM>
2993 typename IsSupported<TensorTypeData<R>, Function<TENSOR_RESULT_TYPE(T,R),NDIM> >::type
2995 return (f*R(1.0)).add_scalar(r);
2996 }
2997
2998 template <typename T, typename R, std::size_t NDIM>
2999 typename IsSupported<TensorTypeData<R>, Function<TENSOR_RESULT_TYPE(T,R),NDIM> >::type
3001 return (f*R(1.0)).add_scalar(r);
3002 }
3003
3004 template <typename T, typename R, std::size_t NDIM>
3005 typename IsSupported<TensorTypeData<R>, Function<TENSOR_RESULT_TYPE(T,R),NDIM> >::type
3007 return (f*R(1.0)).add_scalar(-r);
3008 }
3009
3010 template <typename T, typename R, std::size_t NDIM>
3011 typename IsSupported<TensorTypeData<R>, Function<TENSOR_RESULT_TYPE(T,R),NDIM> >::type
3013 return (f*R(-1.0)).add_scalar(r);
3014 }
3015
3016 namespace detail {
3017 template <std::size_t NDIM>
3018 struct realop {
3019 typedef double resultT;
3021 return real(t);
3022 }
3023
3024 template <typename Archive> void serialize (Archive& ar) {}
3025 };
3026
3027 template <std::size_t NDIM>
3028 struct imagop {
3029 typedef double resultT;
3031 return imag(t);
3032 }
3033
3034 template <typename Archive> void serialize (Archive& ar) {}
3035 };
3036
3037 template <std::size_t NDIM>
3038 struct abssqop {
3039 typedef double resultT;
3041 Tensor<double> r = abs(t);
3042 return r.emul(r);
3043 }
3044
3045 template <typename Archive> void serialize (Archive& ar) {}
3046 };
3047
3048 template <std::size_t NDIM>
3049 struct absop {
3050 typedef double resultT;
3052 Tensor<double> r = abs(t);
3053 return r;
3054 }
3055
3056 template <typename Archive> void serialize (Archive& ar) {}
3057 };
3058
3059 }
3060
3061 /// Returns a new function that is the real part of the input
3062 template <std::size_t NDIM>
3066
3067 /// Returns a new function that is the real part of the input
3068 template <std::size_t NDIM>
3070 return copy(z);
3071 }
3072
3073 /// Returns a new function that is the imaginary part of the input
3074 template <std::size_t NDIM>
3078
3079
3080 /// Create a new function that is the square of f - global comm only if not reconstructed
3081 template <typename T, std::size_t NDIM>
3084 Function<T,NDIM> result = copy(f,true); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3085 return result.square(true); //fence); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3086 }
3087
3088 /// Create a new function that is the abs of f - global comm only if not reconstructed
3089 template <typename T, std::size_t NDIM>
3092 Function<T,NDIM> result = copy(f,true); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3093 return result.abs(true); //fence); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3094 }
3095
3096 /// Create a new function that is the abs_square of f - global comm only if not reconstructed
3097 template <typename T, std::size_t NDIM>
3098 typename std::enable_if<!TensorTypeData<T>::iscomplex, Function<T,NDIM> >::type
3099 abs_square(const Function<T,NDIM>& f, bool fence=true) {
3101 Function<T,NDIM> result = copy(f,true); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3102 return result.abs_square(true); //fence); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3103 }
3104
3105 /// Create a new function that is the abs_square of f - global comm only if not reconstructed
3106 template <typename T, std::size_t NDIM>
3107 typename std::enable_if<TensorTypeData<T>::iscomplex, Function<typename Tensor<T>::scalar_type,NDIM> >::type
3108 abs_square(const Function<T,NDIM>& f, bool fence=true) {
3110 }
3111
3112 /// Returns a new function that is the square of the absolute value of the input
3113 template <std::size_t NDIM>
3117
3118 /// Returns a new function that is the absolute value of the input
3119 template <std::size_t NDIM>
3123
3124 /// get tree state of a function
3125
3126 /// there is a corresponding function in vmra.h
3127 /// @param[in] f function
3128 /// @return TreeState::unknown if the function is not initialized
3129 template <typename T, std::size_t NDIM>
3131 if (f.is_initialized()) return f.get_impl()->get_tree_state();
3132 return TreeState::unknown;
3133 }
3134
3135 /// change tree state of a function
3136
3137 /// there is a corresponding function in vmra.h
3138 /// return this for chaining
3139 /// @param[in] f function
3140 /// @param[in] finalstate the new state
3141 /// @return this in the requested state
3142 template <typename T, std::size_t NDIM>
3144 const TreeState finalstate, bool fence=true) {
3145 return f.change_tree_state(finalstate,fence);
3146 }
3147
3148 template <typename R, std::size_t MDIM>
3150 f1.impl.swap(f2.impl);
3151 }
3152
3153}
3154
3155#include <madness/mra/funcplot.h>
3156
3157namespace madness {
3158 namespace archive {
3159 template <class archiveT, class T, std::size_t NDIM>
3161 static inline void load(const ParallelInputArchive<archiveT>& ar, Function<T,NDIM>& f) {
3162 f.load(*ar.get_world(), ar);
3163 }
3164 };
3165
3166 template <class archiveT, class T, std::size_t NDIM>
3168 static inline void store(const ParallelOutputArchive<archiveT>& ar, const Function<T,NDIM>& f) {
3169 f.store(ar);
3170 }
3171 };
3172 }
3173
3174 template <class T, std::size_t NDIM>
3175 void save(const Function<T,NDIM>& f, const std::string name) {
3177 ar2 & f;
3178 }
3179
3180 template <class T, std::size_t NDIM>
3181 void load(Function<T,NDIM>& f, const std::string name) {
3183 ar2 & f;
3184 }
3185
3186}
3187
3188namespace madness {
3189 // type traits to check if a template parameter is a Function
3190 template<typename>
3191 struct is_madness_function : std::false_type {};
3192
3193 template<typename T, std::size_t NDIM>
3194 struct is_madness_function<madness::Function<T, NDIM>> : std::true_type {};
3195
3196}
3197
3198
3199/* @} */
3200
3201#include <madness/mra/derivative.h>
3202#include <madness/mra/operator.h>
3204#include <madness/mra/vmra.h>
3205// #include <madness/mra/mraimpl.h> !!!!!!!!!!!!! NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO !!!!!!!!!!!!!!!!!!
3206
3207#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.
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
static int get_k()
Returns the default wavelet order.
Definition funcdefaults.h:170
static const double & get_thresh()
Returns the default threshold.
Definition funcdefaults.h:183
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:415
static const BoundaryConditions< NDIM > & get_bc()
Returns the default boundary conditions.
Definition funcdefaults.h:315
static void set_cell(const Tensor< double > &value)
Sets the user cell for the simulation.
Definition funcdefaults.h:374
static const Tensor< double > & get_cell()
Gets the user cell for the simulation.
Definition funcdefaults.h:352
FunctionFactory implements the named-parameter idiom for Function.
Definition function_factory.h:86
FunctionFactory & nofence()
Definition function_factory.h:282
virtual FunctionFactory & thresh(double thresh)
Definition function_factory.h:198
FunctionFactory & fence(bool fence=true)
Definition function_factory.h:276
virtual FunctionFactory & k(int k)
Definition function_factory.h:193
FunctionFactory & empty()
Definition function_factory.h:246
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:1043
const dcT & get_coeffs() const
Definition mraimpl.h:355
void reconstruct(bool fence)
reconstruct this tree – respects fence
Definition mraimpl.h:1584
bool is_on_demand() const
Definition mraimpl.h:285
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:141
void print_tree_json(std::ostream &os=std::cout) const
Definition mra.h:1043
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:412
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:1879
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:1575
T inner_adaptive(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > f, const bool leaf_refine=true) const
Definition mra.h:1560
void unaryop_coeff(const opT &op, bool fence=true)
Unary operation applied inplace to the coefficients.
Definition mra.h:1093
bool is_compressed() const
Returns true if compressed, false otherwise. No communication.
Definition mra.h:544
Function< T, NDIM/2 > dirac_convolution(const bool fence=true) const
Definition mra.h:1639
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:758
bool autorefine() const
Returns value of autorefine flag. No communication.
Definition mra.h:655
TreeState operating_state
Definition mra.h:1501
Function< T, NDIM > & add_scalar(T t, bool fence=true)
Inplace add scalar. No communication except for optional fence.
Definition mra.h:1142
void print_size(const std::string name) const
print some info about this
Definition mra.h:595
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:1347
void broaden(const BoundaryConditions< NDIM > &bc=FunctionDefaults< NDIM >::get_bc(), bool fence=true) const
Inplace broadens support in scaling function basis.
Definition mra.h:1015
void print_info() const
Print a summary of the load balancing info.
Definition mra.h:1059
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:1132
void norm_tree(bool fence=true) const
Initializes information about the function norm at all length scales.
Definition mra.h:872
void load(World &world, Archive &ar)
Replaces this function with one loaded from an archive using the default processor map.
Definition mra.h:1656
Function< T, NDIM > & abs_square(bool fence=true)
Returns *this for chaining.
Definition mra.h:1269
void replicate(const DistributionType type, bool fence=true) const
Definition mra.h:784
double norm2sq_local() const
Returns the square of the norm of the local function ... no communication.
Definition mra.h:826
IsSupported< TensorTypeData< Q >, Function< T, NDIM > >::type & operator*=(const Q q)
Inplace scaling by a constant.
Definition mra.h:1241
void sum_down(bool fence=true) const
Sums scaling coeffs down tree restoring state with coeffs only at leaves. Optional fence....
Definition mra.h:973
Level depthpt(const coordT &xuser) const
Definition mra.h:488
bool is_redundant() const
Returns true if redundant, false otherwise. No communication.
Definition mra.h:574
Function< T, NDIM > & operator+=(const Function< Q, NDIM > &other)
Inplace addition of functions in the wavelet basis.
Definition mra.h:1201
Function< T, NDIM > & operator=(const Function< T, NDIM > &f)
Assignment is shallow. No communication, works in either basis.
Definition mra.h:193
void set_autorefine(bool value, bool fence=true)
Sets the value of the autorefine flag. Optional global fence.
Definition mra.h:665
World & world() const
Returns the world.
Definition mra.h:764
T trace() const
Returns global value of int(f(x),x) ... global comm required.
Definition mra.h:1302
double typeT
Definition mra.h:159
friend void swap(Function< R, MDIM > &f1, Function< R, MDIM > &f2)
implements swap algorithm
Definition mra.h:3149
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:1365
const Function< T, NDIM > & change_tree_state(const TreeState finalstate, bool fence=true) const
changes tree state to given state
Definition mra.h:960
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:1714
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:1049
double norm2() const
Returns the 2-norm of the function ... global sum ... works in either basis.
Definition mra.h:853
Function< T, NDIM > & fill_cuspy_tree(const opT &op, const bool fence=true)
Definition mra.h:1388
void change_tensor_type(const TensorArgs &targs, bool fence=true)
change the tensor type of the coefficients in the FunctionNode
Definition mra.h:1706
const Function< T, NDIM > & refine(bool fence=true) const
Inplace autorefines the function using same test as for squaring.
Definition mra.h:1005
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:453
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:1251
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:1376
void verify_tree() const
Verifies the tree data structure ... global sync implied.
Definition mra.h:535
Future< Level > evaldepthpt(const coordT &xuser) const
Definition mra.h:334
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:1457
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:1845
int k() const
Returns the number of multiwavelets (k). No communication.
Definition mra.h:702
const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > & get_pmap() const
Returns a shared pointer to the process map.
Definition mra.h:772
double thresh() const
Returns value of truncation threshold. No communication.
Definition mra.h:674
void set_truncate_mode(int value)
Definition mra.h:694
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:1831
void set_thresh(double value, bool fence=true)
Sets the value of the truncation threshold. Optional global fence.
Definition mra.h:684
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:1736
void distribute(std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > newmap) const
distribute this function according to newmap
Definition mra.h:816
void unaryop(const opT &op, bool fence=true)
Inplace unary operation on function values.
Definition mra.h:1083
const std::shared_ptr< FunctionImpl< T, NDIM > > & get_impl() const
Returns a shared-pointer to the implementation.
Definition mra.h:730
void standard(bool fence=true)
Converts the function standard compressed form. Possible non-blocking comm.
Definition mra.h:919
void unaryop_node(const opT &op, bool fence=true)
Unary operation applied inplace to the nodes.
Definition mra.h:1103
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:718
Function< T, NDIM > & fill_cuspy_tree(const bool fence=true)
Special refinement on 6D boxes where the electrons come close (meet).
Definition mra.h:1401
std::size_t size() const
Returns the number of coefficients in the function ... collective global sum.
Definition mra.h:640
bool is_on_demand() const
Definition mra.h:752
Function< T, NDIM > & operator-=(const Function< Q, NDIM > &other)
Inplace subtraction of functions in the wavelet basis.
Definition mra.h:1220
bool compressed
Definition mra.h:1323
const Function< T, NDIM > & reconstruct(bool fence=true) const
Reconstructs the function, transforming into scaling function basis. Possible non-blocking comm.
Definition mra.h:950
Function< T, NDIM > & abs(bool fence=true)
Returns *this for chaining.
Definition mra.h:1260
Function< T, NDIM > & reduce_rank(const double thresh=0.0, const bool fence=true)
reduce the rank of the coefficient tensors
Definition mra.h:1909
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:1860
std::size_t max_nodes() const
Returns the max number of nodes on a processor.
Definition mra.h:625
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:1443
std::shared_ptr< FunctionImpl< double, NDIM > > impl
Definition mra.h:148
void replicate_on_hosts(bool fence=true) const
Definition mra.h:809
void replicate(bool fence=true) const
Definition mra.h:797
T trace_local() const
Returns local contribution to int(f(x),x) ... no communication.
Definition mra.h:1282
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:1802
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:1162
Vector< double, NDIM > coordT
Definition mra.h:158
void store(Archive &ar) const
Stores the function to an archive.
Definition mra.h:1694
std::size_t max_local_depth() const
Returns the maximum local depth of the function tree ... no communications.
Definition mra.h:617
MADNESS_CHECK_THROW(compressed or redundant,"functions must be compressed or redundant in inner")
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:1820
impl world gop sum(local)
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:604
Function()
Default constructor makes uninitialized function. No communication.
Definition mra.h:176
std::vector< std::pair< bool, T > > eval_local_only(const std::vector< coordT > &xuser, Level maxlevel) const
Definition mra.h:322
std::size_t tree_size() const
Returns the number of nodes in the function tree ... collective global sum.
Definition mra.h:588
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:1615
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:1727
FunctionImpl< double, NDIM > implT
Definition mra.h:155
void clear(bool fence=true)
Clears the function as if constructed uninitialized. Optional fence.
Definition mra.h:1026
void refine_general(const opT &op, bool fence=true) const
Inplace autorefines the function. Optional fence. Possible non-blocking comm.
Definition mra.h:986
static void doconj(const Key< NDIM >, Tensor< T > &t)
Definition mra.h:1113
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:247
TENSOR_RESULT_TYPE(double, R) inner_local(const Function< R
void set_functor(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > functor)
Replace the current functor with the provided new one.
Definition mra.h:747
bool impl_initialized() const
Definition mra.h:151
Function< T, NDIM > & fill_nuclear_cuspy_tree(const opT &op, const size_t particle, const bool fence=true)
Definition mra.h:1416
bool is_redundant_after_merge() const
Returns true if redundant_after_merge, false otherwise. No communication.
Definition mra.h:582
return local
Definition mra.h:1516
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:287
auto func
Definition mra.h:1594
~Function()
Destruction of any underlying implementation is deferred to next global fence.
Definition mra.h:200
Function(const Function< T, NDIM > &f)
Copy constructor is shallow. No communication, works in either basis.
Definition mra.h:187
void set_impl(const std::shared_ptr< FunctionImpl< T, NDIM > > &impl)
Replace current FunctionImpl with provided new one.
Definition mra.h:737
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:467
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:1527
std::size_t min_nodes() const
Returns the min number of nodes on a processor.
Definition mra.h:632
void make_redundant(bool fence=true) const
Converts the function to redundant form, i.e. sum coefficients on all levels.
Definition mra.h:935
constexpr std::size_t LDIM
Definition mra.h:1593
static constexpr std::size_t dimT
Definition mra.h:160
change_tree_state(operating_state, false)
bool is_nonstandard() const
Returns true if nonstandard-compressed, false otherwise. No communication.
Definition mra.h:566
void verify() const
Asserts that the function is initialized.
Definition mra.h:164
double err(const funcT &func) const
Returns an estimate of the difference ||this-func|| ... global sum performed.
Definition mra.h:522
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:1543
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:1429
double check_symmetry() const
check symmetry of a function by computing the 2nd derivative
Definition mra.h:1895
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:1755
FunctionFactory< double, NDIM > factoryT
Definition mra.h:157
std::size_t size_local() const
Return the number of coefficients in the function on this processor.
Definition mra.h:647
const Function< T, NDIM > & compress(bool fence=true) const
Compresses the function, transforming into wavelet basis. Possible non-blocking comm.
Definition mra.h:892
bool is_initialized() const
Returns true if the function is initialized.
Definition mra.h:169
bool is_reconstructed() const
Returns true if reconstructed, false otherwise. No communication.
Definition mra.h:555
Function< T, NDIM > & chop_at_level(const int n, const bool fence=true)
remove all nodes with level higher than n
Definition mra.h:1917
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:1776
double errsq_local(const funcT &func) const
Returns an estimate of the difference ||this-func||^2 from local data.
Definition mra.h:507
void make_nonstandard(bool keepleaves, bool fence=true) const
Compresses the function retaining scaling function coeffs. Possible non-blocking comm.
Definition mra.h:905
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:213
void print_tree(std::ostream &os=std::cout) const
Process 0 prints a summary of all nodes in the tree (collective).
Definition mra.h:1036
FunctionNode< double, NDIM > nodeT
Definition mra.h:156
bool redundant
Definition mra.h:1324
Future< long > evalR(const coordT &xuser) const
Evaluates the function rank at a point in user coordinates. Possible non-blocking comm.
Definition mra.h:371
Function(const factoryT &factory)
Constructor from FunctionFactory provides named parameter idiom. Possible non-blocking communication.
Definition mra.h:180
NDIM &g const
Definition mra.h:1321
void unaryop(T(*f)(T))
Inplace unary operation on function values.
Definition mra.h:1074
Function< T, NDIM > conj(bool fence=true)
Inplace complex conjugate. No communication except for optional fence.
Definition mra.h:1121
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:71
Definition leafop.h:464
Definition leafop.h:336
Traits class to specify support of numeric types.
Definition type_data.h:56
A tensor is a multidimensional array.
Definition tensor.h:313
Tensor< T > & emul(const Tensor< T > &t)
Inplace multiply by corresponding elements of argument Tensor.
Definition tensor.h:1804
Tensor< T > & conj()
Inplace complex conjugate.
Definition tensor.h:721
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:1587
Interface to be provided by any process map.
Definition worlddc.h:128
void fence(bool debug=false)
Synchronizes all processes in communicator AND globally ensures no pending AM or tasks.
Definition worldgop.cc:177
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 DFConvergence.h:9
Function< T, NDIM > composite_product(World &world, std::vector< composite_term< T, NDIM > > terms, double target_precision=0.0, int oversampling=1, bool fence=true)
Definition mra.h:2677
double FunctionDefaults< NDIM >::thresh
Definition mraimpl.h:3879
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:3114
DistributionType
some introspection of how data is distributed
Definition worlddc.h:87
@ NodeReplicated
even if there are several ranks per node
Definition worlddc.h:90
@ RankReplicated
replicate the container over all world ranks
Definition worlddc.h:89
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:2492
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:2208
std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > FunctionDefaults< NDIM >::pmap
Definition mraimpl.h:3898
std::optional< BoundaryConditions< NDIM > > FunctionDefaults< NDIM >::bc
Definition mraimpl.h:3890
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:2003
int FunctionDefaults< NDIM >::k
Definition mraimpl.h:3878
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:2286
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:1938
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:2563
TreeState
Definition funcdefaults.h:60
@ nonstandard_after_apply
s and d coeffs, state after operator application
Definition funcdefaults.h:65
@ redundant_after_merge
s coeffs everywhere, must be summed up to yield the result
Definition funcdefaults.h:67
@ reconstructed
s coeffs at the leaves only
Definition funcdefaults.h:61
@ nonstandard
s and d coeffs in internal nodes
Definition funcdefaults.h:63
@ unknown
Definition funcdefaults.h:69
@ compressed
d coeffs in internal nodes, s and d coeffs at the root, empty leaves may be present
Definition funcdefaults.h:62
@ redundant
s coeffs everywhere
Definition funcdefaults.h:66
@ nonstandard_with_leaves
like nonstandard, with s coeffs at the leaves
Definition funcdefaults.h:64
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:469
T composite_inner_apply(World &world, const FunctionImpl< T, NDIM > *like, const leaf_opT &leaf_op, std::vector< composite_term< T, NDIM > > &terms, Function< T, NDIM > &bra_function, double target_precision, int oversampling)
Definition composite_product_op.h:583
Tensor< double > FunctionDefaults< NDIM >::cell
Definition mraimpl.h:3892
T composite_inner(World &world, std::vector< composite_term< T, NDIM > > terms, Function< T, NDIM > bra, double target_precision=0.0, int oversampling=1)
Definition mra.h:2739
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:2831
static constexpr long FUNCTION_ARCHIVE_MAGIC
Definition mra.h:137
Function< T, NDIM > mirror(const Function< T, NDIM > &f, const std::vector< long > &mirrormap, bool fence=true)
Generate a new function by mirroring within the dimensions .. optional fence.
Definition mra.h:2532
std::vector< CCPairFunction< T, NDIM > > operator*(const double fac, const std::vector< CCPairFunction< T, NDIM > > &arg)
Definition ccpairfunction.h:1111
std::vector< CCPairFunction< T, NDIM > > operator+(const CCPairFunction< T, NDIM > c1, const CCPairFunction< T, NDIM > &c2)
Definition ccpairfunction.h:1066
std::shared_ptr< FunctionFunctorInterface< double, 3 > > func(new opT(g))
ConcurrentHashMap< hashT, std::shared_ptr< GaussianConvolution1D< double > > > GaussianConvolution1DCache< double >::map
Definition convolution1d.h:1073
int Level
Definition key.h:60
TreeState get_tree_state(const Function< T, NDIM > &f)
get tree state of a function
Definition mra.h:3130
std::vector< CCPairFunction< T, NDIM > > operator-(const std::vector< CCPairFunction< T, NDIM > > c1, const std::vector< CCPairFunction< T, NDIM > > &c2)
Definition ccpairfunction.h:1082
std::string get_mra_data_dir()
Definition startup.cc:215
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:2171
@ TT_2D
Definition gentensor.h:120
@ TT_FULL
Definition gentensor.h:120
NDIM & f
Definition mra.h:2817
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:2163
Function< T, NDIM > symmetrize(const Function< T, NDIM > &f, const std::string symmetry, bool fence=true)
symmetrize a function
Definition mra.h:2589
NDIM const Function< R, NDIM > & g
Definition mra.h:2817
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:2380
void print(const T &t, Ts &&... ts)
Print items to std::cout (items separated by spaces) and terminate with a new line.
Definition print.h:232
const Future< void > Future< void >::value
Definition future.cc:44
double imag(double x)
Definition complexfun.h:56
void composite_product_apply(FunctionImpl< T, NDIM > *result, const leaf_opT &leaf_op, std::vector< composite_term< T, NDIM > > &terms, double target_precision, int oversampling, bool fence)
Definition composite_product_op.h:528
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:2017
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:65
std::string type(const PairType &n)
Definition PNOParameters.h:18
static bool print_timings
Definition SCF.cc:109
CCPairFunction< T, NDIM > apply(const SeparatedConvolution< T, NDIM/2 > &op, const CCPairFunction< T, NDIM > &arg)
apply the operator to the argument
Definition ccpairfunction.h:901
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:1983
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:1007
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:2633
void load(Function< T, NDIM > &f, const std::string name)
Definition mra.h:3181
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:2800
double real(double x)
Definition complexfun.h:52
@ same
same atoms at the same places
Definition RestartPlan.h:152
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:3175
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:2068
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:2239
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 leafop.h:208
void serialize(Archive &ar)
Definition mra.h:1070
T(* f)(T)
Definition mra.h:1065
void operator()(const Key< NDIM > &key, Tensor< T > &t) const
Definition mra.h:1067
SimpleUnaryOpWrapper(T(*f)(T))
Definition mra.h:1066
void serialize(Archive &ar)
Definition mra.h:999
bool operator()(implT *impl, const Key< NDIM > &key, const nodeT &t) const
Definition mra.h:995
Definition type_data.h:146
Definition leafop.h:72
Definition leafop.h:101
Definition leafop.h:260
Definition leafop.h:137
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:3161
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:3168
Default store of an object via serialize(ar, t).
Definition archive.h:612
Definition composite_product_op.h:32
Definition mra.h:3049
Tensor< double > operator()(const Key< NDIM > &key, const Tensor< double_complex > &t) const
Definition mra.h:3051
double resultT
Definition mra.h:3050
void serialize(Archive &ar)
Definition mra.h:3056
Definition mra.h:3038
void serialize(Archive &ar)
Definition mra.h:3045
Tensor< double > operator()(const Key< NDIM > &key, const Tensor< double_complex > &t) const
Definition mra.h:3040
double resultT
Definition mra.h:3039
Definition mra.h:3028
Tensor< double > operator()(const Key< NDIM > &key, const Tensor< double_complex > &t) const
Definition mra.h:3030
void serialize(Archive &ar)
Definition mra.h:3034
double resultT
Definition mra.h:3029
Definition mra.h:3018
Tensor< double > operator()(const Key< NDIM > &key, const Tensor< double_complex > &t) const
Definition mra.h:3020
double resultT
Definition mra.h:3019
void serialize(Archive &ar)
Definition mra.h:3024
Definition mra.h:124
Definition funcimpl.h:708
returns true if the result of a hartree_product is a leaf node (compute norm & error)
Definition funcimpl.h:539
Definition mra.h:3191
Definition mra.h:109
Definition mra.h:112
Definition funcimpl.h:664
Definition lowrankfunction.h:387
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
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
static long abs(long a)
Definition tensor.h:214
#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
Key< D > keyT
Definition writecoeff2.cc:11