MADNESS 0.10.1
leafop.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/*
33* Leafop.h
34 *
35 * Created on: Apr 12, 2016
36 * Author: kottmanj
37 *
38 * Definition of Operators which operate on leaf boxes
39 * includes special operators for cuspy funtions (f12 applications) which enforce deeper refinement on the "diagonal" boxes (coordinate r1 == coordinate r2)
40 *
41 */
42
43#ifndef SRC_MADNESS_MRA_LEAFOP_H_
44#define SRC_MADNESS_MRA_LEAFOP_H_
45
46namespace madness {
47
48// forward declarations
49template<std::size_t NDIM>
50class Key;
51
52template<typename T>
53class GenTensor;
54
55template<typename T, std::size_t NDIM>
56class SeparatedConvolution;
57
58/// helper structure for the Leaf_op
59/// The class has an operator which decides if a given key belongs to a special box (needs further refinement up to a special level)
60/// this is the default class which always gives back false
61template<typename T, std::size_t NDIM>
63public:
65
66 virtual ~Specialbox_op() {}
67
68 virtual std::string name() const { return "default special box which only checks for the special points"; }
69
70 /// the operator which deceides if the given box is special
71 /// @param[in] the key of the current box
72 /// @param[in] the function which will be constructed (if it is needed)
73 /// @param[out] bool which states if the box is special or not
74 virtual bool operator()(const Key<NDIM>& key, const FunctionImpl<T, NDIM> *const f = NULL) const { return false; }
75
76 // check if on of the special points is in the current box (or at low refinement level in a neighbouring box)
77 /// @param[in] the key of the box
78 /// @param[in] the function which will be constructed (if it is needed)
79 bool
80 check_special_points(const Key<NDIM>& key, const FunctionImpl<T, NDIM> *const f) const {
81 const std::vector<Vector<double, NDIM> >& special_points = f->get_special_points();
82 if (special_points.empty()) return false;
83 // level 0 and 1 has only boundary boxes
84 if (key.level() > 1 and box_is_at_boundary(key)) return false;
85 // check for all special points if they are neighbours of the current box
87 const auto bperiodic = bc.is_periodic();
88 for (size_t i = 0; i < special_points.size(); ++i) {
90 user_to_sim(special_points[i], simpt);
91 if (key.is_neighbor_of(simpt, bperiodic)) return true;
92 else return false;
93 }
94 return false;
95 }
96
97
98 template<typename Archive>
99 void
100 serialize(Archive& ar) {}
101
102 /// Determine if a given box is at the boundary of the simulation box
103 /// @param[in] the key of the current box
104 /// Since boxes of level 0 and 1 are always at the boundary this case should be avoided
105 /// if the boundary conditions are periodic then all boxes are boundary boxes
106 virtual bool box_is_at_boundary(const Key<NDIM>& key) const {
107 // l runs from l=0 to l=2^n-1 for every dimension
108 // if one l is = 2^n or 0 we are at the boundary
109 // note that boxes of level 0 and 1 are always boundary boxes
110 for (size_t i = 0; i < NDIM; i++) {
111 if (key.translation()[i] == 0 or key.translation()[i] == pow(2, key.level()) - 1) {
112 if (FunctionDefaults<NDIM>::get_bc()(i, 0) != BC_PERIODIC)return true;
113 }
114 }
115 return false;
116 }
117
118 // if you want to use milder refinement conditions for special boxes with increasing refinement level
119 // Cuspybox_op needs this
121 size_t ll = sl;
122 if (sl % 2 == 0) ll = sl / 2;
123 else ll = (sl + 1) / 2;
124 return ll;
125 }
126
127};
128
129/// the high_dimensional key is broken appart into two lower dimensional keys, if they are neighbours of each other then refinement
130/// up to the special_level is enforced
131/// For general class description see the base class Specialbox_op
132template<typename T, std::size_t NDIM>
133struct ElectronCuspyBox_op : public Specialbox_op<T, NDIM> {
134public:
136
138
139 template<typename Archive>
140 void serialize(Archive& ar) {}
141
142 std::string name() const { return "Cuspybox_op"; }
143
144 /// Operator which decides if the key belongs to a special box
145 /// The key is broken apart in two lower dimensional keys (for electron cusps this is 6D -> 2x3D)
146 /// if the keys are neighbours then refinement up to the special level is enforced (means the 6D box is close to the cusp or contains it)
147 /// if the refinement level is already beyond half of the special_level then refinement is only enforded if the broken keys are the same (6D box contains cusp)
148 bool operator()(const Key<NDIM>& key, const FunctionImpl<T, NDIM> *const f) const {
149 // do not treat boundary boxes beyond level 2 as special (level 1 and 0 consist only of boundary boxes)
150 if (not(key.level() < 2)) {
151 if (this->box_is_at_boundary(key)) return false;
152 }
153
154 // Cuspybox_op only valid for even dimensions, if uneven dims are needed just make a new class with NDIM+1/2 and NDIM-LDIM
155 if constexpr (NDIM % 2 == 0) {
157 const auto bperiodic = bc.template is_periodic<NDIM / 2>();
158 Key<NDIM / 2> key1;
159 Key<NDIM / 2> key2;
160 key.break_apart(key1, key2);
161 int ll = this->get_half_of_special_level();
162 if (ll < f->get_initial_level())
163 ll = f->get_initial_level();
164 if (key.level() > ll) {
165 if (key1 == key2)
166 return true;
167 else
168 return false;
169 } else {
170 if (key1.is_neighbor_of(key2, bperiodic))
171 return true;
172 else
173 return false;
174 }
175 }
176 MADNESS_EXCEPTION("We should not end up here (check further of cuspy box)", 1);
177 return false;
178 }
179
180};
181
182/// This works similar to the Cuspybox_op: The key is broken apart (2N-dimensional -> 2x N-Dimensional)
183/// then it is checked if one of the lower dimensional keys contains a lower dimensional special points (which will be the nuclear-coordinates)
184template<typename T, std::size_t NDIM>
185struct NuclearCuspyBox_op : public Specialbox_op<T, NDIM> {
186public:
188 // failsafe
189 if (NDIM % 2 != 0) MADNESS_EXCEPTION("NuclearCuspyBox works only for even dimensions", 1);
190 }
191
192 NuclearCuspyBox_op(const size_t p) : particle(p) {
193 // failsafe
194 if (NDIM % 2 != 0) MADNESS_EXCEPTION("NuclearCuspyBox works only for even dimensions", 1);
195 MADNESS_ASSERT(particle == 1 or particle == 2 or particle == 0);
196 }
197
199
200 // particle==0: check both particles
201 // particle==1 or particle==2: check only particle1 or 2
203
204 template<typename Archive>
205 void serialize(Archive& ar) { ar & particle; }
206
207 std::string name() const { return "Cuspybox_op for nuclear cusps"; }
208
209 /// Operator which decides if the key belongs to a special box
210 /// The key is broken appart in two lower dimensional keys (6D -> 2x3D)
211 /// The special points should be given in a format which can also be broken appart
212 /// so: 6D special_points = (3D-special-points, 3D-special-points)
213 /// if the refinement level is already beyond half of the special_level then refinement is only enforded if the broken keys are the same (6D box contains cusp)
214 bool operator()(const Key<NDIM>& key, const FunctionImpl<T, NDIM> *const f) const {
215 if (not(key.level() < 2)) {
216 if (this->box_is_at_boundary(key)) return false;
217 }
218 MADNESS_ASSERT(particle == 1 or particle == 2 or particle == 0);
219 if (f == NULL) MADNESS_EXCEPTION("NuclearCuspyBox: Pointer to function is NULL", 1);
220 const std::vector<Vector<double, NDIM> >& special_points = f->get_special_points();
221 if (special_points.empty()) MADNESS_EXCEPTION(
222 "Demanded NuclearCuspyBox but the special points of the function are empty", 1);
223
224 // break the special points into 3D points
225 std::vector<Vector<double, NDIM / 2> > lowdim_sp;
226 for (size_t i = 0; i < special_points.size(); i++) {
227 Vector<double, NDIM / 2> lowdim_tmp;
228 for (size_t j = 0; j < NDIM / 2; j++) {
229 lowdim_tmp[j] = special_points[i][j];
230 // check if the formatting is correct
231 if (special_points[i][j] != special_points[i][NDIM / 2 + j]) MADNESS_EXCEPTION(
232 "NuclearCuspyBox: Wrong format of special_point: ", 1);
233 }
234 lowdim_sp.push_back(lowdim_tmp);
235 }
236
237 // now break the key appart and check if one if the results is in the neighbourhood of a special point
238 BoundaryConditions<NDIM / 2> bc = FunctionDefaults<NDIM / 2>::get_bc();
239 const auto bperiodic = bc.is_periodic();
240 Key<NDIM / 2> key1;
241 Key<NDIM / 2> key2;
242
243 key.break_apart(key1, key2);
244 for (size_t i = 0; i < lowdim_sp.size(); ++i) {
245 Vector<double, NDIM / 2> simpt;
246 user_to_sim(lowdim_sp[i], simpt);
247 const bool hit1 = key1.is_neighbor_of(simpt, bperiodic);
248 const bool hit2 = key2.is_neighbor_of(simpt, bperiodic);
249 if (particle == 1 and hit1) return true;
250 else if (particle == 2 and hit2) return true;
251 else if (particle == 0 and (hit1 or hit2)) return true;
252 else return false;
253 }
254 return false;
255 }
256
257
258};
259
260template<typename T, std::size_t NDIM, typename opT, typename specialboxT>
261class Leaf_op {
262public:
263 /// the function which the operators use (in most cases this function is also the function that will be constructed)
265 /// the operator which is used for screening (null pointer means no screening)
266 const opT *op;
267 /// special box structure: has an operator which decides if a given key belongs to a special box
268 /// the base class Specialbox_op<T,NDIM> just gives back false for every key
269 /// the derived class Cuspybox_op<T,NDIM> is used for potentials containing cusps at coalescence points of electrons
270 specialboxT specialbox;
271
272 /// pre or post screening (see if this is the general_leaf_op or the leaf_op_other)
273 virtual bool
275 return false;
276 }
277
279 : f(NULL), op(NULL), specialbox(specialboxT()) {
280 }
281
283 : f(tmp), op(NULL), specialbox(specialboxT()) {
284 }
285
286 Leaf_op(const FunctionImpl<T, NDIM> *const tmp, specialboxT& sb)
287 : f(tmp), op(NULL), specialbox(sb) {
288 }
289
290 Leaf_op(const FunctionImpl<T, NDIM> *const tmp, const opT *const ope, specialboxT& sb)
291 : f(tmp), op(ope), specialbox(sb) {
292 }
293
294 Leaf_op(const Leaf_op& other) : f(other.f), op(other.op), specialbox(other.specialbox) {}
295
296 virtual
298 }
299
300 virtual std::string
301 name() const {
302 return "general_leaf_op";
303 }
304
305 /// make sanity check
306 virtual void
307 sanity() const {
308 if (f == NULL) MADNESS_EXCEPTION(("Error in " + name() + " pointer to function is NULL").c_str(), 1);
309 }
310
311public:
312 /// pre-determination
313 /// the decision if the current box will be a leaf box is made from information of another function
314 /// this is needed for on demand function
315 /// not that the on-demand function that is being constructed is not the function in this class
316 virtual bool
317 pre_screening(const Key<NDIM>& key) const {
318 MADNESS_EXCEPTION("pre-screening was called for leaf_op != leaf_op_other", 1);
319 return false;
320 }
321
322 /// post-determination
323 /// determination if the box will be a leaf box after the coefficients are made
324 /// the function that is being constructed is the function in this class
325 /// the function will use the opartor op in order to screen, if op is a NULL pointer the result is always: false
326 /// @param[in] key: the key to the current box
327 /// @param[in] coeff: Coefficients of the current box
328 virtual bool
329 post_screening(const Key<NDIM>& key, const GenTensor<T>& coeff) const {
330 if (op == NULL) return false;
331 if (key.level() < this->f->get_initial_level()) return false;
332 sanity();
333 const double cnorm = coeff.normf();
334 // const auto bperiodic = bc.is_periodic();
335
336 typedef Key<opT::opdim> opkeyT;
337 const opkeyT source = op->get_source_key(key);
338
339 const double thresh = (this->f->truncate_tol(this->f->get_thresh(), key));
340 const std::vector<opkeyT>& disp = op->get_disp(key.level());
341 const opkeyT& d = *disp.begin(); // use the zero-displacement for screening
342 const double opnorm = op->norm(key.level(), d, source);
343 const double norm = opnorm * cnorm;
344
345 return norm < thresh;
346 }
347
348 /// determines if a node is well represented compared to the parents
349 /// @param[in] key the FunctionNode which we want to determine if it's a leaf node
350 /// @param[in] coeff the coeffs of key
351 /// @param[in] parent the coeffs of key's parent node
352 /// @return is the FunctionNode of key a leaf node?
353 bool
354 compare_to_parent(const Key<NDIM>& key, const GenTensor<T>& coeff, const GenTensor<T>& parent) const {
355 if (key.level() < this->f->get_initial_level()) return false;
356 //this->sanity();
357 if (parent.has_no_data()) return false;
358 if (key.level() < this->f->get_initial_level()) return false;
359 GenTensor<T> upsampled = this->f->upsample(key, parent);
360 upsampled.scale(-1.0);
361 upsampled += coeff;
362 const double dnorm = upsampled.normf();
363 const bool is_leaf = (dnorm < this->f->truncate_tol(this->f->get_thresh(), key.level()));
364 return is_leaf;
365 }
366
367 /// check if the box is a special box
368 /// first check: Is one of the special points defined in the function f in the current box or a neighbour box
369 /// second check: Is the box special according to the specialbox operator (see class description of Specialbox_op)
370 /// @param[in] the key of the box
371 bool
373 if (key.level() > f->get_special_level()) return false;
374 else if (specialbox.check_special_points(key, f)) return true;
375 else if (specialbox(key, f)) return true;
376 else return false;
377 }
378
379 template<typename Archive>
380 void
381 serialize(Archive& ar) {
382 ar & this->f & this->specialbox;
383 }
384
385};
386
387/// leaf_op for construction of an on-demand function
388/// the function in the class is the function which defines the structure of the on-demand function
389/// means: The tree of the function which is to construct will mirror the tree-structure of the function in this class (function variable defined in base-class)
390template<typename T, std::size_t NDIM>
391class Leaf_op_other : public Leaf_op<T, NDIM, SeparatedConvolution<double, NDIM>, Specialbox_op<T, NDIM> > {
392 std::string
393 name() const {
394 return "leaf_op_other";
395 }
396 /// we only need the pre-determination based on the already constructed function f
397 /// if f at box(key) is a leaf then return true
398public:
399 bool
401 return true;
402 }
403
406
408 this->f = f_;
409 }
410
412 : Leaf_op<T, NDIM, SeparatedConvolution<double, NDIM>, Specialbox_op<T, NDIM> >(other.f) {}
413
414 bool
415 pre_screening(const Key<NDIM>& key) const {
416 MADNESS_ASSERT(this->f->get_coeffs().is_local(key));
417 return (not this->f->get_coeffs().find(key).get()->second.has_children());
418 }
419
420 void sanity() const {
421 if (this->f == 0) MADNESS_EXCEPTION("Leaf_op_other: f is NULL pointer", 1);
422 if (this->op != 0) MADNESS_EXCEPTION("Leaf_op_other: Screening operator was set", 1);
423 }
424
425 /// this should never be called for this leaf_op since the function in this class as already constructed
426 bool
427 post_screening(const Key<NDIM>& key, const GenTensor<T>& G) const {
428 MADNESS_EXCEPTION("post-determination was called for leaf_op_other", 1);
429 return false;
430 }
431
432 /// this should never be called for this leaf_op since the function in this class as already constructed
433 bool
434 compare_to_parent(const Key<NDIM>& key, const GenTensor<T>& a, const GenTensor<T>& b) const {
435 MADNESS_EXCEPTION("compare-to-parent was called for leaf_op_other", 1);
436 return false;
437 }
438
439 /// this should never be called for this leaf_op since the function in this class as already constructed
440 bool
442 MADNESS_EXCEPTION("special_refinement_needed was called for leaf_op_other", 1);
443 return false;
444 }
445
446 template<typename Archive>
447 void
448 serialize(Archive& ar) {
449 ar & this->f;
450 }
451
452};
453
454} /* namespace madness */
455
456#endif /* SRC_MADNESS_MRA_LEAFOP_H_ */
Definition test_derivative.cc:24
This class is used to specify boundary conditions for all operators.
Definition bc.h:72
FunctionDefaults holds default paramaters as static class members.
Definition funcdefaults.h:100
static const BoundaryConditions< NDIM > & get_bc()
Returns the default boundary conditions.
Definition funcdefaults.h:311
FunctionImpl holds all Function state to facilitate shallow copy semantics.
Definition funcimpl.h:945
double get_thresh() const
Definition mraimpl.h:328
coeffT upsample(const keyT &key, const coeffT &coeff) const
upsample the sum coefficients of level 1 to sum coeffs on level n+1
Definition mraimpl.h:1231
double truncate_tol(double tol, const keyT &key) const
Returns the truncation threshold according to truncate_method.
Definition mraimpl.h:649
Definition lowranktensor.h:59
bool has_no_data() const
Definition gentensor.h:211
float_scalar_type normf() const
Definition lowranktensor.h:406
IsSupported< TensorTypeData< Q >, GenTensor< T > & >::type scale(Q fac)
Inplace multiplication by scalar of supported type (legacy name)
Definition lowranktensor.h:426
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_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:325
const Vector< Translation, NDIM > & translation() const
Definition key.h:174
void break_apart(Key< LDIM > &key1, Key< KDIM > &key2) const
break key into two low-dimensional keys
Definition key.h:424
Definition leafop.h:391
void serialize(Archive &ar)
Definition leafop.h:448
bool compare_to_parent(const Key< NDIM > &key, const GenTensor< T > &a, const GenTensor< T > &b) const
this should never be called for this leaf_op since the function in this class as already constructed
Definition leafop.h:434
bool post_screening(const Key< NDIM > &key, const GenTensor< T > &G) const
this should never be called for this leaf_op since the function in this class as already constructed
Definition leafop.h:427
void sanity() const
make sanity check
Definition leafop.h:420
Leaf_op_other(const FunctionImpl< T, NDIM > *const f_)
Definition leafop.h:407
Leaf_op_other(const Leaf_op_other &other)
Definition leafop.h:411
bool do_pre_screening() const
Definition leafop.h:400
Leaf_op_other()
Definition leafop.h:404
bool special_refinement_needed(const Key< NDIM > &key) const
this should never be called for this leaf_op since the function in this class as already constructed
Definition leafop.h:441
bool pre_screening(const Key< NDIM > &key) const
Definition leafop.h:415
std::string name() const
Definition leafop.h:393
Definition leafop.h:261
specialboxT specialbox
Definition leafop.h:270
virtual bool do_pre_screening() const
pre or post screening (see if this is the general_leaf_op or the leaf_op_other)
Definition leafop.h:274
virtual bool pre_screening(const Key< NDIM > &key) const
Definition leafop.h:317
bool special_refinement_needed(const Key< NDIM > &key) const
Definition leafop.h:372
virtual bool post_screening(const Key< NDIM > &key, const GenTensor< T > &coeff) const
Definition leafop.h:329
void serialize(Archive &ar)
Definition leafop.h:381
Leaf_op()
Definition leafop.h:278
const opT * op
the operator which is used for screening (null pointer means no screening)
Definition leafop.h:266
Leaf_op(const Leaf_op &other)
Definition leafop.h:294
virtual ~Leaf_op()
Definition leafop.h:297
Leaf_op(const FunctionImpl< T, NDIM > *const tmp, specialboxT &sb)
Definition leafop.h:286
bool compare_to_parent(const Key< NDIM > &key, const GenTensor< T > &coeff, const GenTensor< T > &parent) const
Definition leafop.h:354
Leaf_op(const FunctionImpl< T, NDIM > *const tmp, const opT *const ope, specialboxT &sb)
Definition leafop.h:290
const FunctionImpl< T, NDIM > * f
the function which the operators use (in most cases this function is also the function that will be c...
Definition leafop.h:264
virtual std::string name() const
Definition leafop.h:301
virtual void sanity() const
make sanity check
Definition leafop.h:307
Leaf_op(const FunctionImpl< T, NDIM > *const tmp)
Definition leafop.h:282
Convolutions in separated form (including Gaussian)
Definition operator.h:139
A simple, fixed dimension vector.
Definition vector.h:64
char * p(char *buf, const char *name, int k, int initial_level, double thresh, int order)
Definition derivatives.cc:72
auto T(World &world, response_space &f) -> response_space
Definition global_functions.cc:28
static double pow(const double *a, const double *b)
Definition lda.h:74
#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
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:10
@ BC_PERIODIC
Definition bc.h:52
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:455
NDIM & f
Definition mra.h:2543
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 thresh
Definition rk.cc:45
Definition test_dc.cc:47
Definition leafop.h:133
~ElectronCuspyBox_op()
Definition leafop.h:137
std::string name() const
Definition leafop.h:142
bool operator()(const Key< NDIM > &key, const FunctionImpl< T, NDIM > *const f) const
Definition leafop.h:148
void serialize(Archive &ar)
Definition leafop.h:140
ElectronCuspyBox_op()
Definition leafop.h:135
Definition leafop.h:185
std::string name() const
Definition leafop.h:207
int particle
Definition leafop.h:202
bool operator()(const Key< NDIM > &key, const FunctionImpl< T, NDIM > *const f) const
Definition leafop.h:214
NuclearCuspyBox_op()
Definition leafop.h:187
~NuclearCuspyBox_op()
Definition leafop.h:198
NuclearCuspyBox_op(const size_t p)
Definition leafop.h:192
void serialize(Archive &ar)
Definition leafop.h:205
Definition leafop.h:62
Specialbox_op()
Definition leafop.h:64
size_t get_half_of_special_level(const size_t &sl=FunctionDefaults< NDIM >::get_special_level()) const
Definition leafop.h:120
virtual bool box_is_at_boundary(const Key< NDIM > &key) const
Definition leafop.h:106
virtual ~Specialbox_op()
Definition leafop.h:66
bool check_special_points(const Key< NDIM > &key, const FunctionImpl< T, NDIM > *const f) const
Definition leafop.h:80
void serialize(Archive &ar)
Definition leafop.h:100
virtual std::string name() const
Definition leafop.h:68
virtual bool operator()(const Key< NDIM > &key, const FunctionImpl< T, NDIM > *const f=NULL) const
Definition leafop.h:74
Definition lowrankfunction.h:336
double norm(const T i1)
Definition test_cloud.cc:85
constexpr std::size_t NDIM
Definition testgconv.cc:54
double source(const coordT &r)
Definition testperiodic.cc:48