@@ -31,7 +31,8 @@ Compute the cohesive energy curve with different deformations.
3131
3232static 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
5055void 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
123145void 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
149166void 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
157176void 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 (" \n The 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 (" \n Elastic 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