MADNESS 0.10.1
kernelrange.h
Go to the documentation of this file.
1//
2// Created by Eduard Valeyev on 1/3/25.
3//
4
5#ifndef MADNESS_MRA_KERNELRANGE_H__INCLUDED
6#define MADNESS_MRA_KERNELRANGE_H__INCLUDED
7
10
11#include <cmath>
12#include <optional>
13
14namespace madness {
15
16/// Denotes lattice summation over range [-N, N]; N=0 is equivalent to including the simulation cell only
18 /// lattice sum over [-N, N]; total # of cells = 2N + 1
19 int N = 0;
20public:
21 /// constructs [0,0]
22 LatticeRange() = default;
23 /// constructs [-n,n]
24 explicit LatticeRange(int n) {
25 set_range(n);
26 }
27 /// @param lattice_sum if true, constructs [-∞,∞], else constructs [0,0]
28 explicit LatticeRange(bool lattice_sum) {
30 }
31
32 /// @param n the lattice summation range in each direction
33 /// @return reference to this
35 MADNESS_ASSERT(n >= 0);
36 this->N = n;
37 return *this;
38 }
39
40 /// @return the lattice summation range in each direction
41 [[nodiscard]] int get_range() const { return N; }
42
43 /// sets this to [-∞,∞]
44 /// @return reference to this
46 N = std::numeric_limits<int>::max();
47 return *this;
48 }
49
50 /// @return true if this is [-∞,∞]
51 [[nodiscard]] bool infinite() const {return N == std::numeric_limits<int>::max();}
52
53 /// @return true if N > 0
54 explicit operator bool() const { return static_cast<bool>(N); }
55};
56
57/// To limit the range of kernel K(x-y) it is multiplied (in user coordinates) by a restrictor function
58/// \f$ r(N/2 - |x-y|) \f$, where \f$ r(x) \f$ is identity for unrestricted kernel or one of the choices
59/// encoded by KernelRange::Type
61public:
62
63 /// types of range restrictor functions
64 enum Type {
65 /// Heavyside (step) function: \f$ r(x) \equiv \theta(x)\f$
67 /// erf approximation to Heavyside function: \f$ r(x) \equiv \theta_\sigma(x) \equiv (1 + \erf(x/\sigma))/2 \f$;
68 /// in the limit $\sigma\to 0$ this becomes the Heaviside function.
70 };
71
72 /// restrictor function
73 struct Restrictor {
74 //Restrictor() = default;
75 //Restrictor(Type type) : type_(type) { MADNESS_ASSERT(type == Hard); }
76 Restrictor(Type type = Hard, double sigma=1.0) : type_(type) { // Avoid uninitialized warning on sigma if type is Hard
78 // if (sigma == 0)
79 // MADNESS_ASSERT(type == Hard);
80 // else {
81 // MADNESS_ASSERT(type != Hard);
82 this->sigma_w_inverse_ = {sigma, 1./sigma};
83 // }
84 }
85
86 Type type() const { return type_; }
87 double sigma() const {
89 return sigma_w_inverse_->first;
90 }
91 double sigma_inverse() const {
93 return sigma_w_inverse_->second;
94 }
95
96 /// @return value of restrictor function r(x) at x
97 double value(double x) const {
98 auto f = [](double x, double ooσ) {
99 return (1 + std::erf(x * ooσ)) * 0.5;
100 };
101
102 switch (type_) {
103 case Hard:
104 // use regularized step function to ensure that value at x=0 is 1/2
105 return f(x, 1e8);
106 case SoftErf:
107 return f(x, this->sigma_inverse());
108 default:
109 MADNESS_EXCEPTION("KernelRange: unknown restrictor type",1);
110 }
111 }
112
113 /// @return true if \p r1 and \p r2 are equal
114 friend bool operator==(const Restrictor& r1, const Restrictor& r2) {
115 return r1.type_ == r2.type_ && (r1.type_ == KernelRange::Type::Hard ||
117 r1.sigma() == r2.sigma()));
118 }
119
120 hashT hash() const {
121 hashT result = hash_value((int)type_);
122 if (sigma())
123 hash_combine(result, sigma());
124 return result;
125 }
126
127 private:
129 std::optional<std::pair<double,double>> sigma_w_inverse_;
130 };
131
132 /// constructs a null (i.e., infinite) kernel range
133 /// @post `this->infinite()==true`
134 KernelRange() = default;
135 /// constructs a finite soft (`sigma > 0`) or hard (`sigma==0`) kernel range
136 /// @param sigma regularization parameter (lengthscale in simulation [0,1] coordinate units) controls the softness of the range restrictor
137 /// @pre `sigma>=0`
138 /// @post `this->soft()==true`
139 KernelRange(unsigned int N, double sigma) {
140 MADNESS_ASSERT(sigma >= 0);
141 if (sigma == 0)
142 data.emplace(N, Restrictor{Hard});
143 else
144 data.emplace(N, Restrictor{SoftErf, sigma});
145 }
146 /// constructs a finite (hard) kernel range
147 /// @post `this->hard()==true`
148 KernelRange(unsigned int N) { data.emplace(N, Restrictor{}); }
149
150 unsigned int N() const { return data.value().N; }
151 Type type() const { return restrictor().type(); }
152 double sigma() const { return restrictor().sigma(); }
153
154 /// @return true if range is limited
155 bool finite() const { return data.has_value(); }
156 /// @return true if range is limited using a hard window function (Heaviside)
157 bool finite_hard() const { return finite() && type() == Hard; }
158 /// @return true if range is limited using a soft window function (sigmoid)
159 bool finite_soft() const { return finite() && type() != Hard; }
160 /// @return true if range is unlimited
161 bool infinite() const { return !finite(); }
162
163 /// @return true if range is limited
164 explicit operator bool() const { return finite(); }
165
166 /// @return true if \p r1 and \p r2 are equal
167 friend bool operator==(const KernelRange& r1, const KernelRange& r2) {
168 if (r1.finite() != r2.finite())
169 return false;
170 if (r1.finite())
171 return r1.N() == r2.N() && r1.restrictor() == r2.restrictor();
172 return true;
173 }
174
175 /// @return value of restrictor function at N/2 - abs(r)
176 double value(double r) const {
177 if (infinite())
178 return 1.;
179 else {
180 auto x = N() * 0.5 - std::abs(r);
181 return restrictor().value(x);
182 }
183 }
184
185 hashT hash() const {
186 hashT result = 0;
187 if (!infinite()) {
188 result = hash_value(N());
189 hash_combine(result, restrictor());
190 }
191 return result;
192 }
193
194 static constexpr double extent_default_epsilon = std::numeric_limits<double>::epsilon();
195
196 /// @return max value of `|x-y|` (rounded up, in units of 1/2)
197 /// for which `r(N/2 - |x-y|)` is greater than @p epsilon
200 if (infinite())
201 return std::numeric_limits<int>::max();
202 else {
203 return data.value().iextent_x2(epsilon);
204 }
205 }
206
207private:
208
209 struct Data {
210 unsigned int N;
212 int iextent_x2_default; // memoized extent(int_extent_default_epsilon)
213
215
216 /// @return max value of `|x-y|` (rounded up, in units of 1/2)
217 /// for which `r(N/2 - |x-y|)` is greater than @p epsilon
218 int iextent_x2(double epsilon) const {
220 return iextent_x2_default;
221 else
223 }
224
225 /// @return max value of `|x-y|` (rounded up, in units of 1/2)
226 /// for which `r(N/2 - |x-y|)` is greater than @p epsilon
227 static int compute_iextent_x2(int N, const Restrictor& restrictor, double epsilon) {
229 switch (restrictor.type()) {
230 case Hard:
231 return N;
232 case SoftErf: {
233 constexpr bool use_newton_solver = false;
234 if (use_newton_solver) {
235 auto f01 = [&, ooσ = 1. / restrictor.sigma(),
236 oosqrtpiσ =
237 1. / (sqrt(M_PI) * restrictor.sigma())](double x) {
238 const auto arg = (0.5 * N - x) * ooσ;
239 const auto fx = (1 + std::erf(arg)) * 0.5;
240 const auto dfx = -std::exp(-arg * arg) * oosqrtpiσ;
241 return std::make_pair(fx, dfx);
242 };
243 auto iter = 0;
244 const auto max_iter = 50;
245 auto x = 0.5;
246 auto dx = 1.;
247 double fx = 1.;
248 // step-restricted newton iteration
249 while ((std::abs(dx) > 0.01 || std::abs(fx) > epsilon) &&
250 iter < max_iter) {
251 double dfx;
252 std::tie(fx, dfx) = f01(x);
253 dx = -(fx - epsilon) / dfx;
254 auto restricted_step = [](const double step,
255 const double maxabs_step) {
256 auto sign = [](const auto x) { return x >= 0 ? 1. : -1.; };
257 return std::abs(step) > maxabs_step ? sign(step) * maxabs_step
258 : step;
259 };
260 x += restricted_step(dx, 0.2);
261 ++iter;
262 }
263 return static_cast<int>(ceil(x * 2.));
264 } else {
265 // keep increasing x until f(x) falls below epsilon
266 int x = N;
267 auto value = [&](const double r) {
268 auto x = N * 0.5 - std::abs(r);
269 return restrictor.value(x);
270 };
271 double fx = value(x * 0.5);
272 while (fx >= epsilon) {
273 ++x;
274 fx = value(x * 0.5);
275 }
276 return x;
277 }
278 }
279 default:
280 MADNESS_EXCEPTION("KernelRange:: unknown restrictor type",1);
281 }
282 }
283
284 }; // Data
285
286 std::optional<Data> data;
287 const Restrictor &restrictor() const { return data.value().restrictor; }
288};
289
290} // madness
291
292#endif // MADNESS_MRA_KERNELRANGE_H__INCLUDED
Definition kernelrange.h:60
const Restrictor & restrictor() const
Definition kernelrange.h:287
bool finite_soft() const
Definition kernelrange.h:159
Type type() const
Definition kernelrange.h:151
static constexpr double extent_default_epsilon
Definition kernelrange.h:194
double sigma() const
Definition kernelrange.h:152
friend bool operator==(const KernelRange &r1, const KernelRange &r2)
Definition kernelrange.h:167
int iextent_x2(double epsilon=extent_default_epsilon) const
Definition kernelrange.h:198
hashT hash() const
Definition kernelrange.h:185
bool infinite() const
Definition kernelrange.h:161
bool finite() const
Definition kernelrange.h:155
KernelRange(unsigned int N)
Definition kernelrange.h:148
unsigned int N() const
Definition kernelrange.h:150
Type
types of range restrictor functions
Definition kernelrange.h:64
@ Hard
Heavyside (step) function: .
Definition kernelrange.h:66
@ SoftErf
Definition kernelrange.h:69
double value(double r) const
Definition kernelrange.h:176
KernelRange(unsigned int N, double sigma)
Definition kernelrange.h:139
std::optional< Data > data
Definition kernelrange.h:286
bool finite_hard() const
Definition kernelrange.h:157
Denotes lattice summation over range [-N, N]; N=0 is equivalent to including the simulation cell only...
Definition kernelrange.h:17
LatticeRange()=default
constructs [0,0]
LatticeRange(int n)
constructs [-n,n]
Definition kernelrange.h:24
LatticeRange & set_range(int n)
Definition kernelrange.h:34
LatticeRange(bool lattice_sum)
Definition kernelrange.h:28
bool infinite() const
Definition kernelrange.h:51
int N
lattice sum over [-N, N]; total # of cells = 2N + 1
Definition kernelrange.h:19
int get_range() const
Definition kernelrange.h:41
LatticeRange & set_infinite()
Definition kernelrange.h:45
static double epsilon
Definition dirac-hatom.cc:20
Tensor< typename Tensor< T >::scalar_type > arg(const Tensor< T > &t)
Return a new tensor holding the argument of each element of t (complex types only)
Definition tensor.h:2518
Defines madness::MadnessException for exception handling.
#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
array_of_bools< NDIM > lattice_sum()
Definition bc.h:248
static double r2(const coord_3d &x)
Definition smooth.h:45
void hash_combine(hashT &seed, const T &v)
Combine hash values.
Definition worldhash.h:260
NDIM & f
Definition mra.h:2528
std::size_t hashT
The hash value type.
Definition worldhash.h:145
madness::hashT hash_value(const std::array< T, N > &a)
Hash std::array with madness hash.
Definition array_addons.h:78
static long abs(long a)
Definition tensor.h:218
Definition test_ccpairfunction.cc:22
Definition kernelrange.h:209
Restrictor restrictor
Definition kernelrange.h:211
static int compute_iextent_x2(int N, const Restrictor &restrictor, double epsilon)
Definition kernelrange.h:227
int iextent_x2(double epsilon) const
Definition kernelrange.h:218
unsigned int N
Definition kernelrange.h:210
Data(unsigned int n, Restrictor r)
Definition kernelrange.h:214
int iextent_x2_default
Definition kernelrange.h:212
restrictor function
Definition kernelrange.h:73
Restrictor(Type type=Hard, double sigma=1.0)
Definition kernelrange.h:76
double sigma_inverse() const
Definition kernelrange.h:91
double sigma() const
Definition kernelrange.h:87
std::optional< std::pair< double, double > > sigma_w_inverse_
Definition kernelrange.h:129
double value(double x) const
Definition kernelrange.h:97
hashT hash() const
Definition kernelrange.h:120
Type type_
Definition kernelrange.h:128
friend bool operator==(const Restrictor &r1, const Restrictor &r2)
Definition kernelrange.h:114
Type type() const
Definition kernelrange.h:86
Defines hash functions for use in distributed containers.