1 /*-
2 * Copyright (c) 2012-2017 Ilya Kaliman
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include "balance.h"
31 #include "clapack.h"
32 #include "elec.h"
33 #include "private.h"
34 #include "stream.h"
35
36 static void
update_fragment(struct frag * frag)37 update_fragment(struct frag *frag)
38 {
39 /* update atoms */
40 for (size_t i = 0; i < frag->n_atoms; i++)
41 efp_move_pt(CVEC(frag->x), &frag->rotmat,
42 CVEC(frag->lib->atoms[i].x), VEC(frag->atoms[i].x));
43
44 efp_update_elec(frag);
45 efp_update_pol(frag);
46 efp_update_disp(frag);
47 efp_update_xr(frag);
48 }
49
50 static enum efp_result
set_coord_xyzabc(struct frag * frag,const double * coord)51 set_coord_xyzabc(struct frag *frag, const double *coord)
52 {
53 frag->x = coord[0];
54 frag->y = coord[1];
55 frag->z = coord[2];
56
57 euler_to_matrix(coord[3], coord[4], coord[5], &frag->rotmat);
58 update_fragment(frag);
59
60 return EFP_RESULT_SUCCESS;
61 }
62
63 static enum efp_result
set_coord_points(struct frag * frag,const double * coord)64 set_coord_points(struct frag *frag, const double *coord)
65 {
66 /* allow fragments with less than 3 atoms by using multipole points of
67 * ghost atoms; multipole points have the same coordinates as atoms */
68 if (frag->n_multipole_pts < 3) {
69 efp_log("fragment must contain at least three atoms");
70 return EFP_RESULT_FATAL;
71 }
72
73 double ref[9] = {
74 frag->lib->multipole_pts[0].x,
75 frag->lib->multipole_pts[0].y,
76 frag->lib->multipole_pts[0].z,
77 frag->lib->multipole_pts[1].x,
78 frag->lib->multipole_pts[1].y,
79 frag->lib->multipole_pts[1].z,
80 frag->lib->multipole_pts[2].x,
81 frag->lib->multipole_pts[2].y,
82 frag->lib->multipole_pts[2].z
83 };
84
85 vec_t p1;
86 mat_t rot1, rot2;
87
88 efp_points_to_matrix(coord, &rot1);
89 efp_points_to_matrix(ref, &rot2);
90 rot2 = mat_transpose(&rot2);
91 frag->rotmat = mat_mat(&rot1, &rot2);
92 p1 = mat_vec(&frag->rotmat, VEC(frag->lib->multipole_pts[0].x));
93
94 /* center of mass */
95 frag->x = coord[0] - p1.x;
96 frag->y = coord[1] - p1.y;
97 frag->z = coord[2] - p1.z;
98
99 update_fragment(frag);
100
101 return EFP_RESULT_SUCCESS;
102 }
103
104 static enum efp_result
set_coord_rotmat(struct frag * frag,const double * coord)105 set_coord_rotmat(struct frag *frag, const double *coord)
106 {
107 if (!efp_check_rotation_matrix((const mat_t *)(coord + 3))) {
108 efp_log("invalid rotation matrix specified");
109 return EFP_RESULT_FATAL;
110 }
111
112 frag->x = coord[0];
113 frag->y = coord[1];
114 frag->z = coord[2];
115
116 memcpy(&frag->rotmat, coord + 3, sizeof(frag->rotmat));
117 update_fragment(frag);
118
119 return EFP_RESULT_SUCCESS;
120 }
121
122 static void
free_frag(struct frag * frag)123 free_frag(struct frag *frag)
124 {
125 if (!frag)
126 return;
127
128 free(frag->atoms);
129 free(frag->multipole_pts);
130 free(frag->polarizable_pts);
131 free(frag->dynamic_polarizable_pts);
132 free(frag->lmo_centroids);
133 free(frag->xr_fock_mat);
134 free(frag->xr_wf);
135 free(frag->xrfit);
136 free(frag->screen_params);
137 free(frag->ai_screen_params);
138
139 for (size_t i = 0; i < 3; i++)
140 free(frag->xr_wf_deriv[i]);
141
142 for (size_t i = 0; i < frag->n_xr_atoms; i++) {
143 for (size_t j = 0; j < frag->xr_atoms[i].n_shells; j++)
144 free(frag->xr_atoms[i].shells[j].coef);
145 free(frag->xr_atoms[i].shells);
146 }
147
148 free(frag->xr_atoms);
149
150 /* don't do free(frag) here */
151 }
152
153 static enum efp_result
copy_frag(struct frag * dest,const struct frag * src)154 copy_frag(struct frag *dest, const struct frag *src)
155 {
156 size_t size;
157
158 memcpy(dest, src, sizeof(*dest));
159
160 if (src->atoms) {
161 size = src->n_atoms * sizeof(struct efp_atom);
162 dest->atoms = (struct efp_atom *)malloc(size);
163 if (!dest->atoms)
164 return EFP_RESULT_NO_MEMORY;
165 memcpy(dest->atoms, src->atoms, size);
166 }
167 if (src->multipole_pts) {
168 size = src->n_multipole_pts * sizeof(struct multipole_pt);
169 dest->multipole_pts = (struct multipole_pt *)malloc(size);
170 if (!dest->multipole_pts)
171 return EFP_RESULT_NO_MEMORY;
172 memcpy(dest->multipole_pts, src->multipole_pts, size);
173 }
174 if (src->screen_params) {
175 size = src->n_multipole_pts * sizeof(double);
176 dest->screen_params = (double *)malloc(size);
177 if (!dest->screen_params)
178 return EFP_RESULT_NO_MEMORY;
179 memcpy(dest->screen_params, src->screen_params, size);
180 }
181 if (src->ai_screen_params) {
182 size = src->n_multipole_pts * sizeof(double);
183 dest->ai_screen_params = (double *)malloc(size);
184 if (!dest->ai_screen_params)
185 return EFP_RESULT_NO_MEMORY;
186 memcpy(dest->ai_screen_params, src->ai_screen_params, size);
187 }
188 if (src->polarizable_pts) {
189 size = src->n_polarizable_pts * sizeof(struct polarizable_pt);
190 dest->polarizable_pts = (struct polarizable_pt *)malloc(size);
191 if (!dest->polarizable_pts)
192 return EFP_RESULT_NO_MEMORY;
193 memcpy(dest->polarizable_pts, src->polarizable_pts, size);
194 }
195 if (src->dynamic_polarizable_pts) {
196 size = src->n_dynamic_polarizable_pts *
197 sizeof(struct dynamic_polarizable_pt);
198 dest->dynamic_polarizable_pts =
199 (struct dynamic_polarizable_pt *)malloc(size);
200 if (!dest->dynamic_polarizable_pts)
201 return EFP_RESULT_NO_MEMORY;
202 memcpy(dest->dynamic_polarizable_pts,
203 src->dynamic_polarizable_pts, size);
204 }
205 if (src->lmo_centroids) {
206 size = src->n_lmo * sizeof(vec_t);
207 dest->lmo_centroids = (vec_t *)malloc(size);
208 if (!dest->lmo_centroids)
209 return EFP_RESULT_NO_MEMORY;
210 memcpy(dest->lmo_centroids, src->lmo_centroids, size);
211 }
212 if (src->xr_atoms) {
213 size = src->n_xr_atoms * sizeof(struct xr_atom);
214 dest->xr_atoms = (struct xr_atom *)malloc(size);
215 if (!dest->xr_atoms)
216 return EFP_RESULT_NO_MEMORY;
217 memcpy(dest->xr_atoms, src->xr_atoms, size);
218
219 for (size_t j = 0; j < src->n_xr_atoms; j++) {
220 const struct xr_atom *at_src = src->xr_atoms + j;
221 struct xr_atom *at_dest = dest->xr_atoms + j;
222
223 size = at_src->n_shells * sizeof(struct shell);
224 at_dest->shells = (struct shell *)malloc(size);
225 if (!at_dest->shells)
226 return EFP_RESULT_NO_MEMORY;
227 memcpy(at_dest->shells, at_src->shells, size);
228
229 for (size_t i = 0; i < at_src->n_shells; i++) {
230 size = (at_src->shells[i].type == 'L' ? 3 : 2) *
231 at_src->shells[i].n_funcs * sizeof(double);
232 at_dest->shells[i].coef =
233 (double *)malloc(size);
234 if (!at_dest->shells[i].coef)
235 return EFP_RESULT_NO_MEMORY;
236 memcpy(at_dest->shells[i].coef,
237 at_src->shells[i].coef, size);
238 }
239 }
240 }
241 if (src->xr_fock_mat) {
242 size = src->n_lmo * (src->n_lmo + 1) / 2 * sizeof(double);
243 dest->xr_fock_mat = (double *)malloc(size);
244 if (!dest->xr_fock_mat)
245 return EFP_RESULT_NO_MEMORY;
246 memcpy(dest->xr_fock_mat, src->xr_fock_mat, size);
247 }
248 if (src->xr_wf) {
249 size = src->n_lmo * src->xr_wf_size * sizeof(double);
250 dest->xr_wf = (double *)malloc(size);
251 if (!dest->xr_wf)
252 return EFP_RESULT_NO_MEMORY;
253 memcpy(dest->xr_wf, src->xr_wf, size);
254 }
255 if (src->xrfit) {
256 size = src->n_lmo * 4 * sizeof(double);
257 dest->xrfit = (double *)malloc(size);
258 if (!dest->xrfit)
259 return EFP_RESULT_NO_MEMORY;
260 memcpy(dest->xrfit, src->xrfit, size);
261 }
262 return EFP_RESULT_SUCCESS;
263 }
264
265 static enum efp_result
check_opts(const struct efp_opts * opts)266 check_opts(const struct efp_opts *opts)
267 {
268 if (opts->enable_pbc) {
269 if ((opts->terms & EFP_TERM_AI_ELEC) ||
270 (opts->terms & EFP_TERM_AI_POL) ||
271 (opts->terms & EFP_TERM_AI_DISP) ||
272 (opts->terms & EFP_TERM_AI_XR) ||
273 (opts->terms & EFP_TERM_AI_CHTR)) {
274 efp_log("periodic calculations are not supported "
275 "for QM/EFP");
276 return EFP_RESULT_FATAL;
277 }
278 if (!opts->enable_cutoff) {
279 efp_log("periodic calculations require interaction "
280 "cutoff to be enabled");
281 return EFP_RESULT_FATAL;
282 }
283 }
284 if (opts->enable_cutoff) {
285 if (opts->swf_cutoff < 1.0) {
286 efp_log("interaction cutoff is too small");
287 return EFP_RESULT_FATAL;
288 }
289 }
290 return EFP_RESULT_SUCCESS;
291 }
292
293 static enum efp_result
check_frag_params(const struct efp_opts * opts,const struct frag * frag)294 check_frag_params(const struct efp_opts *opts, const struct frag *frag)
295 {
296 if ((opts->terms & EFP_TERM_ELEC) || (opts->terms & EFP_TERM_AI_ELEC)) {
297 if (!frag->multipole_pts) {
298 efp_log("electrostatic parameters are missing");
299 return EFP_RESULT_FATAL;
300 }
301 if (opts->elec_damp == EFP_ELEC_DAMP_SCREEN &&
302 frag->screen_params == NULL) {
303 efp_log("screening parameters are missing");
304 return EFP_RESULT_FATAL;
305 }
306 }
307 if ((opts->terms & EFP_TERM_POL) || (opts->terms & EFP_TERM_AI_POL)) {
308 if (!frag->polarizable_pts || !frag->multipole_pts) {
309 efp_log("polarization parameters are missing");
310 return EFP_RESULT_FATAL;
311 }
312 }
313 if ((opts->terms & EFP_TERM_DISP) || (opts->terms & EFP_TERM_AI_DISP)) {
314 if (frag->dynamic_polarizable_pts == NULL) {
315 efp_log("dispersion parameters are missing");
316 return EFP_RESULT_FATAL;
317 }
318 if (opts->disp_damp == EFP_DISP_DAMP_OVERLAP &&
319 frag->n_lmo != frag->n_dynamic_polarizable_pts) {
320 efp_log("number of polarization points does not "
321 "match number of LMOs");
322 return EFP_RESULT_FATAL;
323 }
324 }
325 if ((opts->terms & EFP_TERM_XR) || (opts->terms & EFP_TERM_AI_XR)) {
326 if (!frag->xr_atoms ||
327 !frag->xr_fock_mat ||
328 !frag->xr_wf ||
329 !frag->lmo_centroids) {
330 efp_log("exchange repulsion parameters are missing");
331 return EFP_RESULT_FATAL;
332 }
333 }
334 return EFP_RESULT_SUCCESS;
335 }
336
337 static enum efp_result
check_params(struct efp * efp)338 check_params(struct efp *efp)
339 {
340 enum efp_result res;
341
342 for (size_t i = 0; i < efp->n_frag; i++)
343 if ((res = check_frag_params(&efp->opts, efp->frags + i)))
344 return res;
345
346 return EFP_RESULT_SUCCESS;
347 }
348
349 static int
do_elec(const struct efp_opts * opts)350 do_elec(const struct efp_opts *opts)
351 {
352 return opts->terms & EFP_TERM_ELEC;
353 }
354
355 static int
do_disp(const struct efp_opts * opts)356 do_disp(const struct efp_opts *opts)
357 {
358 return opts->terms & EFP_TERM_DISP;
359 }
360
361 static int
do_xr(const struct efp_opts * opts)362 do_xr(const struct efp_opts *opts)
363 {
364 int xr = (opts->terms & EFP_TERM_XR);
365 int cp = (opts->terms & EFP_TERM_ELEC) &&
366 (opts->elec_damp == EFP_ELEC_DAMP_OVERLAP);
367 int dd = (opts->terms & EFP_TERM_DISP) &&
368 (opts->disp_damp == EFP_DISP_DAMP_OVERLAP);
369 return xr || cp || dd;
370 }
371
372 static void
compute_two_body_range(struct efp * efp,size_t frag_from,size_t frag_to,void * data)373 compute_two_body_range(struct efp *efp, size_t frag_from, size_t frag_to,
374 void *data)
375 {
376 double e_elec = 0.0, e_disp = 0.0, e_xr = 0.0, e_cp = 0.0;
377
378 (void)data;
379
380 #ifdef _OPENMP
381 #pragma omp parallel for schedule(dynamic) reduction(+:e_elec,e_disp,e_xr,e_cp)
382 #endif
383 for (size_t i = frag_from; i < frag_to; i++) {
384 size_t cnt = efp->n_frag % 2 ? (efp->n_frag - 1) / 2 :
385 i < efp->n_frag / 2 ? efp->n_frag / 2 :
386 efp->n_frag / 2 - 1;
387
388 for (size_t j = i + 1; j < i + 1 + cnt; j++) {
389 size_t fr_j = j % efp->n_frag;
390
391 if (!efp_skip_frag_pair(efp, i, fr_j)) {
392 double *s;
393 six_t *ds;
394 size_t n_lmo_ij = efp->frags[i].n_lmo *
395 efp->frags[fr_j].n_lmo;
396
397 s = (double *)calloc(n_lmo_ij, sizeof(double));
398 ds = (six_t *)calloc(n_lmo_ij, sizeof(six_t));
399
400 if (do_xr(&efp->opts)) {
401 double exr, ecp;
402
403 efp_frag_frag_xr(efp, i, fr_j,
404 s, ds, &exr, &ecp);
405 e_xr += exr;
406 e_cp += ecp;
407 }
408 if (do_elec(&efp->opts)) {
409 e_elec += efp_frag_frag_elec(efp,
410 i, fr_j);
411 }
412 if (do_disp(&efp->opts)) {
413 e_disp += efp_frag_frag_disp(efp,
414 i, fr_j, s, ds);
415 }
416 free(s);
417 free(ds);
418 }
419 }
420 }
421 efp->energy.electrostatic += e_elec;
422 efp->energy.dispersion += e_disp;
423 efp->energy.exchange_repulsion += e_xr;
424 efp->energy.charge_penetration += e_cp;
425 }
426
427 EFP_EXPORT enum efp_result
efp_get_energy(struct efp * efp,struct efp_energy * energy)428 efp_get_energy(struct efp *efp, struct efp_energy *energy)
429 {
430 assert(efp);
431 assert(energy);
432
433 *energy = efp->energy;
434
435 return EFP_RESULT_SUCCESS;
436 }
437
438 EFP_EXPORT enum efp_result
efp_get_gradient(struct efp * efp,double * grad)439 efp_get_gradient(struct efp *efp, double *grad)
440 {
441 assert(efp);
442 assert(grad);
443
444 if (!efp->do_gradient) {
445 efp_log("gradient calculation was not requested");
446 return EFP_RESULT_FATAL;
447 }
448 memcpy(grad, efp->grad, efp->n_frag * sizeof(six_t));
449 return EFP_RESULT_SUCCESS;
450 }
451
452 EFP_EXPORT enum efp_result
efp_get_atomic_gradient(struct efp * efp,double * grad)453 efp_get_atomic_gradient(struct efp *efp, double *grad)
454 {
455 six_t *efpgrad = NULL; /* Calculated EFP gradient */
456 vec_t *pgrad; /* Conversion of grad to vec_t type */
457 size_t i, j, k, l;
458 size_t nr; /* Number of atoms in the current fragment */
459 size_t maxa; /* Maximum number of size of m, Ia, r arrays */
460 vec_t *r = NULL; /* Radius-vector of each atom inside current fragment
461 with respect to CoM of that fragment */
462 double mm, *m = NULL; /* Total Mass of fragments and individual atoms */
463 double I, *Ia = NULL; /* Inertia along axis and contribution of each
464 individual atom */
465 mat_t Id; /* Total inertia tensor of a fragment */
466 vec_t v, g; /* Principal axis and Inertia along that axis */
467 vec_t rbuf, rbuf2, tq, ri, rt;
468 double dist, sina, ft, norm;
469 enum efp_result res;
470
471 assert(efp);
472 assert(grad);
473
474 if (!efp->do_gradient) {
475 efp_log("gradient calculation was not requested");
476 return EFP_RESULT_FATAL;
477 }
478 pgrad = (vec_t *)grad;
479
480 /* Calculate maximum size of a fragment */
481 maxa = 0;
482 for (j = 0; j < efp->n_frag; j++) {
483 if (efp->frags[j].n_atoms > maxa)
484 maxa = efp->frags[j].n_atoms;
485 }
486
487 res = EFP_RESULT_NO_MEMORY;
488 /* Create and initialize some arrays for work */
489 if ((r = (vec_t *)malloc(maxa * sizeof(*r))) == NULL)
490 goto error;
491 if ((m = (double *)malloc(maxa * sizeof(*m))) == NULL)
492 goto error;
493 if ((Ia = (double *)malloc(maxa * sizeof(*Ia))) == NULL)
494 goto error;
495
496 /* Copy computed efp->grad */
497 if ((efpgrad = (six_t *)malloc(efp->n_frag * sizeof(*efpgrad))) == NULL)
498 goto error;
499 memcpy(efpgrad, efp->grad, efp->n_frag * sizeof(*efpgrad));
500
501 /* Main cycle (iterate fragments, distribute forces and torques) */
502 for (k = 0, j = 0; j < efp->n_frag; j++) {
503 nr = efp->frags[j].n_atoms;
504 memset(r, 0, maxa * sizeof(*r));
505 memset(m, 0, maxa * sizeof(*m));
506 memset(Ia, 0, maxa * sizeof(*Ia));
507 mm = 0.0;
508 Id = mat_zero;
509 v = vec_zero;
510 g = vec_zero;
511
512 for (i = 0; i < nr ; i++) {
513 r[i].x = efp->frags[j].atoms[i].x - efp->frags[j].x;
514 r[i].y = efp->frags[j].atoms[i].y - efp->frags[j].y;
515 r[i].z = efp->frags[j].atoms[i].z - efp->frags[j].z;
516 m[i] = efp->frags[j].atoms[i].mass;
517 mm += m[i];
518
519 /* Inertia tensor contribution calculations */
520 Id.xx += m[i] * (r[i].y*r[i].y + r[i].z*r[i].z);
521 Id.yy += m[i] * (r[i].x*r[i].x + r[i].z*r[i].z);
522 Id.zz += m[i] * (r[i].x*r[i].x + r[i].y*r[i].y);
523 Id.xy -= m[i] * r[i].x * r[i].y;
524 Id.yx -= m[i] * r[i].x * r[i].y;
525 Id.xz -= m[i] * r[i].x * r[i].z;
526 Id.zx -= m[i] * r[i].x * r[i].z;
527 Id.yz -= m[i] * r[i].y * r[i].z;
528 Id.zy -= m[i] * r[i].y * r[i].z;
529 }
530
531 /* Try to diagonalize Id and get principal axis */
532 if (efp_dsyev('V', 'U', 3, (double *)&Id, 3, (double *)&g)) {
533 efp_log("inertia tensor diagonalization failed");
534 res = EFP_RESULT_FATAL;
535 goto error;
536 }
537
538 /* Add any additional forces from grad array to efpgrad array */
539 for (i = 0; i < nr; i++) {
540 efpgrad[j].x += pgrad[k+i].x;
541 efpgrad[j].y += pgrad[k+i].y;
542 efpgrad[j].z += pgrad[k+i].z;
543 rbuf = vec_cross(&r[i], &pgrad[k+i]);
544 efpgrad[j].a += rbuf.x;
545 efpgrad[j].b += rbuf.y;
546 efpgrad[j].c += rbuf.z;
547 pgrad[k+i] = vec_zero;
548 }
549
550 /* Now we are ready to redistribute efpgrad over the atoms */
551
552 /* Redistribute total translation grad[i]=m[i]/mm*efpgrad[j] */
553 for (i = 0; i < nr; i++) {
554 pgrad[k+i].x = efpgrad[j].x;
555 pgrad[k+i].y = efpgrad[j].y;
556 pgrad[k+i].z = efpgrad[j].z;
557 vec_scale(&pgrad[k+i], m[i] / mm);
558 }
559
560 /* Redistribution of torque should be done over 3 principal
561 axes computed previously */
562 for (l = 0; l < 3; l++) {
563 v = ((vec_t *)&Id)[l];
564 tq.x = efpgrad[j].a;
565 tq.y = efpgrad[j].b;
566 tq.z = efpgrad[j].c;
567
568 /* Calculate contribution of each atom to moment of
569 inertia with respect to current axis */
570 I = 0.0;
571 for (i = 0; i < nr; i++) {
572 rbuf = vec_cross(&v, &r[i]);
573 dist = vec_len(&rbuf);
574 Ia[i] = m[i] * dist * dist;
575 I += Ia[i];
576 }
577
578 /* Project torque onto v axis */
579 norm = vec_dot(&tq, &v);
580 tq = v;
581 vec_scale(&tq, norm);
582
583 /* Now distribute torque using Ia[i]/I as a scale */
584 for (i = 0; i < nr; i++) {
585 if (eq(Ia[i], 0.0))
586 continue;
587 /* If atom is not on the current axis */
588 rbuf = tq;
589 vec_scale(&rbuf, Ia[i]/I);
590 ft = vec_len(&rbuf);
591 ri = r[i];
592 vec_normalize(&ri);
593 rt = tq;
594 vec_normalize(&rt);
595 rbuf2 = vec_cross(&rt, &ri);
596 sina = vec_len(&rbuf2);
597 vec_normalize(&rbuf2);
598 vec_scale(&rbuf2, ft/sina/vec_len(&r[i]));
599 /* Update grad with torque contribution of
600 atom i over axis v */
601 pgrad[k+i] = vec_add(&pgrad[k+i], &rbuf2);
602 }
603 }
604 k += nr;
605 }
606 res = EFP_RESULT_SUCCESS;
607 error:
608 free(r);
609 free(m);
610 free(Ia);
611 free(efpgrad);
612 return res;
613 }
614
615 EFP_EXPORT enum efp_result
efp_set_point_charges(struct efp * efp,size_t n_ptc,const double * ptc,const double * xyz)616 efp_set_point_charges(struct efp *efp, size_t n_ptc, const double *ptc,
617 const double *xyz)
618 {
619 assert(efp);
620 efp->n_ptc = n_ptc;
621
622 if (n_ptc == 0) {
623 free(efp->ptc);
624 free(efp->ptc_xyz);
625 free(efp->ptc_grad);
626 efp->ptc = NULL;
627 efp->ptc_xyz = NULL;
628 efp->ptc_grad = NULL;
629 return EFP_RESULT_SUCCESS;
630 }
631
632 assert(ptc);
633 assert(xyz);
634
635 efp->ptc = (double *)realloc(efp->ptc, n_ptc * sizeof(double));
636 efp->ptc_xyz = (vec_t *)realloc(efp->ptc_xyz, n_ptc * sizeof(vec_t));
637 efp->ptc_grad = (vec_t *)realloc(efp->ptc_grad, n_ptc * sizeof(vec_t));
638
639 memcpy(efp->ptc, ptc, n_ptc * sizeof(double));
640 memcpy(efp->ptc_xyz, xyz, n_ptc * sizeof(vec_t));
641 memset(efp->ptc_grad, 0, n_ptc * sizeof(vec_t));
642
643 return EFP_RESULT_SUCCESS;
644 }
645
646 EFP_EXPORT enum efp_result
efp_get_point_charge_count(struct efp * efp,size_t * n_ptc)647 efp_get_point_charge_count(struct efp *efp, size_t *n_ptc)
648 {
649 assert(efp);
650 assert(n_ptc);
651
652 *n_ptc = efp->n_ptc;
653
654 return EFP_RESULT_SUCCESS;
655 }
656
657 EFP_EXPORT enum efp_result
efp_get_point_charge_gradient(struct efp * efp,double * grad)658 efp_get_point_charge_gradient(struct efp *efp, double *grad)
659 {
660 assert(efp);
661 assert(grad);
662
663 if (!efp->do_gradient) {
664 efp_log("gradient calculation was not requested");
665 return EFP_RESULT_FATAL;
666 }
667 memcpy(grad, efp->ptc_grad, efp->n_ptc * sizeof(vec_t));
668 return EFP_RESULT_SUCCESS;
669 }
670
671 EFP_EXPORT enum efp_result
efp_get_point_charge_coordinates(struct efp * efp,double * xyz)672 efp_get_point_charge_coordinates(struct efp *efp, double *xyz)
673 {
674 assert(efp);
675 assert(xyz);
676
677 memcpy(xyz, efp->ptc_xyz, efp->n_ptc * sizeof(vec_t));
678 return EFP_RESULT_SUCCESS;
679 }
680
681 EFP_EXPORT enum efp_result
efp_set_point_charge_coordinates(struct efp * efp,const double * xyz)682 efp_set_point_charge_coordinates(struct efp *efp, const double *xyz)
683 {
684 assert(efp);
685 assert(xyz);
686
687 memcpy(efp->ptc_xyz, xyz, efp->n_ptc * sizeof(vec_t));
688 return EFP_RESULT_SUCCESS;
689 }
690
691 EFP_EXPORT enum efp_result
efp_get_point_charge_values(struct efp * efp,double * ptc)692 efp_get_point_charge_values(struct efp *efp, double *ptc)
693 {
694 assert(efp);
695 assert(ptc);
696
697 memcpy(ptc, efp->ptc, efp->n_ptc * sizeof(double));
698 return EFP_RESULT_SUCCESS;
699 }
700
701 EFP_EXPORT enum efp_result
efp_set_point_charge_values(struct efp * efp,const double * ptc)702 efp_set_point_charge_values(struct efp *efp, const double *ptc)
703 {
704 assert(efp);
705 assert(ptc);
706
707 memcpy(efp->ptc, ptc, efp->n_ptc * sizeof(double));
708 return EFP_RESULT_SUCCESS;
709 }
710
711 EFP_EXPORT enum efp_result
efp_set_coordinates(struct efp * efp,enum efp_coord_type coord_type,const double * coord)712 efp_set_coordinates(struct efp *efp, enum efp_coord_type coord_type,
713 const double *coord)
714 {
715 assert(efp);
716 assert(coord);
717
718 size_t stride;
719 enum efp_result res;
720
721 switch (coord_type) {
722 case EFP_COORD_TYPE_XYZABC:
723 stride = 6;
724 break;
725 case EFP_COORD_TYPE_POINTS:
726 stride = 9;
727 break;
728 case EFP_COORD_TYPE_ROTMAT:
729 stride = 12;
730 break;
731 }
732
733 for (size_t i = 0; i < efp->n_frag; i++, coord += stride)
734 if ((res = efp_set_frag_coordinates(efp, i, coord_type, coord)))
735 return res;
736
737 return EFP_RESULT_SUCCESS;
738 }
739
740 EFP_EXPORT enum efp_result
efp_set_frag_coordinates(struct efp * efp,size_t frag_idx,enum efp_coord_type coord_type,const double * coord)741 efp_set_frag_coordinates(struct efp *efp, size_t frag_idx,
742 enum efp_coord_type coord_type, const double *coord)
743 {
744 struct frag *frag;
745
746 assert(efp);
747 assert(coord);
748 assert(frag_idx < efp->n_frag);
749
750 frag = efp->frags + frag_idx;
751
752 switch (coord_type) {
753 case EFP_COORD_TYPE_XYZABC:
754 return set_coord_xyzabc(frag, coord);
755 case EFP_COORD_TYPE_POINTS:
756 return set_coord_points(frag, coord);
757 case EFP_COORD_TYPE_ROTMAT:
758 return set_coord_rotmat(frag, coord);
759 }
760 assert(0);
761 }
762
763 EFP_EXPORT enum efp_result
efp_get_coordinates(struct efp * efp,double * xyzabc)764 efp_get_coordinates(struct efp *efp, double *xyzabc)
765 {
766 assert(efp);
767 assert(xyzabc);
768
769 for (size_t i = 0; i < efp->n_frag; i++) {
770 struct frag *frag = efp->frags + i;
771
772 double a, b, c;
773 matrix_to_euler(&frag->rotmat, &a, &b, &c);
774
775 *xyzabc++ = frag->x;
776 *xyzabc++ = frag->y;
777 *xyzabc++ = frag->z;
778 *xyzabc++ = a;
779 *xyzabc++ = b;
780 *xyzabc++ = c;
781 }
782 return EFP_RESULT_SUCCESS;
783 }
784
785 EFP_EXPORT enum efp_result
efp_get_frag_xyzabc(struct efp * efp,size_t frag_idx,double * xyzabc)786 efp_get_frag_xyzabc(struct efp *efp, size_t frag_idx, double *xyzabc)
787 {
788 struct frag *frag;
789 double a, b, c;
790
791 assert(efp);
792 assert(frag_idx < efp->n_frag);
793 assert(xyzabc);
794
795 frag = efp->frags + frag_idx;
796 matrix_to_euler(&frag->rotmat, &a, &b, &c);
797
798 xyzabc[0] = frag->x;
799 xyzabc[1] = frag->y;
800 xyzabc[2] = frag->z;
801 xyzabc[3] = a;
802 xyzabc[4] = b;
803 xyzabc[5] = c;
804
805 return EFP_RESULT_SUCCESS;
806 }
807
808 EFP_EXPORT enum efp_result
efp_set_periodic_box(struct efp * efp,double x,double y,double z)809 efp_set_periodic_box(struct efp *efp, double x, double y, double z)
810 {
811 assert(efp);
812
813 if (x < 2.0 * efp->opts.swf_cutoff ||
814 y < 2.0 * efp->opts.swf_cutoff ||
815 z < 2.0 * efp->opts.swf_cutoff) {
816 efp_log("periodic box dimensions must be at least twice "
817 "the switching function cutoff");
818 return EFP_RESULT_FATAL;
819 }
820
821 efp->box.x = x;
822 efp->box.y = y;
823 efp->box.z = z;
824
825 return EFP_RESULT_SUCCESS;
826 }
827
828 EFP_EXPORT enum efp_result
efp_get_periodic_box(struct efp * efp,double * xyz)829 efp_get_periodic_box(struct efp *efp, double *xyz)
830 {
831 assert(efp);
832 assert(xyz);
833
834 xyz[0] = efp->box.x;
835 xyz[1] = efp->box.y;
836 xyz[2] = efp->box.z;
837
838 return EFP_RESULT_SUCCESS;
839 }
840
841 EFP_EXPORT enum efp_result
efp_get_stress_tensor(struct efp * efp,double * stress)842 efp_get_stress_tensor(struct efp *efp, double *stress)
843 {
844 assert(efp);
845 assert(stress);
846
847 if (!efp->do_gradient) {
848 efp_log("gradient calculation was not requested");
849 return EFP_RESULT_FATAL;
850 }
851
852 *(mat_t *)stress = efp->stress;
853
854 return EFP_RESULT_SUCCESS;
855 }
856
857 EFP_EXPORT enum efp_result
efp_get_ai_screen(struct efp * efp,size_t frag_idx,double * screen)858 efp_get_ai_screen(struct efp *efp, size_t frag_idx, double *screen)
859 {
860 const struct frag *frag;
861 size_t size;
862
863 assert(efp);
864 assert(screen);
865 assert(frag_idx < efp->n_frag);
866
867 frag = &efp->frags[frag_idx];
868
869 if (frag->ai_screen_params == NULL) {
870 efp_log("no screening parameters found for %s", frag->name);
871 return EFP_RESULT_FATAL;
872 }
873
874 size = frag->n_multipole_pts * sizeof(double);
875 memcpy(screen, frag->ai_screen_params, size);
876
877 return EFP_RESULT_SUCCESS;
878 }
879
880 EFP_EXPORT enum efp_result
efp_prepare(struct efp * efp)881 efp_prepare(struct efp *efp)
882 {
883 assert(efp);
884
885 efp->n_polarizable_pts = 0;
886
887 for (size_t i = 0; i < efp->n_frag; i++) {
888 efp->frags[i].polarizable_offset = efp->n_polarizable_pts;
889 efp->n_polarizable_pts += efp->frags[i].n_polarizable_pts;
890 }
891
892 efp->indip = (vec_t *)calloc(efp->n_polarizable_pts, sizeof(vec_t));
893 efp->indipconj = (vec_t *)calloc(efp->n_polarizable_pts, sizeof(vec_t));
894 efp->grad = (six_t *)calloc(efp->n_frag, sizeof(six_t));
895 efp->skiplist = (char *)calloc(efp->n_frag * efp->n_frag, 1);
896
897 return EFP_RESULT_SUCCESS;
898 }
899
900 EFP_EXPORT enum efp_result
efp_set_orbital_energies(struct efp * efp,size_t n_core,size_t n_act,size_t n_vir,const double * oe)901 efp_set_orbital_energies(struct efp *efp, size_t n_core, size_t n_act,
902 size_t n_vir, const double *oe)
903 {
904 size_t size;
905
906 assert(efp);
907 assert(oe);
908
909 efp->n_ai_core = n_core;
910 efp->n_ai_act = n_act;
911 efp->n_ai_vir = n_vir;
912
913 size = (n_core + n_act + n_vir) * sizeof(double);
914
915 efp->ai_orbital_energies = (double *)realloc(efp->ai_orbital_energies,
916 size);
917 memcpy(efp->ai_orbital_energies, oe, size);
918
919 return EFP_RESULT_SUCCESS;
920 }
921
922 EFP_EXPORT enum efp_result
efp_set_dipole_integrals(struct efp * efp,size_t n_core,size_t n_act,size_t n_vir,const double * dipint)923 efp_set_dipole_integrals(struct efp *efp, size_t n_core, size_t n_act,
924 size_t n_vir, const double *dipint)
925 {
926 size_t size;
927
928 assert(efp);
929 assert(dipint);
930
931 efp->n_ai_core = n_core;
932 efp->n_ai_act = n_act;
933 efp->n_ai_vir = n_vir;
934
935 size = 3 * (n_core + n_act + n_vir) * (n_core + n_act + n_vir);
936 efp->ai_dipole_integrals = (double *)realloc(efp->ai_dipole_integrals,
937 size * sizeof(double));
938 memcpy(efp->ai_dipole_integrals, dipint, size * sizeof(double));
939
940 return EFP_RESULT_SUCCESS;
941 }
942
943 EFP_EXPORT enum efp_result
efp_get_wavefunction_dependent_energy(struct efp * efp,double * energy)944 efp_get_wavefunction_dependent_energy(struct efp *efp, double *energy)
945 {
946 assert(efp);
947 assert(energy);
948
949 if (!(efp->opts.terms & EFP_TERM_POL) &&
950 !(efp->opts.terms & EFP_TERM_AI_POL)) {
951 *energy = 0.0;
952 return EFP_RESULT_SUCCESS;
953 }
954 return efp_compute_pol_energy(efp, energy);
955 }
956
957 EFP_EXPORT enum efp_result
efp_compute(struct efp * efp,int do_gradient)958 efp_compute(struct efp *efp, int do_gradient)
959 {
960 enum efp_result res;
961
962 assert(efp);
963
964 if (efp->grad == NULL) {
965 efp_log("call efp_prepare after all fragments are added");
966 return EFP_RESULT_FATAL;
967 }
968
969 efp->do_gradient = do_gradient;
970
971 if ((res = check_params(efp)))
972 return res;
973
974 memset(&efp->energy, 0, sizeof(efp->energy));
975 memset(&efp->stress, 0, sizeof(efp->stress));
976 memset(efp->grad, 0, efp->n_frag * sizeof(six_t));
977 memset(efp->ptc_grad, 0, efp->n_ptc * sizeof(vec_t));
978
979 efp_balance_work(efp, compute_two_body_range, NULL);
980
981 if ((res = efp_compute_pol(efp)))
982 return res;
983 if ((res = efp_compute_ai_elec(efp)))
984 return res;
985 if ((res = efp_compute_ai_disp(efp)))
986 return res;
987
988 #ifdef EFP_USE_MPI
989 efp_allreduce(&efp->energy.electrostatic, 1);
990 efp_allreduce(&efp->energy.dispersion, 1);
991 efp_allreduce(&efp->energy.exchange_repulsion, 1);
992 efp_allreduce(&efp->energy.charge_penetration, 1);
993
994 if (efp->do_gradient) {
995 efp_allreduce((double *)efp->grad, 6 * efp->n_frag);
996 efp_allreduce((double *)efp->ptc_grad, 3 * efp->n_ptc);
997 efp_allreduce((double *)&efp->stress, 9);
998 }
999 #endif
1000 efp->energy.total = efp->energy.electrostatic +
1001 efp->energy.charge_penetration +
1002 efp->energy.electrostatic_point_charges +
1003 efp->energy.polarization +
1004 efp->energy.dispersion +
1005 efp->energy.ai_dispersion +
1006 efp->energy.exchange_repulsion;
1007
1008 return EFP_RESULT_SUCCESS;
1009 }
1010
1011 EFP_EXPORT enum efp_result
efp_get_frag_charge(struct efp * efp,size_t frag_idx,double * charge)1012 efp_get_frag_charge(struct efp *efp, size_t frag_idx, double *charge)
1013 {
1014 struct frag *frag;
1015 double sum = 0.0;
1016 size_t i;
1017
1018 assert(efp);
1019 assert(charge);
1020 assert(frag_idx < efp->n_frag);
1021
1022 frag = efp->frags + frag_idx;
1023
1024 for (i = 0; i < frag->n_atoms; i++)
1025 sum += frag->atoms[i].znuc;
1026 for (i = 0; i < frag->n_multipole_pts; i++)
1027 sum += frag->multipole_pts[i].monopole;
1028
1029 *charge = sum;
1030 return EFP_RESULT_SUCCESS;
1031 }
1032
1033 EFP_EXPORT enum efp_result
efp_get_frag_multiplicity(struct efp * efp,size_t frag_idx,int * mult)1034 efp_get_frag_multiplicity(struct efp *efp, size_t frag_idx, int *mult)
1035 {
1036 assert(efp);
1037 assert(mult);
1038 assert(frag_idx < efp->n_frag);
1039
1040 *mult = efp->frags[frag_idx].multiplicity;
1041 return EFP_RESULT_SUCCESS;
1042 }
1043
1044 EFP_EXPORT enum efp_result
efp_get_frag_multipole_count(struct efp * efp,size_t frag_idx,size_t * n_mult)1045 efp_get_frag_multipole_count(struct efp *efp, size_t frag_idx, size_t *n_mult)
1046 {
1047 assert(efp);
1048 assert(n_mult);
1049 assert(frag_idx < efp->n_frag);
1050
1051 *n_mult = efp->frags[frag_idx].n_multipole_pts;
1052 return EFP_RESULT_SUCCESS;
1053 }
1054
1055 EFP_EXPORT enum efp_result
efp_get_multipole_count(struct efp * efp,size_t * n_mult)1056 efp_get_multipole_count(struct efp *efp, size_t *n_mult)
1057 {
1058 size_t sum = 0;
1059
1060 assert(efp);
1061 assert(n_mult);
1062
1063 for (size_t i = 0; i < efp->n_frag; i++)
1064 sum += efp->frags[i].n_multipole_pts;
1065
1066 *n_mult = sum;
1067 return EFP_RESULT_SUCCESS;
1068 }
1069
1070 EFP_EXPORT enum efp_result
efp_get_multipole_coordinates(struct efp * efp,double * xyz)1071 efp_get_multipole_coordinates(struct efp *efp, double *xyz)
1072 {
1073 assert(efp);
1074 assert(xyz);
1075
1076 for (size_t i = 0; i < efp->n_frag; i++) {
1077 struct frag *frag = efp->frags + i;
1078
1079 for (size_t j = 0; j < frag->n_multipole_pts; j++) {
1080 *xyz++ = frag->multipole_pts[j].x;
1081 *xyz++ = frag->multipole_pts[j].y;
1082 *xyz++ = frag->multipole_pts[j].z;
1083 }
1084 }
1085 return EFP_RESULT_SUCCESS;
1086 }
1087
1088 EFP_EXPORT enum efp_result
efp_get_multipole_values(struct efp * efp,double * mult)1089 efp_get_multipole_values(struct efp *efp, double *mult)
1090 {
1091 assert(efp);
1092 assert(mult);
1093
1094 for (size_t i = 0; i < efp->n_frag; i++) {
1095 struct frag *frag = efp->frags + i;
1096
1097 for (size_t j = 0; j < frag->n_multipole_pts; j++) {
1098 struct multipole_pt *pt = frag->multipole_pts + j;
1099
1100 *mult++ = pt->monopole;
1101
1102 *mult++ = pt->dipole.x;
1103 *mult++ = pt->dipole.y;
1104 *mult++ = pt->dipole.z;
1105
1106 for (size_t t = 0; t < 6; t++)
1107 *mult++ = pt->quadrupole[t];
1108 for (size_t t = 0; t < 10; t++)
1109 *mult++ = pt->octupole[t];
1110 }
1111 }
1112 return EFP_RESULT_SUCCESS;
1113 }
1114
1115 EFP_EXPORT enum efp_result
efp_get_induced_dipole_count(struct efp * efp,size_t * n_dip)1116 efp_get_induced_dipole_count(struct efp *efp, size_t *n_dip)
1117 {
1118 size_t sum = 0;
1119
1120 assert(efp);
1121 assert(n_dip);
1122
1123 for (size_t i = 0; i < efp->n_frag; i++)
1124 sum += efp->frags[i].n_polarizable_pts;
1125
1126 *n_dip = sum;
1127 return EFP_RESULT_SUCCESS;
1128 }
1129
1130 EFP_EXPORT enum efp_result
efp_get_induced_dipole_coordinates(struct efp * efp,double * xyz)1131 efp_get_induced_dipole_coordinates(struct efp *efp, double *xyz)
1132 {
1133 assert(efp);
1134 assert(xyz);
1135
1136 for (size_t i = 0; i < efp->n_frag; i++) {
1137 struct frag *frag = efp->frags + i;
1138
1139 for (size_t j = 0; j < frag->n_polarizable_pts; j++) {
1140 struct polarizable_pt *pt = frag->polarizable_pts + j;
1141
1142 *xyz++ = pt->x;
1143 *xyz++ = pt->y;
1144 *xyz++ = pt->z;
1145 }
1146 }
1147 return EFP_RESULT_SUCCESS;
1148 }
1149
1150 EFP_EXPORT enum efp_result
efp_get_induced_dipole_values(struct efp * efp,double * dip)1151 efp_get_induced_dipole_values(struct efp *efp, double *dip)
1152 {
1153 assert(efp);
1154 assert(dip);
1155
1156 memcpy(dip, efp->indip, efp->n_polarizable_pts * sizeof(vec_t));
1157 return EFP_RESULT_SUCCESS;
1158 }
1159
1160 EFP_EXPORT enum efp_result
efp_get_induced_dipole_conj_values(struct efp * efp,double * dip)1161 efp_get_induced_dipole_conj_values(struct efp *efp, double *dip)
1162 {
1163 assert(efp);
1164 assert(dip);
1165
1166 memcpy(dip, efp->indipconj, efp->n_polarizable_pts * sizeof(vec_t));
1167 return EFP_RESULT_SUCCESS;
1168 }
1169
1170 EFP_EXPORT enum efp_result
efp_get_lmo_count(struct efp * efp,size_t frag_idx,size_t * n_lmo)1171 efp_get_lmo_count(struct efp *efp, size_t frag_idx, size_t *n_lmo)
1172 {
1173 assert(efp != NULL);
1174 assert(frag_idx < efp->n_frag);
1175 assert(n_lmo != NULL);
1176
1177 *n_lmo = efp->frags[frag_idx].n_lmo;
1178 return EFP_RESULT_SUCCESS;
1179 }
1180
1181 EFP_EXPORT enum efp_result
efp_get_lmo_coordinates(struct efp * efp,size_t frag_idx,double * xyz)1182 efp_get_lmo_coordinates(struct efp *efp, size_t frag_idx, double *xyz)
1183 {
1184 struct frag *frag;
1185
1186 assert(efp != NULL);
1187 assert(frag_idx < efp->n_frag);
1188 assert(xyz != NULL);
1189
1190 frag = efp->frags + frag_idx;
1191
1192 if (frag->lmo_centroids == NULL) {
1193 efp_log("no LMO centroids for fragment %s", frag->name);
1194 return EFP_RESULT_FATAL;
1195 }
1196 memcpy(xyz, frag->lmo_centroids, frag->n_lmo * sizeof(vec_t));
1197 return EFP_RESULT_SUCCESS;
1198 }
1199
1200 EFP_EXPORT enum efp_result
efp_get_xrfit(struct efp * efp,size_t frag_idx,double * xrfit)1201 efp_get_xrfit(struct efp *efp, size_t frag_idx, double *xrfit)
1202 {
1203 struct frag *frag;
1204
1205 assert(efp != NULL);
1206 assert(frag_idx < efp->n_frag);
1207 assert(xrfit != NULL);
1208
1209 frag = efp->frags + frag_idx;
1210
1211 if (frag->xrfit == NULL) {
1212 efp_log("no XRFIT parameters for fragment %s", frag->name);
1213 return EFP_RESULT_FATAL;
1214 }
1215 memcpy(xrfit, frag->xrfit, frag->n_lmo * 4 * sizeof(double));
1216 return EFP_RESULT_SUCCESS;
1217 }
1218
1219 EFP_EXPORT void
efp_shutdown(struct efp * efp)1220 efp_shutdown(struct efp *efp)
1221 {
1222 if (efp == NULL)
1223 return;
1224 for (size_t i = 0; i < efp->n_frag; i++)
1225 free_frag(efp->frags + i);
1226 for (size_t i = 0; i < efp->n_lib; i++) {
1227 free_frag(efp->lib[i]);
1228 free(efp->lib[i]);
1229 }
1230 free(efp->frags);
1231 free(efp->lib);
1232 free(efp->grad);
1233 free(efp->ptc);
1234 free(efp->ptc_xyz);
1235 free(efp->ptc_grad);
1236 free(efp->indip);
1237 free(efp->indipconj);
1238 free(efp->ai_orbital_energies);
1239 free(efp->ai_dipole_integrals);
1240 free(efp->skiplist);
1241 free(efp);
1242 }
1243
1244 EFP_EXPORT enum efp_result
efp_set_opts(struct efp * efp,const struct efp_opts * opts)1245 efp_set_opts(struct efp *efp, const struct efp_opts *opts)
1246 {
1247 enum efp_result res;
1248
1249 assert(efp);
1250 assert(opts);
1251
1252 if ((res = check_opts(opts)))
1253 return res;
1254
1255 efp->opts = *opts;
1256 return EFP_RESULT_SUCCESS;
1257 }
1258
1259 EFP_EXPORT enum efp_result
efp_get_opts(struct efp * efp,struct efp_opts * opts)1260 efp_get_opts(struct efp *efp, struct efp_opts *opts)
1261 {
1262 assert(efp);
1263 assert(opts);
1264
1265 *opts = efp->opts;
1266 return EFP_RESULT_SUCCESS;
1267 }
1268
1269 EFP_EXPORT void
efp_opts_default(struct efp_opts * opts)1270 efp_opts_default(struct efp_opts *opts)
1271 {
1272 assert(opts);
1273
1274 memset(opts, 0, sizeof(*opts));
1275 opts->terms = EFP_TERM_ELEC | EFP_TERM_POL | EFP_TERM_DISP |
1276 EFP_TERM_XR | EFP_TERM_AI_ELEC | EFP_TERM_AI_POL;
1277 }
1278
1279 EFP_EXPORT void
efp_set_error_log(void (* cb)(const char *))1280 efp_set_error_log(void (*cb)(const char *))
1281 {
1282 efp_set_log_cb(cb);
1283 }
1284
1285 EFP_EXPORT enum efp_result
efp_add_fragment(struct efp * efp,const char * name)1286 efp_add_fragment(struct efp *efp, const char *name)
1287 {
1288 const struct frag *lib;
1289
1290 assert(efp);
1291 assert(name);
1292
1293 if (efp->skiplist) {
1294 efp_log("cannot add fragments after efp_prepare");
1295 return EFP_RESULT_FATAL;
1296 }
1297 if ((lib = efp_find_lib(efp, name)) == NULL) {
1298 efp_log("cannot find \"%s\" in any of .efp files", name);
1299 return EFP_RESULT_UNKNOWN_FRAGMENT;
1300 }
1301
1302 efp->n_frag++;
1303 efp->frags = (struct frag *)realloc(efp->frags,
1304 efp->n_frag * sizeof(struct frag));
1305 if (efp->frags == NULL)
1306 return EFP_RESULT_NO_MEMORY;
1307
1308 enum efp_result res;
1309 struct frag *frag = efp->frags + efp->n_frag - 1;
1310
1311 if ((res = copy_frag(frag, lib)))
1312 return res;
1313
1314 for (size_t a = 0; a < 3; a++) {
1315 size_t size = frag->xr_wf_size * frag->n_lmo;
1316
1317 frag->xr_wf_deriv[a] = (double *)calloc(size, sizeof(double));
1318 if (frag->xr_wf_deriv[a] == NULL)
1319 return EFP_RESULT_NO_MEMORY;
1320 }
1321 return EFP_RESULT_SUCCESS;
1322 }
1323
1324 EFP_EXPORT enum efp_result
efp_skip_fragments(struct efp * efp,size_t i,size_t j,int value)1325 efp_skip_fragments(struct efp *efp, size_t i, size_t j, int value)
1326 {
1327 assert(efp);
1328 assert(efp->skiplist); /* call efp_prepare first */
1329 assert(i < efp->n_frag);
1330 assert(j < efp->n_frag);
1331
1332 efp->skiplist[i * efp->n_frag + j] = value ? 1 : 0;
1333 efp->skiplist[j * efp->n_frag + i] = value ? 1 : 0;
1334
1335 return EFP_RESULT_SUCCESS;
1336 }
1337
1338 EFP_EXPORT struct efp *
efp_create(void)1339 efp_create(void)
1340 {
1341 struct efp *efp = (struct efp *)calloc(1, sizeof(struct efp));
1342
1343 if (efp == NULL)
1344 return NULL;
1345
1346 efp_opts_default(&efp->opts);
1347
1348 return efp;
1349 }
1350
1351 EFP_EXPORT enum efp_result
efp_set_electron_density_field_fn(struct efp * efp,efp_electron_density_field_fn fn)1352 efp_set_electron_density_field_fn(struct efp *efp,
1353 efp_electron_density_field_fn fn)
1354 {
1355 assert(efp);
1356
1357 efp->get_electron_density_field = fn;
1358
1359 return EFP_RESULT_SUCCESS;
1360 }
1361
1362 EFP_EXPORT enum efp_result
efp_set_electron_density_field_user_data(struct efp * efp,void * user_data)1363 efp_set_electron_density_field_user_data(struct efp *efp, void *user_data)
1364 {
1365 assert(efp);
1366
1367 efp->get_electron_density_field_user_data = user_data;
1368
1369 return EFP_RESULT_SUCCESS;
1370 }
1371
1372 EFP_EXPORT enum efp_result
efp_get_frag_count(struct efp * efp,size_t * n_frag)1373 efp_get_frag_count(struct efp *efp, size_t *n_frag)
1374 {
1375 assert(efp);
1376 assert(n_frag);
1377
1378 *n_frag = efp->n_frag;
1379
1380 return EFP_RESULT_SUCCESS;
1381 }
1382
1383 EFP_EXPORT enum efp_result
efp_get_frag_name(struct efp * efp,size_t frag_idx,size_t size,char * frag_name)1384 efp_get_frag_name(struct efp *efp, size_t frag_idx, size_t size,
1385 char *frag_name)
1386 {
1387 assert(efp);
1388 assert(frag_name);
1389 assert(frag_idx < efp->n_frag);
1390
1391 strncpy(frag_name, efp->frags[frag_idx].name, size);
1392
1393 return EFP_RESULT_SUCCESS;
1394 }
1395
1396 EFP_EXPORT enum efp_result
efp_get_frag_mass(struct efp * efp,size_t frag_idx,double * mass_out)1397 efp_get_frag_mass(struct efp *efp, size_t frag_idx, double *mass_out)
1398 {
1399 assert(efp);
1400 assert(mass_out);
1401 assert(frag_idx < efp->n_frag);
1402
1403 const struct frag *frag = efp->frags + frag_idx;
1404 double mass = 0.0;
1405
1406 for (size_t i = 0; i < frag->n_atoms; i++)
1407 mass += frag->atoms[i].mass;
1408
1409 *mass_out = mass;
1410
1411 return EFP_RESULT_SUCCESS;
1412 }
1413
1414 EFP_EXPORT enum efp_result
efp_get_frag_inertia(struct efp * efp,size_t frag_idx,double * inertia_out)1415 efp_get_frag_inertia(struct efp *efp, size_t frag_idx, double *inertia_out)
1416 {
1417 assert(efp);
1418 assert(inertia_out);
1419 assert(frag_idx < efp->n_frag);
1420
1421 /* center of mass is in origin and axes are principal axes of inertia */
1422
1423 const struct frag *frag = efp->frags[frag_idx].lib;
1424 vec_t inertia = vec_zero;
1425
1426 for (size_t i = 0; i < frag->n_atoms; i++) {
1427 const struct efp_atom *atom = frag->atoms + i;
1428
1429 inertia.x += atom->mass * (atom->y*atom->y + atom->z*atom->z);
1430 inertia.y += atom->mass * (atom->x*atom->x + atom->z*atom->z);
1431 inertia.z += atom->mass * (atom->x*atom->x + atom->y*atom->y);
1432 }
1433
1434 inertia_out[0] = inertia.x;
1435 inertia_out[1] = inertia.y;
1436 inertia_out[2] = inertia.z;
1437
1438 return EFP_RESULT_SUCCESS;
1439 }
1440
1441 EFP_EXPORT enum efp_result
efp_get_frag_atom_count(struct efp * efp,size_t frag_idx,size_t * n_atoms)1442 efp_get_frag_atom_count(struct efp *efp, size_t frag_idx, size_t *n_atoms)
1443 {
1444 assert(efp);
1445 assert(n_atoms);
1446 assert(frag_idx < efp->n_frag);
1447
1448 *n_atoms = efp->frags[frag_idx].n_atoms;
1449
1450 return EFP_RESULT_SUCCESS;
1451 }
1452
1453 EFP_EXPORT enum efp_result
efp_get_frag_atoms(struct efp * efp,size_t frag_idx,size_t size,struct efp_atom * atoms)1454 efp_get_frag_atoms(struct efp *efp, size_t frag_idx, size_t size,
1455 struct efp_atom *atoms)
1456 {
1457 struct frag *frag;
1458
1459 assert(efp);
1460 assert(atoms);
1461 assert(frag_idx < efp->n_frag);
1462 assert(size >= efp->frags[frag_idx].n_atoms);
1463
1464 frag = efp->frags + frag_idx;
1465 memcpy(atoms, frag->atoms, frag->n_atoms * sizeof(struct efp_atom));
1466
1467 return EFP_RESULT_SUCCESS;
1468 }
1469
1470 EFP_EXPORT void
efp_torque_to_derivative(const double * euler,const double * torque,double * deriv)1471 efp_torque_to_derivative(const double *euler, const double *torque,
1472 double *deriv)
1473 {
1474 assert(euler);
1475 assert(torque);
1476 assert(deriv);
1477
1478 double tx = torque[0];
1479 double ty = torque[1];
1480 double tz = torque[2];
1481
1482 double sina = sin(euler[0]);
1483 double cosa = cos(euler[0]);
1484 double sinb = sin(euler[1]);
1485 double cosb = cos(euler[1]);
1486
1487 deriv[0] = tz;
1488 deriv[1] = cosa * tx + sina * ty;
1489 deriv[2] = sinb * sina * tx - sinb * cosa * ty + cosb * tz;
1490 }
1491
1492 EFP_EXPORT const char *
efp_banner(void)1493 efp_banner(void)
1494 {
1495 static const char banner[] =
1496 "LIBEFP ver. " LIBEFP_VERSION_STRING "\n"
1497 "Copyright (c) 2012-2017 Ilya Kaliman\n"
1498 "\n"
1499 "Journal References:\n"
1500 " - Kaliman and Slipchenko, JCC 2013.\n"
1501 " DOI: http://dx.doi.org/10.1002/jcc.23375\n"
1502 " - Kaliman and Slipchenko, JCC 2015.\n"
1503 " DOI: http://dx.doi.org/10.1002/jcc.23772\n"
1504 "\n"
1505 "Project web site: https://libefp.github.io/\n";
1506
1507 return banner;
1508 }
1509
1510 EFP_EXPORT void
efp_print_banner(void)1511 efp_print_banner(void)
1512 {
1513 puts(efp_banner());
1514 }
1515
1516 EFP_EXPORT const char *
efp_result_to_string(enum efp_result res)1517 efp_result_to_string(enum efp_result res)
1518 {
1519 switch (res) {
1520 case EFP_RESULT_SUCCESS:
1521 return "Operation was successful.";
1522 case EFP_RESULT_FATAL:
1523 return "Fatal error has occurred.";
1524 case EFP_RESULT_NO_MEMORY:
1525 return "Insufficient memory.";
1526 case EFP_RESULT_FILE_NOT_FOUND:
1527 return "File not found.";
1528 case EFP_RESULT_SYNTAX_ERROR:
1529 return "Syntax error.";
1530 case EFP_RESULT_UNKNOWN_FRAGMENT:
1531 return "Unknown EFP fragment.";
1532 case EFP_RESULT_POL_NOT_CONVERGED:
1533 return "Polarization SCF procedure did not converge.";
1534 }
1535 assert(0);
1536 }
1537