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/// To limit the range of kernel K(x-y) it is multiplied (in user coordinates) by a restrictor function
17/// \f$ r(N/2 - |x-y|) \f$, where \f$ r(x) \f$ is identity for unrestricted kernel or one of the choices
18/// encoded by KernelRange::Type
20public:
21
22 /// types of range restrictor functions
23 enum Type {
24 /// Heavyside (step) function: \f$ r(x) \equiv \theta(x)\f$
26 /// erf approximation to Heavyside function: \f$ r(x) \equiv \theta_\sigma(x) \equiv (1 + \erf(x/\sigma))/2 \f$;
27 /// in the limit $\sigma\to 0$ this becomes the Heaviside function.
29 };
30
31 /// restrictor function
32 struct Restrictor {
33 Restrictor() = default;
37 if (sigma == 0)
39 else {
41 this->sigma_w_inverse_ = {sigma, 1./sigma};
42 }
43 }
44
45 Type type() const { return type_; }
46 double sigma() const {
48 return sigma_w_inverse_->first;
49 }
50 double sigma_inverse() const {
52 return sigma_w_inverse_->second;
53 }
54
55 /// @return value of restrictor function r(x) at x
56 double value(double x) const {
57 auto f = [](double x, double ooσ) {
58 return (1 + std::erf(x * ooσ)) * 0.5;
59 };
60
61 switch (type_) {
62 case Hard:
63 // use regularized step function to ensure that value at x=0 is 1/2
64 return f(x, 1e8);
65 case SoftErf:
66 return f(x, this->sigma_inverse());
67 default:
68 MADNESS_EXCEPTION("KernelRange: unknown restrictor type",1);
69 }
70 }
71
72 /// @return true if \p r1 and \p r2 are equal
73 friend bool operator==(const Restrictor& r1, const Restrictor& r2) {
74 return r1.type_ == r2.type_ && (r1.type_ == KernelRange::Type::Hard ||
76 r1.sigma() == r2.sigma()));
77 }
78
79 hashT hash() const {
80 hashT result = hash_value((int)type_);
81 if (sigma())
82 hash_combine(result, sigma());
83 return result;
84 }
85
86 private:
88 std::optional<std::pair<double,double>> sigma_w_inverse_;
89 };
90
91 /// constructs a null (i.e., infinite) kernel range
92 /// @post `this->infinite()==true`
93 KernelRange() = default;
94 /// constructs a finite soft (`sigma > 0`) or hard (`sigma==0`) kernel range
95 /// @param sigma regularization parameter (lengthscale in simulation [0,1] coordinate units) controls the softness of the range restrictor
96 /// @pre `sigma>=0`
97 /// @post `this->soft()==true`
98 KernelRange(unsigned int N, double sigma) {
100 if (sigma == 0)
101 data.emplace(N, Restrictor{Hard});
102 else
103 data.emplace(N, Restrictor{SoftErf, sigma});
104 }
105 /// constructs a finite (hard) kernel range
106 /// @post `this->hard()==true`
107 KernelRange(unsigned int N) { data.emplace(N, Restrictor{}); }
108
109 unsigned int N() const { return data.value().N; }
110 Type type() const { return restrictor().type(); }
111 double sigma() const { return restrictor().sigma(); }
112
113 /// @return true if range is limited
114 bool finite() const { return data.has_value(); }
115 /// @return true if range is limited using a hard window function (Heaviside)
116 bool finite_hard() const { return finite() && type() == Hard; }
117 /// @return true if range is limited using a soft window function (sigmoid)
118 bool finite_soft() const { return finite() && type() != Hard; }
119 /// @return true if range is unlimited
120 bool infinite() const { return !finite(); }
121
122 /// @return true if range is limited
123 explicit operator bool() const { return finite(); }
124
125 /// @return true if \p r1 and \p r2 are equal
126 friend bool operator==(const KernelRange& r1, const KernelRange& r2) {
127 if (r1.finite() != r2.finite())
128 return false;
129 if (r1.finite())
130 return r1.N() == r2.N() && r1.restrictor() == r2.restrictor();
131 return true;
132 }
133
134 /// @return value of restrictor function at N/2 - abs(r)
135 double value(double r) const {
136 if (infinite())
137 return 1.;
138 else {
139 auto x = N() * 0.5 - std::abs(r);
140 return restrictor().value(x);
141 }
142 }
143
144 hashT hash() const {
145 hashT result = 0;
146 if (!infinite()) {
147 result = hash_value(N());
148 hash_combine(result, restrictor());
149 }
150 return result;
151 }
152
153 static constexpr double extent_default_epsilon = std::numeric_limits<double>::epsilon();
154
155 /// @return max value of `|x-y|` (rounded up, in units of 1/2)
156 /// for which `r(N/2 - |x-y|)` is greater than @p epsilon
159 if (infinite())
160 return std::numeric_limits<int>::max();
161 else {
162 return data.value().iextent_x2(epsilon);
163 }
164 }
165
166private:
167
168 struct Data {
169 unsigned int N;
171 int iextent_x2_default; // memoized extent(int_extent_default_epsilon)
172
174
175 /// @return max value of `|x-y|` (rounded up, in units of 1/2)
176 /// for which `r(N/2 - |x-y|)` is greater than @p epsilon
177 int iextent_x2(double epsilon) const {
179 return iextent_x2_default;
180 else
182 }
183
184 /// @return max value of `|x-y|` (rounded up, in units of 1/2)
185 /// for which `r(N/2 - |x-y|)` is greater than @p epsilon
186 static int compute_iextent_x2(int N, const Restrictor& restrictor, double epsilon) {
188 switch (restrictor.type()) {
189 case Hard:
190 return N;
191 case SoftErf: {
192 constexpr bool use_newton_solver = false;
193 if (use_newton_solver) {
194 auto f01 = [&, ooσ = 1. / restrictor.sigma(),
195 oosqrtpiσ =
196 1. / (sqrt(M_PI) * restrictor.sigma())](double x) {
197 const auto arg = (0.5 * N - x) * ooσ;
198 const auto fx = (1 + std::erf(arg)) * 0.5;
199 const auto dfx = -std::exp(-arg * arg) * oosqrtpiσ;
200 return std::make_pair(fx, dfx);
201 };
202 auto iter = 0;
203 const auto max_iter = 50;
204 auto x = 0.5;
205 auto dx = 1.;
206 double fx = 1.;
207 // step-restricted newton iteration
208 while ((std::abs(dx) > 0.01 || std::abs(fx) > epsilon) &&
209 iter < max_iter) {
210 double dfx;
211 std::tie(fx, dfx) = f01(x);
212 dx = -(fx - epsilon) / dfx;
213 auto restricted_step = [](const double step,
214 const double maxabs_step) {
215 auto sign = [](const auto x) { return x >= 0 ? 1. : -1.; };
216 return std::abs(step) > maxabs_step ? sign(step) * maxabs_step
217 : step;
218 };
219 x += restricted_step(dx, 0.2);
220 ++iter;
221 }
222 return static_cast<int>(ceil(x * 2.));
223 } else {
224 // keep increasing x until f(x) falls below epsilon
225 int x = N;
226 auto value = [&](const double r) {
227 auto x = N * 0.5 - std::abs(r);
228 return restrictor.value(x);
229 };
230 double fx = value(x * 0.5);
231 while (fx >= epsilon) {
232 ++x;
233 fx = value(x * 0.5);
234 }
235 return x;
236 }
237 }
238 default:
239 MADNESS_EXCEPTION("KernelRange:: unknown restrictor type",1);
240 }
241 }
242
243 }; // Data
244
245 std::optional<Data> data;
246 const Restrictor &restrictor() const { return data.value().restrictor; }
247};
248
249} // madness
250
251#endif // MADNESS_MRA_KERNELRANGE_H__INCLUDED
Definition kernelrange.h:19
const Restrictor & restrictor() const
Definition kernelrange.h:246
bool finite_soft() const
Definition kernelrange.h:118
Type type() const
Definition kernelrange.h:110
static constexpr double extent_default_epsilon
Definition kernelrange.h:153
double sigma() const
Definition kernelrange.h:111
friend bool operator==(const KernelRange &r1, const KernelRange &r2)
Definition kernelrange.h:126
int iextent_x2(double epsilon=extent_default_epsilon) const
Definition kernelrange.h:157
hashT hash() const
Definition kernelrange.h:144
bool infinite() const
Definition kernelrange.h:120
bool finite() const
Definition kernelrange.h:114
KernelRange(unsigned int N)
Definition kernelrange.h:107
unsigned int N() const
Definition kernelrange.h:109
Type
types of range restrictor functions
Definition kernelrange.h:23
@ Hard
Heavyside (step) function: .
Definition kernelrange.h:25
@ SoftErf
Definition kernelrange.h:28
double value(double r) const
Definition kernelrange.h:135
KernelRange(unsigned int N, double sigma)
Definition kernelrange.h:98
std::optional< Data > data
Definition kernelrange.h:245
bool finite_hard() const
Definition kernelrange.h:116
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:2502
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
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:2451
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:168
Restrictor restrictor
Definition kernelrange.h:170
static int compute_iextent_x2(int N, const Restrictor &restrictor, double epsilon)
Definition kernelrange.h:186
int iextent_x2(double epsilon) const
Definition kernelrange.h:177
unsigned int N
Definition kernelrange.h:169
Data(unsigned int n, Restrictor r)
Definition kernelrange.h:173
int iextent_x2_default
Definition kernelrange.h:171
restrictor function
Definition kernelrange.h:32
Restrictor(Type type)
Definition kernelrange.h:34
double sigma_inverse() const
Definition kernelrange.h:50
double sigma() const
Definition kernelrange.h:46
std::optional< std::pair< double, double > > sigma_w_inverse_
Definition kernelrange.h:88
double value(double x) const
Definition kernelrange.h:56
hashT hash() const
Definition kernelrange.h:79
Type type_
Definition kernelrange.h:87
friend bool operator==(const Restrictor &r1, const Restrictor &r2)
Definition kernelrange.h:73
Restrictor(Type type, double sigma)
Definition kernelrange.h:35
Type type() const
Definition kernelrange.h:45
Defines hash functions for use in distributed containers.