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