• R/O
  • SSH
  • HTTPS

molby:


File Info

Rev. 427
Size 9,307 bytes
Time 2014-01-31 00:40:04
Author toshinagata1964
Log Message

Ruby: Molecule#find_close_atoms is modified so that it can accept a Vector3D as the first argument. Cleaning up other sources.

Content

/*
 *  MDPressure.c
 *  Molby
 *
 *  Created by Toshi Nagata on 07/10/12.
 *  Copyright 2007 Toshi Nagata. All rights reserved.
 *
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation version 2 of the License.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 */

#include "MDPressure.h"
#include "MDForce.h"

#include <stdlib.h>
#include <math.h>
#include <string.h>

/*  Calculate the lattice deformation stress  */
static Double
s_lattice_deformation_stress(const Mat33 apply, const Transform celltr, const Transform old_celltr)
{
	Mat33 grad, grad_tr, grad_inv, grad_inv_tr;
	Mat33 strain, tension;
	Double eng, volume;
	Int i;

	/*  Some of the calculations duplicate with md_scale_cell(), but it will not cause
		a serious slowdown  */
	volume = fabs(MatrixDeterminant(celltr));

	/*  Deformation gradient (temp) = celltr * old_rcelltr  */
	MatrixInvert(grad, old_celltr);
	MatrixMul(grad, celltr, grad);
	MatrixTranspose(grad_tr, grad);
	MatrixInvert(grad_inv, grad);
	MatrixTranspose(grad_inv_tr, grad_inv);
	MatrixMul(strain, grad_tr, grad);
	strain[0] -= 1.0;
	strain[4] -= 1.0;
	strain[8] -= 1.0;
	MatrixScale(strain, strain, 0.5);
	MatrixMul(tension, apply, grad_inv_tr);
	MatrixMul(tension, grad_inv, tension);
	MatrixScale(tension, tension, MatrixDeterminant(grad));
	eng = 0.0;
	for (i = 0; i < 9; i++)
		eng += strain[i] * tension[i];
	eng *= volume * BAR2INTERNALPRESSURE;
	return eng;
}

MDPressureArena *
pressure_new(void)
{
	MDPressureArena *pressure = (MDPressureArena *)calloc(sizeof(MDPressureArena), 1);
	if (pressure == NULL)
		return NULL;
	pressure->freq = 20;
	pressure->coupling = 0.3;
	pressure->trial_width = 0.001;
	pressure->control_algorithm = 0;
	pressure->fluctuate_cell_origin = 0.01;
	pressure->fluctuate_cell_orientation = 0.01;
	pressure->apply[0] = 1;
	pressure->apply[1] = 0;
	pressure->apply[2] = 0;
	pressure->apply[3] = 0;
	pressure->apply[4] = 1;
	pressure->apply[5] = 0;
	pressure->apply[6] = 0;
	pressure->apply[7] = 0;
	pressure->apply[8] = 1;
	pressure->cell_flexibility[0] = -1;
	pressure->cell_flexibility[1] = -1;
	pressure->cell_flexibility[2] = -1;
	pressure->cell_flexibility[3] = 0;
	pressure->cell_flexibility[4] = 0;
	pressure->cell_flexibility[5] = 0;
	pressure->cell_flexibility[6] = 0;
	pressure->cell_flexibility[7] = 0;
	return pressure;
}

void
pressure_release(MDPressureArena *pressure)
{
	if (pressure == NULL)
		return;
	free(pressure);
}

void
pressure_prepare(MDArena *arena)
{
	MDPressureArena *pressure = arena->pressure;
	if (pressure == NULL)
		return;
	pressure->mc_accept = pressure->mc_reject = 0;
	if (pressure->temporary_energies != NULL)
		free(pressure->temporary_energies);
	pressure->temporary_energies = (Double *)calloc(sizeof(Double), arena->natoms_uniq);
	if (pressure->temporary_energies == NULL)
		md_panic(arena, "Low memory");
	if (pressure->temporary_velocities != NULL)
		free(pressure->temporary_velocities);
	pressure->temporary_velocities = (Vector *)calloc(sizeof(Vector), arena->natoms_uniq);
	if (pressure->temporary_velocities == NULL)
		md_panic(arena, "Low memory");
}

/*  Pressure control  */
void
pressure_control(MDArena *arena)
{
	Vector cella_save, cellb_save, cellc_save, cello_save;
	Double de, total_energy_save, energies_save[kEndIndex];
	MDPressureArena *pressure = arena->pressure;
	Atom *ap;
	Transform tf;
	Vector v;
	Vector cello_new;
	Mat33 celltr_save;
	Double w, w0;
	int i;
	int needs_cell_recalculate = 0;
	XtalCell *cell = arena->mol->cell;
	
	if (pressure == NULL || (!arena->periodic_a && !arena->periodic_b && !arena->periodic_c))
		return;
	if (pressure->freq == 0 || arena->step % pressure->freq != 0)
		return;

	while (md_rand() < pressure->coupling) {

		Double flex;
		Transform tf0;
	
		/*  Trial move of the periodic cell  */
		memset(tf, 0, sizeof(tf));
		tf[0] = tf[4] = tf[8] = 1;
		memmove(tf0, tf, sizeof(tf));
		w0 = (md_rand() - 0.5) * pressure->trial_width;
		for (i = 0; i < 3; i++) {
			static char idx[] = {4, 8, 7, 5, 0, 8, 6, 2, 0, 4, 3, 1};
			flex = pressure->cell_flexibility[i + 3];
			if (flex > 0) {
				w = w0 = (md_rand() + md_rand() - 1.0) * pressure->trial_width * 0.5;
			} else if (flex < 0) {
				w = w0;
			} else w = 0;
			w *= fabs(flex);
			tf[idx[i * 4]] = tf[idx[i * 4 + 1]] = sqrt(1 - w * w);
			tf[idx[i * 4 + 2]] = tf[idx[i * 4 + 3]] = w;
			TransformMul(tf0, tf0, tf);
			tf[idx[i * 4]] = tf[idx[i * 4 + 1]] = 1;
			tf[idx[i * 4 + 2]] = tf[idx[i * 4 + 3]] = 0;
		}
		memmove(tf, tf0, sizeof(tf));
		w0 = (md_rand() - 0.5) * pressure->trial_width;
		for (i = 0; i < 3; i++) {
			int j;
			flex = pressure->cell_flexibility[i];
			if (flex > 0) {
				w = w0 = (md_rand() - 0.5) * pressure->trial_width;
			} else if (flex < 0) {
				w = w0;
			} else w = 0;
			for (j = 0; j < 3; j++) {
				tf[i * 3 + j] *= 1 + w * fabs(flex);
			}
		}
		
		/*  The new cell vector (bij) = (tik)(akj), so B = A*T  */
		/*  The cell transform matrix R = A*T*(A^-1)  */
		MatrixMul(tf, cell->tr, tf);
		MatrixMul(tf, tf, cell->rtr);
	/*	MatrixInvert(mat, arena->celltr);
		MatrixMul(tf, tf, mat); */

		cella_save = cell->axes[0];
		cellb_save = cell->axes[1];
		cellc_save = cell->axes[2];
		cello_save = cell->origin;
		memmove(celltr_save, cell->tr, sizeof(celltr_save));

		/*  Save a snapshot  */
		md_snapshot(arena, 0);
		total_energy_save = arena->total_energy;
		memmove(energies_save, arena->energies, sizeof(Double) * kEndIndex);

		/*  Transform the cell  */
		md_scale_cell(arena, tf, (pressure->use_atomic_move ? 1 : 2));

		/*  Fluctuate cell origin and orientation if requested  */
		if (pressure->cell_flexibility[6] != 0) {
			cello_new = cell->origin;
			cello_new.x += (md_rand() - 0.5) * pressure->fluctuate_cell_origin;
			cello_new.y += (md_rand() - 0.5) * pressure->fluctuate_cell_origin;
			cello_new.z += (md_rand() - 0.5) * pressure->fluctuate_cell_origin;
			cell->origin = cello_new;
			needs_cell_recalculate = 1;
		}
		if (pressure->cell_flexibility[7] != 0) {
			Vector axis;
			Mat33 mat2;
			switch ((int)pressure->cell_flexibility[7]) {
				case 1: axis.x = 1.0; axis.y = axis.z = 0.0; break;
				case 2: axis.y = 1.0; axis.x = axis.z = 0.0; break;
				case 3: axis.z = 1.0; axis.x = axis.y = 0.0; break;
				case 4:
					axis.x = md_rand() - 0.5;
					axis.y = md_rand() - 0.5;
					axis.z = md_rand() - 0.5;
					w = 1.0 / VecLength(axis);
					VecScaleSelf(axis, w);
					break;
				default:
					axis.x = axis.y = axis.z = 0.0; /* Just to keep compiler happy */
					break;
			}
			MatrixRotation(mat2, &axis, (md_rand() - 0.5) * pressure->fluctuate_cell_orientation);
			MatrixVec(&cell->axes[0], mat2, &cell->axes[0]);
			MatrixVec(&cell->axes[1], mat2, &cell->axes[1]);
			MatrixVec(&cell->axes[2], mat2, &cell->axes[2]);
			needs_cell_recalculate = 1;
		}
		if (needs_cell_recalculate)
			md_update_cell(arena);

		/*  Recalc the energies  */
		md_amend_by_symmetry(arena);
		calc_force(arena);
		md_calc_kinetic_energy(arena);
		pressure->mc_delta_potential = arena->total_energy - total_energy_save;
		pressure->mc_delta_kinetic = arena->energies[kKineticIndex] - energies_save[kKineticIndex];
		pressure->mc_stress = -s_lattice_deformation_stress(pressure->apply, cell->tr, celltr_save);
		de = pressure->mc_delta_potential + pressure->mc_delta_kinetic + pressure->mc_stress;
		pressure->mc_delta_volume = fabs(MatrixDeterminant(cell->tr)) - fabs(MatrixDeterminant(celltr_save));
		
		/*  Metropolis scheme  */
		if (de > 0 && md_rand() > exp(-de / (BOLTZMANN * arena->temperature))) {
			/*  Reject  */
			cell->axes[0] = cella_save;
			cell->axes[1] = cellb_save;
			cell->axes[2] = cellc_save;
			cell->origin = cello_save;
			md_update_cell(arena);
			if (pressure->control_algorithm != 1) {
				md_restore(arena, 0);
				arena->total_energy = total_energy_save;
				memmove(arena->energies, energies_save, sizeof(Double) * kEndIndex);
			}
			pressure->mc_reject++;
		} else {
			pressure->mc_accept++;
			if (pressure->control_algorithm == 1) {
				Vector dr;
				int j, k;
				/*  Update positions and velocities  */
				for (i = 0, ap = arena->mol->atoms; i < arena->mol->natoms; i++, ap++) {
					if (ap->periodic_exclude)
						continue;
					if (i < arena->natoms_uniq) {
						k = arena->fragment_indices[i];
						v = pressure->temporary_velocities[i];
					} else if (ap->symop.alive && (j = ap->symbase) >= 0 && j < arena->natoms_uniq) {
						k = arena->fragment_indices[j];
						v = pressure->temporary_velocities[j];
					} else continue;
					dr = arena->fragment_info[k].pos;
					if (ap->symop.alive) {
						md_transform_vec_by_symmetry(arena, &dr, &dr, ap->symop, 1);
						md_transform_vec_by_symmetry(arena, &v, &v, ap->symop, 1);
					}
					VecInc(ap->r, dr);
					VecInc(arena->verlets_dr[i], dr);
					ap->v = v;
				}
			}
		}
	/*	if (pressure->mc_callback != NULL) {
			if (Tcl_EvalObjEx((Tcl_Interp *)(arena->tcl_interp), pressure->mc_callback, 0) != TCL_OK) {
				arena->request_abort = 1;
				return;
			}
		} */
	} /* end while (mrand() < pressure->coupling) */
}

Show on old repository browser