-
Kurt A. O'Hearn authored
PG-PuReMD: fixes to NVT with Berendsen thermostat. Use updated constants from sPuReMD. Add BGF geometry file parser. Other code clean-up.
Kurt A. O'Hearn authoredPG-PuReMD: fixes to NVT with Berendsen thermostat. Use updated constants from sPuReMD. Add BGF geometry file parser. Other code clean-up.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
system_props.c 16.26 KiB
/*----------------------------------------------------------------------
PuReMD - Purdue ReaxFF Molecular Dynamics Program
Copyright (2010) Purdue University
Hasan Metin Aktulga, haktulga@cs.purdue.edu
Joseph Fogarty, jcfogart@mail.usf.edu
Sagar Pandit, pandit@usf.edu
Ananth Y Grama, ayg@cs.purdue.edu
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; either version 2 of
the License, or (at your option) any later version.
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:
<http://www.gnu.org/licenses/>.
----------------------------------------------------------------------*/
#if (defined(HAVE_CONFIG_H) && !defined(__CONFIG_H_))
#define __CONFIG_H_
#include "../../common/include/config.h"
#endif
#if defined(PURE_REAX)
#include "system_props.h"
#include "comm_tools.h"
#include "tool_box.h"
#include "vector.h"
#elif defined(LAMMPS_REAX)
#include "reax_system_props.h"
#include "reax_comm_tools.h"
#include "reax_tool_box.h"
#include "reax_vector.h"
#endif
#if defined(HAVE_CUDA)
#include "cuda/cuda_copy.h"
#endif
void Temperature_Control( control_params *control, simulation_data *data )
{
real tmp;
/* step-wise temperature control */
if ( control->T_mode == 1 )
{
if ((data->step - data->prev_steps) % ((int)(control->T_freq / control->dt)) == 0)
{
if ( FABS( control->T - control->T_final ) >= FABS( control->T_rate ) )
{
control->T += control->T_rate;
}
else
{
control->T = control->T_final;
}
}
}
/* constant slope control */
else if ( control->T_mode == 2 )
{
tmp = control->T_rate * control->dt / control->T_freq;
if ( FABS( control->T - control->T_final ) >= FABS( tmp ) )
{
control->T += tmp;
}
}
}
void Compute_Kinetic_Energy( reax_system* system, simulation_data* data,
MPI_Comm comm )
{
int i, ret;
rvec p;
real m;
data->my_en.e_kin = 0.0;
for ( i = 0; i < system->n; i++ )
{
m = system->reax_param.sbp[system->my_atoms[i].type].mass;
rvec_Scale( p, m, system->my_atoms[i].v );
data->my_en.e_kin += rvec_Dot( p, system->my_atoms[i].v );
}
data->my_en.e_kin *= 0.5;
ret = MPI_Allreduce( &data->my_en.e_kin, &data->sys_en.e_kin, 1, MPI_DOUBLE,
MPI_SUM, comm );
Check_MPI_Error( ret, __FILE__, __LINE__ );
data->therm.T = (2.0 * data->sys_en.e_kin) / (data->N_f * K_B);
/* avoid T being an absolute zero, might cause F.P.E! */
if ( FABS(data->therm.T) < ALMOST_ZERO )
{
data->therm.T = ALMOST_ZERO;
}
}
void Compute_Total_Energy( reax_system *system, simulation_data *data,
MPI_Comm comm )
{
int ret;
real my_en[14], sys_en[14];
//TODO: remove this is an UGLY fix
my_en[13] = data->my_en.e_kin;
#if defined(HAVE_CUDA)
Cuda_Copy_Simulation_Data_Device_to_Host( data,
(simulation_data *)data->d_simulation_data );
#endif
my_en[0] = data->my_en.e_bond;
my_en[1] = data->my_en.e_ov;
my_en[2] = data->my_en.e_un;
my_en[3] = data->my_en.e_lp;
my_en[4] = data->my_en.e_ang;
my_en[5] = data->my_en.e_pen;
my_en[6] = data->my_en.e_coa;
my_en[7] = data->my_en.e_hb;
my_en[8] = data->my_en.e_tor;
my_en[9] = data->my_en.e_con;
my_en[10] = data->my_en.e_vdW;
my_en[11] = data->my_en.e_ele;
my_en[12] = data->my_en.e_pol;
// my_en[13] = data->my_en.e_kin;
ret = MPI_Reduce( my_en, sys_en, 14, MPI_DOUBLE, MPI_SUM, MASTER_NODE, comm );
Check_MPI_Error( ret, __FILE__, __LINE__ );
data->my_en.e_pot = data->my_en.e_bond
+ data->my_en.e_ov + data->my_en.e_un + data->my_en.e_lp
+ data->my_en.e_ang + data->my_en.e_pen + data->my_en.e_coa
+ data->my_en.e_hb + data->my_en.e_tor + data->my_en.e_con
+ data->my_en.e_vdW + data->my_en.e_ele + data->my_en.e_pol;
data->my_en.e_tot = data->my_en.e_pot + E_CONV * data->my_en.e_kin;
if ( system->my_rank == MASTER_NODE )
{
data->sys_en.e_bond = sys_en[0];
data->sys_en.e_ov = sys_en[1];
data->sys_en.e_un = sys_en[2];
data->sys_en.e_lp = sys_en[3];
data->sys_en.e_ang = sys_en[4];
data->sys_en.e_pen = sys_en[5];
data->sys_en.e_coa = sys_en[6];
data->sys_en.e_hb = sys_en[7];
data->sys_en.e_tor = sys_en[8];
data->sys_en.e_con = sys_en[9];
data->sys_en.e_vdW = sys_en[10];
data->sys_en.e_ele = sys_en[11];
data->sys_en.e_pol = sys_en[12];
data->sys_en.e_kin = sys_en[13];
data->sys_en.e_pot = data->sys_en.e_bond
+ data->sys_en.e_ov + data->sys_en.e_un + data->sys_en.e_lp
+ data->sys_en.e_ang + data->sys_en.e_pen + data->sys_en.e_coa
+ data->sys_en.e_hb + data->sys_en.e_tor + data->sys_en.e_con
+ data->sys_en.e_vdW + data->sys_en.e_ele + data->sys_en.e_pol;
data->sys_en.e_tot = data->sys_en.e_pot + E_CONV * data->sys_en.e_kin;
}
}
void Compute_Total_Mass( reax_system *system, simulation_data *data,
MPI_Comm comm )
{
int i, ret;
real tmp;
tmp = 0;
for ( i = 0; i < system->n; i++ )
{
tmp += system->reax_param.sbp[ system->my_atoms[i].type ].mass;
}
ret = MPI_Allreduce( &tmp, &data->M, 1, MPI_DOUBLE, MPI_SUM, comm );
Check_MPI_Error( ret, __FILE__, __LINE__ );
data->inv_M = 1.0 / data->M;
}
void Compute_Center_of_Mass( reax_system *system, simulation_data *data,
mpi_datatypes *mpi_data, MPI_Comm comm )
{
int i, ret;
real m, det; //xx, xy, xz, yy, yz, zz;
real tmp_mat[6], tot_mat[6];
rvec my_xcm, my_vcm, my_amcm, my_avcm;
rvec tvec, diff;
rtensor mat, inv;
rvec_MakeZero( my_xcm ); // position of CoM
rvec_MakeZero( my_vcm ); // velocity of CoM
rvec_MakeZero( my_amcm ); // angular momentum of CoM
rvec_MakeZero( my_avcm ); // angular velocity of CoM
/* Compute the position, vel. and ang. momentum about the centre of mass */
for ( i = 0; i < system->n; ++i )
{
m = system->reax_param.sbp[ system->my_atoms[i].type ].mass;
rvec_ScaledAdd( my_xcm, m, system->my_atoms[i].x );
rvec_ScaledAdd( my_vcm, m, system->my_atoms[i].v );
rvec_Cross( tvec, system->my_atoms[i].x, system->my_atoms[i].v );
rvec_ScaledAdd( my_amcm, m, tvec );
}
ret = MPI_Allreduce( my_xcm, data->xcm, 3, MPI_DOUBLE, MPI_SUM, comm );
Check_MPI_Error( ret, __FILE__, __LINE__ );
ret = MPI_Allreduce( my_vcm, data->vcm, 3, MPI_DOUBLE, MPI_SUM, comm );
Check_MPI_Error( ret, __FILE__, __LINE__ );
ret = MPI_Allreduce( my_amcm, data->amcm, 3, MPI_DOUBLE, MPI_SUM, comm );
Check_MPI_Error( ret, __FILE__, __LINE__ );
rvec_Scale( data->xcm, data->inv_M, data->xcm );
rvec_Scale( data->vcm, data->inv_M, data->vcm );
rvec_Cross( tvec, data->xcm, data->vcm );
rvec_ScaledAdd( data->amcm, -data->M, tvec );
data->etran_cm = 0.5 * data->M * rvec_Norm_Sqr( data->vcm );
/* Calculate and then invert the inertial tensor */
for ( i = 0; i < 6; ++i )
{
tmp_mat[i] = 0.0;
}
//my_xx = my_xy = my_xz = my_yy = my_yz = my_zz = 0;
for ( i = 0; i < system->n; ++i )
{
m = system->reax_param.sbp[ system->my_atoms[i].type ].mass;
rvec_ScaledSum( diff, 1.0, system->my_atoms[i].x, -1.0, data->xcm );
tmp_mat[0]/*my_xx*/ += diff[0] * diff[0] * m;
tmp_mat[1]/*my_xy*/ += diff[0] * diff[1] * m;
tmp_mat[2]/*my_xz*/ += diff[0] * diff[2] * m;
tmp_mat[3]/*my_yy*/ += diff[1] * diff[1] * m;
tmp_mat[4]/*my_yz*/ += diff[1] * diff[2] * m;
tmp_mat[5]/*my_zz*/ += diff[2] * diff[2] * m;
}
ret = MPI_Reduce( tmp_mat, tot_mat, 6, MPI_DOUBLE, MPI_SUM, MASTER_NODE, comm );
Check_MPI_Error( ret, __FILE__, __LINE__ );
if ( system->my_rank == MASTER_NODE )
{
mat[0][0] = tot_mat[3] + tot_mat[5]; // yy + zz;
mat[0][1] = mat[1][0] = -tot_mat[1]; // -xy;
mat[0][2] = mat[2][0] = -tot_mat[2]; // -xz;
mat[1][1] = tot_mat[0] + tot_mat[5]; // xx + zz;
mat[2][1] = mat[1][2] = -tot_mat[4]; // -yz;
mat[2][2] = tot_mat[0] + tot_mat[3]; // xx + yy;
/* invert the inertial tensor */
det = ( mat[0][0] * mat[1][1] * mat[2][2] +
mat[0][1] * mat[1][2] * mat[2][0] +
mat[0][2] * mat[1][0] * mat[2][1] ) -
( mat[0][0] * mat[1][2] * mat[2][1] +
mat[0][1] * mat[1][0] * mat[2][2] +
mat[0][2] * mat[1][1] * mat[2][0] );
inv[0][0] = mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1];
inv[0][1] = mat[0][2] * mat[2][1] - mat[0][1] * mat[2][2];
inv[0][2] = mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1];
inv[1][0] = mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2];
inv[1][1] = mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0];
inv[1][2] = mat[0][2] * mat[1][0] - mat[0][0] * mat[1][2];
inv[2][0] = mat[1][0] * mat[2][1] - mat[2][0] * mat[1][1];
inv[2][1] = mat[2][0] * mat[0][1] - mat[0][0] * mat[2][1];
inv[2][2] = mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1];
if ( det > ALMOST_ZERO )
{
rtensor_Scale( inv, 1.0 / det, inv );
}
else
{
rtensor_MakeZero( inv );
}
/* Compute the angular velocity about the centre of mass */
rtensor_MatVec( data->avcm, inv, data->amcm );
}
ret = MPI_Bcast( data->avcm, 3, MPI_DOUBLE, MASTER_NODE, comm );
Check_MPI_Error( ret, __FILE__, __LINE__ );
/* Compute the rotational energy */
data->erot_cm = 0.5 * E_CONV * rvec_Dot( data->avcm, data->amcm );
#if defined(DEBUG_FOCUS)
fprintf( stderr, "xcm: %24.15e %24.15e %24.15e\n",
data->xcm[0], data->xcm[1], data->xcm[2] );
fprintf( stderr, "vcm: %24.15e %24.15e %24.15e\n",
data->vcm[0], data->vcm[1], data->vcm[2] );
fprintf( stderr, "amcm: %24.15e %24.15e %24.15e\n",
data->amcm[0], data->amcm[1], data->amcm[2] );
fprintf( stderr, "mat: %f %f %f\n %f %f %f\n %f %f %f\n",
mat[0][0], mat[0][1], mat[0][2],
mat[1][0], mat[1][1], mat[1][2],
mat[2][0], mat[2][1], mat[2][2] );
fprintf( stderr, "inv: %g %g %g\n %g %g %g\n %g %g %g\n",
inv[0][0], inv[0][1], inv[0][2],
inv[1][0], inv[1][1], inv[1][2],
inv[2][0], inv[2][1], inv[2][2] );
fprintf( stderr, "avcm: %24.15e %24.15e %24.15e\n",
data->avcm[0], data->avcm[1], data->avcm[2] );
#endif
}
void Check_Energy( simulation_data* data )
{
if ( !isfinite(data->my_en.e_pol) )
{
fprintf( stderr, "[ERROR] NaN or infinite detected for polarization energy. Terminating...\n" );
exit( NUMERIC_BREAKDOWN );
}
if ( !isfinite(data->my_en.e_pot) )
{
fprintf( stderr, "[ERROR] NaN or infinite detected for potential energy. Terminating...\n" );
exit( NUMERIC_BREAKDOWN );
}
if ( !isfinite(data->my_en.e_tot) )
{
fprintf( stderr, "[ERROR] NaN or infinite detected for total energy. Terminating...\n" );
exit( NUMERIC_BREAKDOWN );
}
}
/* IMPORTANT: This function assumes that current kinetic energy
* the system is already computed
*
* IMPORTANT: In Klein's paper, it is stated that a dU/dV term needs
* to be added when there are long-range interactions or long-range
* corrections to short-range interactions present.
* We may want to add that for more accuracy.
*/
void Compute_Pressure( reax_system* system, control_params *control,
simulation_data* data, mpi_datatypes *mpi_data )
{
int i, ret;
reax_atom *p_atom;
rvec tmp, tx, int_press;
simulation_box *big_box;
big_box = &system->big_box;
/* Calculate internal pressure */
rvec_MakeZero( int_press );
// 0: both int and ext, 1: ext only, 2: int only
if ( control->press_mode == 0 || control->press_mode == 2 )
{
for ( i = 0; i < system->n; ++i )
{
p_atom = &system->my_atoms[i];
/* transform x into unitbox coordinates */
Transform_to_UnitBox( p_atom->x, big_box, 1, tx );
/* this atom's contribution to internal pressure */
rvec_Multiply( tmp, p_atom->f, tx );
rvec_Add( int_press, tmp );
#if defined(DEBUG_FOCUS)
fprintf( stderr, "%8d%8.2f%8.2f%8.2f",
i + 1, p_atom->x[0], p_atom->x[1], p_atom->x[2] );
fprintf( stderr, "%8.2f%8.2f%8.2f",
p_atom->f[0], p_atom->f[1], p_atom->f[2] );
fprintf( stderr, "%8.2f%8.2f%8.2f\n",
int_press[0], int_press[1], int_press[2] );
#endif
}
}
#if defined(DEBUG_FOCUS)
fprintf( stderr, "p%d:p_int(%10.5f %10.5f %10.5f)p_ext(%10.5f %10.5f %10.5f)\n",
system->my_rank, int_press[0], int_press[1], int_press[2],
data->my_ext_press[0], data->my_ext_press[1], data->my_ext_press[2] );
#endif
/* sum up internal and external pressure */
ret = MPI_Allreduce( int_press, data->int_press, 3, MPI_DOUBLE,
MPI_SUM, mpi_data->comm_mesh3D );
Check_MPI_Error( ret, __FILE__, __LINE__ );
ret = MPI_Allreduce( data->my_ext_press, data->ext_press, 3, MPI_DOUBLE,
MPI_SUM, mpi_data->comm_mesh3D );
Check_MPI_Error( ret, __FILE__, __LINE__ );
#if defined(DEBUG_FOCUS)
fprintf( stderr, "p%d: %10.5f %10.5f %10.5f\n",
system->my_rank,
data->int_press[0], data->int_press[1], data->int_press[2] );
fprintf( stderr, "p%d: %10.5f %10.5f %10.5f\n",
system->my_rank,
data->ext_press[0], data->ext_press[1], data->ext_press[2] );
#endif
/* kinetic contribution */
data->kin_press = 2.0 * (E_CONV * data->sys_en.e_kin)
/ (3.0 * big_box->V * P_CONV);
/* Calculate total pressure in each direction */
data->tot_press[0] = data->kin_press -
(( data->int_press[0] + data->ext_press[0] ) /
( big_box->box_norms[1] * big_box->box_norms[2] * P_CONV ));
data->tot_press[1] = data->kin_press -
(( data->int_press[1] + data->ext_press[1] ) /
( big_box->box_norms[0] * big_box->box_norms[2] * P_CONV ));
data->tot_press[2] = data->kin_press -
(( data->int_press[2] + data->ext_press[2] ) /
( big_box->box_norms[0] * big_box->box_norms[1] * P_CONV ));
/* Average pressure for the whole box */
data->iso_bar.P =
( data->tot_press[0] + data->tot_press[1] + data->tot_press[2] ) / 3.;
}
/*
void Compute_Pressure_Isotropic_Klein( reax_system* system,
simulation_data* data )
{
int i;
reax_atom *p_atom;
rvec dx;
// IMPORTANT: This function assumes that current kinetic energy and
// the center of mass of the system is already computed before.
data->iso_bar.P = 2.0 * data->my_en.e_kin;
for( i = 0; i < system->N; ++i ) {
p_atom = &( system->my_atoms[i] );
rvec_ScaledSum(dx,1.0,p_atom->x,-1.0,data->xcm);
data->iso_bar.P += ( -F_CONV * rvec_Dot(p_atom->f, dx) );
}
data->iso_bar.P /= (3.0 * system->my_box.V);
// IMPORTANT: In Klein's paper, it is stated that a dU/dV term needs
// to be added when there are long-range interactions or long-range
// corrections to short-range interactions present.
// We may want to add that for more accuracy.
}
void Compute_Pressure( reax_system* system, simulation_data* data )
{
int i;
reax_atom *p_atom;
rtensor temp;
rtensor_MakeZero( data->flex_bar.P );
for( i = 0; i < system->N; ++i ) {
p_atom = &( system->my_atoms[i] );
// Distance_on_T3_Gen( data->rcm, p_atom->x, &(system->my_box), &dx );
rvec_OuterProduct( temp, p_atom->v, p_atom->v );
rtensor_ScaledAdd( data->flex_bar.P,
system->reax_param.sbp[ p_atom->type ].mass, temp );
// rvec_OuterProduct(temp,workspace->virial_forces[i],p_atom->x); //dx);
rtensor_ScaledAdd( data->flex_bar.P, -F_CONV, temp );
}
rtensor_Scale( data->flex_bar.P, 1.0 / system->my_box.V, data->flex_bar.P );
data->iso_bar.P = rtensor_Trace( data->flex_bar.P ) / 3.0;
}
*/