static enum efp_result check_opts(const struct efp_opts *opts) { if (opts->enable_pbc) { if ((opts->terms & EFP_TERM_AI_ELEC) || (opts->terms & EFP_TERM_AI_POL) || (opts->terms & EFP_TERM_AI_DISP) || (opts->terms & EFP_TERM_AI_XR) || (opts->terms & EFP_TERM_AI_CHTR)) { efp_log("periodic calculations are not supported for QM/EFP"); return EFP_RESULT_FATAL; } if (!opts->enable_cutoff) { efp_log("periodic calculations require interaction cutoff"); return EFP_RESULT_FATAL; } } if (opts->enable_cutoff) { if (opts->swf_cutoff < 1.0) { efp_log("interaction cutoff is too small"); return EFP_RESULT_FATAL; } } return EFP_RESULT_SUCCESS; }
static enum efp_result set_coord_points(struct frag *frag, const double *coord) { if (frag->n_atoms < 3) { efp_log("fragment must contain at least three atoms"); return EFP_RESULT_FATAL; } double ref[9] = { frag->lib->atoms[0].x, frag->lib->atoms[0].y, frag->lib->atoms[0].z, frag->lib->atoms[1].x, frag->lib->atoms[1].y, frag->lib->atoms[1].z, frag->lib->atoms[2].x, frag->lib->atoms[2].y, frag->lib->atoms[2].z }; vec_t p1; mat_t rot1, rot2; efp_points_to_matrix(coord, &rot1); efp_points_to_matrix(ref, &rot2); rot2 = mat_transpose(&rot2); frag->rotmat = mat_mat(&rot1, &rot2); p1 = mat_vec(&frag->rotmat, VEC(frag->lib->atoms[0].x)); /* center of mass */ frag->x = coord[0] - p1.x; frag->y = coord[1] - p1.y; frag->z = coord[2] - p1.z; update_fragment(frag); return EFP_RESULT_SUCCESS; }
enum efp_result efp_compute_id_direct(struct efp *efp) { double *c; size_t n; fortranint_t *ipiv; enum efp_result res; n = 3 * efp->n_polarizable_pts; c = (double *)calloc(n * n, sizeof *c); ipiv = (fortranint_t *)calloc(n, sizeof *ipiv); if (c == NULL || ipiv == NULL) { res = EFP_RESULT_NO_MEMORY; goto error; } /* induced dipoles */ compute_lhs(efp, c, 0); compute_rhs(efp, efp->indip, 0); transpose_matrix(c, n); if (efp_dgesv((fortranint_t)n, 1, c, (fortranint_t)n, ipiv, (double *)efp->indip, (fortranint_t)n) != 0) { efp_log("dgesv: error solving for induced dipoles"); res = EFP_RESULT_FATAL; goto error; } /* conjugate induced dipoles */ compute_lhs(efp, c, 1); compute_rhs(efp, efp->indipconj, 1); transpose_matrix(c, n); if (efp_dgesv((fortranint_t)n, 1, c, (fortranint_t)n, ipiv, (double *)efp->indipconj, (fortranint_t)n) != 0) { efp_log("dgesv: error solving for conjugate induced dipoles"); res = EFP_RESULT_FATAL; goto error; } res = EFP_RESULT_SUCCESS; error: free(c); free(ipiv); return res; }
EFP_EXPORT enum efp_result efp_compute(struct efp *efp, int do_gradient) { enum efp_result res; assert(efp); if (efp->grad == NULL) { efp_log("call efp_prepare after all fragments are added"); return (EFP_RESULT_FATAL); } efp->do_gradient = do_gradient; if ((res = check_params(efp))) return (res); memset(&efp->energy, 0, sizeof(struct efp_energy)); memset(&efp->stress, 0, sizeof(mat_t)); memset(efp->grad, 0, efp->n_frag * sizeof(six_t)); memset(efp->ptc_grad, 0, efp->n_ptc * sizeof(vec_t)); efp_balance_work(efp, compute_two_body_range, NULL); if ((res = efp_compute_pol(efp))) return res; if ((res = efp_compute_ai_elec(efp))) return res; if ((res = efp_compute_ai_disp(efp))) return res; #ifdef WITH_MPI efp_allreduce(&efp->energy.electrostatic, 1); efp_allreduce(&efp->energy.dispersion, 1); efp_allreduce(&efp->energy.exchange_repulsion, 1); efp_allreduce(&efp->energy.charge_penetration, 1); if (efp->do_gradient) { efp_allreduce((double *)efp->grad, 6 * efp->n_frag); efp_allreduce((double *)efp->ptc_grad, 3 * efp->n_ptc); efp_allreduce((double *)&efp->stress, 9); } #endif efp->energy.total = efp->energy.electrostatic + efp->energy.charge_penetration + efp->energy.electrostatic_point_charges + efp->energy.polarization + efp->energy.dispersion + efp->energy.ai_dispersion + efp->energy.exchange_repulsion; return EFP_RESULT_SUCCESS; }
EFP_EXPORT enum efp_result efp_get_stress_tensor(struct efp *efp, double *stress) { assert(efp); assert(stress); if (!efp->do_gradient) { efp_log("gradient calculation was not requested"); return (EFP_RESULT_FATAL); } *(mat_t *)stress = efp->stress; return (EFP_RESULT_SUCCESS); }
EFP_EXPORT enum efp_result efp_get_point_charge_gradient(struct efp *efp, double *grad) { assert(efp); assert(grad); if (!efp->do_gradient) { efp_log("gradient calculation was not requested"); return (EFP_RESULT_FATAL); } memcpy(grad, efp->ptc_grad, efp->n_ptc * sizeof(vec_t)); return (EFP_RESULT_SUCCESS); }
static enum efp_result set_coord_rotmat(struct frag *frag, const double *coord) { if (!efp_check_rotation_matrix((const mat_t *)(coord + 3))) { efp_log("invalid rotation matrix specified"); return EFP_RESULT_FATAL; } frag->x = coord[0]; frag->y = coord[1]; frag->z = coord[2]; memcpy(&frag->rotmat, coord + 3, sizeof(mat_t)); update_fragment(frag); return EFP_RESULT_SUCCESS; }
EFP_EXPORT enum efp_result efp_set_periodic_box(struct efp *efp, double x, double y, double z) { assert(efp); if (x < 2.0 * efp->opts.swf_cutoff || y < 2.0 * efp->opts.swf_cutoff || z < 2.0 * efp->opts.swf_cutoff) { efp_log("periodic box dimensions must be at least twice the cutoff"); return EFP_RESULT_FATAL; } efp->box.x = x; efp->box.y = y; efp->box.z = z; return EFP_RESULT_SUCCESS; }
EFP_EXPORT enum efp_result efp_get_xrfit(struct efp *efp, size_t frag_idx, double *xrfit) { struct frag *frag; assert(efp != NULL); assert(frag_idx < efp->n_frag); assert(xrfit != NULL); frag = efp->frags + frag_idx; if (frag->xrfit == NULL) { efp_log("no XRFIT parameters for fragment %s", frag->name); return (EFP_RESULT_FATAL); } memcpy(xrfit, frag->xrfit, frag->n_lmo * 4 * sizeof(double)); return (EFP_RESULT_SUCCESS); }
EFP_EXPORT enum efp_result efp_get_lmo_coordinates(struct efp *efp, size_t frag_idx, double *xyz) { struct frag *frag; assert(efp != NULL); assert(frag_idx < efp->n_frag); assert(xyz != NULL); frag = efp->frags + frag_idx; if (frag->lmo_centroids == NULL) { efp_log("no LMO centroids for fragment %s", frag->name); return (EFP_RESULT_FATAL); } memcpy(xyz, frag->lmo_centroids, frag->n_lmo * sizeof(vec_t)); return (EFP_RESULT_SUCCESS); }
EFP_EXPORT enum efp_result efp_get_ai_screen(struct efp *efp, size_t frag_idx, double *screen) { const struct frag *frag; size_t size; assert(efp); assert(screen); assert(frag_idx < efp->n_frag); frag = &efp->frags[frag_idx]; if (frag->ai_screen_params == NULL) { efp_log("no screening parameters found for %s", frag->name); return (EFP_RESULT_FATAL); } size = frag->n_multipole_pts * sizeof(double); memcpy(screen, frag->ai_screen_params, size); return (EFP_RESULT_SUCCESS); }
static enum efp_result set_coord_points(struct frag *frag, const double *coord) { /* allow fragments with less than 3 atoms by using multipole points of * ghost atoms; multipole points have the same coordinates as atoms */ if (frag->n_multipole_pts < 3) { efp_log("fragment must contain at least three atoms"); return EFP_RESULT_FATAL; } double ref[9] = { frag->lib->multipole_pts[0].x, frag->lib->multipole_pts[0].y, frag->lib->multipole_pts[0].z, frag->lib->multipole_pts[1].x, frag->lib->multipole_pts[1].y, frag->lib->multipole_pts[1].z, frag->lib->multipole_pts[2].x, frag->lib->multipole_pts[2].y, frag->lib->multipole_pts[2].z }; vec_t p1; mat_t rot1, rot2; efp_points_to_matrix(coord, &rot1); efp_points_to_matrix(ref, &rot2); rot2 = mat_transpose(&rot2); frag->rotmat = mat_mat(&rot1, &rot2); p1 = mat_vec(&frag->rotmat, VEC(frag->lib->multipole_pts[0].x)); /* center of mass */ frag->x = coord[0] - p1.x; frag->y = coord[1] - p1.y; frag->z = coord[2] - p1.z; update_fragment(frag); return EFP_RESULT_SUCCESS; }
EFP_EXPORT enum efp_result efp_add_fragment(struct efp *efp, const char *name) { assert(efp); assert(name); enum efp_result res; const struct frag *lib = efp_find_lib(efp, name); if (!lib) { efp_log("unknown fragment \"%s\"; check its .efp file", name); return EFP_RESULT_UNKNOWN_FRAGMENT; } efp->n_frag++; efp->frags = (struct frag *)realloc(efp->frags, efp->n_frag * sizeof(struct frag)); if (!efp->frags) return EFP_RESULT_NO_MEMORY; struct frag *frag = efp->frags + efp->n_frag - 1; if ((res = copy_frag(frag, lib))) return res; for (size_t a = 0; a < 3; a++) { size_t size = frag->xr_wf_size * frag->n_lmo; frag->xr_wf_deriv[a] = (double *)calloc(size, sizeof(double)); if (!frag->xr_wf_deriv[a]) return EFP_RESULT_NO_MEMORY; } return EFP_RESULT_SUCCESS; }
static enum efp_result check_frag_params(const struct efp_opts *opts, const struct frag *frag) { if ((opts->terms & EFP_TERM_ELEC) || (opts->terms & EFP_TERM_AI_ELEC)) { if (!frag->multipole_pts) { efp_log("electrostatic parameters are missing"); return EFP_RESULT_FATAL; } if (opts->elec_damp == EFP_ELEC_DAMP_SCREEN && !frag->screen_params) { efp_log("screening parameters are missing"); return EFP_RESULT_FATAL; } } if ((opts->terms & EFP_TERM_POL) || (opts->terms & EFP_TERM_AI_POL)) { if (!frag->polarizable_pts || !frag->multipole_pts) { efp_log("polarization parameters are missing"); return EFP_RESULT_FATAL; } } if ((opts->terms & EFP_TERM_DISP) || (opts->terms & EFP_TERM_AI_DISP)) { if (!frag->dynamic_polarizable_pts) { efp_log("dispersion parameters are missing"); return EFP_RESULT_FATAL; } if (opts->disp_damp == EFP_DISP_DAMP_OVERLAP && frag->n_lmo != frag->n_dynamic_polarizable_pts) { efp_log("number of polarization points does not match number of LMOs"); return EFP_RESULT_FATAL; } } if ((opts->terms & EFP_TERM_XR) || (opts->terms & EFP_TERM_AI_XR)) { if (!frag->xr_atoms || !frag->xr_fock_mat || !frag->xr_wf || !frag->lmo_centroids) { efp_log("exchange repulsion parameters are missing"); return EFP_RESULT_FATAL; } } return EFP_RESULT_SUCCESS; }