Ejemplo n.º 1
0
Archivo: disp.c Proyecto: psi4/libefp
/*
 * Reference:
 *
 * Ivana Adamovic, Mark Gordon
 *
 * Dynamic polarizability, dispersion coefficient C6 and dispersion energy in
 * the effective fragment potential method
 *
 * Mol. Phys. 103, 379 (2005)
 */
double
efp_frag_frag_disp(struct efp *efp, size_t frag_i, size_t frag_j,
			const double *s, const six_t *ds)
{
	double energy = 0.0;

	struct frag *fr_i = efp->frags + frag_i;
	struct frag *fr_j = efp->frags + frag_j;

	size_t n_disp_i = fr_i->n_dynamic_polarizable_pts;
	size_t n_disp_j = fr_j->n_dynamic_polarizable_pts;

	struct swf swf = efp_make_swf(efp, fr_i, fr_j);

	for (size_t ii = 0, idx = 0; ii < n_disp_i; ii++)
		for (size_t jj = 0; jj < n_disp_j; jj++, idx++)
			energy += point_point_disp(efp, frag_i, frag_j, ii, jj,
						   s[idx], ds[idx], &swf);

	vec_t force = {
		swf.dswf.x * energy,
		swf.dswf.y * energy,
		swf.dswf.z * energy
	};

	six_atomic_add_xyz(efp->grad + frag_i, &force);
	six_atomic_sub_xyz(efp->grad + frag_j, &force);
	efp_add_stress(&swf.dr, &force, &efp->stress);

	return energy * swf.swf;
}
Ejemplo n.º 2
0
static void
get_induced_dipole_field(struct efp *efp, size_t frag_idx,
			 struct polarizable_pt *pt,
			 vec_t *field, vec_t *field_conj)
{
	struct frag *fr_i = efp->frags + frag_idx;

	*field = vec_zero;
	*field_conj = vec_zero;

	for (size_t j = 0; j < efp->n_frag; j++) {
		if (j == frag_idx || efp_skip_frag_pair(efp, frag_idx, j))
			continue;

		struct frag *fr_j = efp->frags + j;
		struct swf swf = efp_make_swf(efp, fr_i, fr_j);

		for (size_t jj = 0; jj < fr_j->n_polarizable_pts; jj++) {
			struct polarizable_pt *pt_j = fr_j->polarizable_pts + jj;
			size_t idx = fr_j->polarizable_offset + jj;

			vec_t dr = {
				pt->x - pt_j->x + swf.cell.x,
				pt->y - pt_j->y + swf.cell.y,
				pt->z - pt_j->z + swf.cell.z
			};

			double r = vec_len(&dr);
			double r3 = r * r * r;
			double r5 = r3 * r * r;

			double t1 = vec_dot(&efp->indip[idx], &dr);
			double t2 = vec_dot(&efp->indipconj[idx], &dr);

			double p1 = 1.0;

			if (efp->opts.pol_damp == EFP_POL_DAMP_TT)
				p1 = efp_get_pol_damp_tt(r, fr_i->pol_damp, fr_j->pol_damp);

			field->x -= swf.swf * p1 * (efp->indip[idx].x / r3 -
						3.0 * t1 * dr.x / r5);
			field->y -= swf.swf * p1 * (efp->indip[idx].y / r3 -
						3.0 * t1 * dr.y / r5);
			field->z -= swf.swf * p1 * (efp->indip[idx].z / r3 -
						3.0 * t1 * dr.z / r5);

			field_conj->x -= swf.swf * p1 * (efp->indipconj[idx].x / r3 -
						3.0 * t2 * dr.x / r5);
			field_conj->y -= swf.swf * p1 * (efp->indipconj[idx].y / r3 -
						3.0 * t2 * dr.y / r5);
			field_conj->z -= swf.swf * p1 * (efp->indipconj[idx].z / r3 -
						3.0 * t2 * dr.z / r5);
		}
	}
}
Ejemplo n.º 3
0
static mat_t
get_int_mat(const struct efp *efp, size_t i, size_t j, size_t ii, size_t jj)
{
	mat_t m;
	const struct frag *fr_i = efp->frags + i;
	const struct frag *fr_j = efp->frags + j;
	const struct polarizable_pt *pt_i = fr_i->polarizable_pts + ii;
	const struct polarizable_pt *pt_j = fr_j->polarizable_pts + jj;
	struct swf swf = efp_make_swf(efp, fr_i, fr_j);

	vec_t dr = {
		pt_j->x - pt_i->x - swf.cell.x,
		pt_j->y - pt_i->y - swf.cell.y,
		pt_j->z - pt_i->z - swf.cell.z
	};

	double p1 = 1.0;
	double r = vec_len(&dr);
	double r3 = r * r * r;
	double r5 = r3 * r * r;

	if (efp->opts.pol_damp == EFP_POL_DAMP_TT)
		p1 = efp_get_pol_damp_tt(r, fr_i->pol_damp, fr_j->pol_damp);

	m.xx = swf.swf * p1 * (3.0 * dr.x * dr.x / r5 - 1.0 / r3);
	m.xy = swf.swf * p1 *  3.0 * dr.x * dr.y / r5;
	m.xz = swf.swf * p1 *  3.0 * dr.x * dr.z / r5;
	m.yx = swf.swf * p1 *  3.0 * dr.y * dr.x / r5;
	m.yy = swf.swf * p1 * (3.0 * dr.y * dr.y / r5 - 1.0 / r3);
	m.yz = swf.swf * p1 *  3.0 * dr.y * dr.z / r5;
	m.zx = swf.swf * p1 *  3.0 * dr.z * dr.x / r5;
	m.zy = swf.swf * p1 *  3.0 * dr.z * dr.y / r5;
	m.zz = swf.swf * p1 * (3.0 * dr.z * dr.z / r5 - 1.0 / r3);

	return m;
}
Ejemplo n.º 4
0
EFP_EXPORT enum efp_result
efp_get_electric_field(struct efp *efp, size_t frag_idx, const double *xyz, double *field)
{
	assert(efp);
	assert(frag_idx < efp->n_frag);
	assert(xyz);
	assert(field);

	const struct frag *frag = efp->frags + frag_idx;
	vec_t elec_field = vec_zero;

	for (size_t i = 0; i < efp->n_frag; i++) {
		if (i == frag_idx || efp_skip_frag_pair(efp, i, frag_idx))
			continue;

		const struct frag *fr_i = efp->frags + i;
		struct swf swf = efp_make_swf(efp, fr_i, frag);

		/* field due to nuclei */
		for (size_t j = 0; j < fr_i->n_atoms; j++) {
			const struct efp_atom *at = fr_i->atoms + j;

			vec_t dr = {
				xyz[0] - at->x - swf.cell.x,
				xyz[1] - at->y - swf.cell.y,
				xyz[2] - at->z - swf.cell.z
			};

			double r = vec_len(&dr);
			double r3 = r * r * r;

			elec_field.x += swf.swf * at->znuc * dr.x / r3;
			elec_field.y += swf.swf * at->znuc * dr.y / r3;
			elec_field.z += swf.swf * at->znuc * dr.z / r3;
		}

		/* field due to multipoles */
		for (size_t j = 0; j < fr_i->n_multipole_pts; j++) {
			const struct multipole_pt *mpt = fr_i->multipole_pts + j;
			vec_t mult_field = get_multipole_field((const vec_t *)xyz, mpt, &swf);

			elec_field.x += mult_field.x;
			elec_field.y += mult_field.y;
			elec_field.z += mult_field.z;
		}

		/* field due to induced dipoles */
		for (size_t j = 0; j < fr_i->n_polarizable_pts; j++) {
			struct polarizable_pt *pt_i = fr_i->polarizable_pts + j;
			size_t idx = fr_i->polarizable_offset + j;

			vec_t dr = {
				xyz[0] - pt_i->x - swf.cell.x,
				xyz[1] - pt_i->y - swf.cell.y,
				xyz[2] - pt_i->z - swf.cell.z
			};

			double r = vec_len(&dr);
			double r3 = r * r * r;
			double r5 = r3 * r * r;
			double t1 = vec_dot(&efp->indip[idx], &dr);

			elec_field.x -= swf.swf * (efp->indip[idx].x / r3 -
						3.0 * t1 * dr.x / r5);
			elec_field.y -= swf.swf * (efp->indip[idx].y / r3 -
						3.0 * t1 * dr.y / r5);
			elec_field.z -= swf.swf * (efp->indip[idx].z / r3 -
						3.0 * t1 * dr.z / r5);
		}
	}

	if (efp->opts.terms & EFP_TERM_AI_POL) {
		/* field due to nuclei from ab initio subsystem */
		for (size_t i = 0; i < efp->n_ptc; i++) {
			vec_t dr = vec_sub((const vec_t *)xyz, efp->ptc_xyz + i);

			double r = vec_len(&dr);
			double r3 = r * r * r;

			elec_field.x += efp->ptc[i] * dr.x / r3;
			elec_field.y += efp->ptc[i] * dr.y / r3;
			elec_field.z += efp->ptc[i] * dr.z / r3;
		}
	}

	*((vec_t *)field) = elec_field;
	return (EFP_RESULT_SUCCESS);
}
Ejemplo n.º 5
0
static void
compute_grad_point(struct efp *efp, size_t frag_idx, size_t pt_idx)
{
	const struct frag *fr_i = efp->frags + frag_idx;
	const struct polarizable_pt *pt_i = fr_i->polarizable_pts + pt_idx;
	size_t idx_i = fr_i->polarizable_offset + pt_idx;

	vec_t dipole_i = {
		0.5 * (efp->indip[idx_i].x + efp->indipconj[idx_i].x),
		0.5 * (efp->indip[idx_i].y + efp->indipconj[idx_i].y),
		0.5 * (efp->indip[idx_i].z + efp->indipconj[idx_i].z)
	};

	for (size_t j = 0; j < efp->n_frag; j++) {
		if (j == frag_idx || efp_skip_frag_pair(efp, frag_idx, j))
			continue;

		struct frag *fr_j = efp->frags + j;
		struct swf swf = efp_make_swf(efp, fr_i, fr_j);

		/* energy without switching applied */
		double energy = 0.0;

		/* induced dipole - nuclei */
		for (size_t k = 0; k < fr_j->n_atoms; k++) {
			struct efp_atom *at_j = fr_j->atoms + k;

			vec_t dr = {
				at_j->x - pt_i->x - swf.cell.x,
				at_j->y - pt_i->y - swf.cell.y,
				at_j->z - pt_i->z - swf.cell.z
			};

			double p1 = 1.0, p2 = 0.0;

			if (efp->opts.pol_damp == EFP_POL_DAMP_TT) {
				double r = vec_len(&dr);

				p1 = efp_get_pol_damp_tt(r, fr_i->pol_damp,
						fr_j->pol_damp);
				p2 = efp_get_pol_damp_tt_grad(r, fr_i->pol_damp,
						fr_j->pol_damp);
			}

			vec_t force, add_i, add_j;

			double e = -efp_charge_dipole_energy(at_j->znuc, &dipole_i, &dr);

			efp_charge_dipole_grad(at_j->znuc, &dipole_i, &dr,
					       &force, &add_j, &add_i);
			vec_negate(&force);

			vec_scale(&force, p1);
			vec_scale(&add_i, p1);
			vec_scale(&add_j, p1);

			force.x += p2 * e * dr.x;
			force.y += p2 * e * dr.y;
			force.z += p2 * e * dr.z;

			vec_scale(&force, swf.swf);
			vec_scale(&add_i, swf.swf);
			vec_scale(&add_j, swf.swf);

			efp_add_force(efp->grad + frag_idx, CVEC(fr_i->x),
					CVEC(pt_i->x), &force, &add_i);
			efp_sub_force(efp->grad + j, CVEC(fr_j->x),
					CVEC(at_j->x), &force, &add_j);
			efp_add_stress(&swf.dr, &force, &efp->stress);

			energy += p1 * e;
		}

		/* induced dipole - multipoles */
		for (size_t k = 0; k < fr_j->n_multipole_pts; k++) {
			struct multipole_pt *pt_j = fr_j->multipole_pts + k;

			vec_t dr = {
				pt_j->x - pt_i->x - swf.cell.x,
				pt_j->y - pt_i->y - swf.cell.y,
				pt_j->z - pt_i->z - swf.cell.z
			};

			double p1 = 1.0, p2 = 0.0;

			if (efp->opts.pol_damp == EFP_POL_DAMP_TT) {
				double r = vec_len(&dr);

				p1 = efp_get_pol_damp_tt(r, fr_i->pol_damp,
						fr_j->pol_damp);
				p2 = efp_get_pol_damp_tt_grad(r, fr_i->pol_damp,
						fr_j->pol_damp);
			}

			double e = 0.0;

			vec_t force_, add_i_, add_j_;
			vec_t force = vec_zero, add_i = vec_zero, add_j = vec_zero;

			/* induced dipole - charge */
			e -= efp_charge_dipole_energy(pt_j->monopole, &dipole_i, &dr);

			efp_charge_dipole_grad(pt_j->monopole, &dipole_i, &dr,
					       &force_, &add_j_, &add_i_);
			vec_negate(&force_);
			add_3(&force, &force_, &add_i, &add_i_, &add_j, &add_j_);

			/* induced dipole - dipole */
			e += efp_dipole_dipole_energy(&dipole_i, &pt_j->dipole, &dr);

			efp_dipole_dipole_grad(&dipole_i, &pt_j->dipole, &dr,
					       &force_, &add_i_, &add_j_);
			vec_negate(&add_j_);
			add_3(&force, &force_, &add_i, &add_i_, &add_j, &add_j_);

			/* induced dipole - quadrupole */
			e += efp_dipole_quadrupole_energy(&dipole_i, pt_j->quadrupole, &dr);

			efp_dipole_quadrupole_grad(&dipole_i, pt_j->quadrupole, &dr,
						   &force_, &add_i_, &add_j_);
			add_3(&force, &force_, &add_i, &add_i_, &add_j, &add_j_);

			/* induced dipole - octupole interactions are ignored */

			vec_scale(&force, p1);
			vec_scale(&add_i, p1);
			vec_scale(&add_j, p1);

			force.x += p2 * e * dr.x;
			force.y += p2 * e * dr.y;
			force.z += p2 * e * dr.z;

			vec_scale(&force, swf.swf);
			vec_scale(&add_i, swf.swf);
			vec_scale(&add_j, swf.swf);

			efp_add_force(efp->grad + frag_idx, CVEC(fr_i->x),
					CVEC(pt_i->x), &force, &add_i);
			efp_sub_force(efp->grad + j, CVEC(fr_j->x),
					CVEC(pt_j->x), &force, &add_j);
			efp_add_stress(&swf.dr, &force, &efp->stress);

			energy += p1 * e;
		}

		/* induced dipole - induced dipoles */
		for (size_t jj = 0; jj < fr_j->n_polarizable_pts; jj++) {
			struct polarizable_pt *pt_j = fr_j->polarizable_pts + jj;
			size_t idx_j = fr_j->polarizable_offset + jj;

			vec_t dr = {
				pt_j->x - pt_i->x - swf.cell.x,
				pt_j->y - pt_i->y - swf.cell.y,
				pt_j->z - pt_i->z - swf.cell.z
			};

			vec_t half_dipole_i = {
				0.5 * efp->indip[idx_i].x,
				0.5 * efp->indip[idx_i].y,
				0.5 * efp->indip[idx_i].z
			};

			double p1 = 1.0, p2 = 0.0;

			if (efp->opts.pol_damp == EFP_POL_DAMP_TT) {
				double r = vec_len(&dr);

				p1 = efp_get_pol_damp_tt(r, fr_i->pol_damp,
						fr_j->pol_damp);
				p2 = efp_get_pol_damp_tt_grad(r, fr_i->pol_damp,
						fr_j->pol_damp);
			}

			vec_t force, add_i, add_j;

			double e = efp_dipole_dipole_energy(&half_dipole_i,
						&efp->indipconj[idx_j], &dr);

			efp_dipole_dipole_grad(&half_dipole_i, &efp->indipconj[idx_j],
						&dr, &force, &add_i, &add_j);
			vec_negate(&add_j);

			vec_scale(&force, p1);
			vec_scale(&add_i, p1);
			vec_scale(&add_j, p1);

			force.x += p2 * e * dr.x;
			force.y += p2 * e * dr.y;
			force.z += p2 * e * dr.z;

			vec_scale(&force, swf.swf);
			vec_scale(&add_i, swf.swf);
			vec_scale(&add_j, swf.swf);

			efp_add_force(efp->grad + frag_idx, CVEC(fr_i->x),
					CVEC(pt_i->x), &force, &add_i);
			efp_sub_force(efp->grad + j, CVEC(fr_j->x),
					CVEC(pt_j->x), &force, &add_j);
			efp_add_stress(&swf.dr, &force, &efp->stress);

			energy += p1 * e;
		}

		vec_t force = {
			swf.dswf.x * energy,
			swf.dswf.y * energy,
			swf.dswf.z * energy
		};

		six_atomic_add_xyz(efp->grad + frag_idx, &force);
		six_atomic_sub_xyz(efp->grad + j, &force);
		efp_add_stress(&swf.dr, &force, &efp->stress);
	}

	/* induced dipole - ab initio nuclei */
	if (efp->opts.terms & EFP_TERM_AI_POL) {
		for (size_t j = 0; j < efp->n_ptc; j++) {
			vec_t dr = vec_sub(efp->ptc_xyz + j, CVEC(pt_i->x));
			vec_t force, add_i, add_j;

			efp_charge_dipole_grad(efp->ptc[j], &dipole_i, &dr,
					       &force, &add_j, &add_i);
			vec_negate(&add_i);

			vec_atomic_add(efp->ptc_grad + j, &force);
			efp_sub_force(efp->grad + frag_idx, CVEC(fr_i->x),
					CVEC(pt_i->x), &force, &add_i);
		}
	}
}
Ejemplo n.º 6
0
static vec_t
get_elec_field(const struct efp *efp, size_t frag_idx, size_t pt_idx)
{
	const struct frag *fr_j = efp->frags + frag_idx;
	const struct polarizable_pt *pt = fr_j->polarizable_pts + pt_idx;
	vec_t elec_field = vec_zero;

	for (size_t i = 0; i < efp->n_frag; i++) {
		if (i == frag_idx || efp_skip_frag_pair(efp, i, frag_idx))
			continue;

		const struct frag *fr_i = efp->frags + i;
		struct swf swf = efp_make_swf(efp, fr_i, fr_j);

		/* field due to nuclei */
		for (size_t j = 0; j < fr_i->n_atoms; j++) {
			const struct efp_atom *at = fr_i->atoms + j;

			vec_t dr = {
				pt->x - at->x - swf.cell.x,
				pt->y - at->y - swf.cell.y,
				pt->z - at->z - swf.cell.z
			};

			double r = vec_len(&dr);
			double r3 = r * r * r;
			double p1 = 1.0;

			if (efp->opts.pol_damp == EFP_POL_DAMP_TT)
				p1 = efp_get_pol_damp_tt(r, fr_i->pol_damp, fr_j->pol_damp);

			elec_field.x += swf.swf * at->znuc * dr.x / r3 * p1;
			elec_field.y += swf.swf * at->znuc * dr.y / r3 * p1;
			elec_field.z += swf.swf * at->znuc * dr.z / r3 * p1;
		}

		/* field due to multipoles */
		for (size_t j = 0; j < fr_i->n_multipole_pts; j++) {
			const struct multipole_pt *mult_pt = fr_i->multipole_pts + j;
			vec_t mult_field = get_multipole_field(CVEC(pt->x), mult_pt, &swf);

			vec_t dr = {
				pt->x - mult_pt->x - swf.cell.x,
				pt->y - mult_pt->y - swf.cell.y,
				pt->z - mult_pt->z - swf.cell.z
			};

			double r = vec_len(&dr);
			double p1 = 1.0;

			if (efp->opts.pol_damp == EFP_POL_DAMP_TT)
				p1 = efp_get_pol_damp_tt(r, fr_i->pol_damp, fr_j->pol_damp);

			elec_field.x += mult_field.x * p1;
			elec_field.y += mult_field.y * p1;
			elec_field.z += mult_field.z * p1;
		}
	}

	if (efp->opts.terms & EFP_TERM_AI_POL) {
		/* field due to nuclei from ab initio subsystem */
		for (size_t i = 0; i < efp->n_ptc; i++) {
			vec_t dr = vec_sub(CVEC(pt->x), efp->ptc_xyz + i);

			double r = vec_len(&dr);
			double r3 = r * r * r;

			elec_field.x += efp->ptc[i] * dr.x / r3;
			elec_field.y += efp->ptc[i] * dr.y / r3;
			elec_field.z += efp->ptc[i] * dr.z / r3;
		}
	}

	return (elec_field);
}