MADNESS 0.10.1
mraimpl.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_MRAIMPL_H__INCLUDED
33#define MADNESS_MRA_MRAIMPL_H__INCLUDED
34
35#ifndef MPRAIMPLX
36#error "mraimpl.h should ONLY be included in one of the mraX.cc files (x=1..6)"
37#endif
38
40#include <memory>
41#include <math.h>
42#include <cmath>
47
50
51namespace std {
52 template <typename T>
53 bool isnan(const std::complex<T>& v) {
54 MADNESS_PRAGMA_CLANG(diagnostic push)
55 MADNESS_PRAGMA_CLANG(diagnostic ignored "-Wtautological-constant-compare")
56 return ::std::isnan(v.real()) || ::std::isnan(v.imag());
57 MADNESS_PRAGMA_CLANG(diagnostic pop)
58 }
59}
60
61/// \file mra/mraimpl.h
62/// \brief Declaration and initialization of static data, some implementation, some instantiation
63
64namespace madness {
65 // Definition and initialization of FunctionDefaults static members
66 // It cannot be an instance of FunctionFactory since we want to
67 // set the defaults independent of the data type.
68
69 template <typename T, std::size_t NDIM>
71 if (! two_scale_hg(k, &hg)) throw "failed to get twoscale coefficients";
72 hgT = copy(transpose(hg));
73
74 Slice sk(0,k-1), sk2(k,-1);
75 hgsonly = copy(hg(Slice(0,k-1),_));
76
77 h0 = copy(hg(sk,sk));
78 h1 = copy(hg(sk,sk2));
79 g0 = copy(hg(sk2,sk));
80 g1 = copy(hg(sk2,sk2));
81
82 h0T = copy(transpose(hg(sk,sk)));
83 h1T = copy(transpose(hg(sk,sk2)));
84 g0T = copy(transpose(hg(sk2,sk)));
85 g1T = copy(transpose(hg(sk2,sk2)));
86
87 }
88
89 template <typename T, std::size_t NDIM>
91 (int k, int npt, Tensor<double>& quad_x, Tensor<double>& quad_w,
92 Tensor<double>& quad_phi, Tensor<double>& quad_phiw, Tensor<double>& quad_phit) {
93 quad_x = Tensor<double>(npt); // point
94 quad_w = Tensor<double>(npt); // wheight
95 quad_phi = Tensor<double>(npt,k);
96 quad_phiw = Tensor<double>(npt,k);
97
98 gauss_legendre(npt,0.0,1.0,quad_x.ptr(),quad_w.ptr());
99 for (int mu=0; mu<npt; ++mu) {
100 double phi[200];
101 legendre_scaling_functions(quad_x(mu),k,phi);
102 for (int j=0; j<k; ++j) {
103 quad_phi(mu,j) = phi[j];
104 quad_phiw(mu,j) = quad_w(mu)*phi[j];
105 }
106 }
107 quad_phit = transpose(quad_phi);
108 }
109
110 template <typename T, std::size_t NDIM>
113 world.gop.fence(); // Make sure nothing is going on
114 MADNESS_CHECK_THROW(verify_tree_state_local(),"inconsistent coefficients in tree node");
115 MADNESS_CHECK_THROW(verify_parents_and_children(),"missing parents or children");
116 }
117
118 template <typename T, std::size_t NDIM>
120
121 // Ensure that parents and children exist appropriately
122 for (const auto& [key, node] : coeffs) {
123
124 if (key.level() > 0) {
125 const keyT parent = key.parent();
126 typename dcT::const_iterator pit = coeffs.find(parent).get();
127 if (pit == coeffs.end()) {
128 print(world.rank(), "FunctionImpl: verify: MISSING PARENT",key,parent);
129 std::cout.flush();
130 return false;
131 MADNESS_EXCEPTION("FunctionImpl: verify: MISSING PARENT", 0);
132 }
133 const nodeT& pnode = pit->second;
134 if (!pnode.has_children()) {
135 print(world.rank(), "FunctionImpl: verify: PARENT THINKS IT HAS NO CHILDREN",key,parent);
136 return false;
137 std::cout.flush();
138 MADNESS_EXCEPTION("FunctionImpl: verify: PARENT THINKS IT HAS NO CHILDREN", 0);
139 }
140 }
141
142 for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
143 typename dcT::const_iterator cit = coeffs.find(kit.key()).get();
144 if (cit == coeffs.end()) {
145 if (node.has_children()) {
146 print(world.rank(), "FunctionImpl: verify: MISSING CHILD",key,kit.key());
147 return false;
148 std::cout.flush();
149 MADNESS_EXCEPTION("FunctionImpl: verify: MISSING CHILD", 0);
150 }
151 }
152 else {
153 if (! node.has_children()) {
154 print(world.rank(), "FunctionImpl: verify: UNEXPECTED CHILD",key,kit.key());
155 return false;
156 std::cout.flush();
157 MADNESS_EXCEPTION("FunctionImpl: verify: UNEXPECTED CHILD", 0);
158 }
159 }
160 }
161 }
162 world.gop.fence();
163 return true;
164 }
165
166
167
168 template<typename T, std::size_t NDIM>
170
171 const TreeState state=get_tree_state();
172 const int k=get_k();
173
174 auto check_internal_coeff_size = [&state, &k](const coeffT& c) {
175 if (state==compressed or state==nonstandard or state==nonstandard_with_leaves)
176 return c.dim(0)==2*k;
177 if (state==redundant) return c.dim(0)==k;
178 if (state==reconstructed) return (not c.is_assigned()); // must not be assigned at all
179 if (state==redundant_after_merge or state==nonstandard_after_apply) return true;
180 MADNESS_EXCEPTION("unknown state",1);
181 };
182 auto check_leaf_coeff_size = [&state, &k](const coeffT& c) {
183 // citation from compress_spawn
184 // if (not keepleaves) node.clear_coeff();
185 if (state==reconstructed or state==redundant or state==redundant_after_merge or state==nonstandard_with_leaves)
186 return c.dim(0)==k;
187 if (state==compressed or state==nonstandard) return (not c.is_assigned()); // must not be assigned at all
188 if (state==nonstandard_after_apply) return true;
189 MADNESS_EXCEPTION("unknown state",1);
190 };
191
192 bool good=true;
193 for (const auto& [key, node] : coeffs) {
194 const auto& c=node.coeff();
195 const bool is_internal=node.has_children();
196 const bool is_leaf=not node.has_children();
197 if (is_internal) good=good and check_internal_coeff_size(c);
198 if (is_leaf) good=good and check_leaf_coeff_size(c);
199 if (not good) {
200 print("incorrect size of coefficients for key",key,"state",state,c.dim(0));;
201 }
202 }
203 return good;
204 }
205
206 template <typename T, std::size_t NDIM>
207 const std::shared_ptr< WorldDCPmapInterface< Key<NDIM> > >& FunctionImpl<T,NDIM>::get_pmap() const {
208 return coeffs.get_pmap();
209 }
210
211
212 /// perform: this= alpha*f + beta*g, invoked by result
213
214 /// f and g are reconstructed, so we can save on the compress operation,
215 /// walk down the joint tree, and add leaf coefficients; effectively refines
216 /// to common finest level.
217 /// @param[in] alpha prefactor for f
218 /// @param[in] f first addend
219 /// @param[in] beta prefactor for g
220 /// @param[in] g second addend
221 /// @return nothing, but leaves this's tree reconstructed and as sum of f and g
222 template <typename T, std::size_t NDIM>
224 const double beta, const implT& g, const bool fence) {
225
226 MADNESS_CHECK_THROW(f.is_reconstructed(), "gaxpy_oop_reconstructed: f is not reconstructed");
227 MADNESS_CHECK_THROW(g.is_reconstructed(), "gaxpy_oop_reconstructed: g is not reconstructed");
228
229 ProcessID owner = coeffs.owner(cdata.key0);
230 if (world.rank() == owner) {
231
234
235 typedef add_op coeff_opT;
236 coeff_opT coeff_op(ff,gg,alpha,beta);
237 typedef insert_op<T,NDIM> apply_opT;
238 apply_opT apply_op(this);
239
240 woT::task(world.rank(), &implT:: template forward_traverse<coeff_opT,apply_opT>,
241 coeff_op, apply_op, cdata.key0);
242
243 }
244 set_tree_state(reconstructed);
245 if (fence) world.gop.fence();
246 }
247
248 /// Returns true if the function is compressed.
249 template <typename T, std::size_t NDIM>
251 return (tree_state==compressed);
252 }
253
254 /// Returns true if the function is reconstructed.
255 template <typename T, std::size_t NDIM>
257 return (tree_state==reconstructed);
258 }
259
260 /// Returns true if the function is redundant.
261 template <typename T, std::size_t NDIM>
263 return (tree_state==redundant);
264 }
265
266 /// Returns true if the function is redundant_after_merge.
267 template <typename T, std::size_t NDIM>
269 return (tree_state==redundant_after_merge);
270 }
271
272 template <typename T, std::size_t NDIM>
274 return (tree_state==nonstandard);
275 }
276
277 template <typename T, std::size_t NDIM>
279 return (tree_state==nonstandard_with_leaves);
280 }
281
282 template <typename T, std::size_t NDIM>
284 return tree_state==on_demand;
285 }
286
287 template <typename T, std::size_t NDIM>
289 return (tree_state==nonstandard_with_leaves);
290 }
291
292 template <typename T, std::size_t NDIM>
294 set_tree_state(on_demand);
295// this->on_demand=true;
296 functor=functor1;
297 }
298
299 template <typename T, std::size_t NDIM>
300 std::shared_ptr<FunctionFunctorInterface<T,NDIM> > FunctionImpl<T,NDIM>::get_functor() {
301 MADNESS_ASSERT(this->functor);
302 return functor;
303 }
304
305 template <typename T, std::size_t NDIM>
306 std::shared_ptr<FunctionFunctorInterface<T,NDIM> > FunctionImpl<T,NDIM>::get_functor() const {
307 MADNESS_ASSERT(this->functor);
308 return functor;
309 }
310
311 template <typename T, std::size_t NDIM>
313// this->on_demand=false;
314 set_tree_state(unknown);
315 functor.reset();
316 }
317
318 template <typename T, std::size_t NDIM>
320
321 template <typename T, std::size_t NDIM>
323
324 template <typename T, std::size_t NDIM>
326
327 template <typename T, std::size_t NDIM>
329
330 template <typename T, std::size_t NDIM>
331 void FunctionImpl<T,NDIM>::set_thresh(double value) {thresh = value;}
332
333 template <typename T, std::size_t NDIM>
334 bool FunctionImpl<T,NDIM>::get_autorefine() const {return autorefine;}
335
336 template <typename T, std::size_t NDIM>
337 void FunctionImpl<T,NDIM>::set_autorefine(bool value) {autorefine = value;}
338
339 template <typename T, std::size_t NDIM>
340 int FunctionImpl<T,NDIM>::get_k() const {return k;}
341
342 template <typename T, std::size_t NDIM>
343 const typename FunctionImpl<T,NDIM>::dcT& FunctionImpl<T,NDIM>::get_coeffs() const {return coeffs;}
344
345 template <typename T, std::size_t NDIM>
347
348 template <typename T, std::size_t NDIM>
350
351 template <typename T, std::size_t NDIM>
352 void FunctionImpl<T,NDIM>::accumulate_timer(const double time) const {
353 timer_accumulate.accumulate(time);
354 }
355
356 template <typename T, std::size_t NDIM>
358 if (world.rank()==0) {
359 timer_accumulate.print("accumulate");
360 timer_target_driven.print("target_driven");
361 timer_lr_result.print("result2low_rank");
362 }
363 }
364
365 template <typename T, std::size_t NDIM>
367 if (world.rank()==0) {
368 timer_accumulate.reset();
369 timer_target_driven.reset();
370 timer_lr_result.reset();
371 }
372 }
373
374 /// Truncate according to the threshold with optional global fence
375
376 /// If thresh<=0 the default value of this->thresh is used
377 template <typename T, std::size_t NDIM>
378 void FunctionImpl<T,NDIM>::truncate(double tol, bool fence) {
379 // Cannot put tol into object since it would make a race condition
380 if (tol <= 0.0)
381 tol = thresh;
382 if (world.rank() == coeffs.owner(cdata.key0)) {
383 if (is_compressed()) {
384 truncate_spawn(cdata.key0,tol);
385 } else {
386 truncate_reconstructed_spawn(cdata.key0,tol);
387 }
388 }
389 if (fence)
390 world.gop.fence();
391 }
392
393 template <typename T, std::size_t NDIM>
395 return cdata.key0;
396 }
397
398 /// Print a plane ("xy", "xz", or "yz") containing the point x to file
399
400 /// works for all dimensions; we walk through the tree, and if a leaf node
401 /// inside the sub-cell touches the plane we print it in pstricks format
402 template <typename T, std::size_t NDIM>
403 void FunctionImpl<T,NDIM>::print_plane(const std::string filename, const int xaxis, const int yaxis, const coordT& el2) {
404
405 // get the local information
406 Tensor<double> localinfo=print_plane_local(xaxis,yaxis,el2);
407
408 // lump all the local information together, and gather on node0
409 std::vector<Tensor<double> > localinfo_vec(1,localinfo);
410 std::vector<Tensor<double> > printinfo=world.gop.concat0(localinfo_vec);
411 world.gop.fence();
412
413 // do the actual print
414 if (world.rank()==0) do_print_plane(filename,printinfo,xaxis,yaxis,el2);
415 }
416
417 /// collect the data for a plot of the MRA structure locally on each node
418
419 /// @param[in] xaxis the x-axis in the plot (can be any axis of the MRA box)
420 /// @param[in] yaxis the y-axis in the plot (can be any axis of the MRA box)
421 /// @param[in] el2
422 template <typename T, std::size_t NDIM>
423 Tensor<double> FunctionImpl<T,NDIM>::print_plane_local(const int xaxis, const int yaxis, const coordT& el2) {
424 coordT x_sim;
425 user_to_sim<NDIM>(el2,x_sim);
426 x_sim[0]+=1.e-10;
427
428 // dimensions are: (# boxes)(hue, x lo left, y lo left, x hi right, y hi right)
429 Tensor<double> plotinfo(coeffs.size(),5);
430 long counter=0;
431
432 // loop over local boxes, if the fit, add the info to the output tensor
433 typename dcT::const_iterator end = coeffs.end();
434 for (typename dcT::const_iterator it=coeffs.begin(); it!=end; ++it) {
435 const keyT& key = it->first;
436 const nodeT& node = it->second;
437
438 // thisKeyContains ignores dim0 and dim1
439 if (key.thisKeyContains(x_sim,xaxis,yaxis) and node.is_leaf() and (node.has_coeff())) {
440
441 Level n=key.level();
443 // get the diametral edges of the node in the plotting plane
444 double scale=std::pow(0.5,double(n));
445 double xloleft = scale*l[xaxis];
446 double yloleft = scale*l[yaxis];
447 double xhiright = scale*(l[xaxis]+1);
448 double yhiright = scale*(l[yaxis]+1);
449
450 // convert back to user coordinates
451 Vector<double,4> user;
456
457
458 // if ((xloleft<-5.0) or (yloleft<-5.0) or (xhiright>5.0) or (yhiright>5.0)) continue;
459 if ((user[0]<-5.0) or (user[1]<-5.0) or (user[2]>5.0) or (user[3]>5.0)) continue;
460
461 // do rank or do error
462 double color=0.0;
463 if (1) {
464
465 const double maxrank=40;
466 do_convert_to_color hue(maxrank,false);
467 color=hue(node.coeff().rank());
468 } else {
469
470 // Make quadrature rule of higher order
471 const int npt = cdata.npt + 1;
472 Tensor<double> qx, qw, quad_phi, quad_phiw, quad_phit;
473 FunctionCommonData<T,NDIM>::_init_quadrature(k+1, npt, qx, qw, quad_phi, quad_phiw, quad_phit);
474 do_err_box< FunctionFunctorInterface<T,NDIM> > op(this, this->get_functor().get(), npt, qx, quad_phit, quad_phiw);
475
476 do_convert_to_color hue(1000.0,true);
477 double error=op(it);
478 error=sqrt(error);//*pow(2,key.level()*6);
479 color=hue(error);
480 }
481
482 plotinfo(counter,0)=color;
483 plotinfo(counter,1)=user[0];
484 plotinfo(counter,2)=user[1];
485 plotinfo(counter,3)=user[2];
486 plotinfo(counter,4)=user[3];
487 ++counter;
488 }
489 }
490
491 // shrink the info
492 if (counter==0) plotinfo=Tensor<double>();
493 else plotinfo=plotinfo(Slice(0,counter-1),Slice(_));
494 return plotinfo;
495 }
496
497 /// print the MRA structure
498 template <typename T, std::size_t NDIM>
499 void FunctionImpl<T,NDIM>::do_print_plane(const std::string filename, std::vector<Tensor<double> > plotinfo,
500 const int xaxis, const int yaxis, const coordT el2) {
501
502 // invoke only on master node
503 MADNESS_ASSERT(world.rank()==0);
504
505 // prepare file
506 FILE * pFile;
507 pFile = fopen(filename.c_str(), "w");
509
510
511 fprintf(pFile,"\\psset{unit=1cm}\n");
512 fprintf(pFile,"\\begin{pspicture}(%4.2f,%4.2f)(%4.2f,%4.2f)\n",
513 // cell(xaxis,0),cell(xaxis,1),cell(yaxis,0),cell(yaxis,1));
514 -5.0,-5.0,5.0,5.0);
515 fprintf(pFile,"\\pslinewidth=0.1pt\n");
516
517 for (std::vector<Tensor<double> >::const_iterator it=plotinfo.begin(); it!=plotinfo.end(); ++it) {
518
519 Tensor<double> localinfo=*it;
520 if (localinfo.has_data()) {
521
522 for (long i=0; i<localinfo.dim(0); ++i) {
523
524 fprintf(pFile,"\\newhsbcolor{mycolor}{%8.4f 1.0 0.7}\n",localinfo(i,0));
525 fprintf(pFile,"\\psframe["//linewidth=0.5pt,"
526 "fillstyle=solid,"
527 "fillcolor=mycolor]"
528 "(%12.8f,%12.8f)(%12.8f,%12.8f)\n",
529 localinfo(i,1),localinfo(i,2),localinfo(i,3),localinfo(i,4));
530 }
531 }
532 }
533
534
535 fprintf(pFile,"\\end{pspicture}\n");
536 fclose(pFile);
537 }
538
539 /// print the grid (the roots of the quadrature of each leaf box)
540 /// of this function in user xyz coordinates
541 template <typename T, std::size_t NDIM>
542 void FunctionImpl<T,NDIM>::print_grid(const std::string filename) const {
543
544 // get the local information
545 std::vector<keyT> local_keys=local_leaf_keys();
546
547 // lump all the local information together, and gather on node0
548 std::vector<keyT> all_keys=world.gop.concat0(local_keys);
549 world.gop.fence();
550
551 // do the actual print
552 if (world.rank()==0) do_print_grid(filename,all_keys);
553
554 }
555
556 /// return the keys of the local leaf boxes
557 template <typename T, std::size_t NDIM>
558 std::vector<typename FunctionImpl<T,NDIM>::keyT> FunctionImpl<T,NDIM>::local_leaf_keys() const {
559
560 // coeffs.size is maximum number of keys (includes internal keys)
561 std::vector<keyT> keys(coeffs.size());
562
563 // loop over local boxes, if they are leaf boxes add their quadrature roots
564 // to the output tensor
565 int i=0;
566 typename dcT::const_iterator end = coeffs.end();
567 for (typename dcT::const_iterator it=coeffs.begin(); it!=end; ++it) {
568 const keyT& key = it->first;
569 const nodeT& node = it->second;
570 if (node.is_leaf()) keys[i++]=key;
571 }
572
573 // shrink the vector to number of leaf keys
574 keys.resize(i);
575 return keys;
576 }
577
578 /// print the grid in xyz format
579
580 /// the quadrature points and the key information will be written to file,
581 /// @param[in] filename where the quadrature points will be written to
582 /// @param[in] keys all leaf keys
583 template <typename T, std::size_t NDIM>
584 void FunctionImpl<T,NDIM>::do_print_grid(const std::string filename, const std::vector<keyT>& keys) const {
585 // invoke only on master node
586 MADNESS_ASSERT(world.rank()==0);
587
588 // the quadrature points in simulation coordinates of the root node
589 const Tensor<double> qx=cdata.quad_x;
590 const size_t npt = qx.dim(0);
591
592 // the number of coordinates (grid point tuples) per box ({x1},{x2},{x3},..,{xNDIM})
593 long npoints=power<NDIM>(npt);
594 // the number of boxes
595 long nboxes=keys.size();
596
597 // prepare file
598 FILE * pFile;
599 pFile = fopen(filename.c_str(), "w");
600
601 fprintf(pFile,"%ld\n",npoints*nboxes);
602 fprintf(pFile,"%ld points per box and %ld boxes \n",npoints,nboxes);
603
604 // loop over all leaf boxes
605 typename std::vector<keyT>::const_iterator key_it=keys.begin();
606 for (key_it=keys.begin(); key_it!=keys.end(); ++key_it) {
607
608 const keyT& key=*key_it;
609 fprintf(pFile,"# key: %8d",key.level());
610 for (size_t d=0; d<NDIM; d++) fprintf(pFile,"%8d",int(key.translation()[d]));
611 fprintf(pFile,"\n");
612
613 // this is borrowed from fcube
614 const Vector<Translation,NDIM>& l = key.translation();
615 const Level n = key.level();
616 const double h = std::pow(0.5,double(n));
617 coordT c; // will hold the point in user coordinates
618
621
622 if (NDIM == 3) {
623 for (size_t i=0; i<npt; ++i) {
624 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
625 for (size_t j=0; j<npt; ++j) {
626 c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
627 for (size_t k=0; k<npt; ++k) {
628 c[2] = cell(2,0) + h*cell_width[2]*(l[2] + qx(k)); // z
629 // grid weights
630 // double scale = pow(0.5,0.5*NDIM*key.level())*
631 // sqrt(FunctionDefaults<NDIM>::get_cell_volume());
632 // double w=cdata.quad_phiw[i]*cdata.quad_phiw[j]*cdata.quad_phiw[k];
633
634 fprintf(pFile,"%18.12f %18.12f %18.12f\n",c[0],c[1],c[2]);
635 // fprintf(pFile,"%18.12e %18.12e %18.12e %18.12e\n",c[0],c[1],c[2],w*scale);
636 }
637 }
638 }
639 } else {
640 MADNESS_EXCEPTION("only NDIM=3 in print_grid",0);
641 }
642 }
643 fclose(pFile);
644 }
645
646
647 /// Returns the truncation threshold according to truncate_method
648 template <typename T, std::size_t NDIM>
649 double FunctionImpl<T,NDIM>::truncate_tol(double tol, const keyT& key) const {
650
651 // RJH ... introduced max level here to avoid runaway
652 // refinement due to truncation threshold going down to
653 // intrinsic numerical error
654 const int MAXLEVEL1 = 20; // 0.5**20 ~= 1e-6
655 const int MAXLEVEL2 = 10; // 0.25**10 ~= 1e-6
656
657 if (truncate_mode == 0) {
658 return tol;
659 }
660 else if (truncate_mode == 1) {
662 return tol*std::min(1.0,pow(0.5,double(std::min(key.level(),MAXLEVEL1)))*L);
663 }
664 else if (truncate_mode == 2) {
666 return tol*std::min(1.0,pow(0.25,double(std::min(key.level(),MAXLEVEL2)))*L*L);
667 }
668 else if (truncate_mode == 3) {
669 // similar to truncate mode 1, but with an additional factor to
670 // account for an increased number of boxes in higher dimensions
671
672 // here is our handwaving argument: this threshold will give each
673 // FunctionNode an error of less than tol. The total error can
674 // then be as high as sqrt(#nodes) * tol. Therefore in order to
675 // account for higher dimensions: divide tol by about the root of
676 // number of siblings (2^NDIM) that have a large error when we
677 // refine along a deep branch of the tree. FAB
678 //
679 // Nope ... it can easily be as high as #nodes * tol. The real
680 // fix for this is an end-to-end error analysis of the larger
681 // application and if desired to include this factor into the
682 // threshold selected by the application. RJH
683 const static double fac=1.0/std::pow(2,NDIM*0.5);
684 tol*=fac;
685
687 return tol*std::min(1.0,pow(0.5,double(std::min(key.level(),MAXLEVEL1)))*L);
688
689 } else {
690 MADNESS_EXCEPTION("truncate_mode invalid",truncate_mode);
691 }
692 }
693
694 /// Returns patch referring to coeffs of child in parent box
695 template <typename T, std::size_t NDIM>
696 std::vector<Slice> FunctionImpl<T,NDIM>::child_patch(const keyT& child) const {
697 std::vector<Slice> s(NDIM);
698 const Vector<Translation,NDIM>& l = child.translation();
699 for (std::size_t i=0; i<NDIM; ++i)
700 s[i] = cdata.s[l[i]&1]; // Lowest bit of translation
701 return s;
702 }
703
704 /// Directly project parent NS coeffs to child NS coeffs
705
706 template <typename T, std::size_t NDIM>
708 const keyT& child, const keyT& parent, const coeffT& coeff) const {
709
710 const implT* f=this;
711 // MADNESS_ASSERT(coeff.tensor_type()==TT_FULL);
712 coeffT result(f->cdata.v2k,coeff.tensor_type());
713
714 // if the node for child is existent in f, and it is an internal node, we
715 // automatically have the NS form; if it is a leaf node, we only have the
716 // sum coeffs, so we take zero difference coeffs
717 if (child==parent) {
718 if (coeff.dim(0)==2*f->get_k()) result=coeff; // internal node
719 else if (coeff.dim(0)==f->get_k()) { // leaf node
720 result(f->cdata.s0)+=coeff;
721 } else {
722 MADNESS_EXCEPTION("confused k in parent_to_child_NS",1);
723 }
724 } else if (child.level()>parent.level()) {
725
726 // parent and coeff should refer to a leaf node with sum coeffs only
727 // b/c tree should be compressed with leaves kept.
728 MADNESS_ASSERT(coeff.dim(0)==f->get_k());
729 const coeffT scoeff=f->parent_to_child(coeff,parent,child);
730 result(f->cdata.s0)+=scoeff;
731 } else {
732 MADNESS_EXCEPTION("confused keys in parent_to_child_NS",1);
733 }
734 return result;
735 }
736
737 /// truncate tree at a certain level
738 template <typename T, std::size_t NDIM>
739 void FunctionImpl<T,NDIM>::erase(const Level& max_level) {
740 this->make_redundant(true);
741
742 typename dcT::iterator end = coeffs.end();
743 for (typename dcT::iterator it= coeffs.begin(); it!=end; ++it) {
744 keyT key=it->first;
745 nodeT& node=it->second;
746 if (key.level()>max_level) coeffs.erase(key);
747 if (key.level()==max_level) node.set_has_children(false);
748 }
749 this->undo_redundant(true);
750 }
751
752
753 /// Returns some asymmetry measure ... no comms
754 template <typename T, std::size_t NDIM>
758 return world.taskq.reduce<double,rangeT,do_check_symmetry_local>(rangeT(coeffs.begin(),coeffs.end()),
760 }
761
762
763 /// Refine multiple functions down to the same finest level
764
765 /// @param[v] is the vector of functions we are refining.
766 /// @param[key] is the current node.
767 /// @param[c] is the vector of coefficients passed from above.
768 template <typename T, std::size_t NDIM>
770 const std::vector<tensorT>& c,
771 const keyT key) {
772 if (key == cdata.key0 && coeffs.owner(key)!=world.rank()) return;
773
774 // First insert coefficients from above ... also get write accessors here
775 std::unique_ptr<typename dcT::accessor[]> acc(new typename dcT::accessor[v.size()]);
776 for (unsigned int i=0; i<c.size(); i++) {
777 MADNESS_ASSERT(v[i]->coeffs.get_pmap() == coeffs.get_pmap());
778 MADNESS_ASSERT(v[i]->coeffs.owner(key) == world.rank());
779 bool exists = ! v[i]->coeffs.insert(acc[i],key);
780 if (c[i].size()) {
781 MADNESS_CHECK(!exists);
782 acc[i]->second = nodeT(coeffT(c[i],targs),false);
783 }
784 else {
785 MADNESS_ASSERT(exists);
786 }
787 }
788
789 // If everyone has coefficients we are done
790 bool done = true;
791 for (unsigned int i=0; i<v.size(); i++) {
792 done &= acc[i]->second.has_coeff();
793 }
794
795 if (!done) {
796 // Those functions with coefficients need to be refined down
797 std::vector<tensorT> d(v.size());
798 for (unsigned int i=0; i<v.size(); i++) {
799 if (acc[i]->second.has_coeff()) {
800 tensorT s(cdata.v2k);
801 // s(cdata.s0) = acc[i]->second.coeff()(___);
802 s(cdata.s0) = acc[i]->second.coeff().full_tensor();
803 acc[i]->second.clear_coeff();
804 d[i] = unfilter(s);
805 acc[i]->second.set_has_children(true);
806 }
807 }
808
809 // Loop thru children and pass down
810 for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
811 const keyT& child = kit.key();
812 std::vector<Slice> cp = child_patch(child);
813 std::vector<tensorT> childc(v.size());
814 for (unsigned int i=0; i<v.size(); i++) {
815 if (d[i].size()) childc[i] = copy(d[i](cp));
816 }
817 woT::task(coeffs.owner(child), &implT::refine_to_common_level, v, childc, child);
818 }
819 }
820 }
821
822 // horrifically non-scalable
823 template <typename T, std::size_t NDIM>
824 void FunctionImpl<T,NDIM>::put_in_box(ProcessID from, long nl, long ni) const {
825 if (world.size()> 1000)
826 throw "NO!";
827 box_leaf[from] = nl;
828 box_interior[from] = ni;
829 }
830
831 /// Prints summary of data distribution
832 template <typename T, std::size_t NDIM>
834 if (world.size() >= 1000)
835 return;
836 for (int i=0; i<world.size(); ++i)
837 box_leaf[i] = box_interior[i] == 0;
838 world.gop.fence();
839 long nleaf=0, ninterior=0;
840 typename dcT::const_iterator end = coeffs.end();
841 for (typename dcT::const_iterator it=coeffs.begin(); it!=end; ++it) {
842 const nodeT& node = it->second;
843 if (node.is_leaf())
844 ++nleaf;
845 else
846 ++ninterior;
847 }
848 this->send(0, &implT::put_in_box, world.rank(), nleaf, ninterior);
849 world.gop.fence();
850 if (world.rank() == 0) {
851 for (int i=0; i<world.size(); ++i) {
852 printf("load: %5d %8ld %8ld\n", i, box_leaf[i], box_interior[i]);
853 }
854 }
855 world.gop.fence();
856 }
857
858 template <typename T, std::size_t NDIM>
859 bool FunctionImpl<T,NDIM>::noautorefine(const keyT& key, const tensorT& t) const {
860 return false;
861 }
862
863 /// Returns true if this block of coeffs needs autorefining
864 template <typename T, std::size_t NDIM>
865 bool FunctionImpl<T,NDIM>::autorefine_square_test(const keyT& key, const nodeT& t) const {
866 double lo, hi;
867 tnorm(t.coeff().full_tensor(), &lo, &hi);
868 double test = 2*lo*hi + hi*hi;
869 //print("autoreftest",key,thresh,truncate_tol(thresh, key),lo,hi,test);
870 return test> truncate_tol(thresh, key);
871 }
872
873
874 /// is this the same as trickle_down() ?
875 template <typename T, std::size_t NDIM>
877 typename dcT::accessor acc;
878 coeffs.insert(acc,key);
879 nodeT& node = acc->second;
880 coeffT& c = node.coeff();
881
882 //print(key,"received",s.normf(),c.normf(),node.has_children());
883
884 if (s.size() > 0) {
885 if (c.size() > 0)
886 c.gaxpy(1.0,s,1.0);
887 else
888 c = s;
889 }
890
891 if (node.has_children()) {
892 coeffT d;
893 if (c.has_data()) {
894 d = coeffT(cdata.v2k,targs);
895 d(cdata.s0) += c;
896 d = unfilter(d);
897 node.clear_coeff();
898 }
899 for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
900 coeffT ss;
901 const keyT& child = kit.key();
902 if (d.size() > 0) ss = copy(d(child_patch(child)));
903 //print(key,"sending",ss.normf(),"to",child);
904 woT::task(coeffs.owner(child), &implT::sum_down_spawn, child, ss);
905 }
906 }
907 else {
908 // Missing coeffs assumed to be zero
909 if (c.size() <= 0) c = coeffT(cdata.vk,targs);
910 }
911 }
912
913 /// After 1d push operator must sum coeffs down the tree to restore correct scaling function coefficients
914 template <typename T, std::size_t NDIM>
916 tree_state=reconstructed;
917 if (world.rank() == coeffs.owner(cdata.key0)) sum_down_spawn(cdata.key0, coeffT());
918 if (fence) world.gop.fence();
919 }
920
921
922 template <typename T, std::size_t NDIM>
924 const implT* f,
925 const keyT& key,
926 const std::pair<keyT,coeffT>& left,
927 const std::pair<keyT,coeffT>& center,
928 const std::pair<keyT,coeffT>& right) {
929 D->forward_do_diff1(f,this,key,left,center,right);
930 }
931
932
933 template <typename T, std::size_t NDIM>
935 const implT* f,
936 const keyT& key,
937 const std::pair<keyT,coeffT>& left,
938 const std::pair<keyT,coeffT>& center,
939 const std::pair<keyT,coeffT>& right) {
940 D->do_diff1(f,this,key,left,center,right);
941 }
942
943
944 // Called by result function to differentiate f
945 template <typename T, std::size_t NDIM>
946 void FunctionImpl<T,NDIM>::diff(const DerivativeBase<T,NDIM>* D, const implT* f, bool fence) {
947 typedef std::pair<keyT,coeffT> argT;
948 for (const auto& [key, node]: f->coeffs) {
949 if (node.has_coeff()) {
950 Future<argT> left = D->find_neighbor(f, key,-1);
951 argT center(key,node.coeff());
952 Future<argT> right = D->find_neighbor(f, key, 1);
953 world.taskq.add(*this, &implT::do_diff1, D, f, key, left, center, right, TaskAttributes::hipri());
954 }
955 else {
956 coeffs.replace(key,nodeT(coeffT(),true)); // Empty internal node
957 }
958 }
959 if (fence) world.gop.fence();
960 }
961
962
963 /// return the a std::pair<key, node>, which MUST exist
964 template <typename T, std::size_t NDIM>
966 MADNESS_ASSERT(coeffs.probe(key));
967 ShallowNode<T,NDIM> snode(coeffs.find(key).get()->second);
968 return std::pair<Key<NDIM>,ShallowNode<T,NDIM> >(key,snode);
969 }
970
971 /// multiply the ket with a one-electron potential rr(1,2)= f(1,2)*g(1)
972
973 /// @param[in] val_ket function values of f(1,2)
974 /// @param[in] val_pot function values of g(1)
975 /// @param[in] particle if 0 then g(1), if 1 then g(2)
976 /// @return the resulting function values
977 template <typename T, std::size_t NDIM>
979 const coeffT& val_pot, int particle) const {
980
983 MADNESS_ASSERT(val_ket.is_svd_tensor());
984
985 std::vector<long> vkhalf=std::vector<long>(NDIM/2,cdata.vk[0]);
986 tensorT ones=tensorT(vkhalf);
987 ones=1.0;
988
989 TensorArgs targs(-1.0,val_ket.tensor_type());
990 coeffT pot12;
991 if (particle==0) pot12=outer(val_pot.full_tensor(),ones,targs);
992 else if (particle==1) pot12=outer(ones,val_pot.full_tensor(),targs);
993
994 coeffT result=copy(val_ket);
995 result.emul(pot12);
996
997 return result;
998 }
999
1000
1001 /// given several coefficient tensors, assemble a result tensor
1002
1003 /// the result looks like: (v(1,2) + v(1) + v(2)) |ket(1,2)>
1004 /// or (v(1,2) + v(1) + v(2)) |p(1) p(2)>
1005 /// i.e. coefficients for the ket and coefficients for the two particles are
1006 /// mutually exclusive. All potential terms are optional, just pass in empty coeffs.
1007 /// @param[in] key the key of the FunctionNode to which these coeffs belong
1008 /// @param[in] cket coefficients of the ket
1009 /// @param[in] vpotential1 function values of the potential for particle 1
1010 /// @param[in] vpotential2 function values of the potential for particle 2
1011 /// @param[in] veri function values for the 2-particle potential
1012 template <typename T, std::size_t NDIM>
1014 const keyT& key, const coeffT& coeff_ket, const coeffT& vpotential1,
1015 const coeffT& vpotential2, const tensorT& veri) const {
1016
1017 // take a shortcut if we are already done
1018 bool ket_only=(not (vpotential1.has_data() or vpotential2.has_data() or veri.has_data()));
1019 if (ket_only) return coeff_ket;
1020
1021 // switch to values instead of coefficients
1022 coeffT val_ket=coeffs2values(key,coeff_ket);
1023
1024 // the result tensor
1025 coeffT val_result=coeffT(val_ket.ndim(),val_ket.dims(),this->get_tensor_args().tt);
1026 coeffT coeff_result;
1027
1028 // potential for particles 1 and 2, must be done in TT_2D
1029 if (vpotential1.has_data() or vpotential2.has_data()) {
1030 val_ket=val_ket.convert(TensorArgs(-1.0,TT_2D));
1031 }
1032 if (vpotential1.has_data()) val_result+=multiply(val_ket,vpotential1,0);
1033 if (vpotential2.has_data()) val_result+=multiply(val_ket,vpotential2,1);
1034
1035 // values for eri: this must be done in full rank...
1036 if (veri.has_data()) {
1037 tensorT val_ket2=val_ket.full_tensor_copy().emul(veri);
1038 if (val_result.has_data()) val_ket2+=val_result.full_tensor();
1039 // values2coeffs expensive (30%), coeffT() (relatively) cheap (8%)
1040 coeff_result=coeffT(values2coeffs(key,val_ket2),this->get_tensor_args());
1041
1042 } else {
1043
1044 // convert back to original tensor type
1045 val_ket=val_ket.convert(get_tensor_args());
1046 MADNESS_ASSERT(val_result.has_data());
1047 coeff_result=values2coeffs(key,val_result);
1048 coeff_result.reduce_rank(this->get_tensor_args().thresh);
1049 }
1050
1051 return coeff_result;
1052
1053 }
1054
1055 /// Permute the dimensions of f according to map, result on this
1056 template <typename T, std::size_t NDIM>
1057 void FunctionImpl<T,NDIM>::mapdim(const implT& f, const std::vector<long>& map, bool fence) {
1058
1060 const_cast<implT*>(&f)->flo_unary_op_node_inplace(do_mapdim(map,*this),fence);
1061
1062 }
1063
1064 /// mirror the dimensions of f according to mirror, result on this
1065 template <typename T, std::size_t NDIM>
1066 void FunctionImpl<T,NDIM>::mirror(const implT& f, const std::vector<long>& mirrormap, bool fence) {
1068 const_cast<implT*>(&f)->flo_unary_op_node_inplace(do_mirror(mirrormap,*this),fence);
1069 }
1070
1071 /// map and mirror the translation index and the coefficients, result on this
1072
1073 /// first map the dimensions, the mirror!
1074 /// this = mirror(map(f))
1075 template <typename T, std::size_t NDIM>
1076 void FunctionImpl<T,NDIM>::map_and_mirror(const implT& f, const std::vector<long>& map,
1077 const std::vector<long>& mirror, bool fence) {
1079 const_cast<implT*>(&f)->flo_unary_op_node_inplace(do_map_and_mirror(map,mirror,*this),fence);
1080 }
1081
1082
1083
1084 /// take the average of two functions, similar to: this=0.5*(this+rhs)
1085
1086 /// works in either basis and also in nonstandard form
1087 template <typename T, std::size_t NDIM>
1089
1090 rhs.flo_unary_op_node_inplace(do_average(*this),true);
1091 this->scale_inplace(0.5,true);
1092 flo_unary_op_node_inplace(do_reduce_rank(targs),true);
1093 }
1094
1095 /// change the tensor type of the coefficients in the FunctionNode
1096
1097 /// @param[in] targs target tensor arguments (threshold and full/low rank)
1098 template <typename T, std::size_t NDIM>
1100 flo_unary_op_node_inplace(do_change_tensor_type(targs,*this),fence);
1101 }
1102
1103 /// reduce the rank of the coefficients tensors
1104
1105 /// @param[in] targs target tensor arguments (threshold and full/low rank)
1106 template <typename T, std::size_t NDIM>
1107 void FunctionImpl<T,NDIM>::reduce_rank(const double thresh, bool fence) {
1108 flo_unary_op_node_inplace(do_reduce_rank(thresh),fence);
1109 }
1110
1111 /// reduce the rank of the coefficients tensors
1112
1113 /// @param[in] targs target tensor arguments (threshold and full/low rank)
1114 template <typename T, std::size_t NDIM>
1115 void FunctionImpl<T,NDIM>::chop_at_level(const int n, bool fence) {
1116 std::list<keyT> to_be_erased;
1117 for (auto it=coeffs.begin(); it!=coeffs.end(); ++it) {
1118 const keyT& key=it->first;
1119 nodeT& node=it->second;
1120 if (key.level()==n) node.set_is_leaf(true);
1121 if (key.level()>n) to_be_erased.push_back(key);
1122 }
1123 for (auto& key : to_be_erased) coeffs.erase(key);
1124 }
1125
1126
1127/// compute norm of s and d coefficients for all nodes
1128
1129 /// @param[in] targs target tensor arguments (threshold and full/low rank)
1130 template <typename T, std::size_t NDIM>
1132 //const auto& data=FunctionCommonData<T,NDIM>::get(get_k());
1133 flo_unary_op_node_inplace(
1134 do_compute_snorm_and_dnorm(cdata),fence);
1135 }
1136
1137
1138/// Transform sum coefficients at level n to sums+differences at level n-1
1139
1140/// Given scaling function coefficients s[n][l][i] and s[n][l+1][i]
1141/// return the scaling function and wavelet coefficients at the
1142/// coarser level. I.e., decompose Vn using Vn = Vn-1 + Wn-1.
1143 /// \code
1144 /// s_i = sum(j) h0_ij*s0_j + h1_ij*s1_j
1145 /// d_i = sum(j) g0_ij*s0_j + g1_ij*s1_j
1146 // \endcode
1147 /// Returns a new tensor and has no side effects. Works for any
1148 /// number of dimensions.
1149 ///
1150 /// No communication involved.
1151 template <typename T, std::size_t NDIM>
1153 tensorT r(cdata.v2k,false);
1154 tensorT w(cdata.v2k,false);
1155 return fast_transform(s,cdata.hgT,r,w);
1156 //return transform(s,cdata.hgT);
1157 }
1158
1159 template <typename T, std::size_t NDIM>
1161 coeffT result=transform(s,cdata.hgT);
1162 return result;
1163 }
1164
1165 /// Transform sums+differences at level n to sum coefficients at level n+1
1166
1167 /// Given scaling function and wavelet coefficients (s and d)
1168 /// returns the scaling function coefficients at the next finer
1169 /// level. I.e., reconstruct Vn using Vn = Vn-1 + Wn-1.
1170 /// \code
1171 /// s0 = sum(j) h0_ji*s_j + g0_ji*d_j
1172 /// s1 = sum(j) h1_ji*s_j + g1_ji*d_j
1173 /// \endcode
1174 /// Returns a new tensor and has no side effects
1175 ///
1176 /// If (sonly) ... then ss is only the scaling function coeff (and
1177 /// assume the d are zero). Works for any number of dimensions.
1178 ///
1179 /// No communication involved.
1180 template <typename T, std::size_t NDIM>
1182 tensorT r(cdata.v2k,false);
1183 tensorT w(cdata.v2k,false);
1184 return fast_transform(s,cdata.hg,r,w);
1185 //return transform(s, cdata.hg);
1186 }
1187
1188 template <typename T, std::size_t NDIM>
1190 return transform(s,cdata.hg);
1191 }
1192
1193 /// downsample the sum coefficients of level n+1 to sum coeffs on level n
1194
1195 /// specialization of the filter method, will yield only the sum coefficients
1196 /// @param[in] key key of level n
1197 /// @param[in] v vector of sum coefficients of level n+1
1198 /// @param[in] args TensorArguments for possible low rank approximations
1199 /// @return sum coefficients on level n in full tensor format
1200 template <typename T, std::size_t NDIM>
1202
1203 tensorT result(cdata.vk);
1204
1205 // the twoscale coefficients: for downsampling use h0/h1; see Alpert Eq (3.34a)
1206 const tensorT h[2] = {cdata.h0T, cdata.h1T};
1207 tensorT matrices[NDIM];
1208
1209 // loop over all child nodes, transform and accumulate
1210 long i=0;
1211 for (KeyChildIterator<NDIM> kit(key); kit; ++kit,++i) {
1212
1213 // get the appropriate twoscale coefficients for each dimension
1214 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii]=h[kit.key().translation()[ii]%2];
1215
1216 // transform and accumulate on the result
1217 result+=general_transform(v[i].get(),matrices).full_tensor();
1218
1219 }
1220 return result;
1221 }
1222
1223 /// upsample the sum coefficients of level 1 to sum coeffs on level n+1
1224
1225 /// specialization of the unfilter method, will transform only the sum coefficients
1226 /// @param[in] key key of level n+1
1227 /// @param[in] coeff sum coefficients of level n (does NOT belong to key!!)
1228 /// @param[in] args TensorArguments for possible low rank approximations
1229 /// @return sum coefficients on level n+1
1230 template <typename T, std::size_t NDIM>
1232
1233 // the twoscale coefficients: for upsampling use h0/h1; see Alpert Eq (3.35a/b)
1234 // note there are no difference coefficients; if you want that use unfilter
1235 const tensorT h[2] = {cdata.h0, cdata.h1};
1236 tensorT matrices[NDIM];
1237
1238 // get the appropriate twoscale coefficients for each dimension
1239 for (size_t ii=0; ii<NDIM; ++ii) matrices[ii]=h[key.translation()[ii]%2];
1240
1241 // transform and accumulate on the result
1242 const coeffT result=general_transform(coeff,matrices);
1243 return result;
1244 }
1245
1246
1247 /// Projects old function into new basis (only in reconstructed form)
1248 template <typename T, std::size_t NDIM>
1249 void FunctionImpl<T,NDIM>::project(const implT& old, bool fence) {
1250 long kmin = std::min(cdata.k,old.cdata.k);
1251 std::vector<Slice> s(NDIM,Slice(0,kmin-1));
1252 typename dcT::const_iterator end = old.coeffs.end();
1253 for (typename dcT::const_iterator it=old.coeffs.begin(); it!=end; ++it) {
1254 const keyT& key = it->first;
1255 const nodeT& node = it->second;
1256 if (node.has_coeff()) {
1257 coeffT c(cdata.vk,targs);
1258 c(s) += node.coeff()(s);
1259 coeffs.replace(key,nodeT(c,false));
1261 else {
1262 coeffs.replace(key,nodeT(coeffT(),true));
1263 }
1264 }
1265 if (fence)
1266 world.gop.fence();
1267 }
1268
1269 template <typename T, std::size_t NDIM>
1271 return coeffs.probe(key) && coeffs.find(key).get()->second.has_children();
1272 }
1273
1274 template <typename T, std::size_t NDIM>
1276 return coeffs.probe(key) && (not coeffs.find(key).get()->second.has_children());
1277 }
1278
1279
1280 template <typename T, std::size_t NDIM>
1281 void FunctionImpl<T,NDIM>::broaden_op(const keyT& key, const std::vector< Future <bool> >& v) {
1282 for (unsigned int i=0; i<v.size(); ++i) {
1283 if (v[i]) {
1284 refine_op(true_refine_test(), key);
1285 break;
1286 }
1287 }
1288 }
1289
1290 // For each local node sets value of norm tree, snorm and dnorm to 0.0
1291 template <typename T, std::size_t NDIM>
1293 typename dcT::iterator end = coeffs.end();
1294 for (typename dcT::iterator it=coeffs.begin(); it!=end; ++it) {
1295 it->second.set_norm_tree(0.0);
1296 it->second.set_snorm(0.0);
1297 it->second.set_dnorm(0.0);
1298 }
1299 }
1300
1301 // Broaden tree
1302 template <typename T, std::size_t NDIM>
1303 void FunctionImpl<T,NDIM>::broaden(const array_of_bools<NDIM>& is_periodic, bool fence) {
1304 typename dcT::iterator end = coeffs.end();
1305 for (typename dcT::iterator it=coeffs.begin(); it!=end; ++it) {
1306 const keyT& key = it->first;
1307 typename dcT::accessor acc;
1308 const auto found = coeffs.find(acc,key);
1309 MADNESS_CHECK(found);
1310 nodeT& node = acc->second;
1311 if (node.has_coeff() &&
1312 node.get_norm_tree() != -1.0 &&
1313 node.coeff().normf() >= truncate_tol(thresh,key)) {
1314
1315 node.set_norm_tree(-1.0); // Indicates already broadened or result of broadening/refining
1316
1317 //int ndir = std::pow(3,NDIM);
1318 int ndir = static_cast<int>(std::pow(static_cast<double>(3), static_cast<int>(NDIM)));
1319 std::vector< Future <bool> > v = future_vector_factory<bool>(ndir);
1320 keyT neigh;
1321 int i=0;
1322 for (HighDimIndexIterator it(NDIM,3); it; ++it) {
1324 for (std::size_t d=0; d<NDIM; ++d) {
1325 const int odd = key.translation()[d] & 0x1L; // 1 if odd, 0 if even
1326 l[d] -= 1; // (0,1,2) --> (-1,0,1)
1327 if (l[d] == -1)
1328 l[d] = -1-odd;
1329 else if (l[d] == 1)
1330 l[d] = 2 - odd;
1331 }
1332 keyT neigh = neighbor(key, keyT(key.level(),l), is_periodic);
1333
1334 if (neigh.is_valid()) {
1335 v[i++] = this->task(coeffs.owner(neigh), &implT::exists_and_has_children, neigh);
1337 else {
1338 v[i++].set(false);
1340 }
1341 woT::task(world.rank(), &implT::broaden_op, key, v);
1343 }
1344 // Reset value of norm tree so that can repeat broadening
1345 if (fence) {
1346 world.gop.fence();
1347 zero_norm_tree();
1348 world.gop.fence();
1350 }
1352 /// sum all the contributions from all scales after applying an operator in mod-NS form
1353 template <typename T, std::size_t NDIM>
1355 set_tree_state(reconstructed);
1356 if (world.rank() == coeffs.owner(cdata.key0))
1357 woT::task(world.rank(), &implT::trickle_down_op, cdata.key0,coeffT());
1358 if (fence) world.gop.fence();
1359 }
1360
1361 /// sum all the contributions from all scales after applying an operator in mod-NS form
1362
1363 /// cf reconstruct_op
1364 template <typename T, std::size_t NDIM>
1366 // Note that after application of an integral operator not all
1367 // siblings may be present so it is necessary to check existence
1368 // and if absent insert an empty leaf node.
1369 //
1370 // If summing the result of an integral operator (i.e., from
1371 // non-standard form) there will be significant scaling function
1372 // coefficients at all levels and possibly difference coefficients
1373 // in leaves, hence the tree may refine as a result.
1374 typename dcT::iterator it = coeffs.find(key).get();
1375 if (it == coeffs.end()) {
1376 coeffs.replace(key,nodeT(coeffT(),false));
1377 it = coeffs.find(key).get();
1378 }
1379 nodeT& node = it->second;
1380
1381 // The integral operator will correctly connect interior nodes
1382 // to children but may leave interior nodes without coefficients
1383 // ... but they still need to sum down so just give them zeros
1384 if (node.coeff().has_no_data()) node.coeff()=coeffT(cdata.vk,targs);
1386 // if (node.has_children() || node.has_coeff()) { // Must allow for inconsistent state from transform, etc.
1387 if (node.has_children()) { // Must allow for inconsistent state from transform, etc.
1388 coeffT d = node.coeff();
1389 if (key.level() > 0) d += s; // -- note accumulate for NS summation
1390 node.clear_coeff();
1391 for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
1392 const keyT& child = kit.key();
1393 coeffT ss= upsample(child,d);
1394 ss.reduce_rank(thresh);
1395 PROFILE_BLOCK(recon_send);
1396 woT::task(coeffs.owner(child), &implT::trickle_down_op, child, ss);
1397 }
1398 }
1399 else {
1400 node.coeff()+=s;
1401 node.coeff().reduce_rank(thresh);
1402 }
1404
1405 /// change the tree state of this function, might or might not respect fence!
1406 template <typename T, std::size_t NDIM>
1407 void FunctionImpl<T,NDIM>::change_tree_state(const TreeState finalstate, bool fence) {
1409 TreeState current_state=get_tree_state();
1410 if (current_state==finalstate) return;
1411
1412 // try direct conversion if possible, otherwise change to reconstructed state,
1413 // and then convert to final state
1415 // try direct conversion
1416 if (finalstate==reconstructed) { // this MUST cover all cases
1417 if (current_state==compressed) reconstruct(fence);
1418 else if (current_state==nonstandard) reconstruct(fence);
1419 else if (current_state==nonstandard_after_apply) reconstruct(fence);
1420 else if (current_state==nonstandard_with_leaves) {
1421 remove_internal_coefficients(fence);
1422 set_tree_state(reconstructed);
1423 }
1424 else if (current_state==redundant) {
1425 remove_internal_coefficients(fence);
1426 set_tree_state(reconstructed);
1428 else if (current_state==redundant_after_merge) {
1429 sum_down(fence);
1430 set_tree_state(reconstructed);
1431 }
1432 else if (current_state==redundant_after_merge) sum_down(fence);
1433 else MADNESS_EXCEPTION("unknown/unsupported current tree state",1);
1434 set_tree_state(reconstructed);
1435 } else if (finalstate==compressed) { // cases that are not covered will be done in two steps
1436 if (current_state==reconstructed) compress(compressed,fence);
1437 if (current_state==nonstandard) standard(fence);
1438 if (current_state==nonstandard_with_leaves) standard(fence);
1439 } else if (finalstate==nonstandard) { // cases that are not covered will be done in two steps
1440 if (current_state==reconstructed) compress(nonstandard,fence);
1441 if (current_state==nonstandard_with_leaves) {
1442 remove_leaf_coefficients(fence);
1443 set_tree_state(nonstandard);
1444 }
1445 } else if (finalstate==nonstandard_with_leaves) { // cases that are not covered will be done in two steps
1447 } else if (finalstate==redundant) { // cases that are not covered will be done in two steps
1448 if (current_state==reconstructed) make_redundant(fence);
1449 } else {
1450 MADNESS_EXCEPTION("unknown/unsupported final tree state",1);
1452 if (fence && VERIFY_TREE) verify_tree(); // Must be after in case nonstandard
1453
1454 // direct conversion worked, we're good
1455 if (finalstate==get_tree_state()) return;
1456
1457
1458 // go through reconstructed state -- requires fence!
1460 print("could not respect no-fence parameter in change_tree_state");
1461 change_tree_state(finalstate,fence);
1463 }
1464
1465
1466
1467 template <typename T, std::size_t NDIM>
1469
1470 if (is_reconstructed()) return;
1471
1472 if (is_redundant() or is_nonstandard_with_leaves()) {
1473 set_tree_state(reconstructed);
1474 this->remove_internal_coefficients(fence);
1475 } else if (is_compressed() or tree_state==nonstandard_after_apply) {
1476 // Must set true here so that successive calls without fence do the right thing
1477 set_tree_state(reconstructed);
1478 if (world.rank() == coeffs.owner(cdata.key0))
1479 woT::task(world.rank(), &implT::reconstruct_op, cdata.key0,coeffT(), true);
1480 } else if (is_nonstandard()) {
1481 // Must set true here so that successive calls without fence do the right thing
1482 set_tree_state(reconstructed);
1483 if (world.rank() == coeffs.owner(cdata.key0))
1484 woT::task(world.rank(), &implT::reconstruct_op, cdata.key0,coeffT(), false);
1485 } else {
1486 MADNESS_EXCEPTION("cannot reconstruct this tree",1);
1487 }
1488 if (fence) world.gop.fence();
1489
1490 }
1491
1492 /// compress the wave function
1493
1494 /// after application there will be sum coefficients at the root level,
1495 /// and difference coefficients at all other levels; furthermore:
1496 /// @param[in] nonstandard keep sum coeffs at all other levels, except leaves
1497 /// @param[in] keepleaves keep sum coeffs (but no diff coeffs) at leaves
1498 /// @param[in] redundant keep only sum coeffs at all levels, discard difference coeffs
1499 template <typename T, std::size_t NDIM>
1500 void FunctionImpl<T,NDIM>::compress(const TreeState newstate, bool fence) {
1501 MADNESS_CHECK_THROW(is_reconstructed(),"impl::compress wants a reconstructe tree");
1502 // Must set true here so that successive calls without fence do the right thing
1503 set_tree_state(newstate);
1504 bool keepleaves1=(tree_state==nonstandard_with_leaves) or (tree_state==redundant);
1505 bool nonstandard1=(tree_state==nonstandard) or (tree_state==nonstandard_with_leaves);
1506 bool redundant1=(tree_state==redundant);
1507
1508 if (world.rank() == coeffs.owner(cdata.key0)) {
1509
1510 compress_spawn(cdata.key0, nonstandard1, keepleaves1, redundant1);
1511 }
1512 if (fence)
1513 world.gop.fence();
1514 }
1515
1516 template <typename T, std::size_t NDIM>
1518 flo_unary_op_node_inplace(remove_internal_coeffs(),fence);
1519 }
1520
1521 template <typename T, std::size_t NDIM>
1523 flo_unary_op_node_inplace(remove_leaf_coeffs(),fence);
1524 }
1525
1526 /// convert this to redundant, i.e. have sum coefficients on all levels
1527 template <typename T, std::size_t NDIM>
1529
1530 // fast return if possible
1531 if (is_redundant()) return;
1532 MADNESS_CHECK_THROW(is_reconstructed(),"impl::make_redundant() wants a reconstructed tree");
1534 }
1535
1536 /// convert this from redundant to standard reconstructed form
1537 template <typename T, std::size_t NDIM>
1539 MADNESS_CHECK_THROW(is_redundant(),"impl::undo_redundant() wants a redundant tree");
1540 set_tree_state(reconstructed);
1541 flo_unary_op_node_inplace(remove_internal_coeffs(),fence);
1542 }
1543
1544
1545 /// compute for each FunctionNode the norm of the function inside that node
1546 template <typename T, std::size_t NDIM>
1548 if (world.rank() == coeffs.owner(cdata.key0))
1549 norm_tree_spawn(cdata.key0);
1550 if (fence)
1551 world.gop.fence();
1552 }
1553
1554 template <typename T, std::size_t NDIM>
1555 double FunctionImpl<T,NDIM>::norm_tree_op(const keyT& key, const std::vector< Future<double> >& v) {
1556 //PROFILE_MEMBER_FUNC(FunctionImpl);
1557 double sum = 0.0;
1558 int i=0;
1559 for (KeyChildIterator<NDIM> kit(key); kit; ++kit,++i) {
1560 double value = v[i].get();
1561 sum += value*value;
1562 }
1563 sum = sqrt(sum);
1564 coeffs.task(key, &nodeT::set_norm_tree, sum); // why a task? because send is deprecated to keep comm thread free
1565 //if (key.level() == 0) std::cout << "NORM_TREE_TOP " << sum << "\n";
1566 return sum;
1567 }
1568
1569 template <typename T, std::size_t NDIM>
1571 nodeT& node = coeffs.find(key).get()->second;
1572 if (node.has_children()) {
1573 std::vector< Future<double> > v = future_vector_factory<double>(1<<NDIM);
1574 int i=0;
1575 for (KeyChildIterator<NDIM> kit(key); kit; ++kit,++i) {
1576 v[i] = woT::task(coeffs.owner(kit.key()), &implT::norm_tree_spawn, kit.key());
1577 }
1578 return woT::task(world.rank(),&implT::norm_tree_op, key, v);
1579 }
1580 else {
1581 // return Future<double>(node.coeff().normf());
1582 const double norm=node.coeff().normf();
1583 // invoked locally anyways
1584 node.set_norm_tree(norm);
1585 return Future<double>(norm);
1586 }
1587 }
1588
1589 /// truncate using a tree in reconstructed form
1590
1591 /// must be invoked where key is local
1592 template <typename T, std::size_t NDIM>
1594 MADNESS_ASSERT(coeffs.probe(key));
1595 nodeT& node = coeffs.find(key).get()->second;
1596
1597 // if this is a leaf node just return the sum coefficients
1598 if (not node.has_children()) return Future<coeffT>(node.coeff());
1599
1600 // if this is an internal node, wait for all the children's sum coefficients
1601 // and use them to determine if the children can be removed
1602 std::vector<Future<coeffT> > v = future_vector_factory<coeffT>(1<<NDIM);
1603 int i=0;
1604 for (KeyChildIterator<NDIM> kit(key); kit; ++kit,++i) {
1605 v[i] = woT::task(coeffs.owner(kit.key()), &implT::truncate_reconstructed_spawn, kit.key(),tol,TaskAttributes::hipri());
1606 }
1607
1608 // will return (possibly empty) sum coefficients
1609 return woT::task(world.rank(),&implT::truncate_reconstructed_op,key,v,tol,TaskAttributes::hipri());
1610
1611 }
1612
1613 /// given the sum coefficients of all children, truncate or not
1614
1615 /// @return new sum coefficients (empty if internal, not empty, if new leaf); might delete its children
1616 template <typename T, std::size_t NDIM>
1617 typename FunctionImpl<T,NDIM>::coeffT FunctionImpl<T,NDIM>::truncate_reconstructed_op(const keyT& key, const std::vector< Future<coeffT > >& v, const double tol) {
1618
1619 MADNESS_ASSERT(coeffs.probe(key));
1620
1621 // the sum coefficients might be empty, which means they come from an internal node
1622 // and we must not truncate; so just return empty coeffs again
1623 for (size_t i=0; i<v.size(); ++i) if (v[i].get().has_no_data()) return coeffT();
1624
1625 // do not truncate below level 1
1626 if (key.level()<2) return coeffT();
1627
1628 // compute the wavelet coefficients from the child nodes
1629 typename dcT::accessor acc;
1630 const auto found = coeffs.find(acc, key);
1631 MADNESS_CHECK(found);
1632 int i=0;
1633 tensorT d(cdata.v2k);
1634 for (KeyChildIterator<NDIM> kit(key); kit; ++kit,++i) {
1635 // d(child_patch(kit.key())) += v[i].get();
1636 d(child_patch(kit.key())) += v[i].get().full_tensor();
1637 }
1638
1639 d = filter(d);
1640 tensorT s=copy(d(cdata.s0));
1641 d(cdata.s0) = 0.0;
1642 const double error=d.normf();
1643
1644 nodeT& node = coeffs.find(key).get()->second;
1645
1646 if (error < truncate_tol(tol,key)) {
1647 node.set_has_children(false);
1648 for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
1649 coeffs.erase(kit.key());
1650 }
1651 // "replace" children with new sum coefficients
1652 coeffT ss=coeffT(s,targs);
1653 acc->second.set_coeff(ss);
1654 return ss;
1655 } else {
1656 return coeffT();
1657 }
1658 }
1659
1660 /// calculate the wavelet coefficients using the sum coefficients of all child nodes
1661
1662 /// @param[in] key this's key
1663 /// @param[in] v sum coefficients of the child nodes
1664 /// @param[in] nonstandard keep the sum coefficients with the wavelet coefficients
1665 /// @param[in] redundant keep only the sum coefficients, discard the wavelet coefficients
1666 /// @return the sum coefficients
1667 template <typename T, std::size_t NDIM>
1668 std::pair<typename FunctionImpl<T,NDIM>::coeffT,double> FunctionImpl<T,NDIM>::compress_op(const keyT& key,
1669 const std::vector< Future<std::pair<coeffT,double> > >& v, bool nonstandard1) {
1670 //PROFILE_MEMBER_FUNC(FunctionImpl);
1671
1672 double cpu0=cpu_time();
1673 // Copy child scaling coeffs into contiguous block
1674 tensorT d(cdata.v2k);
1675 // coeffT d(cdata.v2k,targs);
1676 int i=0;
1677 double norm_tree2=0.0;
1678 for (KeyChildIterator<NDIM> kit(key); kit; ++kit,++i) {
1679 // d(child_patch(kit.key())) += v[i].get();
1680 d(child_patch(kit.key())) += v[i].get().first.full_tensor();
1681 norm_tree2+=v[i].get().second*v[i].get().second;
1682 }
1683
1684 d = filter(d);
1685 double cpu1=cpu_time();
1686 timer_filter.accumulate(cpu1-cpu0);
1687 cpu0=cpu1;
1688
1689 typename dcT::accessor acc;
1690 const auto found = coeffs.find(acc, key);
1691 MADNESS_CHECK(found);
1692 MADNESS_CHECK_THROW(!acc->second.has_coeff(),"compress_op: existing coeffs where there should be none");
1693
1694 // tighter thresh for internal nodes
1695 TensorArgs targs2=targs;
1696 targs2.thresh*=0.1;
1697
1698 // need the deep copy for contiguity
1699 coeffT ss=coeffT(copy(d(cdata.s0)));
1700 double snorm=ss.normf();
1701
1702 if (key.level()> 0 && !nonstandard1) d(cdata.s0) = 0.0;
1703
1704 coeffT dd=coeffT(d,targs2);
1705 double dnorm=dd.normf();
1706 double norm_tree=sqrt(norm_tree2);
1707
1708 acc->second.set_snorm(snorm);
1709 acc->second.set_dnorm(dnorm);
1710 acc->second.set_norm_tree(norm_tree);
1711
1712 acc->second.set_coeff(dd);
1713 cpu1=cpu_time();
1714 timer_compress_svd.accumulate(cpu1-cpu0);
1715
1716 // return sum coefficients
1717 return std::make_pair(ss,snorm);
1718 }
1719
1720 /// similar to compress_op, but insert only the sum coefficients in the tree
1721
1722 /// also sets snorm, dnorm and norm_tree for all nodes
1723 /// @param[in] key this's key
1724 /// @param[in] v sum coefficients of the child nodes
1725 /// @return the sum coefficients
1726 template <typename T, std::size_t NDIM>
1727 std::pair<typename FunctionImpl<T,NDIM>::coeffT,double>
1728 FunctionImpl<T,NDIM>::make_redundant_op(const keyT& key, const std::vector< Future<std::pair<coeffT,double> > >& v) {
1729
1730 tensorT d(cdata.v2k);
1731 int i=0;
1732 double norm_tree2=0.0;
1733 for (KeyChildIterator<NDIM> kit(key); kit; ++kit,++i) {
1734 d(child_patch(kit.key())) += v[i].get().first.full_tensor();
1735 norm_tree2+=v[i].get().second*v[i].get().second;
1736 }
1737 d = filter(d);
1738 double norm_tree=sqrt(norm_tree2);
1739
1740 // tighter thresh for internal nodes
1741 TensorArgs targs2=targs;
1742 targs2.thresh*=0.1;
1744 // need the deep copy for contiguity
1745 coeffT s=coeffT(copy(d(cdata.s0)),targs2);
1746 d(cdata.s0)=0.0;
1747 double dnorm=d.normf();
1748 double snorm=s.normf();
1749
1750 typename dcT::accessor acc;
1751 const auto found = coeffs.find(acc, key);
1752 MADNESS_CHECK(found);
1754 acc->second.set_coeff(s);
1755 acc->second.set_dnorm(dnorm);
1756 acc->second.set_snorm(snorm);
1757 acc->second.set_norm_tree(norm_tree);
1758
1759 // return sum coefficients
1760 return std::make_pair(s,norm_tree);
1761 }
1762
1763 /// Changes non-standard compressed form to standard compressed form
1764 template <typename T, std::size_t NDIM>
1766
1767 if (is_compressed()) return;
1768 set_tree_state(compressed);
1769 flo_unary_op_node_inplace(do_standard(this),fence);
1770// make_nonstandard = false;
1771 }
1772
1773
1774 /// after apply we need to do some cleanup;
1775
1776 /// forces fence
1777 template <typename T, std::size_t NDIM>
1779 bool print_timings=false;
1780 bool printme=(world.rank()==0 and print_timings);
1781 TensorArgs tight_args(targs);
1782 tight_args.thresh*=0.01;
1783 double begin=wall_time();
1784 double begin1=wall_time();
1785 flo_unary_op_node_inplace(do_consolidate_buffer(tight_args),true);
1786 double end1=wall_time();
1787 if (printme) printf("time in consolidate_buffer %8.4f\n",end1-begin1);
1788
1789
1790 // reduce the rank of the final nodes, leave full tensors unchanged
1791 // flo_unary_op_node_inplace(do_reduce_rank(tight_args.thresh),true);
1792 begin1=wall_time();
1793 flo_unary_op_node_inplace(do_reduce_rank(targs),true);
1794 end1=wall_time();
1795 if (printme) printf("time in do_reduce_rank %8.4f\n",end1-begin1);
1796
1797 // change TT_FULL to low rank
1798 begin1=wall_time();
1799 flo_unary_op_node_inplace(do_change_tensor_type(targs,*this),true);
1800 end1=wall_time();
1801 if (printme) printf("time in do_change_tensor_type %8.4f\n",end1-begin1);
1803 // truncate leaf nodes to avoid excessive tree refinement
1804 begin1=wall_time();
1805 flo_unary_op_node_inplace(do_truncate_NS_leafs(this),true);
1806 end1=wall_time();
1807 if (printme) printf("time in do_truncate_NS_leafs %8.4f\n",end1-begin1);
1808
1809 double end=wall_time();
1810 double elapsed=end-begin;
1811 set_tree_state(nonstandard_after_apply);
1812 world.gop.fence();
1813 return elapsed;
1814 }
1815
1816
1817 /// after summing up we need to do some cleanup;
1818
1819 /// forces fence
1820 template <typename T, std::size_t NDIM>
1822 world.gop.fence();
1823 flo_unary_op_node_inplace(do_consolidate_buffer(get_tensor_args()), true);
1824 sum_down(true);
1825 set_tree_state(reconstructed);
1826 }
1827
1828 /// Returns the square of the local norm ... no comms
1829 template <typename T, std::size_t NDIM>
1833 return world.taskq.reduce<double,rangeT,do_norm2sq_local>(rangeT(coeffs.begin(),coeffs.end()),
1835 }
1836
1837
1838
1839
1840 /// Returns the maximum local depth of the tree ... no communications.
1841 template <typename T, std::size_t NDIM>
1843 std::size_t maxdepth = 0;
1844 typename dcT::const_iterator end = coeffs.end();
1845 for (typename dcT::const_iterator it=coeffs.begin(); it!=end; ++it) {
1846 std::size_t N = (std::size_t) it->first.level();
1847 if (N> maxdepth)
1848 maxdepth = N;
1849 }
1850 return maxdepth;
1851 }
1852
1853
1854 /// Returns the maximum depth of the tree ... collective ... global sum/broadcast
1855 template <typename T, std::size_t NDIM>
1857 std::size_t maxdepth = max_local_depth();
1858 world.gop.max(maxdepth);
1859 return maxdepth;
1860 }
1861
1862 /// Returns the max number of nodes on a processor
1863 template <typename T, std::size_t NDIM>
1865 std::size_t maxsize = 0;
1866 maxsize = coeffs.size();
1867 world.gop.max(maxsize);
1868 return maxsize;
1869 }
1870
1871 /// Returns the min number of nodes on a processor
1872 template <typename T, std::size_t NDIM>
1874 std::size_t minsize = 0;
1875 minsize = coeffs.size();
1876 world.gop.min(minsize);
1877 return minsize;
1878 }
1879
1880 /// Returns the size of the tree structure of the function ... collective global sum
1881 template <typename T, std::size_t NDIM>
1883 std::size_t sum = 0;
1884 sum = coeffs.size();
1885 world.gop.sum(sum);
1886 return sum;
1887 }
1888
1889 /// Returns the number of coefficients in the function for each rank
1890 template <typename T, std::size_t NDIM>
1892 std::size_t sum = 0;
1893 for (const auto& [key,node] : coeffs) {
1894 if (node.has_coeff()) sum+=node.size();
1895 }
1896 return sum;
1897 }
1898
1899 /// Returns the number of coefficients in the function ... collective global sum
1900 template <typename T, std::size_t NDIM>
1901 std::size_t FunctionImpl<T,NDIM>::size() const {
1902 std::size_t sum = size_local();
1903 world.gop.sum(sum);
1904 return sum;
1905 }
1906
1907 /// Returns the number of coefficients in the function ... collective global sum
1908 template <typename T, std::size_t NDIM>
1910 std::size_t sum = coeffs.size() * (sizeof(keyT) + sizeof(nodeT));
1911 typename dcT::const_iterator end = coeffs.end();
1912 for (typename dcT::const_iterator it=coeffs.begin(); it!=end; ++it) {
1913 const nodeT& node = it->second;
1914 if (node.has_coeff()) sum+=node.coeff().real_size();
1915 }
1916 world.gop.sum(sum);
1917 return sum;
1918 }
1919
1920 /// Returns the number of coefficients in the function on this MPI rank
1921 template <typename T, std::size_t NDIM>
1923 std::size_t sum =0;
1924 for (auto& [key,node] : coeffs) {
1925 if (node.has_coeff()) sum+=node.coeff().nCoeff();
1926 }
1927 return sum;
1928 }
1929
1930 /// Returns the number of coefficients in the function ... collective global sum
1931 template <typename T, std::size_t NDIM>
1932 std::size_t FunctionImpl<T,NDIM>::nCoeff() const {
1933 std::size_t sum = nCoeff_local();
1934 world.gop.sum(sum);
1935 return sum;
1936 }
1937
1938
1939 /// print tree size and size
1940 template <typename T, std::size_t NDIM>
1941 void FunctionImpl<T,NDIM>::print_size(const std::string name) const {
1942 const size_t tsize=this->tree_size();
1943// const size_t size=this->size();
1944 const size_t ncoeff=this->nCoeff();
1945 const double wall=wall_time();
1946 const double d=sizeof(T);
1947 const double fac=1024*1024*1024;
1948
1949 double norm=0.0;
1950 {
1951 double local = norm2sq_local();
1952 this->world.gop.sum(local);
1953 this->world.gop.fence();
1954 norm=sqrt(local);
1955 }
1956
1957 if (this->world.rank()==0) {
1958
1959 constexpr std::size_t bufsize=128;
1960 char buf[bufsize];
1961 snprintf(buf, bufsize, "%40s at time %.1fs: norm/tree/#coeff/size: %7.5f %zu, %6.3f m, %6.3f GByte",
1962 (name.c_str()), wall, norm, tsize,double(ncoeff)*1.e-6,double(ncoeff)/fac*d);
1963 print(std::string(buf));
1964 }
1965 }
1966
1967 /// print the number of configurations per node
1968 template <typename T, std::size_t NDIM>
1970 if (this->targs.tt==TT_FULL) return;
1971 int dim=NDIM/2;
1972 int k0=k;
1973 if (is_compressed()) k0=2*k;
1974 Tensor<long> n(int(std::pow(double(k0),double(dim))+1));
1975 long n_full=0;
1976 long n_large=0;
1977
1978 if (world.rank()==0) print("n.size(),k0,dim",n.size(),k0,dim);
1979 typename dcT::const_iterator end = coeffs.end();
1980 for (typename dcT::const_iterator it=coeffs.begin(); it!=end; ++it) {
1981 const nodeT& node = it->second;
1982 if (node.has_coeff()) {
1983 if (node.coeff().rank()>long(n.size())) {
1984 ++n_large;
1985 } else if (node.coeff().rank()==-1) {
1986 ++n_full;
1987 } else if (node.coeff().rank()<0) {
1988 print("small rank",node.coeff().rank());
1989 } else {
1990 n[node.coeff().rank()]++;
1991 }
1992 }
1993 }
1994
1995 world.gop.sum(n.ptr(), n.size());
1996
1997 if (world.rank()==0) {
1998 print("configurations number of nodes");
1999 print(" full rank ",n_full);
2000 for (unsigned int i=0; i<n.size(); i++) {
2001 print(" ",i," ",n[i]);
2002 }
2003 print(" large rank ",n_large);
2004
2005 // repeat for logarithmic scale: <3, <10, <30, <100, ..
2006 Tensor<long> nlog(6);
2007 nlog=0;
2008 for (unsigned int i=0; i<std::min(3l,n.size()); i++) nlog[0]+=n[i];
2009 for (unsigned int i=3; i<std::min(10l,n.size()); i++) nlog[1]+=n[i];
2010 for (unsigned int i=10; i<std::min(30l,n.size()); i++) nlog[2]+=n[i];
2011 for (unsigned int i=30; i<std::min(100l,n.size()); i++) nlog[3]+=n[i];
2012 for (unsigned int i=100; i<std::min(300l,n.size()); i++) nlog[4]+=n[i];
2013 for (unsigned int i=300; i<std::min(1000l,n.size()); i++) nlog[5]+=n[i];
2014
2015 std::vector<std::string> slog={"3","10","30","100","300","1000"};
2016 for (unsigned int i=0; i<nlog.size(); i++) {
2017 print(" < ",slog[i]," ",nlog[i]);
2018 }
2019 print(" large rank ",n_large);
2020
2021 }
2022 }
2023
2024 template <typename T, std::size_t NDIM>
2027 const int k = cdata.k;
2028 double px[NDIM][MAXK];
2029 T sum = T(0.0);
2030
2031 for (std::size_t i=0; i<NDIM; ++i) legendre_scaling_functions(x[i],k,px[i]);
2032
2033 if (NDIM == 1) {
2034 for (int p=0; p<k; ++p)
2035 sum += c(p)*px[0][p];
2036 }
2037 else if (NDIM == 2) {
2038 for (int p=0; p<k; ++p)
2039 for (int q=0; q<k; ++q)
2040 sum += c(p,q)*px[0][p]*px[1][q];
2041 }
2042 else if (NDIM == 3) {
2043 for (int p=0; p<k; ++p)
2044 for (int q=0; q<k; ++q)
2045 for (int r=0; r<k; ++r)
2046 sum += c(p,q,r)*px[0][p]*px[1][q]*px[2][r];
2047 }
2048 else if (NDIM == 4) {
2049 for (int p=0; p<k; ++p)
2050 for (int q=0; q<k; ++q)
2051 for (int r=0; r<k; ++r)
2052 for (int s=0; s<k; ++s)
2053 sum += c(p,q,r,s)*px[0][p]*px[1][q]*px[2][r]*px[3][s];
2054 }
2055 else if (NDIM == 5) {
2056 for (int p=0; p<k; ++p)
2057 for (int q=0; q<k; ++q)
2058 for (int r=0; r<k; ++r)
2059 for (int s=0; s<k; ++s)
2060 for (int t=0; t<k; ++t)
2061 sum += c(p,q,r,s,t)*px[0][p]*px[1][q]*px[2][r]*px[3][s]*px[4][t];
2062 }
2063 else if (NDIM == 6) {
2064 for (int p=0; p<k; ++p)
2065 for (int q=0; q<k; ++q)
2066 for (int r=0; r<k; ++r)
2067 for (int s=0; s<k; ++s)
2068 for (int t=0; t<k; ++t)
2069 for (int u=0; u<k; ++u)
2070 sum += c(p,q,r,s,t,u)*px[0][p]*px[1][q]*px[2][r]*px[3][s]*px[4][t]*px[5][u];
2071 }
2072 else {
2073 MADNESS_EXCEPTION("FunctionImpl:eval_cube:NDIM?",NDIM);
2074 }
2075 return sum*pow(2.0,0.5*NDIM*n)/sqrt(FunctionDefaults<NDIM>::get_cell_volume());
2076 }
2077
2078 template <typename T, std::size_t NDIM>
2079 void FunctionImpl<T,NDIM>::reconstruct_op(const keyT& key, const coeffT& s, const bool accumulate_NS) {
2080 //PROFILE_MEMBER_FUNC(FunctionImpl);
2081 // Note that after application of an integral operator not all
2082 // siblings may be present so it is necessary to check existence
2083 // and if absent insert an empty leaf node.
2084 //
2085 // If summing the result of an integral operator (i.e., from
2086 // non-standard form) there will be significant scaling function
2087 // coefficients at all levels and possibly difference coefficients
2088 // in leaves, hence the tree may refine as a result.
2089 typename dcT::iterator it = coeffs.find(key).get();
2090 if (it == coeffs.end()) {
2091 coeffs.replace(key,nodeT(coeffT(),false));
2092 it = coeffs.find(key).get();
2093 }
2094 nodeT& node = it->second;
2095
2096 // The integral operator will correctly connect interior nodes
2097 // to children but may leave interior nodes without coefficients
2098 // ... but they still need to sum down so just give them zeros
2099 if (node.has_children() && !node.has_coeff()) {
2100 node.set_coeff(coeffT(cdata.v2k,targs));
2101 }
2102
2103 if (node.has_children() || node.has_coeff()) { // Must allow for inconsistent state from transform, etc.
2104 coeffT d = node.coeff();
2105 if (!d.has_data()) d = coeffT(cdata.v2k,targs);
2106 if (accumulate_NS and (key.level() > 0)) d(cdata.s0) += s; // -- note accumulate for NS summation
2107 if (d.dim(0)==2*get_k()) { // d might be pre-truncated if it's a leaf
2108 d = unfilter(d);
2109 node.clear_coeff();
2110 node.set_has_children(true);
2111 for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
2112 const keyT& child = kit.key();
2113 coeffT ss = copy(d(child_patch(child)));
2114 ss.reduce_rank(thresh);
2115 //PROFILE_BLOCK(recon_send); // Too fine grain for routine profiling
2116 woT::task(coeffs.owner(child), &implT::reconstruct_op, child, ss, accumulate_NS);
2117 }
2118 } else {
2119 MADNESS_ASSERT(node.is_leaf());
2120 // node.coeff()+=s;
2121 node.coeff().reduce_rank(targs.thresh);
2122 }
2123 }
2124 else {
2125 coeffT ss=s;
2126 if (s.has_no_data()) ss=coeffT(cdata.vk,targs);
2127 if (key.level()) node.set_coeff(copy(ss));
2128 else node.set_coeff(ss);
2129 }
2130 }
2131
2132 template <typename T, std::size_t NDIM>
2133 Tensor<T> fcube(const Key<NDIM>& key, T (*f)(const Vector<double,NDIM>&), const Tensor<double>& qx) {
2134 // fcube(key,typename FunctionFactory<T,NDIM>::FunctorInterfaceWrapper(f) , qx, fval);
2135 std::vector<long> npt(NDIM,qx.dim(0));
2136 Tensor<T> fval(npt);
2137 fcube(key,ElementaryInterface<T,NDIM>(f) , qx, fval);
2138 return fval;
2139 }
2140
2141 template <typename T, std::size_t NDIM>
2143 // fcube(key,typename FunctionFactory<T,NDIM>::FunctorInterfaceWrapper(f) , qx, fval);
2144 std::vector<long> npt(NDIM,qx.dim(0));
2145 Tensor<T> fval(npt);
2146 fcube(key, f, qx, fval);
2147 return fval;
2148 }
2149
2150 template <typename T, std::size_t NDIM>
2151 // void FunctionImpl<T,NDIM>::fcube(const keyT& key, const FunctionFunctorInterface<T,NDIM>& f, const Tensor<double>& qx, tensorT& fval) const {
2152 void fcube(const Key<NDIM>& key, const FunctionFunctorInterface<T,NDIM>& f, const Tensor<double>& qx, Tensor<T>& fval) {
2153 //~ template <typename T, std::size_t NDIM> template< typename FF>
2154 //~ void FunctionImpl<T,NDIM>::fcube(const keyT& key, const FF& f, const Tensor<double>& qx, tensorT& fval) const {
2156 //PROFILE_MEMBER_FUNC(FunctionImpl);
2157 const Vector<Translation,NDIM>& l = key.translation();
2158 const Level n = key.level();
2159 const double h = std::pow(0.5,double(n));
2160 coordT c; // will hold the point in user coordinates
2161 const int npt = qx.dim(0);
2162
2165
2166 // Do pre-screening of the FunctionFunctorInterface, f, before calculating f(r) at quadrature points
2167 coordT c1, c2;
2168 for (std::size_t i = 0; i < NDIM; i++) {
2169 c1[i] = cell(i,0) + h*cell_width[i]*(l[i] + qx((long)0));
2170 c2[i] = cell(i,0) + h*cell_width[i]*(l[i] + qx(npt-1));
2171 }
2172 if (f.screened(c1, c2)) {
2173 fval(___) = 0.0;
2174 return;
2175 }
2176
2177 Tensor<double> vqx;
2178 bool vectorized = f.supports_vectorized();
2179 if (vectorized) {
2180 T* fvptr = fval.ptr();
2181 if (NDIM == 1) {
2182 double* x1 = new double[npt];
2183 int idx = 0;
2184 for (int i=0; i<npt; ++i, ++idx) {
2185 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
2186 x1[idx] = c[0];
2187 }
2188 Vector<double*,1> xvals {x1};
2189 f(xvals, fvptr, npt);
2190 delete [] x1;
2191 }
2192 else if (NDIM == 2) {
2193 double* x1 = new double[npt*npt];
2194 double* x2 = new double[npt*npt];
2195 int idx = 0;
2196 for (int i=0; i<npt; ++i) {
2197 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
2198 for (int j=0; j<npt; ++j, ++idx) {
2199 c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
2200 x1[idx] = c[0];
2201 x2[idx] = c[1];
2202 }
2203 }
2204 Vector<double*,2> xvals {x1, x2};
2205 f(xvals, fvptr, npt*npt);
2206 delete [] x1;
2207 delete [] x2;
2208 }
2209 else if (NDIM == 3) {
2210 double* x1 = new double[npt*npt*npt];
2211 double* x2 = new double[npt*npt*npt];
2212 double* x3 = new double[npt*npt*npt];
2213 int idx = 0;
2214 for (int i=0; i<npt; ++i) {
2215 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
2216 for (int j=0; j<npt; ++j) {
2217 c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
2218 for (int k=0; k<npt; ++k, ++idx) {
2219 c[2] = cell(2,0) + h*cell_width[2]*(l[2] + qx(k)); // z
2220 x1[idx] = c[0];
2221 x2[idx] = c[1];
2222 x3[idx] = c[2];
2223 }
2224 }
2225 }
2226 Vector<double*,3> xvals {x1, x2, x3};
2227 f(xvals, fvptr, npt*npt*npt);
2228 delete [] x1;
2229 delete [] x2;
2230 delete [] x3;
2231 }
2232 else if (NDIM == 4) {
2233 double* x1 = new double[npt*npt*npt*npt];
2234 double* x2 = new double[npt*npt*npt*npt];
2235 double* x3 = new double[npt*npt*npt*npt];
2236 double* x4 = new double[npt*npt*npt*npt];
2237 int idx = 0;
2238 for (int i=0; i<npt; ++i) {
2239 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
2240 for (int j=0; j<npt; ++j) {
2241 c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
2242 for (int k=0; k<npt; ++k) {
2243 c[2] = cell(2,0) + h*cell_width[2]*(l[2] + qx(k)); // z
2244 for (int m=0; m<npt; ++m, ++idx) {
2245 c[3] = cell(3,0) + h*cell_width[3]*(l[3] + qx(m)); // xx
2246 x1[idx] = c[0];
2247 x2[idx] = c[1];
2248 x3[idx] = c[2];
2249 x4[idx] = c[3];
2250 }
2251 }
2253 }
2254 Vector<double*,4> xvals {x1, x2, x3, x4};
2255 f(xvals, fvptr, npt*npt*npt*npt);
2256 delete [] x1;
2257 delete [] x2;
2258 delete [] x3;
2259 delete [] x4;
2260 }
2261 else if (NDIM == 5) {
2262 double* x1 = new double[npt*npt*npt*npt*npt];
2263 double* x2 = new double[npt*npt*npt*npt*npt];
2264 double* x3 = new double[npt*npt*npt*npt*npt];
2265 double* x4 = new double[npt*npt*npt*npt*npt];
2266 double* x5 = new double[npt*npt*npt*npt*npt];
2267 int idx = 0;
2268 for (int i=0; i<npt; ++i) {
2269 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
2270 for (int j=0; j<npt; ++j) {
2271 c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
2272 for (int k=0; k<npt; ++k) {
2273 c[2] = cell(2,0) + h*cell_width[2]*(l[2] + qx(k)); // z
2274 for (int m=0; m<npt; ++m) {
2275 c[3] = cell(3,0) + h*cell_width[3]*(l[3] + qx(m)); // xx
2276 for (int n=0; n<npt; ++n, ++idx) {
2277 c[4] = cell(4,0) + h*cell_width[4]*(l[4] + qx(n)); // yy
2278 x1[idx] = c[0];
2279 x2[idx] = c[1];
2280 x3[idx] = c[2];
2281 x4[idx] = c[3];
2282 x5[idx] = c[4];
2283 }
2284 }
2285 }
2286 }
2287 }
2288 Vector<double*,5> xvals {x1, x2, x3, x4, x5};
2289 f(xvals, fvptr, npt*npt*npt*npt*npt);
2290 delete [] x1;
2291 delete [] x2;
2292 delete [] x3;
2293 delete [] x4;
2294 delete [] x5;
2295 }
2296 else if (NDIM == 6) {
2297 double* x1 = new double[npt*npt*npt*npt*npt*npt];
2298 double* x2 = new double[npt*npt*npt*npt*npt*npt];
2299 double* x3 = new double[npt*npt*npt*npt*npt*npt];
2300 double* x4 = new double[npt*npt*npt*npt*npt*npt];
2301 double* x5 = new double[npt*npt*npt*npt*npt*npt];
2302 double* x6 = new double[npt*npt*npt*npt*npt*npt];
2303 int idx = 0;
2304 for (int i=0; i<npt; ++i) {
2305 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
2306 for (int j=0; j<npt; ++j) {
2307 c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
2308 for (int k=0; k<npt; ++k) {
2309 c[2] = cell(2,0) + h*cell_width[2]*(l[2] + qx(k)); // z
2310 for (int m=0; m<npt; ++m) {
2311 c[3] = cell(3,0) + h*cell_width[3]*(l[3] + qx(m)); // xx
2312 for (int n=0; n<npt; ++n) {
2313 c[4] = cell(4,0) + h*cell_width[4]*(l[4] + qx(n)); // yy
2314 for (int p=0; p<npt; ++p, ++idx) {
2315 c[5] = cell(5,0) + h*cell_width[5]*(l[5] + qx(p)); // zz
2316 x1[idx] = c[0];
2317 x2[idx] = c[1];
2318 x3[idx] = c[2];
2319 x4[idx] = c[3];
2320 x5[idx] = c[4];
2321 x6[idx] = c[5];
2322 }
2323 }
2324 }
2325 }
2326 }
2327 }
2328 Vector<double*,6> xvals {x1, x2, x3, x4, x5, x6};
2329 f(xvals, fvptr, npt*npt*npt*npt*npt*npt);
2330 delete [] x1;
2331 delete [] x2;
2332 delete [] x3;
2333 delete [] x4;
2334 delete [] x5;
2335 delete [] x6;
2336 }
2337 else {
2338 MADNESS_EXCEPTION("FunctionImpl: fcube: confused about NDIM?",NDIM);
2339 }
2340 }
2341 else {
2342 MADNESS_PRAGMA_CLANG(diagnostic push)
2343 MADNESS_PRAGMA_CLANG(diagnostic ignored "-Wtautological-constant-compare")
2344 auto isnan = [](T v) { return std::isnan(v); };
2345 MADNESS_PRAGMA_CLANG(diagnostic pop)
2346 if (NDIM == 1) {
2347 for (int i=0; i<npt; ++i) {
2348 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
2349 fval(i) = f(c);
2350 MADNESS_ASSERT(!isnan(fval(i)));
2351 }
2352 }
2353 else if (NDIM == 2) {
2354 for (int i=0; i<npt; ++i) {
2355 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
2356 for (int j=0; j<npt; ++j) {
2357 c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
2358 fval(i,j) = f(c);
2359 MADNESS_ASSERT(!isnan(fval(i,j)));
2360 }
2361 }
2362 }
2363 else if (NDIM == 3) {
2364 for (int i=0; i<npt; ++i) {
2365 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
2366 for (int j=0; j<npt; ++j) {
2367 c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
2368 for (int k=0; k<npt; ++k) {
2369 c[2] = cell(2,0) + h*cell_width[2]*(l[2] + qx(k)); // z
2370 fval(i,j,k) = f(c);
2371 MADNESS_ASSERT(!isnan(fval(i,j,k)));
2372 }
2373 }
2374 }
2375 }
2376 else if (NDIM == 4) {
2377 for (int i=0; i<npt; ++i) {
2378 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
2379 for (int j=0; j<npt; ++j) {
2380 c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
2381 for (int k=0; k<npt; ++k) {
2382 c[2] = cell(2,0) + h*cell_width[2]*(l[2] + qx(k)); // z
2383 for (int m=0; m<npt; ++m) {
2384 c[3] = cell(3,0) + h*cell_width[3]*(l[3] + qx(m)); // xx
2385 fval(i,j,k,m) = f(c);
2386 MADNESS_ASSERT(!isnan(fval(i,j,k,m)));
2387 }
2388 }
2389 }
2390 }
2391 }
2392 else if (NDIM == 5) {
2393 for (int i=0; i<npt; ++i) {
2394 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
2395 for (int j=0; j<npt; ++j) {
2396 c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
2397 for (int k=0; k<npt; ++k) {
2398 c[2] = cell(2,0) + h*cell_width[2]*(l[2] + qx(k)); // z
2399 for (int m=0; m<npt; ++m) {
2400 c[3] = cell(3,0) + h*cell_width[3]*(l[3] + qx(m)); // xx
2401 for (int n=0; n<npt; ++n) {
2402 c[4] = cell(4,0) + h*cell_width[4]*(l[4] + qx(n)); // yy
2403 fval(i,j,k,m,n) = f(c);
2404 MADNESS_ASSERT(!isnan(fval(i,j,k,m,n)));
2405 }
2406 }
2407 }
2408 }
2409 }
2410 }
2411 else if (NDIM == 6) {
2412 for (int i=0; i<npt; ++i) {
2413 c[0] = cell(0,0) + h*cell_width[0]*(l[0] + qx(i)); // x
2414 for (int j=0; j<npt; ++j) {
2415 c[1] = cell(1,0) + h*cell_width[1]*(l[1] + qx(j)); // y
2416 for (int k=0; k<npt; ++k) {
2417 c[2] = cell(2,0) + h*cell_width[2]*(l[2] + qx(k)); // z
2418 for (int m=0; m<npt; ++m) {
2419 c[3] = cell(3,0) + h*cell_width[3]*(l[3] + qx(m)); // xx
2420 for (int n=0; n<npt; ++n) {
2421 c[4] = cell(4,0) + h*cell_width[4]*(l[4] + qx(n)); // yy
2422 for (int p=0; p<npt; ++p) {
2423 c[5] = cell(5,0) + h*cell_width[5]*(l[5] + qx(p)); // zz
2424 fval(i,j,k,m,n,p) = f(c);
2425 MADNESS_ASSERT(!isnan(fval(i,j,k,m,n,p)));
2426 }
2427 }
2428 }
2429 }
2430 }
2431 }
2432 }
2433 else {
2434 MADNESS_EXCEPTION("FunctionImpl: fcube: confused about NDIM?",NDIM);
2435 }
2436 }
2437 }
2438
2439 template <typename T, std::size_t NDIM>
2440 void FunctionImpl<T,NDIM>::fcube(const keyT& key, T (*f)(const coordT&), const Tensor<double>& qx, tensorT& fval) const {
2441 // fcube(key,typename FunctionFactory<T,NDIM>::FunctorInterfaceWrapper(f) , qx, fval);
2443 }
2444
2445 template <typename T, std::size_t NDIM>
2447 madness::fcube(key,f,qx,fval);
2448 }
2449
2450
2451 /// project the functor into this functionimpl, and "return" a tree in reconstructed,
2452 /// rank-reduced form.
2453
2454 /// @param[in] key current FunctionNode
2455 /// @param[in] do_refine
2456 /// @param[in] specialpts in case these are very spiky functions -- don't undersample
2457 template <typename T, std::size_t NDIM>
2459 bool do_refine,
2460 const std::vector<Vector<double,NDIM> >& specialpts) {
2461 //PROFILE_MEMBER_FUNC(FunctionImpl);
2462 if (do_refine && key.level() < max_refine_level) {
2463
2464 // Restrict special points to this box
2465 std::vector<Vector<double,NDIM> > newspecialpts;
2466 if (key.level() < special_level && specialpts.size() > 0) {
2468 const auto bperiodic = bc.is_periodic();
2469 for (unsigned int i = 0; i < specialpts.size(); ++i) {
2470 coordT simpt;
2471 user_to_sim(specialpts[i], simpt);
2472 Key<NDIM> specialkey = simpt2key(simpt, key.level());
2473 if (specialkey.is_neighbor_of(key,bperiodic)) {
2474 newspecialpts.push_back(specialpts[i]);
2475 }
2476 }
2477 }
2478
2479 // If refining compute scaling function coefficients and
2480 // norm of difference coefficients
2481 tensorT r, s0;
2482 double dnorm = 0.0;
2483 //////////////////////////if (newspecialpts.size() == 0)
2484 {
2485 // Make in r child scaling function coeffs at level n+1
2486 r = tensorT(cdata.v2k);
2487 for (KeyChildIterator<NDIM> it(key); it; ++it) {
2488 const keyT& child = it.key();
2489 r(child_patch(child)) = project(child);
2490 }
2491 // Filter then test difference coeffs at level n
2492 tensorT d = filter(r);
2493 if (truncate_on_project) s0 = copy(d(cdata.s0));
2494 d(cdata.s0) = T(0);
2495 dnorm = d.normf();
2496 }
2497
2498 // If have special points always refine. If don't have special points
2499 // refine if difference norm is big
2500 if (newspecialpts.size() > 0 || dnorm >=truncate_tol(thresh,key.level())) {
2501 coeffs.replace(key,nodeT(coeffT(),true)); // Insert empty node for parent
2502 for (KeyChildIterator<NDIM> it(key); it; ++it) {
2503 const keyT& child = it.key();
2504 ProcessID p;
2506 p = world.random_proc();
2507 }
2508 else {
2509 p = coeffs.owner(child);
2510 }
2511 //PROFILE_BLOCK(proj_refine_send); // Too fine grain for routine profiling
2512 woT::task(p, &implT::project_refine_op, child, do_refine, newspecialpts);
2513 }
2514 }
2515 else {
2516 if (truncate_on_project) {
2518 coeffs.replace(key,nodeT(s,false));
2519 }
2520 else {
2521 coeffs.replace(key,nodeT(coeffT(),true)); // Insert empty node for parent
2522 for (KeyChildIterator<NDIM> it(key); it; ++it) {
2523 const keyT& child = it.key();
2524 coeffT s(r(child_patch(child)),thresh,FunctionDefaults<NDIM>::get_tensor_type());
2525 coeffs.replace(child,nodeT(s,false));
2526 }
2527 }
2528 }
2529 }
2530 else {
2531 coeffs.replace(key,nodeT(coeffT(project(key),targs),false));
2532 }
2533 }
2534
2535 template <typename T, std::size_t NDIM>
2537 std::vector<long> v0(NDIM,0L);
2538 std::vector<long> v1(NDIM,1L);
2539 std::vector<Slice> s(NDIM,Slice(0,0));
2540 const TensorArgs full_args(-1.0,TT_FULL);
2541 if (is_compressed()) {
2542 if (world.rank() == coeffs.owner(cdata.key0)) {
2543 typename dcT::iterator it = coeffs.find(cdata.key0).get();
2544 MADNESS_ASSERT(it != coeffs.end());
2545 nodeT& node = it->second;
2546 MADNESS_ASSERT(node.has_coeff());
2547 // node.node_to_full_rank();
2548 // node.full_tensor_reference()(v0) += t*sqrt(FunctionDefaults<NDIM>::get_cell_volume());
2549 // node.node_to_low_rank();
2550 change_tensor_type(node.coeff(),full_args);
2552 change_tensor_type(node.coeff(),targs);
2553 }
2554 }
2555 else {
2556 for (typename dcT::iterator it=coeffs.begin(); it!=coeffs.end(); ++it) {
2557 Level n = it->first.level();
2558 nodeT& node = it->second;
2559 if (node.has_coeff()) {
2560 // this looks funny, but is necessary for GenTensor, since you can't access a
2561 // single matrix element. Therefore make a (1^NDIM) tensor, convert to GenTensor, then
2562 // add to the original one by adding a slice.
2563 tensorT ttt(v1);
2564 ttt=t*sqrt(FunctionDefaults<NDIM>::get_cell_volume()*pow(0.5,double(NDIM*n)));
2565 coeffT tt(ttt,get_tensor_args());
2566 node.coeff()(s) += tt;
2567 // this was the original line:
2568 // node.coeff().full_tensor()(v0) += t*sqrt(FunctionDefaults<NDIM>::get_cell_volume()*pow(0.5,double(NDIM*n)));
2569
2570 }
2571 }
2572 }
2573 if (fence) world.gop.fence();
2574 }
2575
2576 template <typename T, std::size_t NDIM>
2579 if (is_compressed()) initial_level = std::max(initial_level,1); // Otherwise zero function is confused
2580 if (coeffs.is_local(key)) {
2581 if (is_compressed()) {
2582 if (key.level() == initial_level) {
2583 coeffs.replace(key, nodeT(coeffT(), false));
2584 }
2585 else {
2586 coeffs.replace(key, nodeT(coeffT(cdata.v2k,targs), true));
2587 }
2588 }
2589 else {
2590 if (key.level()<initial_level) {
2591 coeffs.replace(key, nodeT(coeffT(), true));
2592 }
2593 else {
2594 coeffs.replace(key, nodeT(coeffT(cdata.vk,targs), false));
2595 }
2596 }
2597 }
2598 if (key.level() < initial_level) {
2599 for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
2600 insert_zero_down_to_initial_level(kit.key());
2601 }
2602 }
2603
2604 }
2605
2606
2607 template <typename T, std::size_t NDIM>
2609 //PROFILE_MEMBER_FUNC(FunctionImpl);
2610 typename dcT::iterator it = coeffs.find(key).get();
2611 if (it == coeffs.end()) {
2612 // In a standard tree all children would exist but some ops (transform)
2613 // can leave the tree in a messy state. Just make the missing node as an
2614 // empty leaf.
2615 coeffs.replace(key,nodeT());
2616 it = coeffs.find(key).get();
2617 }
2618 nodeT& node = it->second;
2619 if (node.has_children()) {
2620 std::vector< Future<bool> > v = future_vector_factory<bool>(1<<NDIM);
2621 int i=0;
2622 for (KeyChildIterator<NDIM> kit(key); kit; ++kit,++i) {
2623 v[i] = woT::task(coeffs.owner(kit.key()), &implT::truncate_spawn, kit.key(), tol, TaskAttributes::generator());
2624 }
2625 return woT::task(world.rank(),&implT::truncate_op, key, tol, v);
2626 }
2627 else {
2628 // In compressed form leaves should not have coeffs ... however the
2629 // transform op could leave the tree with leaves that do have coeffs
2630 // in which case we want something sensible to happen
2631 //MADNESS_ASSERT(!node.has_coeff());
2632 if (node.has_coeff() && key.level()>1) {
2633 double dnorm = node.coeff().normf();
2634 if (dnorm < truncate_tol(tol,key)) {
2635 node.clear_coeff();
2636 }
2637 }
2638 return Future<bool>(node.has_coeff());
2639 }
2640 }
2641
2642
2643 template <typename T, std::size_t NDIM>
2644 bool FunctionImpl<T,NDIM>::truncate_op(const keyT& key, double tol, const std::vector< Future<bool> >& v) {
2645 //PROFILE_MEMBER_FUNC(FunctionImpl); // Too fine grain for routine profiling
2646 // If any child has coefficients, a parent cannot truncate
2647 for (int i=0; i<(1<<NDIM); ++i) if (v[i].get()) return true;
2648 nodeT& node = coeffs.find(key).get()->second;
2649
2650 // Interior nodes should always have coeffs but transform might
2651 // leave empty interior nodes ... hence just force no coeffs to
2652 // be zero coeff unless it is a leaf.
2653 if (node.has_children() && !node.has_coeff()) node.set_coeff(coeffT(cdata.v2k,targs));
2654
2655 if (key.level() > 1) { // >1 rather >0 otherwise reconstruct might get confused
2656 double dnorm = node.coeff().normf();
2657 if (dnorm < truncate_tol(tol,key)) {
2658 node.clear_coeff();
2659 if (node.has_children()) {
2660 node.set_has_children(false);
2661 for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
2662 coeffs.erase(kit.key());
2663 }
2664 }
2665 }
2666 }
2667 return node.has_coeff();
2668 }
2669
2670
2671 template <typename T, std::size_t NDIM>
2672 void FunctionImpl<T,NDIM>::print_tree(std::ostream& os, Level maxlevel) const {
2673 if (world.rank() == 0) do_print_tree(cdata.key0, os, maxlevel);
2674 world.gop.fence();
2675 if (world.rank() == 0) os.flush();
2676 world.gop.fence();
2677 }
2678
2679
2680 template <typename T, std::size_t NDIM>
2681 void FunctionImpl<T,NDIM>::do_print_tree(const keyT& key, std::ostream& os, Level maxlevel) const {
2682 typename dcT::const_iterator it = coeffs.find(key).get();
2683 if (it == coeffs.end()) {
2684 //MADNESS_EXCEPTION("FunctionImpl: do_print_tree: null node pointer",0);
2685 for (int i=0; i<key.level(); ++i) os << " ";
2686 os << key << " missing --> " << coeffs.owner(key) << "\n";
2687 }
2688 else {
2689 const nodeT& node = it->second;
2690 for (int i=0; i<key.level(); ++i) os << " ";
2691 os << key << " " << node << " --> " << coeffs.owner(key) << "\n";
2692 if (key.level() < maxlevel && node.has_children()) {
2693 for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
2694 do_print_tree(kit.key(),os,maxlevel);
2695 }
2696 }
2697 }
2698 }
2699
2700 template <typename T, std::size_t NDIM>
2701 void FunctionImpl<T,NDIM>::print_tree_json(std::ostream& os, Level maxlevel) const {
2702 std::multimap<Level, std::tuple<tranT, std::string>> data;
2703 if (world.rank() == 0) do_print_tree_json(cdata.key0, data, maxlevel);
2704 world.gop.fence();
2705 if (world.rank() == 0) {
2706 for (Level level = 0; level != maxlevel; ++level) {
2707 if (data.count(level) == 0)
2708 break;
2709 else {
2710 if (level > 0)
2711 os << ",";
2712 os << "\"" << level << "\":{";
2713 os << "\"level\": " << level << ",";
2714 os << "\"nodes\":{";
2715 auto range = data.equal_range(level);
2716 for (auto it = range.first; it != range.second; ++it) {
2717 os << "\"" << std::get<0>(it->second) << "\":"
2718 << std::get<1>(it->second);
2719 if (std::next(it) != range.second)
2720 os << ",";
2721 }
2722 os << "}}";
2723 }
2724 }
2725 os.flush();
2726 }
2727 world.gop.fence();
2728 }
2729
2730
2731 template <typename T, std::size_t NDIM>
2732 void FunctionImpl<T,NDIM>::do_print_tree_json(const keyT& key, std::multimap<Level, std::tuple<tranT, std::string>>& data, Level maxlevel) const {
2733 typename dcT::const_iterator it = coeffs.find(key).get();
2734 if (it == coeffs.end()) {
2735 MADNESS_EXCEPTION("FunctionImpl: do_print_tree_json: null node pointer",0);
2736 }
2737 else {
2738 const nodeT& node = it->second;
2739 std::ostringstream oss;
2740 oss << "{";
2741 node.print_json(oss);
2742 oss << ",\"owner\": " << coeffs.owner(key) << "}";
2743 auto node_json_str = oss.str();
2744 data.insert(std::make_pair(key.level(), std::make_tuple(key.translation(), node_json_str)));
2745 if (key.level() < maxlevel && node.has_children()) {
2746 for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
2747 do_print_tree_json(kit.key(),data, maxlevel);
2748 }
2749 }
2750 }
2751 }
2752
2753 template <typename T, std::size_t NDIM>
2754 void FunctionImpl<T,NDIM>::print_tree_graphviz(std::ostream& os, Level maxlevel) const {
2755 // aggregate data by level, thus collect data first, then dump
2756 if (world.rank() == 0) do_print_tree_graphviz(cdata.key0, os, maxlevel);
2757 world.gop.fence();
2758 if (world.rank() == 0) os.flush();
2759 world.gop.fence();
2760 }
2761
2762 template <typename T, std::size_t NDIM>
2763 void FunctionImpl<T,NDIM>::do_print_tree_graphviz(const keyT& key, std::ostream& os, Level maxlevel) const {
2764
2765 struct uniqhash {
2766 static int64_t value(const keyT& key) {
2767 int64_t result = 0;
2768 for (int64_t j = 0; j <= key.level()-1; ++j) {
2769 result += (1 << j*NDIM);
2770 }
2771 result += key.translation()[0];
2772 return result;
2773 }
2774 };
2775
2776 typename dcT::const_iterator it = coeffs.find(key).get();
2777 if (it != coeffs.end()) {
2778 const nodeT& node = it->second;
2779 if (key.level() < maxlevel && node.has_children()) {
2780 for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
2781 os << uniqhash::value(key) << " -> " << uniqhash::value(kit.key()) << "\n";
2782 do_print_tree_graphviz(kit.key(),os,maxlevel);
2783 }
2784 }
2785 }
2786 }
2787
2788 template <typename T, std::size_t NDIM>
2790 //PROFILE_MEMBER_FUNC(FunctionImpl);
2791
2792 if (not functor) MADNESS_EXCEPTION("FunctionImpl: project: confusion about function?",0);
2793
2794 // if functor provides coeffs directly, awesome; otherwise use compute by yourself
2795 if (functor->provides_coeff()) return functor->coeff(key).full_tensor_copy();
2796
2797 MADNESS_ASSERT(cdata.npt == cdata.k); // only necessary due to use of fast transform
2798 tensorT fval(cdata.vq,false); // this will be the returned result
2799 tensorT work(cdata.vk,false); // initially evaluate the function in here
2800 tensorT workq(cdata.vq,false); // initially evaluate the function in here
2801
2802 // compute the values of the functor at the quadrature points and scale appropriately
2803 madness::fcube(key,*functor,cdata.quad_x,work);
2804 work.scale(sqrt(FunctionDefaults<NDIM>::get_cell_volume()*pow(0.5,double(NDIM*key.level()))));
2805 //return transform(work,cdata.quad_phiw);
2806 return fast_transform(work,cdata.quad_phiw,fval,workq);
2807 }
2808
2809 template <typename T, std::size_t NDIM>
2811 if (coeffs.probe(key)) {
2812 return Future<double>(coeffs.find(key).get()->second.get_norm_tree());
2813 }
2815 keyT parent = key.parent();
2816 return woT::task(coeffs.owner(parent), &implT::get_norm_tree_recursive, parent, TaskAttributes::hipri());
2817 }
2818
2819
2820 template <typename T, std::size_t NDIM>
2822 const RemoteReference< FutureImpl< std::pair<keyT,coeffT> > >& ref) const {
2823 //PROFILE_MEMBER_FUNC(FunctionImpl);
2824 if (coeffs.probe(key)) {
2825 const nodeT& node = coeffs.find(key).get()->second;
2826 Future< std::pair<keyT,coeffT> > result(ref);
2827 if (node.has_coeff()) {
2828 //madness::print("sock found it with coeff",key);
2829 result.set(std::pair<keyT,coeffT>(key,node.coeff()));
2830 }
2831 else {
2832 //madness::print("sock found it without coeff",key);
2833 result.set(std::pair<keyT,coeffT>(key,coeffT()));
2834 }
2835 }
2836 else {
2837 keyT parent = key.parent();
2838 //madness::print("sock forwarding to parent",key,parent);
2839 //PROFILE_BLOCK(sitome_send); // Too fine grain for routine profiling
2840 if (coeffs.is_local(parent))
2841 woT::send(coeffs.owner(parent), &FunctionImpl<T,NDIM>::sock_it_to_me, parent, ref);
2842 else
2843 woT::task(coeffs.owner(parent), &FunctionImpl<T,NDIM>::sock_it_to_me, parent, ref, TaskAttributes::hipri());
2844 }
2845 }
2846
2847 // like sock_it_to_me, but it replaces empty node with averaged coeffs from further down the tree
2848 template <typename T, std::size_t NDIM>
2850 const RemoteReference< FutureImpl< std::pair<keyT,coeffT> > >& ref) const {
2852 if (coeffs.probe(key)) {
2853 const nodeT& node = coeffs.find(key).get()->second;
2854 Future< std::pair<keyT,coeffT> > result(ref);
2855 if (node.has_coeff()) {
2856 result.set(std::pair<keyT,coeffT>(key,node.coeff()));
2857 }
2858 else {
2859 result.set(std::pair<keyT,coeffT>(key,nodeT(coeffT(project(key),targs),false).coeff()));
2860 }
2861 }
2862 else {
2863 keyT parent = key.parent();
2864 //PROFILE_BLOCK(sitome2_send); // Too fine grain for routine profiling
2865 woT::task(coeffs.owner(parent), &FunctionImpl<T,NDIM>::sock_it_to_me_too, parent, ref, TaskAttributes::hipri());
2866 }
2867 }
2868
2869
2870 template <typename T, std::size_t NDIM>
2872 const keyT& keyin,
2873 const typename Future<T>::remote_refT& ref) {
2874
2876 // This is ugly. We must figure out a clean way to use
2877 // owner computes rule from the container.
2878 Vector<double,NDIM> x = xin;
2879 keyT key = keyin;
2881 ProcessID me = world.rank();
2882 while (1) {
2883 ProcessID owner = coeffs.owner(key);
2884 if (owner != me) {
2885 //PROFILE_BLOCK(eval_send); // Too fine grain for routine profiling
2886 woT::task(owner, &implT::eval, x, key, ref, TaskAttributes::hipri());
2887 return;
2888 }
2889 else {
2890 typename dcT::futureT fut = coeffs.find(key);
2891 typename dcT::iterator it = fut.get();
2892 nodeT& node = it->second;
2893 if (node.has_coeff()) {
2894 Future<T>(ref).set(eval_cube(key.level(), x, node.coeff().full_tensor()));
2895 return;
2896 }
2897 else {
2898 for (std::size_t i=0; i<NDIM; ++i) {
2899 double xi = x[i]*2.0;
2900 int li = int(xi);
2901 if (li == 2) li = 1;
2902 x[i] = xi - li;
2903 l[i] = 2*l[i] + li;
2904 }
2905 key = keyT(key.level()+1,l);
2906 }
2907 }
2908 }
2909 //MADNESS_EXCEPTION("should not be here",0);
2910 }
2911
2912
2913 template <typename T, std::size_t NDIM>
2914 std::pair<bool,T>
2916 Vector<double,NDIM> x = xin;
2917 keyT key(0);
2919 const ProcessID me = world.rank();
2920 while (key.level() <= maxlevel) {
2921 if (coeffs.owner(key) == me) {
2922 typename dcT::futureT fut = coeffs.find(key);
2923 typename dcT::iterator it = fut.get();
2924 if (it != coeffs.end()) {
2925 nodeT& node = it->second;
2926 if (node.has_coeff()) {
2927 return std::pair<bool,T>(true,eval_cube(key.level(), x, node.coeff().full_tensor()));
2928 }
2929 }
2930 }
2931 for (std::size_t i=0; i<NDIM; ++i) {
2932 double xi = x[i]*2.0;
2933 int li = int(xi);
2934 if (li == 2) li = 1;
2935 x[i] = xi - li;
2936 l[i] = 2*l[i] + li;
2937 }
2938 key = keyT(key.level()+1,l);
2939 }
2940 return std::pair<bool,T>(false,0.0);
2941 }
2942
2943 template <typename T, std::size_t NDIM>
2945 const keyT& keyin,
2946 const typename Future<Level>::remote_refT& ref) {
2947
2949 // This is ugly. We must figure out a clean way to use
2950 // owner computes rule from the container.
2951 Vector<double,NDIM> x = xin;
2952 keyT key = keyin;
2954 ProcessID me = world.rank();
2955 while (1) {
2956 ProcessID owner = coeffs.owner(key);
2957 if (owner != me) {
2958 //PROFILE_BLOCK(eval_send); // Too fine grain for routine profiling
2959 woT::task(owner, &implT::evaldepthpt, x, key, ref, TaskAttributes::hipri());
2960 return;
2961 }
2962 else {
2963 typename dcT::futureT fut = coeffs.find(key);
2964 typename dcT::iterator it = fut.get();
2965 nodeT& node = it->second;
2966 if (node.has_coeff()) {
2967 Future<Level>(ref).set(key.level());
2968 return;
2969 }
2970 else {
2971 for (std::size_t i=0; i<NDIM; ++i) {
2972 double xi = x[i]*2.0;
2973 int li = int(xi);
2974 if (li == 2) li = 1;
2975 x[i] = xi - li;
2976 l[i] = 2*l[i] + li;
2977 }
2978 key = keyT(key.level()+1,l);
2979 }
2980 }
2981 }
2982 //MADNESS_EXCEPTION("should not be here",0);
2983 }
2984
2985 template <typename T, std::size_t NDIM>
2987 const keyT& keyin,
2988 const typename Future<long>::remote_refT& ref) {
2989
2991 // This is ugly. We must figure out a clean way to use
2992 // owner computes rule from the container.
2993 Vector<double,NDIM> x = xin;
2994 keyT key = keyin;
2996 ProcessID me = world.rank();
2997 while (1) {
2998 ProcessID owner = coeffs.owner(key);
2999 if (owner != me) {
3000 //PROFILE_BLOCK(eval_send); // Too fine grain for routine profiling
3001 woT::task(owner, &implT::evalR, x, key, ref, TaskAttributes::hipri());
3002 return;
3003 }
3004 else {
3005 typename dcT::futureT fut = coeffs.find(key);
3006 typename dcT::iterator it = fut.get();
3007 nodeT& node = it->second;
3008 if (node.has_coeff()) {
3009 Future<long>(ref).set(node.coeff().rank());
3010 return;
3011 }
3012 else {
3013 for (std::size_t i=0; i<NDIM; ++i) {
3014 double xi = x[i]*2.0;
3015 int li = int(xi);
3016 if (li == 2) li = 1;
3017 x[i] = xi - li;
3018 l[i] = 2*l[i] + li;
3019 }
3020 key = keyT(key.level()+1,l);
3021 }
3022 }
3023 }
3024 //MADNESS_EXCEPTION("should not be here",0);
3025 }
3026
3027
3028 template <typename T, std::size_t NDIM>
3029 void FunctionImpl<T,NDIM>::tnorm(const tensorT& t, double* lo, double* hi) {
3030 //PROFILE_MEMBER_FUNC(FunctionImpl); // Too fine grain for routine profiling
3031 auto& cdata=FunctionCommonData<T,NDIM>::get(t.dim(0));
3032 tensorT work = copy(t);
3033 tensorT tlo = work(cdata.sh);
3034 *lo = tlo.normf();
3035 tlo.fill(0.0);
3036 *hi = work.normf();
3037 }
3038
3039 template <typename T, std::size_t NDIM>
3040 void FunctionImpl<T,NDIM>::tnorm(const GenTensor<T>& t, double* lo, double* hi) {
3041 auto& cdata=FunctionCommonData<T,NDIM>::get(t.dim(0));
3042 coeffT shalf=t(cdata.sh);
3043 *lo=shalf.normf();
3044 coeffT sfull=copy(t);
3045 sfull(cdata.sh)-=shalf;
3046 *hi=sfull.normf();
3047 }
3048
3049 template <typename T, std::size_t NDIM>
3050 void FunctionImpl<T,NDIM>::tnorm(const SVDTensor<T>& t, double* lo, double* hi,
3051 const int particle) {
3052 *lo=0.0;
3053 *hi=0.0;
3054 auto& cdata=FunctionCommonData<T,NDIM>::get(t.dim(0));
3055 if (t.rank()==0) return;
3056 const tensorT vec=t.flat_vector(particle-1);
3057 for (long i=0; i<t.rank(); ++i) {
3058 double lo1,hi1;
3059 tensorT c=vec(Slice(i,i),_).reshape(cdata.vk);
3060 tnorm(c, &lo1, &hi1); // note we use g instead of h, since g is 3D
3061 *lo+=lo1*t.weights(i);
3062 *hi+=hi1*t.weights(i);
3063 }
3064 }
3065
3066
3067 namespace detail {
3068 template <typename A, typename B>
3069 struct noop {
3070 void operator()(const A& a, const B& b) const {};
3071
3072 template <typename Archive> void serialize(Archive& ar) {}
3073 };
3074
3075 template <typename T, std::size_t NDIM>
3079 // G++ 4.1.2 ICEs on BGP ... scaleinplace(T q) : q(q) {}
3080 scaleinplace(T q) {this->q = q;}
3081 void operator()(const Key<NDIM>& key, Tensor<T>& t) const {
3082 t.scale(q);
3083 }
3084 void operator()(const Key<NDIM>& key, FunctionNode<T,NDIM>& node) const {
3085 node.coeff().scale(q);
3086 }
3087 template <typename Archive> void serialize(Archive& ar) {
3088 ar & q;
3089 }
3090 };
3091
3092 template <typename T, std::size_t NDIM>
3094 void operator()(const Key<NDIM>& key, Tensor<T>& t) const {
3095 t.emul(t);
3096 }
3097 template <typename Archive> void serialize(Archive& ar) {}
3098 };
3099
3100 template <typename T, std::size_t NDIM>
3101 struct absinplace {
3102 void operator()(const Key<NDIM>& key, Tensor<T>& t) const {t=abs(t);}
3103 template <typename Archive> void serialize(Archive& ar) {}
3104 };
3105
3106 template <typename T, std::size_t NDIM>
3108 void operator()(const Key<NDIM>& key, Tensor<T>& t) const {abs(t.emul(t));}
3109 template <typename Archive> void serialize(Archive& ar) {}
3110 };
3111
3112 }
3113
3114template <typename T, std::size_t NDIM>
3115 void FunctionImpl<T,NDIM>::scale_inplace(const T q, bool fence) {
3116 // unary_op_coeff_inplace(detail::scaleinplace<T,NDIM>(q), fence);
3117 unary_op_node_inplace(detail::scaleinplace<T,NDIM>(q), fence);
3118 }
3119
3120 template <typename T, std::size_t NDIM>
3122 //unary_op_value_inplace(&implT::autorefine_square_test, detail::squareinplace<T,NDIM>(), fence);
3123 unary_op_value_inplace(detail::squareinplace<T,NDIM>(), fence);
3124 }
3125
3126 template <typename T, std::size_t NDIM>
3128 unary_op_value_inplace(detail::absinplace<T,NDIM>(), fence);
3129 }
3130
3131 template <typename T, std::size_t NDIM>
3133 unary_op_value_inplace(detail::abssquareinplace<T,NDIM>(), fence);
3134 }
3135
3136 template <typename T, std::size_t NDIM>
3138 //PROFILE_MEMBER_FUNC(FunctionImpl); // Too fine grain for routine profiling
3139 double p[200];
3140 double scale = pow(2.0,double(np-nc));
3141 for (int mu=0; mu<cdata.npt; ++mu) {
3142 double xmu = scale*(cdata.quad_x(mu)+lc) - lp;
3143 MADNESS_ASSERT(xmu>-1e-15 && xmu<(1+1e-15));
3144 legendre_scaling_functions(xmu,cdata.k,p);
3145 for (int i=0; i<k; ++i) phi(i,mu) = p[i];
3146 }
3147 phi.scale(pow(2.0,0.5*np));
3148 }
3149
3150 template <typename T, std::size_t NDIM>
3151
3152 const GenTensor<T> FunctionImpl<T,NDIM>::parent_to_child(const coeffT& s, const keyT& parent, const keyT& child) const {
3153 //PROFILE_MEMBER_FUNC(FunctionImpl); // Too fine grain for routine profiling
3154 // An invalid parent/child means that they are out of the box
3155 // and it is the responsibility of the caller to worry about that
3156 // ... most likely the coefficients (s) are zero to reflect
3157 // zero B.C. so returning s makes handling this easy.
3158 if (parent == child || parent.is_invalid() || child.is_invalid()) return s;
3159
3160 coeffT result = fcube_for_mul<T>(child, parent, s);
3161 result.scale(sqrt(FunctionDefaults<NDIM>::get_cell_volume()*pow(0.5,double(NDIM*child.level()))));
3162 result = transform(result,cdata.quad_phiw);
3163
3164 return result;
3165 }
3166
3167
3168 template <typename T, std::size_t NDIM>
3171 std::vector<long> v0(NDIM,0);
3172 T sum = 0.0;
3173 if (is_compressed()) {
3174 if (world.rank() == coeffs.owner(cdata.key0)) {
3175 typename dcT::const_iterator it = coeffs.find(cdata.key0).get();
3176 if (it != coeffs.end()) {
3177 const nodeT& node = it->second;
3178 if (node.has_coeff()) sum = node.coeff().full_tensor()(v0);
3179 }
3180 }
3181 }
3182 else {
3183 for (typename dcT::const_iterator it=coeffs.begin(); it!=coeffs.end(); ++it) {
3184 const keyT& key = it->first;
3185 const nodeT& node = it->second;
3186 if (node.has_coeff()) sum += node.coeff().full_tensor()(v0)*pow(0.5,NDIM*key.level()*0.5);
3187 }
3188 }
3190 }
3191
3192
3193 static inline bool enforce_bc(bool is_periodic, Level n, Translation& l) {
3194 const Translation two2n = 1ul << n;
3195 if (l < 0) {
3196 if (is_periodic) {
3197 do {
3198 l += two2n; // Periodic BC
3199 } while (l < 0);
3200 } else
3201 return false; // Zero BC
3202 } else if (l >= two2n) {
3203 if (is_periodic) {
3204 do {
3205 l -= two2n; // Periodic BC
3206 } while (l >= two2n);
3207 } else
3208 return false; // Zero BC
3209 }
3210 return true;
3211 }
3212
3213 static inline bool enforce_in_volume(Level n, const Translation& l) {
3214 Translation two2n = 1ul << n;
3215 return l >= 0 && l < two2n;
3216 }
3217
3218 template <typename T, std::size_t NDIM>
3219 Key<NDIM> FunctionImpl<T,NDIM>::neighbor(const keyT& key, const Key<NDIM>& disp, const array_of_bools<NDIM>& is_periodic) const {
3221
3222 for (std::size_t axis=0; axis<NDIM; ++axis) {
3223 l[axis] += disp.translation()[axis];
3224
3225 //if (!enforce_bc(bc(axis,0), bc(axis,1), key.level(), l[axis])) {
3226 if (!enforce_bc(is_periodic[axis], key.level(), l[axis])) {
3227 return keyT::invalid();
3228 }
3229 }
3230 return keyT(key.level(),l);
3231 }
3232
3233 template <typename T, std::size_t NDIM>
3236
3237 for (std::size_t axis = 0; axis < NDIM; ++axis) {
3238 l[axis] += disp.translation()[axis];
3239
3240 if (!enforce_in_volume(key.level(), l[axis])) {
3241 return keyT::invalid();
3242 }
3243 }
3244 return keyT(key.level(), l);
3245 }
3246
3247 template <typename T, std::size_t NDIM>
3250 //PROFILE_MEMBER_FUNC(FunctionImpl); // Too fine grain for routine profiling
3251 typedef std::pair< Key<NDIM>,coeffT > argT;
3252 Future<argT> result;
3253 //PROFILE_BLOCK(find_me_send); // Too fine grain for routine profiling
3254 woT::task(coeffs.owner(key), &implT::sock_it_to_me_too, key, result.remote_ref(world), TaskAttributes::hipri());
3255 return result;
3256 }
3257
3258
3259 /// will insert
3260 /// @return s coefficient and norm_tree for key
3261 template <typename T, std::size_t NDIM>
3263 bool nonstandard1, bool keepleaves, bool redundant1) {
3264 if (!coeffs.probe(key)) print("missing node",key);
3265 MADNESS_ASSERT(coeffs.probe(key));
3266
3267 // get fetches remote data (here actually local)
3268 nodeT& node = coeffs.find(key).get()->second;
3269
3270 // internal node -> continue recursion
3271 if (node.has_children()) {
3272 std::vector< Future<std::pair<coeffT,double> > > v = future_vector_factory<std::pair<coeffT,double> >(1<<NDIM);
3273 int i=0;
3274 for (KeyChildIterator<NDIM> kit(key); kit; ++kit,++i) {
3275 //PROFILE_BLOCK(compress_send); // Too fine grain for routine profiling
3276 // readily available
3277 v[i] = woT::task(coeffs.owner(kit.key()), &implT::compress_spawn, kit.key(),
3278 nonstandard1, keepleaves, redundant1, TaskAttributes::hipri());
3279 }
3280 if (redundant1) return woT::task(world.rank(),&implT::make_redundant_op, key, v);
3281 return woT::task(world.rank(),&implT::compress_op, key, v, nonstandard1);
3282 }
3283
3284 // leaf node -> remove coefficients here and pass them back to parent for filtering
3285 // insert snorm, dnorm=0.0, normtree (=snorm)
3286 else {
3287 // special case: tree has only root node: keep sum coeffs and make zero diff coeffs
3288 if (key.level()==0) {
3289 if (redundant1) {
3290 // with only the root node existing redundant and reconstructed are the same
3291 coeffT result(node.coeff());
3292 double snorm=node.coeff().normf();
3293 node.set_dnorm(0.0);
3294 node.set_snorm(snorm);
3295 node.set_norm_tree(snorm);
3296 return Future< std::pair<GenTensor<T>,double> >(std::make_pair(result,snorm));
3297 } else {
3298 // compress
3299 coeffT result(node.coeff());
3300 coeffT sdcoeff(cdata.v2k,this->get_tensor_type());
3301 sdcoeff(cdata.s0)+=node.coeff();
3302 node.coeff()=sdcoeff;
3303 double snorm=node.coeff().normf();
3304 node.set_dnorm(0.0);
3305 node.set_snorm(snorm);
3306 node.set_norm_tree(snorm);
3307 return Future< std::pair<GenTensor<T>,double> >(std::make_pair(result,node.coeff().normf()));
3308 }
3309
3310 } else { // this is a leaf node
3311 Future<coeffT > result(node.coeff());
3312 if (not keepleaves) node.clear_coeff();
3313
3314 auto snorm=(keepleaves) ? node.coeff().normf() : 0.0;
3315 node.set_norm_tree(snorm);
3316 node.set_snorm(snorm);
3317 node.set_dnorm(0.0);
3318
3319 return Future< std::pair<GenTensor<T>,double> >(std::make_pair(result,snorm));
3320 }
3321 }
3322 }
3323
3324 template <typename T, std::size_t NDIM>
3326 const keyT& key,
3327 const coordT& plotlo, const coordT& plothi, const std::vector<long>& npt,
3328 bool eval_refine) const {
3329
3330 Tensor<T>& r = *ptr;
3331
3332 coordT h; // Increment between points in each dimension
3333 for (std::size_t i=0; i<NDIM; ++i) {
3334 if (npt[i] > 1) {
3335 h[i] = (plothi[i]-plotlo[i])/(npt[i]-1);
3336 }
3337 else {
3338 MADNESS_ASSERT(plotlo[i] == plothi[i]);
3339 h[i] = 0.0;
3340 }
3341 }
3342
3343 const Level n = key.level();
3344 const Vector<Translation,NDIM>& l = key.translation();
3345 const double twon = pow(2.0,double(n));
3346 const tensorT& coeff = coeffs.find(key).get()->second.coeff().full_tensor(); // Ugh!
3347 long ind[NDIM];
3348 coordT x;
3349
3350 coordT boxlo, boxhi;
3351 Vector<int,NDIM> boxnpt;
3352 double fac = pow(0.5,double(key.level()));
3353 int npttotal = 1;
3354 for (std::size_t d=0; d<NDIM; ++d) {
3355 // Coords of box
3356 boxlo[d] = fac*key.translation()[d];
3357 boxhi[d] = boxlo[d]+fac;
3359 if (boxlo[d] > plothi[d] || boxhi[d] < plotlo[d]) {
3360 // Discard boxes out of the plot range
3361 npttotal = boxnpt[d] = 0;
3362 //print("OO range?");
3363 break;
3364 }
3365 else if (npt[d] == 1) {
3366 // This dimension is only a single point
3367 boxlo[d] = boxhi[d] = plotlo[d];
3368 boxnpt[d] = 1;
3369 }
3370 else {
3371 // Restrict to plot range
3372 boxlo[d] = std::max(boxlo[d],plotlo[d]);
3373 boxhi[d] = std::min(boxhi[d],plothi[d]);
3374
3375 // Round lo up to next plot point; round hi down
3376 double xlo = long((boxlo[d]-plotlo[d])/h[d])*h[d] + plotlo[d];
3377 if (xlo < boxlo[d]) xlo += h[d];
3378 boxlo[d] = xlo;
3379 double xhi = long((boxhi[d]-plotlo[d])/h[d])*h[d] + plotlo[d];
3380 if (xhi > boxhi[d]) xhi -= h[d];
3381 // MADNESS_ASSERT(xhi >= xlo); // nope
3382 boxhi[d] = xhi;
3383 boxnpt[d] = long(round((boxhi[d] - boxlo[d])/h[d])) + 1;
3384 }
3385 npttotal *= boxnpt[d];
3386 }
3387 //print(" box", boxlo, boxhi, boxnpt, npttotal);
3388 if (npttotal > 0) {
3389 for (IndexIterator it(boxnpt); it; ++it) {
3390 for (std::size_t d=0; d<NDIM; ++d) {
3391 double xd = boxlo[d] + it[d]*h[d]; // Sim. coords of point
3392 x[d] = twon*xd - l[d]; // Offset within box
3393 MADNESS_ASSERT(x[d]>=0.0 && x[d] <=1.0); // sanity
3394 if (npt[d] > 1) {
3395 ind[d] = long(round((xd-plotlo[d])/h[d])); // Index of plot point
3396 }
3397 else {
3398 ind[d] = 0;
3399 }
3400 MADNESS_ASSERT(ind[d]>=0 && ind[d]<npt[d]); // sanity
3401 }
3402 if (eval_refine) {
3403 r(ind) = n;
3404 }
3405 else {
3406 T tmp = eval_cube(n, x, coeff);
3407 r(ind) = tmp;
3408 //print(" eval", ind, tmp, r(ind));
3409 }
3410 }
3411 }
3412 }
3413
3414 /// Set plot_refine=true to get a plot of the refinment levels of
3415 /// the given function (defaulted to false in prototype).
3416 template <typename T, std::size_t NDIM>
3418 const coordT& plothi,
3419 const std::vector<long>& npt,
3420 const bool eval_refine) const {
3422 Tensor<T> r(NDIM, &npt[0]);
3423 //r(___) = 99.0;
3424 MADNESS_ASSERT(is_reconstructed());
3425
3426 for (typename dcT::const_iterator it=coeffs.begin(); it!=coeffs.end(); ++it) {
3427 const keyT& key = it->first;
3428 const nodeT& node = it->second;
3429 if (node.has_coeff()) {
3430 woT::task(world.rank(), &implT::plot_cube_kernel,
3431 archive::archive_ptr< Tensor<T> >(&r), key, plotlo, plothi, npt, eval_refine);
3432 }
3433 }
3434
3435 // ITERATOR(r, if (r(IND) == 99.0) {print("BAD", IND); error("bad",0);});
3436
3437 world.taskq.fence();
3438 world.gop.sum(r.ptr(), r.size());
3439 world.gop.fence();
3440
3441 return r;
3442 }
3443
3444 static inline void dxprintvalue(FILE* f, const double t) {
3445 fprintf(f,"%.6e\n",t);
3446 }
3447
3448 static inline void dxprintvalue(FILE* f, const double_complex& t) {
3449 fprintf(f,"%.6e %.6e\n", t.real(), t.imag());
3450 }
3451
3452 template <typename T, std::size_t NDIM>
3454 const char* filename,
3455 const Tensor<double>& cell,
3456 const std::vector<long>& npt,
3457 bool binary) {
3460 const char* element[6] = {"lines","quads","cubes","cubes4D","cubes5D","cubes6D"};
3461
3462 function.verify();
3463 World& world = const_cast< Function<T,NDIM>& >(function).world();
3464 FILE *f=0;
3465 if (world.rank() == 0) {
3466 f = fopen(filename, "w");
3467 if (!f) MADNESS_EXCEPTION("plotdx: failed to open the plot file", 0);
3469 fprintf(f,"object 1 class gridpositions counts ");
3470 for (std::size_t d=0; d<NDIM; ++d) fprintf(f," %ld",npt[d]);
3471 fprintf(f,"\n");
3472
3473 fprintf(f,"origin ");
3474 for (std::size_t d=0; d<NDIM; ++d) fprintf(f, " %.6e", cell(d,0));
3475 fprintf(f,"\n");
3476
3477 for (std::size_t d=0; d<NDIM; ++d) {
3478 fprintf(f,"delta ");
3479 for (std::size_t c=0; c<d; ++c) fprintf(f, " 0");
3480 double h = 0.0;
3481 if (npt[d]>1) h = (cell(d,1)-cell(d,0))/(npt[d]-1);
3482 fprintf(f," %.6e", h);
3483 for (std::size_t c=d+1; c<NDIM; ++c) fprintf(f, " 0");
3484 fprintf(f,"\n");
3486 fprintf(f,"\n");
3487
3488 fprintf(f,"object 2 class gridconnections counts ");
3489 for (std::size_t d=0; d<NDIM; ++d) fprintf(f," %ld",npt[d]);
3490 fprintf(f,"\n");
3491 fprintf(f, "attribute \"element type\" string \"%s\"\n", element[NDIM-1]);
3492 fprintf(f, "attribute \"ref\" string \"positions\"\n");
3493 fprintf(f,"\n");
3494
3495 int npoint = 1;
3496 for (std::size_t d=0; d<NDIM; ++d) npoint *= npt[d];
3497 const char* iscomplex = "";
3498 if (TensorTypeData<T>::iscomplex) iscomplex = "category complex";
3499 const char* isbinary = "";
3500 if (binary) isbinary = "binary";
3501 fprintf(f,"object 3 class array type double %s rank 0 items %d %s data follows\n",
3502 iscomplex, npoint, isbinary);
3503 }
3504
3505 world.gop.fence();
3506 Tensor<T> r = function.eval_cube(cell, npt);
3507
3508 if (world.rank() == 0) {
3509 if (binary) {
3510 // This assumes that the values are double precision
3511 fflush(f);
3512 fwrite((void *) r.ptr(), sizeof(T), r.size(), f);
3513 fflush(f);
3514 }
3515 else {
3516 for (IndexIterator it(npt); it; ++it) {
3517 //fprintf(f,"%.6e\n",r(*it));
3518 dxprintvalue(f,r(*it));
3519 }
3520 }
3521 fprintf(f,"\n");
3522
3523 fprintf(f,"object \"%s\" class field\n",filename);
3524 fprintf(f,"component \"positions\" value 1\n");
3525 fprintf(f,"component \"connections\" value 2\n");
3526 fprintf(f,"component \"data\" value 3\n");
3527 fprintf(f,"\nend\n");
3528 fclose(f);
3529 }
3530 world.gop.fence();
3531 }
3532
3533 template <std::size_t NDIM>
3535 k = 6;
3536 thresh = 1e-4;
3537 initial_level = 2;
3538 special_level = 3;
3539 max_refine_level = 30;
3540 truncate_mode = 0;
3541 refine = true;
3542 autorefine = true;
3543 debug = false;
3544 truncate_on_project = true;
3545 apply_randomize = false;
3546 project_randomize = false;
3547 if (!bc.has_value()) bc = BoundaryConditions<NDIM>(BC_FREE);
3548 tt = TT_FULL;
3549 cell = make_default_cell();
3550 recompute_cell_info();
3551 set_default_pmap(world);
3552 }
3553
3554 template <std::size_t NDIM>
3555 std::shared_ptr< WorldDCPmapInterface< Key<NDIM> > > FunctionDefaults<NDIM>::make_default_pmap(World& world) {
3556 // return std::make_shared<WorldDCDefaultPmap< Key<NDIM> >>(world);
3557 return std::make_shared<LevelPmap< Key<NDIM> >>(world);
3558 // return std::make_shared<SimplePmap< Key<NDIM> >>(world);
3559 }
3560
3561 template <std::size_t NDIM>
3563 pmap = make_default_pmap(world);
3564 pmap_nproc = world.nproc();
3565 }
3566
3567
3568 template <std::size_t NDIM>
3570 std::cout << "Function Defaults:" << std::endl;
3571 std::cout << " Dimension " << ": " << NDIM << std::endl;
3572 std::cout << " k" << ": " << k << std::endl;
3573 std::cout << " thresh" << ": " << thresh << std::endl;
3574 std::cout << " initial_level" << ": " << initial_level << std::endl;
3575 std::cout << " special_level" << ": " << special_level << std::endl;
3576 std::cout << " max_refine_level" << ": " << max_refine_level << std::endl;
3577 std::cout << " truncate_mode" << ": " << truncate_mode << std::endl;
3578 std::cout << " refine" << ": " << refine << std::endl;
3579 std::cout << " autorefine" << ": " << autorefine << std::endl;
3580 std::cout << " debug" << ": " << debug << std::endl;
3581 std::cout << " truncate_on_project" << ": " << truncate_on_project << std::endl;
3582 std::cout << " apply_randomize" << ": " << apply_randomize << std::endl;
3583 std::cout << " project_randomize" << ": " << project_randomize << std::endl;
3584 std::cout << " bc" << ": " << get_bc() << std::endl;
3585 std::cout << " tt" << ": " << tt << std::endl;
3586 std::cout << " cell" << ": " << cell << std::endl;
3587 }
3588
3589 template <typename T, std::size_t NDIM>
3590 const FunctionCommonData<T,NDIM>* FunctionCommonData<T,NDIM>::data[MAXK] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3591
3592 // default values match those in FunctionDefaults::set_defaults(world)
3593 template <std::size_t NDIM> int FunctionDefaults<NDIM>::k = 6;
3594 template <std::size_t NDIM> double FunctionDefaults<NDIM>::thresh = 1e-4;
3595 template <std::size_t NDIM> int FunctionDefaults<NDIM>::initial_level = 2;
3596 template <std::size_t NDIM> int FunctionDefaults<NDIM>::special_level = 3;
3597 template <std::size_t NDIM> int FunctionDefaults<NDIM>::max_refine_level = 30;
3598 template <std::size_t NDIM> int FunctionDefaults<NDIM>::truncate_mode = 0;
3599 template <std::size_t NDIM> bool FunctionDefaults<NDIM>::refine = true;
3600 template <std::size_t NDIM> bool FunctionDefaults<NDIM>::autorefine = true;
3601 template <std::size_t NDIM> bool FunctionDefaults<NDIM>::debug = false;
3602 template <std::size_t NDIM> bool FunctionDefaults<NDIM>::truncate_on_project = true;
3603 template <std::size_t NDIM> bool FunctionDefaults<NDIM>::apply_randomize = false;
3604 template <std::size_t NDIM> bool FunctionDefaults<NDIM>::project_randomize = false;
3605 template <std::size_t NDIM> std::optional<BoundaryConditions<NDIM>> FunctionDefaults<NDIM>::bc;
3606 template <std::size_t NDIM> TensorType FunctionDefaults<NDIM>::tt = TT_FULL;
3607 template <std::size_t NDIM> Tensor<double> FunctionDefaults<NDIM>::cell = FunctionDefaults<NDIM>::make_default_cell();
3608 template <std::size_t NDIM> Tensor<double> FunctionDefaults<NDIM>::cell_width = FunctionDefaults<NDIM>::make_default_cell_width();
3609 template <std::size_t NDIM> Tensor<double> FunctionDefaults<NDIM>::rcell_width = FunctionDefaults<NDIM>::make_default_cell_width();
3610 template <std::size_t NDIM> double FunctionDefaults<NDIM>::cell_volume = 1.;
3611 template <std::size_t NDIM> double FunctionDefaults<NDIM>::cell_min_width = 1.;
3612 template <std::size_t NDIM> std::shared_ptr< WorldDCPmapInterface< Key<NDIM> > > FunctionDefaults<NDIM>::pmap;
3613 template <std::size_t NDIM> int FunctionDefaults<NDIM>::pmap_nproc{-1};
3614
3615 template <std::size_t NDIM> std::vector< Key<NDIM> > Displacements<NDIM>::disp;
3616 template <std::size_t NDIM> array_of_bools<NDIM> Displacements<NDIM>::periodic_axes{false};
3617 template <std::size_t NDIM> std::vector< Key<NDIM> > Displacements<NDIM>::disp_periodic[64];
3618
3619}
3620
3621#endif // MADNESS_MRA_MRAIMPL_H__INCLUDED
double w(double t, double eps)
Definition DKops.h:22
double q(double t)
Definition DKops.h:18
std::complex< double > double_complex
Definition cfft.h:14
Definition test_ar.cc:118
Definition test_ar.cc:141
Definition test_tree.cc:78
long dim(int i) const
Returns the size of dimension i.
Definition basetensor.h:147
long size() const
Returns the number of elements in the tensor.
Definition basetensor.h:138
This class is used to specify boundary conditions for all operators.
Definition bc.h:72
a class to track where relevant (parent) coeffs are
Definition funcimpl.h:791
Tri-diagonal operator traversing tree primarily for derivative operator.
Definition derivative.h:73
static std::vector< Key< NDIM > > disp
standard displacements to be used with standard kernels (range-unrestricted, no lattice sum)
Definition displacements.h:53
static array_of_bools< NDIM > periodic_axes
along which axes lattice summation is performed?
Definition displacements.h:54
static std::vector< Key< NDIM > > disp_periodic[64]
displacements to be used with lattice-summed kernels
Definition displacements.h:55
ElementaryInterface (formerly FunctorInterfaceWrapper) interfaces a c-function.
Definition function_interface.h:273
FunctionCommonData holds all Function data common for given k.
Definition function_common_data.h:52
static const FunctionCommonData< T, NDIM > & get(int k)
Definition function_common_data.h:111
static void _init_quadrature(int k, int npt, Tensor< double > &quad_x, Tensor< double > &quad_w, Tensor< double > &quad_phi, Tensor< double > &quad_phiw, Tensor< double > &quad_phit)
Initialize the quadrature information.
Definition mraimpl.h:91
void _init_twoscale()
Private. Initialize the twoscale coefficients.
Definition mraimpl.h:70
FunctionDefaults holds default paramaters as static class members.
Definition funcdefaults.h:100
static Tensor< double > make_default_cell_width()
Definition funcdefaults.h:136
static std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > make_default_pmap(World &world)
Makes a default process map for the given world.
Definition mraimpl.h:3555
static bool truncate_on_project
If true initial projection inserts at n-1 not n.
Definition funcdefaults.h:114
static bool apply_randomize
If true use randomization for load balancing in apply integral operator.
Definition funcdefaults.h:115
static double cell_volume
Volume of simulation cell.
Definition funcdefaults.h:121
static int k
Wavelet order.
Definition funcdefaults.h:105
static int truncate_mode
Truncation method.
Definition funcdefaults.h:110
static void set_default_pmap(World &world)
Definition mraimpl.h:3562
static int pmap_nproc
Number of processes assumed by pmap, -1 indicates uninitialized pmap.
Definition funcdefaults.h:125
static Tensor< double > cell_width
Width of simulation cell in each dimension.
Definition funcdefaults.h:119
static double thresh
Truncation threshold.
Definition funcdefaults.h:106
static bool debug
Controls output of debug info.
Definition funcdefaults.h:113
static int special_level
Minimum level for fine scale projection of special boxes.
Definition funcdefaults.h:108
static double cell_min_width
Size of smallest dimension.
Definition funcdefaults.h:122
static std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > pmap
Default mapping of keys to processes.
Definition funcdefaults.h:124
static const Tensor< double > & get_cell_width()
Returns the width of each user cell dimension.
Definition funcdefaults.h:370
static const BoundaryConditions< NDIM > & get_bc()
Returns the default boundary conditions.
Definition funcdefaults.h:311
static Tensor< double > cell
cell[NDIM][2] Simulation cell, cell(0,0)=xlo, cell(0,1)=xhi, ...
Definition funcdefaults.h:118
static int initial_level
Initial level for fine scale projection.
Definition funcdefaults.h:107
static bool autorefine
Whether to autorefine in multiplication, etc.
Definition funcdefaults.h:112
static Tensor< double > make_default_cell()
Definition funcdefaults.h:127
static std::optional< BoundaryConditions< NDIM > > bc
Default boundary conditions, not initialized by default and must be set explicitly before use.
Definition funcdefaults.h:117
static void print()
Definition mraimpl.h:3569
static Tensor< double > rcell_width
Reciprocal of width.
Definition funcdefaults.h:120
static double get_cell_min_width()
Returns the minimum width of any user cell dimension.
Definition funcdefaults.h:380
static bool project_randomize
If true use randomization for load balancing in project/refine.
Definition funcdefaults.h:116
static const Tensor< double > & get_cell()
Gets the user cell for the simulation.
Definition funcdefaults.h:348
static void set_defaults(World &world)
Definition mraimpl.h:3534
static int max_refine_level
Level at which to stop refinement.
Definition funcdefaults.h:109
static TensorType tt
structure of the tensor in FunctionNode
Definition funcdefaults.h:123
static bool refine
Whether to refine new functions.
Definition funcdefaults.h:111
Abstract base class interface required for functors used as input to Functions.
Definition function_interface.h:68
Definition funcimpl.h:5536
FunctionImpl holds all Function state to facilitate shallow copy semantics.
Definition funcimpl.h:945
bool is_nonstandard() const
Definition mraimpl.h:273
T eval_cube(Level n, coordT &x, const tensorT &c) const
Definition mraimpl.h:2025
void do_print_tree_graphviz(const keyT &key, std::ostream &os, Level maxlevel) const
Functor for the do_print_tree method (using GraphViz)
Definition mraimpl.h:2763
void change_tensor_type1(const TensorArgs &targs, bool fence)
change the tensor type of the coefficients in the FunctionNode
Definition mraimpl.h:1099
void evaldepthpt(const Vector< double, NDIM > &xin, const keyT &keyin, const typename Future< Level >::remote_refT &ref)
Get the depth of the tree at a point in simulation coordinates.
Definition mraimpl.h:2944
void scale_inplace(const T q, bool fence)
In-place scale by a constant.
Definition mraimpl.h:3115
void gaxpy_oop_reconstructed(const double alpha, const implT &f, const double beta, const implT &g, const bool fence)
perform: this= alpha*f + beta*g, invoked by result
Definition mraimpl.h:223
bool is_redundant() const
Returns true if the function is redundant.
Definition mraimpl.h:262
FunctionNode< Q, NDIM > nodeT
Type of node.
Definition funcimpl.h:955
std::size_t nCoeff_local() const
Returns the number of coefficients in the function for this MPI rank.
Definition mraimpl.h:1922
void print_size(const std::string name) const
print tree size and size
Definition mraimpl.h:1941
void print_info() const
Prints summary of data distribution.
Definition mraimpl.h:833
void abs_inplace(bool fence)
Definition mraimpl.h:3127
void print_timer() const
Definition mraimpl.h:357
void evalR(const Vector< double, NDIM > &xin, const keyT &keyin, const typename Future< long >::remote_refT &ref)
Get the rank of leaf box of the tree at a point in simulation coordinates.
Definition mraimpl.h:2986
const FunctionCommonData< T, NDIM > & cdata
Definition funcimpl.h:983
void do_print_grid(const std::string filename, const std::vector< keyT > &keys) const
print the grid in xyz format
Definition mraimpl.h:584
std::size_t nCoeff() const
Returns the number of coefficients in the function ... collective global sum.
Definition mraimpl.h:1932
keyT neighbor_in_volume(const keyT &key, const keyT &disp) const
Returns key of general neighbor that resides in-volume.
Definition mraimpl.h:3234
void compress(const TreeState newstate, bool fence)
compress the wave function
Definition mraimpl.h:1500
std::pair< coeffT, double > compress_op(const keyT &key, const std::vector< Future< std::pair< coeffT, double > > > &v, bool nonstandard)
calculate the wavelet coefficients using the sum coefficients of all child nodes
Definition mraimpl.h:1668
Future< bool > truncate_spawn(const keyT &key, double tol)
Returns true if after truncation this node has coefficients.
Definition mraimpl.h:2608
Future< double > norm_tree_spawn(const keyT &key)
Definition mraimpl.h:1570
std::vector< keyT > local_leaf_keys() const
return the keys of the local leaf boxes
Definition mraimpl.h:558
void do_print_tree(const keyT &key, std::ostream &os, Level maxlevel) const
Functor for the do_print_tree method.
Definition mraimpl.h:2681
void unset_functor()
Definition mraimpl.h:312
void do_print_plane(const std::string filename, std::vector< Tensor< double > > plotinfo, const int xaxis, const int yaxis, const coordT el2)
print the MRA structure
Definition mraimpl.h:499
std::pair< Key< NDIM >, ShallowNode< T, NDIM > > find_datum(keyT key) const
return the a std::pair<key, node>, which MUST exist
Definition mraimpl.h:965
void set_functor(const std::shared_ptr< FunctionFunctorInterface< T, NDIM > > functor1)
Definition mraimpl.h:293
bool verify_tree_state_local() const
check that the tree state and the coeffs are consistent
Definition mraimpl.h:169
const std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > & get_pmap() const
Definition mraimpl.h:207
void sock_it_to_me(const keyT &key, const RemoteReference< FutureImpl< std::pair< keyT, coeffT > > > &ref) const
Walk up the tree returning pair(key,node) for first node with coefficients.
Definition mraimpl.h:2821
double get_thresh() const
Definition mraimpl.h:328
void trickle_down(bool fence)
sum all the contributions from all scales after applying an operator in mod-NS form
Definition mraimpl.h:1354
std::pair< coeffT, double > make_redundant_op(const keyT &key, const std::vector< Future< std::pair< coeffT, double > > > &v)
similar to compress_op, but insert only the sum coefficients in the tree
Definition mraimpl.h:1728
void set_autorefine(bool value)
Definition mraimpl.h:337
tensorT filter(const tensorT &s) const
Transform sum coefficients at level n to sums+differences at level n-1.
Definition mraimpl.h:1152
void chop_at_level(const int n, const bool fence=true)
remove all nodes with level higher than n
Definition mraimpl.h:1115
void print_tree_json(std::ostream &os=std::cout, Level maxlevel=10000) const
Definition mraimpl.h:2701
coeffT parent_to_child_NS(const keyT &child, const keyT &parent, const coeffT &coeff) const
Directly project parent NS coeffs to child NS coeffs.
Definition mraimpl.h:707
void mapdim(const implT &f, const std::vector< long > &map, bool fence)
Permute the dimensions of f according to map, result on this.
Definition mraimpl.h:1057
bool is_compressed() const
Returns true if the function is compressed.
Definition mraimpl.h:250
void mirror(const implT &f, const std::vector< long > &mirror, bool fence)
mirror the dimensions of f according to map, result on this
Definition mraimpl.h:1066
void print_stats() const
print the number of configurations per node
Definition mraimpl.h:1969
void broaden(const array_of_bools< NDIM > &is_periodic, bool fence)
Definition mraimpl.h:1303
coeffT truncate_reconstructed_op(const keyT &key, const std::vector< Future< coeffT > > &v, const double tol)
given the sum coefficients of all children, truncate or not
Definition mraimpl.h:1617
void fcube(const keyT &key, const FunctionFunctorInterface< T, NDIM > &f, const Tensor< double > &qx, tensorT &fval) const
Evaluate function at quadrature points in the specified box.
Definition mraimpl.h:2446
void forward_do_diff1(const DerivativeBase< T, NDIM > *D, const implT *f, const keyT &key, const std::pair< keyT, coeffT > &left, const std::pair< keyT, coeffT > &center, const std::pair< keyT, coeffT > &right)
Definition mraimpl.h:923
std::vector< Slice > child_patch(const keyT &child) const
Returns patch referring to coeffs of child in parent box.
Definition mraimpl.h:696
void print_tree_graphviz(std::ostream &os=std::cout, Level maxlevel=10000) const
Definition mraimpl.h:2754
std::size_t min_nodes() const
Returns the min number of nodes on a processor.
Definition mraimpl.h:1873
void make_redundant(const bool fence)
convert this to redundant, i.e. have sum coefficients on all levels
Definition mraimpl.h:1528
std::size_t max_nodes() const
Returns the max number of nodes on a processor.
Definition mraimpl.h:1864
coeffT upsample(const keyT &key, const coeffT &coeff) const
upsample the sum coefficients of level 1 to sum coeffs on level n+1
Definition mraimpl.h:1231
void flo_unary_op_node_inplace(const opT &op, bool fence)
Definition funcimpl.h:2229
std::size_t size_local() const
Returns the number of coefficients in the function for each rank.
Definition mraimpl.h:1891
void plot_cube_kernel(archive::archive_ptr< Tensor< T > > ptr, const keyT &key, const coordT &plotlo, const coordT &plothi, const std::vector< long > &npt, bool eval_refine) const
Definition mraimpl.h:3325
T trace_local() const
Returns int(f(x),x) in local volume.
Definition mraimpl.h:3169
void print_grid(const std::string filename) const
Definition mraimpl.h:542
Future< std::pair< coeffT, double > > compress_spawn(const keyT &key, bool nonstandard, bool keepleaves, bool redundant1)
Invoked on node where key is local.
Definition mraimpl.h:3262
bool get_autorefine() const
Definition mraimpl.h:334
void phi_for_mul(Level np, Translation lp, Level nc, Translation lc, Tensor< double > &phi) const
Compute the Legendre scaling functions for multiplication.
Definition mraimpl.h:3137
Future< std::pair< keyT, coeffT > > find_me(const keyT &key) const
find_me. Called by diff_bdry to get coefficients of boundary function
Definition mraimpl.h:3249
TensorType get_tensor_type() const
Definition mraimpl.h:319
void remove_leaf_coefficients(const bool fence)
Definition mraimpl.h:1522
void insert_zero_down_to_initial_level(const keyT &key)
Initialize nodes to zero function at initial_level of refinement.
Definition mraimpl.h:2577
void do_diff1(const DerivativeBase< T, NDIM > *D, const implT *f, const keyT &key, const std::pair< keyT, coeffT > &left, const std::pair< keyT, coeffT > &center, const std::pair< keyT, coeffT > &right)
Definition mraimpl.h:934
void do_print_tree_json(const keyT &key, std::multimap< Level, std::tuple< tranT, std::string > > &data, Level maxlevel) const
Functor for the do_print_tree_json method.
Definition mraimpl.h:2732
void finalize_sum()
after summing up we need to do some cleanup;
Definition mraimpl.h:1821
dcT coeffs
The coefficients.
Definition funcimpl.h:988
bool exists_and_is_leaf(const keyT &key) const
Definition mraimpl.h:1275
void verify_tree() const
Verify tree is properly constructed ... global synchronization involved.
Definition mraimpl.h:111
void set_tensor_args(const TensorArgs &t)
Definition mraimpl.h:325
Range< typename dcT::const_iterator > rangeT
Definition funcimpl.h:5665
std::size_t real_size() const
Returns the number of coefficients in the function ... collective global sum.
Definition mraimpl.h:1909
bool exists_and_has_children(const keyT &key) const
Definition mraimpl.h:1270
void sum_down_spawn(const keyT &key, const coeffT &s)
is this the same as trickle_down() ?
Definition mraimpl.h:876
keyT neighbor(const keyT &key, const keyT &disp, const array_of_bools< NDIM > &is_periodic) const
Returns key of general neighbor enforcing BC.
Definition mraimpl.h:3219
void norm_tree(bool fence)
compute for each FunctionNode the norm of the function inside that node
Definition mraimpl.h:1547
bool has_leaves() const
Definition mraimpl.h:288
bool verify_parents_and_children() const
check that parents and children are consistent
Definition mraimpl.h:119
void reconstruct_op(const keyT &key, const coeffT &s, const bool accumulate_NS=true)
Definition mraimpl.h:2079
const coeffT parent_to_child(const coeffT &s, const keyT &parent, const keyT &child) const
Directly project parent coeffs to child coeffs.
Definition mraimpl.h:3152
void undo_redundant(const bool fence)
convert this from redundant to standard reconstructed form
Definition mraimpl.h:1538
GenTensor< Q > coeffT
Type of tensor used to hold coeffs.
Definition funcimpl.h:956
const keyT & key0() const
Returns cdata.key0.
Definition mraimpl.h:394
double finalize_apply()
after apply we need to do some cleanup;
Definition mraimpl.h:1778
const dcT & get_coeffs() const
Definition mraimpl.h:343
double norm2sq_local() const
Returns the square of the local norm ... no comms.
Definition mraimpl.h:1830
const FunctionCommonData< T, NDIM > & get_cdata() const
Definition mraimpl.h:349
void sum_down(bool fence)
After 1d push operator must sum coeffs down the tree to restore correct scaling function coefficients...
Definition mraimpl.h:915
bool noautorefine(const keyT &key, const tensorT &t) const
Always returns false (for when autorefine is not wanted)
Definition mraimpl.h:859
double truncate_tol(double tol, const keyT &key) const
Returns the truncation threshold according to truncate_method.
Definition mraimpl.h:649
bool autorefine_square_test(const keyT &key, const nodeT &t) const
Returns true if this block of coeffs needs autorefining.
Definition mraimpl.h:865
void erase(const Level &max_level)
truncate tree at a certain level
Definition mraimpl.h:739
void reconstruct(bool fence)
reconstruct this tree – respects fence
Definition mraimpl.h:1468
void multiply(const implT *f, const FunctionImpl< T, LDIM > *g, const int particle)
multiply f (a pair function of NDIM) with an orbital g (LDIM=NDIM/2)
Definition funcimpl.h:3659
coeffT assemble_coefficients(const keyT &key, const coeffT &coeff_ket, const coeffT &vpotential1, const coeffT &vpotential2, const tensorT &veri) const
given several coefficient tensors, assemble a result tensor
Definition mraimpl.h:1013
static void tnorm(const tensorT &t, double *lo, double *hi)
Computes norm of low/high-order polyn. coeffs for autorefinement test.
Definition mraimpl.h:3029
std::pair< bool, T > eval_local_only(const Vector< double, NDIM > &xin, Level maxlevel)
Evaluate function only if point is local returning (true,value); otherwise return (false,...
Definition mraimpl.h:2915
std::size_t max_depth() const
Returns the maximum depth of the tree ... collective ... global sum/broadcast.
Definition mraimpl.h:1856
std::size_t size() const
Returns the number of coefficients in the function ... collective global sum.
Definition mraimpl.h:1901
void reduce_rank(const double thresh, bool fence)
reduce the rank of the coefficients tensors
Definition mraimpl.h:1107
std::shared_ptr< FunctionFunctorInterface< T, NDIM > > get_functor()
Definition mraimpl.h:300
tensorT unfilter(const tensorT &s) const
Transform sums+differences at level n to sum coefficients at level n+1.
Definition mraimpl.h:1181
Tensor< T > eval_plot_cube(const coordT &plotlo, const coordT &plothi, const std::vector< long > &npt, const bool eval_refine=false) const
Definition mraimpl.h:3417
void change_tree_state(const TreeState finalstate, bool fence=true)
change the tree state of this function, might or might not respect fence!
Definition mraimpl.h:1407
Future< coeffT > truncate_reconstructed_spawn(const keyT &key, const double tol)
truncate using a tree in reconstructed form
Definition mraimpl.h:1593
void map_and_mirror(const implT &f, const std::vector< long > &map, const std::vector< long > &mirror, bool fence)
map and mirror the translation index and the coefficients, result on this
Definition mraimpl.h:1076
void truncate(double tol, bool fence)
Truncate according to the threshold with optional global fence.
Definition mraimpl.h:378
bool is_reconstructed() const
Returns true if the function is compressed.
Definition mraimpl.h:256
double norm_tree_op(const keyT &key, const std::vector< Future< double > > &v)
Definition mraimpl.h:1555
void reset_timer()
Definition mraimpl.h:366
void refine_to_common_level(const std::vector< FunctionImpl< T, NDIM > * > &v, const std::vector< tensorT > &c, const keyT key)
Refine multiple functions down to the same finest level.
Definition mraimpl.h:769
int get_k() const
Definition mraimpl.h:340
void eval(const Vector< double, NDIM > &xin, const keyT &keyin, const typename Future< T >::remote_refT &ref)
Evaluate the function at a point in simulation coordinates.
Definition mraimpl.h:2871
bool truncate_op(const keyT &key, double tol, const std::vector< Future< bool > > &v)
Definition mraimpl.h:2644
void zero_norm_tree()
Definition mraimpl.h:1292
std::size_t max_local_depth() const
Returns the maximum local depth of the tree ... no communications.
Definition mraimpl.h:1842
tensorT project(const keyT &key) const
Definition mraimpl.h:2789
double check_symmetry_local() const
Returns some asymmetry measure ... no comms.
Definition mraimpl.h:755
Future< double > get_norm_tree_recursive(const keyT &key) const
Definition mraimpl.h:2810
bool is_redundant_after_merge() const
Returns true if the function is redundant_after_merge.
Definition mraimpl.h:268
Key< NDIM > keyT
Type of key.
Definition funcimpl.h:954
bool is_on_demand() const
Definition mraimpl.h:283
void accumulate_timer(const double time) const
Definition mraimpl.h:352
void trickle_down_op(const keyT &key, const coeffT &s)
sum all the contributions from all scales after applying an operator in mod-NS form
Definition mraimpl.h:1365
void set_thresh(double value)
Definition mraimpl.h:331
Tensor< double > print_plane_local(const int xaxis, const int yaxis, const coordT &el2)
collect the data for a plot of the MRA structure locally on each node
Definition mraimpl.h:423
void sock_it_to_me_too(const keyT &key, const RemoteReference< FutureImpl< std::pair< keyT, coeffT > > > &ref) const
Definition mraimpl.h:2849
void broaden_op(const keyT &key, const std::vector< Future< bool > > &v)
Definition mraimpl.h:1281
void print_plane(const std::string filename, const int xaxis, const int yaxis, const coordT &el2)
Print a plane ("xy", "xz", or "yz") containing the point x to file.
Definition mraimpl.h:403
void print_tree(std::ostream &os=std::cout, Level maxlevel=10000) const
Definition mraimpl.h:2672
void project_refine_op(const keyT &key, bool do_refine, const std::vector< Vector< double, NDIM > > &specialpts)
Definition mraimpl.h:2458
std::size_t tree_size() const
Returns the size of the tree structure of the function ... collective global sum.
Definition mraimpl.h:1882
void add_scalar_inplace(T t, bool fence)
Adds a constant to the function. Local operation, optional fence.
Definition mraimpl.h:2536
tensorT downsample(const keyT &key, const std::vector< Future< coeffT > > &v) const
downsample the sum coefficients of level n+1 to sum coeffs on level n
Definition mraimpl.h:1201
void abs_square_inplace(bool fence)
Definition mraimpl.h:3132
void put_in_box(ProcessID from, long nl, long ni) const
Definition mraimpl.h:824
TensorArgs get_tensor_args() const
Definition mraimpl.h:322
void average(const implT &rhs)
take the average of two functions, similar to: this=0.5*(this+rhs)
Definition mraimpl.h:1088
void diff(const DerivativeBase< T, NDIM > *D, const implT *f, bool fence)
Definition mraimpl.h:946
void square_inplace(bool fence)
Pointwise squaring of function with optional global fence.
Definition mraimpl.h:3121
void remove_internal_coefficients(const bool fence)
Definition mraimpl.h:1517
void compute_snorm_and_dnorm(bool fence=true)
compute norm of s and d coefficients for all nodes
Definition mraimpl.h:1131
void standard(bool fence)
Changes non-standard compressed form to standard compressed form.
Definition mraimpl.h:1765
bool is_nonstandard_with_leaves() const
Definition mraimpl.h:278
FunctionNode holds the coefficients, etc., at each node of the 2^NDIM-tree.
Definition funcimpl.h:127
bool has_coeff() const
Returns true if there are coefficients in this node.
Definition funcimpl.h:200
void clear_coeff()
Clears the coefficients (has_coeff() will subsequently return false)
Definition funcimpl.h:295
bool is_leaf() const
Returns true if this does not have children.
Definition funcimpl.h:213
void set_has_children(bool flag)
Sets has_children attribute to value of flag.
Definition funcimpl.h:254
double get_norm_tree() const
Gets the value of norm_tree.
Definition funcimpl.h:311
void set_snorm(const double sn)
set the precomputed norm of the (virtual) s coefficients
Definition funcimpl.h:321
void print_json(std::ostream &s) const
Definition funcimpl.h:466
bool has_children() const
Returns true if this node has children.
Definition funcimpl.h:207
void set_coeff(const coeffT &coeffs)
Takes a shallow copy of the coeff — same as this->coeff()=coeff.
Definition funcimpl.h:285
void set_dnorm(const double dn)
set the precomputed norm of the (virtual) d coefficients
Definition funcimpl.h:326
coeffT & coeff()
Returns a non-const reference to the tensor containing the coeffs.
Definition funcimpl.h:227
void set_norm_tree(double norm_tree)
Sets the value of norm_tree.
Definition funcimpl.h:306
A multiresolution adaptive numerical function.
Definition mra.h:139
Implements the functionality of futures.
Definition future.h:74
A future is a possibly yet unevaluated value.
Definition future.h:369
T & get(bool dowork=true) &
Gets the value, waiting if necessary.
Definition future.h:570
remote_refT remote_ref(World &world) const
Returns a structure used to pass references to another process.
Definition future.h:671
void set(const Future< T > &other)
A.set(B), where A and B are futures ensures A has/will have the same value as B.
Definition future.h:504
RemoteReference< FutureImpl< T > > remote_refT
Definition future.h:394
Definition lowranktensor.h:59
GenTensor convert(const TensorArgs &targs) const
Definition gentensor.h:198
long dim(const int i) const
return the number of entries in dimension i
Definition lowranktensor.h:391
Tensor< T > full_tensor_copy() const
Definition gentensor.h:206
long ndim() const
Definition lowranktensor.h:386
constexpr bool is_full_tensor() const
Definition gentensor.h:224
size_t real_size() const
Definition gentensor.h:214
GenTensor< T > & emul(const GenTensor< T > &other)
Inplace multiply by corresponding elements of argument Tensor.
Definition lowranktensor.h:631
float_scalar_type normf() const
Definition lowranktensor.h:406
void reduce_rank(const double &eps)
Definition gentensor.h:217
long rank() const
Definition gentensor.h:212
const Tensor< T > & full_tensor() const
Definition gentensor.h:200
TensorType tensor_type() const
Definition gentensor.h:221
bool has_data() const
Definition gentensor.h:210
const long * dims() const
return the number of entries in dimension i
Definition lowranktensor.h:397
GenTensor & gaxpy(const T alpha, const GenTensor &other, const T beta)
Definition lowranktensor.h:580
IsSupported< TensorTypeData< Q >, GenTensor< T > & >::type scale(Q fac)
Inplace multiplication by scalar of supported type (legacy name)
Definition lowranktensor.h:426
constexpr bool is_svd_tensor() const
Definition gentensor.h:222
Definition indexit.h:141
Definition indexit.h:55
Iterates in lexical order thru all children of a key.
Definition key.h:467
Key is the index for a node of the 2^NDIM-tree.
Definition key.h:69
Level level() const
Definition key.h:168
bool is_neighbor_of(const Key &key, const array_of_bools< NDIM > &bperiodic) const
Assuming keys are at the same level, returns true if displaced by no more than 1 in any direction.
Definition key.h:287
bool is_valid() const
Checks if a key is valid.
Definition key.h:123
bool thisKeyContains(const Vector< double, NDIM > &x, const unsigned int &dim0, const unsigned int &dim1) const
check if this MultiIndex contains point x, disregarding these two dimensions
Definition key.h:319
bool is_invalid() const
Checks if a key is invalid.
Definition key.h:118
Key parent(int generation=1) const
Returns the key of the parent.
Definition key.h:252
const Vector< Translation, NDIM > & translation() const
Definition key.h:173
Range, vaguely a la Intel TBB, to encapsulate a random-access, STL-like start and end iterator with c...
Definition range.h:64
Simple structure used to manage references/pointers to remote instances.
Definition worldref.h:395
double weights(const unsigned int &i) const
return the weight
Definition srconf.h:671
const Tensor< T > flat_vector(const unsigned int &idim) const
return shallow copy of a slice of one of the vectors, flattened to (r,kVec)
Definition srconf.h:545
Definition SVDTensor.h:42
long rank() const
Definition SVDTensor.h:77
A slice defines a sub-range or patch of a dimension.
Definition slice.h:103
static TaskAttributes hipri()
Definition thread.h:456
static TaskAttributes generator()
Definition thread.h:448
Traits class to specify support of numeric types.
Definition type_data.h:56
A tensor is a multidimensional array.
Definition tensor.h:317
float_scalar_type normf() const
Returns the Frobenius norm of the tensor.
Definition tensor.h:1726
Tensor< T > & fill(T x)
Inplace fill with a scalar (legacy name)
Definition tensor.h:562
T sum() const
Returns the sum of all elements of the tensor.
Definition tensor.h:1662
Tensor< T > reshape(int ndimnew, const long *d)
Returns new view/tensor reshaping size/number of dimensions to conforming tensor.
Definition tensor.h:1384
T * ptr()
Returns a pointer to the internal data.
Definition tensor.h:1825
IsSupported< TensorTypeData< Q >, Tensor< T > & >::type scale(Q x)
Inplace multiplication by scalar of supported type (legacy name)
Definition tensor.h:686
Tensor< T > & emul(const Tensor< T > &t)
Inplace multiply by corresponding elements of argument Tensor.
Definition tensor.h:1799
bool has_data() const
Definition tensor.h:1887
iterator begin()
Returns an iterator to the beginning of the local data (no communication)
Definition worlddc.h:1357
implT::const_iterator const_iterator
Definition worlddc.h:1135
iterator end()
Returns an iterator past the end of the local data (no communication)
Definition worlddc.h:1371
Future< iterator > futureT
Definition worlddc.h:1138
implT::iterator iterator
Definition worlddc.h:1134
implT::accessor accessor
Definition worlddc.h:1136
void fence(bool debug=false)
Synchronizes all processes in communicator AND globally ensures no pending AM or tasks.
Definition worldgop.cc:161
A parallel world class.
Definition world.h:132
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition world.h:320
WorldGopInterface & gop
Global operations.
Definition world.h:207
ProcessID nproc() const
Returns the number of processes in this World (same as MPI_Comm_size()).
Definition world.h:325
Wrapper for an opaque pointer for serialization purposes.
Definition archive.h:851
syntactic sugar for std::array<bool, N>
Definition array_of_bools.h:19
char * p(char *buf, const char *name, int k, int initial_level, double thresh, int order)
Definition derivatives.cc:72
const std::size_t bufsize
Definition derivatives.cc:16
static double lo
Definition dirac-hatom.cc:23
static bool debug
Definition dirac-hatom.cc:16
Provides FunctionCommonData, FunctionImpl and FunctionFactory.
static double function(const coord_3d &r)
Normalized gaussian.
Definition functionio.cc:100
auto T(World &world, response_space &f) -> response_space
Definition global_functions.cc:28
Tensor< TENSOR_RESULT_TYPE(T, Q) > & fast_transform(const Tensor< T > &t, const Tensor< Q > &c, Tensor< TENSOR_RESULT_TYPE(T, Q) > &result, Tensor< TENSOR_RESULT_TYPE(T, Q) > &workspace)
Restricted but heavily optimized form of transform()
Definition tensor.h:2444
const double beta
Definition gygi_soltion.cc:62
static const double v
Definition hatom_sf_dirac.cc:20
static double u(double r, double c)
Definition he.cc:20
Tensor< double > op(const Tensor< double > &x)
Definition kain.cc:508
static double pow(const double *a, const double *b)
Definition lda.h:74
Macros and tools pertaining to the configuration of MADNESS.
#define MADNESS_PRAGMA_CLANG(x)
Definition madness_config.h:200
#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
static const bool VERIFY_TREE
Definition mra.h:57
Definition potentialmanager.cc:41
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:10
bool two_scale_hg(int k, Tensor< double > *hg)
Definition twoscale.cc:151
@ BC_FREE
Definition bc.h:53
void make_redundant(World &world, const std::vector< Function< T, NDIM > > &v, bool fence=true)
change tree_state of a vector of functions to redundant
Definition vmra.h:186
static const char * filename
Definition legendre.cc:96
static const std::vector< Slice > ___
Entire dimension.
Definition slice.h:128
static bool enforce_in_volume(Level n, const Translation &l)
Definition mraimpl.h:3213
double abs(double x)
Definition complexfun.h:48
static double cpu_time()
Returns the cpu time in seconds relative to an arbitrary origin.
Definition timers.h:127
Vector< double, 3 > coordT
Definition corepotential.cc:54
GenTensor< TENSOR_RESULT_TYPE(R, Q)> general_transform(const GenTensor< R > &t, const Tensor< Q > c[])
Definition gentensor.h:274
response_space scale(response_space a, double b)
void legendre_scaling_functions(double x, long k, double *p)
Evaluate the first k Legendre scaling functions.
Definition legendre.cc:85
void norm_tree(World &world, const std::vector< Function< T, NDIM > > &v, bool fence=true)
Makes the norm tree for all functions in a vector.
Definition vmra.h:1181
std::vector< Function< TENSOR_RESULT_TYPE(T, R), NDIM > > transform(World &world, const std::vector< Function< T, NDIM > > &v, const Tensor< R > &c, bool fence=true)
Transforms a vector of functions according to new[i] = sum[j] old[j]*c[j,i].
Definition vmra.h:707
static Key< NDIM > simpt2key(const Vector< T, NDIM > &pt, Level n)
Definition funcdefaults.h:453
TreeState
Definition funcdefaults.h:59
@ nonstandard_after_apply
s and d coeffs, state after operator application
Definition funcdefaults.h:64
@ on_demand
no coeffs anywhere, but a functor providing if necessary
Definition funcdefaults.h:67
@ redundant_after_merge
s coeffs everywhere, must be summed up to yield the result
Definition funcdefaults.h:66
@ reconstructed
s coeffs at the leaves only
Definition funcdefaults.h:60
@ nonstandard
s and d coeffs in internal nodes
Definition funcdefaults.h:62
@ unknown
Definition funcdefaults.h:68
@ compressed
d coeffs in internal nodes, s and d coeffs at the root
Definition funcdefaults.h:61
@ redundant
s coeffs everywhere
Definition funcdefaults.h:65
@ nonstandard_with_leaves
like nonstandard, with s coeffs at the leaves
Definition funcdefaults.h:63
static void user_to_sim(const Vector< double, NDIM > &xuser, Vector< double, NDIM > &xsim)
Convert user coords (cell[][]) to simulation coords ([0,1]^ndim)
Definition funcdefaults.h:444
void standard(World &world, std::vector< Function< T, NDIM > > &v, bool fence=true)
Generates standard form of a vector of functions.
Definition vmra.h:243
Tensor< double > tensorT
Definition distpm.cc:21
void compress(World &world, const std::vector< Function< T, NDIM > > &v, bool fence=true)
Compress a vector of functions.
Definition vmra.h:149
const std::vector< Function< T, NDIM > > & reconstruct(const std::vector< Function< T, NDIM > > &v)
reconstruct a vector of functions
Definition vmra.h:162
response_space transpose(response_space &f)
Definition basic_operators.cc:10
int64_t Translation
Definition key.h:57
void plotdx(const Function< T, NDIM > &f, const char *filename, const Tensor< double > &cell=FunctionDefaults< NDIM >::get_cell(), const std::vector< long > &npt=std::vector< long >(NDIM, 201L), bool binary=true)
Writes an OpenDX format file with a cube/slice of points on a uniform grid.
Definition mraimpl.h:3453
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:2383
static void verify_tree(World &world, const std::vector< Function< T, NDIM > > &v)
Definition SCF.cc:74
static const Slice _(0,-1, 1)
void change_tensor_type(GenTensor< T > &t, const TensorArgs &targs)
change representation to targ.tt
Definition gentensor.h:284
int Level
Definition key.h:58
std::enable_if< std::is_base_of< ProjectorBase, projT >::value, OuterProjector< projT, projQ > >::type outer(const projT &p0, const projQ &p1)
Definition projector.h:457
TreeState get_tree_state(const Function< T, NDIM > &f)
get tree state of a function
Definition mra.h:2841
bool gauss_legendre(int n, double xlo, double xhi, double *x, double *w)
Definition legendre.cc:226
static double pop(std::vector< double > &v)
Definition SCF.cc:115
void print(const T &t, const Ts &... ts)
Print items to std::cout (items separated by spaces) and terminate with a new line.
Definition print.h:226
Tensor< T > fcube(const Key< NDIM > &, T(*f)(const Vector< double, NDIM > &), const Tensor< double > &)
Definition mraimpl.h:2133
TensorType
low rank representations of tensors (see gentensor.h)
Definition gentensor.h:120
@ TT_2D
Definition gentensor.h:120
@ TT_FULL
Definition gentensor.h:120
static void dxprintvalue(FILE *f, const double t)
Definition mraimpl.h:3444
void refine(World &world, const std::vector< Function< T, NDIM > > &vf, bool fence=true)
refine the functions according to the autorefine criteria
Definition vmra.h:196
NDIM & f
Definition mra.h:2528
void error(const char *msg)
Definition world.cc:142
const Function< T, NDIM > & change_tree_state(const Function< T, NDIM > &f, const TreeState finalstate, bool fence=true)
change tree state of a function
Definition mra.h:2854
NDIM const Function< R, NDIM > & g
Definition mra.h:2528
double wall_time()
Returns the wall time in seconds relative to an arbitrary origin.
Definition timers.cc:48
static bool print_timings
Definition SCF.cc:106
constexpr Vector< T, sizeof...(Ts)+1 > vec(T t, Ts... ts)
Factory function for creating a madness::Vector.
Definition vector.h:750
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:2484
static std::vector< double > ttt
Definition SCF.cc:107
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:2511
std::string name(const FuncType &type, const int ex=-1)
Definition ccpairfunction.h:28
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:2096
static const int MAXK
The maximum wavelet order presently supported.
Definition funcdefaults.h:54
static bool enforce_bc(bool is_periodic, Level n, Translation &l)
Definition mraimpl.h:3193
Definition mraimpl.h:51
bool isnan(const std::complex< T > &v)
Definition mraimpl.h:53
const double mu
Definition navstokes_cosines.cc:95
static const double b
Definition nonlinschro.cc:119
static const double d
Definition nonlinschro.cc:121
static const double a
Definition nonlinschro.cc:118
static const double c
Definition relops.cc:10
static const double m
Definition relops.cc:9
static const double L
Definition rk.cc:46
static const double thresh
Definition rk.cc:45
static const long k
Definition rk.cc:44
const double xi
Exponent for delta function approx.
Definition siam_example.cc:60
Definition test_ar.cc:204
Definition test_ccpairfunction.cc:22
add two functions f and g: result=alpha * f + beta * g
Definition funcimpl.h:3598
"put" this on g
Definition funcimpl.h:2654
change representation of nodes' coeffs to low rank, optional fence
Definition funcimpl.h:2687
check symmetry wrt particle exchange
Definition funcimpl.h:2360
compute the norm of the wavelet coefficients
Definition funcimpl.h:4495
mirror dimensions of this, write result on f
Definition funcimpl.h:2588
map this on f
Definition funcimpl.h:2508
mirror dimensions of this, write result on f
Definition funcimpl.h:2538
Definition funcimpl.h:5590
reduce the rank of the nodes, optional fence
Definition funcimpl.h:2334
remove all coefficients of internal nodes
Definition funcimpl.h:2280
Definition funcimpl.h:4567
shallow-copy, pared-down version of FunctionNode, for special purpose only
Definition funcimpl.h:749
TensorArgs holds the arguments for creating a LowRankTensor.
Definition gentensor.h:134
double thresh
Definition gentensor.h:135
Definition mraimpl.h:3101
void operator()(const Key< NDIM > &key, Tensor< T > &t) const
Definition mraimpl.h:3102
void serialize(Archive &ar)
Definition mraimpl.h:3103
Definition mraimpl.h:3107
void operator()(const Key< NDIM > &key, Tensor< T > &t) const
Definition mraimpl.h:3108
void serialize(Archive &ar)
Definition mraimpl.h:3109
Definition mraimpl.h:3069
void operator()(const A &a, const B &b) const
Definition mraimpl.h:3070
void serialize(Archive &ar)
Definition mraimpl.h:3072
Definition mraimpl.h:3076
void operator()(const Key< NDIM > &key, FunctionNode< T, NDIM > &node) const
Definition mraimpl.h:3084
void serialize(Archive &ar)
Definition mraimpl.h:3087
T q
Definition mraimpl.h:3077
scaleinplace()
Definition mraimpl.h:3078
scaleinplace(T q)
Definition mraimpl.h:3080
void operator()(const Key< NDIM > &key, Tensor< T > &t) const
Definition mraimpl.h:3081
Definition mraimpl.h:3093
void serialize(Archive &ar)
Definition mraimpl.h:3097
void operator()(const Key< NDIM > &key, Tensor< T > &t) const
Definition mraimpl.h:3094
insert/replaces the coefficients into the function
Definition funcimpl.h:692
Definition lowrankfunction.h:336
int np
Definition tdse1d.cc:165
static const double s0
Definition tdse4.cc:83
AtomicInt sum
Definition test_atomicint.cc:46
int me
Definition test_binsorter.cc:10
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
#define N
Definition testconv.cc:37
static const double alpha
Definition testcosine.cc:10
static const int truncate_mode
Definition testcosine.cc:14
constexpr std::size_t NDIM
Definition testgconv.cc:54
double h(const coord_1d &r)
Definition testgconv.cc:175
double g1(const coord_t &r)
Definition testgconv.cc:122
std::size_t axis
Definition testpdiff.cc:59
double k0
Definition testperiodic.cc:66
Defines and implements WorldObject.
Implements WorldContainer.
Defines and implements a concurrent hashmap.
#define PROFILE_FUNC
Definition worldprofile.h:209
#define PROFILE_MEMBER_FUNC(classname)
Definition worldprofile.h:210
#define PROFILE_BLOCK(name)
Definition worldprofile.h:208
int ProcessID
Used to clearly identify process number/rank.
Definition worldtypes.h:43
Key< D > keyT
Definition writecoeff2.cc:11
void test()
Definition y.cc:696