MADNESS 0.10.1
derivative.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_DERIVATIVE_H__INCLUDED
33#define MADNESS_DERIVATIVE_H__INCLUDED
34
35#include <iostream>
36#include <iomanip>
37#include <fstream>
40#include <madness/world/print.h>
41#include <madness/misc/misc.h>
42
45
46#include <madness/mra/key.h>
48
49
50/// \file mra/derivative.h
51/// \brief Declaration and initialization of tree traversal functions and generic derivative
52/// \ingroup mra
53
54namespace madness {
55
56 template<typename T, std::size_t NDIM>
57 class FunctionNode;
58
59 template<typename T, std::size_t NDIM>
60 class Function;
61
62}
63
64
65
66namespace madness {
67
68
69/// Tri-diagonal operator traversing tree primarily for derivative operator
70
71 /// \ingroup mra
72 template <typename T, std::size_t NDIM>
73 class DerivativeBase : public WorldObject< DerivativeBase<T, NDIM> > {
75 protected:
77 const std::size_t axis ; ///< Axis along which the operation is performed
78 const int k ; ///< Number of wavelets of the function
80 const std::vector<long> vk; ///< (k,...) used to initialize Tensors
81
82 public:
83 friend class FunctionImpl<T, NDIM>;
84
85 typedef Tensor<T> tensorT ; ///< regular tensors, like rm, etc
86 typedef GenTensor<T> coeffT ; ///< holding the node's coeffs (possibly low rank)
87 typedef Key<NDIM> keyT ;
88 typedef std::pair<keyT,coeffT> argT ;
93
94 /// Spawn `diff`'s per-node tasks from the task pool instead of the main thread.
95
96 /// The same tasks are produced, so the result is unchanged. Per instance and off by default,
97 /// since it only pays off when many functions are differentiated at once.
98 bool parallel_submit_ = false;
99
102 , world(world)
103 , axis(axis)
104 , k(k)
105 , bc(bc)
106 , vk(NDIM,k)
107 {
108 // No! Cannot process incoming messages until the *derived* class is constructed.
109 // this->process_pending();
110 }
111
112 virtual ~DerivativeBase() { }
113
114 void forward_do_diff1(const implT* f, implT* df, const keyT& key,
115 const argT& left,
116 const argT& center,
117 const argT& right) const {
118
119 const dcT& coeffs = f->get_coeffs();
120 ProcessID owner = coeffs.owner(key);
121
122 if (owner == world.rank()) {
123 if (!left.second.has_data()) {
125 f, df, key, find_neighbor(f, key,-1), center, right,
127 }
128 else if (!right.second.has_data()) {
130 f, df, key, left, center, find_neighbor(f, key,1),
132 }
133 // Boundary node
134 else if (left.first.is_invalid() || right.first.is_invalid()) {
136 f, df, key, left, center, right);
137 }
138 // Interior node
139 else {
141 f, df, key, left, center, right);
142 }
143 }
144 else {
146 this, f, key, left, center, right, TaskAttributes::hipri());
147 }
148 }
149
150 void do_diff1(const implT* f, implT* df, const keyT& key,
151 const argT& left,
152 const argT& center,
153 const argT& right) const {
155
156// if (left.second.size()==0 || right.second.size()==0) {
157 if ((!left.second.has_data()) || (!right.second.has_data())) {
158 // One of the neighbors is below us in the tree ... recur down
159 df->get_coeffs().replace(key,nodeT(coeffT(),true));
160 for (KeyChildIterator<NDIM> kit(key); kit; ++kit) {
161 const keyT& child = kit.key();
162 if ((child.translation()[axis]&1) == 0) {
163 // leftmost child automatically has right sibling
164 forward_do_diff1(f, df, child, left, center, center);
165 }
166 else {
167 // rightmost child automatically has left sibling
168 forward_do_diff1(f, df, child, center, center, right);
169 }
170 }
171 }
172 else {
173 forward_do_diff1(f, df, key, left, center, right);
174 }
175 }
176
177 virtual void do_diff2b(const implT* f, implT* df, const keyT& key,
178 const argT& left,
179 const argT& center,
180 const argT& right) const = 0;
181
182 virtual void do_diff2i(const implT* f, implT* df, const keyT& key,
183 const argT& left,
184 const argT& center,
185 const argT& right) const = 0;
186
187
188 /// Differentiate w.r.t. given coordinate (x=0, y=1, ...) with optional fence
189
190 /// Returns a new function with the same distribution
192 operator()(const functionT& f, bool fence=true) const {
193 if (VERIFY_TREE) f.verify_tree();
194 if (fence) f.change_tree_state(reconstructed);
195 MADNESS_CHECK_THROW(f.is_reconstructed(),"diff: trying to diff a compressed function without fencing");
196
197 functionT df;
198 df.set_impl(f,false);
199
200 df.get_impl()->diff(this, f.get_impl().get(), fence);
201 return df;
202 }
203
204
205 static bool enforce_bc(int bc_left, int bc_right, Level n, Translation& l) {
206 Translation two2n = 1ul << n;
207 if (l < 0) {
208 if (bc_left == BC_ZERO || bc_left == BC_FREE || bc_left == BC_DIRICHLET || bc_left == BC_ZERONEUMANN || bc_left == BC_NEUMANN) {
209 return false; // f=0 BC, or no BC, or nonzero f BC, or zero deriv BC, or nonzero deriv BC
210 }
211 else if (bc_left == BC_PERIODIC) {
212 l += two2n; // Periodic BC
213 MADNESS_ASSERT(bc_left == bc_right); //check that both BCs are periodic
214 }
215 else {
216 MADNESS_EXCEPTION("enforce_bc: confused left BC?",bc_left);
217 }
218 }
219 else if (l >= two2n) {
220 if (bc_right == BC_ZERO || bc_right == BC_FREE || bc_right == BC_DIRICHLET || bc_right == BC_ZERONEUMANN || bc_right == BC_NEUMANN) {
221 return false; // f=0 BC, or no BC, or nonzero f BC, or zero deriv BC, or nonzero deriv BC
222 }
223 else if (bc_right == BC_PERIODIC) {
224 l -= two2n; // Periodic BC
225 MADNESS_ASSERT(bc_left == bc_right); //check that both BCs are periodic
226 }
227 else {
228 MADNESS_EXCEPTION("enforce_bc: confused BC right?",bc_right);
229 }
230 }
231 return true;
232 }
233
234 Key<NDIM> neighbor(const keyT& key, int step) const {
236 l[axis] += step;
237 if (!enforce_bc(bc(axis,0), bc(axis,1), key.level(), l[axis])) {
238 return keyT::invalid();
239 }
240 else {
241 return keyT(key.level(),l);
242 }
243 }
244
245 /// Push f's remote same-level neighbor coefficients to the ranks that will need them.
246
247 /// Node M is the neighbor of M-1 and M+1, so its owner pushes it to the owners of those keys
248 /// without being asked, one batched message per destination. This is the axis-specific
249 /// staging policy for `FunctionImpl`'s halo table; `halo_clear()` frees the result. The
250 /// pushes arrive as tasks, so the fence is what separates staging from differentiating.
251 void stage_halo(const implT* f, bool fence = true) const {
252 const dcT& coeffs = f->get_coeffs();
253 std::map<ProcessID, std::vector<argT> > out;
254 for (const auto& [key, node] : coeffs) {
255 for (int step : {-1, 1}) {
256 keyT consumer = neighbor(key, step);
257 if (consumer.is_invalid()) continue; // domain boundary: no consumer there
258 ProcessID d = coeffs.owner(consumer);
259 if (d == world.rank()) continue; // local consumer: the pull is cheap
260 out[d].push_back(argT(key, node.has_coeff() ? node.coeff() : coeffT()));
261 }
262 }
263 for (auto& kv : out)
264 f->task(kv.first, &implT::receive_halo, kv.second, TaskAttributes::hipri());
265 if (fence) world.gop.fence();
266 }
267
269 find_neighbor(const implT* f, const Key<NDIM>& key, int step) const {
270 keyT neigh = neighbor(key, step);
271 if (neigh.is_invalid()) {
272 return Future<argT>(argT(neigh,coeffT(vk,f->get_tensor_args()))); // Zero bc
273 }
274 else {
275 // hit: same-level leaf or interior node. miss: neighbor is coarser, walk up below.
276 coeffT c;
277 if (f->halo_probe(neigh, c)) return Future<argT>(argT(neigh, c));
278 const auto& coeffs = f->get_coeffs();
279 keyT curr = neigh;
280 while (coeffs.is_local(curr)) {
281 if (coeffs.probe(curr)) {
282 const auto& node = coeffs.find(curr).get()->second;
283 return Future<argT>(argT(curr, node.has_coeff() ? node.coeff() : coeffT()));
284 }
285 // Key::parent() of the root is the root, so without this a tree missing its root spins here
286 MADNESS_CHECK_THROW(curr.level() > 0, "find_neighbor: no ancestor of the neighbor is in the tree");
287 curr = curr.parent();
288 }
289 Future<argT> result;
290 f->task(coeffs.owner(curr), &implT::sock_it_to_me, curr, result.remote_ref(world), TaskAttributes::hipri());
291 return result;
292 }
293 }
294
295
296 /// Body of `FunctionImpl::diff`'s submission loop, as a functor for `taskq.for_each`.
297 struct submit_op {
300 const implT* f;
302 submit_op(const DerivativeBase<T,NDIM>* D=nullptr, const implT* f=nullptr, implT* df=nullptr)
303 : D(D), f(f), df(df) {}
304 bool operator()(typename rangeT::iterator& it) const {
305 const keyT& key = it->first;
306 const nodeT& node = it->second;
307 if (node.has_coeff()) {
308 Future<argT> left = D->find_neighbor(f, key, -1);
309 argT center(key, node.coeff());
310 Future<argT> right = D->find_neighbor(f, key, 1);
311 df->world.taskq.add(*df, &implT::do_diff1, D, f, key, left, center, right, TaskAttributes::hipri());
312 }
313 else {
314 df->get_coeffs().replace(key, nodeT(coeffT(), true)); // empty internal node
315 }
316 return true;
317 }
318 template <typename Archive> void serialize(const Archive& ar) {}
319 };
320
321 /// Parallel form of `FunctionImpl::diff`'s submission loop; the caller owns the fence.
322 void submit_diff_tasks(const implT* f, implT* df) const {
324 df->world.taskq.template for_each<rangeT, submit_op>(
325 rangeT(f->get_coeffs().begin(), f->get_coeffs().end()), submit_op(this, f, df));
326 }
327
328 template <typename Archive> void serialize(const Archive& ar) const {
329 throw "NOT IMPLEMENTED";
330 }
331
332 }; // End of the DerivativeBase class
333
334
335 /// Implements derivatives operators with variety of boundary conditions on simulation domain
336 template <typename T, std::size_t NDIM>
337 class Derivative : public DerivativeBase<T, NDIM> {
338 private:
340
341 public:
343 typedef GenTensor<T> coeffT ; ///< holding the node's coeffs (possibly low rank)
344 typedef Key<NDIM> keyT ;
345 typedef std::pair<keyT,coeffT> argT ;
350
351 private:
352 const functionT g1; ///< Function describing the boundary condition on the right side
353 const functionT g2; ///< Function describing the boundary condition on the left side
354
357
358 // Tensors for holding the modified coefficients
359 Tensor<double> rm, r0, rp ; ///< Blocks of the derivative operator
360 Tensor<double> rmt, r0t, rpt ; ///< Blocks of the derivative operator, transposed
361 Tensor<double> left_rm, left_r0 ; ///< Blocks of the derivative for the left boundary
362 Tensor<double> left_rmt, left_r0t ; ///< Blocks of the derivative for the left boundary
363 Tensor<double> right_r0, right_rp; ///< Blocks of the derivative for the right boundary
364 Tensor<double> right_r0t, right_rpt; ///< Blocks of the derivative for the right boundary
365 Tensor<double> bv_left, bv_right ; ///< Blocks of the derivative operator for the boundary contribution
366
367
368 // Tensors for the bspline smoothed central difference operator
375
376 void do_diff2b(const implT* f, implT* df, const keyT& key,
377 const argT& left,
378 const argT& center,
379 const argT& right) const {
381 double lev = (double) key.level();
382
383 coeffT d;
384
385 //left boundary
386 if (l[this->axis] == 0) {
387
388 coeffT tensor_right=df->parent_to_child(right.second, right.first, this->neighbor(key,1));
389 coeffT tensor_center=df->parent_to_child(center.second, center.first, key);
390
391 d= transform_dir(tensor_right,left_rmt,this->axis);
392 d+=transform_dir(tensor_center,left_r0t,this->axis);
393 }
394 else {
395
396 coeffT tensor_left=df->parent_to_child(left.second, left.first, this->neighbor(key,-1));
397 coeffT tensor_center=df->parent_to_child(center.second, center.first, key);
398
399 d= transform_dir(tensor_left,right_rpt,this->axis);
400 d+=transform_dir(tensor_center,right_r0t,this->axis);
401 }
402
403 double fac = FunctionDefaults<NDIM>::get_rcell_width()[this->axis]*pow(2.0,lev);
404 if (is_second) fac *= fac;
405 else if (is_third) fac *= fac*fac;
406
407 d.scale(fac);
408 d.reduce_rank(df->get_thresh());
409 df->get_coeffs().replace(key,nodeT(d,false));
410
411
412 // This is the boundary contribution (formally in BoundaryDerivative)
413 int bc_left = this->bc(this->axis,0);
414 int bc_right = this->bc(this->axis,1);
415
416 Future<argT> found_argT;
417 tensorT bf, bdry_t;
418 //left boundary
419 if (l[this->axis] == 0) {
420 if (bc_left != BC_PERIODIC && bc_left != BC_FREE && bc_left != BC_ZERO && bc_left != BC_ZERONEUMANN) {
421 bf = copy(bv_left);
422 found_argT = g1.get_impl()->find_me(key);
423 }
424 else {
425 return;
426 }
427 }
428 else { //right boundary
429 if (bc_right != BC_PERIODIC && bc_right != BC_FREE && bc_right != BC_ZERO && bc_right != BC_ZERONEUMANN) {
430 bf = copy(bv_right);
431 found_argT = g2.get_impl()->find_me(key);
432 }
433 else {
434 return;
435 }
436 }
437#ifdef HAVE_PARSEC
438 std::cerr << "FATAL ERROR: PaRSEC does not support recursive task execution but Derivative::do_diff2b requires this. Use a different backend" << std::endl;
439 abort();
440#endif
441 const auto& found_argT_value = found_argT.get(); // do not recursively execute tasks to avoid making PaRSEC sad
442 tensorT gcoeffs = df->parent_to_child(found_argT_value.second, found_argT_value.first,key).full_tensor_copy();
443
444 //if (this->bc.get_bc().dim(0) == 1) {
445 if (NDIM == 1) {
446 bdry_t = gcoeffs[0]*bf;
447 }
448 else {
449 tensorT slice_aid(this->k); //vector of zeros
450 slice_aid[0] = 1;
451 tensorT tmp = inner(slice_aid, gcoeffs, 0, this->axis);
452 bdry_t = outer(bf,tmp);
453 if (this->axis) bdry_t = copy(bdry_t.cycledim(this->axis,0,this->axis)); // make it contiguous
454 }
455 bdry_t.scale(FunctionDefaults<NDIM>::get_rcell_width()[this->axis]);
456
457 if (l[this->axis]==0) {
458 if (bc_left == BC_DIRICHLET)
459 bdry_t.scale( pow(2.0,lev));
460 else if (bc_left ==BC_NEUMANN)
461 bdry_t.scale(FunctionDefaults<NDIM>::get_cell_width()[this->axis]);
462 }
463 else {
464 if (bc_right == BC_DIRICHLET)
465 bdry_t.scale( pow(2.0,lev));
466 else if (bc_right ==BC_NEUMANN)
467 bdry_t.scale(FunctionDefaults<NDIM>::get_cell_width()[this->axis]);
468 }
469
470 bdry_t += d.full_tensor_copy();;
471 df->get_coeffs().replace(key,nodeT(coeffT(bdry_t,df->get_thresh(),df->get_tensor_type()),false));
472 }
473
474 void do_diff2i(const implT* f, implT*df, const keyT& key,
475 const argT& left,
476 const argT& center,
477 const argT& right) const
478 {
479//#if !HAVE_GENTENSOR
480// coeffT d = madness::inner(rp,
481// df->parent_to_child(left.second, left.first, baseT::neighbor(key,-1)).swapdim(this->axis,0),
482// 1, 0);
483// inner_result(r0,
484// df->parent_to_child(center.second, center.first, key).swapdim(this->axis,0),
485// 1, 0, d);
486// inner_result(rm,
487// df->parent_to_child(right.second, right.first, baseT::neighbor(key,1)).swapdim(this->axis,0),
488// 1, 0, d);
489// // flo thinks this is wrong for higher dimensions -- need to cycledim
490// if (this->axis) d = copy(d.swapdim(this->axis,0)); // make it contiguous
491// d.scale(FunctionDefaults<NDIM>::get_rcell_width()[this->axis]*pow(2.0,(double) key.level()));
492// df->get_coeffs().replace(key,nodeT(d,false));
493//
494//#else
495 coeffT tensor_left=df->parent_to_child(left.second, left.first, this->neighbor(key,-1));
496 coeffT tensor_center=df->parent_to_child(center.second, center.first, key);
497 coeffT tensor_right=df->parent_to_child(right.second, right.first, this->neighbor(key,1));
498
499 coeffT d= transform_dir(tensor_left,rpt,this->axis);
500 d+=transform_dir(tensor_center,r0t,this->axis);
501 d+=transform_dir(tensor_right,rmt,this->axis);
502
503 double fac = FunctionDefaults<NDIM>::get_rcell_width()[this->axis]*pow(2.0,(double) key.level());
504 if (is_second) fac *= fac;
505 else if (is_third) fac *= fac*fac;
506
507 d.scale(fac);
508 d.reduce_rank(df->get_thresh());
509 df->get_coeffs().replace(key,nodeT(d,false));
510
511//#endif
512
513 }
514
516 is_second = false;
517 is_third = false;
518
519 r0 = Tensor<double>(this->k,this->k);
520 rp = Tensor<double>(this->k,this->k);
521 rm = Tensor<double>(this->k,this->k);
522
523 left_rm = Tensor<double>(this->k,this->k);
524 left_r0 = Tensor<double>(this->k,this->k);
525
526 right_r0 = Tensor<double>(this->k,this->k);
527 right_rp = Tensor<double>(this->k,this->k);
528
529 // These are the coefficients for the boundary contribution
530 bv_left = Tensor<double>(this->k);
531 bv_right = Tensor<double>(this->k);
532
533 int bc_left = this->bc(this->axis,0);
534 int bc_right = this->bc(this->axis,1);
535
536 double kphase = -1.0;
537 if (this->k%2 == 0) kphase = 1.0;
538 double iphase = 1.0;
539 for (int i=0; i<this->k; ++i) {
540 double jphase = 1.0;
541 for (int j=0; j<this->k; ++j) {
542 double gammaij = sqrt(double((2*i+1)*(2*j+1)));
543 double Kij;
544 if (((i-j)>0) && (((i-j)%2)==1))
545 Kij = 2.0;
546 else
547 Kij = 0.0;
548
549 r0(i,j) = 0.5*(1.0 - iphase*jphase - 2.0*Kij)*gammaij;
550 rm(i,j) = 0.5*jphase*gammaij;
551 rp(i,j) =-0.5*iphase*gammaij;
552
553 // Constraints on the derivative
554 if (bc_left == BC_ZERONEUMANN || bc_left == BC_NEUMANN) {
555 left_rm(i,j) = jphase*gammaij*0.5*(1.0 + iphase*kphase/this->k);
556
557 double phi_tmpj_left = 0;
558
559 for (int l=0; l<this->k; ++l) {
560 double gammalj = sqrt(double((2*l+1)*(2*j+1)));
561 double Klj;
562
563 if (((l-j)>0) && (((l-j)%2)==1)) Klj = 2.0;
564 else Klj = 0.0;
565
566 phi_tmpj_left += sqrt(double(2*l+1))*Klj*gammalj;
567 }
568 phi_tmpj_left = -jphase*phi_tmpj_left;
569 left_r0(i,j) = (0.5*(1.0 + iphase*kphase/this->k) - Kij)*gammaij + iphase*sqrt(double(2*i+1))*phi_tmpj_left/pow(this->k,2.);
570 }
571 else if (bc_left == BC_ZERO || bc_left == BC_DIRICHLET || bc_left == BC_FREE) {
572 left_rm(i,j) = rm(i,j);
573
574 // B.C. with a function
575 if (bc_left == BC_ZERO || bc_left == BC_DIRICHLET)
576 left_r0(i,j) = (0.5 - Kij)*gammaij;
577
578 // No B.C.
579 else if (bc_left == BC_FREE)
580 left_r0(i,j) = (0.5 - iphase*jphase - Kij)*gammaij;
581 }
582
583 // Constraints on the derivative
584 if (bc_right == BC_ZERONEUMANN || bc_right == BC_NEUMANN) {
585 right_rp(i,j) = -0.5*(iphase + kphase / this->k)*gammaij;
586
587 double phi_tmpj_right = 0;
588 for (int l=0; l<this->k; ++l) {
589 double gammalj = sqrt(double((2*l+1)*(2*j+1)));
590 double Klj;
591 if (((l-j)>0) && (((l-j)%2)==1)) Klj = 2.0;
592 else Klj = 0.0;
593 phi_tmpj_right += sqrt(double(2*l+1))*Klj*gammalj;
594 }
595 right_r0(i,j) = -(0.5*jphase*(iphase+ kphase/this->k) + Kij)*gammaij + sqrt(double(2*i+1))*phi_tmpj_right/pow(this->k,2.);
596 }
597 else if (bc_right == BC_ZERO || bc_right == BC_FREE || bc_right == BC_DIRICHLET) {
598 right_rp(i,j) = rp(i,j);
599
600 // Zero BC
601 if (bc_right == BC_ZERO || bc_right == BC_DIRICHLET)
602 right_r0(i,j) = -(0.5*iphase*jphase + Kij)*gammaij;
603
604 // No BC
605 else if (bc_right == BC_FREE)
606 right_r0(i,j) = (1.0 - 0.5*iphase*jphase - Kij)*gammaij;
607
608 }
609
610 jphase = -jphase;
611 }
612 iphase = -iphase;
613 }
614
615 // Coefficients for the boundary contributions
616 iphase = 1.0;
617 for (int i=0; i<this->k; ++i) {
618 iphase = -iphase;
619
620 if (bc_left == BC_DIRICHLET)
621 bv_left(i) = iphase*sqrt(double(2*i+1)); // vector for left dirichlet BC
622 else if(bc_left == BC_NEUMANN)
623 bv_left(i) = -iphase*sqrt(double(2*i+1))/pow(this->k,2.); // vector for left deriv BC
624 else
625 bv_left(i) = 0.0;
626
627 if (bc_right == BC_DIRICHLET)
628 bv_right(i) = sqrt(double(2*i+1)); // vector for right dirichlet BC
629 else if (bc_right == BC_NEUMANN)
630 bv_right(i) = sqrt(double(2*i+1))/pow(this->k,2.); // vector for right deriv BC
631 else
632 bv_right(i) = 0.0;
633 }
634
635 r0t = transpose(r0);
636 rpt = transpose(rp);
637 rmt = transpose(rm);
638
641
644
645 //print(rm.normf(),r0.normf(),rp.normf(),left_rm.normf(),left_r0.normf(),right_r0.normf(),right_rp.normf(),bv_left.normf(),bv_right.normf());
646 }
647
648 public:
649 typedef T opT;
650
651 /// Constructs a derivative operator
652
653 /// @param world The world
654 /// @param axis The direction to differentiate
655 /// @param bc Boundary conditions (default from FunctionDefaults)
656 /// @param g1 Function providing left boundary value (default empty)
657 /// @param g2 Function providing right boundary value (default empty)
658 /// @param k Wavelet order (default from FunctionDefaults)
660 std::size_t axis,
662 const functionT g1=functionT(),
663 const functionT g2=functionT(),
665 : DerivativeBase<T, NDIM>(world, axis, k, bc)
666 , g1(g1)
667 , g2(g2)
668 {
671 g1.reconstruct();
672 g2.reconstruct();
673
674 this->process_pending();
675 }
676
677 virtual ~Derivative() { }
678
679 void set_is_first() {is_second = false; is_third = false;}
680 void set_is_second() {is_second = true; is_third=false;}
681 void set_is_third() {is_second = false; is_third = true;}
682
685 if(k > 18) throw "Bspline derivatives are only available up to k=18";
686 std::string filename = get_mra_data_dir() + "/b-spline-deriv1.txt";
688 }
689
692 if(k > 18) throw "Bspline derivatives are only available up to k=18";
693 std::string filename = get_mra_data_dir() + "/b-spline-deriv2.txt";
695 }
696
699 if(k > 18) throw "Bspline derivatives are only available up to k=18";
700 std::string filename = get_mra_data_dir() + "/b-spline-deriv3.txt";
702 }
703
704 void set_ble1() {
706 if(k > 15) throw "BLE derivatives are only available up to k=15";
707 std::string filename = get_mra_data_dir() + "/ble-first.txt";
709 }
710
711 void set_ble2() {
713 if(k > 15) throw "BLE derivatives are only available up to k=15";
714 std::string filename = get_mra_data_dir() + "/ble-second.txt";
716 }
717
718 void read_from_file(const std::string& filename, unsigned int order = 1) {
719
720 Tensor<double> r0_bsp(this->k,this->k);
721 Tensor<double> rp_bsp(this->k,this->k);
722 Tensor<double> rm_bsp(this->k,this->k);
723
724 std::ifstream f(filename);
725 bool found=false;
726
727 for (int m; f >> m; ) {
728 if (m == this->k) {
729 for (int i=0; i<m; i++)
730 for (int j=0; j<m; j++)
731 MADNESS_CHECK(f >> rp_bsp(i,j));
732 for (int i=0; i<m; i++)
733 for (int j=0; j<m; j++)
734 MADNESS_CHECK(f >> r0_bsp(i,j));
735 for (int i=0; i<m; i++)
736 for (int j=0; j<m; j++)
737 MADNESS_CHECK(f >> rm_bsp(i,j));
738 found = true;
739 break;
740 }
741 else {
742 double junk;
743 for (int i=0; i<3*m*m; i++)
744 MADNESS_CHECK(f >> junk);
745 }
746 }
747 MADNESS_CHECK(found);
751
753
755
757
758 // Get scaling factor right for higher order derivatives
759 if (order == 1) {
760 set_is_first();
761 }
762 else if(order == 2) {
764 }
765 else if(order == 3) {
766 set_is_third();
767 }
768 }
769 };
770
771
772 /// Convenience function returning derivative operator with free-space boundary conditions
773 template <typename T, std::size_t NDIM>
774 Derivative<T,NDIM>
778
779
780 /// Conveinence function returning derivative operator with periodic boundary conditions
781 template <typename T, std::size_t NDIM>
782 Derivative<T,NDIM>
786
787 /// Applies derivative operator to function (for syntactic equivalence to integral operator apply)
788 template <typename T, std::size_t NDIM>
789 Function<T,NDIM>
790 apply(const Derivative<T,NDIM>& D, const Function<T,NDIM>& f, bool fence=true) {
791 return D(f,fence);
792 }
793
794 /// Convenience function returning vector of derivative operators implementing grad (\f$ \nabla \f$)
795
796 /// This will only work for BC_ZERO, BC_PERIODIC, BC_FREE and
797 /// BC_ZERONEUMANN since we are not passing in any boundary
798 /// functions.
799 template <typename T, std::size_t NDIM>
800 std::vector< std::shared_ptr< Derivative<T,NDIM> > >
804 std::vector< std::shared_ptr< Derivative<T,NDIM> > > r(NDIM);
805 for (std::size_t d=0; d<NDIM; ++d) {
806 MADNESS_CHECK(bc(d,0)!=BC_DIRICHLET && bc(d,1)!=BC_DIRICHLET);
807 MADNESS_CHECK(bc(d,0)!=BC_NEUMANN && bc(d,1)!=BC_NEUMANN);
808 r[d].reset(new Derivative<T,NDIM>(world,d,bc,Function<T,NDIM>(),Function<T,NDIM>(),k));
809 }
810 return r;
811 }
812
813
814 namespace archive {
815 template <class Archive, class T, std::size_t NDIM>
816 struct ArchiveLoadImpl<Archive,const DerivativeBase<T,NDIM>*> {
817 static void load(const Archive& ar, const DerivativeBase<T,NDIM>*& ptr) {
819 ar & p;
820 ptr = static_cast< const DerivativeBase<T,NDIM>* >(p);
821 }
822 };
823
824 template <class Archive, class T, std::size_t NDIM>
825 struct ArchiveStoreImpl<Archive,const DerivativeBase<T,NDIM>*> {
826 static void store(const Archive& ar, const DerivativeBase<T,NDIM>* const & ptr) {
827 ar & ptr->id();
828 }
829 };
830 }
831
832} // End of the madness namespace
833
834#endif // MADNESS_MRA_DERIVATIVE_H_INCLUDED
This header should include pretty much everything needed for the parallel runtime.
This class is used to specify boundary conditions for all operators.
Definition bc.h:72
Tri-diagonal operator traversing tree primarily for derivative operator.
Definition derivative.h:73
void submit_diff_tasks(const implT *f, implT *df) const
Parallel form of FunctionImpl::diff's submission loop; the caller owns the fence.
Definition derivative.h:322
void do_diff1(const implT *f, implT *df, const keyT &key, const argT &left, const argT &center, const argT &right) const
Definition derivative.h:150
GenTensor< T > coeffT
holding the node's coeffs (possibly low rank)
Definition derivative.h:86
static bool enforce_bc(int bc_left, int bc_right, Level n, Translation &l)
Definition derivative.h:205
DerivativeBase(World &world, std::size_t axis, int k, BoundaryConditions< NDIM > bc)
Definition derivative.h:100
Key< NDIM > keyT
Definition derivative.h:87
const BoundaryConditions< NDIM > bc
Definition derivative.h:79
Tensor< T > tensorT
regular tensors, like rm, etc
Definition derivative.h:85
const std::vector< long > vk
(k,...) used to initialize Tensors
Definition derivative.h:80
Key< NDIM > neighbor(const keyT &key, int step) const
Definition derivative.h:234
WorldContainer< Key< NDIM >, FunctionNode< T, NDIM > > dcT
Definition derivative.h:91
virtual ~DerivativeBase()
Definition derivative.h:112
FunctionImpl< T, NDIM > implT
Definition derivative.h:89
FunctionNode< T, NDIM > nodeT
Definition derivative.h:92
Function< T, NDIM > functionT
Definition derivative.h:90
void forward_do_diff1(const implT *f, implT *df, const keyT &key, const argT &left, const argT &center, const argT &right) const
Definition derivative.h:114
const int k
Number of wavelets of the function.
Definition derivative.h:78
WorldObject< DerivativeBase< T, NDIM > > woT
Definition derivative.h:74
void serialize(const Archive &ar) const
Definition derivative.h:328
Future< argT > find_neighbor(const implT *f, const Key< NDIM > &key, int step) const
Definition derivative.h:269
Function< T, NDIM > operator()(const functionT &f, bool fence=true) const
Differentiate w.r.t. given coordinate (x=0, y=1, ...) with optional fence.
Definition derivative.h:192
void stage_halo(const implT *f, bool fence=true) const
Push f's remote same-level neighbor coefficients to the ranks that will need them.
Definition derivative.h:251
virtual void do_diff2i(const implT *f, implT *df, const keyT &key, const argT &left, const argT &center, const argT &right) const =0
const std::size_t axis
Axis along which the operation is performed.
Definition derivative.h:77
World & world
Definition derivative.h:76
virtual void do_diff2b(const implT *f, implT *df, const keyT &key, const argT &left, const argT &center, const argT &right) const =0
bool parallel_submit_
Spawn diff's per-node tasks from the task pool instead of the main thread.
Definition derivative.h:98
std::pair< keyT, coeffT > argT
Definition derivative.h:88
Implements derivatives operators with variety of boundary conditions on simulation domain.
Definition derivative.h:337
Tensor< double > right_r0t
Definition derivative.h:364
void set_ble2()
Definition derivative.h:711
Tensor< double > rmt
Definition derivative.h:360
Tensor< double > bv_left
Definition derivative.h:365
void set_bspline1()
Definition derivative.h:683
Tensor< double > r0
Definition derivative.h:359
Tensor< double > rp_bsp
Definition derivative.h:371
bool is_second
Definition derivative.h:355
Tensor< double > right_rp
Blocks of the derivative for the right boundary.
Definition derivative.h:363
void set_is_second()
Definition derivative.h:680
Derivative(World &world, std::size_t axis, const BoundaryConditions< NDIM > &bc=FunctionDefaults< NDIM >::get_bc(), const functionT g1=functionT(), const functionT g2=functionT(), int k=FunctionDefaults< NDIM >::get_k())
Constructs a derivative operator.
Definition derivative.h:659
Function< T, NDIM > functionT
Definition derivative.h:347
Tensor< double > r0t
Definition derivative.h:360
std::pair< keyT, coeffT > argT
Definition derivative.h:345
FunctionImpl< T, NDIM > implT
Definition derivative.h:346
Tensor< double > right_rpt
Blocks of the derivative for the right boundary.
Definition derivative.h:364
Tensor< double > left_rmt
Definition derivative.h:362
Tensor< double > rp_bsp_t
Definition derivative.h:374
virtual ~Derivative()
Definition derivative.h:677
GenTensor< T > coeffT
holding the node's coeffs (possibly low rank)
Definition derivative.h:343
const functionT g2
Function describing the boundary condition on the left side.
Definition derivative.h:353
void read_from_file(const std::string &filename, unsigned int order=1)
Definition derivative.h:718
Tensor< double > rp
Blocks of the derivative operator.
Definition derivative.h:359
void do_diff2i(const implT *f, implT *df, const keyT &key, const argT &left, const argT &center, const argT &right) const
Definition derivative.h:474
bool is_third
Definition derivative.h:356
void set_bspline3()
Definition derivative.h:697
Tensor< double > rm_bsp
Definition derivative.h:370
void set_bspline2()
Definition derivative.h:690
Tensor< double > rm
Definition derivative.h:359
void initCoefficients()
Definition derivative.h:515
Tensor< double > left_r0
Blocks of the derivative for the left boundary.
Definition derivative.h:361
Tensor< double > rpt
Blocks of the derivative operator, transposed.
Definition derivative.h:360
void do_diff2b(const implT *f, implT *df, const keyT &key, const argT &left, const argT &center, const argT &right) const
Definition derivative.h:376
void set_is_third()
Definition derivative.h:681
T opT
Definition derivative.h:649
Tensor< double > rm_bsp_t
Definition derivative.h:373
Tensor< double > left_r0t
Blocks of the derivative for the left boundary.
Definition derivative.h:362
Tensor< T > tensorT
Definition derivative.h:342
void set_is_first()
Definition derivative.h:679
FunctionNode< T, NDIM > nodeT
Definition derivative.h:349
Tensor< double > bv_right
Blocks of the derivative operator for the boundary contribution.
Definition derivative.h:365
Key< NDIM > keyT
Definition derivative.h:344
const functionT g1
Function describing the boundary condition on the right side.
Definition derivative.h:352
void set_ble1()
Definition derivative.h:704
Tensor< double > left_rm
Definition derivative.h:361
WorldContainer< Key< NDIM >, FunctionNode< T, NDIM > > dcT
Definition derivative.h:348
Tensor< double > r0_bsp
Definition derivative.h:369
Tensor< double > right_r0
Definition derivative.h:363
DerivativeBase< T, NDIM > baseT
Definition derivative.h:339
Tensor< double > r0_bsp_t
Definition derivative.h:372
FunctionDefaults holds default paramaters as static class members.
Definition funcdefaults.h:101
static int get_k()
Returns the default wavelet order.
Definition funcdefaults.h:170
static const Tensor< double > & get_rcell_width()
Returns the reciprocal of the width of each user cell dimension.
Definition funcdefaults.h:395
FunctionImpl holds all Function state to facilitate shallow copy semantics.
Definition funcimpl.h:982
World & world
Definition funcimpl.h:1001
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:2908
double get_thresh() const
Definition mraimpl.h:340
void receive_halo(const std::vector< std::pair< keyT, coeffT > > &buf) const
Insert pushed neighbor nodes into the halo; runs as a task, concurrently with other pushes.
Definition funcimpl.h:1064
TensorType get_tensor_type() const
Definition mraimpl.h:331
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:961
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:3330
const dcT & get_coeffs() const
Definition mraimpl.h:355
FunctionNode holds the coefficients, etc., at each node of the 2^NDIM-tree.
Definition funcimpl.h:136
A multiresolution adaptive numerical function.
Definition mra.h:144
A future is a possibly yet unevaluated value.
Definition future.h:370
T & get(bool dowork=true) &
Gets the value, waiting if necessary.
Definition future.h:571
remote_refT remote_ref(World &world) const
Returns a structure used to pass references to another process.
Definition future.h:672
Definition lowranktensor.h:59
Tensor< T > full_tensor_copy() const
Definition gentensor.h:206
Iterates in lexical order thru all children of a key.
Definition key.h:548
Key is the index for a node of the 2^NDIM-tree.
Definition key.h:70
Level level() const
Definition key.h:169
bool is_invalid() const
Checks if a key is invalid.
Definition key.h:119
Key parent(int generation=1) const
Returns the key of the parent.
Definition key.h:290
const Vector< Translation, NDIM > & translation() const
Definition key.h:174
static Key< NDIM > invalid()
Returns an invalid key.
Definition key.h:110
Range, vaguely a la Intel TBB, to encapsulate a random-access, STL-like start and end iterator with c...
Definition range.h:64
static TaskAttributes hipri()
Definition thread.h:457
A tensor is a multidimensional array.
Definition tensor.h:318
A simple, fixed dimension vector.
Definition vector.h:64
Makes a distributed container with specified attributes.
Definition worlddc.h:1299
void replace(const pairT &datum)
Inserts/replaces key+value pair (non-blocking communication if key not local)
Definition worlddc.h:1453
void fence(bool debug=false)
Synchronizes all processes in communicator AND globally ensures no pending AM or tasks.
Definition worldgop.cc:177
Implements most parts of a globally addressable object (via unique ID).
Definition world_object.h:491
void process_pending()
To be called from derived constructor to process pending messages.
Definition world_object.h:787
detail::task_result_type< memfnT >::futureT task(ProcessID dest, memfnT memfn, const TaskAttributes &attr=TaskAttributes()) const
Sends task to derived class method returnT (this->*memfn)().
Definition world_object.h:1132
void add(TaskInterface *t)
Add a new local task, taking ownership of the pointer.
Definition world_task_queue.h:466
A parallel world class.
Definition world.h:134
WorldTaskQueue & taskq
Task queue.
Definition world.h:215
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition world.h:344
WorldGopInterface & gop
Global operations.
Definition world.h:216
char * p(char *buf, const char *name, int k, int initial_level, double thresh, int order)
Definition derivatives.cc:72
Provides FunctionDefaults and utilities for coordinate transformation.
Tensor< T > transpose(const Tensor< T > &t)
Returns a new deep copy of the transpose of the input tensor.
Definition tensor.h:2035
Multidimension Key for MRA tree and associated iterators.
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
Header to declare stuff which has not yet found a home.
static const bool VERIFY_TREE
Definition mra.h:57
Namespace for all elements and tools of MADNESS.
Definition DFConvergence.h:9
@ BC_DIRICHLET
Definition bc.h:54
@ BC_NEUMANN
Definition bc.h:56
@ BC_ZERO
Definition bc.h:51
@ BC_PERIODIC
Definition bc.h:52
@ BC_ZERONEUMANN
Definition bc.h:55
@ BC_FREE
Definition bc.h:53
static const char * filename
Definition legendre.cc:96
@ reconstructed
s coeffs at the leaves only
Definition funcdefaults.h:61
int64_t Translation
Definition key.h:58
std::vector< std::shared_ptr< Derivative< T, NDIM > > > gradient_operator(World &world, const BoundaryConditions< NDIM > &bc=FunctionDefaults< NDIM >::get_bc(), int k=FunctionDefaults< NDIM >::get_k())
Convenience function returning vector of derivative operators implementing grad ( )
Definition derivative.h:801
Derivative< T, NDIM > periodic_derivative(World &world, int axis, int k=FunctionDefaults< NDIM >::get_k())
Conveinence function returning derivative operator with periodic boundary conditions.
Definition derivative.h:783
int Level
Definition key.h:59
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
std::string get_mra_data_dir()
Definition startup.cc:209
Derivative< T, NDIM > free_space_derivative(World &world, int axis, int k=FunctionDefaults< NDIM >::get_k())
Convenience function returning derivative operator with free-space boundary conditions.
Definition derivative.h:775
NDIM & f
Definition mra.h:2668
GenTensor< TENSOR_RESULT_TYPE(R, Q)> transform_dir(const GenTensor< R > &t, const Tensor< Q > &c, const int axis)
Definition lowranktensor.h:1106
CCPairFunction< T, NDIM > apply(const SeparatedConvolution< T, NDIM/2 > &op, const CCPairFunction< T, NDIM > &arg)
apply the operator to the argument
Definition ccpairfunction.h:896
Function< T, CCPairFunction< T, NDIM >::LDIM > inner(const CCPairFunction< T, NDIM > &c, const Function< T, CCPairFunction< T, NDIM >::LDIM > &f, const std::tuple< int, int, int > v1, const std::tuple< int, int, int > v2)
Definition ccpairfunction.h:993
Function< T, NDIM > 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:2233
static const double d
Definition nonlinschro.cc:121
Defines simple templates for printing to std::cout "a la Python".
static const double c
Definition relops.cc:10
static const double m
Definition relops.cc:9
static const long k
Definition rk.cc:44
Definition test_ar.cc:204
Body of FunctionImpl::diff's submission loop, as a functor for taskq.for_each.
Definition derivative.h:297
submit_op(const DerivativeBase< T, NDIM > *D=nullptr, const implT *f=nullptr, implT *df=nullptr)
Definition derivative.h:302
Range< typename dcT::const_iterator > rangeT
Definition derivative.h:298
void serialize(const Archive &ar)
Definition derivative.h:318
const DerivativeBase< T, NDIM > * D
Definition derivative.h:299
const implT * f
Definition derivative.h:300
bool operator()(typename rangeT::iterator &it) const
Definition derivative.h:304
implT * df
Definition derivative.h:301
const uniqueidT & id() const
Returns the globally unique object ID.
Definition world_object.h:424
static void load(const Archive &ar, const DerivativeBase< T, NDIM > *&ptr)
Definition derivative.h:817
Default load of an object via serialize(ar, t).
Definition archive.h:667
static void store(const Archive &ar, const DerivativeBase< T, NDIM > *const &ptr)
Definition derivative.h:826
Default store of an object via serialize(ar, t).
Definition archive.h:612
Defines and implements most of Tensor.
constexpr std::size_t NDIM
Definition testgconv.cc:54
std::size_t axis
Definition testpdiff.cc:59
Implements WorldContainer.
int ProcessID
Used to clearly identify process number/rank.
Definition worldtypes.h:43