Skip to content

Commit 83795c3

Browse files
committed
stratmann revised
1 parent 3f8d425 commit 83795c3

File tree

3 files changed

+168
-97
lines changed

3 files changed

+168
-97
lines changed

source/module_base/grid/partition.cpp

Lines changed: 113 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,41 @@
22
#include "module_base/constants.h"
33

44
#include <cmath>
5+
#include <functional>
56
#include <numeric>
6-
#include <vector>
7+
#include <algorithm>
78

89
namespace Grid {
910
namespace Partition {
1011

1112
const double stratmann_a = 0.64;
1213
const double stratmann_mod_b = 0.8;
1314

15+
1416
double w_becke(
1517
int nR0,
16-
double* drR,
17-
double* dRR,
18+
const double* drR,
19+
const double* dRR,
1820
int nR,
19-
int* iR,
21+
const int* iR,
2022
int c
2123
) {
22-
std::vector<double> P(nR, 1.0);
24+
double P[nR];
25+
std::fill(P, P + nR, 1.0);
2326
for (int i = 0; i < nR; ++i) {
2427
int I = iR[i];
2528
for (int j = i + 1; j < nR; ++j) {
2629
int J = iR[j];
2730
double mu = (drR[I] - drR[J]) / dRR[I*nR0 + J];
2831
double s = s_becke(mu);
2932
P[I] *= s;
30-
P[J] *= (1.0 - s); // s_becke(-mu) = 1 - s_becke(mu)
33+
P[J] *= (1.0 - s); // s(-mu) = 1 - s(mu)
3134
}
3235
}
33-
return P[c] / std::accumulate(P.begin(), P.end(), 0.0);
36+
return P[c] / std::accumulate(P, P + nR, 0.0);
3437
}
3538

39+
3640
double s_becke(double mu) {
3741
/*
3842
* Becke's iterated polynomials (3rd order)
@@ -51,59 +55,63 @@ double s_becke(double mu) {
5155

5256
double w_stratmann(
5357
int nR0,
54-
double* drR,
55-
double* dRR,
56-
double* drR_thr,
57-
int nR,
58+
const double* drR,
59+
const double* dRR,
60+
const double* drR_thr,
61+
const int nR,
5862
int* iR,
5963
int c
6064
) {
65+
int I = iR[c], J = 0;
6166

62-
// if r falls within the exclusive zone of the center
63-
// whom this grid point belongs to
64-
int I = iR[c];
65-
if (drR[I] <= drR_thr[I]) {
66-
return 1.0;
67-
}
68-
69-
// if r falls within the exclusive zone of a center
70-
// other than the one whom this grid point belongs to
71-
for (int J = 0; J < nR; ++J) {
72-
// no need to exclude J == c because it was checked before
73-
if (drR[iR[J]] <= drR_thr[iR[J]]) {
74-
return 0.0;
67+
// If r falls within the exclusive zone of a center, return immediately.
68+
for (int j = 0; j < nR; ++j) {
69+
J = iR[j];
70+
if (drR[J] <= drR_thr[J]) {
71+
return static_cast<double>(I == J);
7572
}
7673
}
7774

78-
double Pc = 1.0;
79-
for (int i = 0; i < c; ++i) {
80-
int J = iR[i];
81-
double mu = (drR[I] - drR[J]) / dRR[I*nR0 + J];
82-
Pc *= s_stratmann(mu);
83-
}
84-
for (int i = c + 1; i < nR; ++i) {
85-
int J = iR[i];
75+
// Even if the grid point does not fall within the exclusive zone of any
76+
// center, the normalized weight could still be 0 or 1, and this can be
77+
// figured out by examining the unnormalized weight alone.
78+
79+
// Move the center to the first position for convenience. Swap back later.
80+
std::swap(iR[0], iR[c]);
81+
82+
double P[nR];
83+
for (int j = 1; j < nR; ++j) {
84+
J = iR[j];
8685
double mu = (drR[I] - drR[J]) / dRR[I*nR0 + J];
87-
Pc *= s_stratmann(mu);
86+
P[j] = s_stratmann(mu);
8887
}
89-
if (Pc == 0.0 || Pc == 1.0) {
90-
return Pc;
88+
P[0] = std::accumulate(P + 1, P + nR, 1.0, std::multiplies<double>());
89+
90+
if (P[0] == 0.0 || P[0] == 1.0) {
91+
std::swap(iR[0], iR[c]);
92+
return P[0];
9193
}
9294

93-
std::vector<double> P(nR, 1.0);
94-
for (int i = 0; i < nR; ++i) {
95-
int I = iR[i];
95+
// If it passes all the screening, all unnormalized weights have to be
96+
// calculated in order to get the normalized weight.
97+
98+
std::for_each(P + 1, P + nR, [](double& s) { s = 1.0 - s; });
99+
for (int i = 1; i < nR; ++i) {
100+
I = iR[i];
96101
for (int j = i + 1; j < nR; ++j) {
97-
int J = iR[j];
102+
J = iR[j];
98103
double mu = (drR[I] - drR[J]) / dRR[I*nR0 + J];
99104
double s = s_stratmann(mu);
100-
P[I] *= s;
101-
P[J] *= (1.0 - s); // s(-mu) = 1 - s(mu)
105+
P[i] *= s;
106+
P[j] *= (1.0 - s); // s(-mu) = 1 - s(mu)
102107
}
103108
}
104-
return P[c] / std::accumulate(P.begin(), P.end(), 0.0);
109+
110+
std::swap(iR[0], iR[c]);
111+
return P[0] / std::accumulate(P, P + nR, 0.0);
105112
}
106113

114+
107115
double s_stratmann(double mu) {
108116
/*
109117
* Stratmann's piecewise cell function
@@ -127,57 +135,76 @@ double s_stratmann(double mu) {
127135
}
128136

129137

130-
double u_stratmann_mod(double y) {
131-
using ModuleBase::PI;
132-
bool core = y <= stratmann_mod_b;
133-
bool edge = !core && y < 1.0;
134-
return core + edge * 0.5 * (1.0 +
135-
std::cos(PI * (y - stratmann_mod_b) / (1.0 - stratmann_mod_b)));
138+
double w_stratmann_mod(
139+
int nR0,
140+
const double* drR,
141+
const double* dRR,
142+
const double* drR_thr,
143+
const double* Rcut,
144+
int nR,
145+
int* iR,
146+
int c
147+
) {
148+
int I = iR[c], J = 0;
149+
150+
// If r falls within the exclusive zone of a center, return immediately.
151+
for (int j = 0; j < nR; ++j) {
152+
J = iR[j];
153+
if (drR[J] <= drR_thr[J]) {
154+
return static_cast<double>(I == J);
155+
}
156+
}
157+
158+
// Even if the grid point does not fall within the exclusive zone of any
159+
// center, the normalized weight could still be 0 or 1, and this can be
160+
// figured out by examining the unnormalized weight alone.
161+
162+
// Move the center to the first position for convenience. Swap back later.
163+
std::swap(iR[0], iR[c]);
164+
165+
double P[nR];
166+
for (int j = 1; j < nR; ++j) {
167+
J = iR[j];
168+
double mu = (drR[I] - drR[J]) / dRR[I*nR0 + J];
169+
P[j] = s_stratmann(mu);
170+
}
171+
P[0] = std::accumulate(P + 1, P + nR, 1.0, std::multiplies<double>());
172+
173+
if (P[0] == 0.0 || P[0] == 1.0) {
174+
std::swap(iR[0], iR[c]);
175+
return P[0];
176+
}
177+
178+
// If it passes all the screening, all unnormalized weights have to be
179+
// calculated in order to get the normalized weight.
180+
181+
std::for_each(P + 1, P + nR, [](double& s) { s = 1.0 - s; });
182+
for (int i = 1; i < nR; ++i) {
183+
I = iR[i];
184+
for (int j = i + 1; j < nR; ++j) {
185+
J = iR[j];
186+
double mu = (drR[I] - drR[J]) / dRR[I*nR0 + J];
187+
double s = s_stratmann(mu);
188+
P[i] *= s;
189+
P[j] *= (1.0 - s); // s(-mu) = 1 - s(mu)
190+
}
191+
}
192+
193+
std::swap(iR[0], iR[c]);
194+
return P[0] / std::accumulate(P, P + nR, 0.0);
136195
}
137196

138197

139198
double s_stratmann_mod(double mu, double y) {
140-
// Modified Stratmann's cell function by Knuth et al.
141-
// y = |r-R(J)| / Rcut(J)
142-
return 1.0 + u_stratmann_mod(y) * (s_stratmann(mu) - 1.0);
199+
using ModuleBase::PI;
200+
bool core = y <= stratmann_mod_b;
201+
bool edge = !core && y < 1.0;
202+
double u = core + edge * 0.5 * (1.0 +
203+
std::cos(PI * (y - stratmann_mod_b) / (1.0 - stratmann_mod_b)));
204+
return 1.0 + u * (s_stratmann(mu) - 1.0);
143205
}
144206

145207

146-
//double weight(
147-
// int nRtot,
148-
// double* drR,
149-
// double* dRR,
150-
// int nR,
151-
// int* iR,
152-
// int c,
153-
// CellFuncType type,
154-
// double* Rcut
155-
//) {
156-
// // unnormalized weight
157-
// std::vector<double> P(nR, 1.0);
158-
//
159-
// // confocal ellipsoidal coordinates
160-
// std::vector<double> mu(nR*nR, 0.0);
161-
// for (int i = 0; i < nR; ++i) {
162-
// int I = iR[i];
163-
// for (int j = i + 1; j < nR; ++j) {
164-
// int J = iR[j];
165-
// mu[I*nR + J] = (drR[I] - drR[J]) / dRR[I*nRtot + J];
166-
// mu[J*nR + I] = -mu[I*nR + J];
167-
// }
168-
// }
169-
//
170-
// for (int i = 0; i < nR; ++i) {
171-
// if (i == c) {
172-
// continue;
173-
// }
174-
// int J = iR[i];
175-
// double mu = (drR[I] - drR[J]) / dRR[I*nRtot + J];
176-
// P[i] *= s_becke(mu);
177-
// }
178-
//
179-
// return P[c] / std::accumulate(P.begin(), P.end(), 0.0);
180-
//}
181208

182209
} // end of namespace Partition
183210
} // end of namespace Grid

source/module_base/grid/partition.h

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ extern const double stratmann_mod_b;
3939
*/
4040
double w_becke(
4141
int nR0,
42-
double* drR,
43-
double* dRR,
42+
const double* drR,
43+
const double* dRR,
4444
int nR,
45-
int* iR,
45+
const int* iR,
4646
int c
4747
);
4848

@@ -69,9 +69,9 @@ double s_becke(double mu);
6969
*/
7070
double w_stratmann(
7171
int nR0,
72-
double* drR,
73-
double* dRR,
74-
double* drR_thr,
72+
const double* drR,
73+
const double* dRR,
74+
const double* drR_thr,
7575
int nR,
7676
int* iR,
7777
int c
@@ -82,13 +82,28 @@ double s_stratmann(double mu);
8282

8383

8484
/**
85+
* @brief Becke's partition weight with a modified Stratmann's scheme
86+
* by Knuth et al.
87+
*
88+
* Reference:
8589
* Knuth, F., Carbogno, C., Atalla, V., Blum, V., & Scheffler, M. (2015).
8690
* All-electron formalism for total energy strain derivatives and stress
8791
* tensor components for numeric atom-centered orbitals.
8892
* Computer Physics Communications, 190, 33-50.
93+
*
8994
*/
90-
double s_stratmann_mod(double mu, double y);
91-
double u_stratmann_mod(double y); // used by s_stratmann_mod
95+
double w_stratmann_mod(
96+
int nR0,
97+
const double* drR,
98+
const double* dRR,
99+
const double* drR_thr,
100+
const double* Rcut,
101+
int nR,
102+
int* iR,
103+
int c
104+
);
105+
106+
double s_stratmann_mod(double mu, double y); // y = || r - R[J] || / Rcut[J]
92107

93108

94109
} // end of namespace Partition

0 commit comments

Comments
 (0)