Skip to content

Commit 4ac1052

Browse files
authored
Merge pull request brucefan1983#1386 from tang070205/20260306-cohesive
Expandability Calculation Cohesive Energy and Elastic Constants
2 parents 0337554 + c5364c5 commit 4ac1052

File tree

4 files changed

+205
-76
lines changed

4 files changed

+205
-76
lines changed

doc/gpumd/input_parameters/compute_cohesive.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@ Syntax
1414

1515
This keyword is used as follows::
1616

17-
compute_cohesive <e1> <e2> <num_points>
17+
compute_cohesive <e1> <e2> <direction>
1818

1919
Here,
2020
:attr:`e1` is the smaller box-scaling factor,
2121
:attr:`e2` is the larger box-scaling factor, and
22-
:attr:`num_points` is the number of points sampled uniformly from :attr:`e1` to :attr:`e2`.
22+
:attr:`direction` specifies the direction of the scaling, which can take values from 0 to 6, corresponding to the x, y, z, xy, yz, zx, and xyz directions, respectively.
2323

2424

2525
Examples
2626
--------
2727

2828
The command::
2929

30-
compute_cohesive 0.9 1.2 301
30+
compute_cohesive 0.9 1.2 0
3131

32-
means that one wants to compute the cohesive energy curve from the box-scaling factor 0.9 to the box-scaling factor 1.2, with 301 points.
32+
means that one wants to compute the cohesive energy curve in the x-direction from the box-scaling factor 0.9 to the box-scaling factor 1.2, with ``(e2 - e1)*1000 +1`` points.
3333
The box-scaling points will be 0.9, 0.901, 0.902, ..., 1.2.
3434

3535

doc/gpumd/input_parameters/compute_elastic.rst

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,18 @@ Syntax
1313

1414
This keyword is used as follows::
1515

16-
compute_elastic <strain_value> <symmetry_type>
16+
compute_elastic <strain_value>
1717

1818
:attr:`strain_value` is the amount of strain to be applied in the calculations.
1919

20-
:attr:`symmetry_type` is the symmetry type of the material considered.
21-
Currently, it can only be :attr:`cubic`.
2220

2321
Example
2422
-------
2523
For example, the command::
2624

27-
compute_elastic 0.01 cubic
25+
compute_elastic 0.01
2826

29-
means that one wants to compute the elastic constants for a cubic system with a strain of 0.01.
27+
means that one wants to compute the elastic constants with a strain of 0.01.
3028

3129
Caveats
3230
-------

src/main_gpumd/cohesive.cu

Lines changed: 183 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ Compute the cohesive energy curve with different deformations.
3131

3232
static void __global__ deform_position(
3333
const int N,
34-
const D cpu_d,
34+
const double* old_inv,
35+
const double* new_h,
3536
const double* old_x,
3637
const double* old_y,
3738
const double* old_z,
@@ -41,33 +42,53 @@ static void __global__ deform_position(
4142
{
4243
const int n = blockDim.x * blockIdx.x + threadIdx.x;
4344
if (n < N) {
44-
new_x[n] = cpu_d.data[0] * old_x[n] + cpu_d.data[1] * old_y[n] + cpu_d.data[2] * old_z[n];
45-
new_y[n] = cpu_d.data[3] * old_x[n] + cpu_d.data[4] * old_y[n] + cpu_d.data[5] * old_z[n];
46-
new_z[n] = cpu_d.data[6] * old_x[n] + cpu_d.data[7] * old_y[n] + cpu_d.data[8] * old_z[n];
45+
double u = old_inv[0] * old_x[n] + old_inv[1] * old_y[n] + old_inv[2] * old_z[n];
46+
double v = old_inv[3] * old_x[n] + old_inv[4] * old_y[n] + old_inv[5] * old_z[n];
47+
double w = old_inv[6] * old_x[n] + old_inv[7] * old_y[n] + old_inv[8] * old_z[n];
48+
49+
new_x[n] = new_h[0] * u + new_h[1] * v + new_h[2] * w;
50+
new_y[n] = new_h[3] * u + new_h[4] * v + new_h[5] * w;
51+
new_z[n] = new_h[6] * u + new_h[7] * v + new_h[8] * w;
4752
}
4853
}
4954

5055
void Cohesive::deform_box(
51-
const int N, const D& cpu_d, Box& old_box, Box& new_box, GPU_Vector<double>& position_per_atom)
56+
const int N,
57+
const D& cpu_d,
58+
Box& old_box,
59+
Box& new_box,
60+
GPU_Vector<double>& position_per_atom,
61+
const GPU_Vector<double>& old_box_inv)
5262
{
5363
new_box.pbc_x = old_box.pbc_x;
5464
new_box.pbc_y = old_box.pbc_y;
5565
new_box.pbc_z = old_box.pbc_z;
5666

57-
for (int r = 0; r < 3; ++r) {
58-
for (int c = 0; c < 3; ++c) {
59-
double tmp = 0.0f;
60-
for (int k = 0; k < 3; ++k) {
61-
tmp += cpu_d.data[r * 3 + k] * old_box.cpu_h[k * 3 + c];
67+
if (deformation_type == 0) {
68+
for (int r = 0; r < 3; ++r) {
69+
for (int c = 0; c < 3; ++c) {
70+
new_box.cpu_h[r + c * 3] = cpu_d.data[r * 3 + c] * old_box.cpu_h[r + c * 3];
71+
}
72+
}
73+
} else {
74+
for (int r = 0; r < 3; ++r) {
75+
for (int c = 0; c < 3; ++c) {
76+
double tmp = 0.0f;
77+
for (int k = 0; k < 3; ++k) {
78+
tmp += cpu_d.data[r * 3 + k] * old_box.cpu_h[k * 3 + c];
79+
}
80+
new_box.cpu_h[r * 3 + c] = tmp + old_box.cpu_h[r * 3 + c];
6281
}
63-
new_box.cpu_h[r * 3 + c] = tmp;
6482
}
6583
}
84+
6685
new_box.get_inverse();
86+
new_box_h.copy_from_host(new_box.cpu_h, 9);
6787

6888
deform_position<<<(N - 1) / 128 + 1, 128>>>(
6989
N,
70-
cpu_d,
90+
old_box_inv.data(),
91+
new_box_h.data(),
7192
position_per_atom.data(),
7293
position_per_atom.data() + N,
7394
position_per_atom.data() + N * 2,
@@ -108,23 +129,24 @@ void Cohesive::parse_cohesive(const char** param, int num_param)
108129
}
109130
printf(" end_factor = %g.\n", end_factor);
110131

111-
if (!is_valid_int(param[3], &num_points)) {
112-
PRINT_INPUT_ERROR("num_points should be an integer.\n");
132+
if (!is_valid_int(param[3], &deform_d)) {
133+
PRINT_INPUT_ERROR("deform direction should be an integer.\n");
113134
}
114-
if (num_points < 2) {
115-
PRINT_INPUT_ERROR("num_points should >= 2.\n");
135+
if (deform_d < 0 || deform_d > 6) {
136+
PRINT_INPUT_ERROR("deform direction should >=0 and <= 6.\n");
116137
}
138+
num_points = (round((end_factor - start_factor) * 10) * 100) + 1;
117139
printf(" num_points = %d.\n", num_points);
118140

119-
delta_factor = (end_factor - start_factor) / (num_points - 1);
141+
delta_factor = 0.001; // (end_factor - start_factor) / (num_points - 1);
120142
deformation_type = 0; // deformation for cohesive
121143
}
122144

123145
void Cohesive::parse_elastic(const char** param, int num_param)
124146
{
125147
printf("Compute elastic constants.\n");
126-
if (num_param != 3) {
127-
PRINT_INPUT_ERROR("compute_elastic should have 2 parameters.\n");
148+
if (num_param != 2) {
149+
PRINT_INPUT_ERROR("compute_elastic should have 1 parameter.\n");
128150
}
129151

130152
if (!is_valid_real(param[1], &strain)) {
@@ -137,13 +159,8 @@ void Cohesive::parse_elastic(const char** param, int num_param)
137159
}
138160
printf(" strain = %g.\n", strain);
139161

140-
if (strcmp(param[2], "cubic") == 0) {
141-
printf(" crystal type = cubic.\n");
142-
deformation_type = 1; // deformation for cubic
143-
num_points = 5; // 1 (original) + 4
144-
} else {
145-
PRINT_INPUT_ERROR("Invalid crystal type.");
146-
}
162+
deformation_type = 1;
163+
num_points = 181;
147164
}
148165

149166
void Cohesive::allocate_memory(const int num_atoms)
@@ -152,40 +169,51 @@ void Cohesive::allocate_memory(const int num_atoms)
152169
cpu_potential_total.resize(num_points);
153170
cpu_potential_per_atom.resize(num_atoms);
154171
new_position_per_atom.resize(num_atoms * 3);
172+
old_box_inv.resize(9);
173+
new_box_h.resize(9);
155174
}
156175

157176
void Cohesive::compute_D()
158177
{
159178
for (int n = 0; n < num_points; ++n) {
160179
for (int k = 0; k < 9; ++k) {
161-
cpu_D[n].data[k] = 0.0;
180+
cpu_D[n].data[k] = (deformation_type == 0) ? 1.0 : 0.0;
162181
}
163182
}
183+
164184
if (deformation_type == 0) {
165185
for (int n = 0; n < num_points; ++n) {
166186
const double factor = start_factor + n * delta_factor;
167-
cpu_D[n].data[0] = factor;
168-
cpu_D[n].data[4] = factor;
169-
cpu_D[n].data[8] = factor;
187+
if (deform_d < 3) {
188+
for (int k = 3 * deform_d; k < 3 * deform_d + 3; ++k) {
189+
cpu_D[n].data[k] = factor;
190+
}
191+
} else if (deform_d > 2 && deform_d < 6) {
192+
for (int k = 3 * (deform_d - 3); k < 3 * (deform_d - 2) + 3; ++k) {
193+
if (k > 8) {
194+
k -= 9;
195+
}
196+
cpu_D[n].data[k] = factor;
197+
}
198+
} else {
199+
for (int k = 0; k < 9; ++k) {
200+
cpu_D[n].data[k] = factor;
201+
}
202+
}
203+
}
204+
} else {
205+
int idx = 1;
206+
for (int i = 0; i < 9; ++i) {
207+
for (int j = i; j < 9; ++j) {
208+
for (int s1 : {-1, 1}) {
209+
for (int s2 : {-1, 1}) {
210+
cpu_D[idx].data[i] = s1 * strain;
211+
cpu_D[idx].data[j] = s2 * strain;
212+
idx++;
213+
}
214+
}
215+
}
170216
}
171-
} else if (deformation_type == 1) {
172-
cpu_D[0].data[0] = 1.0;
173-
cpu_D[0].data[4] = 1.0;
174-
cpu_D[0].data[8] = 1.0;
175-
cpu_D[1].data[0] = 1.0 + strain;
176-
cpu_D[1].data[4] = 1.0 + strain;
177-
cpu_D[1].data[8] = 1.0 + strain;
178-
cpu_D[2].data[0] = 1.0 - strain;
179-
cpu_D[2].data[4] = 1.0 - strain;
180-
cpu_D[2].data[8] = 1.0 - strain;
181-
cpu_D[3].data[0] = 1.0 + strain;
182-
cpu_D[3].data[4] = 1.0 - strain;
183-
cpu_D[3].data[8] = 1.0 / (1.0 - strain * strain);
184-
cpu_D[4].data[0] = 1.0;
185-
cpu_D[4].data[1] = strain;
186-
cpu_D[4].data[3] = strain;
187-
cpu_D[4].data[4] = 1.0;
188-
cpu_D[4].data[8] = 1.0 / (1.0 - strain * strain);
189217
}
190218
}
191219

@@ -199,24 +227,109 @@ void Cohesive::output(Box& box)
199227
fprintf(fid, "%15.7e%15.7e\n", factor, cpu_potential_total[n]);
200228
}
201229
printf("Cohesive energies have been computed.\n");
202-
} else if (deformation_type == 1) {
230+
} else {
203231
const double volume = box.get_volume();
232+
M.resize(180, std::vector<double>(81, 0.0));
233+
MTM.resize(81, std::vector<double>(81, 0.0));
234+
MTE.resize(81, 0.0);
235+
C81.resize(81);
236+
204237
for (int n = 1; n < num_points; ++n) {
205-
cpu_potential_total[n] = (cpu_potential_total[n] - cpu_potential_total[0]) /
206-
(volume * strain * strain) * PRESSURE_UNIT_CONVERSION;
238+
int idx = 0;
239+
for (int i = 0; i < 3; ++i) {
240+
for (int j = 0; j < 3; ++j) {
241+
double S_ij = cpu_D[n].data[i * 3 + j];
242+
for (int k = 0; k < 3; ++k) {
243+
for (int l = 0; l < 3; ++l) {
244+
double S_kl = cpu_D[n].data[k * 3 + l];
245+
M[n - 1][idx] = 0.5 * S_ij * S_kl;
246+
idx++;
247+
}
248+
}
249+
}
250+
}
251+
}
252+
253+
for (int i = 0; i < 81; ++i) {
254+
for (int j = 0; j < 81; ++j) {
255+
for (int k = 0; k < 180; ++k) {
256+
MTM[i][j] += M[k][i] * M[k][j];
257+
}
258+
}
259+
MTM[i][i] += 1e-15;
260+
}
261+
262+
for (int j = 0; j < 81; ++j) {
263+
for (int i = 0; i < 180; ++i) {
264+
double delta_E = cpu_potential_total[i + 1] - cpu_potential_total[0];
265+
MTE[j] += M[i][j] * delta_E;
266+
}
207267
}
208-
double C11 =
209-
(cpu_potential_total[1] + cpu_potential_total[2] + 6.0 * cpu_potential_total[3]) / 9.0;
210-
double C12 =
211-
(cpu_potential_total[1] + cpu_potential_total[2] - 3.0 * cpu_potential_total[3]) / 9.0;
212-
double C44 = cpu_potential_total[4] * 0.5;
213-
printf("\nThe elastic constants are:\n");
214-
printf("C11 = %g Gpa\n", C11);
215-
printf("C12 = %g GPa\n", C12);
216-
printf("C44 = %g GPa\n", C44);
217-
fprintf(fid, "C11 = %g Gpa\n", C11);
218-
fprintf(fid, "C12 = %g GPa\n", C12);
219-
fprintf(fid, "C44 = %g GPa\n", C44);
268+
269+
for (int i = 0; i < 81; ++i) {
270+
int max_j = i;
271+
double max_val = std::abs(MTM[i][i]);
272+
for (int j = i + 1; j < 81; ++j) {
273+
if (std::abs(MTM[j][i]) > max_val) {
274+
max_val = std::abs(MTM[j][i]);
275+
max_j = j;
276+
}
277+
}
278+
279+
if (max_j != i) {
280+
std::swap(MTM[i], MTM[max_j]);
281+
std::swap(MTE[i], MTE[max_j]);
282+
}
283+
284+
if (std::abs(MTM[i][i]) < 1e-20) {
285+
printf("Warning: Singular matrix at column %d\n", i);
286+
continue;
287+
}
288+
289+
for (int k = i + 1; k < 81; ++k) {
290+
double factor = MTM[k][i] / MTM[i][i];
291+
for (int l = i; l < 81; ++l) {
292+
MTM[k][l] -= factor * MTM[i][l];
293+
}
294+
MTE[k] -= factor * MTE[i];
295+
}
296+
}
297+
298+
for (int i = 80; i >= 0; --i) {
299+
double sum = MTE[i];
300+
for (int j = i + 1; j < 81; ++j) {
301+
sum -= MTM[i][j] * C81[j];
302+
}
303+
C81[i] = sum / MTM[i][i];
304+
}
305+
306+
int voigt_idx[6][2] = {{0, 0}, {1, 1}, {2, 2}, {1, 2}, {2, 0}, {0, 1}};
307+
for (int a = 0; a < 6; ++a) {
308+
int i = voigt_idx[a][0], j = voigt_idx[a][1];
309+
for (int b = 0; b < 6; ++b) {
310+
int k = voigt_idx[b][0], l = voigt_idx[b][1];
311+
C[a][b] = C81[27 * i + 9 * j + 3 * k + l] / volume * PRESSURE_UNIT_CONVERSION;
312+
}
313+
}
314+
315+
printf("\nElastic Constants Matrix (GPa):\n");
316+
printf(" 1 2 3 4 5 6\n");
317+
for (int i = 0; i < 6; i++) {
318+
printf("%d ", i + 1);
319+
for (int j = 0; j < 6; j++) {
320+
printf("%8.3f ", C[i][j]);
321+
}
322+
printf("\n");
323+
}
324+
325+
fprintf(fid, "# Elastic Constants Matrix (GPa):\n");
326+
for (int i = 0; i < 6; i++) {
327+
for (int j = 0; j < 6; j++) {
328+
fprintf(fid, "%8.3f ", C[i][j]);
329+
}
330+
fprintf(fid, "\n");
331+
}
332+
printf("Elastic Constants have been computed.\n");
220333
}
221334

222335
fclose(fid);
@@ -236,9 +349,15 @@ void Cohesive::compute(
236349
allocate_memory(num_atoms);
237350
compute_D();
238351

352+
double old_inv[9];
353+
for (int i = 0; i < 9; ++i) {
354+
old_inv[i] = box.cpu_h[9 + i];
355+
}
356+
old_box_inv.copy_from_host(old_inv, 9);
357+
239358
for (int n = 0; n < num_points; ++n) {
240359
Box new_box;
241-
deform_box(num_atoms, cpu_D[n], box, new_box, position_per_atom);
360+
deform_box(num_atoms, cpu_D[n], box, new_box, position_per_atom, old_box_inv);
242361

243362
Minimizer_SD minimizer(-1, num_atoms, 1000, 1.0e-5);
244363
minimizer.compute(

0 commit comments

Comments
 (0)