Octopus
vdw_ts_low.c
Go to the documentation of this file.
1/*
2** Copyright (C) 2015 Xavier Andrade, Carlos Borca, Alfredo Correa
3**
4** This library is free software: you can redistribute it and/or modify
5** it under the terms of the GNU Lesser General Public License as published by
6** the Free Software Foundation, either version 3 of the License, or
7** (at your option) any later version.
8**
9** This library is distributed in the hope that it will be useful,
10** but WITHOUT ANY WARRANTY; without even the implied warranty of
11** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12** GNU Lesser General Public License for more details.
13**
14** You should have received a copy of the GNU Lesser General Public License
15** along with this program. If not, see <http://www.gnu.org/licenses/>.
16**
17*/
18
19#include <math.h>
20#include <stdio.h>
21
22#ifndef _TEST
23#include "config.h"
24#endif
25
26/* Function to retrieve Van der Waals parameters of the free atoms. */
27void get_vdw_params(const int zatom, double *c6, double *alpha, double *r0) {
28
29 switch (zatom) {
30
31 // Hydrogen (H)
32 case 1:
33 *alpha = 4.500000;
34 *c6 = 6.500000;
35 *r0 = 3.100000;
36 break;
37
38 // Helium (He)
39 case 2:
40 *alpha = 1.380000;
41 *c6 = 1.460000;
42 *r0 = 2.650000;
43 break;
44
45 // Lithium (Li)
46 case 3:
47 *alpha = 164.200000;
48 *c6 = 1387.000000;
49 *r0 = 4.160000;
50 break;
51
52 // Berillium (Be)
53 case 4:
54 *alpha = 38.000000;
55 *c6 = 214.000000;
56 *r0 = 4.170000;
57 break;
58
59 // Boron (B)
60 case 5:
61 *alpha = 21.000000;
62 *c6 = 99.500000;
63 *r0 = 3.890000;
64 break;
66 // Carbon (C)
67 case 6:
68 *alpha = 12.000000;
69 *c6 = 46.600000;
70 *r0 = 3.590000;
71 break;
73 // Nitrogen (N)
74 case 7:
75 *alpha = 7.400000;
76 *c6 = 24.200000;
77 *r0 = 3.340000;
78 break;
79
80 // Oxygen (O)
81 case 8:
82 *alpha = 5.400000;
83 *c6 = 15.600000;
84 *r0 = 3.190000;
85 break;
87 // Fluorine (F)
88 case 9:
89 *alpha = 3.800000;
90 *c6 = 9.520000;
91 *r0 = 3.040000;
92 break;
93
94 // Neon (Ne)
95 case 10:
96 *alpha = 2.670000;
97 *c6 = 6.380000;
98 *r0 = 2.910000;
99 break;
100
101 // Sodium (Na)
102 case 11:
103 *alpha = 162.700000;
104 *c6 = 1556.000000;
105 *r0 = 3.730000;
106 break;
107
108 // Magnesium (Mg)
109 case 12:
110 *alpha = 71.000000;
111 *c6 = 627.000000;
112 *r0 = 4.270000;
113 break;
115 // Aluminium (Al)
116 case 13:
117 *alpha = 60.000000;
118 *c6 = 528.000000;
119 *r0 = 4.330000;
120 break;
122 // Silicon (Si)
123 case 14:
124 *alpha = 37.000000;
125 *c6 = 305.000000;
126 *r0 = 4.200000;
127 break;
129 // Phosphorus (P)
130 case 15:
131 *alpha = 25.000000;
132 *c6 = 185.000000;
133 *r0 = 4.010000;
134 break;
135
136 // Sulphur (S)
137 case 16:
138 *alpha = 19.600000;
139 *c6 = 134.000000;
140 *r0 = 3.860000;
141 break;
143 // Clorine (Cl)
144 case 17:
145 *alpha = 15.000000;
146 *c6 = 94.600000;
147 *r0 = 3.710000;
148 break;
149
150 // Argon (Ar)
151 case 18:
152 *alpha = 11.100000;
153 *c6 = 64.300000;
154 *r0 = 3.550000;
155 break;
157 // Potassium (K)
158 case 19:
159 *alpha = 292.900000;
160 *c6 = 3897.000000;
161 *r0 = 3.710000;
162 break;
163
164 // Calcium (Ca)
165 case 20:
166 *alpha = 160.000000;
167 *c6 = 2221.000000;
168 *r0 = 4.650000;
169 break;
171 // Scandium (Sc)
172 case 21:
173 *alpha = 120.000000;
174 *c6 = 1383.000000;
175 *r0 = 4.590000;
176 break;
178 // Titanium (Ti)
179 case 22:
180 *alpha = 98.000000;
181 *c6 = 1044.000000;
182 *r0 = 4.510000;
183 break;
184
185 // Vanadium (V)
186 case 23:
187 *alpha = 84.000000;
188 *c6 = 832.000000;
189 *r0 = 4.440000;
190 break;
191
192 // Chromium (Cr)
193 case 24:
194 *alpha = 78.000000;
195 *c6 = 602.000000;
196 *r0 = 3.990000;
197 break;
198
199 // Manganese (Mn)
200 case 25:
201 *alpha = 63.000000;
202 *c6 = 552.000000;
203 *r0 = 3.970000;
204 break;
206 // Iron (Fe)
207 case 26:
208 *alpha = 56.000000;
209 *c6 = 482.000000;
210 *r0 = 4.230000;
211 break;
212
213 // Cobalt (Co)
214 case 27:
215 *alpha = 50.000000;
216 *c6 = 408.000000;
217 *r0 = 4.180000;
218 break;
219
220 // Nickel (Ni)
221 case 28:
222 *alpha = 48.000000;
223 *c6 = 373.000000;
224 *r0 = 3.820000;
225 break;
226
227 // Copper (Cu)
228 case 29:
229 *alpha = 42.000000;
230 *c6 = 253.000000;
231 *r0 = 3.760000;
232 break;
234 // Zinc (Zn)
235 case 30:
236 *alpha = 40.000000;
237 *c6 = 284.000000;
238 *r0 = 4.020000;
239 break;
241 // Gallium (Ga)
242 case 31:
243 *alpha = 60.000000;
244 *c6 = 498.000000;
245 *r0 = 4.190000;
246 break;
248 // Germanium (Ge)
249 case 32:
250 *alpha = 41.000000;
251 *c6 = 354.000000;
252 *r0 = 4.200000;
253 break;
255 // Arsenic (As)
256 case 33:
257 *alpha = 29.000000;
258 *c6 = 246.000000;
259 *r0 = 4.110000;
260 break;
261
262 // Selenium (Se)
263 case 34:
264 *alpha = 25.000000;
265 *c6 = 210.000000;
266 *r0 = 4.040000;
267 break;
268
269 // Bromine (Br)
270 case 35:
271 *alpha = 20.000000;
272 *c6 = 162.000000;
273 *r0 = 3.930000;
274 break;
275
276 // Krypton (Kr)
277 case 36:
278 *alpha = 16.800000;
279 *c6 = 129.600000;
280 *r0 = 3.820000;
281 break;
283 // Rubidium (Rb)
284 case 37:
285 *alpha = 319.200000;
286 *c6 = 4691.000000;
287 *r0 = 3.720000;
288 break;
289
290 // Strontium (Sr)
291 case 38:
292 *alpha = 199.000000;
293 *c6 = 3170.000000;
294 *r0 = 4.540000;
295 break;
297 // Elements from 39 - Yttrium (Y) to 44 Ruthenium (Ru) are not included.
298
299 // Rhodium (Rh)
300 case 45:
301 *alpha = 56.1;
302 *c6 = 469.0;
303 *r0 = 3.95;
304 break;
305
306 // Palladium (Pd)
307 case 46:
308 *alpha = 23.680000;
309 *c6 = 157.500000;
310 *r0 = 3.66000;
311 break;
312
313 // Silver (Ag)
314 case 47:
315 *alpha = 50.600000;
316 *c6 = 339.000000;
317 *r0 = 3.820000;
318 break;
319
320 // Cadmium (Cd)
321 case 48:
322 *alpha = 39.7;
323 *c6 = 452.0;
324 *r0 = 3.99;
325 break;
326
327 // Elements from 49 - Indium (In) to 51 - Antimony (Sb) are not included.
328
329 // Tellurium (Te)
330 case 52:
331 *alpha = 37.65;
332 *c6 = 396.0;
333 *r0 = 4.22;
334 break;
335
336 // Iodine (I)
337 case 53:
338 *alpha = 35.000000;
339 *c6 = 385.000000;
340 *r0 = 4.170000;
341 break;
343 // Xenon (Xe)
344 case 54:
345 *alpha = 27.300000;
346 *c6 = 285.900000;
347 *r0 = 4.080000;
348 break;
349
350 // Element 55 - Caesium (Cs) is not included.
351
352 // Barium (Ba)
353 case 56:
354 *alpha = 275.0;
355 *c6 = 5727.0;
356 *r0 = 4.77;
357 break;
358
359 // Elements from 57 - Lanthanum (La) to 76 - Osmium (Os) are not included.
360
361 // Iridium (Ir)
362 case 77:
363 *alpha = 42.51;
364 *c6 = 359.1;
365 *r0 = 4.00;
366 break;
367
368 // Platinum (Pt)
369 case 78:
370 *alpha = 39.68;
371 *c6 = 347.1;
372 *r0 = 3.92;
373 break;
374
375 // Gold (Au)
376 case 79:
377 *alpha = 36.5;
378 *c6 = 298.0;
379 *r0 = 3.86;
380 break;
381
382 // Mercury (Hg)
383 case 80:
384 *alpha = 33.9;
385 *c6 = 392.0;
386 *r0 = 3.98;
387 break;
388
389 // Element 81 - Thallium (Tl) is not included.
390
391 // Lead (Pb)
392 case 82:
393 *alpha = 61.8;
394 *c6 = 697.0;
395 *r0 = 4.31;
396 break;
397
398 // Bismuth (Bi)
399 case 83:
400 *alpha = 49.02;
401 *c6 = 571.0;
402 *r0 = 4.32;
403
404 // Elements from 84 - Polonium (Po) to 118 - Ununoctium (Uuo) are not
405 // included.
406 }
407}
408
409/* Damping function. */
410void fdamp(const double rr, const double r0ab, const double dd, const double sr,
411 double *ff, double *dffdrab, double *dffdr0) {
412
413 // Calculate the damping coefficient.
414 double ee = exp(-dd * ((rr / (sr * r0ab)) - 1.0));
415 *ff = 1.0 / (1.0 + ee);
416 double dee = ee * (*ff) * (*ff);
417
418 // Calculate the derivative of the damping function with respect to the
419 // distance between atoms A and B.
420 *dffdrab = (dd / (sr * r0ab)) * dee;
421
422 // Calculate the derivative of the damping function with respect to the
423 // distance between the van der Waals radius.
424 *dffdr0 = -dd * rr / (sr * r0ab * r0ab) * dee;
425}
426
427/* Calculation of the square of separations. */
428void distance(const int iatom, const int jatom, const double coordinates[],
429 double *rr, double *rr2, double *rr6, double *rr7) {
430
431 double x_ij = coordinates[3 * iatom + 0] - coordinates[3 * jatom + 0];
432 double y_ij = coordinates[3 * iatom + 1] - coordinates[3 * jatom + 1];
433 double z_ij = coordinates[3 * iatom + 2] - coordinates[3 * jatom + 2];
434
435 *rr2 = x_ij * x_ij + y_ij * y_ij + z_ij * z_ij;
436 *rr6 = rr2[0] * rr2[0] *
437 rr2[0]; // This is the same as: *rr6 = (*rr2)*(*rr2)*(*rr2)
438 *rr = sqrt(rr2[0]); // This is the same as: *rr = sqrt(*rr2)
439 *rr7 = rr6[0] * rr[0]; // This is the same as: *rr6 = (*rr6)*(*rr)
440
441 // Print information controls.
442 // printf("R_(%i-%i)= %f\n", iatom+1, jatom+1, *rr);
443 // printf("R_(%i-%i)^2 = %f\n", iatom+1, jatom+1, *rr2);
444 // printf("R_(%i-%i)^6 = %f\n", iatom+1, jatom+1, *rr6);
445}
446
447/* Function to calculate the Van der Waals energy... and forces */
448void vdw_calculate(const int natoms, const double dd, const double sr,
449 const int zatom[], const double coordinates[],
450 const double volume_ratio[], double *energy, double force[],
451 double derivative_coeff[]) {
452 int ia;
453
454 *energy = 0.0;
455
456 // Loop to calculate the pair-wise Van der Waals energy correction.
457 for (ia = 0; ia < natoms; ia++) {
458
459 double c6_a, alpha_a, r0_a;
460 int ib;
461
462 force[3 * ia + 0] = 0.0;
463 force[3 * ia + 1] = 0.0;
464 force[3 * ia + 2] = 0.0;
465
466 derivative_coeff[ia] = 0.0;
467
468 get_vdw_params(zatom[ia], &c6_a, &alpha_a, &r0_a);
469
470 for (ib = 0; ib < natoms; ib++) {
471
472 double c6_b, alpha_b, r0_b;
473
474 if (ia == ib)
475 continue;
476
477 // Pair-wise calculation of separations.
478 double rr, rr2, rr6, rr7;
479 distance(ia, ib, coordinates, &rr, &rr2, &rr6, &rr7);
480
481 get_vdw_params(zatom[ib], &c6_b, &alpha_b, &r0_b);
482
483 // Determination of c6abfree, for isolated atoms a and b.
484 double num = 2.0 * c6_a * c6_b;
485 double den = (alpha_b / alpha_a) * c6_a + (alpha_a / alpha_b) * c6_b;
486
487 double c6abfree = num / den;
488
489 // Determination of the effective c6 coefficient.
490 double c6abeff = volume_ratio[ia] * volume_ratio[ib] * c6abfree;
491 // Determination of the effective radius of atom a.
492 double r0ab =
493 cbrt(volume_ratio[ia]) * r0_a + cbrt(volume_ratio[ib]) * r0_b;
494
495 // Pair-wise calculation of the damping coefficient
496 double ff;
497 double dffdrab;
498 double dffdr0;
499 fdamp(rr, r0ab, dd, sr, &ff, &dffdrab, &dffdr0);
500 // Pair-wise correction to energy.
501 *energy += -0.5 * ff * c6abeff / rr6;
502
503 // Calculation of the pair-wise partial energy derivative with respect to
504 // the distance between atoms A and B.
505 double deabdrab = dffdrab * c6abeff / rr6 - 6.0 * ff * c6abeff / rr7;
506
507 // Derivative of the AB van der Waals separation with respect to the
508 // volume ratio of atom A.
509 double dr0dvra = r0_a / (3.0 * pow(volume_ratio[ia], 2.0 / 3.0));
510
511 // Derivative of the damping function with respecto to the volume ratio of
512 // atom A.
513 double dffdvra = dffdr0 * dr0dvra;
514
515 // Calculation of the pair-wise partial energy derivative with respect to
516 // the volume ratio of atom A.
517 double deabdvra =
518 dffdvra * c6abeff / rr6 + ff * volume_ratio[ib] * c6abfree / rr6;
519
520 force[3 * ia + 0] +=
521 deabdrab * (coordinates[3 * ia + 0] - coordinates[3 * ib + 0]) / rr;
522 force[3 * ia + 1] +=
523 deabdrab * (coordinates[3 * ia + 1] - coordinates[3 * ib + 1]) / rr;
524 force[3 * ia + 2] +=
525 deabdrab * (coordinates[3 * ia + 2] - coordinates[3 * ib + 2]) / rr;
526
527 derivative_coeff[ia] += deabdvra;
528
529 // Print information controls.
530 // printf("Distance between atoms %i and %i = %f.\n", ia+1, ib+1, rr);
531 // printf("Atom %i, c6= %f, alpha= %f, r0= %f.\n", ia+1, c6_a, alpha_a,
532 // r0_a); printf("Atom %i, c6= %f, alpha= %f, r0= %f.\n", ib+1, c6_b,
533 // alpha_b, r0_b); printf("For atoms %i and %i, c6abeff= %f.\n", ia+1,
534 // ib+1, c6abfree);
535 }
536 }
537 // printf("THE FINAL VAN DER WAALS ENERGY CORRECTION IS = %f.\n", *energy);
538 // printf("THE FINAL VAN DER WAALS FORCE CORRECTION IS = %f.\n", *force);
539}
540
541#ifndef _TEST
542/* This is a wrapper to be called from Fortran. */
543void FC_FUNC_(f90_vdw_calculate,
544 F90_VDW_CALCULATE)(const int *natoms, const double *dd,
545 const double *sr, const int zatom[],
546 const double coordinates[],
547 const double volume_ratio[], double *energy,
548 double force[], double derivative_coeff[]) {
549 vdw_calculate(*natoms, *dd, *sr, zatom, coordinates, volume_ratio, energy,
550 force, derivative_coeff);
551}
552#endif
553
554/* Main test function. */
555#ifdef _TEST
556int main() {
557 const int natoms = 3;
558 const int zatom[] = {23, 29, 31};
559 const double volume_ratio[] = {1.0, 1.0, 1.0};
560 double energy;
561 double force[natoms * 3];
562 double derivative_coeff[natoms];
563
564 double x;
565 for (x = 0.1; x < 10; x += 0.1) {
566 double coordinates[] = {0.2, -0.3, 0.5, -0.7, 1.1, -1.3, x, 0.0, 0.0};
567
568 vdw_calculate(natoms, zatom, coordinates, volume_ratio, &energy, force,
569 derivative_coeff);
570
571 coordinates[5] += 0.001;
572 double energy_2;
573
574 vdw_calculate(natoms, zatom, coordinates, volume_ratio, &energy_2, force,
575 derivative_coeff);
576 }
577}
578#endif
double pow(double __x, double __y) __attribute__((__nothrow__
double exp(double __x) __attribute__((__nothrow__
void vdw_calculate(const int natoms, const double dd, const double sr, const int zatom[], const double coordinates[], const double volume_ratio[], double *energy, double force[], double derivative_coeff[])
Definition: vdw_ts_low.c:2079
double cbrt(double __x) __attribute__((__nothrow__
void fdamp(const double rr, const double r0ab, const double dd, const double sr, double *ff, double *dffdrab, double *dffdr0)
Definition: vdw_ts_low.c:2041
double sqrt(double __x) __attribute__((__nothrow__
void distance(const int iatom, const int jatom, const double coordinates[], double *rr, double *rr2, double *rr6, double *rr7)
Definition: vdw_ts_low.c:2059