static void mass_weight_hessian(struct efp *efp, const double *in, double *out) { size_t n_frags, n_coord; check_fail(efp_get_frag_count(efp, &n_frags)); n_coord = 6 * n_frags; double mass_fact[n_frags]; mat_t inertia_fact[n_frags]; get_weight_factor(efp, mass_fact, inertia_fact); for (size_t i = 0; i < n_frags; i++) { for (size_t j = 0; j < n_frags; j++) { size_t offset = 6 * n_coord * i + 6 * j; w_tr_tr(mass_fact[i], mass_fact[j], n_coord, in + offset, out + offset); w_tr_rot(mass_fact[i], inertia_fact + j, n_coord, in + offset + 3, out + offset + 3); w_rot_tr(inertia_fact + i, mass_fact[j], n_coord, in + offset + 3 * n_coord, out + offset + 3 * n_coord); w_rot_rot(inertia_fact + i, inertia_fact + j, n_coord, in + offset + 3 * n_coord + 3, out + offset + 3 * n_coord + 3); } } }
static void get_weight_factor(struct efp *efp, double *mass_fact, mat_t *inertia_fact) { size_t n_frags; check_fail(efp_get_frag_count(efp, &n_frags)); double xyzabc[6 * n_frags]; check_fail(efp_get_coordinates(efp, xyzabc)); for (size_t i = 0; i < n_frags; i++) { double mass; check_fail(efp_get_frag_mass(efp, i, &mass)); double inertia[3]; check_fail(efp_get_frag_inertia(efp, i, inertia)); double a = xyzabc[6 * i + 3]; double b = xyzabc[6 * i + 4]; double c = xyzabc[6 * i + 5]; mat_t rotmat; euler_to_matrix(a, b, c, &rotmat); mass_fact[i] = 1.0 / sqrt(mass); get_inertia_factor(inertia, &rotmat, inertia_fact + i); } }
void sim_hess(struct state *state) { msg("HESSIAN JOB\n\n\n"); print_geometry(state->efp); compute_energy(state, true); print_energy(state); print_gradient(state); size_t n_frags, n_coord; double *hess, *mass_hess, *eigen; check_fail(efp_get_frag_count(state->efp, &n_frags)); n_coord = 6 * n_frags; hess = xmalloc(n_coord * n_coord * sizeof(double)); compute_hessian(state, hess); msg(" HESSIAN MATRIX\n\n"); print_matrix(n_coord, n_coord, hess); mass_hess = xmalloc(n_coord * n_coord * sizeof(double)); mass_weight_hessian(state->efp, hess, mass_hess); msg(" MASS-WEIGHTED HESSIAN MATRIX\n\n"); print_matrix(n_coord, n_coord, mass_hess); msg(" NORMAL MODE ANALYSIS\n\n"); eigen = xmalloc(n_coord * sizeof(double)); if (efp_dsyev('V', 'U', (int)n_coord, mass_hess, (int)n_coord, eigen)) error("unable to diagonalize mass-weighted hessian matrix"); for (size_t i = 0; i < n_coord; i++) { print_mode(i + 1, eigen[i]); print_vector(n_coord, mass_hess + i * n_coord); } free(hess); free(mass_hess); free(eigen); msg("HESSIAN JOB COMPLETED SUCCESSFULLY\n"); }
static void compute_hessian(struct state *state, double *hess) { size_t n_frags, n_coord; double *xyzabc, *grad_f, *grad_b; bool central = cfg_get_bool(state->cfg, "hess_central"); check_fail(efp_get_frag_count(state->efp, &n_frags)); n_coord = 6 * n_frags; xyzabc = xmalloc(n_coord * sizeof(double)); grad_f = xmalloc(n_coord * sizeof(double)); grad_b = xmalloc(n_coord * sizeof(double)); check_fail(efp_get_coordinates(state->efp, xyzabc)); if (!central) { memcpy(grad_b, state->grad, n_frags * 6 * sizeof(double)); for (size_t i = 0; i < n_frags; i++) { const double *euler = xyzabc + 6 * i + 3; double *gradptr = grad_b + 6 * i + 3; efp_torque_to_derivative(euler, gradptr, gradptr); } } for (size_t i = 0; i < n_coord; i++) { double save = xyzabc[i]; double step = i % 6 < 3 ? cfg_get_double(state->cfg, "num_step_dist") : cfg_get_double(state->cfg, "num_step_angle"); show_progress(i + 1, n_coord, "FORWARD"); xyzabc[i] = save + step; compute_gradient(state, n_frags, xyzabc, grad_f); if (central) { show_progress(i + 1, n_coord, "BACKWARD"); xyzabc[i] = save - step; compute_gradient(state, n_frags, xyzabc, grad_b); } double delta = central ? 2.0 * step : step; for (size_t j = 0; j < n_coord; j++) hess[i * n_coord + j] = (grad_f[j] - grad_b[j]) / delta; xyzabc[i] = save; } /* restore original coordinates */ check_fail(efp_set_coordinates(state->efp, EFP_COORD_TYPE_XYZABC, xyzabc)); /* reduce error by computing the average of H(i,j) and H(j,i) */ for (size_t i = 0; i < n_coord; i++) { for (size_t j = i + 1; j < n_coord; j++) { double sum = hess[i * n_coord + j] + hess[j * n_coord + i]; hess[i * n_coord + j] = 0.5 * sum; hess[j * n_coord + i] = hess[i * n_coord + j]; } } free(xyzabc); free(grad_f); free(grad_b); msg("\n\n"); }
/* current coordinates from efp struct are used */ void compute_energy(struct state *state, bool do_grad) { struct efp_atom *atoms; struct efp_energy efp_energy; double xyz[3], xyzabc[6], *grad; size_t ifrag, nfrag, iatom, natom; int itotal; /* EFP part */ check_fail(efp_compute(state->efp, do_grad)); check_fail(efp_get_energy(state->efp, &efp_energy)); check_fail(efp_get_frag_count(state->efp, &nfrag)); if (do_grad) { check_fail(efp_get_gradient(state->efp, state->grad)); check_fail(efp_get_point_charge_gradient(state->efp, state->grad + 6 * nfrag)); } state->energy = efp_energy.total; /* constraints */ for (ifrag = 0; ifrag < nfrag; ifrag++) { const struct frag *frag = state->sys->frags + ifrag; check_fail(efp_get_frag_xyzabc(state->efp, ifrag, xyzabc)); if (frag->constraint_enable) { double dr2, drx, dry, drz; drx = xyzabc[0] - frag->constraint_xyz.x; dry = xyzabc[1] - frag->constraint_xyz.y; drz = xyzabc[2] - frag->constraint_xyz.z; dr2 = drx * drx + dry * dry + drz * drz; state->energy += 0.5 * frag->constraint_k * dr2; if (do_grad) { grad = state->grad + 6 * ifrag; grad[0] += frag->constraint_k * drx; grad[1] += frag->constraint_k * dry; grad[2] += frag->constraint_k * drz; } } } /* MM force field part */ if (state->ff == NULL) return; for (ifrag = 0, itotal = 0; ifrag < nfrag; ifrag++) { check_fail(efp_get_frag_atom_count(state->efp, ifrag, &natom)); atoms = malloc(natom * sizeof(struct efp_atom)); check_fail(efp_get_frag_atoms(state->efp, ifrag, natom, atoms)); for (iatom = 0; iatom < natom; iatom++, itotal++) ff_set_atom_xyz(state->ff, itotal, &atoms[iatom].x); free(atoms); } ff_compute(state->ff, do_grad); if (do_grad) { for (ifrag = 0, itotal = 0, grad = state->grad; ifrag < nfrag; ifrag++, grad += 6) { check_fail(efp_get_frag_xyzabc(state->efp, ifrag, xyzabc)); check_fail(efp_get_frag_atom_count(state->efp, ifrag, &natom)); atoms = malloc(natom * sizeof(struct efp_atom)); check_fail(efp_get_frag_atoms(state->efp, ifrag, natom, atoms)); for (iatom = 0; iatom < natom; iatom++, itotal++) { ff_get_atom_gradient(state->ff, itotal, xyz); grad[0] += xyz[0]; grad[1] += xyz[1]; grad[2] += xyz[2]; grad[3] += (atoms[iatom].y - xyzabc[1]) * xyz[2] - (atoms[iatom].z - xyzabc[2]) * xyz[1]; grad[4] += (atoms[iatom].z - xyzabc[2]) * xyz[0] - (atoms[iatom].x - xyzabc[0]) * xyz[2]; grad[5] += (atoms[iatom].x - xyzabc[0]) * xyz[1] - (atoms[iatom].y - xyzabc[1]) * xyz[0]; } free(atoms); } } state->energy += ff_get_energy(state->ff); }
/* current coordinates from efp struct are used */ void compute_energy(struct state *state, bool do_grad) { struct efp_atom *atoms; struct efp_energy efp_energy; double xyz[3], xyzabc[6], *grad; size_t ifrag, nfrag, iatom, natom; int itotal; check_fail(efp_compute(state->efp, do_grad)); check_fail(efp_get_energy(state->efp, &efp_energy)); check_fail(efp_get_frag_count(state->efp, &nfrag)); if (do_grad) { check_fail(efp_get_gradient(state->efp, state->grad)); check_fail(efp_get_point_charge_gradient(state->efp, state->grad + 6 * nfrag)); } state->energy = efp_energy.total; if (state->ff == NULL) return; for (ifrag = 0, itotal = 0; ifrag < nfrag; ifrag++) { check_fail(efp_get_frag_atom_count(state->efp, ifrag, &natom)); atoms = malloc(natom * sizeof(struct efp_atom)); check_fail(efp_get_frag_atoms(state->efp, ifrag, natom, atoms)); for (iatom = 0; iatom < natom; iatom++, itotal++) ff_set_atom_xyz(state->ff, itotal, &atoms[iatom].x); free(atoms); } ff_compute(state->ff, do_grad); if (do_grad) { for (ifrag = 0, itotal = 0, grad = state->grad; ifrag < nfrag; ifrag++, grad += 6) { check_fail(efp_get_frag_xyzabc(state->efp, ifrag, xyzabc)); check_fail(efp_get_frag_atom_count(state->efp, ifrag, &natom)); atoms = malloc(natom * sizeof(struct efp_atom)); check_fail(efp_get_frag_atoms(state->efp, ifrag, natom, atoms)); for (iatom = 0; iatom < natom; iatom++, itotal++) { ff_get_atom_gradient(state->ff, itotal, xyz); grad[0] += xyz[0]; grad[1] += xyz[1]; grad[2] += xyz[2]; grad[3] += (atoms[iatom].y - xyzabc[1]) * xyz[2] - (atoms[iatom].z - xyzabc[2]) * xyz[1]; grad[4] += (atoms[iatom].z - xyzabc[2]) * xyz[0] - (atoms[iatom].x - xyzabc[0]) * xyz[2]; grad[5] += (atoms[iatom].x - xyzabc[0]) * xyz[1] - (atoms[iatom].y - xyzabc[1]) * xyz[0]; } free(atoms); } } state->energy += ff_get_energy(state->ff); }