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